API reference

Error reference

Every error code, reason, and warning each API returns, with what to do about it.

Dynamic Audience API

Errors use a top-level { "code", "message" } body. Each status means the whole request failed and nothing was mailed or charged. See Errors for an example of each.

StatuscodemessageWhat to do
401invalid_api_keyWe could not verify that API key. Check the key and try again.Send a Full access key. Integration keys and Formulas only keys get this same response.
404campaign_not_foundWe could not find a campaign with that campaign ID.Copy the campaign ID again from the campaign's API / Webhook setup. IDs are case-sensitive, and a request with no campaign_id gets this response too.
409campaign_not_activeThat campaign is not active, so we did not mail anyone.Open the campaign in Postaged and check that it is active, gets its audience from API / Webhook, and has a design on every step, then send the request again. If it keeps happening, contact support.
409design_cannot_renderA design holds a setting we can't print: This campaign can't be placed yet. "{name}" on the {surface} of "{template name}" uses a setting we can't print. Change or delete it in the designer, then try again.
A design is still an AI draft: Open and save this AI draft in the designer before using it in a campaign.
Open the named design in the designer, change or delete the item the message names, then send the request again. When the message says to open and save an AI draft, open that template in the designer and save it, then send the request again. Nothing was mailed or charged.
413payload_too_largeThat request was too large. Send up to 5,000 recipients per request.Split the recipients across requests: up to 5,000 each (250 for Neighborhood Mail), each under 4.25 MB.
422invalid_payloadWe could not read that request. Check the format and try again.Send a valid JSON body with a recipients array that isn't empty.
429rate_limitedToo many requests. Wait a moment and try again.Wait the number of seconds in Retry-After, then send the request again.
500internal_errorSomething went wrong on our end. Nothing was mailed. Try again shortly.Send the same request again in a few minutes.
503validation_unavailableWe could not check addresses just now, so nothing was mailed. Try again in a few minutes. If it keeps happening, contact support.Send the same request again in a few minutes. Contact support if it keeps happening.

Reasons a recipient was not mailed

A recipient's reason when its status is not_mailed. The request itself succeeded with 200.

reasonTypical detailWhat to do
invalid_addressWe could not verify this address.Check this recipient's address fields, then send it again in a later request.
do_not_mailThis address is on a do-not-mail list for this campaign.Nothing to do: this address is on a do-not-mail list for this campaign.
filtered_locationOutside the area you drew on the map.Nothing to do: the address is outside the area drawn on the campaign's map.
filtered_conditionsAdded to the campaign. Waiting on your filter conditions.Nothing to do: the recipient waits in the campaign and is mailed if it meets your filter conditions later.
budget_exceededThis campaign's budget was already spent.Raise the campaign's budget in Postaged, then send this recipient again.
duplicate_recentWe already mailed this address for this campaign recently.Nothing to do: this address was already mailed for this campaign within its re-send window.
payment_failedYour card was declined, so nothing was mailed.Update the team's payment method in Postaged, then send the request again.
no_homes_foundNo homes inside the radius around this address.Nothing to do: no homes were found inside the radius around this address.
request_capacity_reachedWe reached this request's limit. Send this address again in another request.Send this recipient again in another request.
text_overflowThe custom text does not fit its text box on your design.Shorten this recipient's custom text, or make its text box larger in the designer, then send it again.
variable_image_missingVariable image "{title}" is not usable, and this request set require_variable_images.Send a usable image link for the field the detail names, or leave require_variable_images off to mail with the default image.
unsupported_characters{font name} can't print {characters} in the "{box name}" text box.Send this recipient's values without the characters the detail names, or change the text box's font in the designer, then send it again.
removed_by_senderRemoved from this campaign by the sender.Nothing to do: you removed this recipient from the campaign.

detail can vary with the case, for example naming the text box or the image. Branch on reason, never on detail.

filtered_conditions isn't final. We add the recipient to the campaign and check them against your filter conditions every day. When they match, we mail them and charge your team then, within the campaign's budget, and the mailing shows in the campaign's Recipients received list. Sending the same address again updates their information.

Warning codes

A mailed recipient carries warnings when a fallback fired. The card still mails.

