Integrations
Partner API reference
Every operation the partner API offers, with the scopes, request shapes, and rules a client has to follow.
On this page
The partner API is a versioned, server-to-server REST API at https://integrations.snapbar.com/v1, authenticated with an API key as a bearer token. The OpenAPI document is the canonical reference for parameters, bodies, and schemas; this page explains the rules around them. Start with Create API keys.
Read activations and submissions
GET /activationslists the activations (experiences) in the key account, newest first, withid,short_id,name,type,state,starts_at,ends_at, andcreated_at. Theidis the activation identifier every other route takes. Scope: read submissions. A full example page is in Create API keys.GET /activations/{id}/submissionslists completed submissions as envelopes with visible finished media.submission.approval_statusispending,approved, orrejected; addapproved_only=truefor a display or approval-aware catch-up. Approval and completion are different: a generic completed list may contain unreviewed photos. Hidden media is omitted. Withoutinclude_lead=true, the lead key is left out. An unknown or foreign activation answersresource_not_found. Scope: read submissions.For incremental polling, choose a fixed
completed_afterlower bound and keep it unchanged while draining every page vianext_cursor, including pages of equal timestamps. Only afterhas_more=falsepersist the greatest observedsubmission.completed_at. Start the next scan before that watermark (for example, five minutes earlier) and upsert by submission/media ID. The filter is strictly greater-than, so advancing it between pages loses equal-timestamp rows. Bounded overlap cannot guarantee capture of arbitrarily late commits or later approval/hide/delete changes: periodically drain a full scan withoutcompleted_after, and reconcile local membership only after the complete scan succeeds. The runnable poller linked below implements these rules. Without the parameter, results remain newest first.curl --fail-with-body --get \ --header "Authorization: Bearer ${SNAPBAR_API_KEY}" \ --data-urlencode "completed_after=2026-07-18T19:00:00Z" \ --data-urlencode "limit=100" \ https://integrations.snapbar.com/v1/activations/${ACTIVATION_ID}/submissionsGET /submissions/{id}returns any submission state, currentapproval_status, and nullableexternal_id. Pending/processing/failed submissions have no finished media andcompleted_at: null; poll after an ingest202until complete. For an approval-gated display, require bothstate: completeandapproval_status: approved, and use only the returned visible media. A missing/deleted submission answersresource_not_found; remove its cached copy. Scope: read submissions.Add
include_lead=trueto any read to include contact details, custom fields, and consent. That needs the read lead details preset and a live key, and returns leads regardless of marketing consent: consent gates what Snapbar pushes to a destination, not what the owning account may read about its own guests.
Send photos in
POST /activations/{id}/submissionscreates a submission from one to three public HTTPS image links. Scope: create submissions. Every accepted request spends one activation credit. AnIdempotency-Keyheader of up to 255 characters is required; see the rules below before choosing one.curl --fail-with-body \ --request POST \ --header "Authorization: Bearer ${SNAPBAR_API_KEY}" \ --header 'Content-Type: application/json' \ --header "Idempotency-Key: ${YOUR_REQUEST_ID}" \ --data '{ "media_urls": ["https://media.example.com/source.jpg"], "processing": "ai", "locale": "en", "input_data": {"campaign": "summer-launch"}, "lead_data": {"email": "guest@example.com", "terms_consent": true, "marketing_consent": false} }' \ https://integrations.snapbar.com/v1/activations/${ACTIVATION_ID}/submissionsThe response reports the activation, the style that ran, the processing mode, and the new submission.
lead_persistedistruewhen yourlead_datawas stored,nullwhen you sent none, andfalsewhen the photo landed but the lead could not be saved; a201or202withfalsemeans the submission exists, the credit is spent, and you should resend the contact details through your own channel because the request will not be retried for you.HTTP/1.1 202 Accepted X-Request-Id: c0a8012e-4f2b-4b7d-9c1e-6d3a8f5b2e10 { "activation_id": "2f5c1a8e-7d3b-4e1f-9a6c-0b8d4e2f1a37", "definition_key": "style_1", "lead_persisted": true, "processing": "ai", "submission": { "id": "6b1d9e3c-2a4f-4c8e-b7d1-5f0a3e9c2b48", "short_id": "sub_Sub123Def456", "state": "pending" } }processingisaiby default: the images are inputs, the activation style runs, and the response is202with statepending.upload_onlytreats the images as the finished result and returns201with statecomplete. Both consume one credit; with none available the API answersinsufficient_credits.Before fetching any image, Snapbar checks that the activation exists in the account, is active and unlocked with a published release, that
definition_keynames an active style, and that a credit is available, in that order. A request that fails those checks is refused withresource_not_found,activation_not_accepting, orinsufficient_creditsbefore any media is downloaded, so it costs nothing and returns quickly.Idempotency keys are account-scoped and shared by every key in that account: namespace them by application. Repeat the same key and body after an uncertain response; never mint a new key to retry that photo. A stored success replays its original response.
503 ingest_outcome_unknownmeans the commit outcome is not yet known: wait forRetry-Afterand retry unchanged. A409 idempotency_conflictthat carriesRetry-Aftermeans the original request is still in flight (for up to ten minutes): keep retrying the same key and body. A409 idempotency_conflictwithoutRetry-Aftermeans the body changed. A confirmed rejection releases the claim. Success replay expires after 24 hours, after which reuse may create a second submission and charge again; reconcile by your saved submission/external ID before retrying an older request.Each image may be up to 20 MB and must be a PNG, JPEG, GIF, or WebP; the file bytes are checked, not just the extension. Snapbar fetches it through a protected fetcher that follows no redirects and gives up after 15 seconds, then rehosts it before storing the submission. A fetch, type, size, or rehosting failure returns
media_unfetchable. Video, HEIC, and other media types are not accepted.GET /activations/{id}/styleslists active styles in the published release withdefinition_key,name,pipeline_type,prompt_max_length, andoutput_count. Scope: read submissions. Use the returned key for ingest; omit it to use the first active published style. An unknown or inactive key answersresource_not_found. The list contains public style metadata, not the private prompt or workflow.lead_datais optional. Any contact field or custom field requiresterms_consent: true, and the consent source is recorded asapi.localeis a BCP 47 tag such asenorpt-BRand controls the language of the result email and text message; omitted, delivery uses the activation default.input_dataremains write-only job metadata; keep your own copy. Use the separate top-levelexternal_id(an opaque string of up to 255 characters, without personal data) to correlate your application: it is echoed by ingest and returned assubmission.external_idin reads and webhooks. It is not unique and does not replaceIdempotency-Key. Reservedinput_data.promptoverrides the AI style prompt; whitespace means unset. The selected published style’sprompt_max_lengthis enforced before image fetching or credit reservation: Seedream 4.5 and Seedream 5 Pro allow 4,000 characters; compatible image models allow up to 10,000. Reservedinput_data.localeoverrides top-levellocale; both are BCP 47 language tags. Do not use these names for unrelated metadata.
Moderate media
PATCH /media/{id}hides or restores one media item. Scope: moderate submissions. The change also applies to every item in the same submission whose address is byte-identical, such as a passthrough input and output pair, and never to another submission. Hidden media disappears from later reads and from Snapbar displays; deliveries already sent are not recalled. A hide made through the API is recorded as an API hide, so a later dashboard approval does not undo it; only your tools or a moderator restore it.curl --fail-with-body \ --request PATCH \ --header "Authorization: Bearer ${SNAPBAR_API_KEY}" \ --header 'Content-Type: application/json' \ --data '{"is_hidden": true}' \ https://integrations.snapbar.com/v1/media/${MEDIA_ID}
Deliveries
GET /deliverieslists deliveries newest first with optionalstatus,experience_id, andendpoint_idfilters.statustakes one or more ofpending,paused,delivering,succeeded,failed_retryable,failed_permanent,unknown,skipped_consent,skipped_no_contact, andskipped_disabled, comma-separated or repeated, at most 10 per request. The table below maps each value to the label in Activity. Scope: operations.curl --fail-with-body --get \ --header "Authorization: Bearer ${SNAPBAR_API_KEY}" \ --data-urlencode "status=failed_retryable,failed_permanent" \ --data-urlencode "endpoint_id=${ENDPOINT_ID}" \ https://integrations.snapbar.com/v1/deliveriesEach row carries the ids you need to join it to a submission and an endpoint or destination, the attempt count, the next scheduled attempt, and the class of the last error.
originislivefor a delivery created by guest activity andbackfillfor one queued by Send finalized leads;destination_kindiswebhook_endpointorconnection, anddestination_labelis the receiver host for a webhook.{ "id": "0d7f3a2b-9c1e-4b6d-8a5f-3e2c1b0a9d8e", "account_id": "…", "experience_id": "2f5c1a8e-7d3b-4e1f-9a6c-0b8d4e2f1a37", "submission_id": "6b1d9e3c-2a4f-4c8e-b7d1-5f0a3e9c2b48", "destination_kind": "webhook_endpoint", "destination_label": "example.com", "endpoint_id": "9c2e4b6a-1d3f-4a5b-8c7d-2e1f0a9b8c7d", "binding_id": null, "binding_config_version": null, "connection_id": null, "trigger_event": "submission.completed", "origin": "live", "status": "failed_retryable", "attempts": 2, "last_error_class": "http_503", "next_attempt_at": "2026-07-18T19:30:35.000+00:00", "delivering_started_at": null, "completed_at": null, "idempotency_key": "…", "provider_object_ids": null, "created_at": "2026-07-18T19:24:35.512+00:00" }POST /deliveries/{id}/replayqueues a delivery again. Eligible states arefailed_retryable,failed_permanent,skipped_disabled, andunknown; anything else answersdelivery_not_replayable. Anunknownoutcome needs{"verified": true}to confirm you checked that the receiver never processed the original attempt. A replay during a live retry supersedes the pending retry rather than racing it. Scope: operations.
Webhook endpoints
GET /webhook-endpoints,POST /webhook-endpoints, andDELETE /webhook-endpoints/{id}list, register, and remove signed endpoints. Registration answers201with the endpoint and its one-timesigning_secret; the full response and the receiver contract are in Receive signed webhooks at your own endpoint. Scope: manage notification endpoints.Deleting an endpoint answers
204and prevents new sends. Pending and retryable work closes asskipped_disabled; an attempt already in flight settles through its owned outcome or stale-attempt recovery. Deletion cannot recall an HTTP request already sent. Terminal history remains, and a replacement does not inherit old deliveries. Automatic disablement also closes queued work without recalling in-flight requests.GET /hooks/sample?event_type=…returns one synthetic envelope in an array.POST /test/deliveriesrequires a live key andendpoint_id, then signs a synthetic send with that registered endpoint’s existing secret. Both need the manage notification endpoints preset; see Create API keys for what a test key can do.The OpenAPI document also lists hook subscription operations reserved for automation partners. They are not intended for direct use.
Pagination
Collections return
data,next_cursor, andhas_more.limitdefaults to 20 and is capped at 100. Results are newest first unlesscompleted_afteris set. Passnext_cursorback unchanged; keep the same collection and filters for the whole scan. Malformed tokens and tokens from the other pagination mode returninvalid_cursor; tokens do not enforce collection or filter identity, so changing either mid-scan can skip records.curl --fail-with-body --get \ --header "Authorization: Bearer ${SNAPBAR_API_KEY}" \ --data-urlencode "limit=100" \ --data-urlencode "cursor=${NEXT_CURSOR}" \ https://integrations.snapbar.com/v1/deliveries
Delivery status values and Activity labels
The status value on a delivery row, the label the Activity tab shows for it, and what it means. The tab is described in Fix failed deliveries.
Sending
pendingis queued and waiting for a send slot;deliveringis in flight right now.- Not replayable.
Retrying
- A temporary failure with attempts left on the retry ladder;
next_attempt_atsays when. - Replayable, which supersedes the pending retry.
Action needed
- A permanent failure, or the ninth attempt failed.
last_error_classnames the cause. - Replayable after the cause is fixed.
Needs verification
- Snapbar cannot prove whether the receiver processed the request.
- Replayable only with
{"verified": true}.
Skipped with reason
skipped_consentlacked the required consent;skipped_no_contacthad no email for a managed destination;skipped_disabledcovers a deleted or auto-disabled endpoint and an approval retracted before delivery (last_error_classsays which).- Only
skipped_disabledis replayable, and a retracted approval revives on its own.
Paused
- The destination was paused or the account switch was off when the delivery was claimed.
- Not replayable; it resumes when the switch returns.
Delivered
- The receiver or provider accepted the delivery.
- Not replayable.
What to know
- Versioning.The version is part of the path. Within
/v1, Snapbar may add optional request fields, response fields, event types, and enum values; existing fields never change meaning. Clients must ignore unknown fields and tolerate new enum values. A breaking change gets a new version, and a deprecated version carriesDeprecationandSunsetheaders for at least six months before removal. - Envelope versions.Webhook deliveries and API reads share Lead Envelope version 1, which is additive only. Each endpoint stores a payload version; when a new version ships, existing endpoints stay pinned and both versions are published for at least six months.
- Retention and deletion.Ninety days after a delivery finishes, its stored payload is cleared while the row and its status remain; a replay after that point is rebuilt from current data. The ingest idempotency store keeps a successful response for 24 hours. When a submission is erased, personal fields are scrubbed from stored envelopes and error details, media links stop working, and a non-personal tombstone remains for audit. A system that copied lead or media data must honor its own deletion obligations.
- Errors.Every error response has a stable shape with a
codefor program logic, amessagefor diagnostics, adoc_urlthat links to the matching section of Partner API errors and limits, and arequest_idto quote when contacting Snapbar.
Tips
- Prove the registered receiver with a signed synthetic delivery first; test and live key capabilities are spelled out in Create API keys.
- Store the submission
short_idwith anything you keep; it is the identifier staff see in the dashboard.