# createPlan

> Part of the MAP Audio Music API docs. Index of every page: https://map.audio/developers/music-api/llms.txt. OpenAPI document: https://map.audio/developers/music-api/openapi.json.

`POST https://api.map.audio/v1/plans`

Plan a render from a prompt

Turn a short prompt into an editable render plan, or store one you wrote. The `rules` planner matches the prompt's words and tempo against the catalogue, with no AI model, and returns its ranked candidates and a spec; `caller` stores your own spec once every reference checks out. Plans are free and never change: edit a spec and send it back as a `caller` plan. Next: POST /v1/renders with `plan` set to the plan's id.

Auth: `Authorization: Bearer` with an API key or a map.audio access token. MCP tool: `create_plan`.

## Body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `planner` | "rules" \| "caller" | no | `rules` plans from `prompt` and `constraints`; `caller` stores the `spec` you send. Default `"rules"`. |
| `prompt` | string | no | What you want, in a few words: genre, mood, instruments, a tempo such as 128 bpm, or "variations". At most 500 characters. |
| `spec` | object | no |  |
| `spec.product` | "pam" | no | Default `"pam"`. |
| `spec.base` | object | yes | A factory preset, and optionally one of its variation slots. |
| `spec.base.preset` | string | yes | A factory preset `pam:factory/<slug>`, or its bare slug. At most 200 characters. |
| `spec.base.variation` | integer | no | A variation slot of the preset, numbered from 1; GET /v1/presets/{id} lists the slots it has. Default: its base state. From 1 to 16. |
| `spec.tempo` | number | no | Render at this tempo instead of the preset's, in BPM. From 20 to 400. |
| `spec.morph` | object | no |  |
| `spec.morph.to` | object | yes | A factory preset, and optionally one of its variation slots. |
| `spec.morph.at` | number | no | Morph position: 0 is the start, 1 the target; values outside 0..1 extrapolate along the same line. From -1 to 2. Default `0.5`. |
| `spec.morph.curve` | "linear" \| "ease" \| "exp" \| "log" | no | How the morph position eases, as a live Glide shapes its window. Default `"ease"`. |
| `spec.morph.pattern` | "dissolve" \| "wipe" \| "cells" | no | Stage the cells' patterns at `at` as a Steps transition does; without it the patterns stay the start's below 1. |
| `spec.morph.patternSeed` | integer | no | Draws each step of a `dissolve`, so the same seed gives the same steps. From 0 to 4294967295. |
| `spec.blend` | array of object | no | 2 to 16 items. |
| `spec.blend[].preset` | string | yes | A factory preset `pam:factory/<slug>`, or its bare slug. At most 200 characters. |
| `spec.blend[].variation` | integer | no | The preset's variation slot to blend; default: its base state. From 1 to 16. |
| `spec.blend[].weight` | number | yes | More than 0. |
| `spec.envelopes` | array of object | no | State envelopes ({delta, options?}) applied in order before rendering: the same envelopes POST /v1/state takes. 0 to 64 items. |
| `spec.arrangement` | object | no | `loop` renders `bars` of the base; `variations` renders each listed slot. |
| `spec.arrangement.kind` | "loop" \| "variations" | yes |  |
| `spec.arrangement.bars` | integer | no | From 1 to 64. |
| `spec.arrangement.variations` | array of integer | no | 0 to 16 items. |
| `seed` | integer | no | Breaks ties between equally good presets; the same seed and prompt give the same plan. From 0 to 4294967295. Default `0`. |
| `constraints` | object or null | no |  |
| `constraints.tempo` | number | no | From 20 to 400. |
| `constraints.category` | string | no | At most 60 characters. |
| `constraints.candidates` | integer | no | From 1 to 10. Default `3`. |

## Example

```sh
curl -sS "https://api.map.audio/v1/plans" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01" \
  -H "Content-Type: application/json" \
  -d '{"prompt":"dark techno around 125 bpm","constraints":{"candidates":3},"seed":7}'
```

### Request: Plan from a prompt

```json
{
  "prompt": "dark techno around 125 bpm",
  "constraints": {
    "candidates": 3
  },
  "seed": 7
}
```

### Request: Store your own spec: a morph toward another preset at 128 BPM

```json
{
  "planner": "caller",
  "spec": {
    "base": {
      "preset": "pam:factory/acid-sprinkle",
      "variation": 1
    },
    "tempo": 128,
    "morph": {
      "to": {
        "preset": "pam:factory/teknochonic"
      },
      "at": 0.35
    },
    "arrangement": {
      "kind": "loop",
      "bars": 8
    }
  }
}
```

### 201: A stored caller plan

```json
{
  "object": "plan",
  "id": "plan_01M6BPRCC4FTKB29RFYD2JDKJQ",
  "seed": 0,
  "prompt": null,
  "planner": {
    "kind": "caller",
    "version": "caller-1",
    "model": null
  },
  "candidates": [],
  "spec": {
    "product": "pam",
    "base": {
      "preset": "pam:factory/acid-sprinkle",
      "variation": 1
    },
    "tempo": 128,
    "morph": {
      "to": {
        "preset": "pam:factory/teknochonic"
      },
      "at": 0.35
    },
    "arrangement": {
      "kind": "loop",
      "bars": 8
    }
  },
  "createdAt": "2026-11-01T14:02:10.250Z",
  "provenance": {
    "aiModels": [],
    "presets": [
      "pam:factory/acid-sprinkle",
      "pam:factory/teknochonic"
    ]
  }
}
```

### 400: Invalid request

```json
{
  "error": {
    "type": "invalid_request",
    "code": "invalid_request",
    "message": "Give a prompt, or constraints with a tempo or category, to plan from.",
    "param": "prompt",
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#invalid_request",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}
```

## Responses

- `201`: The plan.
- `400`: Invalid request
- `default`: Any other error: `error.code` names it, `error.param` the field at fault, and `error.docUrl` its entry in the error catalogue.

## Errors

- [`terms_required`](https://map.audio/developers/music-api/errors#terms_required)
- [`preset_not_found`](https://map.audio/developers/music-api/errors#preset_not_found)
- [`preset_not_served`](https://map.audio/developers/music-api/errors#preset_not_served)
- [`variation_not_found`](https://map.audio/developers/music-api/errors#variation_not_found)
- [`invalid_envelope`](https://map.audio/developers/music-api/errors#invalid_envelope)
- [`invalid_request`](https://map.audio/developers/music-api/errors#invalid_request)
- [`unsupported_media_type`](https://map.audio/developers/music-api/errors#unsupported_media_type)
- [`payload_too_large`](https://map.audio/developers/music-api/errors#payload_too_large)
- [`idempotency_key_unsupported`](https://map.audio/developers/music-api/errors#idempotency_key_unsupported)