codeWhat to do
variable_image_fallbackThe card was mailed with the design's default image. Send a usable image link for the field next time, or set require_variable_images to skip recipients instead.
variable_image_blankThe card was mailed with the image area blank, because the design has no default image. Send a usable image link, add a default image, or set require_variable_images.
qr_fallback_linkThe QR code sends this recipient to the fallback link because the fields it needs were empty. Send those fields to give each recipient their own link.
text_overlapThe card was mailed with this recipient's text overlapping another element. Shorten the value or make room for it in the designer.
text_unmeasurableThe card was mailed in full, but we couldn't check the text box the detail names for fit or overlaps. Check it in a proof in Postaged.
text_curve_too_longThe card was mailed in full with this recipient's text too long for its curve or path, even at its smallest size. Shorten the value, or reduce the curve or lengthen the path in the designer.

return_address_reason values

valueWhat to do
missing_token_valueSend every field the return address uses, so it can be filled in for this recipient.
unverified_addressCheck the return-address fields you send: the address they make could not be verified.
verification_limit_reachedReturn addresses were not checked because this month's verification limit was reached. The card used the fallback return address; nothing is needed from you.

Integrations push API

Errors use the body { "error": { "code", "message", "details" } }; details appears only on some codes. A {name} in a message is filled with the value for your request. See Errors for an example of each.

StatuscodemessageWhat to do
401invalid_keyThat API key is not valid for this integration.Send this integration's key (it starts with pk_int_) in the Authorization: Bearer header. A revoked key, another kind of key, or a key for a removed integration gets this error.
403integration_unavailableThis integration is not accepting data. Contact support if you think that is wrong.The integration is paused or disconnected in Postaged. Ask the owner to resume it, then send the request again.
429rate_limitedToo many requests. Slow down and retry.Wait the number of seconds in the Retry-After header, then send the request again.
400invalid_jsonThe request body must be JSON.Send the body as JSON with a Content-Type of application/json.
400invalid_requestPush records: Send { records: [...] }.
Declare the schema: Send { fields: [...] } describing your columns.
Declare the schema, a field with no key: Every field needs a non-empty key.
Send the body in the shape the message names, then send the request again.
413too_many_recordsYou sent {received} records. Send at most {limit} per batch.Split the batch so each one holds at most the records in details.limit.
413payload_too_largeA batch may be at most {limit} bytes.Split the batch so each body stays at or under the bytes in details.limit.
400missing_idempotency_keyPush records: Send an Idempotency-Key header so a retried batch is not applied twice.
Begin a sync: Send an Idempotency-Key header so a retry cannot open a second sync.
Complete a sync: Send an Idempotency-Key header so a retry cannot complete the sync twice.
Send an Idempotency-Key header with a new value for each request, and the same value when you retry that request.
409idempotency_key_reusedPush records: That Idempotency-Key was used for a different batch. Use a new key.
Begin a sync and Complete a sync: That Idempotency-Key was used for a different request. Use a new key.
Use a new Idempotency-Key for this request. Reuse a key only to retry the same request with the same body.
409in_progressPush records: That batch is still being processed.
Begin a sync and Complete a sync: That request is still being processed.
The first attempt is still running. Wait a few seconds, then retry with the same Idempotency-Key to get its response.
409no_open_syncPush records: Begin a sync before pushing records, so a full sync knows what it saw.
Complete a sync: There is no open sync to complete.
Begin a sync with POST /api/integrations/push/v1/sync first. A sync left open expires after 24 hours.
409sync_in_progressA sync is already open for this integration. Complete it before beginning another.Complete the open sync named in details.syncId, or wait for it to expire, then begin a new one.
400too_many_fieldsYou declared {received} fields. The limit is {limit}.Declare at most the fields in details.limit, counting the fields already declared.
409field_lockedThese fields have a type set in Postaged and cannot be changed from here.The owner set these fields' types in Postaged. Declare them with the types they already have, or ask the owner to change them.
404sync_not_foundThere is no sync with that id on this integration.Use a syncId this integration's sync calls returned, or leave it out to read the latest sync.
400invalid_sync_idsyncId must be the id a sync call returned.Fix the query parameter the message names: syncId is a sync id from a sync call, type is rejection or warning, after is the previous page's nextAfter, and limit is a whole number in range.
400invalid_typetype must be "rejection" or "warning".Fix the query parameter the message names: syncId is a sync id from a sync call, type is rejection or warning, after is the previous page's nextAfter, and limit is a whole number in range.
400invalid_cursorafter must be the nextAfter value of the previous page.Fix the query parameter the message names: syncId is a sync id from a sync call, type is rejection or warning, after is the previous page's nextAfter, and limit is a whole number in range.
400invalid_limitlimit must be a whole number from 1 to 1000.Fix the query parameter the message names: syncId is a sync id from a sync call, type is rejection or warning, after is the previous page's nextAfter, and limit is a whole number in range.

