What’s new in the Postally API

Released changes for API integrators. API update emails are enabled by default for account holders; manage your preference in Settings.

Design save now refuses moves that would leave a template unprintable

POST /v1/designs/save with a different template_id or side now moves the design away from its current template and is refused with the same 409 errors as POST /v1/designs/delete. 409 design_in_use is returned when active campaigns use the template, and 409 template_published when the template is published. Ordinary saves that keep the same template and side are unaffected. Previously such a save could succeed and leave a published template without a design or front, causing later sends and proofs to fail.

breaking · POST /v1/designs/save, POST /v1/designs/delete

Action: If you re-point a design to another template or change its side, cancel or complete active campaigns first and unpublish the template, and handle 409 design_in_use and template_published.

Released 2026-10-15

Unknown keys in return_address and default_return_address are now rejected

PATCH /v1/account now returns 400 validation_error for unknown keys inside return_address, naming the keys and allowed fields, instead of returning success and silently ignoring them. POST /v1/triggers/create does the same for default_return_address and now includes a message field. The account return address uses unprefixed names such as address_line1. A trigger's default_return_address uses return_-prefixed names such as return_address_line1, and also accepts return_address_line3.

breaking · PATCH /v1/account, POST /v1/triggers/create

Action: Check that return_address uses unprefixed field names and default_return_address uses return_-prefixed names. Handle 400 validation_error for unrecognized keys.

Released 2026-10-15

Clearer error when previewing PDF-uploaded templates

POST /v1/designs/preview-render now returns 501 preview_not_supported, with a message to generate the proof instead, for templates uploaded as a PDF that have no builder design. Previously these templates received 400 no_front_design, which advised saving a design in the builder. The 501 message for PDF templates has also been reworded. The API reference now lists the 400 no_front_design and 501 preview_not_supported responses.

improved · POST /v1/designs/preview-render

Action: Treat 501 preview_not_supported as meaning the template is a PDF upload, and use the campaign proof to review it.

Released 2026-10-15

Zapier/Make send actions now accept size as the postcard size field

On /actions/send-postcard and /actions/send-letter, size is now accepted as an alias of format. Previously a size value such as postcard_6x9 was silently ignored and the default 4x6 was mailed and billed. If a request sends both size and format with different values, it is refused with 400 validation_error.

fixed · POST /v1/integrations/actions/send-postcard, POST /v1/integrations/actions/send-letter

Action: If your automation sent size and received the default 4x6 postcard, re-check your mapped fields. Send only one of size or format, or make sure both have the same value.

Released 2026-10-15

Recipient update validates state and postal_code against the stored country

On POST /v1/recipients/update, a state or postal_code sent without country is now checked against the recipient's stored country using the same rules as /v1/recipients/new. Previously a ZIP-only patch on a US recipient was rejected as an invalid Canadian postal code. A Canadian postal code or an invalid state could also be stored on a US or international recipient. Canadian postal codes are normalised to A1A 1A1, and full US state names are stored as codes.

fixed · POST /v1/recipients/update

Action: Patches that send state or postal_code without country must now match the recipient's stored country. To move a recipient to another country, send country together with the new state and postal_code.

Released 2026-10-15

Zapier/Make send actions now require a verified email

POST /v1/integrations/actions/send-postcard and POST /v1/integrations/actions/send-letter now answer 403 email_not_verified until the account's email is verified, test keys included, like the other send endpoints. Nothing is created or charged in that case.

breaking · POST /v1/integrations/actions/send-postcard, POST /v1/integrations/actions/send-letter

Action: Make sure accounts used with Zapier/Make actions have verified their email, and handle 403 email_not_verified.

Released 2026-10-14

Klaviyo trigger refuses unverified trigger owners

POST /v1/triggers/klaviyo now checks the account that owns the trigger before anything is created or debited. It answers 403 email_not_verified if the owner has not verified their email, and 404 account_not_found if the owner account is missing or deleted. This matches POST /v1/triggers/inbound/:id.

breaking · POST /v1/triggers/klaviyo

Action: Verify the email of any account that owns a Klaviyo trigger, and handle the 403 and 404 responses.

Released 2026-10-14

Signup response now returns the test API key once

The 201 response from POST /v1/auth/signup now includes api_key.key (the plaintext test key, shown once) and api_key.id. The welcome email carries the same key. The verification and welcome emails are now sent after the response is returned, and the welcome email no longer attaches PDFs; it links the API Reference and Dashboard Guide instead.

