API errors

Every error from the Pluto Ads API is application/problem+json (RFC 9457). Its type is a link to one section of this page, named after the stable code. The title is written for the person or agent reading it and never contains provider or database internals.

JSON
{"type":"https://docs.plutoads.ai/api/errors#invalid","title":"The request has 1 problem.","status":422,"code":"invalid","errors":[{"field":"name","message":"Use a name of 1 to 120 characters."}]}

Retry a write with the same Idempotency-Key whenever you retry it at all. The stored result comes back and nothing runs twice. See Idempotency keys.


bad_request

Status 400. The request can't be read: malformed JSON, a wrong type (a JSON number where an amount belongs), a missing or malformed header such as Pluto-Workspace, or an invalid path or query value. The title names the problem. Fix the request; sending it again unchanged fails the same way.


unauthenticated

Status 401. There is no credential, or it is invalid, expired or revoked. Keys and agent clients stop working on the first request after they are revoked. Get a new credential: create a key on the API page of the app, or exchange your agent client's credentials for a new token. See Authentication.


forbidden

Status 403. The credential is valid but can't do this. Either it lacks the permission (review, write, publish, admin or organization), or it names a workspace it doesn't belong to. The title says which. Ask a workspace admin for the permission, or use a credential of that workspace.


not_found

Status 404. The item isn't in this workspace. It may have been deleted, or the ID belongs to another workspace: the API never reveals whether an ID exists elsewhere. Check the ID and the workspace the credential belongs to.


conflict

Status 409. The request is well formed but can't apply to the current state. The problem body carries what you need to resolve it:

