Skip to content

Developers

Music API reference

Every operation of the MAP Audio Music API, grouped as in the OpenAPI document, with its fields, a curl example and the errors it can answer with.

View as MarkdownOpenAPI JSONOpenAPI YAMLSkill (.zip)MCP https://api.map.audio/mcp

Examples read the key from MAP_API_KEY and pin the version with Map-Version. Their ids have the shape real ones have, such as job_01M6BPRE186QHP9QPYGDX5NNFP: put in the ids from your own answers. Every operation is also published on its own as Markdown, linked from its entry.

Account

The account behind a credential: plan, render-minutes, usage, terms, access requests, API keys and billing. Keys and billing need a map.audio sign-in on MAP Audio's own pages (map.audio/music).

GET/v1/account

getAccount

Get the calling account

Who this credential belongs to: the Music API account's status, the terms version it accepted, its tier's limits and this month's render-minutes. Call it first. currentTerms is the version POST /v1/account/terms takes (every request that starts work needs it), and credits.remaining is what jobs can still draw. Free.

  • Auth: Authorization: Bearer with an API key or a map.audio access token.
  • MCP tool: get_account
curl
curl -sS "https://api.map.audio/v1/account" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01"
200: An active free-tier account
{
  "object": "account",
  "id": "acct_01M6BPR7CRAWF0WZQZNP3ZD818",
  "email": "dev@example.com",
  "status": "active",
  "termsVersion": "2026-11-01-prototype",
  "currentTerms": "2026-11-01-prototype",
  "livemode": false,
  "limits": {
    "renderMinutesPerMonth": 30,
    "maxRenderSeconds": 300,
    "maxSampleRate": 48000,
    "concurrentJobs": 2,
    "requestsPerMinute": 120,
    "maxDrumSeconds": 30,
    "outputRetentionDays": 7
  },
  "credits": {
    "object": "credits",
    "period": "2026-11",
    "unit": "render_minute",
    "tier": {
      "id": "free",
      "name": "Free",
      "currentPeriodEnd": null,
      "cancelAtPeriodEnd": false
    },
    "granted": 30,
    "used": 4.214,
    "reserved": 0.267,
    "remaining": 25.519,
    "grants": [
      {
        "source": "free",
        "amount": 30,
        "remaining": 25.519,
        "expiresAt": "2026-12-01T00:00:00.000Z"
      }
    ]
  }
}
403: No Music API access yet
{
  "error": {
    "type": "entitlement",
    "code": "not_invited",
    "message": "This map.audio account (customer 8f14e45f-ceea-467a-9575-62f3b1a6c2d0) has no Music API access yet. Request access at https://map.audio/music, or POST /v1/access-requests with this token.",
    "param": null,
    "details": {
      "customerId": "8f14e45f-ceea-467a-9575-62f3b1a6c2d0",
      "emailConfirmed": true,
      "accessRequest": null,
      "requestAccessUrl": "https://map.audio/music"
    },
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#not_invited",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 200 The account., 403 No Music API access yet, default Any other error: `error.code` names it, `error.param` the field at fault, and `error.docUrl` its entry in the error catalogue..

Errors: invalid_request.

View as Markdown

POST/v1/account/terms

acceptTerms

Accept the prototype terms

Accept the terms that every request starting work needs: renders, commands, plans, arrangements, uploads and checkout. Send the version from currentTerms in GET /v1/account; an invited account becomes active. The terms are on map.audio/music, where you can also accept them signed in. Free.

  • Auth: Authorization: Bearer with an API key or a map.audio access token.
  • MCP tool: accept_terms
acceptTerms body
FieldTypeRequiredDescription
acceptstringyesThe version in currentTerms.
curl
curl -sS "https://api.map.audio/v1/account/terms" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01" \
  -H "Content-Type: application/json" \
  -d '{"accept":"2026-11-01-prototype"}'
Request: Accept the current terms
{
  "accept": "2026-11-01-prototype"
}
200: Terms accepted
{
  "object": "account",
  "id": "acct_01M6BPR7CRAWF0WZQZNP3ZD818",
  "email": "dev@example.com",
  "status": "active",
  "termsVersion": "2026-11-01-prototype",
  "currentTerms": "2026-11-01-prototype",
  "livemode": false,
  "limits": {
    "renderMinutesPerMonth": 30,
    "maxRenderSeconds": 300,
    "maxSampleRate": 48000,
    "concurrentJobs": 2,
    "requestsPerMinute": 120,
    "maxDrumSeconds": 30,
    "outputRetentionDays": 7
  },
  "credits": {
    "object": "credits",
    "period": "2026-11",
    "unit": "render_minute",
    "tier": {
      "id": "free",
      "name": "Free",
      "currentPeriodEnd": null,
      "cancelAtPeriodEnd": false
    },
    "granted": 30,
    "used": 4.214,
    "reserved": 0.267,
    "remaining": 25.519,
    "grants": [
      {
        "source": "free",
        "amount": 30,
        "remaining": 25.519,
        "expiresAt": "2026-12-01T00:00:00.000Z"
      }
    ]
  }
}
400: Wrong terms version
{
  "error": {
    "type": "invalid_request",
    "code": "terms_version_mismatch",
    "message": "accept must be \"2026-11-01-prototype\", the current terms version; got \"2026-10-01\".",
    "param": "accept",
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#terms_version_mismatch",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 200 The account, now active., 400 Wrong terms version, 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_version_mismatch, invalid_request, unsupported_media_type, payload_too_large, idempotency_key_unsupported.

View as Markdown

POST/v1/access-requests

createAccessRequest

Request Music API access

Ask MAP Audio for Music API access as the signed-in map.audio account behind the access token. Use it when a call answers 403 not_invited: send the same token, with a line about what you will build and a website if you like. One request per account; sending again updates the fields you send (null clears one), keeps the ones you leave out, and answers 200. MAP Audio emails the account when access is ready, and map.audio/music does the same signed in. An API key cannot call this route, and it never answers not_invited. Free.

  • Auth: Authorization: Bearer with a map.audio access token; an API key is refused.
  • Not an MCP tool: An MCP session already has Music API access; an account without it requests access signed in at map.audio/music.
createAccessRequest body
FieldTypeRequiredDescription
useCasestring or nullnoWhat you want to build with the API, in a sentence or two. null clears a saved one; leaving it out keeps it. At most 1000 characters.
websitestring or nullnoA public https URL for you or your product: a host name, not an IP address, localhost or a URL with credentials. null clears a saved one; leaving it out keeps it. At most 200 characters. Matches ^https://.
curl
curl -sS "https://api.map.audio/v1/access-requests" \
  -H "Authorization: Bearer $MAP_ACCESS_TOKEN" \
  -H "Map-Version: 2026-11-01" \
  -H "Content-Type: application/json" \
  -d '{"useCase":"A game that scores every level with new loops from PAM presets.","website":"https://example.com"}'
Request: A short note about the project
{
  "useCase": "A game that scores every level with new loops from PAM presets.",
  "website": "https://example.com"
}
200: Updated
{
  "object": "access_request",
  "id": "areq_01M6BPS09M7WAVD3A2N3JPJE0X",
  "status": "pending",
  "email": "dev@example.com",
  "useCase": "A game that scores every level with new loops from PAM presets.",
  "website": "https://example.com",
  "createdAt": "2026-11-01T13:40:12.007Z",
  "updatedAt": "2026-11-01T14:05:51.630Z"
}
201: Created
{
  "object": "access_request",
  "id": "areq_01M6BPS09M7WAVD3A2N3JPJE0X",
  "status": "pending",
  "email": "dev@example.com",
  "useCase": "A game that scores every level with new loops from PAM presets.",
  "website": "https://example.com",
  "createdAt": "2026-11-01T13:40:12.007Z",
  "updatedAt": "2026-11-01T13:40:12.007Z"
}
403: Access requests need a sign-in
{
  "error": {
    "type": "entitlement",
    "code": "access_request_needs_sign_in",
    "message": "An API key cannot request access: every key belongs to an account that has it already. Sign in at https://map.audio/music with the map.audio account that needs access, and request it there.",
    "param": null,
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#access_request_needs_sign_in",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}
409: Already has access
{
  "error": {
    "type": "conflict",
    "code": "already_has_access",
    "message": "This map.audio account already has Music API access, so there is nothing to request. Call the API with this token, or create API keys at https://map.audio/music.",
    "param": null,
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#already_has_access",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 200 The request, updated., 201 The request, created., 403 Access requests need a sign-in, 409 Already has access, default Any other error: `error.code` names it, `error.param` the field at fault, and `error.docUrl` its entry in the error catalogue..

Errors: access_request_needs_sign_in, already_has_access, customer_erased, rate_limited, invalid_request, unsupported_media_type, payload_too_large, idempotency_key_unsupported.

View as Markdown

GET/v1/usage

getUsage

Get usage by key and meter

Meter totals for the account per API key and meter: render-minutes, rendered audio seconds, compute time, and the free commands' own meters. from and to are UTC days, at most a year apart and at most 90 days back, as usage is kept that long. Requests made with a map.audio sign-in have keyId: null. Free; GET /v1/credits shows what is left to spend.

  • Auth: Authorization: Bearer with an API key or a map.audio access token.
  • Not an MCP tool: Per-key meter totals are for dashboards and audits; get_credits shows the render-minutes an agent can still spend.
getUsage parameters
NameInTypeRequiredDescription
fromquerystringnoFirst UTC day, YYYY-MM-DD, at most 90 days back. Default: the first of this month.
toquerystringnoLast UTC day, included. Default: today.
curl
curl -sS "https://api.map.audio/v1/usage?from=2026-11-01&to=2026-11-30" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01"
200: This month so far
{
  "object": "usage",
  "from": "2026-11-01",
  "to": "2026-11-01",
  "data": [
    {
      "keyId": "key_01M6BPR91W1E1YGMF0P6TAZZNG",
      "meter": "audioSeconds",
      "quantity": 252.8
    },
    {
      "keyId": "key_01M6BPR91W1E1YGMF0P6TAZZNG",
      "meter": "computeMs",
      "quantity": 61408
    },
    {
      "keyId": "key_01M6BPR91W1E1YGMF0P6TAZZNG",
      "meter": "renderMinutes",
      "quantity": 4.214
    }
  ]
}
400: Invalid request
{
  "error": {
    "type": "invalid_request",
    "code": "invalid_request",
    "message": "from must be a date as YYYY-MM-DD; got \"yesterday\".",
    "param": "from",
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#invalid_request",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 200 Usage., 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: invalid_request.

View as Markdown

GET/v1/credits

getCredits

Get the render-minute balance

What jobs can still spend this month: the tier's allowance, render-minutes used, render-minutes running jobs hold, credits bought, and remaining, which the next job draws on. A job reserves its estimate when it is admitted and settles at its outputs' real length. Free. Buy render-minutes or a paid tier at map.audio/music.

  • Auth: Authorization: Bearer with an API key or a map.audio access token.
  • MCP tool: get_credits
curl
curl -sS "https://api.map.audio/v1/credits" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01"
200: A free-tier account part way through the month
{
  "object": "credits",
  "period": "2026-11",
  "unit": "render_minute",
  "tier": {
    "id": "free",
    "name": "Free",
    "currentPeriodEnd": null,
    "cancelAtPeriodEnd": false
  },
  "granted": 30,
  "used": 4.214,
  "reserved": 0.267,
  "remaining": 25.519,
  "grants": [
    {
      "source": "free",
      "amount": 30,
      "remaining": 25.519,
      "expiresAt": "2026-12-01T00:00:00.000Z"
    }
  ]
}
401: Authentication failed
{
  "error": {
    "type": "authentication",
    "code": "authentication_failed",
    "message": "That API key is not valid or was revoked.",
    "param": null,
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#authentication_failed",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 200 Credits., 401 Authentication failed, default Any other error: `error.code` names it, `error.param` the field at fault, and `error.docUrl` its entry in the error catalogue..

Errors: invalid_request.

View as Markdown

GET/v1/api-keys

listApiKeys

List API keys

The account's API keys, newest first, without their secrets; prefix shows each one's first characters so you can tell them apart. Free.

  • Auth: Authorization: Bearer with an API key or a map.audio access token.
  • Not an MCP tool: API keys are created, listed and revoked signed in at map.audio/music, so a connected app never holds or handles credentials.
curl
curl -sS "https://api.map.audio/v1/api-keys" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01"
200: One key
{
  "object": "list",
  "data": [
    {
      "object": "api_key",
      "id": "key_01M6BPR91W1E1YGMF0P6TAZZNG",
      "name": "Build server",
      "mode": "test",
      "prefix": "sk_test_7Hq2",
      "createdAt": "2026-10-28T09:12:44.031Z",
      "lastUsedAt": "2026-11-01T14:03:31.000Z",
      "revokedAt": null
    }
  ]
}
400: Invalid request
{
  "error": {
    "type": "invalid_request",
    "code": "invalid_request",
    "message": "\"cursor\" is not a parameter of GET /v1/api-keys; it takes none.",
    "param": "cursor",
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#invalid_request",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 200 Keys., 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: invalid_request.

View as Markdown

POST/v1/api-keys

createApiKey

Create an API key

Create an API key; its secret is in this response only, so store it now. Needs a map.audio sign-in on MAP Audio's own pages (map.audio/music), not an API key or another app's token, so a leaked key cannot mint more. mode picks the sk_test_ or sk_live_ prefix: both modes spend the same render-minutes and see the same jobs and files. An account holds at most 10 active keys. Send acceptTerms to accept the terms in the same call. Free.

  • Auth: Authorization: Bearer with an API key or a map.audio access token.
  • Not an MCP tool: API keys are created, listed and revoked signed in at map.audio/music, so a connected app never holds or handles credentials.
createApiKey body
FieldTypeRequiredDescription
namestringnoA label you choose, to tell keys apart. At most 80 characters.
mode"test" | "live"notest or live. Both draw on the same render-minutes; the prefix separates Idempotency-Key namespaces and marks test renders' provenance. Default "test".
acceptTermsstringnoThe prototype terms version being accepted, required until the account has accepted it.
curl
curl -sS "https://api.map.audio/v1/api-keys" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01" \
  -H "Content-Type: application/json" \
  -d '{"name":"Production server","mode":"live"}'
Request: A live key for a server
{
  "name": "Production server",
  "mode": "live"
}
Request: A first test key, accepting the terms
{
  "name": "Laptop",
  "mode": "test",
  "acceptTerms": "2026-11-01-prototype"
}
201: Created
{
  "object": "api_key",
  "id": "key_01M6BPRAQ0QXZ93APJ3C3FRWXZ",
  "name": "Production server",
  "mode": "live",
  "prefix": "sk_live_Qm4T",
  "createdAt": "2026-11-01T14:10:05.311Z",
  "lastUsedAt": null,
  "revokedAt": null,
  "secret": "sk_live_Qm4Tz8VbN2rYp6KcW1sXe9JhL3dGa7FuR5o"
}
403: Needs the account owner's sign-in
{
  "error": {
    "type": "entitlement",
    "code": "oauth_required",
    "message": "Only the account owner, signed in at https://map.audio/music, can create or revoke API keys. This request used an API key.",
    "param": null,
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#oauth_required",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}
403: Key limit reached
{
  "error": {
    "type": "entitlement",
    "code": "too_many_keys",
    "message": "An account may hold 10 active keys; revoke one (DELETE /v1/api-keys/{id}) first.",
    "param": null,
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#too_many_keys",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 201 The key, with its secret., 403 Needs the account owner's sign-in; Key limit reached, default Any other error: `error.code` names it, `error.param` the field at fault, and `error.docUrl` its entry in the error catalogue..

Errors: oauth_required, terms_version_mismatch, too_many_keys, invalid_request, unsupported_media_type, payload_too_large, idempotency_key_unsupported.

View as Markdown

DELETE/v1/api-keys/{id}

revokeApiKey

Revoke an API key

Revoke a key at once: requests with it answer 401 from then on, and webhook endpoints whose secret it last set are disabled with it. Needs a map.audio sign-in on MAP Audio's own pages (map.audio/music), so a leaked key cannot revoke the others. Free.

  • Auth: Authorization: Bearer with an API key or a map.audio access token.
  • Not an MCP tool: API keys are created, listed and revoked signed in at map.audio/music, so a connected app never holds or handles credentials.
revokeApiKey parameters
NameInTypeRequiredDescription
idpathstringyesAn API key id (key_…), from GET /v1/api-keys; not the secret. Matches ^key_[0-9A-HJKMNP-TV-Z]{26}$.
curl
curl -sS -X DELETE "https://api.map.audio/v1/api-keys/key_01M6BPRAQ0QXZ93APJ3C3FRWXZ" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01"
200: Revoked
{
  "object": "api_key",
  "id": "key_01M6BPRAQ0QXZ93APJ3C3FRWXZ",
  "name": "Production server",
  "mode": "live",
  "prefix": "sk_live_Qm4T",
  "createdAt": "2026-11-01T14:10:05.311Z",
  "lastUsedAt": null,
  "revokedAt": "2026-11-01T14:12:40.902Z"
}
404: Not found
{
  "error": {
    "type": "not_found",
    "code": "not_found",
    "message": "No API key with that id; GET /v1/api-keys lists this account's keys.",
    "param": "id",
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#not_found",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 200 The key, revoked., 404 Not found, default Any other error: `error.code` names it, `error.param` the field at fault, and `error.docUrl` its entry in the error catalogue..

Errors: oauth_required, not_found, invalid_request.

View as Markdown

POST/v1/billing/checkout

createBillingCheckout

Buy a tier or render-minutes

Open a Stripe Checkout page to subscribe to a paid tier or to buy render-minutes; the tier or credits apply once Stripe confirms the payment. Send tier or renderMinutes, not both. Needs a map.audio sign-in on MAP Audio's own pages, as map.audio/music uses; an API key or another app cannot buy. Answers with a URL for a person to open in a browser.

  • Auth: Authorization: Bearer with an API key or a map.audio access token.
  • Not an MCP tool: Spends money on a Stripe page a person completes in a browser; only MAP Audio's own pages may open one.
createBillingCheckout body
FieldTypeRequiredDescription
tier"creator" | "pro" | "app"noA paid tier to subscribe to.
renderMinutesintegernoWhole render-minutes of pay-as-you-go credit to buy. From 334 to 100000.
consentobjectnoThe buyer's analytics and advertising choice on map.audio, which the purchase's analytics and ad reports follow. Without it, both count as denied.
consent.analytics"granted" | "denied"yes
consent.advertising"granted" | "denied"yes
curl
curl -sS "https://api.map.audio/v1/billing/checkout" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01" \
  -H "Content-Type: application/json" \
  -d '{"tier":"pro","consent":{"analytics":"granted","advertising":"denied"}}'
Request: Subscribe to Pro
{
  "tier": "pro",
  "consent": {
    "analytics": "granted",
    "advertising": "denied"
  }
}
Request: Buy 500 render-minutes
{
  "renderMinutes": 500
}
200: Checkout
{
  "object": "billing_link",
  "url": "https://checkout.stripe.com/c/pay/cs_live_a1B2c3D4e5F6g7H8i9J0kLmNoPqRsTuVwXyZ"
}
409: Already subscribed
{
  "error": {
    "type": "conflict",
    "code": "subscription_exists",
    "message": "This account already subscribes to a plan; change or cancel it from the billing portal (POST /v1/billing/portal).",
    "param": null,
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#subscription_exists",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 200 A Stripe Checkout page., 409 Already subscribed, default Any other error: `error.code` names it, `error.param` the field at fault, and `error.docUrl` its entry in the error catalogue..

Errors: oauth_required, terms_required, subscription_exists, billing_rate_limited, billing_unavailable, invalid_request, unsupported_media_type, payload_too_large, idempotency_key_unsupported.

View as Markdown

POST/v1/billing/portal

createBillingPortal

Open the billing portal

Open the Stripe billing portal, where a subscriber changes plan or card, cancels and reads invoices. Needs a map.audio sign-in on MAP Audio's own pages. It does not wait on the terms, so a subscription can always be cancelled.

  • Auth: Authorization: Bearer with an API key or a map.audio access token.
  • Not an MCP tool: Spends money on a Stripe page a person completes in a browser; only MAP Audio's own pages may open one.
curl
curl -sS -X POST "https://api.map.audio/v1/billing/portal" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01"
200: Portal
{
  "object": "billing_link",
  "url": "https://billing.stripe.com/p/session/live_YWNjdF8xUHFSc1R1VndYeVo"
}
409: No billing account yet
{
  "error": {
    "type": "conflict",
    "code": "billing_not_available",
    "message": "Nothing has been bought on this account yet, so it has no billing portal; buy with POST /v1/billing/checkout.",
    "param": null,
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#billing_not_available",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 200 The billing portal., 409 No billing account yet, default Any other error: `error.code` names it, `error.param` the field at fault, and `error.docUrl` its entry in the error catalogue..

Errors: oauth_required, billing_not_available, billing_rate_limited, billing_unavailable, idempotency_key_unsupported.

View as Markdown

Catalogue

The factory presets the engine renders, the drum-synth engines, the DJ transitions, and this document.

GET/v1/presets

listPresets

Search the factory presets

Search the factory presets the engine renders, by words in their names, descriptions, categories and tags, by category and by tempo. Each preset's ref (pam:factory/<slug>) is what renders, plans, arrangements and DJ sets take, and variations lists its slots. Free. Next: POST /v1/renders with source.preset set to a ref.

  • Auth: Authorization: Bearer with an API key or a map.audio access token.
  • MCP tool: search_presets
listPresets parameters
NameInTypeRequiredDescription
qquerystringnoWords that must each start a word of a preset's name, description, category, subcategory, author or tags. At most 200 characters.
categoryquerystringnoA category, matched without regard to case.
tempoMinquerynumbernoLowest tempo, in BPM.
tempoMaxquerynumbernoHighest tempo, in BPM.
limitqueryintegernoPresets per page. From 1 to 100. Default 25.
cursorquerystringnoThe nextCursor of the previous page.
curl
curl -sS "https://api.map.audio/v1/presets?q=disco&category=Drums&tempoMin=118&tempoMax=128" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01"
200: Searching for "disco"
{
  "object": "list",
  "data": [
    {
      "object": "preset",
      "slug": "313-disco",
      "ref": "pam:factory/313-disco",
      "product": "pam",
      "name": "313 Disco",
      "author": "TopograFX",
      "description": "Motor City disco with aquatic funk",
      "bpm": 120,
      "timeSignature": [
        4,
        4
      ],
      "category": "Drums",
      "subcategory": "Disco",
      "tags": [],
      "variations": [
        1
      ],
      "sha256": "3afbf5dea1003b2d17385955017785a57d74c65f77f97b58cf5d7cec9794ca1c",
      "hasSong": false
    }
  ],
  "total": 1,
  "nextCursor": null
}
400: Invalid request
{
  "error": {
    "type": "invalid_request",
    "code": "invalid_request",
    "message": "limit must be a whole number from 1 to 100; got \"500\".",
    "param": "limit",
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#invalid_request",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 200 Matching presets., 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: invalid_request.

View as Markdown

GET/v1/presets/{id}

getPreset

Get one preset

One factory preset by its slug (313-disco) or URL-encoded reference: name, tempo, time signature, category, tags and the variation slots it has. Free.

  • Auth: Authorization: Bearer with an API key or a map.audio access token.
  • MCP tool: get_preset
getPreset parameters
NameInTypeRequiredDescription
idpathstringyesA factory preset's slug (313-disco) or its URL-encoded reference (pam%3Afactory%2F313-disco). At most 200 characters.
curl
curl -sS "https://api.map.audio/v1/presets/313-disco" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01"
200: 313 Disco
{
  "object": "preset",
  "slug": "313-disco",
  "ref": "pam:factory/313-disco",
  "product": "pam",
  "name": "313 Disco",
  "author": "TopograFX",
  "description": "Motor City disco with aquatic funk",
  "bpm": 120,
  "timeSignature": [
    4,
    4
  ],
  "category": "Drums",
  "subcategory": "Disco",
  "tags": [],
  "variations": [
    1
  ],
  "sha256": "3afbf5dea1003b2d17385955017785a57d74c65f77f97b58cf5d7cec9794ca1c",
  "hasSong": false
}
404: No such preset
{
  "error": {
    "type": "not_found",
    "code": "preset_not_found",
    "message": "No factory preset 313-discoo; list them with GET /v1/presets.",
    "param": "id",
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#preset_not_found",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 200 The preset., 404 No such preset, default Any other error: `error.code` names it, `error.param` the field at fault, and `error.docUrl` its entry in the error catalogue..

Errors: invalid_request, preset_not_found, preset_not_served.

View as Markdown

GET/v1/drum-engines

listDrumEngines

List the drum-synth engines

The drum-synth engines POST /v1/synth/drum plays, each with its controls: label, unit and range. Set controls by label in that route's param (Tune=55,Decay=1.5); percent controls take 0 to 100. Free.

  • Auth: Authorization: Bearer with an API key or a map.audio access token.
  • MCP tool: list_drum_engines
curl
curl -sS "https://api.map.audio/v1/drum-engines" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01"
200: The first two engines
{
  "object": "list",
  "data": [
    {
      "id": "1",
      "slug": "kick",
      "name": "Kick",
      "controls": [
        {
          "label": "Tune",
          "unit": "Hz",
          "min": 30,
          "max": 160
        },
        {
          "label": "P.Depth",
          "unit": "ratio",
          "min": 1,
          "max": 5
        },
        {
          "label": "P.Decay",
          "unit": "s",
          "min": 0.005,
          "max": 0.2
        },
        {
          "label": "Decay",
          "unit": "s",
          "min": 0.03,
          "max": 3
        },
        {
          "label": "Click",
          "unit": "percent",
          "min": 0,
          "max": 100
        },
        {
          "label": "Drive",
          "unit": "percent",
          "min": 0,
          "max": 100
        },
        {
          "label": "Tone",
          "unit": "Hz",
          "min": 150,
          "max": 16000
        },
        {
          "label": "Wave",
          "unit": "percent",
          "min": 0,
          "max": 100
        }
      ]
    },
    {
      "id": "2",
      "slug": "snare",
      "name": "Snare",
      "controls": [
        {
          "label": "Tune",
          "unit": "Hz",
          "min": 120,
          "max": 400
        },
        {
          "label": "Noise",
          "unit": "percent",
          "min": 0,
          "max": 100
        },
        {
          "label": "Decay",
          "unit": "s",
          "min": 0.03,
          "max": 0.5
        },
        {
          "label": "N.Decay",
          "unit": "s",
          "min": 0.03,
          "max": 0.6
        },
        {
          "label": "N.Tone",
          "unit": "Hz",
          "min": 800,
          "max": 8000
        },
        {
          "label": "P.Depth",
          "unit": "ratio",
          "min": 1,
          "max": 3
        },
        {
          "label": "P.Decay",
          "unit": "s",
          "min": 0.005,
          "max": 0.3
        },
        {
          "label": "Drive",
          "unit": "percent",
          "min": 0,
          "max": 100
        }
      ]
    }
  ]
}
429: Rate limited
{
  "error": {
    "type": "rate_limit",
    "code": "rate_limited",
    "message": "This API key sent more than 120 requests in a minute, the limit for each key; retry after 10 s.",
    "param": null,
    "retryable": true,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#rate_limited",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 200 Engines., 429 Rate limited, default Any other error: `error.code` names it, `error.param` the field at fault, and `error.docUrl` its entry in the error catalogue..

Errors: invalid_request.

View as Markdown

GET/v1/transition-presets

listTransitionPresets

List the DJ transitions

What a DJ set's transitions can use: the transition presets a render knows, the modes and curves a transition takes, the longest window in bars, and the DJ set schema's definitions. Read it before writing a set for POST /v1/arrangements or POST /v1/dj/set. Free.

  • Auth: Authorization: Bearer with an API key or a map.audio access token.
  • MCP tool: list_transition_presets
curl
curl -sS "https://api.map.audio/v1/transition-presets" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01"
200: Factory transitions (definitions cut to DjTransition's plain fields)
{
  "object": "transition_presets",
  "presets": [
    "drop",
    "rise",
    "break",
    "blend",
    "sweep",
    "fill"
  ],
  "modes": [
    "auto",
    "param",
    "mix",
    "seq",
    "all",
    "swap",
    "chop"
  ],
  "curves": [
    "linear",
    "ease",
    "exp",
    "log"
  ],
  "maxBars": 32,
  "schema": "https://map.audio/schemas/pam/dj-set.schema.json",
  "definitions": {
    "DjTransition": {
      "type": "object",
      "additionalProperties": false,
      "description": "Resolved in order: the preset's spec, spec merged over it one level deep per section, then bars, mode and curve as the DJ view's Length, Mode and Curve rows apply them.",
      "properties": {
        "preset": {
          "type": "string",
          "minLength": 1,
          "maxLength": 64,
          "description": "A transition preset id: drop, rise, break, blend, sweep, fill, or one the user saved."
        },
        "bars": {
          "type": "number",
          "minimum": 0,
          "maximum": 32
        },
        "mode": {
          "enum": [
            "auto",
            "param",
            "mix",
            "seq",
            "all",
            "swap",
            "chop"
          ]
        },
        "curve": {
          "enum": [
            "linear",
            "ease",
            "exp",
            "log"
          ]
        }
      }
    }
  }
}
401: Authentication failed
{
  "error": {
    "type": "authentication",
    "code": "authentication_failed",
    "message": "Send an API key or a map.audio access token as `Authorization: Bearer …`.",
    "param": null,
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#authentication_failed",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 200 Transitions., 401 Authentication failed, default Any other error: `error.code` names it, `error.param` the field at fault, and `error.docUrl` its entry in the error catalogue..

Errors: invalid_request.

View as Markdown

GET/v1/openapi.json

getOpenApi

Get this OpenAPI document

This document, with servers set to the origin that served it. Public. Free.

  • Auth: none; this route is public.
  • Not an MCP tool: This document; MCP clients get the same schemas from tools/list.
curl
curl -sS "https://api.map.audio/v1/openapi.json" \
  -H "Map-Version: 2026-11-01"
200: The document (shortened)
{
  "openapi": "3.1.0",
  "info": {
    "title": "MAP Audio Music API",
    "version": "2026-11-01"
  },
  "servers": [
    {
      "url": "https://api.map.audio"
    }
  ]
}
500: Internal error
{
  "error": {
    "type": "unavailable",
    "code": "internal_error",
    "message": "Something went wrong on our side; nothing was charged.",
    "param": null,
    "retryable": true,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#internal_error",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 200 OpenAPI 3.1., 500 Internal error, default Any other error: `error.code` names it, `error.param` the field at fault, and `error.docUrl` its entry in the error catalogue..

View as Markdown

Plans

Turn a short prompt, or a spec you write, into an editable render plan. Free; no AI model.

POST/v1/plans

createPlan

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
createPlan body
FieldTypeRequiredDescription
planner"rules" | "caller"norules plans from prompt and constraints; caller stores the spec you send. Default "rules".
promptstringnoWhat you want, in a few words: genre, mood, instruments, a tempo such as 128 bpm, or "variations". At most 500 characters.
specobjectno
spec.product"pam"noDefault "pam".
spec.baseobjectyesA factory preset, and optionally one of its variation slots.
spec.base.presetstringyesA factory preset pam:factory/<slug>, or its bare slug. At most 200 characters.
spec.base.variationintegernoA 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.temponumbernoRender at this tempo instead of the preset's, in BPM. From 20 to 400.
spec.morphobjectno
spec.morph.toobjectyesA factory preset, and optionally one of its variation slots.
spec.morph.atnumbernoMorph 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"noHow the morph position eases, as a live Glide shapes its window. Default "ease".
spec.morph.pattern"dissolve" | "wipe" | "cells"noStage the cells' patterns at at as a Steps transition does; without it the patterns stay the start's below 1.
spec.morph.patternSeedintegernoDraws each step of a dissolve, so the same seed gives the same steps. From 0 to 4294967295.
spec.blendarray of objectno2 to 16 items.
spec.blend[].presetstringyesA factory preset pam:factory/<slug>, or its bare slug. At most 200 characters.
spec.blend[].variationintegernoThe preset's variation slot to blend; default: its base state. From 1 to 16.
spec.blend[].weightnumberyesMore than 0.
spec.envelopesarray of objectnoState envelopes ({delta, options?}) applied in order before rendering: the same envelopes POST /v1/state takes. 0 to 64 items.
spec.arrangementobjectnoloop renders bars of the base; variations renders each listed slot.
spec.arrangement.kind"loop" | "variations"yes
spec.arrangement.barsintegernoFrom 1 to 64.
spec.arrangement.variationsarray of integerno0 to 16 items.
seedintegernoBreaks ties between equally good presets; the same seed and prompt give the same plan. From 0 to 4294967295. Default 0.
constraintsobject or nullno
constraints.temponumbernoFrom 20 to 400.
constraints.categorystringnoAt most 60 characters.
constraints.candidatesintegernoFrom 1 to 10. Default 3.
curl
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
{
  "prompt": "dark techno around 125 bpm",
  "constraints": {
    "candidates": 3
  },
  "seed": 7
}
Request: Store your own spec: a morph toward another preset at 128 BPM
{
  "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
{
  "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
{
  "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, preset_not_found, preset_not_served, variation_not_found, invalid_envelope, invalid_request, unsupported_media_type, payload_too_large, idempotency_key_unsupported.

View as Markdown

GET/v1/plans/{id}

getPlan

Get a plan

A stored plan: its spec, the candidates the rules planner ranked, and the presets it names. Plans never change; render one with POST /v1/renders and plan. Free.

  • Auth: Authorization: Bearer with an API key or a map.audio access token.
  • MCP tool: get_plan
getPlan parameters
NameInTypeRequiredDescription
idpathstringyesA plan id (plan_…), from POST /v1/plans. Matches ^plan_[0-9A-HJKMNP-TV-Z]{26}$.
curl
curl -sS "https://api.map.audio/v1/plans/plan_01M6BPRCC4FTKB29RFYD2JDKJQ" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01"
200: A caller plan
{
  "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"
    ]
  }
}
404: Not found
{
  "error": {
    "type": "not_found",
    "code": "not_found",
    "message": "No plan with that id; plans come from POST /v1/plans, which returns the id.",
    "param": "id",
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#not_found",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 200 The plan., 404 Not found, default Any other error: `error.code` names it, `error.param` the field at fault, and `error.docUrl` its entry in the error catalogue..

Errors: not_found, invalid_request.

View as Markdown

Renders

Render presets and plans to audio, and fit cutdowns or check DJ sets before rendering.

POST/v1/renders

createRender

Render presets or a plan to audio

Render a factory preset or a stored plan as one job, with one output or many: a length in bars or seconds, a variation, stems, a sample rate, WAV, FLAC or MP3, and a seed (the job reports the seed it used; sending it again renders the same audio). variations renders several slots, seeds, morph positions or a blend; items names outputs of their own lengths or cutdowns; quality: standard renders candidate seeds, measures each and keeps the best. Costs render-minutes: each output's length in minutes, at least 0.1 an output, shown in estimate before it runs. Answers 202 with the queued job unless Prefer: wait covers it; its outputs are in result.outputs once it succeeds.

  • Auth: Authorization: Bearer with an API key or a map.audio access token.
  • Send Prefer: wait=N (0 to 60) to receive the finished job when it ends within N seconds.
  • Send Idempotency-Key to retry safely: the same key and body return the same result for 24 hours.
  • MCP tool: create_render
createRender body
FieldTypeRequiredDescription
sourceobjectnoThe preset to render; give source or plan.
source.presetstringyesA factory preset pam:factory/<slug>, or its bare slug. At most 200 characters.
source.variationintegernoA 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.
planstringnoA stored plan's id (plan_…), instead of source. Matches ^plan_.
barsintegernoLength in bars of the preset's time signature, at its tempo (or the plan's). Default 4; give bars or seconds. From 1 to 64.
secondsnumbernoLength in seconds, instead of bars. More than 0, up to 300.
tailnumbernoSeconds of effect tail after the transport stops, added to the length. From 0 to 30. Default 0.
seedintegernoSeed for everything random in the render; 0 draws one, which the job reports, and sending that seed again renders the same audio. From 0 to 4294967295. Default 0.
stemsbooleannoAlso write one stem per cell, captured after cell effects and before the master chain, encoded like the master. Default false.
sampleRate22050 | 32000 | 44100 | 48000noOutput sample rate in Hz. Default 48000.
formatobjectnoContainer and MP3 bitrate for every output; WAV unless you ask.
format.container"wav" | "flac" | "mp3"noDefault "wav".
format.bitrate96 | 112 | 128 | 160 | 192 | 224 | 256 | 320noMP3 only, kbit/s. At 22050 Hz the most is 160, which is then the default. Default 320.
quality"draft" | "standard" | "elite"nostandard renders search.candidates seeds, measures each and returns the best that pass the limit gate; elite is refused until a curated archive exists. Default "draft".
searchobjectnoOnly with quality standard.
search.candidatesintegernoFrom 2 to 8. Default 4.
search.returnintegernoFrom 1 to 4. Default 1.
search.targetLufsnumbernoFrom -40 to -6.
variationsobject, kind slots, seeds, morph, blendnoSeveral outputs from one job: slots renders variation slots, seeds takes from derived seeds, morph renders positions between the source and to, blend renders a weighted blend of presets.
variations.slotsarray of integernoWith kind slots. 1 to 16 items.
variations.countintegeryesWith kind seeds. From 2 to 8.
variations.toobjectyesWith kind morph. A factory preset, and optionally one of its variation slots.
variations.to.presetstringyesWith kind morph. A factory preset pam:factory/<slug>, or its bare slug. At most 200 characters.
variations.to.variationintegernoWith kind morph. 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.
variations.atarray of numberyesWith kind morph. 2 to 8 items.
variations.curve"linear" | "ease" | "exp" | "log"noWith kind morph.
variations.pattern"dissolve" | "wipe" | "cells"noWith kind morph.
variations.patternSeedintegernoWith kind morph. From 0 to 4294967295.
variations.presetsarray of objectyesWith kind blend. 2 to 16 items.
variations.presets[].presetstringyesWith kind blend. A factory preset pam:factory/<slug>, or its bare slug. At most 200 characters.
variations.presets[].variationintegernoWith kind blend. The preset's variation slot to blend; default: its base state. From 1 to 16.
variations.presets[].weightnumberyesWith kind blend. More than 0.
itemsarray of objectnoNamed outputs of their own lengths: a variation for some bars, or a cutdown fitted to seconds across the preset's variations. 1 to 8 items.
items[].namestringyesMatches ^[A-Za-z0-9_-]{1,40}$.
items[].variationintegernoFrom 1 to 16.
items[].barsintegernoFrom 1 to 64.
items[].cutdownobjectnoFits the preset to this length across its variations. An item with a cutdown takes no variation or bars.
items[].cutdown.secondsnumberyesFrom 5 to 300.
previewobjectnoA short render published first, as a job.preview event. A job that succeeds pays for its render or its preview, whichever is longer; if it fails or is cancelled, the preview is still charged at its own length.
preview.barsintegernoFrom 1 to 8. Default 4.
metadatamap of stringnoUp to 20 string pairs stored with the job and returned with it. At most 20 entries.
curl
curl -sS "https://api.map.audio/v1/renders" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01" \
  -H "Prefer: wait=30" \
  -H "Content-Type: application/json" \
  -d '{"source":{"preset":"pam:factory/313-disco"},"bars":8,"seed":42}'
Request: Eight bars of 313 Disco as WAV, with a fixed seed
{
  "source": {
    "preset": "pam:factory/313-disco"
  },
  "bars": 8,
  "seed": 42
}
Request: Four of Cal's variation slots in one job, as FLAC
{
  "source": {
    "preset": "pam:factory/cal"
  },
  "bars": 8,
  "variations": {
    "kind": "slots",
    "slots": [
      1,
      2,
      3,
      4
    ]
  },
  "format": {
    "container": "flac"
  }
}
Request: Four takes of Totes Rando, each from its own seed
{
  "source": {
    "preset": "pam:factory/totes-rando"
  },
  "bars": 4,
  "variations": {
    "kind": "seeds",
    "count": 4
  },
  "seed": 7
}
Request: Sixteen bars of a variation with one stem per cell
{
  "source": {
    "preset": "pam:factory/breakbeatrcool",
    "variation": 2
  },
  "bars": 16,
  "stems": true,
  "seed": 42
}
Request: Three points on a morph from Acid Sprinkle toward Teknochonic
{
  "source": {
    "preset": "pam:factory/acid-sprinkle"
  },
  "bars": 8,
  "variations": {
    "kind": "morph",
    "to": {
      "preset": "pam:factory/teknochonic"
    },
    "at": [
      0.25,
      0.5,
      0.75
    ]
  }
}
Request: 30- and 15-second cutdowns for an ad, as 256 kbit/s MP3
{
  "source": {
    "preset": "pam:factory/thaw"
  },
  "items": [
    {
      "name": "spot-30",
      "cutdown": {
        "seconds": 30
      }
    },
    {
      "name": "spot-15",
      "cutdown": {
        "seconds": 15
      }
    }
  ],
  "format": {
    "container": "mp3",
    "bitrate": 256
  }
}
Request: Render four seeds and keep the one nearest -14 LUFS
{
  "source": {
    "preset": "pam:factory/junglistic"
  },
  "bars": 8,
  "quality": "standard",
  "search": {
    "candidates": 4,
    "return": 1,
    "targetLufs": -14
  }
}
Request: Two minutes, with a 4-bar preview published first
{
  "source": {
    "preset": "pam:factory/corduroy"
  },
  "seconds": 120,
  "preview": {
    "bars": 4
  },
  "seed": 11
}
Request: Render a stored plan
{
  "plan": "plan_01M6BPRCC4FTKB29RFYD2JDKJQ",
  "format": {
    "container": "mp3"
  }
}
200: Succeeded: 16 s of 313 Disco
{
  "object": "job",
  "id": "job_01M6BPRE186QHP9QPYGDX5NNFP",
  "operation": "renders.create",
  "status": "succeeded",
  "livemode": false,
  "sequence": 3,
  "progress": 1,
  "queuePosition": null,
  "createdAt": "2026-11-01T14:03:31.512Z",
  "startedAt": "2026-11-01T14:03:33.104Z",
  "finishedAt": "2026-11-01T14:03:41.877Z",
  "estimate": {
    "audioSeconds": 16,
    "renderMinutes": 0.267
  },
  "result": {
    "outputs": [
      {
        "role": "master",
        "name": null,
        "cell": null,
        "file": "file_01M6BPRK0M34NBP2XKJ1RMX1TQ",
        "sha256": "5a3485b7a3221be5f7ead6ab953cbc198988a7246158215b32bb937acbd3852b",
        "bytes": 4608044,
        "format": "wav",
        "sampleRate": 48000,
        "durationSeconds": 16,
        "url": "https://api.map.audio/v1/download/file_01M6BPRK0M34NBP2XKJ1RMX1TQ?expires=1793545422&signature=yaoMrgCHcK9T8MaVnCVtXZc4Ym0FWWM8P-0feZDMObk",
        "expiresAt": "2026-11-01T15:03:42.000Z"
      }
    ],
    "seed": 42,
    "command": {
      "ok": true,
      "wavPath": "file_01M6BPRK0M34NBP2XKJ1RMX1TQ",
      "sampleRate": 48000,
      "channels": 2,
      "durationSeconds": 16,
      "seed": 42,
      "stems": [],
      "stemTap": "post_cell_pre_master",
      "latencySamples": 0,
      "missingSamples": []
    },
    "spec": {
      "source": {
        "preset": "pam:factory/313-disco"
      },
      "plan": null,
      "bars": 8,
      "seconds": null,
      "tail": 0,
      "seed": 42,
      "stems": false,
      "sampleRate": 48000,
      "format": {
        "container": "wav"
      },
      "quality": "draft",
      "tempo": 120
    },
    "provenance": {
      "object": "provenance",
      "id": "prov_01M6BPRVA8ZC7F7J737SQ0EPN2",
      "jobId": "job_01M6BPRE186QHP9QPYGDX5NNFP",
      "createdAt": "2026-11-01T14:03:41.877Z",
      "engine": {
        "product": "pam",
        "version": null,
        "runtime": "native-linux-x86_64",
        "image": "registry.cloudflare.com/c7c2e61448617e81ced650f444fb6787/pam-render@sha256:5c5ffe3fabc103e277280fbd65a08988d31361f00fe7857e36f603d67bcec42d"
      },
      "seed": 42,
      "presets": [
        {
          "ref": "pam:factory/313-disco",
          "sha256": "3afbf5dea1003b2d17385955017785a57d74c65f77f97b58cf5d7cec9794ca1c"
        }
      ],
      "packs": [],
      "userFiles": [],
      "inputs": [],
      "outputs": [
        {
          "file": "file_01M6BPRK0M34NBP2XKJ1RMX1TQ",
          "sha256": "5a3485b7a3221be5f7ead6ab953cbc198988a7246158215b32bb937acbd3852b"
        }
      ],
      "planner": null,
      "contracts": {
        "api": "2026-11-01",
        "pam.cli": 1
      },
      "aiModels": [],
      "audioByModel": false,
      "license": {
        "id": "lic_api_prototype_test",
        "commercialUse": false,
        "attribution": true
      },
      "kid": "6c2f0a9d4b7e1358",
      "signature": "ed25519:jsfkW3eF1r4kChqccp6AKLTvjTK5Re8acrEusqigz7MDUu6uZhsJXVnuQEl6EsErDgVYNXOkos9d0mMyt2CVCg"
    }
  },
  "error": null,
  "usage": {
    "renderMinutes": 0.267,
    "audioSeconds": 16,
    "computeMs": 6273
  },
  "metadata": {},
  "urls": {
    "self": "https://api.map.audio/v1/jobs/job_01M6BPRE186QHP9QPYGDX5NNFP",
    "events": "https://api.map.audio/v1/jobs/job_01M6BPRE186QHP9QPYGDX5NNFP/events",
    "cancel": "https://api.map.audio/v1/jobs/job_01M6BPRE186QHP9QPYGDX5NNFP/cancel"
  }
}
202: Queued
{
  "object": "job",
  "id": "job_01M6BPRE186QHP9QPYGDX5NNFP",
  "operation": "renders.create",
  "status": "queued",
  "livemode": false,
  "sequence": 1,
  "progress": 0,
  "queuePosition": null,
  "createdAt": "2026-11-01T14:03:31.512Z",
  "startedAt": null,
  "finishedAt": null,
  "estimate": {
    "audioSeconds": 16,
    "renderMinutes": 0.267
  },
  "result": null,
  "error": null,
  "usage": null,
  "metadata": {},
  "urls": {
    "self": "https://api.map.audio/v1/jobs/job_01M6BPRE186QHP9QPYGDX5NNFP",
    "events": "https://api.map.audio/v1/jobs/job_01M6BPRE186QHP9QPYGDX5NNFP/events",
    "cancel": "https://api.map.audio/v1/jobs/job_01M6BPRE186QHP9QPYGDX5NNFP/cancel"
  }
}
400: Render too long
{
  "error": {
    "type": "invalid_request",
    "code": "render_too_long",
    "message": "This render is about 310 s (seconds 300 plus tail 10 s); a render may be at most 300 s.",
    "param": "seconds",
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#render_too_long",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}
402: Not enough render-minutes
{
  "error": {
    "type": "entitlement",
    "code": "insufficient_credits",
    "message": "This job needs 0.267 render-minutes and 0.012 remain this month; make it shorter, or buy render-minutes at https://map.audio/music.",
    "param": null,
    "details": {
      "needed": 0.267,
      "remaining": 0.012
    },
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#insufficient_credits",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}
403: Terms not accepted
{
  "error": {
    "type": "entitlement",
    "code": "terms_required",
    "message": "This account has not accepted the prototype terms (2026-11-01-prototype), which work needs. Read and accept them at https://map.audio/music, or send POST /v1/account/terms with {\"accept\": \"2026-11-01-prototype\"} (over MCP, the accept_terms tool).",
    "param": null,
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#terms_required",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 200 The finished job, when it ends within `Prefer: wait`., 202 The queued job; poll `urls.self`, stream `urls.events`, or wait for a webhook., 400 Render too long, 402 Not enough render-minutes, 403 Terms not accepted, 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, preset_not_found, preset_not_served, variation_not_found, quality_unavailable, render_too_long, not_found, concurrency_limit, insufficient_credits, idempotency_key_reused, idempotency_in_flight, queue_unavailable, invalid_request, unsupported_media_type, payload_too_large.

View as Markdown

POST/v1/arrangements

createArrangement

Fit a cutdown or check a DJ set

Plan a render without rendering. cutdown fits one preset (from source or a stored plan) to a length in seconds as a DJ set over its variations; set checks a DJ set you wrote: references, variations, lengths and transitions. The answer is the set in preset references, its tempo and length, and each item's start in bars and seconds. It costs nothing; render the set with POST /v1/dj/set, or a cutdown as an item of POST /v1/renders.

  • Auth: Authorization: Bearer with an API key or a map.audio access token.
  • MCP tool: create_arrangement
createArrangement body
FieldTypeRequiredDescription
sourceobjectnoThe preset a cutdown fits; give source or plan.
source.presetstringyesA factory preset pam:factory/<slug>, or its bare slug. At most 200 characters.
source.variationintegernoA 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.
planstringnoA stored plan whose base preset and tempo a cutdown fits. Matches ^plan_.
cutdownobjectnoFit the preset to about this many seconds, as an opening, a main section and an ending over its variations.
cutdown.secondsnumberyesFrom 5 to 300.
setobjectnoA DJ set to check: queue lists its items in play order, each naming a factory preset (presetPath), its variation (variationIndex, counted from 0), its length in bars and the transition into it. GET /v1/transition-presets lists the transitions and the set schema's definitions.
curl
curl -sS "https://api.map.audio/v1/arrangements" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01" \
  -H "Content-Type: application/json" \
  -d '{"source":{"preset":"pam:factory/thaw"},"cutdown":{"seconds":30}}'
Request: Fit Thaw to about 30 seconds
{
  "source": {
    "preset": "pam:factory/thaw"
  },
  "cutdown": {
    "seconds": 30
  }
}
Request: Check a three-preset set
{
  "set": {
    "queue": [
      {
        "presetPath": "pam:factory/acid-sprinkle",
        "bars": 16
      },
      {
        "presetPath": "pam:factory/teknochonic",
        "variationIndex": 1,
        "bars": 16,
        "transition": {
          "preset": "blend",
          "bars": 8
        }
      },
      {
        "presetPath": "pam:factory/breakbeatrcool",
        "variationIndex": 2,
        "bars": 16,
        "transition": {
          "preset": "drop"
        }
      }
    ],
    "tempo": {
      "bpm": 124
    }
  }
}
200: Thaw fitted to 30.9 seconds
{
  "object": "arrangement",
  "set": {
    "queue": [
      {
        "presetPath": "pam:factory/thaw",
        "variationIndex": 0,
        "bars": 4
      },
      {
        "presetPath": "pam:factory/thaw",
        "variationIndex": 3,
        "bars": 9,
        "transition": {
          "preset": "blend",
          "bars": 2
        }
      },
      {
        "presetPath": "pam:factory/thaw",
        "variationIndex": 5,
        "bars": 4,
        "transition": {
          "preset": "blend",
          "bars": 2
        }
      }
    ],
    "tempo": {
      "bpm": 132
    }
  },
  "seconds": 30.909,
  "bpm": 132,
  "bars": 17,
  "boundaries": [
    {
      "index": 0,
      "preset": "pam:factory/thaw",
      "variation": 1,
      "startBar": 0,
      "startSeconds": 0,
      "bars": 4
    },
    {
      "index": 1,
      "preset": "pam:factory/thaw",
      "variation": 4,
      "startBar": 4,
      "startSeconds": 7.273,
      "bars": 9
    },
    {
      "index": 2,
      "preset": "pam:factory/thaw",
      "variation": 6,
      "startBar": 13,
      "startSeconds": 23.636,
      "bars": 4
    }
  ]
}
400: Unknown transition preset
{
  "error": {
    "type": "invalid_request",
    "code": "dj_unknown_transition_preset",
    "message": "Unknown transition preset swoosh; GET /v1/transition-presets lists the ones a render can use.",
    "param": "set.queue[1].transition.preset",
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#dj_unknown_transition_preset",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 200 The arrangement., 400 Unknown transition preset, 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, preset_not_found, preset_not_served, variation_not_found, not_found, dj_invalid_set, dj_offline_unsupported, dj_preset_missing, dj_unknown_transition_preset, invalid_request, unsupported_media_type, payload_too_large, idempotency_key_unsupported.

View as Markdown

Commands

PAM's engine commands as endpoints: audio analysis and editing, preset renders, effects, mastering, headless state, DJ sets, patterns and drum synthesis. Body fields use the same names as the commands' MCP arguments.

POST/v1/audio/analyze

audioAnalyze

Measure audio loudness and peaks (BS.1770).

Measure audio this account holds, such as a render's master: loudness (BS.1770), true peak, spectrum, stereo image, tempo, key, sections and defects. Send file ids from a job's result.outputs; the measurements come back in result.command, under files when you send more than one. Run it on a render before you keep or deliver it, or to compare seeds. Free: it counts in GET /v1/usage, never in render-minutes. Answers 200 with the finished job when it ends within Prefer: wait=N (30 s unless sent, at most 60), else 202 with the job to poll.

  • Auth: Authorization: Bearer with an API key or a map.audio access token.
  • Send Prefer: wait=N (0 to 60) to receive the finished job when it ends within N seconds.
  • Send Idempotency-Key to retry safely: the same key and body return the same result for 24 hours.
  • MCP tool: audio_analyze
audioAnalyze body
FieldTypeRequiredDescription
filesarray of stringyesIds (file_…) of WAV or FLAC audio this account holds, at most 16. 1 to 16 items.
peaksbooleannoInclude the existing 48-bin RMS envelope.
pitchbooleannoEstimate mono pitch and confidence.
classbooleannoClassify the mono sample and report measured features.
spectrumbooleannoLong-term third-octave spectrum of mid and side, and each band's energy share (sub, low, lowMid, mid, highMid, air), relative to the file's total energy from 20 Hz to 20 kHz.
stereobooleannoSide minus mid and L/R correlation per band, and the mono fold-down's loudness difference.
hpssbooleannoHarmonic, percussive and residual energy shares from the Transient card's spectral split (HpssCore, FIRM).
sectionsbooleannoSection boundaries from Foote novelty over third-octave features, with each section's loudness and true peak.
transientsbooleannoTransient times from the sampler's transient detector.
beatsbooleannoTempo in BPM, its confidence and the first downbeat, from the DJ view's beat tracker; a tempo in the file name ("loop 92 BPM.wav") fixes the octave.
musicalKeybooleannoMusical key ("A minor") with its Camelot code and confidence, from the DJ view's key estimate.
levelsbooleannoLevel statistics: RMS, PLR (true peak minus integrated), PSR (3 s true peak minus short-term loudness, median and lowest), the loudest momentary and short-term loudness, block crest and level swing.
validitybooleannoFile defects: non-finite samples with the first frame and channel, subnormals, DC offset, clipped samples, where sound starts and ends, and the level of the last 100 ms.
timbrebooleannoTimbre: spectral centroid, spread, skewness, kurtosis and 95% rolloff in Hz, flatness and crest in dB (median and 90th percentile over the frames within 60 dB of the loudest) across 20 Hz-20 kHz and per broad band, MFCCs 1-13 (mean and standard deviation) and each pitch class's share of the power (chroma, C first).
comparestringnoCompare with a reference file at the same rate, such as a render's input, lined up by latency: the null raw, after one best gain and after the best linear filter, the largest and RMS sample difference, the residual per broad band, gain and coherence per third octave, the envelope change per band, and MFCC and chroma distances. The id (file_…) of WAV or FLAC audio this account holds: a render output, or an upload once uploads open. Matches ^file_[0-9A-HJKMNP-TV-Z]{26}$.
latencyintegernoFrames the file lags the compare reference by, such as a render's latencySamples. From -8388608 to 8388608. Default 0.
thdnumbernoA steady tone's distortion at this frequency in Hz, over the whole file: harmonics in dBc, THD, THD+N, the even harmonics' share and the worst spur. From 1 to 192000.
imdstringnoA steady twin tone's intermodulation, its two frequencies in Hz as 19000,20000: the difference tone and all products against the pair.
windownumbernoAdds a per-window series of spectrum, stereo and hpss values, this many seconds a window, at most 256 windows. From 0.5 to 3600.
metadatamap of stringnoUp to 20 string pairs stored with the job. At most 20 entries.
curl
curl -sS "https://api.map.audio/v1/audio/analyze" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01" \
  -H "Prefer: wait=30" \
  -H "Content-Type: application/json" \
  -d '{"files":["file_01M6BPRK0M34NBP2XKJ1RMX1TQ"],"levels":true,"validity":true}'
Request: Check a render's loudness and look for defects
{
  "files": [
    "file_01M6BPRK0M34NBP2XKJ1RMX1TQ"
  ],
  "levels": true,
  "validity": true
}
200: Finished
{
  "object": "job",
  "id": "job_01M6BPRFPCH9EBPY7B6JKM7CE1",
  "operation": "audioAnalyze",
  "status": "succeeded",
  "livemode": false,
  "sequence": 3,
  "progress": 1,
  "queuePosition": null,
  "createdAt": "2026-11-01T14:03:31.512Z",
  "startedAt": "2026-11-01T14:03:33.104Z",
  "finishedAt": "2026-11-01T14:03:41.877Z",
  "estimate": {
    "audioSeconds": 0,
    "renderMinutes": 0
  },
  "result": {
    "outputs": [],
    "seed": null,
    "command": {
      "ok": true,
      "path": "file_01M6BPRK0M34NBP2XKJ1RMX1TQ",
      "format": "wav",
      "sampleRate": 48000,
      "channels": 2,
      "durationSeconds": 16,
      "integratedLufs": -9.6,
      "loudnessRange": 3.8,
      "truePeakDb": -0.7,
      "samplePeakDb": -1.1,
      "levels": {
        "rmsDbfs": -11.4,
        "plrDb": 8.9,
        "psrDb": 7.6,
        "minPsrDb": 5.2,
        "maxMomentaryLufs": -6.9,
        "maxShortTermLufs": -8.3,
        "crestDb": 10.3,
        "swingDb": 6.1
      },
      "validity": {
        "nonFinite": {
          "count": 0,
          "firstFrame": null,
          "firstChannel": null,
          "firstSeconds": null
        },
        "subnormals": 0,
        "dc": [
          0.0001,
          -0.0001
        ],
        "dcDbfs": -80,
        "clipping": {
          "threshold": 0.99997,
          "samples": 0,
          "firstSeconds": null
        },
        "firstAudibleSeconds": 0,
        "lastAudibleSeconds": 15.98,
        "tailRmsDbfs": -31.2
      }
    },
    "provenance": null
  },
  "error": null,
  "usage": {
    "renderMinutes": 0,
    "audioSeconds": 0,
    "computeMs": 184
  },
  "metadata": {},
  "urls": {
    "self": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1",
    "events": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/events",
    "cancel": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/cancel"
  }
}
202: Still running
{
  "object": "job",
  "id": "job_01M6BPRFPCH9EBPY7B6JKM7CE1",
  "operation": "audioAnalyze",
  "status": "running",
  "livemode": false,
  "sequence": 2,
  "progress": 0,
  "queuePosition": null,
  "createdAt": "2026-11-01T14:03:31.512Z",
  "startedAt": "2026-11-01T14:03:33.104Z",
  "finishedAt": null,
  "estimate": {
    "audioSeconds": 0,
    "renderMinutes": 0
  },
  "result": null,
  "error": null,
  "usage": null,
  "metadata": {},
  "urls": {
    "self": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1",
    "events": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/events",
    "cancel": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/cancel"
  }
}
404: Not found
{
  "error": {
    "type": "not_found",
    "code": "not_found",
    "message": "No file with that id; GET /v1/files lists this account's files.",
    "param": "files[0]",
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#not_found",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 200 The finished job: `result.outputs` link each file it wrote and `result.command` is the engine's own result., 202 The job, still running when `Prefer: wait` ran out; poll `urls.self`., 404 Not found, default Any other error: `error.code` names it, `error.param` the field at fault, and `error.docUrl` its entry in the error catalogue..

Errors: invalid_request, unsupported_media_type, payload_too_large, terms_required, concurrency_limit, idempotency_key_reused, idempotency_in_flight, queue_unavailable, not_found, file_not_ready, file_expired, uploads_disabled.

View as Markdown

POST/v1/audio/normalize

audioNormalize

Normalize loudness and verify a true-peak ceiling.

Bring a file to a loudness target under a true-peak ceiling, for a platform's delivery spec (-14 LUFS and -1 dBTP unless you send others). Writes a new WAV and reports the loudness it reached; the source file stays as it was. Free: it counts in GET /v1/usage, never in render-minutes. Answers 200 with the finished job when it ends within Prefer: wait=N (30 s unless sent, at most 60), else 202 with the job to poll.

  • Auth: Authorization: Bearer with an API key or a map.audio access token.
  • Send Prefer: wait=N (0 to 60) to receive the finished job when it ends within N seconds.
  • Send Idempotency-Key to retry safely: the same key and body return the same result for 24 hours.
  • MCP tool: audio_normalize
audioNormalize body
FieldTypeRequiredDescription
filestringyesThe id (file_…) of WAV or FLAC audio this account holds: a render output, or an upload once uploads open. Matches ^file_[0-9A-HJKMNP-TV-Z]{26}$.
lufsnumbernoTarget integrated LUFS; achieved loudness is reported if the peak ceiling prevents the target. From -60 to 0. Default -14.
tpnumbernoMaximum measured true peak in dBTP. From -24 to 0. Default -1.
metadatamap of stringnoUp to 20 string pairs stored with the job. At most 20 entries.
curl
curl -sS "https://api.map.audio/v1/audio/normalize" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01" \
  -H "Prefer: wait=30" \
  -H "Content-Type: application/json" \
  -d '{"file":"file_01M6BPRK0M34NBP2XKJ1RMX1TQ","lufs":-14,"tp":-1}'
Request: Normalize a render to -14 LUFS with a -1 dBTP ceiling
{
  "file": "file_01M6BPRK0M34NBP2XKJ1RMX1TQ",
  "lufs": -14,
  "tp": -1
}
200: Finished
{
  "object": "job",
  "id": "job_01M6BPRFPCH9EBPY7B6JKM7CE1",
  "operation": "audioNormalize",
  "status": "succeeded",
  "livemode": false,
  "sequence": 3,
  "progress": 1,
  "queuePosition": null,
  "createdAt": "2026-11-01T14:03:31.512Z",
  "startedAt": "2026-11-01T14:03:33.104Z",
  "finishedAt": "2026-11-01T14:03:41.877Z",
  "estimate": {
    "audioSeconds": 0,
    "renderMinutes": 0
  },
  "result": {
    "outputs": [
      {
        "role": "master",
        "name": null,
        "cell": null,
        "file": "file_01M6BPRMNR7PYGFNA66BX2YJ8M",
        "sha256": "13d41d922519699fc14a7587130eceee7d0f149414350000578de1564866a0d4",
        "bytes": 4608044,
        "format": "wav",
        "sampleRate": 48000,
        "durationSeconds": 16,
        "url": "https://api.map.audio/v1/download/file_01M6BPRMNR7PYGFNA66BX2YJ8M?expires=1793545422&signature=GQ2GkmPjqXuxxBSSM4NKBCY7OjU7w3YSeZBrCoxxtbY",
        "expiresAt": "2026-11-01T15:03:42.000Z"
      }
    ],
    "seed": null,
    "command": {
      "ok": true,
      "wavPath": "file_01M6BPRMNR7PYGFNA66BX2YJ8M",
      "sampleRate": 48000,
      "channels": 2,
      "durationSeconds": 16,
      "integratedLufs": -14,
      "truePeakDb": -1.4,
      "targetReached": true
    },
    "provenance": {
      "object": "provenance",
      "id": "prov_01M6BPRVA8ZC7F7J737SQ0EPN2",
      "jobId": "job_01M6BPRFPCH9EBPY7B6JKM7CE1",
      "createdAt": "2026-11-01T14:03:41.877Z",
      "engine": {
        "product": "pam",
        "version": null,
        "runtime": "native-linux-x86_64",
        "image": "registry.cloudflare.com/c7c2e61448617e81ced650f444fb6787/pam-render@sha256:5c5ffe3fabc103e277280fbd65a08988d31361f00fe7857e36f603d67bcec42d"
      },
      "seed": null,
      "presets": [],
      "packs": [],
      "userFiles": [],
      "inputs": [
        {
          "file": "file_01M6BPRK0M34NBP2XKJ1RMX1TQ",
          "sha256": "5a3485b7a3221be5f7ead6ab953cbc198988a7246158215b32bb937acbd3852b"
        }
      ],
      "outputs": [
        {
          "file": "file_01M6BPRMNR7PYGFNA66BX2YJ8M",
          "sha256": "13d41d922519699fc14a7587130eceee7d0f149414350000578de1564866a0d4"
        }
      ],
      "planner": null,
      "contracts": {
        "api": "2026-11-01",
        "pam.cli": 1
      },
      "aiModels": [],
      "audioByModel": false,
      "license": {
        "id": "lic_api_prototype_test",
        "commercialUse": false,
        "attribution": true
      },
      "kid": "6c2f0a9d4b7e1358",
      "signature": "ed25519:LEVZHpOHj8BMGZgJh-_Y7SmKbqDlBDR8LqY-XelU6GYK8lntZqg3rRK4b3BH8cy25bK0iWzOXFXmkiGHEYue7A"
    }
  },
  "error": null,
  "usage": {
    "renderMinutes": 0,
    "audioSeconds": 16,
    "computeMs": 6273
  },
  "metadata": {},
  "urls": {
    "self": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1",
    "events": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/events",
    "cancel": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/cancel"
  }
}
202: Still running
{
  "object": "job",
  "id": "job_01M6BPRFPCH9EBPY7B6JKM7CE1",
  "operation": "audioNormalize",
  "status": "running",
  "livemode": false,
  "sequence": 2,
  "progress": 0,
  "queuePosition": null,
  "createdAt": "2026-11-01T14:03:31.512Z",
  "startedAt": "2026-11-01T14:03:33.104Z",
  "finishedAt": null,
  "estimate": {
    "audioSeconds": 0,
    "renderMinutes": 0
  },
  "result": null,
  "error": null,
  "usage": null,
  "metadata": {},
  "urls": {
    "self": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1",
    "events": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/events",
    "cancel": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/cancel"
  }
}
410: File no longer stored
{
  "error": {
    "type": "gone",
    "code": "file_expired",
    "message": "File file_01M6BPRK0M34NBP2XKJ1RMX1TQ expired at 2026-11-08T14:03:41.877Z; render it again.",
    "param": "file",
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#file_expired",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 200 The finished job: `result.outputs` link each file it wrote and `result.command` is the engine's own result., 202 The job, still running when `Prefer: wait` ran out; poll `urls.self`., 410 File no longer stored, default Any other error: `error.code` names it, `error.param` the field at fault, and `error.docUrl` its entry in the error catalogue..

Errors: invalid_request, unsupported_media_type, payload_too_large, terms_required, concurrency_limit, idempotency_key_reused, idempotency_in_flight, queue_unavailable, not_found, file_not_ready, file_expired, uploads_disabled.

View as Markdown

POST/v1/audio/repitch

audioRepitch

Render varispeed pitch shifting using the browser repitch core.

Shift a file's pitch by varispeed, as a turntable does: tempo and length move with the pitch, so 12 semitones down plays at half speed. Writes a new WAV. Free: it counts in GET /v1/usage, never in render-minutes. Answers 200 with the finished job when it ends within Prefer: wait=N (30 s unless sent, at most 60), else 202 with the job to poll.

  • Auth: Authorization: Bearer with an API key or a map.audio access token.
  • Send Prefer: wait=N (0 to 60) to receive the finished job when it ends within N seconds.
  • Send Idempotency-Key to retry safely: the same key and body return the same result for 24 hours.
  • MCP tool: audio_repitch
audioRepitch body
FieldTypeRequiredDescription
filestringyesThe id (file_…) of WAV or FLAC audio this account holds: a render output, or an upload once uploads open. Matches ^file_[0-9A-HJKMNP-TV-Z]{26}$.
semitonesnumbernoVarispeed pitch shift; duration changes. From -24 to 24. Default 0.
centsnumbernoAdditional pitch shift in cents. From -100 to 100. Default 0.
metadatamap of stringnoUp to 20 string pairs stored with the job. At most 20 entries.
curl
curl -sS "https://api.map.audio/v1/audio/repitch" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01" \
  -H "Prefer: wait=30" \
  -H "Content-Type: application/json" \
  -d '{"file":"file_01M6BPRK0M34NBP2XKJ1RMX1TQ","semitones":-2}'
Request: Drop a loop two semitones
{
  "file": "file_01M6BPRK0M34NBP2XKJ1RMX1TQ",
  "semitones": -2
}
200: Finished
{
  "object": "job",
  "id": "job_01M6BPRFPCH9EBPY7B6JKM7CE1",
  "operation": "audioRepitch",
  "status": "succeeded",
  "livemode": false,
  "sequence": 3,
  "progress": 1,
  "queuePosition": null,
  "createdAt": "2026-11-01T14:03:31.512Z",
  "startedAt": "2026-11-01T14:03:33.104Z",
  "finishedAt": "2026-11-01T14:03:41.877Z",
  "estimate": {
    "audioSeconds": 0,
    "renderMinutes": 0
  },
  "result": {
    "outputs": [
      {
        "role": "master",
        "name": null,
        "cell": null,
        "file": "file_01M6BPRMNR7PYGFNA66BX2YJ8M",
        "sha256": "13d41d922519699fc14a7587130eceee7d0f149414350000578de1564866a0d4",
        "bytes": 5172236,
        "format": "wav",
        "sampleRate": 48000,
        "durationSeconds": 17.959,
        "url": "https://api.map.audio/v1/download/file_01M6BPRMNR7PYGFNA66BX2YJ8M?expires=1793545422&signature=GQ2GkmPjqXuxxBSSM4NKBCY7OjU7w3YSeZBrCoxxtbY",
        "expiresAt": "2026-11-01T15:03:42.000Z"
      }
    ],
    "seed": null,
    "command": {
      "ok": true,
      "wavPath": "file_01M6BPRMNR7PYGFNA66BX2YJ8M",
      "sampleRate": 48000,
      "channels": 2,
      "durationSeconds": 17.959
    },
    "provenance": {
      "object": "provenance",
      "id": "prov_01M6BPRVA8ZC7F7J737SQ0EPN2",
      "jobId": "job_01M6BPRFPCH9EBPY7B6JKM7CE1",
      "createdAt": "2026-11-01T14:03:41.877Z",
      "engine": {
        "product": "pam",
        "version": null,
        "runtime": "native-linux-x86_64",
        "image": "registry.cloudflare.com/c7c2e61448617e81ced650f444fb6787/pam-render@sha256:5c5ffe3fabc103e277280fbd65a08988d31361f00fe7857e36f603d67bcec42d"
      },
      "seed": null,
      "presets": [],
      "packs": [],
      "userFiles": [],
      "inputs": [
        {
          "file": "file_01M6BPRK0M34NBP2XKJ1RMX1TQ",
          "sha256": "5a3485b7a3221be5f7ead6ab953cbc198988a7246158215b32bb937acbd3852b"
        }
      ],
      "outputs": [
        {
          "file": "file_01M6BPRMNR7PYGFNA66BX2YJ8M",
          "sha256": "13d41d922519699fc14a7587130eceee7d0f149414350000578de1564866a0d4"
        }
      ],
      "planner": null,
      "contracts": {
        "api": "2026-11-01",
        "pam.cli": 1
      },
      "aiModels": [],
      "audioByModel": false,
      "license": {
        "id": "lic_api_prototype_test",
        "commercialUse": false,
        "attribution": true
      },
      "kid": "6c2f0a9d4b7e1358",
      "signature": "ed25519:LEVZHpOHj8BMGZgJh-_Y7SmKbqDlBDR8LqY-XelU6GYK8lntZqg3rRK4b3BH8cy25bK0iWzOXFXmkiGHEYue7A"
    }
  },
  "error": null,
  "usage": {
    "renderMinutes": 0,
    "audioSeconds": 17.959,
    "computeMs": 6273
  },
  "metadata": {},
  "urls": {
    "self": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1",
    "events": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/events",
    "cancel": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/cancel"
  }
}
202: Still running
{
  "object": "job",
  "id": "job_01M6BPRFPCH9EBPY7B6JKM7CE1",
  "operation": "audioRepitch",
  "status": "running",
  "livemode": false,
  "sequence": 2,
  "progress": 0,
  "queuePosition": null,
  "createdAt": "2026-11-01T14:03:31.512Z",
  "startedAt": "2026-11-01T14:03:33.104Z",
  "finishedAt": null,
  "estimate": {
    "audioSeconds": 0,
    "renderMinutes": 0
  },
  "result": null,
  "error": null,
  "usage": null,
  "metadata": {},
  "urls": {
    "self": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1",
    "events": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/events",
    "cancel": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/cancel"
  }
}
400: Invalid request
{
  "error": {
    "type": "invalid_request",
    "code": "invalid_request",
    "message": "semitones must be at most 24; got 30.",
    "param": "semitones",
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#invalid_request",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 200 The finished job: `result.outputs` link each file it wrote and `result.command` is the engine's own result., 202 The job, still running when `Prefer: wait` ran out; poll `urls.self`., 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: invalid_request, unsupported_media_type, payload_too_large, terms_required, concurrency_limit, idempotency_key_reused, idempotency_in_flight, queue_unavailable, not_found, file_not_ready, file_expired, uploads_disabled.

View as Markdown

POST/v1/audio/trim

audioTrim

Trim a sample by time using the shared sample-edit core.

Cut a file to a time range in seconds, such as a loop's first bars or a hit without its lead-in. Writes a new WAV. Free: it counts in GET /v1/usage, never in render-minutes. Answers 200 with the finished job when it ends within Prefer: wait=N (30 s unless sent, at most 60), else 202 with the job to poll.

  • Auth: Authorization: Bearer with an API key or a map.audio access token.
  • Send Prefer: wait=N (0 to 60) to receive the finished job when it ends within N seconds.
  • Send Idempotency-Key to retry safely: the same key and body return the same result for 24 hours.
  • MCP tool: audio_trim
audioTrim body
FieldTypeRequiredDescription
filestringyesThe id (file_…) of WAV or FLAC audio this account holds: a render output, or an upload once uploads open. Matches ^file_[0-9A-HJKMNP-TV-Z]{26}$.
startnumbernoTrim start in seconds. From 0 to 86400. Default 0.
endnumbernoTrim end in seconds; absent uses file end. From 0 to 86400.
metadatamap of stringnoUp to 20 string pairs stored with the job. At most 20 entries.
curl
curl -sS "https://api.map.audio/v1/audio/trim" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01" \
  -H "Prefer: wait=30" \
  -H "Content-Type: application/json" \
  -d '{"file":"file_01M6BPRK0M34NBP2XKJ1RMX1TQ","start":0,"end":8}'
Request: Keep the first 8 seconds
{
  "file": "file_01M6BPRK0M34NBP2XKJ1RMX1TQ",
  "start": 0,
  "end": 8
}
200: Finished
{
  "object": "job",
  "id": "job_01M6BPRFPCH9EBPY7B6JKM7CE1",
  "operation": "audioTrim",
  "status": "succeeded",
  "livemode": false,
  "sequence": 3,
  "progress": 1,
  "queuePosition": null,
  "createdAt": "2026-11-01T14:03:31.512Z",
  "startedAt": "2026-11-01T14:03:33.104Z",
  "finishedAt": "2026-11-01T14:03:41.877Z",
  "estimate": {
    "audioSeconds": 0,
    "renderMinutes": 0
  },
  "result": {
    "outputs": [
      {
        "role": "master",
        "name": null,
        "cell": null,
        "file": "file_01M6BPRMNR7PYGFNA66BX2YJ8M",
        "sha256": "13d41d922519699fc14a7587130eceee7d0f149414350000578de1564866a0d4",
        "bytes": 2304044,
        "format": "wav",
        "sampleRate": 48000,
        "durationSeconds": 8,
        "url": "https://api.map.audio/v1/download/file_01M6BPRMNR7PYGFNA66BX2YJ8M?expires=1793545422&signature=GQ2GkmPjqXuxxBSSM4NKBCY7OjU7w3YSeZBrCoxxtbY",
        "expiresAt": "2026-11-01T15:03:42.000Z"
      }
    ],
    "seed": null,
    "command": {
      "ok": true,
      "wavPath": "file_01M6BPRMNR7PYGFNA66BX2YJ8M",
      "sampleRate": 48000,
      "channels": 2,
      "durationSeconds": 8
    },
    "provenance": {
      "object": "provenance",
      "id": "prov_01M6BPRVA8ZC7F7J737SQ0EPN2",
      "jobId": "job_01M6BPRFPCH9EBPY7B6JKM7CE1",
      "createdAt": "2026-11-01T14:03:41.877Z",
      "engine": {
        "product": "pam",
        "version": null,
        "runtime": "native-linux-x86_64",
        "image": "registry.cloudflare.com/c7c2e61448617e81ced650f444fb6787/pam-render@sha256:5c5ffe3fabc103e277280fbd65a08988d31361f00fe7857e36f603d67bcec42d"
      },
      "seed": null,
      "presets": [],
      "packs": [],
      "userFiles": [],
      "inputs": [
        {
          "file": "file_01M6BPRK0M34NBP2XKJ1RMX1TQ",
          "sha256": "5a3485b7a3221be5f7ead6ab953cbc198988a7246158215b32bb937acbd3852b"
        }
      ],
      "outputs": [
        {
          "file": "file_01M6BPRMNR7PYGFNA66BX2YJ8M",
          "sha256": "13d41d922519699fc14a7587130eceee7d0f149414350000578de1564866a0d4"
        }
      ],
      "planner": null,
      "contracts": {
        "api": "2026-11-01",
        "pam.cli": 1
      },
      "aiModels": [],
      "audioByModel": false,
      "license": {
        "id": "lic_api_prototype_test",
        "commercialUse": false,
        "attribution": true
      },
      "kid": "6c2f0a9d4b7e1358",
      "signature": "ed25519:LEVZHpOHj8BMGZgJh-_Y7SmKbqDlBDR8LqY-XelU6GYK8lntZqg3rRK4b3BH8cy25bK0iWzOXFXmkiGHEYue7A"
    }
  },
  "error": null,
  "usage": {
    "renderMinutes": 0,
    "audioSeconds": 8,
    "computeMs": 6273
  },
  "metadata": {},
  "urls": {
    "self": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1",
    "events": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/events",
    "cancel": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/cancel"
  }
}
202: Still running
{
  "object": "job",
  "id": "job_01M6BPRFPCH9EBPY7B6JKM7CE1",
  "operation": "audioTrim",
  "status": "running",
  "livemode": false,
  "sequence": 2,
  "progress": 0,
  "queuePosition": null,
  "createdAt": "2026-11-01T14:03:31.512Z",
  "startedAt": "2026-11-01T14:03:33.104Z",
  "finishedAt": null,
  "estimate": {
    "audioSeconds": 0,
    "renderMinutes": 0
  },
  "result": null,
  "error": null,
  "usage": null,
  "metadata": {},
  "urls": {
    "self": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1",
    "events": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/events",
    "cancel": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/cancel"
  }
}
400: Invalid request
{
  "error": {
    "type": "invalid_request",
    "code": "invalid_request",
    "message": "end (2 s) must be after start (4 s).",
    "param": "end",
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#invalid_request",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 200 The finished job: `result.outputs` link each file it wrote and `result.command` is the engine's own result., 202 The job, still running when `Prefer: wait` ran out; poll `urls.self`., 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: invalid_request, unsupported_media_type, payload_too_large, terms_required, concurrency_limit, idempotency_key_reused, idempotency_in_flight, queue_unavailable, not_found, file_not_ready, file_expired, uploads_disabled.

View as Markdown

POST/v1/audio/gain

audioGain

Apply sample gain using the shared sample-edit core.

Raise or lower a file's level by a number of decibels; samples past full scale clip. For a loudness target, POST /v1/audio/normalize measures and sets the level for you. Free: it counts in GET /v1/usage, never in render-minutes. Answers 200 with the finished job when it ends within Prefer: wait=N (30 s unless sent, at most 60), else 202 with the job to poll.

  • Auth: Authorization: Bearer with an API key or a map.audio access token.
  • Send Prefer: wait=N (0 to 60) to receive the finished job when it ends within N seconds.
  • Send Idempotency-Key to retry safely: the same key and body return the same result for 24 hours.
  • MCP tool: audio_gain
audioGain body
FieldTypeRequiredDescription
filestringyesThe id (file_…) of WAV or FLAC audio this account holds: a render output, or an upload once uploads open. Matches ^file_[0-9A-HJKMNP-TV-Z]{26}$.
dbnumberyesGain in decibels; samples exceeding full scale clip in the output WAV. From -96 to 48.
metadatamap of stringnoUp to 20 string pairs stored with the job. At most 20 entries.
curl
curl -sS "https://api.map.audio/v1/audio/gain" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01" \
  -H "Prefer: wait=30" \
  -H "Content-Type: application/json" \
  -d '{"file":"file_01M6BPRK0M34NBP2XKJ1RMX1TQ","db":-3}'
Request: Turn a render down 3 dB
{
  "file": "file_01M6BPRK0M34NBP2XKJ1RMX1TQ",
  "db": -3
}
200: Finished
{
  "object": "job",
  "id": "job_01M6BPRFPCH9EBPY7B6JKM7CE1",
  "operation": "audioGain",
  "status": "succeeded",
  "livemode": false,
  "sequence": 3,
  "progress": 1,
  "queuePosition": null,
  "createdAt": "2026-11-01T14:03:31.512Z",
  "startedAt": "2026-11-01T14:03:33.104Z",
  "finishedAt": "2026-11-01T14:03:41.877Z",
  "estimate": {
    "audioSeconds": 0,
    "renderMinutes": 0
  },
  "result": {
    "outputs": [
      {
        "role": "master",
        "name": null,
        "cell": null,
        "file": "file_01M6BPRMNR7PYGFNA66BX2YJ8M",
        "sha256": "13d41d922519699fc14a7587130eceee7d0f149414350000578de1564866a0d4",
        "bytes": 4608044,
        "format": "wav",
        "sampleRate": 48000,
        "durationSeconds": 16,
        "url": "https://api.map.audio/v1/download/file_01M6BPRMNR7PYGFNA66BX2YJ8M?expires=1793545422&signature=GQ2GkmPjqXuxxBSSM4NKBCY7OjU7w3YSeZBrCoxxtbY",
        "expiresAt": "2026-11-01T15:03:42.000Z"
      }
    ],
    "seed": null,
    "command": {
      "ok": true,
      "wavPath": "file_01M6BPRMNR7PYGFNA66BX2YJ8M",
      "sampleRate": 48000,
      "channels": 2,
      "durationSeconds": 16
    },
    "provenance": {
      "object": "provenance",
      "id": "prov_01M6BPRVA8ZC7F7J737SQ0EPN2",
      "jobId": "job_01M6BPRFPCH9EBPY7B6JKM7CE1",
      "createdAt": "2026-11-01T14:03:41.877Z",
      "engine": {
        "product": "pam",
        "version": null,
        "runtime": "native-linux-x86_64",
        "image": "registry.cloudflare.com/c7c2e61448617e81ced650f444fb6787/pam-render@sha256:5c5ffe3fabc103e277280fbd65a08988d31361f00fe7857e36f603d67bcec42d"
      },
      "seed": null,
      "presets": [],
      "packs": [],
      "userFiles": [],
      "inputs": [
        {
          "file": "file_01M6BPRK0M34NBP2XKJ1RMX1TQ",
          "sha256": "5a3485b7a3221be5f7ead6ab953cbc198988a7246158215b32bb937acbd3852b"
        }
      ],
      "outputs": [
        {
          "file": "file_01M6BPRMNR7PYGFNA66BX2YJ8M",
          "sha256": "13d41d922519699fc14a7587130eceee7d0f149414350000578de1564866a0d4"
        }
      ],
      "planner": null,
      "contracts": {
        "api": "2026-11-01",
        "pam.cli": 1
      },
      "aiModels": [],
      "audioByModel": false,
      "license": {
        "id": "lic_api_prototype_test",
        "commercialUse": false,
        "attribution": true
      },
      "kid": "6c2f0a9d4b7e1358",
      "signature": "ed25519:LEVZHpOHj8BMGZgJh-_Y7SmKbqDlBDR8LqY-XelU6GYK8lntZqg3rRK4b3BH8cy25bK0iWzOXFXmkiGHEYue7A"
    }
  },
  "error": null,
  "usage": {
    "renderMinutes": 0,
    "audioSeconds": 16,
    "computeMs": 6273
  },
  "metadata": {},
  "urls": {
    "self": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1",
    "events": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/events",
    "cancel": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/cancel"
  }
}
202: Still running
{
  "object": "job",
  "id": "job_01M6BPRFPCH9EBPY7B6JKM7CE1",
  "operation": "audioGain",
  "status": "running",
  "livemode": false,
  "sequence": 2,
  "progress": 0,
  "queuePosition": null,
  "createdAt": "2026-11-01T14:03:31.512Z",
  "startedAt": "2026-11-01T14:03:33.104Z",
  "finishedAt": null,
  "estimate": {
    "audioSeconds": 0,
    "renderMinutes": 0
  },
  "result": null,
  "error": null,
  "usage": null,
  "metadata": {},
  "urls": {
    "self": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1",
    "events": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/events",
    "cancel": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/cancel"
  }
}
400: Invalid request
{
  "error": {
    "type": "invalid_request",
    "code": "invalid_request",
    "message": "db is required.",
    "param": "db",
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#invalid_request",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 200 The finished job: `result.outputs` link each file it wrote and `result.command` is the engine's own result., 202 The job, still running when `Prefer: wait` ran out; poll `urls.self`., 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: invalid_request, unsupported_media_type, payload_too_large, terms_required, concurrency_limit, idempotency_key_reused, idempotency_in_flight, queue_unavailable, not_found, file_not_ready, file_expired, uploads_disabled.

View as Markdown

POST/v1/audio/reverse

audioReverse

Reverse a sample using the shared sample-edit core.

Play a file backwards, for reverse cymbals, risers and transitions. Writes a new WAV. Free: it counts in GET /v1/usage, never in render-minutes. Answers 200 with the finished job when it ends within Prefer: wait=N (30 s unless sent, at most 60), else 202 with the job to poll.

  • Auth: Authorization: Bearer with an API key or a map.audio access token.
  • Send Prefer: wait=N (0 to 60) to receive the finished job when it ends within N seconds.
  • Send Idempotency-Key to retry safely: the same key and body return the same result for 24 hours.
  • MCP tool: audio_reverse
audioReverse body
FieldTypeRequiredDescription
filestringyesThe id (file_…) of WAV or FLAC audio this account holds: a render output, or an upload once uploads open. Matches ^file_[0-9A-HJKMNP-TV-Z]{26}$.
metadatamap of stringnoUp to 20 string pairs stored with the job. At most 20 entries.
curl
curl -sS "https://api.map.audio/v1/audio/reverse" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01" \
  -H "Prefer: wait=30" \
  -H "Content-Type: application/json" \
  -d '{"file":"file_01M6BPRK0M34NBP2XKJ1RMX1TQ"}'
Request: Reverse a render
{
  "file": "file_01M6BPRK0M34NBP2XKJ1RMX1TQ"
}
200: Finished
{
  "object": "job",
  "id": "job_01M6BPRFPCH9EBPY7B6JKM7CE1",
  "operation": "audioReverse",
  "status": "succeeded",
  "livemode": false,
  "sequence": 3,
  "progress": 1,
  "queuePosition": null,
  "createdAt": "2026-11-01T14:03:31.512Z",
  "startedAt": "2026-11-01T14:03:33.104Z",
  "finishedAt": "2026-11-01T14:03:41.877Z",
  "estimate": {
    "audioSeconds": 0,
    "renderMinutes": 0
  },
  "result": {
    "outputs": [
      {
        "role": "master",
        "name": null,
        "cell": null,
        "file": "file_01M6BPRMNR7PYGFNA66BX2YJ8M",
        "sha256": "13d41d922519699fc14a7587130eceee7d0f149414350000578de1564866a0d4",
        "bytes": 4608044,
        "format": "wav",
        "sampleRate": 48000,
        "durationSeconds": 16,
        "url": "https://api.map.audio/v1/download/file_01M6BPRMNR7PYGFNA66BX2YJ8M?expires=1793545422&signature=GQ2GkmPjqXuxxBSSM4NKBCY7OjU7w3YSeZBrCoxxtbY",
        "expiresAt": "2026-11-01T15:03:42.000Z"
      }
    ],
    "seed": null,
    "command": {
      "ok": true,
      "wavPath": "file_01M6BPRMNR7PYGFNA66BX2YJ8M",
      "sampleRate": 48000,
      "channels": 2,
      "durationSeconds": 16
    },
    "provenance": {
      "object": "provenance",
      "id": "prov_01M6BPRVA8ZC7F7J737SQ0EPN2",
      "jobId": "job_01M6BPRFPCH9EBPY7B6JKM7CE1",
      "createdAt": "2026-11-01T14:03:41.877Z",
      "engine": {
        "product": "pam",
        "version": null,
        "runtime": "native-linux-x86_64",
        "image": "registry.cloudflare.com/c7c2e61448617e81ced650f444fb6787/pam-render@sha256:5c5ffe3fabc103e277280fbd65a08988d31361f00fe7857e36f603d67bcec42d"
      },
      "seed": null,
      "presets": [],
      "packs": [],
      "userFiles": [],
      "inputs": [
        {
          "file": "file_01M6BPRK0M34NBP2XKJ1RMX1TQ",
          "sha256": "5a3485b7a3221be5f7ead6ab953cbc198988a7246158215b32bb937acbd3852b"
        }
      ],
      "outputs": [
        {
          "file": "file_01M6BPRMNR7PYGFNA66BX2YJ8M",
          "sha256": "13d41d922519699fc14a7587130eceee7d0f149414350000578de1564866a0d4"
        }
      ],
      "planner": null,
      "contracts": {
        "api": "2026-11-01",
        "pam.cli": 1
      },
      "aiModels": [],
      "audioByModel": false,
      "license": {
        "id": "lic_api_prototype_test",
        "commercialUse": false,
        "attribution": true
      },
      "kid": "6c2f0a9d4b7e1358",
      "signature": "ed25519:LEVZHpOHj8BMGZgJh-_Y7SmKbqDlBDR8LqY-XelU6GYK8lntZqg3rRK4b3BH8cy25bK0iWzOXFXmkiGHEYue7A"
    }
  },
  "error": null,
  "usage": {
    "renderMinutes": 0,
    "audioSeconds": 16,
    "computeMs": 6273
  },
  "metadata": {},
  "urls": {
    "self": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1",
    "events": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/events",
    "cancel": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/cancel"
  }
}
202: Still running
{
  "object": "job",
  "id": "job_01M6BPRFPCH9EBPY7B6JKM7CE1",
  "operation": "audioReverse",
  "status": "running",
  "livemode": false,
  "sequence": 2,
  "progress": 0,
  "queuePosition": null,
  "createdAt": "2026-11-01T14:03:31.512Z",
  "startedAt": "2026-11-01T14:03:33.104Z",
  "finishedAt": null,
  "estimate": {
    "audioSeconds": 0,
    "renderMinutes": 0
  },
  "result": null,
  "error": null,
  "usage": null,
  "metadata": {},
  "urls": {
    "self": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1",
    "events": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/events",
    "cancel": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/cancel"
  }
}
404: Not found
{
  "error": {
    "type": "not_found",
    "code": "not_found",
    "message": "No file with that id; GET /v1/files lists this account's files.",
    "param": "file",
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#not_found",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 200 The finished job: `result.outputs` link each file it wrote and `result.command` is the engine's own result., 202 The job, still running when `Prefer: wait` ran out; poll `urls.self`., 404 Not found, default Any other error: `error.code` names it, `error.param` the field at fault, and `error.docUrl` its entry in the error catalogue..

Errors: invalid_request, unsupported_media_type, payload_too_large, terms_required, concurrency_limit, idempotency_key_reused, idempotency_in_flight, queue_unavailable, not_found, file_not_ready, file_expired, uploads_disabled.

View as Markdown

POST/v1/preset/render

presetRender

Render a PAM preset to WAV without opening PAM.

The engine's own render command: one factory preset to one WAV, with optional stems and an input file that the preset's External cells play. POST /v1/renders is the render API for everything else (FLAC and MP3, variation and seed batches, cutdowns, quality search, previews); use this route for an input file or the exact pam preset render options. It costs render-minutes for the audio it renders: its length in minutes, at least 0.1 a render. Answers 202 with the queued job: poll GET /v1/jobs/{id}, stream GET /v1/jobs/{id}/events, or send Prefer: wait=N (at most 60 s) to get the finished job in this response.

  • Auth: Authorization: Bearer with an API key or a map.audio access token.
  • Send Prefer: wait=N (0 to 60) to receive the finished job when it ends within N seconds.
  • Send Idempotency-Key to retry safely: the same key and body return the same result for 24 hours.
  • MCP tool: preset_render
presetRender body
FieldTypeRequiredDescription
presetstringyesA factory preset reference, pam:factory/<slug> or the bare slug; GET /v1/presets lists them. At most 200 characters.
secondsnumbernoRender length in seconds; mutually exclusive with bars. Defaults to the input duration for fx and audio master. From 0.001 to 300.
barsintegernoLength in bars (1..64): pattern generation uses four beats and defaults to 1; preset rendering uses the preset time signature and defaults to 4. From 1 to 64.
sampleRateintegernoOutput sample rate. From 22050 to 48000. Default 48000.
tailnumbernoAdditional effect tail in seconds after transport stops. From 0 to 30. Default 0.
seedintegernoReproducible seed; zero draws a random seed. From 0 to 4294967295. Default 0.
variationintegernoPreset variation, numbered from 1. From 1 to 16.
stemsbooleannoWrite each cell stem alongside the master in one render pass.
inputstringnoAudio played into the engine's input, through the PAM cells whose source is External. Without seconds or bars the render lasts as long as the input, plus tail. The id (file_…) of WAV or FLAC audio this account holds: a render output, or an upload once uploads open. Matches ^file_[0-9A-HJKMNP-TV-Z]{26}$.
metadatamap of stringnoUp to 20 string pairs stored with the job. At most 20 entries.
curl
curl -sS "https://api.map.audio/v1/preset/render" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01" \
  -H "Prefer: wait=30" \
  -H "Content-Type: application/json" \
  -d '{"preset":"pam:factory/313-disco","bars":8,"seed":42}'
Request: Render 8 bars of 313 Disco with a fixed seed
{
  "preset": "pam:factory/313-disco",
  "bars": 8,
  "seed": 42
}
200: Finished
{
  "object": "job",
  "id": "job_01M6BPRFPCH9EBPY7B6JKM7CE1",
  "operation": "presetRender",
  "status": "succeeded",
  "livemode": false,
  "sequence": 3,
  "progress": 1,
  "queuePosition": null,
  "createdAt": "2026-11-01T14:03:31.512Z",
  "startedAt": "2026-11-01T14:03:33.104Z",
  "finishedAt": "2026-11-01T14:03:41.877Z",
  "estimate": {
    "audioSeconds": 16,
    "renderMinutes": 0.267
  },
  "result": {
    "outputs": [
      {
        "role": "master",
        "name": null,
        "cell": null,
        "file": "file_01M6BPRMNR7PYGFNA66BX2YJ8M",
        "sha256": "13d41d922519699fc14a7587130eceee7d0f149414350000578de1564866a0d4",
        "bytes": 4608044,
        "format": "wav",
        "sampleRate": 48000,
        "durationSeconds": 16,
        "url": "https://api.map.audio/v1/download/file_01M6BPRMNR7PYGFNA66BX2YJ8M?expires=1793545422&signature=GQ2GkmPjqXuxxBSSM4NKBCY7OjU7w3YSeZBrCoxxtbY",
        "expiresAt": "2026-11-01T15:03:42.000Z"
      }
    ],
    "seed": 42,
    "command": {
      "ok": true,
      "wavPath": "file_01M6BPRMNR7PYGFNA66BX2YJ8M",
      "sampleRate": 48000,
      "durationSeconds": 16,
      "seed": 42,
      "stems": [],
      "latencySamples": 0
    },
    "provenance": {
      "object": "provenance",
      "id": "prov_01M6BPRVA8ZC7F7J737SQ0EPN2",
      "jobId": "job_01M6BPRFPCH9EBPY7B6JKM7CE1",
      "createdAt": "2026-11-01T14:03:41.877Z",
      "engine": {
        "product": "pam",
        "version": null,
        "runtime": "native-linux-x86_64",
        "image": "registry.cloudflare.com/c7c2e61448617e81ced650f444fb6787/pam-render@sha256:5c5ffe3fabc103e277280fbd65a08988d31361f00fe7857e36f603d67bcec42d"
      },
      "seed": 42,
      "presets": [
        {
          "ref": "pam:factory/313-disco",
          "sha256": "3afbf5dea1003b2d17385955017785a57d74c65f77f97b58cf5d7cec9794ca1c"
        }
      ],
      "packs": [],
      "userFiles": [],
      "inputs": [],
      "outputs": [
        {
          "file": "file_01M6BPRMNR7PYGFNA66BX2YJ8M",
          "sha256": "13d41d922519699fc14a7587130eceee7d0f149414350000578de1564866a0d4"
        }
      ],
      "planner": null,
      "contracts": {
        "api": "2026-11-01",
        "pam.cli": 1
      },
      "aiModels": [],
      "audioByModel": false,
      "license": {
        "id": "lic_api_prototype_test",
        "commercialUse": false,
        "attribution": true
      },
      "kid": "6c2f0a9d4b7e1358",
      "signature": "ed25519:LEVZHpOHj8BMGZgJh-_Y7SmKbqDlBDR8LqY-XelU6GYK8lntZqg3rRK4b3BH8cy25bK0iWzOXFXmkiGHEYue7A"
    }
  },
  "error": null,
  "usage": {
    "renderMinutes": 0.267,
    "audioSeconds": 16,
    "computeMs": 6273
  },
  "metadata": {},
  "urls": {
    "self": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1",
    "events": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/events",
    "cancel": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/cancel"
  }
}
202: Queued
{
  "object": "job",
  "id": "job_01M6BPRFPCH9EBPY7B6JKM7CE1",
  "operation": "presetRender",
  "status": "queued",
  "livemode": false,
  "sequence": 1,
  "progress": 0,
  "queuePosition": null,
  "createdAt": "2026-11-01T14:03:31.512Z",
  "startedAt": null,
  "finishedAt": null,
  "estimate": {
    "audioSeconds": 16,
    "renderMinutes": 0.267
  },
  "result": null,
  "error": null,
  "usage": null,
  "metadata": {},
  "urls": {
    "self": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1",
    "events": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/events",
    "cancel": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/cancel"
  }
}
402: Not enough render-minutes
{
  "error": {
    "type": "entitlement",
    "code": "insufficient_credits",
    "message": "This job needs 0.267 render-minutes and 0.012 remain this month; make it shorter, or buy render-minutes at https://map.audio/music.",
    "param": null,
    "details": {
      "needed": 0.267,
      "remaining": 0.012
    },
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#insufficient_credits",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 200 The finished job: `result.outputs` link each file it wrote and `result.command` is the engine's own result., 202 The queued job; poll `urls.self` or stream `urls.events`., 402 Not enough render-minutes, default Any other error: `error.code` names it, `error.param` the field at fault, and `error.docUrl` its entry in the error catalogue..

Errors: invalid_request, unsupported_media_type, payload_too_large, terms_required, concurrency_limit, idempotency_key_reused, idempotency_in_flight, queue_unavailable, insufficient_credits, render_too_long, preset_not_found, preset_not_served, variation_not_found, not_found, file_not_ready, file_expired, uploads_disabled.

View as Markdown

POST/v1/project/remix

projectRemix

Remix an Ableton Live set, Bitwig project, DAWproject or FL Studio project into a PAM preset built from its own samples, MIDI and sections.

Turn an uploaded DAW project (Ableton Live, Bitwig, DAWproject or FL Studio) into a PAM preset built from its own samples, MIDI and sections, returned as a .zip that holds the preset and its samples. Free: it counts in GET /v1/usage, never in render-minutes. Answers 202 with the queued job: poll GET /v1/jobs/{id}, stream GET /v1/jobs/{id}/events, or send Prefer: wait=N (at most 60 s) to get the finished job in this response. Needs uploads, which stay off until the decoder and project-reader fuzzers have run; until then it answers 403 uploads_disabled.

  • Auth: Authorization: Bearer with an API key or a map.audio access token.
  • Send Prefer: wait=N (0 to 60) to receive the finished job when it ends within N seconds.
  • Send Idempotency-Key to retry safely: the same key and body return the same result for 24 hours.
  • MCP tool: project_remix
projectRemix body
FieldTypeRequiredDescription
projectstringyesThe id (file_…) of an uploaded DAW project or zipped project folder. Matches ^file_[0-9A-HJKMNP-TV-Z]{26}$.
seedintegernoSeed for the remix variations; absent or zero derives one from the project, so the same project remixes the same way as a drop into PAM. From 0 to 4294967295. Default 0.
namestringnoPreset name; absent uses the project file name followed by Remix.
faithfulbooleannoKeep only the project's own sections; skip PAM's remix variations and song tail.
metadatamap of stringnoUp to 20 string pairs stored with the job. At most 20 entries.
curl
curl -sS "https://api.map.audio/v1/project/remix" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01" \
  -H "Prefer: wait=30" \
  -H "Content-Type: application/json" \
  -d '{"project":"file_01M6BPRR00A11F2KEPGNR7V3Q9","seed":7}'
Request: Remix an uploaded Live set with a fixed seed
{
  "project": "file_01M6BPRR00A11F2KEPGNR7V3Q9",
  "seed": 7
}
200: Finished
{
  "object": "job",
  "id": "job_01M6BPRFPCH9EBPY7B6JKM7CE1",
  "operation": "projectRemix",
  "status": "succeeded",
  "livemode": false,
  "sequence": 3,
  "progress": 1,
  "queuePosition": null,
  "createdAt": "2026-11-01T14:03:31.512Z",
  "startedAt": "2026-11-01T14:03:33.104Z",
  "finishedAt": "2026-11-01T14:03:41.877Z",
  "estimate": {
    "audioSeconds": 0,
    "renderMinutes": 0
  },
  "result": {
    "outputs": [
      {
        "role": "preset",
        "name": null,
        "cell": null,
        "file": "file_01M6BPRMNR7PYGFNA66BX2YJ8M",
        "sha256": "13d41d922519699fc14a7587130eceee7d0f149414350000578de1564866a0d4",
        "bytes": 18734,
        "format": "zip",
        "sampleRate": null,
        "durationSeconds": null,
        "url": "https://api.map.audio/v1/download/file_01M6BPRMNR7PYGFNA66BX2YJ8M?expires=1793545422&signature=GQ2GkmPjqXuxxBSSM4NKBCY7OjU7w3YSeZBrCoxxtbY",
        "expiresAt": "2026-11-01T15:03:42.000Z"
      }
    ],
    "seed": 7,
    "command": {
      "ok": true,
      "presetPath": "file_01M6BPRMNR7PYGFNA66BX2YJ8M",
      "bundled": true,
      "presetName": "Night Drive Remix",
      "bpm": 124,
      "timeSignature": "4/4",
      "seed": 7,
      "variations": [
        "Intro",
        "Groove",
        "Break",
        "Drop"
      ],
      "missingSampleCount": 0,
      "warnings": []
    },
    "provenance": {
      "object": "provenance",
      "id": "prov_01M6BPRVA8ZC7F7J737SQ0EPN2",
      "jobId": "job_01M6BPRFPCH9EBPY7B6JKM7CE1",
      "createdAt": "2026-11-01T14:03:41.877Z",
      "engine": {
        "product": "pam",
        "version": null,
        "runtime": "native-linux-x86_64",
        "image": "registry.cloudflare.com/c7c2e61448617e81ced650f444fb6787/pam-render@sha256:5c5ffe3fabc103e277280fbd65a08988d31361f00fe7857e36f603d67bcec42d"
      },
      "seed": 7,
      "presets": [],
      "packs": [],
      "userFiles": [],
      "inputs": [
        {
          "file": "file_01M6BPRR00A11F2KEPGNR7V3Q9",
          "sha256": "e20c37e5e2607bde5dfd78c1fe0b7fd000e0209a38b9e4eb963d14cfe7191b16"
        }
      ],
      "outputs": [
        {
          "file": "file_01M6BPRMNR7PYGFNA66BX2YJ8M",
          "sha256": "13d41d922519699fc14a7587130eceee7d0f149414350000578de1564866a0d4"
        }
      ],
      "planner": null,
      "contracts": {
        "api": "2026-11-01",
        "pam.cli": 1
      },
      "aiModels": [],
      "audioByModel": false,
      "license": {
        "id": "lic_api_prototype_test",
        "commercialUse": false,
        "attribution": true
      },
      "kid": "6c2f0a9d4b7e1358",
      "signature": "ed25519:LEVZHpOHj8BMGZgJh-_Y7SmKbqDlBDR8LqY-XelU6GYK8lntZqg3rRK4b3BH8cy25bK0iWzOXFXmkiGHEYue7A"
    }
  },
  "error": null,
  "usage": {
    "renderMinutes": 0,
    "audioSeconds": 0,
    "computeMs": 6273
  },
  "metadata": {},
  "urls": {
    "self": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1",
    "events": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/events",
    "cancel": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/cancel"
  }
}
202: Queued
{
  "object": "job",
  "id": "job_01M6BPRFPCH9EBPY7B6JKM7CE1",
  "operation": "projectRemix",
  "status": "queued",
  "livemode": false,
  "sequence": 1,
  "progress": 0,
  "queuePosition": null,
  "createdAt": "2026-11-01T14:03:31.512Z",
  "startedAt": null,
  "finishedAt": null,
  "estimate": {
    "audioSeconds": 0,
    "renderMinutes": 0
  },
  "result": null,
  "error": null,
  "usage": null,
  "metadata": {},
  "urls": {
    "self": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1",
    "events": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/events",
    "cancel": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/cancel"
  }
}
403: Uploads not open yet
{
  "error": {
    "type": "entitlement",
    "code": "uploads_disabled",
    "message": "POST /v1/project/remix works on uploaded files, and uploads are not open yet. Nothing was charged.",
    "param": null,
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#uploads_disabled",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 200 The finished job: `result.outputs` link each file it wrote and `result.command` is the engine's own result., 202 The queued job; poll `urls.self` or stream `urls.events`., 403 Uploads not open yet, default Any other error: `error.code` names it, `error.param` the field at fault, and `error.docUrl` its entry in the error catalogue..

Errors: invalid_request, unsupported_media_type, payload_too_large, terms_required, concurrency_limit, idempotency_key_reused, idempotency_in_flight, queue_unavailable, not_found, file_not_ready, file_expired, uploads_disabled.

View as Markdown

POST/v1/fx

fx

Render a PAM cell effect chain over an audio file.

Run a file through PAM's cell effects: one cell's chain (delay, flanger, crusher, EQ and the rest of the cell rack), set as PAM parameters in chain. Without bars or seconds the render lasts as long as the file, plus tail. It costs render-minutes for the audio it renders: its length in minutes, at least 0.1 a render. Answers 202 with the queued job: poll GET /v1/jobs/{id}, stream GET /v1/jobs/{id}/events, or send Prefer: wait=N (at most 60 s) to get the finished job in this response.

  • Auth: Authorization: Bearer with an API key or a map.audio access token.
  • Send Prefer: wait=N (0 to 60) to receive the finished job when it ends within N seconds.
  • Send Idempotency-Key to retry safely: the same key and body return the same result for 24 hours.
  • MCP tool: fx
fx body
FieldTypeRequiredDescription
filestringyesThe id (file_…) of WAV or FLAC audio this account holds: a render output, or an upload once uploads open. Matches ^file_[0-9A-HJKMNP-TV-Z]{26}$.
secondsnumbernoRender length in seconds; mutually exclusive with bars. Defaults to the input duration for fx and audio master. From 0.001 to 300.
barsintegernoLength in bars (1..64): pattern generation uses four beats and defaults to 1; preset rendering uses the preset time signature and defaults to 4. From 1 to 64.
sampleRateintegernoOutput sample rate. From 22050 to 48000. Default 48000.
tailnumbernoAdditional effect tail in seconds after transport stops. From 0 to 30. Default 0.
seedintegernoReproducible seed; zero draws a random seed. From 0 to 4294967295. Default 0.
chainobjectyesA PAM state fragment as a JSON object: for fx, cell1_* settings, cell1_effectOrder and cells.1.effectConfig, or the same as {params, effectConfig, effectOrder} without the cell1_ prefix; master* settings for audio master.
metadatamap of stringnoUp to 20 string pairs stored with the job. At most 20 entries.
curl
curl -sS "https://api.map.audio/v1/fx" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01" \
  -H "Prefer: wait=30" \
  -H "Content-Type: application/json" \
  -d '{"file":"file_01M6BPRK0M34NBP2XKJ1RMX1TQ","chain":{"params":{"delayMix":30,"delayFeedback":45},"effectConfig":{"delayEnabled":true},"effectOrder":["delay"]},"tail":2}'
Request: Put a render through a feedback delay with a 2-second tail
{
  "file": "file_01M6BPRK0M34NBP2XKJ1RMX1TQ",
  "chain": {
    "params": {
      "delayMix": 30,
      "delayFeedback": 45
    },
    "effectConfig": {
      "delayEnabled": true
    },
    "effectOrder": [
      "delay"
    ]
  },
  "tail": 2
}
200: Finished
{
  "object": "job",
  "id": "job_01M6BPRFPCH9EBPY7B6JKM7CE1",
  "operation": "fx",
  "status": "succeeded",
  "livemode": false,
  "sequence": 3,
  "progress": 1,
  "queuePosition": null,
  "createdAt": "2026-11-01T14:03:31.512Z",
  "startedAt": "2026-11-01T14:03:33.104Z",
  "finishedAt": "2026-11-01T14:03:41.877Z",
  "estimate": {
    "audioSeconds": 18,
    "renderMinutes": 0.3
  },
  "result": {
    "outputs": [
      {
        "role": "master",
        "name": null,
        "cell": null,
        "file": "file_01M6BPRMNR7PYGFNA66BX2YJ8M",
        "sha256": "13d41d922519699fc14a7587130eceee7d0f149414350000578de1564866a0d4",
        "bytes": 5184044,
        "format": "wav",
        "sampleRate": 48000,
        "durationSeconds": 18,
        "url": "https://api.map.audio/v1/download/file_01M6BPRMNR7PYGFNA66BX2YJ8M?expires=1793545422&signature=GQ2GkmPjqXuxxBSSM4NKBCY7OjU7w3YSeZBrCoxxtbY",
        "expiresAt": "2026-11-01T15:03:42.000Z"
      }
    ],
    "seed": 1795302311,
    "command": {
      "ok": true,
      "wavPath": "file_01M6BPRMNR7PYGFNA66BX2YJ8M",
      "sampleRate": 48000,
      "durationSeconds": 18,
      "seed": 1795302311,
      "stems": [],
      "latencySamples": 0
    },
    "provenance": {
      "object": "provenance",
      "id": "prov_01M6BPRVA8ZC7F7J737SQ0EPN2",
      "jobId": "job_01M6BPRFPCH9EBPY7B6JKM7CE1",
      "createdAt": "2026-11-01T14:03:41.877Z",
      "engine": {
        "product": "pam",
        "version": null,
        "runtime": "native-linux-x86_64",
        "image": "registry.cloudflare.com/c7c2e61448617e81ced650f444fb6787/pam-render@sha256:5c5ffe3fabc103e277280fbd65a08988d31361f00fe7857e36f603d67bcec42d"
      },
      "seed": 1795302311,
      "presets": [],
      "packs": [],
      "userFiles": [],
      "inputs": [
        {
          "file": "file_01M6BPRK0M34NBP2XKJ1RMX1TQ",
          "sha256": "5a3485b7a3221be5f7ead6ab953cbc198988a7246158215b32bb937acbd3852b"
        }
      ],
      "outputs": [
        {
          "file": "file_01M6BPRMNR7PYGFNA66BX2YJ8M",
          "sha256": "13d41d922519699fc14a7587130eceee7d0f149414350000578de1564866a0d4"
        }
      ],
      "planner": null,
      "contracts": {
        "api": "2026-11-01",
        "pam.cli": 1
      },
      "aiModels": [],
      "audioByModel": false,
      "license": {
        "id": "lic_api_prototype_test",
        "commercialUse": false,
        "attribution": true
      },
      "kid": "6c2f0a9d4b7e1358",
      "signature": "ed25519:LEVZHpOHj8BMGZgJh-_Y7SmKbqDlBDR8LqY-XelU6GYK8lntZqg3rRK4b3BH8cy25bK0iWzOXFXmkiGHEYue7A"
    }
  },
  "error": null,
  "usage": {
    "renderMinutes": 0.3,
    "audioSeconds": 18,
    "computeMs": 6273
  },
  "metadata": {},
  "urls": {
    "self": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1",
    "events": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/events",
    "cancel": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/cancel"
  }
}
202: Queued
{
  "object": "job",
  "id": "job_01M6BPRFPCH9EBPY7B6JKM7CE1",
  "operation": "fx",
  "status": "queued",
  "livemode": false,
  "sequence": 1,
  "progress": 0,
  "queuePosition": null,
  "createdAt": "2026-11-01T14:03:31.512Z",
  "startedAt": null,
  "finishedAt": null,
  "estimate": {
    "audioSeconds": 18,
    "renderMinutes": 0.3
  },
  "result": null,
  "error": null,
  "usage": null,
  "metadata": {},
  "urls": {
    "self": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1",
    "events": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/events",
    "cancel": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/cancel"
  }
}
400: Invalid request
{
  "error": {
    "type": "invalid_request",
    "code": "invalid_request",
    "message": "chain must be a JSON object; got a string.",
    "param": "chain",
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#invalid_request",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 200 The finished job: `result.outputs` link each file it wrote and `result.command` is the engine's own result., 202 The queued job; poll `urls.self` or stream `urls.events`., 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: invalid_request, unsupported_media_type, payload_too_large, terms_required, concurrency_limit, idempotency_key_reused, idempotency_in_flight, queue_unavailable, insufficient_credits, render_too_long, not_found, file_not_ready, file_expired, uploads_disabled.

View as Markdown

POST/v1/audio/master

audioMaster

Render the PAM master effect chain over an audio file.

Run a file through PAM's master chain (EQ, compression, tape, clipping, limiting and the other master stages), set as master* parameters in chain. For loudness alone, POST /v1/audio/normalize is free. It costs render-minutes for the audio it renders: its length in minutes, at least 0.1 a render. Answers 202 with the queued job: poll GET /v1/jobs/{id}, stream GET /v1/jobs/{id}/events, or send Prefer: wait=N (at most 60 s) to get the finished job in this response.

  • Auth: Authorization: Bearer with an API key or a map.audio access token.
  • Send Prefer: wait=N (0 to 60) to receive the finished job when it ends within N seconds.
  • Send Idempotency-Key to retry safely: the same key and body return the same result for 24 hours.
  • MCP tool: audio_master
audioMaster body
FieldTypeRequiredDescription
filestringyesThe id (file_…) of WAV or FLAC audio this account holds: a render output, or an upload once uploads open. Matches ^file_[0-9A-HJKMNP-TV-Z]{26}$.
secondsnumbernoRender length in seconds; mutually exclusive with bars. Defaults to the input duration for fx and audio master. From 0.001 to 300.
barsintegernoLength in bars (1..64): pattern generation uses four beats and defaults to 1; preset rendering uses the preset time signature and defaults to 4. From 1 to 64.
sampleRateintegernoOutput sample rate. From 22050 to 48000. Default 48000.
tailnumbernoAdditional effect tail in seconds after transport stops. From 0 to 30. Default 0.
seedintegernoReproducible seed; zero draws a random seed. From 0 to 4294967295. Default 0.
chainobjectyesA PAM state fragment as a JSON object: for fx, cell1_* settings, cell1_effectOrder and cells.1.effectConfig, or the same as {params, effectConfig, effectOrder} without the cell1_ prefix; master* settings for audio master.
metadatamap of stringnoUp to 20 string pairs stored with the job. At most 20 entries.
curl
curl -sS "https://api.map.audio/v1/audio/master" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01" \
  -H "Prefer: wait=30" \
  -H "Content-Type: application/json" \
  -d '{"file":"file_01M6BPRK0M34NBP2XKJ1RMX1TQ","chain":{"masterEqEnabled":1,"masterEqTilt":-1.5,"masterCompressorEnabled":1,"masterCompThreshold":-18,"masterCompRatio":2,"masterTapeEnabled":1,"masterTapeDrive":0.35}}'
Request: Master a render with a gentle tilt, glue compression and tape
{
  "file": "file_01M6BPRK0M34NBP2XKJ1RMX1TQ",
  "chain": {
    "masterEqEnabled": 1,
    "masterEqTilt": -1.5,
    "masterCompressorEnabled": 1,
    "masterCompThreshold": -18,
    "masterCompRatio": 2,
    "masterTapeEnabled": 1,
    "masterTapeDrive": 0.35
  }
}
200: Finished
{
  "object": "job",
  "id": "job_01M6BPRFPCH9EBPY7B6JKM7CE1",
  "operation": "audioMaster",
  "status": "succeeded",
  "livemode": false,
  "sequence": 3,
  "progress": 1,
  "queuePosition": null,
  "createdAt": "2026-11-01T14:03:31.512Z",
  "startedAt": "2026-11-01T14:03:33.104Z",
  "finishedAt": "2026-11-01T14:03:41.877Z",
  "estimate": {
    "audioSeconds": 16,
    "renderMinutes": 0.267
  },
  "result": {
    "outputs": [
      {
        "role": "master",
        "name": null,
        "cell": null,
        "file": "file_01M6BPRMNR7PYGFNA66BX2YJ8M",
        "sha256": "13d41d922519699fc14a7587130eceee7d0f149414350000578de1564866a0d4",
        "bytes": 4608044,
        "format": "wav",
        "sampleRate": 48000,
        "durationSeconds": 16,
        "url": "https://api.map.audio/v1/download/file_01M6BPRMNR7PYGFNA66BX2YJ8M?expires=1793545422&signature=GQ2GkmPjqXuxxBSSM4NKBCY7OjU7w3YSeZBrCoxxtbY",
        "expiresAt": "2026-11-01T15:03:42.000Z"
      }
    ],
    "seed": 2290871365,
    "command": {
      "ok": true,
      "wavPath": "file_01M6BPRMNR7PYGFNA66BX2YJ8M",
      "sampleRate": 48000,
      "durationSeconds": 16,
      "seed": 2290871365,
      "stems": [],
      "latencySamples": 0
    },
    "provenance": {
      "object": "provenance",
      "id": "prov_01M6BPRVA8ZC7F7J737SQ0EPN2",
      "jobId": "job_01M6BPRFPCH9EBPY7B6JKM7CE1",
      "createdAt": "2026-11-01T14:03:41.877Z",
      "engine": {
        "product": "pam",
        "version": null,
        "runtime": "native-linux-x86_64",
        "image": "registry.cloudflare.com/c7c2e61448617e81ced650f444fb6787/pam-render@sha256:5c5ffe3fabc103e277280fbd65a08988d31361f00fe7857e36f603d67bcec42d"
      },
      "seed": 2290871365,
      "presets": [],
      "packs": [],
      "userFiles": [],
      "inputs": [
        {
          "file": "file_01M6BPRK0M34NBP2XKJ1RMX1TQ",
          "sha256": "5a3485b7a3221be5f7ead6ab953cbc198988a7246158215b32bb937acbd3852b"
        }
      ],
      "outputs": [
        {
          "file": "file_01M6BPRMNR7PYGFNA66BX2YJ8M",
          "sha256": "13d41d922519699fc14a7587130eceee7d0f149414350000578de1564866a0d4"
        }
      ],
      "planner": null,
      "contracts": {
        "api": "2026-11-01",
        "pam.cli": 1
      },
      "aiModels": [],
      "audioByModel": false,
      "license": {
        "id": "lic_api_prototype_test",
        "commercialUse": false,
        "attribution": true
      },
      "kid": "6c2f0a9d4b7e1358",
      "signature": "ed25519:LEVZHpOHj8BMGZgJh-_Y7SmKbqDlBDR8LqY-XelU6GYK8lntZqg3rRK4b3BH8cy25bK0iWzOXFXmkiGHEYue7A"
    }
  },
  "error": null,
  "usage": {
    "renderMinutes": 0.267,
    "audioSeconds": 16,
    "computeMs": 6273
  },
  "metadata": {},
  "urls": {
    "self": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1",
    "events": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/events",
    "cancel": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/cancel"
  }
}
202: Queued
{
  "object": "job",
  "id": "job_01M6BPRFPCH9EBPY7B6JKM7CE1",
  "operation": "audioMaster",
  "status": "queued",
  "livemode": false,
  "sequence": 1,
  "progress": 0,
  "queuePosition": null,
  "createdAt": "2026-11-01T14:03:31.512Z",
  "startedAt": null,
  "finishedAt": null,
  "estimate": {
    "audioSeconds": 16,
    "renderMinutes": 0.267
  },
  "result": null,
  "error": null,
  "usage": null,
  "metadata": {},
  "urls": {
    "self": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1",
    "events": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/events",
    "cancel": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/cancel"
  }
}
409: File not ready
{
  "error": {
    "type": "conflict",
    "code": "file_not_ready",
    "message": "File file_01M6BPRK0M34NBP2XKJ1RMX1TQ is still being written by job_01M6BPRE186QHP9QPYGDX5NNFP; retry when that job succeeds.",
    "param": "file",
    "retryable": true,
    "jobId": "job_01M6BPRE186QHP9QPYGDX5NNFP",
    "docUrl": "https://map.audio/developers/music-api/errors#file_not_ready",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 200 The finished job: `result.outputs` link each file it wrote and `result.command` is the engine's own result., 202 The queued job; poll `urls.self` or stream `urls.events`., 409 File not ready, default Any other error: `error.code` names it, `error.param` the field at fault, and `error.docUrl` its entry in the error catalogue..

Errors: invalid_request, unsupported_media_type, payload_too_large, terms_required, concurrency_limit, idempotency_key_reused, idempotency_in_flight, queue_unavailable, insufficient_credits, render_too_long, not_found, file_not_ready, file_expired, uploads_disabled.

View as Markdown

POST/v1/state

state

Apply state envelopes to Init, a preset or a point between two presets in the headless PAM engine, read the resulting state and optionally render it.

Run PAM's engine headless on a preset's state: apply envelopes (parameter changes), morph toward another preset or variation, or blend presets, then read the resulting state or render it. Without render it is free and answers at once; with render: true it renders like POST /v1/renders and also returns the session as a .preset file. Free without render; with render: true it costs render-minutes for the audio it renders. Answers 200 with the finished job when it ends within Prefer: wait=N (30 s unless sent, at most 60), else 202 with the job to poll; with render: true it waits only as long as Prefer: wait asks.

  • Auth: Authorization: Bearer with an API key or a map.audio access token.
  • Send Prefer: wait=N (0 to 60) to receive the finished job when it ends within N seconds.
  • Send Idempotency-Key to retry safely: the same key and body return the same result for 24 hours.
  • MCP tool: state
state body
FieldTypeRequiredDescription
presetstringnoA factory preset reference, pam:factory/<slug> or the bare slug; GET /v1/presets lists them. At most 200 characters.
envelopesobject or array of anynoState envelopes ({delta, options?}, or {directNodeOps, options?} without a delta) applied in order, as a JSON array or object.
keysstringnoTop-level state keys to return, as a comma list or a JSON array; absent keys are listed in missingKeys.
temponumbernoTransport tempo in beats per minute before the envelopes apply. From 20 to 999.
playingbooleannoStart the transport before the envelopes apply.
variationintegernoPreset variation, numbered from 1. From 1 to 16.
morphTostringnoPreset to morph toward, from the preset argument or Init, at the position at gives. Below 1 the session stays the start's and only its parameters move; from 1 it is this preset's. A factory preset reference, pam:factory/<slug> or the bare slug; GET /v1/presets lists them. At most 200 characters.
toVariationintegernoVariation, numbered from 1, the morph moves toward: of the morphTo preset, or of the preset argument without morphTo. From 1 to 16.
atnumbernoMorph position: 0 is the start, 1 the target. Values outside 0..1 extrapolate along the same line, clamped to each parameter's range.
curve"linear" | "ease" | "exp" | "log"noShape applied to at between 0 and 1, as a live Glide shapes its window. Default "ease".
discretestringnoWhen parameters a Glide switches instead of moving (modes, selectors, timing) take the target's value: hold until 1, switch once at is above 0, or a threshold between 0 and 1. Default "hold".
pattern"dissolve" | "wipe" | "cells"noStage the cells' patterns at at as a Steps transition does: dissolve fades the start's steps out and the target's in through their probability, wipe sweeps a frontier through each pattern, cells hands patterns over cell by cell. Without it the patterns stay the start's below 1.
patternCurve"linear" | "ease" | "exp" | "log"noShape applied to at for pattern, as a live transition shapes its pattern stages. Default "linear".
patternSeedintegernoDecide each step a pattern dissolve scaled: a start-only step stays with probability 1 - p and a target-only step arrives with p, drawn from this seed, so the cells hold a concrete pattern. The same seed gives the same steps. From 0 to 4294967295.
relations"off" | "stepped"noA live Glide's relations: stepped moves a drum synth's pitch through its semitones instead of switching it at the anchor. Default "off".
stagger"off" | "cell" | "category"noA live Glide's cascade: parameters start moving group by group, by cell or by category, over the staggerSpread fraction of the window. Default "off".
staggerSpreadnumbernoFraction of the window a stagger cascade spreads its groups' starts over; 0 staggers nothing, as in a live transition. From 0 to 0.9. Default 0.
staggerOrder"forward" | "reverse"noOrder of a stagger cascade: forward starts the first cell or category first. Default "forward".
liveCapbooleannoMove only the 1,024 largest moves, as a live Glide does when more parameters differ; the others switch as discrete says.
blendarray of objectnoPresets to blend instead of a start and a target, each with a positive weight; weights are relative. 2 to 16 items.
blend[].presetstringyesA factory preset pam:factory/<slug>, or its bare slug. At most 200 characters.
blend[].variationintegernoThe preset's variation slot to blend; default: its base state. From 1 to 16.
blend[].weightnumberyesMore than 0.
renderbooleannoRender the session the envelopes leave to WAV, as preset render renders a preset.
secondsnumbernoRender length in seconds; mutually exclusive with bars. Defaults to the input duration for fx and audio master. From 0.001 to 300.
barsintegernoLength in bars (1..64): pattern generation uses four beats and defaults to 1; preset rendering uses the preset time signature and defaults to 4. From 1 to 64.
sampleRateintegernoOutput sample rate. From 22050 to 48000. Default 48000.
tailnumbernoAdditional effect tail in seconds after transport stops. From 0 to 30. Default 0.
seedintegernoReproducible seed; zero draws a random seed. From 0 to 4294967295. Default 0.
stemsbooleannoWrite each cell stem alongside the master in one render pass.
inputstringnoAudio played into the engine's input, through the PAM cells whose source is External. Without seconds or bars the render lasts as long as the input, plus tail. The id (file_…) of WAV or FLAC audio this account holds: a render output, or an upload once uploads open. Matches ^file_[0-9A-HJKMNP-TV-Z]{26}$.
saveSlotintegernoVariation slot, numbered from 1, that holds the saved state; the other slots keep the session's bank. Defaults to the slot the session is on. From 1 to 8.
metaobjectnoMetadata for the preset a render saves, as a JSON object: name, author, description, category, tags and the other browser fields.
metadatamap of stringnoUp to 20 string pairs stored with the job. At most 20 entries.
curl
curl -sS "https://api.map.audio/v1/state" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01" \
  -H "Prefer: wait=30" \
  -H "Content-Type: application/json" \
  -d '{"preset":"pam:factory/acid-sprinkle","variation":1,"toVariation":3,"at":0.5,"render":true,"bars":8,"seed":7}'
Request: Render 8 bars halfway between two variations of Acid Sprinkle
{
  "preset": "pam:factory/acid-sprinkle",
  "variation": 1,
  "toVariation": 3,
  "at": 0.5,
  "render": true,
  "bars": 8,
  "seed": 7
}
200: Finished
{
  "object": "job",
  "id": "job_01M6BPRFPCH9EBPY7B6JKM7CE1",
  "operation": "state",
  "status": "succeeded",
  "livemode": false,
  "sequence": 3,
  "progress": 1,
  "queuePosition": null,
  "createdAt": "2026-11-01T14:03:31.512Z",
  "startedAt": "2026-11-01T14:03:33.104Z",
  "finishedAt": "2026-11-01T14:03:41.877Z",
  "estimate": {
    "audioSeconds": 15.484,
    "renderMinutes": 0.258
  },
  "result": {
    "outputs": [
      {
        "role": "master",
        "name": null,
        "cell": null,
        "file": "file_01M6BPRMNR7PYGFNA66BX2YJ8M",
        "sha256": "13d41d922519699fc14a7587130eceee7d0f149414350000578de1564866a0d4",
        "bytes": 4459436,
        "format": "wav",
        "sampleRate": 48000,
        "durationSeconds": 15.484,
        "url": "https://api.map.audio/v1/download/file_01M6BPRMNR7PYGFNA66BX2YJ8M?expires=1793545422&signature=GQ2GkmPjqXuxxBSSM4NKBCY7OjU7w3YSeZBrCoxxtbY",
        "expiresAt": "2026-11-01T15:03:42.000Z"
      },
      {
        "role": "preset",
        "name": null,
        "cell": null,
        "file": "file_01M6BPRPAWG14FNFS6AKGVPEHH",
        "sha256": "da659a796033a280992f3e665c5eb95ebfe7a08b753aa574d84cf70db61b8b29",
        "bytes": 18734,
        "format": "preset",
        "sampleRate": null,
        "durationSeconds": null,
        "url": "https://api.map.audio/v1/download/file_01M6BPRPAWG14FNFS6AKGVPEHH?expires=1793545422&signature=oRSM1YDQ_hhkALQN7N4rgA-xKU4SFZlZGkf6rO28LlI",
        "expiresAt": "2026-11-01T15:03:42.000Z"
      }
    ],
    "seed": 7,
    "command": {
      "ok": true,
      "source": {
        "kind": "preset",
        "path": "pam:factory/acid-sprinkle",
        "variation": 1
      },
      "applied": 0,
      "render": {
        "wavPath": "file_01M6BPRMNR7PYGFNA66BX2YJ8M",
        "sampleRate": 48000,
        "channels": 2,
        "durationSeconds": 15.484,
        "seed": 7,
        "stems": []
      },
      "saved": {
        "presetPath": "file_01M6BPRPAWG14FNFS6AKGVPEHH",
        "name": "session",
        "variation": 1,
        "product": "pam"
      },
      "ms": 1840
    },
    "provenance": {
      "object": "provenance",
      "id": "prov_01M6BPRVA8ZC7F7J737SQ0EPN2",
      "jobId": "job_01M6BPRFPCH9EBPY7B6JKM7CE1",
      "createdAt": "2026-11-01T14:03:41.877Z",
      "engine": {
        "product": "pam",
        "version": null,
        "runtime": "native-linux-x86_64",
        "image": "registry.cloudflare.com/c7c2e61448617e81ced650f444fb6787/pam-render@sha256:5c5ffe3fabc103e277280fbd65a08988d31361f00fe7857e36f603d67bcec42d"
      },
      "seed": 7,
      "presets": [
        {
          "ref": "pam:factory/acid-sprinkle",
          "variation": 1,
          "sha256": "eee63255e1350ec8f03f098656befcc3c1c1c23c0bd7933f93fee84071f9279d"
        }
      ],
      "packs": [],
      "userFiles": [],
      "inputs": [],
      "outputs": [
        {
          "file": "file_01M6BPRMNR7PYGFNA66BX2YJ8M",
          "sha256": "13d41d922519699fc14a7587130eceee7d0f149414350000578de1564866a0d4"
        },
        {
          "file": "file_01M6BPRPAWG14FNFS6AKGVPEHH",
          "sha256": "da659a796033a280992f3e665c5eb95ebfe7a08b753aa574d84cf70db61b8b29"
        }
      ],
      "planner": null,
      "contracts": {
        "api": "2026-11-01",
        "pam.cli": 1
      },
      "aiModels": [],
      "audioByModel": false,
      "license": {
        "id": "lic_api_prototype_test",
        "commercialUse": false,
        "attribution": true
      },
      "kid": "6c2f0a9d4b7e1358",
      "signature": "ed25519:LEVZHpOHj8BMGZgJh-_Y7SmKbqDlBDR8LqY-XelU6GYK8lntZqg3rRK4b3BH8cy25bK0iWzOXFXmkiGHEYue7A"
    }
  },
  "error": null,
  "usage": {
    "renderMinutes": 0.258,
    "audioSeconds": 15.484,
    "computeMs": 6273
  },
  "metadata": {},
  "urls": {
    "self": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1",
    "events": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/events",
    "cancel": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/cancel"
  }
}
202: Still running
{
  "object": "job",
  "id": "job_01M6BPRFPCH9EBPY7B6JKM7CE1",
  "operation": "state",
  "status": "running",
  "livemode": false,
  "sequence": 2,
  "progress": 0,
  "queuePosition": null,
  "createdAt": "2026-11-01T14:03:31.512Z",
  "startedAt": "2026-11-01T14:03:33.104Z",
  "finishedAt": null,
  "estimate": {
    "audioSeconds": 15.484,
    "renderMinutes": 0.258
  },
  "result": null,
  "error": null,
  "usage": null,
  "metadata": {},
  "urls": {
    "self": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1",
    "events": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/events",
    "cancel": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/cancel"
  }
}
400: Invalid request
{
  "error": {
    "type": "invalid_request",
    "code": "invalid_request",
    "message": "bars needs render: true.",
    "param": "bars",
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#invalid_request",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 200 The finished job: `result.outputs` link each file it wrote and `result.command` is the engine's own result., 202 The job, still running when `Prefer: wait` ran out; poll `urls.self`., 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: invalid_request, unsupported_media_type, payload_too_large, terms_required, concurrency_limit, idempotency_key_reused, idempotency_in_flight, queue_unavailable, insufficient_credits, render_too_long, preset_not_found, preset_not_served, variation_not_found, not_found, file_not_ready, file_expired, uploads_disabled, invalid_envelope.

View as Markdown

POST/v1/dj/set

djSet

Render a DJ set of PAM presets to WAV, each boundary on its DJ view transition, without opening PAM.

Render a DJ set: factory presets in order, each boundary on its DJ-view transition (blend, drop, rise, break, sweep or fill), as one WAV. Check the set first with POST /v1/arrangements, which costs nothing and returns the boundaries; GET /v1/transition-presets lists the transitions. It costs render-minutes for the audio it renders: its length in minutes, at least 0.1 a render. Answers 202 with the queued job: poll GET /v1/jobs/{id}, stream GET /v1/jobs/{id}/events, or send Prefer: wait=N (at most 60 s) to get the finished job in this response.

  • Auth: Authorization: Bearer with an API key or a map.audio access token.
  • Send Prefer: wait=N (0 to 60) to receive the finished job when it ends within N seconds.
  • Send Idempotency-Key to retry safely: the same key and body return the same result for 24 hours.
  • MCP tool: render_dj_set
djSet body
FieldTypeRequiredDescription
setobjectyesThe set to render. queue lists its items in play order: queue[0] plays first, and each item names a factory preset (presetPath, such as pam:factory/313-disco), its variation (variationIndex, counted from 0), its length in bars and the transition into it. stepBars, launchBars, defaultTransition and tempo set the defaults; without tempo.bpm the set runs at its first preset's tempo, and auto: false is refused because a render steps through the set itself. POST /v1/arrangements checks a set without rendering it; GET /v1/transition-presets lists the transition presets, modes and the set schema's definitions.
sampleRateintegernoOutput sample rate. From 22050 to 48000. Default 48000.
tailnumbernoAdditional effect tail in seconds after transport stops. From 0 to 30. Default 0.
seedintegernoReproducible seed; zero draws a random seed. From 0 to 4294967295. Default 0.
stemsbooleannoWrite each cell stem alongside the master in one render pass.
metadatamap of stringnoUp to 20 string pairs stored with the job. At most 20 entries.
curl
curl -sS "https://api.map.audio/v1/dj/set" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01" \
  -H "Prefer: wait=30" \
  -H "Content-Type: application/json" \
  -d '{"set":{"queue":[{"presetPath":"pam:factory/acid-sprinkle","bars":16},{"presetPath":"pam:factory/teknochonic","variationIndex":1,"bars":16,"transition":{"preset":"blend","bars":8}},{"presetPath":"pam:factory/breakbeatrcool","variationIndex":2,"bars":16,"transition":{"preset":"drop"}}],"tempo":{"bpm":124}},"seed":42}'
Request: Three presets at 124 BPM: an 8-bar blend, then a drop
{
  "set": {
    "queue": [
      {
        "presetPath": "pam:factory/acid-sprinkle",
        "bars": 16
      },
      {
        "presetPath": "pam:factory/teknochonic",
        "variationIndex": 1,
        "bars": 16,
        "transition": {
          "preset": "blend",
          "bars": 8
        }
      },
      {
        "presetPath": "pam:factory/breakbeatrcool",
        "variationIndex": 2,
        "bars": 16,
        "transition": {
          "preset": "drop"
        }
      }
    ],
    "tempo": {
      "bpm": 124
    }
  },
  "seed": 42
}
200: Finished
{
  "object": "job",
  "id": "job_01M6BPRFPCH9EBPY7B6JKM7CE1",
  "operation": "djSet",
  "status": "succeeded",
  "livemode": false,
  "sequence": 3,
  "progress": 1,
  "queuePosition": null,
  "createdAt": "2026-11-01T14:03:31.512Z",
  "startedAt": "2026-11-01T14:03:33.104Z",
  "finishedAt": "2026-11-01T14:03:41.877Z",
  "estimate": {
    "audioSeconds": 92.903,
    "renderMinutes": 1.548
  },
  "result": {
    "outputs": [
      {
        "role": "master",
        "name": null,
        "cell": null,
        "file": "file_01M6BPRMNR7PYGFNA66BX2YJ8M",
        "sha256": "13d41d922519699fc14a7587130eceee7d0f149414350000578de1564866a0d4",
        "bytes": 26756108,
        "format": "wav",
        "sampleRate": 48000,
        "durationSeconds": 92.903,
        "url": "https://api.map.audio/v1/download/file_01M6BPRMNR7PYGFNA66BX2YJ8M?expires=1793545422&signature=GQ2GkmPjqXuxxBSSM4NKBCY7OjU7w3YSeZBrCoxxtbY",
        "expiresAt": "2026-11-01T15:03:42.000Z"
      }
    ],
    "seed": 42,
    "command": {
      "ok": true,
      "wavPath": "file_01M6BPRMNR7PYGFNA66BX2YJ8M",
      "sampleRate": 48000,
      "durationSeconds": 92.903,
      "seed": 42,
      "stems": [],
      "boundaries": [
        {
          "index": 1,
          "presetPath": "pam:factory/teknochonic",
          "variationIndex": 1,
          "anchorBar": 16,
          "windowBars": 8,
          "mode": "mix",
          "locked": false
        },
        {
          "index": 2,
          "presetPath": "pam:factory/breakbeatrcool",
          "variationIndex": 2,
          "anchorBar": 32,
          "windowBars": 0,
          "mode": "auto",
          "locked": false
        }
      ],
      "bpm": 124,
      "timeSig": [
        4,
        4
      ],
      "bars": 48
    },
    "provenance": {
      "object": "provenance",
      "id": "prov_01M6BPRVA8ZC7F7J737SQ0EPN2",
      "jobId": "job_01M6BPRFPCH9EBPY7B6JKM7CE1",
      "createdAt": "2026-11-01T14:03:41.877Z",
      "engine": {
        "product": "pam",
        "version": null,
        "runtime": "native-linux-x86_64",
        "image": "registry.cloudflare.com/c7c2e61448617e81ced650f444fb6787/pam-render@sha256:5c5ffe3fabc103e277280fbd65a08988d31361f00fe7857e36f603d67bcec42d"
      },
      "seed": 42,
      "presets": [
        {
          "ref": "pam:factory/acid-sprinkle",
          "sha256": "eee63255e1350ec8f03f098656befcc3c1c1c23c0bd7933f93fee84071f9279d"
        },
        {
          "ref": "pam:factory/teknochonic",
          "variation": 2,
          "sha256": "a2e6645b2108343284008cd4ef4b8356ab1f4c47dbd9da63a785d893b31a9266"
        },
        {
          "ref": "pam:factory/breakbeatrcool",
          "variation": 3,
          "sha256": "92916c116f9e0a17fd8217a67a98b57063efc8554de0e66b8398053dda7e3296"
        }
      ],
      "packs": [],
      "userFiles": [],
      "inputs": [],
      "outputs": [
        {
          "file": "file_01M6BPRMNR7PYGFNA66BX2YJ8M",
          "sha256": "13d41d922519699fc14a7587130eceee7d0f149414350000578de1564866a0d4"
        }
      ],
      "planner": null,
      "contracts": {
        "api": "2026-11-01",
        "pam.cli": 1
      },
      "aiModels": [],
      "audioByModel": false,
      "license": {
        "id": "lic_api_prototype_test",
        "commercialUse": false,
        "attribution": true
      },
      "kid": "6c2f0a9d4b7e1358",
      "signature": "ed25519:LEVZHpOHj8BMGZgJh-_Y7SmKbqDlBDR8LqY-XelU6GYK8lntZqg3rRK4b3BH8cy25bK0iWzOXFXmkiGHEYue7A"
    }
  },
  "error": null,
  "usage": {
    "renderMinutes": 1.548,
    "audioSeconds": 92.903,
    "computeMs": 6273
  },
  "metadata": {},
  "urls": {
    "self": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1",
    "events": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/events",
    "cancel": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/cancel"
  }
}
202: Queued
{
  "object": "job",
  "id": "job_01M6BPRFPCH9EBPY7B6JKM7CE1",
  "operation": "djSet",
  "status": "queued",
  "livemode": false,
  "sequence": 1,
  "progress": 0,
  "queuePosition": null,
  "createdAt": "2026-11-01T14:03:31.512Z",
  "startedAt": null,
  "finishedAt": null,
  "estimate": {
    "audioSeconds": 92.903,
    "renderMinutes": 1.548
  },
  "result": null,
  "error": null,
  "usage": null,
  "metadata": {},
  "urls": {
    "self": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1",
    "events": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/events",
    "cancel": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/cancel"
  }
}
400: Set cannot render as sent
{
  "error": {
    "type": "invalid_request",
    "code": "dj_offline_unsupported",
    "message": "set.auto false waits for a hand to advance the set, and a render steps through it on its own; leave out auto or send true.",
    "param": "set.auto",
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#dj_offline_unsupported",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 200 The finished job: `result.outputs` link each file it wrote and `result.command` is the engine's own result., 202 The queued job; poll `urls.self` or stream `urls.events`., 400 Set cannot render as sent, default Any other error: `error.code` names it, `error.param` the field at fault, and `error.docUrl` its entry in the error catalogue..

Errors: invalid_request, unsupported_media_type, payload_too_large, terms_required, concurrency_limit, idempotency_key_reused, idempotency_in_flight, queue_unavailable, insufficient_credits, render_too_long, preset_not_found, preset_not_served, variation_not_found, dj_invalid_set, dj_offline_unsupported, dj_preset_missing, dj_unknown_transition_preset.

View as Markdown

POST/v1/pattern/generate

patternGenerate

Generate seeded genre patterns with the shared MIDI corpus; optionally write MIDI.

Generate seeded drum and bass patterns in a genre from PAM's MIDI corpus, returned as notes per cell and a MIDI file. It renders no audio, so it is free; render presets to audio with POST /v1/renders. Free: it counts in GET /v1/usage, never in render-minutes. Answers 200 with the finished job when it ends within Prefer: wait=N (30 s unless sent, at most 60), else 202 with the job to poll.

  • Auth: Authorization: Bearer with an API key or a map.audio access token.
  • Send Prefer: wait=N (0 to 60) to receive the finished job when it ends within N seconds.
  • Send Idempotency-Key to retry safely: the same key and body return the same result for 24 hours.
  • MCP tool: pattern_generate
patternGenerate body
FieldTypeRequiredDescription
genre"trap" | "drill" | "boombap" | "dnb" | "house" | "techno" | "idm"noPattern genre. Default "trap".
seedintegernoReproducible seed; zero draws a random seed. From 0 to 4294967295. Default 0.
bpmnumbernoMIDI tempo in beats per minute. From 20 to 400. Default 120.
barsintegernoLength in bars (1..64): pattern generation uses four beats and defaults to 1; preset rendering uses the preset time signature and defaults to 4. From 1 to 64.
cellsstringnoComma-separated PAM cell IDs (1..12); factory roles are used. Default "1,2,3,6".
densitynumbernoPattern density; absent uses genre default. From 0 to 1.
syncopationnumbernoPattern syncopation; absent uses genre default. From 0 to 1.
coherencenumbernoCross-cell pattern coherence. From 0 to 1. Default 0.5.
metadatamap of stringnoUp to 20 string pairs stored with the job. At most 20 entries.
curl
curl -sS "https://api.map.audio/v1/pattern/generate" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01" \
  -H "Prefer: wait=30" \
  -H "Content-Type: application/json" \
  -d '{"genre":"house","bpm":124,"bars":4,"seed":42}'
Request: Four bars of house at 124 BPM
{
  "genre": "house",
  "bpm": 124,
  "bars": 4,
  "seed": 42
}
200: Finished
{
  "object": "job",
  "id": "job_01M6BPRFPCH9EBPY7B6JKM7CE1",
  "operation": "patternGenerate",
  "status": "succeeded",
  "livemode": false,
  "sequence": 3,
  "progress": 1,
  "queuePosition": null,
  "createdAt": "2026-11-01T14:03:31.512Z",
  "startedAt": "2026-11-01T14:03:33.104Z",
  "finishedAt": "2026-11-01T14:03:41.877Z",
  "estimate": {
    "audioSeconds": 0,
    "renderMinutes": 0
  },
  "result": {
    "outputs": [
      {
        "role": "midi",
        "name": null,
        "cell": null,
        "file": "file_01M6BPRMNR7PYGFNA66BX2YJ8M",
        "sha256": "13d41d922519699fc14a7587130eceee7d0f149414350000578de1564866a0d4",
        "bytes": 1214,
        "format": "mid",
        "sampleRate": null,
        "durationSeconds": null,
        "url": "https://api.map.audio/v1/download/file_01M6BPRMNR7PYGFNA66BX2YJ8M?expires=1793545422&signature=GQ2GkmPjqXuxxBSSM4NKBCY7OjU7w3YSeZBrCoxxtbY",
        "expiresAt": "2026-11-01T15:03:42.000Z"
      }
    ],
    "seed": 42,
    "command": {
      "ok": true,
      "seed": 42,
      "genre": "house",
      "bpm": 124,
      "lengthBeats": 16,
      "roles": {
        "1": "kick",
        "2": "snare",
        "3": "hihat",
        "6": "bass"
      },
      "corpus": true,
      "midiPath": "file_01M6BPRMNR7PYGFNA66BX2YJ8M"
    },
    "provenance": {
      "object": "provenance",
      "id": "prov_01M6BPRVA8ZC7F7J737SQ0EPN2",
      "jobId": "job_01M6BPRFPCH9EBPY7B6JKM7CE1",
      "createdAt": "2026-11-01T14:03:41.877Z",
      "engine": {
        "product": "pam",
        "version": null,
        "runtime": "native-linux-x86_64",
        "image": "registry.cloudflare.com/c7c2e61448617e81ced650f444fb6787/pam-render@sha256:5c5ffe3fabc103e277280fbd65a08988d31361f00fe7857e36f603d67bcec42d"
      },
      "seed": 42,
      "presets": [],
      "packs": [],
      "userFiles": [],
      "inputs": [],
      "outputs": [
        {
          "file": "file_01M6BPRMNR7PYGFNA66BX2YJ8M",
          "sha256": "13d41d922519699fc14a7587130eceee7d0f149414350000578de1564866a0d4"
        }
      ],
      "planner": null,
      "contracts": {
        "api": "2026-11-01",
        "pam.cli": 1
      },
      "aiModels": [],
      "audioByModel": false,
      "license": {
        "id": "lic_api_prototype_test",
        "commercialUse": false,
        "attribution": true
      },
      "kid": "6c2f0a9d4b7e1358",
      "signature": "ed25519:LEVZHpOHj8BMGZgJh-_Y7SmKbqDlBDR8LqY-XelU6GYK8lntZqg3rRK4b3BH8cy25bK0iWzOXFXmkiGHEYue7A"
    }
  },
  "error": null,
  "usage": {
    "renderMinutes": 0,
    "audioSeconds": 0,
    "computeMs": 6273
  },
  "metadata": {},
  "urls": {
    "self": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1",
    "events": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/events",
    "cancel": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/cancel"
  }
}
202: Still running
{
  "object": "job",
  "id": "job_01M6BPRFPCH9EBPY7B6JKM7CE1",
  "operation": "patternGenerate",
  "status": "running",
  "livemode": false,
  "sequence": 2,
  "progress": 0,
  "queuePosition": null,
  "createdAt": "2026-11-01T14:03:31.512Z",
  "startedAt": "2026-11-01T14:03:33.104Z",
  "finishedAt": null,
  "estimate": {
    "audioSeconds": 0,
    "renderMinutes": 0
  },
  "result": null,
  "error": null,
  "usage": null,
  "metadata": {},
  "urls": {
    "self": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1",
    "events": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/events",
    "cancel": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/cancel"
  }
}
400: Invalid request
{
  "error": {
    "type": "invalid_request",
    "code": "invalid_request",
    "message": "genre must be one of trap, drill, boombap, dnb, house, techno or idm; got \"polka\".",
    "param": "genre",
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#invalid_request",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 200 The finished job: `result.outputs` link each file it wrote and `result.command` is the engine's own result., 202 The job, still running when `Prefer: wait` ran out; poll `urls.self`., 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: invalid_request, unsupported_media_type, payload_too_large, terms_required, concurrency_limit, idempotency_key_reused, idempotency_in_flight, queue_unavailable.

View as Markdown

POST/v1/synth/drum

synthDrum

Render procedural drum engines with named controls and timed triggers.

Synthesize drum hits with one of PAM's drum-synth engines (kick, snare, hats, 808 and more), set by named controls in real units, with trigger times for a pattern of hits. It is free; GET /v1/drum-engines lists the engines and their controls. Free: it counts in GET /v1/usage, never in render-minutes. Answers 200 with the finished job when it ends within Prefer: wait=N (30 s unless sent, at most 60), else 202 with the job to poll.

  • Auth: Authorization: Bearer with an API key or a map.audio access token.
  • Send Prefer: wait=N (0 to 60) to receive the finished job when it ends within N seconds.
  • Send Idempotency-Key to retry safely: the same key and body return the same result for 24 hours.
  • MCP tool: synth_drum
synthDrum body
FieldTypeRequiredDescription
engine"1" | "kick" | "2" | "snare" | "3" | "hihat" | "4" | "clap" | "5" | "tom" | "6" | "fm" | "7" | "cymbal" | "8" | "cowbell" | "9" | "808" | "10" | "shaker" | "11" | "rim" | "12" | "conga" | "13" | "bell" | "14" | "pluck" | "15" | "zap" | "16" | "wave" | "17" | "chaos" | "18" | "stab" | "19" | "acoustic-kick" | "20" | "acoustic-snare" | "21" | "acoustic-cymbal" | "22" | "acoustic-hi-hat"noDrum engine name or id; GET /v1/drum-engines lists them with their controls. Default "kick".
paramstringnoComma-separated name=value controls in registry units (Hz, seconds, ratios; pct controls use 0..100). Kick: Tune=30..160 note, P.Depth=1..5 ratio, P.Decay=0.005..0.2 time, Decay=0.03..3 time, Click=0..100 percent, Drive=0..100 percent, Tone=150..16000 freq, Wave=0..100 percent; Snare: Tune=120..400 freq, Noise=0..100 percent, Decay=0.03..0.5 time, N.Decay=0.03..0.6 time, N.Tone=800..8000 freq, P.Depth=1..3 ratio, P.Decay=0.005..0.3 time, Drive=0..100 percent; HiHat: Tune=160..640 freq, Decay=0.02..1 time, Tone=2000..12000 freq, Metal=0..100 percent, Noise=0..100 percent; Clap: Freq=400..3500 freq, Spread=0.004..0.02 time, Decay=0.05..2 time, Reso=1..12 num, Drive=0..100 percent; Tom: Tune=80..400 note, P.Depth=1..3 ratio, Decay=0.05..2.5 time, Tone=120..12000 freq, Noise=0..100 percent, Drive=0..100 percent, P.Decay=0.01..0.8 time; FM: Tune=50..1000 note, Ratio=0.5..8 ratio, FM Amt=0..24 num, Decay=0.03..3 time, FM Decay=0..100 percent, F.Back=0..100 percent, Drive=0..100 percent; Cymbal: Tune=140..560 freq, Decay=0.2..4 time, Tone=3000..14000 freq, Metal=0..100 percent, Sizzle=0..100 percent; Cowbell: Tune=300..900 note, Decay=0.08..0.8 time, Ratio=1.2..1.8 ratio, Tone=700..9000 freq, Drive=0..100 percent; 808: Tune=27.5..220 note, P.Depth=0..36 st, P.Time=0.005..0.12 time, Decay=0.1..8 time, Saturate=0..100 percent, Click=0..100 percent, Tone=80..6000 freq; Shaker: Tune=2000..12000 freq, Color=0..100 percent, Onset=0.0005..0.05 time, Decay=0.02..0.6 time, Rattle=0..0.012 time, Tone=0..100 percent; Rim: Tune=200..2500 note, Ring=0..100 percent, Decay=0.015..0.15 time, Partial=1..2.7 ratio, Snap=0..100 percent, Drive=0..100 percent; Conga: Tune=75..700 note, Slap=1..2.5 ratio, Decay=0.08..0.7 time, Partial=1.4..2 ratio, Tone=300..9000 freq, Skin=0..100 percent, Drive=0..100 percent; Bell: Tune=200..1800 note, Ratio=1.4..7 ratio, FM Amt=0..10 num, Decay=0.2..4 time, Inharm=0..100 percent, Strike=0..100 percent, Tone=800..18000 freq; Pluck: Tune=60..1200 note, Sustain=0..100 percent, Damp=0..100 percent, Excite=0..100 percent, Bright=300..12000 freq, Drive=0..100 percent, Decay=0.3..6 time; Zap: Tune=40..2000 note, Sweep=-6..6 num, S.Time=0.02..1 time, Decay=0.03..1.5 time, Timbre=0..100 percent, Noise=0..100 percent, Drive=0..100 percent, Tone=200..14000 freq; Wave: Tune=40..2000 note, Position=0..100 percent, P.Env=1..4 ratio, Decay=0.03..1.5 time, Bright=300..14000 freq, Fold=0..100 percent, Drive=0..100 percent, Draw=0..100 percent; Chaos: Tune=40..6000 note, Chaos=0..100 percent, Decay=0.03..1.2 time, Tone=300..12000 freq, Drive=0..100 percent, Noise=0..100 percent; Stab: Tune=35..1000 note, Shape=0..100 percent, Width=0..100 percent, Chord=0..6 num, Detune=0..100 percent, Decay=0.05..3 time, Tone=200..16000 freq, Drive=0..100 percent; Acoustic Kick: Tune=35..120 note, Punch=1..4 ratio, Decay=0.12..1.8 time, Beater=0..100 percent, Shell=0..100 percent, Damp=0..100 percent, Tone=200..9000 freq, Drive=0..100 percent; Acoustic Snare: Tune=110..440 note, Depth=0..100 percent, Decay=0.08..1.2 time, Snap=0..100 percent, Wires=0..100 percent, Buzz=0.03..0.9 time, Tone=400..12000 freq, Drive=0..100 percent; Acoustic Cymbal: Size=180..900 freq, Strike=0..100 percent, Decay=0.4..8 time, Bell=0..100 percent, Sizzle=0..100 percent, Tone=200..6000 freq, Spread=0..100 percent, Drive=0..100 percent; Acoustic Hi-Hat: Size=260..1100 freq, Open=0..100 percent, Decay=0.08..4.5 time, Strike=0..100 percent, Chatter=0..100 percent, Sizzle=0..100 percent, Tone=1200..16000 freq, Drive=0..100 percent
durationnumbernoDuration in seconds. From 0.05 to 30. Default 1.
velocitynumbernoDrum trigger velocity. From 0 to 1. Default 1.
triggersstringnoComma-separated trigger times in seconds. Default "0".
sampleRateintegernoOutput sample rate. From 22050 to 48000. Default 48000.
metadatamap of stringnoUp to 20 string pairs stored with the job. At most 20 entries.
curl
curl -sS "https://api.map.audio/v1/synth/drum" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01" \
  -H "Prefer: wait=30" \
  -H "Content-Type: application/json" \
  -d '{"engine":"808","param":"Tune=55,Decay=1.5","duration":2}'
Request: A two-second 808 tuned to 55 Hz
{
  "engine": "808",
  "param": "Tune=55,Decay=1.5",
  "duration": 2
}
200: Finished
{
  "object": "job",
  "id": "job_01M6BPRFPCH9EBPY7B6JKM7CE1",
  "operation": "synthDrum",
  "status": "succeeded",
  "livemode": false,
  "sequence": 3,
  "progress": 1,
  "queuePosition": null,
  "createdAt": "2026-11-01T14:03:31.512Z",
  "startedAt": "2026-11-01T14:03:33.104Z",
  "finishedAt": "2026-11-01T14:03:41.877Z",
  "estimate": {
    "audioSeconds": 2,
    "renderMinutes": 0
  },
  "result": {
    "outputs": [
      {
        "role": "master",
        "name": null,
        "cell": null,
        "file": "file_01M6BPRMNR7PYGFNA66BX2YJ8M",
        "sha256": "13d41d922519699fc14a7587130eceee7d0f149414350000578de1564866a0d4",
        "bytes": 576044,
        "format": "wav",
        "sampleRate": 48000,
        "durationSeconds": 2,
        "url": "https://api.map.audio/v1/download/file_01M6BPRMNR7PYGFNA66BX2YJ8M?expires=1793545422&signature=GQ2GkmPjqXuxxBSSM4NKBCY7OjU7w3YSeZBrCoxxtbY",
        "expiresAt": "2026-11-01T15:03:42.000Z"
      }
    ],
    "seed": null,
    "command": {
      "ok": true,
      "wavPath": "file_01M6BPRMNR7PYGFNA66BX2YJ8M",
      "sampleRate": 48000,
      "channels": 2,
      "durationSeconds": 2,
      "engine": "808"
    },
    "provenance": {
      "object": "provenance",
      "id": "prov_01M6BPRVA8ZC7F7J737SQ0EPN2",
      "jobId": "job_01M6BPRFPCH9EBPY7B6JKM7CE1",
      "createdAt": "2026-11-01T14:03:41.877Z",
      "engine": {
        "product": "pam",
        "version": null,
        "runtime": "native-linux-x86_64",
        "image": "registry.cloudflare.com/c7c2e61448617e81ced650f444fb6787/pam-render@sha256:5c5ffe3fabc103e277280fbd65a08988d31361f00fe7857e36f603d67bcec42d"
      },
      "seed": null,
      "presets": [],
      "packs": [],
      "userFiles": [],
      "inputs": [],
      "outputs": [
        {
          "file": "file_01M6BPRMNR7PYGFNA66BX2YJ8M",
          "sha256": "13d41d922519699fc14a7587130eceee7d0f149414350000578de1564866a0d4"
        }
      ],
      "planner": null,
      "contracts": {
        "api": "2026-11-01",
        "pam.cli": 1
      },
      "aiModels": [],
      "audioByModel": false,
      "license": {
        "id": "lic_api_prototype_test",
        "commercialUse": false,
        "attribution": true
      },
      "kid": "6c2f0a9d4b7e1358",
      "signature": "ed25519:LEVZHpOHj8BMGZgJh-_Y7SmKbqDlBDR8LqY-XelU6GYK8lntZqg3rRK4b3BH8cy25bK0iWzOXFXmkiGHEYue7A"
    }
  },
  "error": null,
  "usage": {
    "renderMinutes": 0,
    "audioSeconds": 2,
    "computeMs": 6273
  },
  "metadata": {},
  "urls": {
    "self": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1",
    "events": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/events",
    "cancel": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/cancel"
  }
}
202: Still running
{
  "object": "job",
  "id": "job_01M6BPRFPCH9EBPY7B6JKM7CE1",
  "operation": "synthDrum",
  "status": "running",
  "livemode": false,
  "sequence": 2,
  "progress": 0,
  "queuePosition": null,
  "createdAt": "2026-11-01T14:03:31.512Z",
  "startedAt": "2026-11-01T14:03:33.104Z",
  "finishedAt": null,
  "estimate": {
    "audioSeconds": 2,
    "renderMinutes": 0
  },
  "result": null,
  "error": null,
  "usage": null,
  "metadata": {},
  "urls": {
    "self": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1",
    "events": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/events",
    "cancel": "https://api.map.audio/v1/jobs/job_01M6BPRFPCH9EBPY7B6JKM7CE1/cancel"
  }
}
400: Invalid request
{
  "error": {
    "type": "invalid_request",
    "code": "invalid_request",
    "message": "duration must be at most 30; got 45.",
    "param": "duration",
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#invalid_request",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 200 The finished job: `result.outputs` link each file it wrote and `result.command` is the engine's own result., 202 The job, still running when `Prefer: wait` ran out; poll `urls.self`., 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: invalid_request, unsupported_media_type, payload_too_large, terms_required, concurrency_limit, idempotency_key_reused, idempotency_in_flight, queue_unavailable.

View as Markdown

Jobs

Every engine call is a job: read it, wait for it, stream its events or cancel it.

GET/v1/jobs

listJobs

List jobs

The account's jobs, newest first, optionally filtered by status and operation, with fresh download links on the outputs. Jobs from test and live keys are listed together. Job records are kept 90 days. Free.

  • Auth: Authorization: Bearer with an API key or a map.audio access token.
  • MCP tool: list_jobs
listJobs parameters
NameInTypeRequiredDescription
statusquery"queued" | "running" | "succeeded" | "failed" | "cancelled" | "expired"noOnly jobs in this status.
operationquerystringnoOnly jobs of this operation: renders.create, uploads.complete, or a command's operationId such as presetRender.
limitqueryintegernoJobs per page. From 1 to 100. Default 25.
cursorquerystringnoThe nextCursor of the previous page.
curl
curl -sS "https://api.map.audio/v1/jobs?operation=renders.create" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01"
200: The latest job
{
  "object": "list",
  "data": [
    {
      "object": "job",
      "id": "job_01M6BPRE186QHP9QPYGDX5NNFP",
      "operation": "renders.create",
      "status": "succeeded",
      "livemode": false,
      "sequence": 3,
      "progress": 1,
      "queuePosition": null,
      "createdAt": "2026-11-01T14:03:31.512Z",
      "startedAt": "2026-11-01T14:03:33.104Z",
      "finishedAt": "2026-11-01T14:03:41.877Z",
      "estimate": {
        "audioSeconds": 16,
        "renderMinutes": 0.267
      },
      "result": {
        "outputs": [
          {
            "role": "master",
            "name": null,
            "cell": null,
            "file": "file_01M6BPRK0M34NBP2XKJ1RMX1TQ",
            "sha256": "5a3485b7a3221be5f7ead6ab953cbc198988a7246158215b32bb937acbd3852b",
            "bytes": 4608044,
            "format": "wav",
            "sampleRate": 48000,
            "durationSeconds": 16,
            "url": "https://api.map.audio/v1/download/file_01M6BPRK0M34NBP2XKJ1RMX1TQ?expires=1793545422&signature=yaoMrgCHcK9T8MaVnCVtXZc4Ym0FWWM8P-0feZDMObk",
            "expiresAt": "2026-11-01T15:03:42.000Z"
          }
        ],
        "seed": 42,
        "command": {
          "ok": true,
          "wavPath": "file_01M6BPRK0M34NBP2XKJ1RMX1TQ",
          "sampleRate": 48000,
          "channels": 2,
          "durationSeconds": 16,
          "seed": 42,
          "stems": [],
          "stemTap": "post_cell_pre_master",
          "latencySamples": 0,
          "missingSamples": []
        },
        "spec": {
          "source": {
            "preset": "pam:factory/313-disco"
          },
          "plan": null,
          "bars": 8,
          "seconds": null,
          "tail": 0,
          "seed": 42,
          "stems": false,
          "sampleRate": 48000,
          "format": {
            "container": "wav"
          },
          "quality": "draft",
          "tempo": 120
        },
        "provenance": {
          "object": "provenance",
          "id": "prov_01M6BPRVA8ZC7F7J737SQ0EPN2",
          "jobId": "job_01M6BPRE186QHP9QPYGDX5NNFP",
          "createdAt": "2026-11-01T14:03:41.877Z",
          "engine": {
            "product": "pam",
            "version": null,
            "runtime": "native-linux-x86_64",
            "image": "registry.cloudflare.com/c7c2e61448617e81ced650f444fb6787/pam-render@sha256:5c5ffe3fabc103e277280fbd65a08988d31361f00fe7857e36f603d67bcec42d"
          },
          "seed": 42,
          "presets": [
            {
              "ref": "pam:factory/313-disco",
              "sha256": "3afbf5dea1003b2d17385955017785a57d74c65f77f97b58cf5d7cec9794ca1c"
            }
          ],
          "packs": [],
          "userFiles": [],
          "inputs": [],
          "outputs": [
            {
              "file": "file_01M6BPRK0M34NBP2XKJ1RMX1TQ",
              "sha256": "5a3485b7a3221be5f7ead6ab953cbc198988a7246158215b32bb937acbd3852b"
            }
          ],
          "planner": null,
          "contracts": {
            "api": "2026-11-01",
            "pam.cli": 1
          },
          "aiModels": [],
          "audioByModel": false,
          "license": {
            "id": "lic_api_prototype_test",
            "commercialUse": false,
            "attribution": true
          },
          "kid": "6c2f0a9d4b7e1358",
          "signature": "ed25519:jsfkW3eF1r4kChqccp6AKLTvjTK5Re8acrEusqigz7MDUu6uZhsJXVnuQEl6EsErDgVYNXOkos9d0mMyt2CVCg"
        }
      },
      "error": null,
      "usage": {
        "renderMinutes": 0.267,
        "audioSeconds": 16,
        "computeMs": 6273
      },
      "metadata": {},
      "urls": {
        "self": "https://api.map.audio/v1/jobs/job_01M6BPRE186QHP9QPYGDX5NNFP",
        "events": "https://api.map.audio/v1/jobs/job_01M6BPRE186QHP9QPYGDX5NNFP/events",
        "cancel": "https://api.map.audio/v1/jobs/job_01M6BPRE186QHP9QPYGDX5NNFP/cancel"
      }
    }
  ],
  "nextCursor": null
}
400: Invalid request
{
  "error": {
    "type": "invalid_request",
    "code": "invalid_request",
    "message": "status must be one of queued, running, succeeded, failed, cancelled or expired; got \"done\".",
    "param": "status",
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#invalid_request",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 200 Jobs., 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: invalid_request.

View as Markdown

GET/v1/jobs/{id}

getJob

Get a job

A job as it stands: status, progress and estimate, and once it ends, its outputs with download links valid for an hour, the seed, the engine's own result, the provenance record and the render-minutes it was charged. Poll it after a 202, or read it when a webhook says the job ended. Free.

  • Auth: Authorization: Bearer with an API key or a map.audio access token.
  • MCP tool: get_job
getJob parameters
NameInTypeRequiredDescription
idpathstringyesA job id (job_…), from the response that created the job or GET /v1/jobs. Matches ^job_[0-9A-HJKMNP-TV-Z]{26}$.
curl
curl -sS "https://api.map.audio/v1/jobs/job_01M6BPRE186QHP9QPYGDX5NNFP" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01"
200: Succeeded: 16 s of 313 Disco
{
  "object": "job",
  "id": "job_01M6BPRE186QHP9QPYGDX5NNFP",
  "operation": "renders.create",
  "status": "succeeded",
  "livemode": false,
  "sequence": 3,
  "progress": 1,
  "queuePosition": null,
  "createdAt": "2026-11-01T14:03:31.512Z",
  "startedAt": "2026-11-01T14:03:33.104Z",
  "finishedAt": "2026-11-01T14:03:41.877Z",
  "estimate": {
    "audioSeconds": 16,
    "renderMinutes": 0.267
  },
  "result": {
    "outputs": [
      {
        "role": "master",
        "name": null,
        "cell": null,
        "file": "file_01M6BPRK0M34NBP2XKJ1RMX1TQ",
        "sha256": "5a3485b7a3221be5f7ead6ab953cbc198988a7246158215b32bb937acbd3852b",
        "bytes": 4608044,
        "format": "wav",
        "sampleRate": 48000,
        "durationSeconds": 16,
        "url": "https://api.map.audio/v1/download/file_01M6BPRK0M34NBP2XKJ1RMX1TQ?expires=1793545422&signature=yaoMrgCHcK9T8MaVnCVtXZc4Ym0FWWM8P-0feZDMObk",
        "expiresAt": "2026-11-01T15:03:42.000Z"
      }
    ],
    "seed": 42,
    "command": {
      "ok": true,
      "wavPath": "file_01M6BPRK0M34NBP2XKJ1RMX1TQ",
      "sampleRate": 48000,
      "channels": 2,
      "durationSeconds": 16,
      "seed": 42,
      "stems": [],
      "stemTap": "post_cell_pre_master",
      "latencySamples": 0,
      "missingSamples": []
    },
    "spec": {
      "source": {
        "preset": "pam:factory/313-disco"
      },
      "plan": null,
      "bars": 8,
      "seconds": null,
      "tail": 0,
      "seed": 42,
      "stems": false,
      "sampleRate": 48000,
      "format": {
        "container": "wav"
      },
      "quality": "draft",
      "tempo": 120
    },
    "provenance": {
      "object": "provenance",
      "id": "prov_01M6BPRVA8ZC7F7J737SQ0EPN2",
      "jobId": "job_01M6BPRE186QHP9QPYGDX5NNFP",
      "createdAt": "2026-11-01T14:03:41.877Z",
      "engine": {
        "product": "pam",
        "version": null,
        "runtime": "native-linux-x86_64",
        "image": "registry.cloudflare.com/c7c2e61448617e81ced650f444fb6787/pam-render@sha256:5c5ffe3fabc103e277280fbd65a08988d31361f00fe7857e36f603d67bcec42d"
      },
      "seed": 42,
      "presets": [
        {
          "ref": "pam:factory/313-disco",
          "sha256": "3afbf5dea1003b2d17385955017785a57d74c65f77f97b58cf5d7cec9794ca1c"
        }
      ],
      "packs": [],
      "userFiles": [],
      "inputs": [],
      "outputs": [
        {
          "file": "file_01M6BPRK0M34NBP2XKJ1RMX1TQ",
          "sha256": "5a3485b7a3221be5f7ead6ab953cbc198988a7246158215b32bb937acbd3852b"
        }
      ],
      "planner": null,
      "contracts": {
        "api": "2026-11-01",
        "pam.cli": 1
      },
      "aiModels": [],
      "audioByModel": false,
      "license": {
        "id": "lic_api_prototype_test",
        "commercialUse": false,
        "attribution": true
      },
      "kid": "6c2f0a9d4b7e1358",
      "signature": "ed25519:jsfkW3eF1r4kChqccp6AKLTvjTK5Re8acrEusqigz7MDUu6uZhsJXVnuQEl6EsErDgVYNXOkos9d0mMyt2CVCg"
    }
  },
  "error": null,
  "usage": {
    "renderMinutes": 0.267,
    "audioSeconds": 16,
    "computeMs": 6273
  },
  "metadata": {},
  "urls": {
    "self": "https://api.map.audio/v1/jobs/job_01M6BPRE186QHP9QPYGDX5NNFP",
    "events": "https://api.map.audio/v1/jobs/job_01M6BPRE186QHP9QPYGDX5NNFP/events",
    "cancel": "https://api.map.audio/v1/jobs/job_01M6BPRE186QHP9QPYGDX5NNFP/cancel"
  }
}
404: Not found
{
  "error": {
    "type": "not_found",
    "code": "not_found",
    "message": "No job with that id; GET /v1/jobs lists this account's jobs.",
    "param": "id",
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#not_found",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 200 The job., 404 Not found, default Any other error: `error.code` names it, `error.param` the field at fault, and `error.docUrl` its entry in the error catalogue..

Errors: not_found, invalid_request.

View as Markdown

POST/v1/jobs/{id}/cancel

cancelJob

Cancel a job

Stop a queued or running job. A queued job ends cancelled at once and a running one when its engine stops; nothing is charged unless the job already published a preview. A job that already ended keeps its outcome. Free.

  • Auth: Authorization: Bearer with an API key or a map.audio access token.
  • MCP tool: cancel_job
cancelJob parameters
NameInTypeRequiredDescription
idpathstringyesA job id (job_…), from the response that created the job or GET /v1/jobs. Matches ^job_[0-9A-HJKMNP-TV-Z]{26}$.
curl
curl -sS -X POST "https://api.map.audio/v1/jobs/job_01M6BPRE186QHP9QPYGDX5NNFP/cancel" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01"
200: Cancelled while queued
{
  "object": "job",
  "id": "job_01M6BPRE186QHP9QPYGDX5NNFP",
  "operation": "renders.create",
  "status": "cancelled",
  "livemode": false,
  "sequence": 2,
  "progress": 0,
  "queuePosition": null,
  "createdAt": "2026-11-01T14:03:31.512Z",
  "startedAt": null,
  "finishedAt": "2026-11-01T14:03:32.204Z",
  "estimate": {
    "audioSeconds": 16,
    "renderMinutes": 0.267
  },
  "result": null,
  "error": null,
  "usage": null,
  "metadata": {},
  "urls": {
    "self": "https://api.map.audio/v1/jobs/job_01M6BPRE186QHP9QPYGDX5NNFP",
    "events": "https://api.map.audio/v1/jobs/job_01M6BPRE186QHP9QPYGDX5NNFP/events",
    "cancel": "https://api.map.audio/v1/jobs/job_01M6BPRE186QHP9QPYGDX5NNFP/cancel"
  }
}
404: Not found
{
  "error": {
    "type": "not_found",
    "code": "not_found",
    "message": "No job with that id; GET /v1/jobs lists this account's jobs.",
    "param": "id",
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#not_found",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 200 The job., 404 Not found, default Any other error: `error.code` names it, `error.param` the field at fault, and `error.docUrl` its entry in the error catalogue..

Errors: not_found, idempotency_key_unsupported, invalid_request.

View as Markdown

GET/v1/jobs/{id}/events

streamJobEvents

Stream a job's events

Server-sent events for one job: job.queued, job.started, job.progress, job.preview and job.requeued, then job.succeeded, job.failed, job.cancelled or job.expired. Each event's data is JSON with jobId and createdAt; job.preview carries the preview's outputs, and job.failed the error. Reconnect with Last-Event-ID (or after) to miss nothing; a stream closes after 10 minutes or once the job has ended. A browser's EventSource cannot send Authorization, so read it with fetch. Free.

  • Auth: Authorization: Bearer with an API key or a map.audio access token.
  • Not an MCP tool: A server-sent event stream; MCP tools answer once, so poll get_job instead.
streamJobEvents parameters
NameInTypeRequiredDescription
idpathstringyesA job id (job_…), from the response that created the job or GET /v1/jobs. Matches ^job_[0-9A-HJKMNP-TV-Z]{26}$.
afterqueryintegernoResume after this event id, as the Last-Event-ID header does. At least 0.
Last-Event-IDheaderstringnoThe last event id received; the stream resumes after it. Matches ^\d{1,9}$.
curl
curl -sS "https://api.map.audio/v1/jobs/job_01M6BPRE186QHP9QPYGDX5NNFP/events?after=2" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01"
404: Not found
{
  "error": {
    "type": "not_found",
    "code": "not_found",
    "message": "No job with that id; GET /v1/jobs lists this account's jobs.",
    "param": "id",
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#not_found",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 200 The event stream., 404 Not found, default Any other error: `error.code` names it, `error.param` the field at fault, and `error.docUrl` its entry in the error catalogue..

Errors: not_found, invalid_request.

View as Markdown

Files

Render outputs and uploads, with signed download links. Uploads stay off until the decoder and project-reader fuzzers have run.

GET/v1/files

listFiles

List files

Render outputs and uploads the account holds, newest first: kind, status, size, SHA-256 and the job that wrote each. Outputs are kept 7 days on the free tier and longer on paid tiers. Free.

  • Auth: Authorization: Bearer with an API key or a map.audio access token.
  • MCP tool: list_files
listFiles parameters
NameInTypeRequiredDescription
limitqueryintegernoFiles per page. From 1 to 100. Default 25.
cursorquerystringnoThe nextCursor of the previous page.
curl
curl -sS "https://api.map.audio/v1/files" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01"
200: One output
{
  "object": "list",
  "data": [
    {
      "object": "file",
      "id": "file_01M6BPRK0M34NBP2XKJ1RMX1TQ",
      "kind": "output",
      "status": "ready",
      "name": "master.wav",
      "contentType": "audio/wav",
      "bytes": 4608044,
      "sha256": "5a3485b7a3221be5f7ead6ab953cbc198988a7246158215b32bb937acbd3852b",
      "jobId": "job_01M6BPRE186QHP9QPYGDX5NNFP",
      "role": "master",
      "createdAt": "2026-11-01T14:03:41.877Z",
      "expiresAt": "2026-11-08T14:03:41.877Z"
    }
  ],
  "nextCursor": null
}
400: Invalid request
{
  "error": {
    "type": "invalid_request",
    "code": "invalid_request",
    "message": "The cursor is not one this API issued; pass the nextCursor of the page before, unchanged.",
    "param": "cursor",
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#invalid_request",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 200 Files., 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: invalid_request.

View as Markdown

GET/v1/files/{id}

getFile

Get a file

One file's metadata: kind, status, name, content type, size, SHA-256, the job that wrote it and when retention deletes it. For its bytes, GET /v1/files/{id}/content. Free.

  • Auth: Authorization: Bearer with an API key or a map.audio access token.
  • MCP tool: get_file
getFile parameters
NameInTypeRequiredDescription
idpathstringyesA file id (file_…), from a job's result.outputs or GET /v1/files. Matches ^file_[0-9A-HJKMNP-TV-Z]{26}$.
curl
curl -sS "https://api.map.audio/v1/files/file_01M6BPRK0M34NBP2XKJ1RMX1TQ" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01"
200: A render's master
{
  "object": "file",
  "id": "file_01M6BPRK0M34NBP2XKJ1RMX1TQ",
  "kind": "output",
  "status": "ready",
  "name": "master.wav",
  "contentType": "audio/wav",
  "bytes": 4608044,
  "sha256": "5a3485b7a3221be5f7ead6ab953cbc198988a7246158215b32bb937acbd3852b",
  "jobId": "job_01M6BPRE186QHP9QPYGDX5NNFP",
  "role": "master",
  "createdAt": "2026-11-01T14:03:41.877Z",
  "expiresAt": "2026-11-08T14:03:41.877Z"
}
404: Not found
{
  "error": {
    "type": "not_found",
    "code": "not_found",
    "message": "No file with that id; GET /v1/files lists this account's files.",
    "param": "id",
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#not_found",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 200 The file., 404 Not found, default Any other error: `error.code` names it, `error.param` the field at fault, and `error.docUrl` its entry in the error catalogue..

Errors: not_found, invalid_request.

View as Markdown

DELETE/v1/files/{id}

deleteFile

Delete a file

Delete a file's bytes now, before retention would; its record stays with status deleted, and an output leaves its job's outputs. A file whose job is still running cannot be deleted yet. Free.

  • Auth: Authorization: Bearer with an API key or a map.audio access token.
  • Not an MCP tool: Deleting a render cannot be undone, so it stays with your own code: DELETE /v1/files/{id} with an API key.
deleteFile parameters
NameInTypeRequiredDescription
idpathstringyesA file id (file_…), from a job's result.outputs or GET /v1/files. Matches ^file_[0-9A-HJKMNP-TV-Z]{26}$.
curl
curl -sS -X DELETE "https://api.map.audio/v1/files/file_01M6BPRK0M34NBP2XKJ1RMX1TQ" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01"
200: Deleted
{
  "object": "file",
  "id": "file_01M6BPRK0M34NBP2XKJ1RMX1TQ",
  "kind": "output",
  "status": "deleted",
  "name": "master.wav",
  "contentType": "audio/wav",
  "bytes": 4608044,
  "sha256": "5a3485b7a3221be5f7ead6ab953cbc198988a7246158215b32bb937acbd3852b",
  "jobId": "job_01M6BPRE186QHP9QPYGDX5NNFP",
  "role": "master",
  "createdAt": "2026-11-01T14:03:41.877Z",
  "expiresAt": "2026-11-08T14:03:41.877Z"
}
409: File not ready
{
  "error": {
    "type": "conflict",
    "code": "file_not_ready",
    "message": "File file_01M6BPRK0M34NBP2XKJ1RMX1TQ is still being written by job_01M6BPRE186QHP9QPYGDX5NNFP; retry when that job succeeds.",
    "param": "id",
    "retryable": true,
    "jobId": "job_01M6BPRE186QHP9QPYGDX5NNFP",
    "docUrl": "https://map.audio/developers/music-api/errors#file_not_ready",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 200 The file, deleted., 409 File not ready, default Any other error: `error.code` names it, `error.param` the field at fault, and `error.docUrl` its entry in the error catalogue..

Errors: not_found, file_not_ready, invalid_request.

View as Markdown

GET/v1/files/{id}/content

getFileContent

Download a file

Redirects (302) to a signed link for the file's bytes, valid for one hour; the link needs no Authorization header. Job outputs already carry such a link in url; use this route for a fresh one. Free.

  • Auth: Authorization: Bearer with an API key or a map.audio access token.
  • Not an MCP tool: Answers with a redirect to raw bytes, which a tool result cannot carry; get_job lists each output with a signed download url.
getFileContent parameters
NameInTypeRequiredDescription
idpathstringyesA file id (file_…), from a job's result.outputs or GET /v1/files. Matches ^file_[0-9A-HJKMNP-TV-Z]{26}$.
curl
curl -sSL --fail-with-body -o render.wav "https://api.map.audio/v1/files/file_01M6BPRK0M34NBP2XKJ1RMX1TQ/content" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01"
410: File no longer stored
{
  "error": {
    "type": "gone",
    "code": "file_expired",
    "message": "File file_01M6BPRK0M34NBP2XKJ1RMX1TQ expired at 2026-11-08T14:03:41.877Z; render it again.",
    "param": "id",
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#file_expired",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 302 Redirect to the signed download link., 410 File no longer stored, default Any other error: `error.code` names it, `error.param` the field at fault, and `error.docUrl` its entry in the error catalogue..

Errors: not_found, file_not_ready, file_expired, invalid_request.

View as Markdown

POST/v1/uploads

createUpload

Start an upload

Start a multipart upload of an audio file or a DAW project, declared by kind, name, size and SHA-256. Send the parts with PUT /v1/uploads/{id}/parts/{part}, then POST /v1/uploads/{id}/complete. Uploads are off until the decoder and project-reader fuzzers have run, so today this answers 403 uploads_disabled. Free.

  • Auth: Authorization: Bearer with an API key or a map.audio access token.
  • Not an MCP tool: Uploads send raw bytes in parts, which a JSON tool call cannot carry; uploads are also off until the decoder fuzzers have run.
createUpload body
FieldTypeRequiredDescription
kind"audio" | "sample" | "project"yessample is an alias of audio. Preset and project-folder uploads are not served yet.
namestringyesAt most 255 characters.
bytesintegeryesAt least 1.
sha256stringyesMatches ^[0-9a-f]{64}$.
curl
curl -sS "https://api.map.audio/v1/uploads" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01" \
  -H "Content-Type: application/json" \
  -d '{"kind":"audio","name":"vocal-take.wav","bytes":23040044,"sha256":"3b8f1c6e2d9a4b7e0f5c1a8d6e3b9f2c4a7d0e1b5c8f3a6d9e2b4c7f0a1d3e5b"}'
Request: A 24-bit WAV
{
  "kind": "audio",
  "name": "vocal-take.wav",
  "bytes": 23040044,
  "sha256": "3b8f1c6e2d9a4b7e0f5c1a8d6e3b9f2c4a7d0e1b5c8f3a6d9e2b4c7f0a1d3e5b"
}
201: Two parts to send
{
  "object": "upload",
  "id": "file_01M6BPRR00A11F2KEPGNR7V3Q9",
  "file": "file_01M6BPRR00A11F2KEPGNR7V3Q9",
  "kind": "audio",
  "status": "uploading",
  "partBytes": 16777216,
  "parts": 2,
  "expiresAt": "2026-11-02T14:20:00.000Z"
}
403: Uploads not open yet
{
  "error": {
    "type": "entitlement",
    "code": "uploads_disabled",
    "message": "File uploads are not open yet; render from factory presets (GET /v1/presets) and pass render outputs as files meanwhile.",
    "param": null,
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#uploads_disabled",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 201 The upload., 403 Uploads not open yet, default Any other error: `error.code` names it, `error.param` the field at fault, and `error.docUrl` its entry in the error catalogue..

Errors: uploads_disabled, terms_required, invalid_request, unsupported_media_type, payload_too_large, idempotency_key_unsupported.

View as Markdown

PUT/v1/uploads/{id}/parts/{part}

putUploadPart

Send one upload part

Send one part of an upload as raw bytes with its exact Content-Length: every part but the last is partBytes long (16 MiB), the last holds the rest. Sending a part again replaces it. Uploads are off for now, so this answers 403 uploads_disabled. Free.

  • Auth: Authorization: Bearer with an API key or a map.audio access token.
  • Not an MCP tool: Uploads send raw bytes in parts, which a JSON tool call cannot carry; uploads are also off until the decoder fuzzers have run.
putUploadPart parameters
NameInTypeRequiredDescription
idpathstringyesThe upload's file id (file_…), from POST /v1/uploads. Matches ^file_[0-9A-HJKMNP-TV-Z]{26}$.
partpathintegeryesThe part number, from 1. From 1 to 10000.
curl
curl -sS -X PUT "https://api.map.audio/v1/uploads/file_01M6BPRR00A11F2KEPGNR7V3Q9/parts/1" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01" \
  -H "Content-Type: application/octet-stream" \
  --data-binary @part.bin
200: Part 1 stored
{
  "object": "upload_part",
  "upload": "file_01M6BPRR00A11F2KEPGNR7V3Q9",
  "part": 1,
  "bytes": 16777216
}
403: Uploads not open yet
{
  "error": {
    "type": "entitlement",
    "code": "uploads_disabled",
    "message": "File uploads are not open yet; render from factory presets (GET /v1/presets) and pass render outputs as files meanwhile.",
    "param": null,
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#uploads_disabled",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 200 The part, stored., 403 Uploads not open yet, default Any other error: `error.code` names it, `error.param` the field at fault, and `error.docUrl` its entry in the error catalogue..

Errors: uploads_disabled, terms_required, not_found, invalid_request, upload_closed, upload_expired.

View as Markdown

POST/v1/uploads/{id}/complete

completeUpload

Finish an upload

Close the upload and start its probe job: the render host checks the bytes against the declared SHA-256 and rewrites audio as a canonical WAV, after which the file is ready for commands. Answers with the probe job; completing again retries a probe that never started. Uploads are off for now, so this answers 403 uploads_disabled. Free.

  • Auth: Authorization: Bearer with an API key or a map.audio access token.
  • Send Prefer: wait=N (0 to 60) to receive the finished job when it ends within N seconds.
  • Send Idempotency-Key to retry safely: the same key and body return the same result for 24 hours.
  • Not an MCP tool: Uploads send raw bytes in parts, which a JSON tool call cannot carry; uploads are also off until the decoder fuzzers have run.
completeUpload parameters
NameInTypeRequiredDescription
idpathstringyesThe upload's file id (file_…), from POST /v1/uploads. Matches ^file_[0-9A-HJKMNP-TV-Z]{26}$.
curl
curl -sS -X POST "https://api.map.audio/v1/uploads/file_01M6BPRR00A11F2KEPGNR7V3Q9/complete" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01" \
  -H "Prefer: wait=30"
200: Probe finished
{
  "object": "job",
  "id": "job_01M6BPRE186QHP9QPYGDX5NNFP",
  "operation": "uploads.complete",
  "status": "succeeded",
  "livemode": false,
  "sequence": 3,
  "progress": 1,
  "queuePosition": null,
  "createdAt": "2026-11-01T14:03:31.512Z",
  "startedAt": "2026-11-01T14:03:33.104Z",
  "finishedAt": "2026-11-01T14:03:41.877Z",
  "estimate": {
    "audioSeconds": 0,
    "renderMinutes": 0
  },
  "result": {
    "outputs": [],
    "seed": null,
    "command": {
      "probe": {
        "ok": true,
        "durationSeconds": 120,
        "sampleRate": 48000,
        "channels": 2
      }
    },
    "provenance": null
  },
  "error": null,
  "usage": {
    "renderMinutes": 0,
    "audioSeconds": 0,
    "computeMs": 2210
  },
  "metadata": {},
  "urls": {
    "self": "https://api.map.audio/v1/jobs/job_01M6BPRE186QHP9QPYGDX5NNFP",
    "events": "https://api.map.audio/v1/jobs/job_01M6BPRE186QHP9QPYGDX5NNFP/events",
    "cancel": "https://api.map.audio/v1/jobs/job_01M6BPRE186QHP9QPYGDX5NNFP/cancel"
  }
}
202: Probe queued
{
  "object": "job",
  "id": "job_01M6BPRE186QHP9QPYGDX5NNFP",
  "operation": "uploads.complete",
  "status": "queued",
  "livemode": false,
  "sequence": 1,
  "progress": 0,
  "queuePosition": null,
  "createdAt": "2026-11-01T14:03:31.512Z",
  "startedAt": null,
  "finishedAt": null,
  "estimate": {
    "audioSeconds": 0,
    "renderMinutes": 0
  },
  "result": null,
  "error": null,
  "usage": null,
  "metadata": {},
  "urls": {
    "self": "https://api.map.audio/v1/jobs/job_01M6BPRE186QHP9QPYGDX5NNFP",
    "events": "https://api.map.audio/v1/jobs/job_01M6BPRE186QHP9QPYGDX5NNFP/events",
    "cancel": "https://api.map.audio/v1/jobs/job_01M6BPRE186QHP9QPYGDX5NNFP/cancel"
  }
}
403: Uploads not open yet
{
  "error": {
    "type": "entitlement",
    "code": "uploads_disabled",
    "message": "File uploads are not open yet; render from factory presets (GET /v1/presets) and pass render outputs as files meanwhile.",
    "param": null,
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#uploads_disabled",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 200 The probe job, finished., 202 The probe job, queued., 403 Uploads not open yet, default Any other error: `error.code` names it, `error.param` the field at fault, and `error.docUrl` its entry in the error catalogue..

Errors: uploads_disabled, terms_required, not_found, invalid_request, upload_closed, upload_expired, upload_incomplete, upload_processing, checksum_mismatch, concurrency_limit, idempotency_key_reused, idempotency_in_flight, queue_unavailable.

View as Markdown

Webhooks

Signed Standard Webhooks deliveries of job events to your HTTPS endpoints.

GET/v1/webhook-endpoints

listWebhookEndpoints

List webhook endpoints

The account's webhook endpoints, newest first, without their secrets. Free.

  • Auth: Authorization: Bearer with an API key or a map.audio access token.
  • Not an MCP tool: Webhook endpoints hold signing secrets for your own server; set them up with an API key (POST /v1/webhook-endpoints) or with the account holder's map.audio sign-in.
curl
curl -sS "https://api.map.audio/v1/webhook-endpoints" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01"
200: One endpoint
{
  "object": "list",
  "data": [
    {
      "object": "webhook_endpoint",
      "id": "whep_01M6BPRWZCT8J4PSWZ8KG7EXWV",
      "url": "https://hooks.example.com/map-audio",
      "events": [
        "job.succeeded",
        "job.failed"
      ],
      "description": "Render notifications",
      "status": "enabled",
      "createdAt": "2026-11-01T13:58:02.418Z"
    }
  ]
}
400: Invalid request
{
  "error": {
    "type": "invalid_request",
    "code": "invalid_request",
    "message": "\"limit\" is not a parameter of GET /v1/webhook-endpoints; it takes none.",
    "param": "limit",
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#invalid_request",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 200 Endpoints., 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: invalid_request.

View as Markdown

POST/v1/webhook-endpoints

createWebhookEndpoint

Create a webhook endpoint

Subscribe a public HTTPS URL to job events: job.succeeded, job.failed and job.cancelled unless you list others, or * for every event. Each delivery is a signed Standard Webhooks POST (webhook-id, webhook-timestamp and webhook-signature headers: HMAC-SHA256 under the whsec_ secret, which is in this response only), retried with backoff for about 63 hours. An endpoint is disabled after three deliveries in a row run out of retries. Needs an API key or a map.audio sign-in on MAP Audio's own pages; an account has at most 10 endpoints. Free.

  • Auth: Authorization: Bearer with an API key or a map.audio access token.
  • Not an MCP tool: Webhook endpoints hold signing secrets for your own server; set them up with an API key (POST /v1/webhook-endpoints) or with the account holder's map.audio sign-in.
createWebhookEndpoint body
FieldTypeRequiredDescription
urlstringyesA public HTTPS URL with a host name; deliveries are POSTs to it. Matches ^https://.
eventsarray of "job.preview" | "job.succeeded" | "job.failed" | "job.cancelled" | "job.expired" | "webhook.test" or "*"noEvent types to receive; * receives every event.
descriptionstringnoAt most 200 characters.
curl
curl -sS "https://api.map.audio/v1/webhook-endpoints" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://hooks.example.com/map-audio","events":["job.succeeded","job.failed"],"description":"Render notifications"}'
Request: Hear when renders end
{
  "url": "https://hooks.example.com/map-audio",
  "events": [
    "job.succeeded",
    "job.failed"
  ],
  "description": "Render notifications"
}
201: Created
{
  "object": "webhook_endpoint",
  "id": "whep_01M6BPRWZCT8J4PSWZ8KG7EXWV",
  "url": "https://hooks.example.com/map-audio",
  "events": [
    "job.succeeded",
    "job.failed"
  ],
  "description": "Render notifications",
  "status": "enabled",
  "createdAt": "2026-11-01T13:58:02.418Z",
  "secret": "whsec_Zm9ydHkgdHdvIGJ5dGVzIG9mIGV4YW1wbGUgc2VjcmV0IGtleSE="
}
400: Invalid request
{
  "error": {
    "type": "invalid_request",
    "code": "invalid_request",
    "message": "url must use https; got http.",
    "param": "url",
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#invalid_request",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}
403: Webhook endpoint limit reached
{
  "error": {
    "type": "entitlement",
    "code": "too_many_endpoints",
    "message": "An account may have 10 webhook endpoints; delete one with DELETE /v1/webhook-endpoints/{id} first (GET /v1/webhook-endpoints lists them).",
    "param": null,
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#too_many_endpoints",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 201 The endpoint, with its secret., 400 Invalid request, 403 Webhook endpoint limit reached, default Any other error: `error.code` names it, `error.param` the field at fault, and `error.docUrl` its entry in the error catalogue..

Errors: oauth_required, too_many_endpoints, invalid_request, unsupported_media_type, payload_too_large, idempotency_key_unsupported.

View as Markdown

DELETE/v1/webhook-endpoints/{id}

deleteWebhookEndpoint

Delete a webhook endpoint

Delete an endpoint; deliveries to it stop. Free.

  • Auth: Authorization: Bearer with an API key or a map.audio access token.
  • Not an MCP tool: Webhook endpoints hold signing secrets for your own server; set them up with an API key (POST /v1/webhook-endpoints) or with the account holder's map.audio sign-in.
deleteWebhookEndpoint parameters
NameInTypeRequiredDescription
idpathstringyesA webhook endpoint id (whep_…), from GET /v1/webhook-endpoints. Matches ^whep_[0-9A-HJKMNP-TV-Z]{26}$.
curl
curl -sS -X DELETE "https://api.map.audio/v1/webhook-endpoints/whep_01M6BPRWZCT8J4PSWZ8KG7EXWV" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01"
200: Deleted
{
  "object": "webhook_endpoint",
  "id": "whep_01M6BPRWZCT8J4PSWZ8KG7EXWV",
  "url": "https://hooks.example.com/map-audio",
  "events": [
    "job.succeeded",
    "job.failed"
  ],
  "description": "Render notifications",
  "status": "enabled",
  "createdAt": "2026-11-01T13:58:02.418Z",
  "deleted": true
}
404: Not found
{
  "error": {
    "type": "not_found",
    "code": "not_found",
    "message": "No webhook endpoint with that id; GET /v1/webhook-endpoints lists this account's endpoints.",
    "param": "id",
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#not_found",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 200 The endpoint, deleted., 404 Not found, default Any other error: `error.code` names it, `error.param` the field at fault, and `error.docUrl` its entry in the error catalogue..

Errors: not_found, invalid_request.

View as Markdown

POST/v1/webhook-endpoints/{id}/rotate-secret

rotateWebhookSecret

Rotate a webhook secret

Issue a new whsec_ secret, in this response only. For 24 hours each delivery carries signatures under both the old and the new secret, so your server can switch without dropping one; rotating a disabled endpoint also enables it again. Free.

  • Auth: Authorization: Bearer with an API key or a map.audio access token.
  • Not an MCP tool: Webhook endpoints hold signing secrets for your own server; set them up with an API key (POST /v1/webhook-endpoints) or with the account holder's map.audio sign-in.
rotateWebhookSecret parameters
NameInTypeRequiredDescription
idpathstringyesA webhook endpoint id (whep_…), from GET /v1/webhook-endpoints. Matches ^whep_[0-9A-HJKMNP-TV-Z]{26}$.
curl
curl -sS -X POST "https://api.map.audio/v1/webhook-endpoints/whep_01M6BPRWZCT8J4PSWZ8KG7EXWV/rotate-secret" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01"
200: Rotated
{
  "object": "webhook_endpoint",
  "id": "whep_01M6BPRWZCT8J4PSWZ8KG7EXWV",
  "url": "https://hooks.example.com/map-audio",
  "events": [
    "job.succeeded",
    "job.failed"
  ],
  "description": "Render notifications",
  "status": "enabled",
  "createdAt": "2026-11-01T13:58:02.418Z",
  "secret": "whsec_bmV3IHNlY3JldCBmb3IgdGhlIG5leHQgMjQgaG91cnMgb2Ygc2lnbmluZw=="
}
409: Secret rotation in progress
{
  "error": {
    "type": "conflict",
    "code": "rotation_in_progress",
    "message": "The previous secret stays valid until 2026-11-02T14:20:00.000Z; rotate again after that, or delete the endpoint and create a new one.",
    "param": null,
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#rotation_in_progress",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 200 The endpoint, with its new secret., 409 Secret rotation in progress, default Any other error: `error.code` names it, `error.param` the field at fault, and `error.docUrl` its entry in the error catalogue..

Errors: not_found, oauth_required, rotation_in_progress, idempotency_key_unsupported, invalid_request.

View as Markdown

POST/v1/webhook-endpoints/{id}/test

testWebhookEndpoint

Send a test event

Queue a signed webhook.test event to the endpoint, to check that your server receives deliveries and verifies their signatures. Free.

  • Auth: Authorization: Bearer with an API key or a map.audio access token.
  • Not an MCP tool: Webhook endpoints hold signing secrets for your own server; set them up with an API key (POST /v1/webhook-endpoints) or with the account holder's map.audio sign-in.
testWebhookEndpoint parameters
NameInTypeRequiredDescription
idpathstringyesA webhook endpoint id (whep_…), from GET /v1/webhook-endpoints. Matches ^whep_[0-9A-HJKMNP-TV-Z]{26}$.
curl
curl -sS -X POST "https://api.map.audio/v1/webhook-endpoints/whep_01M6BPRWZCT8J4PSWZ8KG7EXWV/test" \
  -H "Authorization: Bearer $MAP_API_KEY" \
  -H "Map-Version: 2026-11-01"
202: Queued
{
  "id": "evt_01M6BPRYMG75T6HXQ8E61EARAX",
  "type": "webhook.test",
  "createdAt": "2026-11-01T14:15:09.664Z",
  "apiVersion": "2026-11-01",
  "data": {
    "object": {
      "endpoint": "whep_01M6BPRWZCT8J4PSWZ8KG7EXWV"
    }
  }
}
409: Webhook endpoint disabled
{
  "error": {
    "type": "conflict",
    "code": "endpoint_disabled",
    "message": "This endpoint is disabled, after repeated failed deliveries or because the key that set its secret was revoked; rotate its secret (POST /v1/webhook-endpoints/{id}/rotate-secret) to enable it again.",
    "param": null,
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#endpoint_disabled",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 202 The queued event., 409 Webhook endpoint disabled, default Any other error: `error.code` names it, `error.param` the field at fault, and `error.docUrl` its entry in the error catalogue..

Errors: not_found, endpoint_disabled, idempotency_key_unsupported, invalid_request.

View as Markdown

Provenance

Signed records of what made each render, and the public keys that verify them.

GET/v1/provenance/{id}

getProvenance

Get a provenance record

A render's signed provenance record: the engine image, seed, presets, inputs and outputs with their SHA-256, the licence the render was made under, and that no AI model made the audio. Public, so anyone holding a record id can check it: verify signature (Ed25519 over the record's JSON with sorted keys and without signature) with the key in GET /.well-known/jwks.json whose kid matches. Free.

  • Auth: none; this route is public.
  • Not an MCP tool: Public and unauthenticated: read it with a plain GET. get_job already returns each render's provenance record.
getProvenance parameters
NameInTypeRequiredDescription
idpathstringyesA provenance record id (prov_…), from a job's result.provenance.id. Matches ^prov_[0-9A-HJKMNP-TV-Z]{26}$.
curl
curl -sS "https://api.map.audio/v1/provenance/prov_01M6BPRVA8ZC7F7J737SQ0EPN2" \
  -H "Map-Version: 2026-11-01"
200: A render of 313 Disco
{
  "object": "provenance",
  "id": "prov_01M6BPRVA8ZC7F7J737SQ0EPN2",
  "jobId": "job_01M6BPRE186QHP9QPYGDX5NNFP",
  "createdAt": "2026-11-01T14:03:41.877Z",
  "engine": {
    "product": "pam",
    "version": null,
    "runtime": "native-linux-x86_64",
    "image": "registry.cloudflare.com/c7c2e61448617e81ced650f444fb6787/pam-render@sha256:5c5ffe3fabc103e277280fbd65a08988d31361f00fe7857e36f603d67bcec42d"
  },
  "seed": 42,
  "presets": [
    {
      "ref": "pam:factory/313-disco",
      "sha256": "3afbf5dea1003b2d17385955017785a57d74c65f77f97b58cf5d7cec9794ca1c"
    }
  ],
  "packs": [],
  "userFiles": [],
  "inputs": [],
  "outputs": [
    {
      "file": "file_01M6BPRK0M34NBP2XKJ1RMX1TQ",
      "sha256": "5a3485b7a3221be5f7ead6ab953cbc198988a7246158215b32bb937acbd3852b"
    }
  ],
  "planner": null,
  "contracts": {
    "api": "2026-11-01",
    "pam.cli": 1
  },
  "aiModels": [],
  "audioByModel": false,
  "license": {
    "id": "lic_api_prototype_test",
    "commercialUse": false,
    "attribution": true
  },
  "kid": "6c2f0a9d4b7e1358",
  "signature": "ed25519:jsfkW3eF1r4kChqccp6AKLTvjTK5Re8acrEusqigz7MDUu6uZhsJXVnuQEl6EsErDgVYNXOkos9d0mMyt2CVCg"
}
404: Not found
{
  "error": {
    "type": "not_found",
    "code": "not_found",
    "message": "No provenance record with that id; a job's result.provenance.id names its record.",
    "param": "id",
    "retryable": false,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#not_found",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 200 The record., 404 Not found, default Any other error: `error.code` names it, `error.param` the field at fault, and `error.docUrl` its entry in the error catalogue..

Errors: not_found, rate_limited, invalid_request.

View as Markdown

GET/.well-known/jwks.json

getJwks

Get the provenance signing keys

The public keys (Ed25519, as JWKs) that sign provenance records; pick the one whose kid matches a record's. Public. Free.

  • Auth: none; this route is public.
  • Not an MCP tool: Public keys for checking provenance; fetch them with a plain GET.
curl
curl -sS "https://api.map.audio/.well-known/jwks.json" \
  -H "Map-Version: 2026-11-01"
200: One signing key
{
  "keys": [
    {
      "kty": "OKP",
      "crv": "Ed25519",
      "x": "r7VbRk8sQ1mN4pT6yW2cE9hJ3uL5aF0dG7iK1oZ2qXs",
      "kid": "6c2f0a9d4b7e1358",
      "use": "sig",
      "alg": "EdDSA"
    }
  ]
}
500: Internal error
{
  "error": {
    "type": "unavailable",
    "code": "internal_error",
    "message": "Something went wrong on our side; nothing was charged.",
    "param": null,
    "retryable": true,
    "jobId": null,
    "docUrl": "https://map.audio/developers/music-api/errors#internal_error",
    "requestId": "9a3f7c2e5b1d8f40-LHR"
  }
}

Responses: 200 JWKS., 500 Internal error, default Any other error: `error.code` names it, `error.param` the field at fault, and `error.docUrl` its entry in the error catalogue..

View as Markdown