added · POST /v1/auth/signup

Action: Store the key from the signup response if you need it; it is not shown again.

Released 2026-10-14

Test sends without artwork may become a 400 refusal

The API reference now states that a test send naming neither template_id nor front_pdf_url, which currently returns 201 with a no_artwork warning, may in future be refused with 400 test_artwork_required and nothing created. Current behaviour is unchanged.

deprecated · POST /v1/postcards/create, POST /v1/letters/create

Action: Always pass a published template_id or front_pdf_url (and back_pdf_url) on test sends.

Released 2026-10-14

Idempotency-Key is now scoped to the API key that first used it

Another API key on the same account that sends an Idempotency-Key already used by a different key now gets 422 idempotency_key_reuse instead of the saved response, and the request is not run. The message is the same whether or not the body matches. Retries from the same key replay as before; a dashboard sign-in made with an API key counts as that key.

breaking · POST /v1/postcards/create, POST /v1/recipients/new, POST /v1/api-keys/create

Action: If several API keys share Idempotency-Keys, use a distinct key per request. On a 422 from another key, check with the matching get or list endpoint whether the request took effect before retrying under a new Idempotency-Key.

Released 2026-10-13

Concurrent top-up requests open only one checkout; new 409 topup_in_progress

If several top-up requests arrive together, one opens a Stripe checkout and the others receive 409 topup_in_progress with retry_after_seconds (5). POST /v1/credits/topup/cancel returns the same 409 while a checkout is still being opened. This 409 is never cached under an Idempotency-Key, so a retry with the same key runs again. The Checkout page description now reads "Postally account".

improved · POST /v1/account/topup, POST /v1/credits/topup/cancel

Action: Treat 409 topup_in_progress as retryable: wait retry_after_seconds and retry. A same-amount retry returns the pending checkout.

Released 2026-10-13

Credit history entries now identify the mailpiece and campaign

Each entry in credit history now carries mailpiece ({id, type, format, mail_class, campaign_id} or null) and campaign_id. Mailpiece details are null for API keys (or sessions from them) lacking mailpieces.read, and for references not belonging to your account. Stored descriptions are unchanged.

added · GET /v1/account/credits/history

Action: Use the new fields instead of parsing the description. Grant mailpieces.read to keys that need piece details.

Released 2026-10-13

Test sends without artwork return a no_artwork warning

A test send with neither template_id nor front_pdf_url is still created, but the 201 now carries a no_artwork warning because nothing is rendered: has_pdf stays false and there is no PDF or preview.

added · POST /v1/postcards/create

Action: Pass a published template_id, or front_pdf_url and back_pdf_url, to see the rendered card.

Released 2026-10-13

New endpoint for getting-started progress

GET /v1/account/onboarding returns the account's seven ordered setup steps with done flags, the next step with a hint, capped counts, the api or dashboard path and a quickstart URL. It takes no query parameters (unknown ones return 400), is never cached and contains no recipient data.

added · GET /v1/account/onboarding

Action: Optionally use it to show what remains before your first live send.

Released 2026-10-13

Signup accepts attribution; users/me reports acquisition

POST /v1/auth/signup accepts an optional strict attribution object (utm_* tags, gclid, msclkid, fbclid, referrer_host, landing_path); unknown keys or invalid values are refused with 400. GET /v1/users/me now returns an acquisition object with channel and detail for the account.

added · POST /v1/auth/signup, GET /v1/users/me

Action: If you post signups directly, send attribution only with the documented keys.

Released 2026-10-13

Zapier polling triggers now filter mailpieces by API key environment

The new-mailpiece, status-change and qr-scan polling triggers now return only pieces from your API key's environment: a live key sees live pieces and a test key sees test pieces, as GET /v1/mailpieces/list does. Use ?is_test=true, ?is_test=false or ?is_test=all to override; any other value returns 400 validation_error. New-mailpiece and status-change rows now include is_test. New-recipient and new-order triggers are not split by environment.

improved

Action: If you relied on a test key seeing live pieces (or the reverse), add ?is_test=all to your trigger requests. Handle the new is_test field in rows.

Released 2026-10-13

Price-quote action now quotes the mail class the send action will charge