CauseExtra fieldWhat to do
A stale expectedVersion (someone changed the same field), on launches, ad sets, ads, media, folders and settingscurrentMerge with current, retry with expectedVersion set to current.version
An Idempotency-Key or commandId reused for a different requestreason: command_id_reusedUse a new key for new work
A launch that isn't ready to publish, or an approval that no longer matches ititemsFix the checklist, then approve again
Pending changes that changed since you reviewed themrevisionsVersionRead GET /launches/{id}/revisions again and resend with that version
Pending changes Meta can't takeproblems or blockedFix the listed fields, or discard the changes Meta can't apply
A live change to a value that stays managed in Meta (imported launches)managedInMetaChange it in Meta Ads Manager
A review status still in useusageCountMove its ads to another status first
A targeting, audience or ad preview request without a Meta connectionreason: meta_disconnectedAn admin connects Meta in Integrations
A targeting, audience or ad preview request after Meta access expired or was revokedreason: meta_reauthorizeAn admin reconnects Meta in Integrations
A targeting change that makes an ad set reach the EU without the advertiser names Meta requiresreason: eu_advertiser_required, missing, fixSet the beneficiary and payer names (fix links to where), then try again
An ad preview Meta can't render yetreason: not_previewable, missingAdd what missing lists (or read metaMessage when Meta refused it)
Deleting media a launch that isn't published yet still usesreason: used_in_unpublished_launch, launchesRemove it from those launches first, or archive the media instead
A comment action the Meta connection lacks permissions forreason: meta_permissions, missingPermissionsAn admin reconnects Meta and grants the listed permissions
A profit read without a connected Pluto Profit storereason: pluto_profit_not_connectedAn admin connects Pluto Profit in Integrations
A profit read after Pluto Profit stopped accepting the workspace's approval (removed or expired, or the person who approved lost the store) or key (revoked)reason: pluto_profit_reauthorizeAn admin reconnects Pluto Profit in Integrations (or reconnect_pluto_profit); statusReason on the connection says why
A Slack action without a connected Slack workspacereason: slack_not_connectedAn admin connects Slack in Integrations
A Slack action after Pluto Ads was removed from the Slack workspace, or its access was revokedreason: slack_reauthorizeAn admin reconnects Slack in Integrations
A Slack message to a channel the workspace hasn't connectedreason: slack_channel_not_connectedAn admin connects the channel in Integrations, or post to a connected one
A Slack message to a connected channel Slack no longer lets Pluto Ads post in (archived, deleted, or the app was removed from it)reason: slack_channel_unavailableRestore the channel or invite Pluto Ads again in Slack, or connect another channel
A retry of a Slack message whose first attempt may already have been posted (Slack didn't answer in time)reason: slack_message_outcome_unknownCheck the channel in Slack; send again with a new idempotency key only if the message isn't there
A change to an archived ad or ad set, a draft-only action on something live, or a job with nothing to retryNoneRead title; restore the item or use the live controls
A plan change or checkout the organization doesn't fit: more workspaces than the plan holds (Pro holds 5, so Business to Pro needs 5 or fewer)reason: too_many_workspaces, limit, used, nextAction: archive_workspaces, upgradeTo (the plan that fits)Archive workspaces or move them to another organization (nothing is deleted), then try again; or choose the plan in upgradeTo
A plan change on an Enterprise planreason: contact_sales, salesUrl, contactUrlTalk to sales: book a call at salesUrl
Cancelling an Enterprise agreement before its end date (POST /organizations/{id}/billing/portal with flow: cancel)reason: agreement_term, runsUntil (the end date), nextAction: contact_sales, salesUrl, contactUrlThe agreement runs until runsUntil; talk to your account manager about the renewal
Changing the plan of an organization that doesn't subscribe yetreason: not_subscribedStart a checkout with POST /organizations/{id}/billing/checkout instead
Moving to a larger plan and to monthly billing in one requestreason: one_change_at_a_timeUpgrade first, then switch to monthly billing
Starting the free trial for an organization that already had onereason: trial_unavailableChoose a plan
Choosing a plan while the organization is scheduled for deletionreason: organization_deletingRestore the organization first
Turning on extra storage without a subscriptionreason: subscription_requiredChoose a plan first
A checkout for an organization that already subscribesreason: subscribedChange the plan with POST /organizations/{id}/billing/plan instead
A checkout while another checkout for the organization is still being preparedreason: checkout_in_progressWait a moment, then try again; a retry with the same idempotency key continues the same checkout
A checkout that ended before it opened (it expired, or another checkout replaced it)reason: checkout_endedStart a new checkout with a new idempotency key
Turning on on-demand usage without a paid plan: during the trial, without a plan, or with complimentary access (there's no card)reason: trial, no_subscription or complimentaryChoose a plan first (for complimentary, talk to sales for more); turning it off always works
Archiving or deleting the organization's last active workspace, or a workspace that's already in that stateNoneRead title; to close everything, an owner deletes the organization
Restoring an organization after deleting its data has startedreason: purge_startedNone: it can't be restored any more
Deleting your account while you're the only owner of an organizationreason: sole_owner, organizationsMake someone else an owner of each listed organization, then try again
Transferring ownership to someone who isn't an admin of the organizationNoneMake them an admin first

See Versions and conflicts.


invalid

Status 422. One or more fields break a rule. errors lists every problem at once, each with a field path (such as adSets/0/name) and a message. Fix every listed field before you send it again.


rate_limited

Status 429. The credential or its workspace is over its request budget. The Retry-After header says how many seconds to wait. Wait that long, then retry with the same idempotency key. See Rate limits. Slack messages get it too when a channel's next posting slot is more than a few seconds away, or when Slack itself asks us to slow down.


payment_required

Status 402. The organization has no access right now, so it's read-only and nothing was changed. accessReason says why: no_subscription, trial_ended (the free trial ended without a subscription), canceled, unpaid, past_due after its grace period, incomplete, paused, stale (a renewal couldn't be confirmed) or complimentary_ended (complimentary access ended and the days to choose a plan passed). feature names what was refused, for example writes or publishing. upgradeUrl is the organization's Plan & billing page: an owner or admin subscribes there (or with start_checkout), or updates the payment method when a payment failed.

A read-only organization can still do the same things in the app, with API keys and through MCP:

  • Read everything, including exports (a workspace's ads as CSV, its media as a ZIP, your account's data).
  • Pause campaigns, ad sets and ads, and lower budgets. Resuming and raising are refused.
  • Turn a loop off, archive it, or delete a draft that never ran (DELETE /loops/{id}).
  • Approve a change set that only pauses or lowers budgets, reject any change set, and undo a change (POST /change-sets/{id}/items/{key}/undo, POST /loop-runs/{id}/undo) when the undo pauses or lowers a budget.
  • Cancel a publish, a queued job or a loop run; revoke API keys, agent clients, agent connections and invitations; delete webhooks; disconnect Meta, Slack and Pluto Profit.
  • Archive or delete workspaces, delete or restore the organization, remove members and leave.
  • Use the account routes and billing (the billing routes and tools), so you can always read the state and hand the link to a person.

Everything else answers payment_required. Manual refreshes such as sync_leads or a comment sync are refused too; background syncs from Meta keep running. Queued work that isn't on this list stops when it runs: the job item fails with "This organization is read-only until it has a plan.", and isn't run again once the organization pays. Loops don't run, and webhook deliveries are recorded as not sent. Offline changes uploaded through the sync queue are refused one by one (rejected, with this message as reason), except your own preferences and inbox. See Billing.

JSON
{"type":"https://docs.plutoads.ai/api/errors#payment_required","title":"The free trial ended, so this organization is read-only. An organization owner or admin can choose a plan in Organization settings, Plan & billing.","status":402,"code":"payment_required","feature":"writes","accessReason":"trial_ended","upgradeUrl":"https://app.plutoads.ai/settings/organization/billing"}

plan_limit

Status 402. The organization's plan doesn't include this, so it didn't start and nothing was changed. feature says what, plan is the organization's plan (pro, business, enterprise, or null during the trial), and nextAction is the one next step: upgrade (to the plan in upgradeTo, from upgradeUrl), contact_sales (book a call with sales at salesUrl; contactUrl is the contact page), keep_plan, or for media storage enable_extra_storage or raise_storage_limit. upgradeTo is never smaller than what the organization needs: Pro when its workspaces fit Pro (up to 5) and Pro costs no more than Business for its members, otherwise Business. Owners and admins change the plan in Plan & billing, or with POST /organizations/{id}/billing/plan.

featureMeaningNext step
workspacesCreating or restoring a workspace past what the plan holds (limit, used). reason is trial (the free trial holds 1), plan_cap (Pro holds 5, and complimentary access may cover a set number; Business and Enterprise have no cap, and on Enterprise workspaces beyond the agreement are added to the next invoice) or scheduled_plan_cap (a move to a smaller plan is scheduled for the end of the period, and limit is what that plan holds)For trial, upgrade to Pro. For plan_cap, upgrade to Business, or contact_sales with complimentary access. For scheduled_plan_cap, keep_plan: cancel the scheduled change with DELETE /organizations/{id}/billing/plan, then add the workspace
membersInviting, adding or reactivating a member past what complimentary access covers (limit, used; pending member invitations count, guests never do). An invitation accepted once it's full stays pending until there's roomcontact_sales: talk to sales at salesUrl
workspace_limitsSetting a monthly limit per workspace comes with Business. Removing one (limit: null) works on every planupgrade to Business
usage_breakdownUsage by workspace and by connected agent come with Business: by=workspace and by=agent, the workspaceId and agentId filters, GET /workspace/usage (get_workspace_usage) and the CSV export. Usage by member, source, loop and model works on every planupgrade to Business
media_storageThe organization's media storage is full (limit, used in GB, decimal strings). reason is extra_storage_off (nextAction enable_extra_storage), storage_limit (extra storage reached its monthly limit; nextAction raise_storage_limit) or extra_storage_unavailable (during the trial: nextAction upgrade), with raisedBy: organization_adminAn owner or admin turns on or raises extra storage in Spending, or with PUT /organizations/{id}/billing/storage; uploads continue then

Pluto Ads never deletes anything to make room. Retrying unchanged fails the same way.

JSON
{"type":"https://docs.plutoads.ai/api/errors#plan_limit","title":"Pro holds up to 5 workspaces. Upgrade to Business to add more.","status":402,"code":"plan_limit","feature":"workspaces","reason":"plan_cap","limit":5,"used":5,"plan":"pro","nextAction":"upgrade","upgradeTo":"business","upgradeUrl":"https://app.plutoads.ai/settings/organization/billing","salesUrl":"https://cal.com/plutocamp/pluto-ads-sales","contactUrl":"https://plutoads.ai/contact"}

spend_limit

Status 402. The Agent (or an AI step in a loop) reached a usage limit, so it didn't start this work and nothing was changed. The first limit reached stops it; reason names it:

reasonMeaningWhat to do
trial_capThe free trial's AI usage is usedAn owner or admin chooses a plan
included_usedThe organization's included usage is used up and usage beyond it is offAn owner or admin turns on usage beyond what's included, or wait for resetsAt
spend_limitUsage beyond what's included reached the organization's monthly limitAn owner or admin raises the limit, or wait for resetsAt
workspace_limitThis workspace reached the monthly limit set for it (targetId, targetName)An owner or admin raises or removes the workspace's limit, or wait for resetsAt
member_limitThis person reached the monthly limit set for them (targetId, targetName)An owner or admin raises or removes their limit, or wait for resetsAt
complimentary_usedThe organization has complimentary access, and this month's included AI usage is used. There's no usage beyond it (raisedBy: support, salesUrl, contactUrl)Wait for resetsAt, the 1st of next month (UTC), or talk to sales at salesUrl for more

limit and used are decimal strings in currency (usd), resetsAt is when usage starts again from zero (the end of the billing period), raisedBy is who can change it (organization_admin), and usageUrl is the organization's Spending page, where owners and admins change limits (or set_usage_limit, PUT /organizations/{id}/usage/limits/..., PUT /organizations/{id}/billing/on-demand); upgradeUrl is Plan & billing. Retrying before a limit changes fails the same way. Everything that doesn't use AI keeps working. See Billing.

JSON
{"type":"https://docs.plutoads.ai/api/errors#spend_limit","title":"This organization used the AI usage its members include for this billing period. An organization owner or admin can turn on on-demand usage in Organization settings, Spending; included usage resets on October 26.","status":402,"code":"spend_limit","reason":"included_used","limit":"100.00","used":"100.00","currency":"usd","resetsAt":"2026-10-26T00:00:00Z","onDemandEnabled":false,"raisedBy":"organization_admin","upgradeUrl":"https://app.plutoads.ai/settings/organization/billing","usageUrl":"https://app.plutoads.ai/settings/organization/spending"}

workspace_archived

Status 409. The workspace is archived, so it can be read but not changed. Every write refuses the same way, whatever the credential. workspaceId and organizationId name it. An organization owner or admin restores it with POST /organizations/{id}/workspaces/{workspaceId}/restore (or restore_workspace), or in the app under Organization settings, Workspaces. See Archiving and deleting.

JSON
{"type":"https://docs.plutoads.ai/api/errors#workspace_archived","title":"This workspace is archived, so it can be viewed but not changed. An organization owner or admin can restore it.","status":409,"code":"workspace_archived","workspaceId":"0192c9a4-7c1e-7b6e-9a51-3f1d2c4b5a60","organizationId":"0192c9a4-7c1e-7b6e-9a51-3f1d2c4b5a61"}

workspace_deleted

Status 410. The workspace is scheduled for deletion. Nobody can open it and its credentials were revoked. purgeAfter is when its data and media are deleted for good; until then an organization owner or admin can restore it. After that date the workspace is gone and its ID answers 404.

JSON
{"type":"https://docs.plutoads.ai/api/errors#workspace_deleted","title":"This workspace is scheduled for deletion on October 26, 2026. An organization owner or admin can restore it until then.","status":410,"code":"workspace_deleted","workspaceId":"0192c9a4-7c1e-7b6e-9a51-3f1d2c4b5a60","organizationId":"0192c9a4-7c1e-7b6e-9a51-3f1d2c4b5a61","purgeAfter":"2026-10-26T09:41:12Z"}

organization_deleted

Status 410. The workspace's organization is scheduled for deletion, with every workspace in it. purgeAfter is the date. Until then an organization owner, signed in to the app, can restore it.


member_suspended

Status 403. An organization owner or admin suspended your access to organizationName (organizationId). Your work stays; ask them to reactivate you. API keys and agents you had there were revoked and don't come back on reactivation.


member_removed

Status 403. You were removed from organizationName (organizationId). Your work there stays. You can still use your other organizations, and an owner or admin can invite you again.


unavailable

Status 503. A service the API depends on is down or not configured. Nothing was changed. Retry later with the same idempotency key.


internal

Status 500. Something failed on our side. We log it with the request's x-request-id. Retry with the same idempotency key, and include the x-request-id response header when you report it.