Rejection codes

One rejection per record a batch refused. The rest of the batch is still applied.

codeWhat to do
missing_external_idSend an external_id on every record: your system's stable id for the contact.
invalid_external_idShorten the external_id to 128 characters or fewer.
unknown_fieldDeclare the field with POST /api/integrations/push/v1/schema before you push it, or stop sending it.
invalid_typeSend a value that fits the field's declared type. This rejects the record only for a field mapped to a contact column (it has a semantic); any other field drops just the value, as a warning.
invalid_emailSend a complete email address, or leave the field empty.
duplicate_in_batchSend each contact once per batch. Merge the duplicates under one external_id.
record_too_largeSend less data in this record. A record may be at most 64 KB.

Value warnings

Values dropped from records that were still accepted, one warning per field and code, with a count and up to 5 example externalIds (index and externalId name the first). Every dropped value is listed one per record by GET /sync/rejections with type=warning.

codeWhat to do
invalid_typeThe record was accepted without this value. Send values that fit the field's declared type, or declare the field as text.

Integrations MCP server

JSON-RPC errors, every one with HTTP 200. A {name} is filled with the tool or method you called.

CodeHTTP statusmessageWhat to do
-32700200The request body must be JSON-RPC.Send the request body as one JSON-RPC 2.0 message in JSON.
-32600200A JSON-RPC method is required.The message has no method, or the body is over the size limit. Fix the request, then send it again.
-32600200That request is too large.The message has no method, or the body is over the size limit. Fix the request, then send it again.
-32601200Unknown tool: {name}Use a method and a tool name the server lists. Call tools/list for the tool names.
-32601200Unknown method: {method}Use a method and a tool name the server lists. Call tools/list for the tool names.
-32603200That call could not be completed.Something went wrong on our side and nothing was changed. Send the call again shortly; if it keeps failing, contact support.

HTTP errors

Authentication, availability, and rate-limit failures, and a GET, use the push API's error body.

StatuscodemessageWhat to do
401invalid_keyThat API key is not valid for this integration.Send this integration's key (it starts with pk_int_) in the Authorization: Bearer header. A revoked key, another kind of key, or a key for a removed integration gets this error.
403integration_unavailableThis integration is not accepting data. Contact support if you think that is wrong.The integration is paused or disconnected in Postaged. Ask the owner to resume it, then send the request again.
429rate_limitedToo many requests. Slow down and retry.Wait the number of seconds in the Retry-After header, then send the request again.
405use_postThis MCP endpoint speaks JSON-RPC over POST.Send JSON-RPC messages to the Integrations MCP endpoint with POST.

Tool failures

A tool that cannot do what it was asked returns a result, not a JSON-RPC error. Its text carries error and message.

Toolerrormessage
begin_syncsync_in_progressA sync is already open. Complete it before beginning another.
push_recordsno_open_syncCall begin_sync first.
push_recordstoo_many_recordsSend at most {limit} records per batch.
complete_syncno_open_syncThere is no sync to complete.
get_rejectionssync_not_foundThere is no sync with that id on this integration.
get_rejectionsinvalid_sync_idsyncId must be the id a sync call returned.
get_rejectionsinvalid_typetype must be "rejection" or "warning".
get_rejectionsinvalid_cursorafter must be the nextAfter value of the previous page.
get_rejectionsinvalid_limitlimit must be a whole number from 1 to 1000.