The price-quote action no longer defaults mail_class to standard. An omitted mail_class is quoted as Lettermail (first_class) below 125 pieces and Personalized Mail (standard) at 125 or more; an explicit standard below 125 pieces is quoted as first_class, matching POST /v1/pricing/quote. The response mail_class names the class quoted, and requested_mail_class appears when it differs from what you sent. Previously quotes could differ from the charge for small sends.

improved

Action: Read mail_class and requested_mail_class in the quote response instead of assuming the class you sent was priced.

Released 2026-10-13

Builder design save keeps template link and joins sibling side to its template

When you update an existing design (id set) and omit template_id, the design now keeps its current template instead of being detached; null is still not accepted. If the kept template was deleted, the design is detached rather than rejected. When you create a side without template_id and the other side with the same name and format is attached to a template, the new side joins that template if that side is free and spec_version and address_layout match; otherwise it is saved standalone. Rename or format edits of an attached design no longer trigger address_layout_mismatch.

fixed · POST /v1/designs/save

Action: No change needed. Be aware that newly created sides may now be attached to an existing template automatically.

Released 2026-10-13

POST /v1/campaigns/approve refuses prepaid campaigns the credit balance cannot cover

Approving a prepaid_credits campaign now compares your balance with what its dispatch will debit (per-piece amounts with tax rounded per piece, plus small-order and AI design-review fees), after setting aside credits that your other in-progress campaigns need. If short, it returns 402 insufficient_credits with details.required_cents, balance_cents, reserved_cents and shortfall_cents. Nothing is written and the proof_token stays valid. If the check cannot run in time, it returns 503 balance_check_unavailable with Retry-After and retry_after_seconds. Neither response is cached under your Idempotency-Key. Test and pay_per_job campaigns are not checked.

breaking · POST /v1/campaigns/approve

Action: Handle 402 insufficient_credits by adding credits and re-sending the same approve request with the same proof_token. Retry 503 balance_check_unavailable after retry_after_seconds; if the retry returns 409, check the campaign status with GET /v1/campaigns/get/:id.

Released 2026-10-09

Prepaid credit warnings on proof generation and re-check for scheduled campaigns

The proof-generation call never blocks on credit, but for a prepaid campaign the balance does not cover, the response now includes a credit_warning object (code, required_cents, balance_cents, reserved_cents, shortfall_cents, message). Scheduled prepaid campaigns are checked again on the send date: if the balance is short, the campaign returns to draft with metadata.scheduled_reset.reason of insufficient_credits and you are emailed; nothing is printed or charged. Scheduled prepaid campaigns are now also charged their campaign-level fees at dispatch, as immediate approvals are.

improved · POST /v1/campaigns/approve

Action: Check for credit_warning in the proof response and top up before approving. For scheduled prepaid campaigns, keep enough balance through the send date; if a campaign returns to draft, add credits and approve again.

Released 2026-10-09

Pricing quote returns prepaid_required_cents

A prepaid_credits pricing quote now includes prepaid_required_cents and prepaid_required_display: the credits approval will require. Because each piece is taxed and rounded individually, it can be a few cents above grand_total_cents. It is null when the quote has neither group_id nor destinations, and for pay_per_job quotes.

added · POST /v1/pricing/quote

Action: Compare your balance with prepaid_required_cents rather than grand_total_cents before approving a prepaid campaign.

Released 2026-10-09

Approve accepts non-canonical proof_token spellings and rejects non-UUID tokens with 409

proof_token on approve is now normalised to its canonical UUID spelling (case, braces and hyphen placement) before use. A string that is not a UUID at all now returns 409 conflict, the same as a wrong token, instead of a server error.

fixed · POST /v1/campaigns/approve

Released 2026-10-09

Template back_pdf_url check is now enforced on create and update

A back_pdf_url that fails the compliance check (unreadable, wrong size, rotated, not exactly one page) is now refused with 422 pdf_compliance_failed or 422 pdf_fetch_failed and no template is saved, instead of being saved with a back_pdf_check_failed warning. On create, a two-page front_pdf_url sent together with a back_pdf_url is refused with 422 pdf_compliance_failed before the back is read, because the front's page 2 would never print. On update, a back is also checked when the request changes spec_version via front_pdf_url, and a refusal tells you to send a back made for the new spec_version. A classic-layout template cannot move to spec_version 1 (400 address_layout_unsupported, answered before any PDF is read).

breaking · POST /v1/templates/create, POST /v1/templates/update

Action: Make sure back_pdf_url is a single unrotated page at the right size for the format and spec_version, and send front_pdf_url and back_pdf_url as separate single-page files. When changing spec_version on update, send a matching back_pdf_url in the same request.

Released 2026-10-09

Temporary PDF host failures return retryable 503 pdf_fetch_unavailable

When the host serving front_pdf_url or back_pdf_url answers 408, 429 or 5xx, refuses or drops the connection, or times out, create returns 503 pdf_fetch_unavailable instead of a cached 422. Update returns it for back_pdf_url. The response includes a Retry-After header and retry_after_seconds, nothing is saved, and it is not cached under your Idempotency-Key. Definitive answers such as 404 or 403 remain 422 pdf_fetch_failed. On update, the stored front on a format change still returns 400 format_change_requires_pdf_revalidation.

improved · POST /v1/templates/create, POST /v1/templates/update

Action: Retry 503 pdf_fetch_unavailable after the Retry-After interval, reusing the same Idempotency-Key.

Released 2026-10-09

API changelog and email preferences

Released API improvements and fixes now have a public web changelog and JSON feed. Recent entries also appear in the API reference PDF. Accounts have a default-on API update email preference that owners can change in Settings or through the account preference endpoint.

added · GET /v1/docs/changelog, GET /v1/docs/download/api-reference, GET /v1/account/api-updates, PATCH /v1/account/api-updates

Action: Use the changelog to track released API changes. Sign in with a password or passkey to change your email preference.

Released 2026-10-09

API key revocation reasons and password-change counts

API key reads expose revoked_reason for revoked keys. Password reset and password change responses include api_keys_revoked so clients can explain how many usable API keys were deactivated.

improved · GET /v1/api-keys/list, GET /v1/account/security, POST /v1/auth/reset-password, POST /v1/auth/change-password

Action: Display the returned revocation reason and count when explaining credential changes to account owners.

Released 2026-10-09

Request IDs for API troubleshooting

API responses include X-Request-Id, and API error responses include request_id. These identifiers help correlate an unsuccessful request with support diagnostics.

improved

Action: Save the returned request ID when reporting an API error.

Released 2026-10-09

Orders check print-ready designs before checkout

Order creation and checkout check that authored postcard sides have print-ready PDFs. A design still being prepared returns 409 design_render_pending with retry_after_seconds: 2; an unavailable or failed design returns 400 design_render_failed. A pending resumed checkout retains its existing payment session.

improved · POST /v1/orders/create, POST /v1/orders/checkout

Action: Retry pending requests after the stated delay. For a failed design, re-save the affected side and retry.

Released 2026-10-09

Campaign proofs require authored back artwork

Campaign proof generation refuses to complete when an authored back has no print-ready PDF. Deliberately blank backs remain one-sided. Printing from an approved proof uses the approved back snapshot, so a later back edit is not silently added to the mailing.

fixed · POST /v1/campaigns/approve

Action: Re-save an affected design side before retrying proof generation. Generate and approve a new proof when changing the artwork to be mailed.

Released 2026-10-09

Back PDF validation uses back-side requirements

Template back PDFs are assessed as back artwork using structural and format checks. Front-side address and postage furniture are not required on the back. Validation can report non-enforced compliance findings as warnings.

improved · POST /v1/templates/create, POST /v1/templates/update, POST /v1/templates/publish, POST /v1/designs/validate-pdf

Action: Review returned validation issues and warnings when uploading or publishing two-sided artwork.

Released 2026-10-09

Campaign cancellation counts match eligible pieces

Reads of processing and completed campaigns include cancellable_pieces and align the older cancellable_count field with the cancellation endpoint's piece eligibility rules.

fixed · GET /v1/campaigns/get/:id, GET /v1/campaigns/list, POST /v1/campaigns/cancel

Action: Use cancellable_pieces when showing the current number of pieces eligible for cancellation.

Released 2026-10-09

Recipient return-address names and country can be cleared

Recipient updates accept an empty string for return_country, return_first_name, return_last_name and return_company to clear those stored fields.

fixed · POST /v1/recipients/update

Action: Send an empty string for each supported return-address field you want to clear; omit a field to leave it unchanged.

Released 2026-10-09

API documentation · API reference PDF