API reference
The reference is rendered from OpenAPI.
113 public operations are described by the downloadable OpenAPI 3.1 contract. Filter them by path, method, tag, or summary. Every request goes to https://api.perionpayments.com, in Sandbox and Live alike.
For machine use
Download the OpenAPI contract or read llms.txt. Problem codes are at /problems.json.
Authentication
1POST/oauth/tokenGets a tokenExchange client credentials for an access token
Exchanges an API client's ID and secret, sent with HTTP Basic or as form fields, for a short-lived bearer token carrying a subset of the client's scopes. Call it from a server: the secret never belongs in a browser, a mobile app or an agent's prompt. A token lasts at most ten minutes and never outlives its client's own expiry, so request a new one rather than caching it. An expired client is refused with `invalid_client` and `code: api_client_expired`; retrying cannot fix that.
- Operation ID
issueClientToken- Authentication
- OAuthClient
- Safety class
- Credentials · gets a token or a session
- Agent key
- Allowed
Request body Required
application/x-www-form-urlencodedResponses
200A short-lived opaque bearer token.application/json400Invalid grant or scope.application/json401Client authentication failed. When the secret was correct but the API client has passed its expiry, `error` is still `invalid_client` and `code` is `api_client_expired`: retrying cannot succeed, and the merchant must issue a new credential.application/json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+json503Token service temporarily unavailable.application/jsonAPI client
1GET/v1/api_clientRead this API client's own terms
Returns the API client behind the presenting token: its kind, expiry, scopes and the token's narrower scopes, its policy, the limits the server applies (agent defaults included), what it can and cannot do in plain verbs, its request rate, and what it did today in the merchant's business day -- payments created and paid, refunds sent and what it may still refund, payers prompted in the last hour and refusals. Read it before acting, so an agent can tell a customer "I can take up to USD 50.00 here" and plan a larger order as a payment link, instead of learning each limit by being refused. Any valid token may call it; no scope is needed to know one's own terms. It never describes another credential and never returns secret material.
- Operation ID
getSelfAPIClient- Authentication
- OAuth2
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200This API client's own record.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonPayment intents
6POST/v1/payment_intentsAsks the payer · a prompt already sent can't be recalledCreate a payment intent
Creates one merchant-scoped payment and, with `confirm: true` and a payment method, starts collecting it. Send an `Idempotency-Key` unique to the order: repeating the same request with the same key returns the original result instead of a second payment, which makes it the only safe retry after a timeout or a lost response. The 201 response is not proof of payment. A mobile-money payment normally returns `requires_action` with `next_action.type: approve_on_device`: the payer must approve the prompt on their own phone with their PIN, and neither the merchant nor an agent can approve for them. Fulfill only after a signed `payment_intent.succeeded` event or a read showing `succeeded` for the expected amount and currency. While `processing_reason` is `provider_outcome_unknown` the debit may still complete: keep the same payment and never create another for the same order.
- Asks the payer. Nothing completes until the payer approves it on their own phone or payment page. The response is not proof of payment.
- One key, one movement of money. Retry it only with the same
Idempotency-Keyand body; a new key starts a new movement of money.
- Operation ID
createPaymentIntent- Authentication
- OAuth2 (payment_intents:write)
- Safety class
- Request · nothing completes until the payer approves · a prompt already sent can't be recalled
- Agent key
- Only when
allowed_operationslistspayment_intents:create
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
Idempotency-Key | header | Required unless previewing | Stable opaque key for this semantic command. Reuse it after timeouts. Required for every request except a preview (`Perion-Preview: true`), which claims nothing.string16–255 characters |
Perion-Preview | header | Optional | `true` previews the request instead of sending it. Every admission check
that needs no write runs -- your client's limits (per payment, per refund
and per day, and how many payers it may prompt), the order and reference
guards, the payment method's eligibility, and the one-prompt-per-payer
rule -- and the answer is a Preview:
what the request would do, who decides whether money moves, whether it can
be undone, its limits, and the exact problems it would be refused with.
Nothing is created or claimed, no provider is called and nothing reaches a
payer's phone. Show the preview to whoever decides, then send the request
without the header.
stringOne of true, false |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
X-Request-Id | header | Optional | stringUp to 128 characters |
Request body Required
application/json · PaymentIntentCreateResponses
200A preview, answered because the request sent `Perion-Preview: true`. Nothing was created, reserved or sent, and no provider or phone was reached.application/json201Intent committed; provider dispatch may still be pending or ambiguous.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json409Idempotency or lifecycle conflict.application/problem+json422The request is well formed, but a limit the merchant set refuses it before anything is created or charged. `api_client_policy_amount_exceeded` means the amount is above this API client's per-payment limit for the currency, or the client's policy lists no limit for that currency; `limit` names it. Use an amount within the limit; do not split one order into several payments to pass it. `api_client_policy_refund_limit_exceeded` means a refund is above the client's per-refund limit, past what it may refund today, or on a payment it did not create; `limit` names the bound and `remaining_today` what is left. Refunds go out with no customer approval: stop and tell the merchant rather than trying smaller amounts.application/problem+json429Nothing was sent. Retry after the indicated delay with the same Idempotency-Key and body. `rate_limited` is this API client's request budget. `payer_prompt_limit_reached` means the payer already has the allowed number of payment prompts from this merchant waiting on their phone (`limit.prompts_waiting`), or has had the hourly allowance (`limit.prompts_per_hour`): check the payments already waiting instead of starting another. `api_client_policy_prompt_reach_exceeded` means this API client has prompted as many different payers' phones this hour as its policy allows (`limit.payers_per_hour`); send the customer a payment link instead, or wait. `payment_method_requires_hosted_checkout` (409) is returned to an Agent key for a method that would ask the customer for a one-time code: create a checkout session and send its `url`.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+json503Dependency or rail is unavailable; retry safely where documented.application/problem+jsonGET/v1/payment_intentsList payment intents
This operation is defined by its request and response contract below.
- Operation ID
listPaymentIntents- Authentication
- OAuth2 (payment_intents:read)
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
limit | query | Optional | integerFrom 1 to 100 · Default 20 |
starting_after | query | Optional | string |
ending_before | query | Optional | string |
created[gte] | query | Optional | string · date-time |
created[lte] | query | Optional | string · date-time |
status | query | Optional | stringOne of requires_payment_method, requires_confirmation, requires_action, processing, succeeded, partially_refunded, refunded, failed, cancelled, expired |
currency | query | Optional | stringPattern ^[A-Z]{3}$ |
rail | query | Optional | stringUp to 64 characters |
merchant_reference | query | Optional | Exact merchant-owned reference. Search never performs a fuzzy or cross-tenant match.stringUp to 128 characters |
api_client | query | Optional | Only what this API client created (`cl_…`). An id that is not one of this merchant's clients in this environment matches nothing.stringUp to 128 characters · Pattern ^cl_[A-Za-z0-9]+$ |
mobile_number_last4 | query | Optional | Exactly four digits matched only against the stored masked payment-method display. Requires both created bounds with a maximum 31-day window. Raw mobile numbers are not searchable.stringPattern ^[0-9]{4}$ |
support_reference | query | Optional | Exact PerionPayments support reference (`req_…`).stringUp to 128 characters · Pattern ^req_[A-Za-z0-9]+$ |
payer_reference | query | Optional | The payer's `PER-` reference in any spoken or typed form; see PayerReference.stringUp to 32 characters |
order_reference | query | Optional | Exact order reference. Every payment for the order, newest first.stringUp to 128 characters |
payment_link | query | Optional | Payments made through this payment link.stringUp to 128 characters · Pattern ^pl_[A-Za-z0-9]+$ |
attempt_id | query | Optional | Exact payment-attempt identifier. Resolves the merchant-safe parent payment intent without exposing provider evidence.stringUp to 128 characters · Pattern ^pa_[A-Za-z0-9]+$ |
failure_owner | query | Optional | Exact governed terminal failure ownership. Provider-outcome-unknown is non-terminal and is never admitted here.stringOne of customer_declined, customer_abandoned, provider_error, perion_error |
needs_investigation | query | Optional | true keeps only processing payments that need investigation (held for manual review, or with a provider outcome unknown for more than an hour); false leaves them out. Combines only with status=processing or no status.boolean |
amount[gte] | query | Optional | integer · int64At least 0 |
amount[lte] | query | Optional | integer · int64At least 0 |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Newest-first merchant-scoped page.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonGET/v1/payment_intents/{payment_intent_id}Retrieve a payment
Returns the authoritative state of one payment. Make this read after a timeout, a webhook, or a payer's return to your site, and fulfill only when `status` is `succeeded` and `amount` and `currency` match the order. `requires_action` means the payer still has to act -- for `approve_on_device`, on their own phone; `processing` means the outcome is not yet known. Keep reading the same payment, no sooner than `next_poll_after` when it is set, and never create a replacement while it is `requires_action` or `processing`.
- Operation ID
getPaymentIntent- Authentication
- OAuth2 (payment_intents:read)
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
payment_intent_id | path | Required | stringPattern ^pi_[A-Za-z0-9]+$ |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Current intent projection.application/json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonGET/v1/payment_intents/{payment_intent_id}/timelineList a payment's timeline
Returns one tenant-scoped, oldest-first evidence snapshot. Provider raw payloads, internal identifiers, operator annotations, and webhook response bodies are never included.
- Operation ID
getPaymentIntentTimeline- Authentication
- OAuth2 (payment_intents:read)
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
payment_intent_id | path | Required | stringPattern ^pi_[A-Za-z0-9]+$ |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Current payment projection with its merchant-safe evidence history.application/json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonPOST/v1/payment_intents/{payment_intent_id}/confirmAsks the payer · a prompt already sent can't be recalledConfirm an unconfirmed intent
Starts collecting an unconfirmed payment with the given payment method. For mobile money the payer receives a prompt on their own phone and must approve it with their PIN; read `status` and `next_action` and wait for the outcome rather than confirming again. Send an `Idempotency-Key`: an exact retry returns the first result. One merchant can have only a bounded number of prompts waiting on one payer, and send only a bounded number per hour, so a looping caller is refused with 429 `payer_prompt_limit_reached` before anything reaches the phone.
- Asks the payer. Nothing completes until the payer approves it on their own phone or payment page. The response is not proof of payment.
- One key, one movement of money. Retry it only with the same
Idempotency-Keyand body; a new key starts a new movement of money.
- Operation ID
confirmPaymentIntent- Authentication
- OAuth2 (payment_intents:write)
- Safety class
- Request · nothing completes until the payer approves · a prompt already sent can't be recalled
- Agent key
- Only when
allowed_operationslistspayment_intents:confirm
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
payment_intent_id | path | Required | stringPattern ^pi_[A-Za-z0-9]+$ |
Idempotency-Key | header | Required | Stable opaque key for this semantic command. Reuse it after timeouts.string16–255 characters |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Request body Required
application/jsonResponses
200Confirmed intent; inspect its state and next action.application/json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json409Idempotency or lifecycle conflict.application/problem+json422The request is well formed, but a limit the merchant set refuses it before anything is created or charged. `api_client_policy_amount_exceeded` means the amount is above this API client's per-payment limit for the currency, or the client's policy lists no limit for that currency; `limit` names it. Use an amount within the limit; do not split one order into several payments to pass it. `api_client_policy_refund_limit_exceeded` means a refund is above the client's per-refund limit, past what it may refund today, or on a payment it did not create; `limit` names the bound and `remaining_today` what is left. Refunds go out with no customer approval: stop and tell the merchant rather than trying smaller amounts.application/problem+json429Nothing was sent. Retry after the indicated delay with the same Idempotency-Key and body. `rate_limited` is this API client's request budget. `payer_prompt_limit_reached` means the payer already has the allowed number of payment prompts from this merchant waiting on their phone (`limit.prompts_waiting`), or has had the hourly allowance (`limit.prompts_per_hour`): check the payments already waiting instead of starting another. `api_client_policy_prompt_reach_exceeded` means this API client has prompted as many different payers' phones this hour as its policy allows (`limit.payers_per_hour`); send the customer a payment link instead, or wait. `payment_method_requires_hosted_checkout` (409) is returned to an Agent key for a method that would ask the customer for a one-time code: create a checkout session and send its `url`.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonPOST/v1/payment_intents/{payment_intent_id}/cancelStops or removes · can't be undoneCancel a payment the payer hasn't approved
Cancels a payment that has not yet been sent to its payment method (`requires_payment_method` or `requires_confirmation`). Once a payer prompt is out, cancellation is refused with 409 `attempt_in_flight`: the payer may still approve, so wait for the outcome instead of cancelling and paying again. A payment waiting on a hosted card page (`requires_action` on a hosted card rail) is different: cancelling it reports that the payer left that page without paying. Nothing is decided on that word. PerionPayments asks the acquirer at once and answers 202 with the payment as it stands. If nothing was submitted, the payment ends within seconds as `failed` with `failure_code` `customer_cancelled`, and the event is `payment_intent.failed`, not `payment_intent.cancelled`: treat it as not paid. If the payer paid after all, it succeeds as usual.
- Operation ID
cancelPaymentIntent- Authentication
- OAuth2 (payment_intents:write)
- Safety class
- Destructive · stops or removes something · can't be undone
- Agent key
- Only when
allowed_operationslistspayment_intents:cancel
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
payment_intent_id | path | Required | stringPattern ^pi_[A-Za-z0-9]+$ |
Idempotency-Key | header | Required | Stable opaque key for this semantic command. Reuse it after timeouts.string16–255 characters |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Request body Optional
application/jsonResponses
200Cancelled intent.application/json202The payment waits on a hosted card page; the acquirer is being asked
whether the payer paid. The body is the payment as it stands.
application/json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json409Idempotency or lifecycle conflict.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonCheckout sessions
3POST/v1/checkout_sessionsAsks the payerCreate hosted checkout
Creates a hosted checkout for one payment: a new payment from `amount` and `currency`, or an existing unconfirmed `payment_intent`. Send the payer to the returned `url`, or mount `client_secret` with PerionPayments.js. Creating a session moves no money; the payer chooses a method and approves the payment themselves. A browser return to `return_url` is navigation, not proof of payment: confirm the payment intent's status from your server.
- Asks the payer. Nothing completes until the payer approves it on their own phone or payment page. The response is not proof of payment.
- Operation ID
createCheckoutSession- Authentication
- OAuth2 (checkout_sessions:write)
- Safety class
- Request · nothing completes until the payer approves
- Agent key
- Only when
allowed_operationslistscheckout_sessions:create
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
Idempotency-Key | header | Required unless previewing | Stable opaque key for this semantic command. Reuse it after timeouts. Required for every request except a preview (`Perion-Preview: true`), which claims nothing.string16–255 characters |
Perion-Preview | header | Optional | `true` previews the request instead of sending it. Every admission check
that needs no write runs -- your client's limits (per payment, per refund
and per day, and how many payers it may prompt), the order and reference
guards, the payment method's eligibility, and the one-prompt-per-payer
rule -- and the answer is a Preview:
what the request would do, who decides whether money moves, whether it can
be undone, its limits, and the exact problems it would be refused with.
Nothing is created or claimed, no provider is called and nothing reaches a
payer's phone. Show the preview to whoever decides, then send the request
without the header.
stringOne of true, false |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Request body Required
application/json · CheckoutSessionCreateResponses
200A preview, answered because the request sent `Perion-Preview: true`. Nothing was created, reserved or sent, and no provider or phone was reached.application/json201Hosted checkout session.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json409Idempotency or lifecycle conflict.application/problem+json422The request is well formed, but a limit the merchant set refuses it before anything is created or charged. `api_client_policy_amount_exceeded` means the amount is above this API client's per-payment limit for the currency, or the client's policy lists no limit for that currency; `limit` names it. Use an amount within the limit; do not split one order into several payments to pass it. `api_client_policy_refund_limit_exceeded` means a refund is above the client's per-refund limit, past what it may refund today, or on a payment it did not create; `limit` names the bound and `remaining_today` what is left. Refunds go out with no customer approval: stop and tell the merchant rather than trying smaller amounts.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonGET/v1/checkout_sessions/{checkout_session_id}Retrieve checkout session
This operation is defined by its request and response contract below.
- Operation ID
getCheckoutSession- Authentication
- OAuth2 (checkout_sessions:read)
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
checkout_session_id | path | Required | stringPattern ^cs_[A-Za-z0-9]+$ |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Session projection; `client_secret` is always null and fulfillment still follows its payment intent.application/json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonPOST/v1/checkout_sessions/{checkout_session_id}/saved_cards/revokeStops or removes · can't be undoneWithdraw saved-card access from a checkout
Monotonically withdraws only the saved-card delegation. A repeat keeps the original withdrawal; it never renews access. It does not cancel a payment already admitted or detach the customer's cards.
- Operation ID
revokeCheckoutSavedCards- Authentication
- OAuth2 (checkout_sessions:write, payment_methods:read)
- Safety class
- Destructive · stops or removes something · can't be undone
- Agent key
- Only when
allowed_operationslistscheckout_sessions:revoke_saved_cards
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
checkout_session_id | path | Required | stringPattern ^cs_[A-Za-z0-9]+$ |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Idempotency-Key | header | Required | Stable opaque key for this semantic command. Reuse it after timeouts.string16–255 characters |
Responses
204Saved-card authority is withdrawn or was never delegated.400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+json503Dependency or rail is unavailable; retry safely where documented.application/problem+jsonCustomers
5GET/v1/customer_commands/{command_key}Look up an earlier customer request
This operation is defined by its request and response contract below.
- Operation ID
getCustomerCommandStatus- Authentication
- OAuth2 (customers:read)
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
command_key | path | Required | string16–255 characters |
operation | query | Required | stringOne of create, update |
customer | query | Optional | Exact customer ID, required for update and omitted for create.stringPattern ^cust_[A-Za-z0-9]+$ |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Recorded receipt or unconfirmed state. Unconfirmed is not proof of failure. No customer save is issued.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json409Idempotency or lifecycle conflict.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonPOST/v1/customersCreates or changes recordsCreate a customer
This operation is defined by its request and response contract below.
- Operation ID
createCustomer- Authentication
- OAuth2 (customers:write)
- Safety class
- Records · creates or changes a record
- Agent key
- Never
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
Idempotency-Key | header | Required | Stable opaque key for this semantic command. Reuse it after timeouts.string16–255 characters |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Request body Required
application/json · CustomerCreateResponses
201Customer identity committed once.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json409Idempotency or lifecycle conflict.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonGET/v1/customersList merchant customers
This operation is defined by its request and response contract below.
- Operation ID
listCustomers- Authentication
- OAuth2 (customers:read)
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
limit | query | Optional | integerFrom 1 to 100 · Default 20 |
starting_after | query | Optional | string |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Newest-first customer page.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonGET/v1/customers/{customer_id}Retrieve a merchant customer
This operation is defined by its request and response contract below.
- Operation ID
getCustomer- Authentication
- OAuth2 (customers:read)
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
customer_id | path | Required | stringPattern ^cust_[A-Za-z0-9]+$ |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Exact customer projection.application/json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonPOST/v1/customers/{customer_id}Creates or changes recordsUpdate a merchant customer
This operation is defined by its request and response contract below.
- Operation ID
updateCustomer- Authentication
- OAuth2 (customers:write)
- Safety class
- Records · creates or changes a record
- Agent key
- Never
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
customer_id | path | Required | stringPattern ^cust_[A-Za-z0-9]+$ |
Idempotency-Key | header | Required | Stable opaque key for this semantic command. Reuse it after timeouts.string16–255 characters |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Request body Required
application/json · CustomerUpdateResponses
200Updated customer projection.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json409Idempotency or lifecycle conflict.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonBilling
25POST/v1/plansChanges settingsCreate an immutable billing plan version
This operation is defined by its request and response contract below.
- Operation ID
createPlan- Authentication
- OAuth2 (billing:write)
- Safety class
- Configuration · changes settings
- Agent key
- Never
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
Idempotency-Key | header | Required | Stable opaque key for this semantic command. Reuse it after timeouts.string16–255 characters |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Request body Required
application/json · BillingPlanCreateResponses
201Billing plan committed once.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json409Idempotency or lifecycle conflict.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonGET/v1/plansList billing plans
This operation is defined by its request and response contract below.
- Operation ID
listPlans- Authentication
- OAuth2 (billing:read)
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
limit | query | Optional | integerFrom 1 to 100 · Default 20 |
starting_after | query | Optional | string |
status | query | Optional | Exact status from the lifecycle of the billing object being listed.stringUp to 40 characters |
q | query | Optional | Case-insensitive plan name or public-ID search across the safe identifiers exposed by this billing ledger.stringUp to 128 characters |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Newest-first bounded plan page.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonGET/v1/plans/{plan_id}Retrieve an exact billing plan version
This operation is defined by its request and response contract below.
- Operation ID
getPlan- Authentication
- OAuth2 (billing:read)
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
plan_id | path | Required | stringPattern ^plan_[A-Za-z0-9]+$ |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Exact plan projection.application/json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonPOST/v1/plans/{plan_id}/archiveChanges settings · can't be undoneArchive a billing plan for new enrollments
Existing agreements and subscriptions retain their accepted immutable plan version.
- Operation ID
archivePlan- Authentication
- OAuth2 (billing:write)
- Safety class
- Configuration · changes settings · can't be undone
- Agent key
- Never
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
plan_id | path | Required | stringPattern ^plan_[A-Za-z0-9]+$ |
Idempotency-Key | header | Required | Stable opaque key for this semantic command. Reuse it after timeouts.string16–255 characters |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Request body Required
application/json · BillingPlanArchiveResponses
200Archived plan projection.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json409Idempotency or lifecycle conflict.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonGET/v1/agreementsList recurring-payment agreements
This operation is defined by its request and response contract below.
- Operation ID
listAgreements- Authentication
- OAuth2 (billing:read)
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
limit | query | Optional | integerFrom 1 to 100 · Default 20 |
starting_after | query | Optional | string |
status | query | Optional | Exact status from the lifecycle of the billing object being listed.stringUp to 40 characters |
q | query | Optional | Case-insensitive plan name or public-ID search across the safe identifiers exposed by this billing ledger.stringUp to 128 characters |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Newest-first bounded agreement page.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonGET/v1/agreements/{agreement_id}Retrieve an exact recurring-payment agreement and acceptance evidence
This operation is defined by its request and response contract below.
- Operation ID
getAgreement- Authentication
- OAuth2 (billing:read)
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
agreement_id | path | Required | stringPattern ^agr_[A-Za-z0-9]+$ |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Exact agreement projection.application/json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonPOST/v1/subscriptionsAsks the payer · a prompt already sent can't be recalledBegin a subscription through a consent-bound first-payment checkout
The returned agreement remains pending and the subscription incomplete until the payer explicitly accepts the current terms and the first payment reaches authoritative success evidence.
- Asks the payer. Nothing completes until the payer approves it on their own phone or payment page. The response is not proof of payment.
- Operation ID
createSubscription- Authentication
- OAuth2 (billing:write)
- Safety class
- Request · nothing completes until the payer approves · a prompt already sent can't be recalled
- Agent key
- Never
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
Idempotency-Key | header | Required unless previewing | Stable opaque key for this semantic command. Reuse it after timeouts. Required for every request except a preview (`Perion-Preview: true`), which claims nothing.string16–255 characters |
Perion-Preview | header | Optional | `true` previews the request instead of sending it. Every admission check
that needs no write runs -- your client's limits (per payment, per refund
and per day, and how many payers it may prompt), the order and reference
guards, the payment method's eligibility, and the one-prompt-per-payer
rule -- and the answer is a Preview:
what the request would do, who decides whether money moves, whether it can
be undone, its limits, and the exact problems it would be refused with.
Nothing is created or claimed, no provider is called and nothing reaches a
payer's phone. Show the preview to whoever decides, then send the request
without the header.
stringOne of true, false |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Request body Required
application/json · BillingSubscriptionCreateResponses
200A preview, answered because the request sent `Perion-Preview: true`. Nothing was created, reserved or sent, and no provider or phone was reached.application/json201Enrollment objects and first-payment checkout committed atomically.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json409Idempotency or lifecycle conflict.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonGET/v1/subscriptionsList subscriptions
This operation is defined by its request and response contract below.
- Operation ID
listSubscriptions- Authentication
- OAuth2 (billing:read)
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
limit | query | Optional | integerFrom 1 to 100 · Default 20 |
starting_after | query | Optional | string |
status | query | Optional | Exact status from the lifecycle of the billing object being listed.stringUp to 40 characters |
q | query | Optional | Case-insensitive plan name or public-ID search across the safe identifiers exposed by this billing ledger.stringUp to 128 characters |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Newest-first bounded subscription page.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonGET/v1/subscriptions/{subscription_id}Retrieve an exact subscription
This operation is defined by its request and response contract below.
- Operation ID
getSubscription- Authentication
- OAuth2 (billing:read)
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
subscription_id | path | Required | stringPattern ^sub_[A-Za-z0-9]+$ |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Exact subscription projection.application/json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonGET/v1/subscriptions/{subscription_id}/enrollmentRetrieve the original enrollment and current checkout availability
This operation is defined by its request and response contract below.
- Operation ID
getSubscriptionEnrollment- Authentication
- OAuth2 (billing:read, checkout_sessions:read)
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
subscription_id | path | Required | stringPattern ^sub_[A-Za-z0-9]+$ |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Current enrollment evidence. Read only; never creates another checkout. Handoff is null unless the original checkout is ready.application/json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json409Idempotency or lifecycle conflict.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonGET/v1/subscriptions/{subscription_id}/reconsentsList replacement requests linked to this subscription
This operation is defined by its request and response contract below.
- Operation ID
listSubscriptionReconsents- Authentication
- OAuth2 (billing:read)
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
subscription_id | path | Required | stringPattern ^sub_[A-Za-z0-9]+$ |
limit | query | Optional | integerFrom 1 to 100 · Default 20 |
starting_after | query | Optional | string |
status | query | Optional | Restrict requests to this persisted lifecycle status. A pending request has not activated; it may already contain payer acceptance evidence.stringOne of pending_acceptance, activated, canceled, expired |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Newest-first bounded history of immediate incoming and outgoing replacement requests with the subject subscription from the same read-only snapshot. No checkout credentials are returned.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json409Idempotency or lifecycle conflict.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonGET/v1/subscriptions/{subscription_id}/payment_source_changesList payer-requested payment-source changes for this subscription
Read-only. Only the payer can replace the paying mobile number, from their private billing link, and the agreement switches only after an approval prompt on the new number succeeds. There is no merchant command to change the payment source. Numbers are returned masked only.
- Operation ID
listSubscriptionPaymentSourceChanges- Authentication
- OAuth2 (billing:read)
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
subscription_id | path | Required | stringPattern ^sub_[A-Za-z0-9]+$ |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Newest-first bounded history of payer-driven payment-source changes. A pending change has not switched the source; an unknown provider outcome stays pending.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json409Idempotency or lifecycle conflict.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonPOST/v1/subscriptions/{subscription_id}/reconsentAsks the payer · a prompt already sent can't be recalledCreate a replacement enrollment that activates only after fresh payer consent
The source agreement and subscription remain authoritative until the replacement terms are explicitly accepted and the replacement first payment reaches accepted assurance. Currency cannot change in this operation.
- Asks the payer. Nothing completes until the payer approves it on their own phone or payment page. The response is not proof of payment.
- Operation ID
reconsentSubscription- Authentication
- OAuth2 (billing:write)
- Safety class
- Request · nothing completes until the payer approves · a prompt already sent can't be recalled
- Agent key
- Never
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
subscription_id | path | Required | stringPattern ^sub_[A-Za-z0-9]+$ |
Idempotency-Key | header | Required | Stable opaque key for this semantic command. Reuse it after timeouts.string16–255 characters |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Request body Required
application/json · BillingReconsentCreateResponses
201A pending replacement enrollment and reveal-once consent checkout.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json409Idempotency or lifecycle conflict.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonPOST/v1/subscriptions/{subscription_id}/{action}Stops or removes · can't be undonePause, resume, or permanently cancel an exact subscription
This operation is defined by its request and response contract below.
- Operation ID
controlSubscription- Authentication
- OAuth2 (billing:write)
- Safety class
- Destructive · stops or removes something · can't be undone
- Agent key
- Never
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
subscription_id | path | Required | stringPattern ^sub_[A-Za-z0-9]+$ |
action | path | Required | stringOne of pause, resume, cancel |
Idempotency-Key | header | Required | Stable opaque key for this semantic command. Reuse it after timeouts.string16–255 characters |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Request body Required
application/json · BillingSubscriptionControlRequestResponses
200The agreement and subscription after the audited state transition.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json409Idempotency or lifecycle conflict.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonGET/v1/invoicesList invoices and linked payment attempts
This operation is defined by its request and response contract below.
- Operation ID
listInvoices- Authentication
- OAuth2 (billing:read)
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
limit | query | Optional | integerFrom 1 to 100 · Default 20 |
starting_after | query | Optional | string |
status | query | Optional | Exact status from the lifecycle of the billing object being listed.stringUp to 40 characters |
q | query | Optional | Case-insensitive plan name or public-ID search across the safe identifiers exposed by this billing ledger.stringUp to 128 characters |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Newest-first bounded invoice page.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonGET/v1/invoices/{invoice_id}Retrieve an exact invoice and its linked payment attempts
This operation is defined by its request and response contract below.
- Operation ID
getInvoice- Authentication
- OAuth2 (billing:read)
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
invoice_id | path | Required | stringPattern ^inv_[A-Za-z0-9]+$ |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Exact invoice projection.application/json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonGET/v1/collection_cyclesList recurring collection cycles with their canonical payment attempts
This operation is defined by its request and response contract below.
- Operation ID
listCollectionCycles- Authentication
- OAuth2 (billing:read)
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
limit | query | Optional | integerFrom 1 to 100 · Default 20 |
starting_after | query | Optional | string |
status | query | Optional | Exact status from the lifecycle of the billing object being listed.stringUp to 40 characters |
q | query | Optional | Case-insensitive plan name or public-ID search across the safe identifiers exposed by this billing ledger.stringUp to 128 characters |
subscription | query | Optional | stringPattern ^sub_[A-Za-z0-9]+$ |
reason | query | Optional | stringOne of prompt_timeout, payer_declined, insufficient_funds, provider_unavailable, provider_uncertainty, agreement_revoked |
recovered | query | Optional | Select cycles paid after a succeeded attempt beyond sequence one, or its complement.boolean |
attempt_sequence | query | Optional | Select cycles containing this exact prompt-attempt sequence.integerFrom 1 to 12 |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Newest-first bounded cycle page; attempts are ordered by sequence.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonGET/v1/collection_cycles/{collection_cycle_id}Retrieve one collection cycle and its attempt evidence
This operation is defined by its request and response contract below.
- Operation ID
getCollectionCycle- Authentication
- OAuth2 (billing:read)
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
collection_cycle_id | path | Required | stringPattern ^cyc_[A-Za-z0-9]+$ |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Exact collection-cycle projection.application/json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonGET/v1/billing/collection_healthRead real collection conversion, recovery, and failure ownership
This operation is defined by its request and response contract below.
- Operation ID
getCollectionHealth- Authentication
- OAuth2 (billing:read)
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Environment-scoped collection-health snapshot.application/json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonGET/v1/billing/collection_policyRead the effective bounded collection policy
This operation is defined by its request and response contract below.
- Operation ID
getCollectionPolicy- Authentication
- OAuth2 (billing:read)
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Effective policy and immutable version.application/json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonPOST/v1/billing/collection_policyChanges settingsReplace the collection policy within server-enforced safety bounds
This operation is defined by its request and response contract below.
- Operation ID
updateCollectionPolicy- Authentication
- OAuth2 (billing:write)
- Safety class
- Configuration · changes settings
- Agent key
- Never
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
Idempotency-Key | header | Required | Stable opaque key for this semantic command. Reuse it after timeouts.string16–255 characters |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Request body Required
application/json · BillingCollectionPolicyUpdateResponses
200New effective policy version, or the exact idempotent replay.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json409Idempotency or lifecycle conflict.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonPOST/v1/test_clocksCreates or changes records · can't be undoneCreate the merchant's advance-only sandbox billing clock
This operation is defined by its request and response contract below.
- Operation ID
createBillingTestClock- Authentication
- OAuth2 (billing:write)
- Safety class
- Records · creates or changes a record · can't be undone
- Agent key
- Never
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
Idempotency-Key | header | Required | Stable opaque key for this semantic command. Reuse it after timeouts.string16–255 characters |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Request body Required
application/json · BillingTestClockCreateResponses
201The single sandbox billing clock was created.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json409Idempotency or lifecycle conflict.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonGET/v1/test_clocksList the merchant's sandbox billing clock
This operation is defined by its request and response contract below.
- Operation ID
listBillingTestClocks- Authentication
- OAuth2 (billing:read)
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Zero or one merchant-scoped clock.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonGET/v1/test_clocks/{test_clock_id}Retrieve the exact sandbox billing clock
This operation is defined by its request and response contract below.
- Operation ID
getBillingTestClock- Authentication
- OAuth2 (billing:read)
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
test_clock_id | path | Required | stringPattern ^bclock_[A-Za-z0-9]+$ |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Exact advance-only logical clock.application/json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonPOST/v1/test_clocks/{test_clock_id}/advanceCreates or changes records · can't be undoneAdvance sandbox billing time without changing security or lease time
This operation is defined by its request and response contract below.
- Operation ID
advanceBillingTestClock- Authentication
- OAuth2 (billing:write)
- Safety class
- Records · creates or changes a record · can't be undone
- Agent key
- Never
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
test_clock_id | path | Required | stringPattern ^bclock_[A-Za-z0-9]+$ |
Idempotency-Key | header | Required | Stable opaque key for this semantic command. Reuse it after timeouts.string16–255 characters |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Request body Required
application/json · BillingTestClockAdvanceResponses
200Clock advanced and a task-queue promotion pass was scheduled.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json409Idempotency or lifecycle conflict.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonPayment methods
3GET/v1/payment_methodsList eligible payment methods
This operation is defined by its request and response contract below.
- Operation ID
listPaymentMethods- Authentication
- OAuth2 (payment_methods:read)
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
currency | query | Required | stringPattern ^[A-Z]{3}$ |
amount | query | Required | integer · int64At least 1 |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Capability-, amount-, currency-, and health-scoped methods.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonGET/v1/payment_method_credentialsList stored cards
Cards payers saved with this merchant, as scheme, last four, expiry, and stored-credential eligibility. Revoked cards remain listed so a merchant can see what was detached; they are never chargeable. Nothing on this API can create a stored card, because creation is a consented capture inside the PerionPayments field frames.
- Operation ID
listPaymentMethodCredentials- Authentication
- OAuth2 (payment_methods:read)
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
customer | query | Optional | stringPattern ^cust_[A-Za-z0-9]+$ |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Stored cards, newest first, at most one hundred.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+jsonPOST/v1/payment_method_credentials/{payment_method_credential_id}/detachStops or removes · can't be undoneDetach a stored card
Retires a stored card so that no later charge, payer-present or scheduled, can name it. Idempotent by construction; a repeat returns the same retired card. The sealed account number behind it is purged by the cardholder-data environment on its own schedule.
- Operation ID
detachPaymentMethodCredential- Authentication
- OAuth2 (payment_methods:write)
- Safety class
- Destructive · stops or removes something · can't be undone
- Agent key
- Never
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
payment_method_credential_id | path | Required | stringPattern ^pm_[A-Za-z0-9]+$ |
Idempotency-Key | header | Required | Stable opaque key for this semantic command. Reuse it after timeouts.string16–255 characters |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200The retired stored card.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+jsonRefunds
3GET/v1/refundsList refunds
This operation is defined by its request and response contract below.
- Operation ID
listRefunds- Authentication
- OAuth2 (refunds:read)
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
limit | query | Optional | integerFrom 1 to 100 · Default 20 |
starting_after | query | Optional | string |
payment_intent | query | Optional | stringPattern ^pi_[A-Za-z0-9]+$ |
status | query | Optional | stringOne of pending, processing, succeeded, failed |
currency | query | Optional | stringPattern ^[A-Z]{3}$ |
settlement_evidence | query | Optional | stringOne of none, provider_response_only, provider_file_confirmed, bank_confirmed, provider_query_confirmed |
merchant_reference | query | Optional | stringUp to 128 characters |
api_client | query | Optional | Only what this API client created (`cl_…`). An id that is not one of this merchant's clients in this environment matches nothing.stringUp to 128 characters · Pattern ^cl_[A-Za-z0-9]+$ |
search_reference | query | Optional | Exact match on this refund’s reference or its parent payment’s reference. The parent must belong to the same merchant, environment, cell, legal entity and currency. Other supplied filters still apply. Matching is case-sensitive; prefixes and substrings are not searched.string1–128 characters |
created[gte] | query | Optional | Inclusive RFC 3339 lower bound.string · date-time |
created[lte] | query | Optional | Inclusive RFC 3339 upper bound.string · date-time |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Newest-first merchant-scoped refund page.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonPOST/v1/refundsMoves money · can't be undoneCreate a full or partial refund
Reserves captured value once and dispatches the reversal on the original payment rail. Send an `Idempotency-Key`: an exact retry returns the first refund instead of reserving the value again. Omit `amount` to refund everything captured and not already reserved. A provider acceptance leaves the refund processing until provider-file or bank evidence confirms settlement; the payer is not asked to approve a refund.
- One key, one movement of money. Retry it only with the same
Idempotency-Keyand body; a new key starts a new movement of money.
- Operation ID
createRefund- Authentication
- OAuth2 (refunds:write)
- Safety class
- Moves money · no payer approves it · can't be undone
- Agent key
- Only when
allowed_operationslistsrefunds:create
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
Idempotency-Key | header | Required unless previewing | Stable opaque key for this semantic command. Reuse it after timeouts. Required for every request except a preview (`Perion-Preview: true`), which claims nothing.string16–255 characters |
Perion-Preview | header | Optional | `true` previews the request instead of sending it. Every admission check
that needs no write runs -- your client's limits (per payment, per refund
and per day, and how many payers it may prompt), the order and reference
guards, the payment method's eligibility, and the one-prompt-per-payer
rule -- and the answer is a Preview:
what the request would do, who decides whether money moves, whether it can
be undone, its limits, and the exact problems it would be refused with.
Nothing is created or claimed, no provider is called and nothing reaches a
payer's phone. Show the preview to whoever decides, then send the request
without the header.
stringOne of true, false |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
X-Request-Id | header | Optional | stringUp to 128 characters |
Request body Required
application/json · RefundCreateResponses
200A preview, answered because the request sent `Perion-Preview: true`. Nothing was created, reserved or sent, and no provider or phone was reached.application/json201Refund committed; inspect status and settlement evidence separately.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json409Idempotency or lifecycle conflict.application/problem+json422The request is well formed, but a limit the merchant set refuses it before anything is created or charged. `api_client_policy_amount_exceeded` means the amount is above this API client's per-payment limit for the currency, or the client's policy lists no limit for that currency; `limit` names it. Use an amount within the limit; do not split one order into several payments to pass it. `api_client_policy_refund_limit_exceeded` means a refund is above the client's per-refund limit, past what it may refund today, or on a payment it did not create; `limit` names the bound and `remaining_today` what is left. Refunds go out with no customer approval: stop and tell the merchant rather than trying smaller amounts.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+json503Dependency or rail is unavailable; retry safely where documented.application/problem+jsonGET/v1/refunds/{refund_id}Retrieve a refund
Returns a refund's operational `status` and, separately, its `settlement_evidence`. A platform refund is complete for accounting only when the evidence reaches `provider_file_confirmed` or `bank_confirmed`; a provider acceptance alone is `provider_response_only`.
- Operation ID
getRefund- Authentication
- OAuth2 (refunds:read)
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
refund_id | path | Required | stringPattern ^re_[A-Za-z0-9]+$ |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Current refund and its strongest settlement evidence.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonBalances
1GET/v1/balancesList merchant balance projections
Reads ledger projections; it never creates a competing money record.
- Operation ID
listBalances- Authentication
- OAuth2 (balances:read)
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
currency | query | Optional | stringPattern ^[A-Z]{3}$ |
paid_directly[gte] | query | Optional | Inclusive start of the window for paid_directly totals only. Ledger balances are always current and are not filtered.string · date-time |
paid_directly[lte] | query | Optional | Inclusive end of the window for paid_directly totals only. It must not precede paid_directly[gte].string · date-time |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200One projection per ledger book and currency.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonSettlements
5GET/v1/settlementsList scheduled merchant settlement batches
This operation is defined by its request and response contract below.
- Operation ID
listSettlements- Authentication
- OAuth2 (settlements:read)
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
limit | query | Optional | integerFrom 1 to 100 · Default 20 |
starting_after | query | Optional | string |
status | query | Optional | stringOne of pending_approval, approved, dispatched, evidence_pending, confirmed, failed, returned |
currency | query | Optional | stringPattern ^[A-Z]{3}$ |
search_reference | query | Optional | Exact match on a payment reference included in this batch. The related payment must belong to the same merchant, environment, cell, legal entity and currency. A batch appears only once. Other supplied filters still apply. Matching is case-sensitive; prefixes and substrings are not searched.string1–128 characters |
created[gte] | query | Optional | Inclusive RFC 3339 lower bound.string · date-time |
created[lte] | query | Optional | Inclusive RFC 3339 upper bound.string · date-time |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Newest-first merchant-scoped settlement batches.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonGET/v1/settlements/{settlement_batch_id}Retrieve settlement and bank-evidence state
This operation is defined by its request and response contract below.
- Operation ID
getSettlement- Authentication
- OAuth2 (settlements:read)
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
settlement_batch_id | path | Required | stringPattern ^se_[A-Za-z0-9]+$ |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Current immutable composition, merchant-safe manifest rows, and evidence projection.application/json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonGET/v1/settlements/{settlement_batch_id}/statementDownload the deterministic ledger-backed settlement statement
This operation is defined by its request and response contract below.
- Operation ID
downloadSettlementStatement- Authentication
- OAuth2 (settlements:read)
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
settlement_batch_id | path | Required | stringPattern ^se_[A-Za-z0-9]+$ |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200RFC 4180 activity detail using the immutable stmt_v1 columns.text/csv401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json409Idempotency or lifecycle conflict.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonGET/v1/books/daily_closes/{business_date}Read one exact merchant daily-close artifact
Returns one repeatable-read, currency-separated ledger statement and close checks. A missing dimension is never represented as zero.
- Operation ID
getMerchantDailyClose- Authentication
- OAuth2 (settlements:read)
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
business_date | path | Required | string · date |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200The ledger-backed daily-close artifact for the requested Africa/Harare business date.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonGET/v1/books/daily_closes/{business_date}/statementDownload the checksummed merchant daily-close statement
This operation is defined by its request and response contract below.
- Operation ID
downloadMerchantDailyCloseStatement- Authentication
- OAuth2 (settlements:read)
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
business_date | path | Required | string · date |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200RFC 4180 merchant-account entries carrying the merchant_daily_close_v1 version.text/csv400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonReconciliation
2GET/v1/reconciliation/exceptionsList merchant reconciliation exceptions
Returns the enterprise merchant-safe projection only. Raw provider rows, retained evidence payloads, journal identifiers, and operator notes are never exposed. Resolution remains an evidence-backed operator workflow. Continuations are bound to the complete selected-set revision and exact merchant filters. A changed set returns reconciliation_list_changed; refresh without starting_after. Cursors do not preserve historical rows.
- Operation ID
listReconciliationExceptions- Authentication
- OAuth2 (reconciliation:read) + MutualTLS
- Safety class
- Read · changes nothing
- Agent key
- Never
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
limit | query | Optional | integerFrom 1 to 100 · Default 20 |
starting_after | query | Optional | string |
status | query | Optional | stringOne of unresolved, open, investigating, pending_approval, resolved |
class | query | Optional | stringOne of internal_success_missing_from_provider, provider_success_missing_internally, bank_settlement_missing, amount_currency_mismatch, fee_levy_mismatch, duplicate_provider_record, post_success_reversal, refund_unsettled, misdirected_settlement, timing_difference, corrupt_file, bank_settlement_returned |
severity | query | Optional | stringOne of low, medium, high, critical |
settlement_batch | query | Optional | Exact settlement pivot used by the settlement evidence view.stringPattern ^se_[A-Za-z0-9]+$ |
created[gte] | query | Optional | Inclusive RFC 3339 lower bound.string · date-time |
created[lte] | query | Optional | Inclusive RFC 3339 upper bound.string · date-time |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Newest-first tenant and environment scoped exception page with a full-filter summary.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json409The selected reconciliation set changed. Code reconciliation_list_changed requires a fresh first page with the same filters; no continuation records are returned.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonGET/v1/reconciliation/exceptions/{reconciliation_exception_id}Retrieve one merchant reconciliation exception
This operation is defined by its request and response contract below.
- Operation ID
getReconciliationException- Authentication
- OAuth2 (reconciliation:read) + MutualTLS
- Safety class
- Read · changes nothing
- Agent key
- Never
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
reconciliation_exception_id | path | Required | stringPattern ^rex_[A-Za-z0-9]+$ |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Exact merchant-safe exception state and related public financial objects.application/json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonExports
5GET/v1/export_jobsList governed export jobs
This operation is defined by its request and response contract below.
- Operation ID
listExportJobs- Authentication
- OAuth2 (exports:read)
- Safety class
- Read · changes nothing
- Agent key
- Never
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
limit | query | Optional | integerFrom 1 to 100 · Default 20 |
starting_after | query | Optional | string |
report | query | Optional | stringOne of payments, refunds, settlements, fees, performance |
status | query | Optional | stringOne of active, queued, processing, ready, failed, expired |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Newest-first merchant and environment scoped export jobs.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonPOST/v1/export_jobsQueue a governed CSV export
Freezes a bounded report scope and audit reason, then generates asynchronously. Marked sample rows are excluded unless explicitly included. Within a schema version columns are only appended on the right: `payments_v1` ends with `payer_reference`, `created_by_id` and `created_by_name`, and `refunds_v1` with `created_by_id` and `created_by_name`; the creator columns are blank when a person, the checkout or PerionPayments made the row.
- Operation ID
createExportJob- Authentication
- OAuth2 (exports:write)
- Safety class
- Read · changes nothing
- Agent key
- Never
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
Idempotency-Key | header | Required | Stable opaque key for this semantic command. Reuse it after timeouts.string16–255 characters |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Request body Required
application/json · ExportJobCreateResponses
202Durable export job accepted for asynchronous generation.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json409Idempotency or lifecycle conflict.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonGET/v1/export_jobs/{export_job_id}Retrieve one governed export job
This operation is defined by its request and response contract below.
- Operation ID
getExportJob- Authentication
- OAuth2 (exports:read)
- Safety class
- Read · changes nothing
- Agent key
- Never
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
export_job_id | path | Required | stringPattern ^exj_[A-Za-z0-9]+$ |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Exact immutable-scope export projection.application/json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonPOST/v1/export_jobs/{export_job_id}/download_sessionsMint a short-lived one-use export download
This operation is defined by its request and response contract below.
- Operation ID
createExportDownloadSession- Authentication
- OAuth2 (exports:read)
- Safety class
- Read · changes nothing
- Agent key
- Never
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
export_job_id | path | Required | stringPattern ^exj_[A-Za-z0-9]+$ |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
201One-use download URL; bearer authorization remains required.application/json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json409Idempotency or lifecycle conflict.application/problem+json410The retained artifact has expired.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonGET/v1/export_jobs/{export_job_id}/downloadConsume a one-use governed export download
This operation is defined by its request and response contract below.
- Operation ID
downloadExport- Authentication
- OAuth2 (exports:read)
- Safety class
- Read · changes nothing
- Agent key
- Never
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
export_job_id | path | Required | stringPattern ^exj_[A-Za-z0-9]+$ |
token | query | Required | Opaque one-use token returned by the download-session endpoint; only its SHA-256 hash is retained.stringPattern ^dlt_[A-Za-z0-9]+$ |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200RFC 4180 CSV matching the job's immutable schema version and checksum.text/csv400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json409Idempotency or lifecycle conflict.application/problem+json410The artifact or one-use token is no longer usable.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonPayment links
4POST/v1/payment_linksAsks the payerCreate a fixed-amount payment link
Creates a shareable fixed-amount link. Every payer who opens it gets their own checkout and approves their own payment; creating or sharing a link moves no money. A single-use link closes after its first successful payment. The issuing API client's per-payment limit, if it has one, applies to the link's amount.
- Asks the payer. Nothing completes until the payer approves it on their own phone or payment page. The response is not proof of payment.
- Operation ID
createPaymentLink- Authentication
- OAuth2 (payment_links:write)
- Safety class
- Request · nothing completes until the payer approves
- Agent key
- Only when
allowed_operationslistspayment_links:create
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
Idempotency-Key | header | Required unless previewing | Stable opaque key for this semantic command. Reuse it after timeouts. Required for every request except a preview (`Perion-Preview: true`), which claims nothing.string16–255 characters |
Perion-Preview | header | Optional | `true` previews the request instead of sending it. Every admission check
that needs no write runs -- your client's limits (per payment, per refund
and per day, and how many payers it may prompt), the order and reference
guards, the payment method's eligibility, and the one-prompt-per-payer
rule -- and the answer is a Preview:
what the request would do, who decides whether money moves, whether it can
be undone, its limits, and the exact problems it would be refused with.
Nothing is created or claimed, no provider is called and nothing reaches a
payer's phone. Show the preview to whoever decides, then send the request
without the header.
stringOne of true, false |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Request body Required
application/json · PaymentLinkCreateResponses
200A preview, answered because the request sent `Perion-Preview: true`. Nothing was created, reserved or sent, and no provider or phone was reached.application/json201Shareable fixed-amount link.application/json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json409Idempotency or lifecycle conflict.application/problem+json422The request is well formed, but a limit the merchant set refuses it before anything is created or charged. `api_client_policy_amount_exceeded` means the amount is above this API client's per-payment limit for the currency, or the client's policy lists no limit for that currency; `limit` names it. Use an amount within the limit; do not split one order into several payments to pass it. `api_client_policy_refund_limit_exceeded` means a refund is above the client's per-refund limit, past what it may refund today, or on a payment it did not create; `limit` names the bound and `remaining_today` what is left. Refunds go out with no customer approval: stop and tell the merchant rather than trying smaller amounts.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonGET/v1/payment_linksList payment links
This operation is defined by its request and response contract below.
- Operation ID
listPaymentLinks- Authentication
- OAuth2 (payment_links:read)
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
limit | query | Optional | integerFrom 1 to 100 · Default 20 |
starting_after | query | Optional | string |
status | query | Optional | stringOne of active, consumed, deactivated, expired |
currency | query | Optional | stringPattern ^[A-Z]{3}$ |
merchant_reference | query | Optional | Exact merchant reference of the link.stringUp to 128 characters |
created[gte] | query | Optional | Inclusive RFC 3339 lower bound.string · date-time |
created[lte] | query | Optional | Inclusive RFC 3339 upper bound.string · date-time |
amount[gte] | query | Optional | integer · int64At least 1 |
amount[lte] | query | Optional | integer · int64At least 1 |
api_client | query | Optional | Only what this API client created (`cl_…`). An id that is not one of this merchant's clients in this environment matches nothing.stringUp to 128 characters · Pattern ^cl_[A-Za-z0-9]+$ |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Newest-first payment-link page.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonGET/v1/payment_links/{payment_link_id}Retrieve a payment link
This operation is defined by its request and response contract below.
- Operation ID
getPaymentLink- Authentication
- OAuth2 (payment_links:read)
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
payment_link_id | path | Required | stringPattern ^pl_[A-Za-z0-9]+$ |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Payment-link projection.application/json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonPOST/v1/payment_links/{payment_link_id}/deactivateStops or removes · can't be undoneStop new sessions from a payment link
This operation is defined by its request and response contract below.
- Operation ID
deactivatePaymentLink- Authentication
- OAuth2 (payment_links:write)
- Safety class
- Destructive · stops or removes something · can't be undone
- Agent key
- Only when
allowed_operationslistspayment_links:deactivate
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
payment_link_id | path | Required | stringPattern ^pl_[A-Za-z0-9]+$ |
Idempotency-Key | header | Required | Stable opaque key for this semantic command. Reuse it after timeouts.string16–255 characters |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Request body Optional
Optional reason recorded in the audit trail. Omit the body for legacy clients; retries must preserve the same normalized reason.
application/json · PaymentLinkDeactivateResponses
200Deactivated link; existing attempts continue to resolve.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json409Idempotency or lifecycle conflict.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonPublic checkout
15POST/public/v1/continuations/claimResume a checkout or payment link from a short capability code
Resolves the code without placing it in a URL or loggable query string. A checkout continuation returns the reveal-on-claim browser credential with no-store headers; a payment-link continuation returns the effect-free landing. The operation never creates, confirms, retries, or dispatches a payment.
- Operation ID
claimPublicContinuation- Authentication
- No authentication requirement is declared.
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Request body Required
application/jsonResponses
200Exact payer-safe target state and the capability needed to continue it.application/json400Request validation failed.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json429Rate limit exceeded; honor Retry-After.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+json503Dependency or rail is unavailable; retry safely where documented.application/problem+jsonPOST/public/v1/continuations/sms_status_claimsCreates or changes records · can't be undoneExercise the normalized sandbox inbound-SMS status claim
Queues an encrypted transactional SMS reply through the ordinary notification worker. This public conformance route resolves sandbox targets only. A live inbound SMS provider adapter remains transport-gated and invokes the same application command after provider authentication.
- Operation ID
claimSandboxSMSContinuationStatus- Authentication
- No authentication requirement is declared.
- Safety class
- Records · creates or changes a record · can't be undone
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
Idempotency-Key | header | Required | Stable opaque key for this semantic command. Reuse it after timeouts.string16–255 characters |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Request body Required
application/jsonResponses
202Idempotent status reply queued against the exact sandbox target.application/json400Request validation failed.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json429Rate limit exceeded; honor Retry-After.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+json503Dependency or rail is unavailable; retry safely where documented.application/problem+jsonGET/public/v1/payment_links/{payment_link_id}Resolve a public payment-link landing
Returns only payer-safe merchant and amount context. It never exposes merchant metadata.
- Operation ID
resolvePublicPaymentLink- Authentication
- No authentication requirement is declared.
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
payment_link_id | path | Required | stringPattern ^pl_[A-Za-z0-9]+$ |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Payer-safe payment-link landing.application/json404Resource is absent or belongs to another merchant.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+json503Dependency or rail is unavailable; retry safely where documented.application/problem+jsonGET/l/{payment_link_id}Open the payer-safe checkout shell for a payment link
Renders semantic HTML with the current merchant, amount, environment, and verification host. Reading this shell never authorizes fulfillment or initiates a payment; interactive state is hydrated only through the capability-protected public checkout API.
- Operation ID
getPublicPaymentLinkCheckoutPage- Authentication
- No authentication requirement is declared.
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
payment_link_id | path | Required | stringPattern ^pl_[A-Za-z0-9]+$ |
Responses
200Payer-safe checkout shell HTML for an active payment link.text/html404Generic HTML page for an unknown, inactive, or scope-mismatched link.text/html429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+json503Generic HTML page shown while payment-link truth is unavailable.text/htmlGET/p/{payment_link_ids}View up to twelve explicit payment links from one merchant
Composes a current script-free page from explicit link capabilities. It never creates a catalogue object, blends merchants or environments, or revives an inactive link. An optional collection title travels with the share URL as plain text; it never replaces the verified merchant, per-item amount, currency or checkout destination.
- Operation ID
getPaymentLinkPage- Authentication
- No authentication requirement is declared.
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
payment_link_ids | path | Required | One to twelve explicit payment-link capabilities separated by tildes.stringUp to 1536 characters · Pattern ^pl_[A-Za-z0-9]+(?:~pl_[A-Za-z0-9]+){0,11}$ |
title | query | Optional | Optional plain-text collection title, trimmed to 1–80 Unicode characters, without controls or bidirectional overrides. Duplicate titles are rejected. The title is a share label, not authenticated merchant identity.string1–80 characters |
Responses
200Script-free composed payment page HTML.text/html400Generic HTML page when the collection title is invalid.text/html404Generic HTML page when no valid same-merchant link remains.text/html429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+json503Generic HTML page shown while payment-link truth is unavailable.text/htmlPOST/public/v1/payment_links/{payment_link_id}/checkout_sessionsAsks the payerBegin an isolated checkout from a payment link
Creates exactly one intent and checkout session. Store the returned client_secret only in transient browser state and send it with the PerionCheckout authorization scheme.
- Asks the payer. Nothing completes until the payer approves it on their own phone or payment page. The response is not proof of payment.
- Operation ID
claimPublicPaymentLink- Authentication
- No authentication requirement is declared.
- Safety class
- Request · nothing completes until the payer approves
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
payment_link_id | path | Required | stringPattern ^pl_[A-Za-z0-9]+$ |
Idempotency-Key | header | Required | Stable opaque key for this semantic command. Reuse it after timeouts.string16–255 characters |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
X-Request-Id | header | Optional | stringUp to 128 characters |
Responses
201Checkout created. Reusing the same semantic command returns the exact committed response.application/json400Request validation failed.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json409Idempotency or lifecycle conflict.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+json503Dependency or rail is unavailable; retry safely where documented.application/problem+jsonGET/public/v1/checkout_sessions/{checkout_session_id}Retrieve payer-safe checkout state
A reduced projection without merchant metadata, merchant references, or merchant callback URLs.
- Operation ID
getPublicCheckoutSession- Authentication
- CheckoutCapability
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
checkout_session_id | path | Required | stringPattern ^cs_[A-Za-z0-9]+$ |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Perion-Embed-Origin | header | Optional | Canonical parent origin observed by the PerionPayments embedded checkout
frame. Official SDK integrations send this automatically; hosted checkout
clients omit it. A mismatch is rejected as an invalid checkout capability.
stringUp to 512 characters · Pattern ^https?://[^/?#@\s]+$ |
Responses
200Current checkout and authoritative payment evidence.application/json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json409Idempotency or lifecycle conflict.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+json503Dependency or rail is unavailable; retry safely where documented.application/problem+jsonGET/s/{checkout_session_id}Open the payer-safe checkout shell for a checkout session
Renders semantic HTML with the current merchant, amount, environment, and verification host. Reading this shell never authorizes fulfillment or initiates a payment; authoritative payment state is hydrated only through the checkout-capability API.
- Operation ID
getPublicCheckoutSessionPage- Authentication
- No authentication requirement is declared.
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
checkout_session_id | path | Required | stringPattern ^cs_[A-Za-z0-9]+$ |
Responses
200Payer-safe checkout shell HTML for the current checkout session.text/html404Generic HTML page for an unknown or scope-mismatched checkout session.text/html429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+json503Generic HTML page shown while checkout truth is unavailable.text/htmlGET/s/{checkout_session_id}/pay/{attempt_id}Hand a payer to the acquirer's hosted card page
Opened from a hosted card payment's redirect_to_url next action. The signed link is verified before anything is read; the page then posts the acquirer's form or renders the acquirer's own payment widget for the payment the platform recorded. Card details are typed only on the acquirer's page and never reach this page or the platform. A payment that no longer waits for its payer is never handed to the acquirer again. Reading this page moves no money.
- Operation ID
getHostedCardLaunchPage- Authentication
- No authentication requirement is declared.
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
checkout_session_id | path | Required | stringPattern ^cs_[A-Za-z0-9]+$ |
attempt_id | path | Required | The payment attempt the hosted card page belongs to.stringPattern ^pa_[A-Za-z0-9]{8,64}$ |
e | query | Required | When the signed hosted card link expires, in Unix seconds.integer · int64At least 1 |
t | query | Required | The signature that binds the link to its checkout session, attempt, page and expiry.stringPattern ^[A-Za-z0-9_-]{43}$ |
Responses
200Payer-safe HTML that hands the payer to the acquirer, or explains that the payment page is closed.text/html404Generic HTML page for an incomplete, altered or foreign link.text/html429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+json503Generic HTML page shown while the hosted card page cannot be prepared. No payment was started from it.text/htmlGET/s/{checkout_session_id}/pay/{attempt_id}/returnReturn a payer from the acquirer's hosted card page
Where the acquirer sends the payer back after its card page. Nothing the browser carries is read as a payment result: the return asks for an immediate status query to the acquirer and sends the payer on to the merchant's return URL. The payment's outcome arrives through the payment's own events and the checkout-capability API.
- Operation ID
returnFromHostedCardPage- Authentication
- No authentication requirement is declared.
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
checkout_session_id | path | Required | stringPattern ^cs_[A-Za-z0-9]+$ |
attempt_id | path | Required | The payment attempt the hosted card page belongs to.stringPattern ^pa_[A-Za-z0-9]{8,64}$ |
e | query | Required | When the signed hosted card link expires, in Unix seconds.integer · int64At least 1 |
t | query | Required | The signature that binds the link to its checkout session, attempt, page and expiry.stringPattern ^[A-Za-z0-9_-]{43}$ |
Responses
303The payer is sent to the merchant's return URL.404Generic HTML page for an incomplete, altered or foreign link.text/html429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonPOST/s/{checkout_session_id}/pay/{attempt_id}/returnReturn a payer from an acquirer that posts its result back
The same return for acquirers whose card page posts a form back. The posted fields are never read as a payment result.
- Operation ID
postReturnFromHostedCardPage- Authentication
- No authentication requirement is declared.
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
checkout_session_id | path | Required | stringPattern ^cs_[A-Za-z0-9]+$ |
attempt_id | path | Required | The payment attempt the hosted card page belongs to.stringPattern ^pa_[A-Za-z0-9]{8,64}$ |
e | query | Required | When the signed hosted card link expires, in Unix seconds.integer · int64At least 1 |
t | query | Required | The signature that binds the link to its checkout session, attempt, page and expiry.stringPattern ^[A-Za-z0-9_-]{43}$ |
Responses
303The payer is sent to the merchant's return URL.404Generic HTML page for an incomplete, altered or foreign link.text/html429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonGET/public/v1/checkout_sessions/{checkout_session_id}/saved_cardsList cards explicitly delegated to this checkout
Returns only the merchant-delegated card choices after checkout capability, origin, scope and lifecycle checks. Customer recognition and public payment links create no delegation. No query filters are accepted. Revoked or expired grants return no card metadata. Selection references cannot be used on another checkout or the merchant card API.
- Operation ID
listPublicCheckoutSavedCards- Authentication
- CheckoutCapability
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
checkout_session_id | path | Required | stringPattern ^cs_[A-Za-z0-9]+$ |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Perion-Embed-Origin | header | Optional | Canonical parent origin observed by the PerionPayments embedded checkout
frame. Official SDK integrations send this automatically; hosted checkout
clients omit it. A mismatch is rejected as an invalid checkout capability.
stringUp to 512 characters · Pattern ^https?://[^/?#@\s]+$ |
Responses
200Current narrow card choices; always no-store.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json409Idempotency or lifecycle conflict.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+json503Dependency or rail is unavailable; retry safely where documented.application/problem+jsonGET/public/v1/checkout_sessions/{checkout_session_id}/payment_methodsList currently eligible checkout methods
Re-evaluates merchant capability, amount, currency, rail health, and session allowlists server side.
- Operation ID
listPublicCheckoutPaymentMethods- Authentication
- CheckoutCapability
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
checkout_session_id | path | Required | stringPattern ^cs_[A-Za-z0-9]+$ |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Perion-Embed-Origin | header | Optional | Canonical parent origin observed by the PerionPayments embedded checkout
frame. Official SDK integrations send this automatically; hosted checkout
clients omit it. A mismatch is rejected as an invalid checkout capability.
stringUp to 512 characters · Pattern ^https?://[^/?#@\s]+$ |
Responses
200Methods eligible at request time.application/json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json409Idempotency or lifecycle conflict.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+json503Dependency or rail is unavailable; retry safely where documented.application/problem+jsonPOST/public/v1/checkout_sessions/{checkout_session_id}/confirmAsks the payer · a prompt already sent can't be recalledConfirm the checkout payment
Rechecks eligibility and preserves the merchant-authorized return URL. If the outcome is processing or unknown, retrieve this same checkout and do not pay again.
- Asks the payer. Nothing completes until the payer approves it on their own phone or payment page. The response is not proof of payment.
- One key, one movement of money. Retry it only with the same
Idempotency-Keyand body; a new key starts a new movement of money.
- Operation ID
confirmPublicCheckoutSession- Authentication
- CheckoutCapability
- Safety class
- Request · nothing completes until the payer approves · a prompt already sent can't be recalled
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
checkout_session_id | path | Required | stringPattern ^cs_[A-Za-z0-9]+$ |
Idempotency-Key | header | Required | Stable opaque key for this semantic command. Reuse it after timeouts.string16–255 characters |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
X-Request-Id | header | Optional | stringUp to 128 characters |
Perion-Embed-Origin | header | Optional | Canonical parent origin observed by the PerionPayments embedded checkout
frame. Official SDK integrations send this automatically; hosted checkout
clients omit it. A mismatch is rejected as an invalid checkout capability.
stringUp to 512 characters · Pattern ^https?://[^/?#@\s]+$ |
Perion-Payer-Agent | header | Optional | Optional attribution for a payer's personal assistant confirming this
checkout for the person: `<name>` or `<name>; url=<https URL>`. The
merchant's timeline shows "Started by the customer's assistant (name)". It
is a declaration that grants nothing: the payer still approves on their own
phone or enters their own card on the payment page.
stringUp to 400 characters |
Request body Required
application/json · PublicCheckoutConfirmResponses
200Confirmation committed; inspect the nested payment intent and next action.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json409Idempotency or lifecycle conflict.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+json503Dependency or rail is unavailable; retry safely where documented.application/problem+jsonPublic presentation
1GET/assets/fonts/{font_name}Retrieve a reviewed payer-surface font
Serves one of the two immutable Latin WOFF2 subsets embedded in the API binary for script-free payer surfaces. Unknown names return a generic not-found response; this is not a general asset or filesystem endpoint.
- Operation ID
getPayerSurfaceFont- Authentication
- No authentication requirement is declared.
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
font_name | path | Required | stringOne of inter-latin-wght-normal.woff2, bricolage-grotesque-latin-600-normal.woff2 |
Responses
200Immutable same-origin WOFF2 font bytes.font/woff2304The caller already holds the exact immutable font.404The requested name is outside the closed font vocabulary.text/plainPublic receipts
2GET/public/v1/receipts/{receipt_id}Retrieve a forward-safe payment receipt
Resolves an opaque receipt capability into authoritative payment and refund evidence. The projection excludes payer contacts, provider references, internal identifiers, descriptions, and merchant metadata. Anyone holding the URL can view this narrow receipt.
- Operation ID
getPublicReceipt- Authentication
- No authentication requirement is declared.
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
receipt_id | path | Required | stringPattern ^rcpt_[A-Za-z0-9]{16,128}$ |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Forward-safe payment receipt with evidence-qualified refund history.application/json404Resource is absent or belongs to another merchant.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+json503Dependency or rail is unavailable; retry safely where documented.application/problem+jsonGET/r/{receipt_id}Read and print a forward-safe payment receipt
Renders the same minimized receipt projection as semantic HTML. The page has no JavaScript or third-party resource dependency, is excluded from indexing, and cannot initiate or mutate a payment. Unknown and malformed capabilities share one generic page.
- Operation ID
getPublicReceiptPage- Authentication
- No authentication requirement is declared.
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
receipt_id | path | Required | stringPattern ^rcpt_[A-Za-z0-9]{16,128}$ |
Responses
200Script-free, print-safe receipt HTML.text/html404Generic HTML page for an unknown, malformed, or never-issued capability.text/html429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+json503Generic HTML page shown while authoritative receipt truth is unavailable.text/htmlPublic billing portal
10GET/public/v1/billing_portal/{billing_portal_token}Resolve one payer's recurring agreement through an opaque capability
This operation is defined by its request and response contract below.
- Operation ID
getBillingPortal- Authentication
- No authentication requirement is declared.
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
billing_portal_token | path | Required | Opaque bearer capability delivered only to the payer; clients must not log it.stringPattern ^bpt_[A-Za-z0-9]+$ |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Capability-minimized agreement, subscription, plan, controls, and cycle history.application/json404Resource is absent or belongs to another merchant.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonPOST/public/v1/billing_portal/{billing_portal_token}/{billing_portal_action}Stops or removes · can't be undonePause, resume, or cancel the capability-bound agreement
This operation is defined by its request and response contract below.
- Operation ID
mutateBillingPortal- Authentication
- No authentication requirement is declared.
- Safety class
- Destructive · stops or removes something · can't be undone
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
billing_portal_token | path | Required | Opaque bearer capability delivered only to the payer; clients must not log it.stringPattern ^bpt_[A-Za-z0-9]+$ |
billing_portal_action | path | Required | stringOne of pause, resume, cancel |
Idempotency-Key | header | Required | Stable opaque key for this semantic command. Reuse it after timeouts.string16–255 characters |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Exact post-command portal state, or its byte-identical idempotent replay.application/json400Request validation failed.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json409Idempotency or lifecycle conflict.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonGET/billing/p/{billing_portal_token}View a capability-bound billing portal without JavaScript
Renders the minimized agreement, collection history, and currently valid payer controls as semantic HTML. The page sets no cookies, loads no third-party resources, is excluded from indexing, and never treats navigation as a payment event.
- Operation ID
getBillingPortalPage- Authentication
- No authentication requirement is declared.
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
billing_portal_token | path | Required | Opaque bearer capability delivered only to the payer; clients must not log it.stringPattern ^bpt_[A-Za-z0-9]+$ |
Responses
200Script-free, private billing portal HTML.text/html404Generic HTML page for an unknown, malformed, expired, or inactive capability.text/html429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+json503Generic HTML page shown while authoritative billing truth is unavailable.text/htmlGET/billing/p/{billing_portal_token}/invoices/{invoice_id}View one retained capability-bound invoice without JavaScript
Renders a printable, non-payable invoice from the retained portal history. The invoice identifier is not authority by itself; the opaque billing portal capability must resolve to the same agreement and invoice.
- Operation ID
getBillingInvoicePage- Authentication
- No authentication requirement is declared.
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
billing_portal_token | path | Required | Opaque bearer capability delivered only to the payer; clients must not log it.stringPattern ^bpt_[A-Za-z0-9]+$ |
invoice_id | path | Required | stringPattern ^inv_[A-Za-z0-9]+$ |
Responses
200Script-free printable invoice HTML.text/html404Generic HTML page for an unavailable capability or invoice.text/html429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+json503Generic HTML page shown while authoritative billing truth is unavailable.text/htmlPOST/billing/p/{billing_portal_token}/{billing_portal_action}Stops or removes · can't be undonePause, resume, or cancel from the script-free billing portal
Executes the same capability-bound command as the JSON endpoint using a deterministic hidden idempotency key, then redirects to the current portal state.
- Operation ID
mutateBillingPortalPage- Authentication
- No authentication requirement is declared.
- Safety class
- Destructive · stops or removes something · can't be undone
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
billing_portal_token | path | Required | Opaque bearer capability delivered only to the payer; clients must not log it.stringPattern ^bpt_[A-Za-z0-9]+$ |
billing_portal_action | path | Required | stringOne of pause, resume, cancel |
Request body Required
application/x-www-form-urlencodedResponses
303Command completed or safely conflicted; retrieve the current portal state.400Generic HTML page for an unreadable form command.text/html404Generic HTML page for an unavailable capability or action.text/html429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+json503Generic HTML page shown while authoritative billing truth is unavailable.text/htmlGET/billing/p/{billing_portal_token}/numberStart a payer-only change of the paying mobile number
Script-free form for the payer to enter a replacement mobile number. Only the payer can change the number, through this capability; merchants have no command. Shows why a change cannot start when one is already waiting or a payment is still being confirmed.
- Operation ID
getBillingPortalSourcePage- Authentication
- No authentication requirement is declared.
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
billing_portal_token | path | Required | Opaque bearer capability delivered only to the payer; clients must not log it.stringPattern ^bpt_[A-Za-z0-9]+$ |
Responses
200Script-free number-entry or explanation HTML.text/html404Generic HTML page for an unavailable capability.text/html429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+json503Generic HTML page shown while authoritative billing truth is unavailable.text/htmlPOST/billing/p/{billing_portal_token}/number/reviewReview exactly what a payment-number change does
Validates the number and shows which payment prompts it (the oldest open collectible invoice now, or the next scheduled collection), its amount and time. The plan amount and schedule are unchanged and nothing switches until that prompt succeeds. Records nothing.
- Operation ID
reviewBillingPortalSource- Authentication
- No authentication requirement is declared.
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
billing_portal_token | path | Required | Opaque bearer capability delivered only to the payer; clients must not log it.stringPattern ^bpt_[A-Za-z0-9]+$ |
Request body Required
application/x-www-form-urlencodedResponses
200Script-free review HTML with the confirmation form.text/html303The reviewed plan changed; retrieve the current portal state.404Generic HTML page for an unavailable capability.text/html409HTML explaining why no change can start now.text/html422HTML form with the number marked invalid.text/html429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+json503Generic HTML page shown while authoritative billing truth is unavailable.text/htmlPOST/billing/p/{billing_portal_token}/number/confirmAsks the payer · a prompt already sent can't be recalledConfirm a payer-only payment-number change
Records the reviewed change once under a deterministic hidden idempotency key; an exact retry replays it. The new number is sealed. The switch happens only after the approval prompt on the new number succeeds; a failed or expired prompt changes nothing and an unknown outcome keeps it waiting.
- Asks the payer. Nothing completes until the payer approves it on their own phone or payment page. The response is not proof of payment.
- One key, one movement of money. Retry it only with the same
Idempotency-Keyand body; a new key starts a new movement of money.
- Operation ID
confirmBillingPortalSource- Authentication
- No authentication requirement is declared.
- Safety class
- Request · nothing completes until the payer approves · a prompt already sent can't be recalled
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
billing_portal_token | path | Required | Opaque bearer capability delivered only to the payer; clients must not log it.stringPattern ^bpt_[A-Za-z0-9]+$ |
Request body Required
application/x-www-form-urlencodedResponses
303Change recorded, already waiting, or the reviewed state changed; retrieve the current portal state.404Generic HTML page for an unavailable capability.text/html429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+json503HTML that preserves the exact request for a safe retry when the result is unknown.text/htmlGET/billing/p/{billing_portal_token}/payReview paying a missed plan payment now, or follow its prompt
Script-free review of the one payment the payer can pay now from the plan link: an unpaid payment no automatic prompt will ask for again (its prompts are used up, or the payer declined it), before its deadline, on a mobile money plan with an approved number. States the amount, the number that gets the prompt and what the deadline does. With `invoice` and `prompt` it is the waiting step for that prompt, checked by reloading, then its result. Records nothing.
- Operation ID
getBillingPortalPay- Authentication
- No authentication requirement is declared.
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
billing_portal_token | path | Required | Opaque bearer capability delivered only to the payer; clients must not log it.stringPattern ^bpt_[A-Za-z0-9]+$ |
invoice | query | Optional | stringPattern ^inv_[A-Za-z0-9]+$ |
prompt | query | Optional | stringPattern ^[1-4]$ |
auto | query | Optional | `off` stops the waiting step from checking by itself.Always off |
Responses
200Script-free review, waiting or result HTML.text/html303Nothing can be paid from the link now, the payment was already asked for, or the address is not one this step writes.404Generic HTML page for an unavailable capability.text/html429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+json503Generic HTML page shown while authoritative billing truth is unavailable.text/htmlPOST/billing/p/{billing_portal_token}/payAsks the payer · a prompt already sent can't be recalledPay a missed plan payment now
Queues the reviewed unpaid invoice's own collection prompt to the plan's approved number, once, under a deterministic hidden idempotency key; an exact retry replays it and a changed request with the same key is refused. Bound to the agreement and subscription versions, the invoice, the amount and the payment's prompt count, so a review made before another prompt sends nothing. No extra amount is charged and nothing is taken unless the payer approves the prompt.
- Asks the payer. Nothing completes until the payer approves it on their own phone or payment page. The response is not proof of payment.
- One key, one movement of money. Retry it only with the same
Idempotency-Keyand body; a new key starts a new movement of money.
- Operation ID
confirmBillingPortalPay- Authentication
- No authentication requirement is declared.
- Safety class
- Request · nothing completes until the payer approves · a prompt already sent can't be recalled
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
billing_portal_token | path | Required | Opaque bearer capability delivered only to the payer; clients must not log it.stringPattern ^bpt_[A-Za-z0-9]+$ |
Request body Required
application/x-www-form-urlencodedResponses
303Payment requested (the waiting step for its prompt), nothing to pay now (the plan), or the reviewed state changed; retrieve the current state.404Generic HTML page for an unavailable capability.text/html429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+json503HTML that preserves the exact request for a safe retry when the result is unknown.text/htmlPublic status
2GET/public/v1/statusRetrieve current component posture and published incidents
Returns only explicitly published incident updates. Drafts never appear. Every update projects constrained money-safety language before operator-authored recovery detail.
- Operation ID
getPublicStatus- Authentication
- No authentication requirement is declared.
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
cell | query | Optional | stringPattern ^[A-Z]{2}$ · Default ZW |
environment | query | Optional | stringOne of sandbox, live · Default live |
Responses
200Current component posture, open incidents, and recent resolved incidents.application/json400Request validation failed.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+json503Dependency or rail is unavailable; retry safely where documented.application/problem+jsonGET/public/v1/status/incidents/{incident_id}Retrieve one exact published incident
Returns the complete published timeline in the explicit cell and environment, including incidents outside the recent status feed. Drafts and operator identities are excluded. This is publication evidence, not an individual payment outcome.
- Operation ID
getPublishedIncident- Authentication
- No authentication requirement is declared.
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
incident_id | path | Required | stringPattern ^inc_[A-Za-z0-9]{1,124}$ |
cell | query | Required | stringPattern ^[A-Z]{2}$ |
environment | query | Required | stringOne of sandbox, live |
Responses
200Exact published incident and its scope.application/json400Request validation failed.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+json503Dependency or rail is unavailable; retry safely where documented.application/problem+jsonPublic contact
1POST/public/v1/contact_requestsCreates or changes records · can't be undoneSubmit a merchant-pilot or support enquiry
Accepts JSON for programmatic clients and form encoding for the script-free public site. Contact PII is encrypted before persistence. An optional opaque submission identity makes ambiguous or repeated submissions exact for 24 hours; reuse with changed details is rejected. A KYB-1 review response is targeted within 1–2 business days; this is not live-money approval.
- Operation ID
createPublicContactRequest- Authentication
- No authentication requirement is declared.
- Safety class
- Records · creates or changes a record · can't be undone
- Agent key
- Allowed
Request body Required
application/json · PublicContactCreateapplication/x-www-form-urlencoded · PublicContactCreateResponses
202The encrypted enquiry was durably accepted for review.application/json303A script-free browser form was redirected without submitted PII in the URL, either to the static acknowledgement page after acceptance or to a branded, outcome-specific recovery page.400Request validation failed.application/problem+json409Idempotency or lifecycle conflict.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+json503Dependency or rail is unavailable; retry safely where documented.application/problem+jsonNotifications
1GET/v1/notificationsList merchant notifications
Returns tenant- and environment-scoped source-backed notices. Incident publications and terminal webhook replay batches are current producers.
- Operation ID
listMerchantNotifications- Authentication
- OAuth2 (notifications:read)
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
limit | query | Optional | integerFrom 1 to 100 · Default 20 |
starting_after | query | Optional | string |
category | query | Optional | Restrict the archive to one source-routing category.stringOne of incident, developers, money, account, data |
action_required | query | Optional | Restrict the archive to notices that do or do not require merchant action.boolean |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Merchant notification archive with deterministic newest-first continuation.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonEvents
4GET/v1/eventsList immutable merchant events
Lists signed event envelopes, newest first, with the same bytes webhook delivery sends. Use it to recover events an endpoint missed. Events can arrive more than once and out of order: deduplicate by `id`, and ignore an event whose object `version` is older than the state you already hold.
- Operation ID
listEvents- Authentication
- OAuth2 (events:read)
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
limit | query | Optional | integerFrom 1 to 100 · Default 20 |
starting_after | query | Optional | string |
type | query | Optional | Exact event name or one trailing wildcard, such as payment_intent.*.stringUp to 128 characters |
related_object | query | Optional | A payment intent, refund, checkout session, or settlement identifier.stringPattern ^(pi|re|cs|se)_[A-Za-z0-9]+$ |
created[gte] | query | Optional | Inclusive RFC 3339 lower bound.string · date-time |
created[lte] | query | Optional | Inclusive RFC 3339 upper bound.string · date-time |
ending_before | query | Optional | In the default newest-first order, the page immediately newer than this cursor, still newest first. Its `next_cursor` continues toward newer events; pass it as `ending_before` again.stringUp to 512 characters |
order | query | Optional | `asc` reads forward, oldest first, in the order events were written --
the polling feed for software with no webhook endpoint. Start with
`after_event` (the last event you handled) or page with `starting_after`
set to the previous `next_cursor`. The forward feed holds back the
newest five seconds, so a transaction still committing can't slip an
event in behind your position.
stringOne of asc, desc · Default desc |
after_event | query | Optional | Events written after this one, oldest first. Implies `order=asc`.stringUp to 128 characters · Pattern ^evt_[A-Za-z0-9]+$ |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Newest-first event page. Envelopes are the same bytes used for webhook delivery.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonGET/v1/events/{event_id}Retrieve an immutable event envelope
This operation is defined by its request and response contract below.
- Operation ID
getEvent- Authentication
- OAuth2 (events:read)
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
event_id | path | Required | stringPattern ^evt_[A-Za-z0-9]+$ |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Exact stored event envelope.application/json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonGET/v1/events/{event_id}/deliveriesList an event's deliveries
Returns logical delivery and attempt evidence without changing or enriching the immutable event envelope.
- Operation ID
getEventDeliveryEvidence- Authentication
- OAuth2 (events:read)
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
event_id | path | Required | stringPattern ^evt_[A-Za-z0-9]+$ |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Tenant- and environment-scoped webhook delivery evidence.application/json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonPOST/v1/events/{event_id}/replaySends an event again · can't be undoneEnqueue deliberate webhook redelivery
Creates new delivery records without creating or mutating the event.
- Operation ID
replayEvent- Authentication
- OAuth2 (events:replay)
- Safety class
- Redelivery · sends an event again · can't be undone
- Agent key
- Never
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
event_id | path | Required | stringPattern ^evt_[A-Za-z0-9]+$ |
Idempotency-Key | header | Required | Stable opaque key for this semantic command. Reuse it after timeouts.string16–255 characters |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Request body Optional
application/json · EventReplayCreateResponses
202Eligible deliveries were enqueued.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json409Idempotency or lifecycle conflict.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonWebhook endpoints
6POST/v1/webhook_endpointsChanges settingsCreate a webhook endpoint
Registers an HTTPS destination for signed events. The signing secret appears only in this committed response and exact idempotent replays of it; store it before relying on the endpoint. Verify each delivery's signature over the raw body, return 2xx only after storing the event, and treat a read of the payment as the authority for fulfillment.
- Operation ID
createWebhookEndpoint- Authentication
- OAuth2 (webhook_endpoints:manage)
- Safety class
- Configuration · changes settings
- Agent key
- Never
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
Idempotency-Key | header | Required | Stable opaque key for this semantic command. Reuse it after timeouts.string16–255 characters |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Request body Required
application/json · WebhookEndpointCreateResponses
200Exact replay of a previously committed create command.application/json201Endpoint and one-time signing secret.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json409Idempotency or lifecycle conflict.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonGET/v1/webhook_endpointsList webhook endpoints
This operation is defined by its request and response contract below.
- Operation ID
listWebhookEndpoints- Authentication
- OAuth2 (webhook_endpoints:manage)
- Safety class
- Read · changes nothing
- Agent key
- Never
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
starting_after | query | Optional | string |
limit | query | Optional | integerFrom 1 to 100 · Default 20 |
status | query | Optional | stringOne of enabled, disabled |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Merchant endpoints; signing secrets are omitted.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonGET/v1/webhook_endpoints/{webhook_endpoint_id}Retrieve a webhook endpoint
This operation is defined by its request and response contract below.
- Operation ID
getWebhookEndpoint- Authentication
- OAuth2 (webhook_endpoints:manage)
- Safety class
- Read · changes nothing
- Agent key
- Never
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
webhook_endpoint_id | path | Required | stringPattern ^we_[A-Za-z0-9]+$ |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Current endpoint configuration without its signing secret.application/json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonPOST/v1/webhook_endpoints/{webhook_endpoint_id}Changes settingsUpdate a webhook endpoint
This operation is defined by its request and response contract below.
- Operation ID
updateWebhookEndpoint- Authentication
- OAuth2 (webhook_endpoints:manage)
- Safety class
- Configuration · changes settings
- Agent key
- Never
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
webhook_endpoint_id | path | Required | stringPattern ^we_[A-Za-z0-9]+$ |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Idempotency-Key | header | Required | Stable opaque key for this semantic command. Reuse it after timeouts.string16–255 characters |
Request body Required
application/json · WebhookEndpointUpdateResponses
200Updated endpoint configuration.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json409Idempotency or lifecycle conflict.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonDELETE/v1/webhook_endpoints/{webhook_endpoint_id}Stops or removes · can't be undoneDelete a webhook endpoint
Stops future delivery selection while preserving delivery and audit evidence.
- Operation ID
deleteWebhookEndpoint- Authentication
- OAuth2 (webhook_endpoints:manage)
- Safety class
- Destructive · stops or removes something · can't be undone
- Agent key
- Never
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
webhook_endpoint_id | path | Required | stringPattern ^we_[A-Za-z0-9]+$ |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
204Endpoint deleted.401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonPOST/v1/webhook_endpoints/{webhook_endpoint_id}/rotate_secretChanges settings · can't be undoneRotate a webhook signing secret
Returns the new secret once and keeps the previous secret valid only for the requested overlap.
- Operation ID
rotateWebhookEndpointSecret- Authentication
- OAuth2 (webhook_endpoints:manage)
- Safety class
- Configuration · changes settings · can't be undone
- Agent key
- Never
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
webhook_endpoint_id | path | Required | stringPattern ^we_[A-Za-z0-9]+$ |
Idempotency-Key | header | Required | Stable opaque key for this semantic command. Reuse it after timeouts.string16–255 characters |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Request body Optional
application/json · WebhookSecretRotateResponses
200Endpoint and newly issued signing secret.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json409Idempotency or lifecycle conflict.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonEvent delivery
3GET/v1/webhook_endpoints/{webhook_endpoint_id}/deliveriesList an endpoint's deliveries
Returns one repeatable-read, exact-merchant and exact-environment snapshot. Active failures and dead-lettered deliveries are oldest-event-first; cancelled and delivered rows are newest-event-first. Raw response excerpts, error codes, TLS internals, signature values, and signing material are excluded.
- Operation ID
listWebhookEndpointDeliveries- Authentication
- OAuth2 (events:read)
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
webhook_endpoint_id | path | Required | stringPattern ^we_[A-Za-z0-9]+$ |
latest_only | query | Optional | When true, retain only the latest logical delivery per event before filtering outcomes. Use this with endpoint_version to review an exact replay population. Each page is a separate snapshot; the command rechecks the reviewed membership.booleanDefault false |
limit | query | Optional | integerFrom 1 to 100 · Default 20 |
starting_after | query | Optional | string |
outcome | query | Optional | stringOne of undelivered, delivered, failing, dead_lettered, cancelled |
type | query | Optional | Exact event name or one trailing wildcard, such as payment_intent.*.stringUp to 128 characters |
occurred[gte] | query | Optional | Inclusive event-occurrence lower bound as an RFC 3339 instant.string · date-time |
occurred[lte] | query | Optional | Inclusive event-occurrence upper bound as an RFC 3339 instant.string · date-time |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Filtered health aggregate and deterministic endpoint-delivery page.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonPOST/v1/webhook_endpoints/{webhook_endpoint_id}/replaySends an event again · can't be undoneReplay a reviewed endpoint outage scope
Replays each distinct event whose latest logical delivery matches the reviewed undelivered scope. The expected count must still match while the endpoint is locked; historical failed rows never widen the command. Optional expected_deliveries and expected_endpoint_version also bind the exact latest delivery identities and endpoint configuration. A mismatch returns bulk_replay_scope_changed without enqueuing work. An exact idempotent replay returns the original receipt before reevaluating these preconditions.
- Operation ID
bulkReplayWebhookEndpoint- Authentication
- OAuth2 (events:replay)
- Safety class
- Redelivery · sends an event again · can't be undone
- Agent key
- Never
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
webhook_endpoint_id | path | Required | stringPattern ^we_[A-Za-z0-9]+$ |
Idempotency-Key | header | Required | Stable opaque key for this semantic command. Reuse it after timeouts.string16–255 characters |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Request body Required
application/json · EndpointBulkReplayCreateResponses
202One new pending logical delivery was durably queued for each reviewed event.application/json400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json409Idempotency or lifecycle conflict.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonGET/v1/webhook_replay_batches/{webhook_replay_batch_id}Retrieve durable webhook replay progress
Returns exact queued, active, delivered, dead-lettered, and cancelled counts for one frozen bulk-replay scope. Counts and the bounded delivery membership are read in the same repeatable-read snapshot. A terminal state is derived only from committed delivery outcomes.
- Operation ID
getWebhookReplayBatch- Authentication
- OAuth2 (events:read)
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
webhook_replay_batch_id | path | Required | stringPattern ^wrb_[A-Za-z0-9]+$ |
Perion-Version | header | Optional | stringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15 |
Responses
200Merchant- and environment-scoped replay progress.application/json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json403Scope or merchant capability is absent, or (`api_client_policy_operation_not_allowed`) the merchant issued this API client with a policy that does not allow the operation; the problem names the `operation` and the client's `allowed_operations`. Nothing was created or charged. `api_client_paused` means the merchant paused this API client: stop and tell them, because retrying will not help until they resume it.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonSandbox callback ingress
1POST/callbacks/v1/{provider_code}/{provider_account_id}Provider-onlyRetain one signed deterministic sandbox callback
The exact body is retained encrypted before asynchronous normalization. Authentication failure is retained as evidence but returns 401. This route is not a contract for any future live provider.
- Provider-only. Payment providers call this address to report a result. Your integration never calls it, and no API client can.
- Operation ID
acceptSandboxProviderCallback- Authentication
- No authentication requirement is declared.
- Safety class
- Moves money · no payer approves it · can't be undone
- Agent key
- Never
Parameters
| Name | Location | Requirement | Description |
|---|---|---|---|
provider_code | path | Required | Provider-specific verification and normalization registry key. The published deterministic contract currently admits only sandbox; provider-certified codes are added with their exact signature contract.stringOne of sandbox |
provider_account_id | path | Required | stringPattern ^pra_[A-Za-z0-9]+$ |
Perion-Sandbox-Signature | header | Required | Comma-separated `t=<unix>,v1=<hex HMAC-SHA256>` over `t.body`; maximum skew is five minutes.stringUp to 512 characters |
Request body Required
application/json · SandboxProviderCallbackResponses
204Authenticated receipt retained for asynchronous normalization.400Request validation failed.application/problem+json401Authentication failed. `invalid_token` means the bearer token is missing, invalid or expired: obtain a new token. `api_client_expired` means the API client behind a valid token has passed its expiry: no new token can be issued for it, so stop and ask the merchant for a new credential.application/problem+json404Resource is absent or belongs to another merchant.application/problem+json409Idempotency or lifecycle conflict.application/problem+json413Callback body exceeds one mebibyte.429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+json503Dependency or rail is unavailable; retry safely where documented.application/problem+jsonHealth
3GET/health/liveProcess liveness
This operation is defined by its request and response contract below.
- Operation ID
getLiveness- Authentication
- No authentication requirement is declared.
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Responses
200The process is alive.application/json405The route only accepts GET.429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+jsonGET/health/readyDependency readiness
This operation is defined by its request and response contract below.
- Operation ID
getReadiness- Authentication
- No authentication requirement is declared.
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Responses
200The process can serve requests.application/json405The route only accepts GET.429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+json503A dependency is unavailable, so the process must not receive traffic.application/jsonGET/versionRuntime build identity
This operation is defined by its request and response contract below.
- Operation ID
getVersion- Authentication
- No authentication requirement is declared.
- Safety class
- Read · changes nothing
- Agent key
- Allowed
Responses
200Service, environment, build version, and process start time.application/json405The route only accepts GET.429Admission control refused the request. Retry after the indicated delay. Every authenticated and public route is admission controlled, so this is reachable everywhere — including a token refresh loop and a provider retry storm, which is exactly where an undeclared 429 surprises a client that has no backoff for it. A payment confirmation can also be refused with `payer_prompt_limit_reached` when the payer already has the allowed number of prompts from the merchant; nothing was sent.application/problem+json500The request could not be completed. The response carries a request_id; retrying with the same idempotency key is safe where the operation accepts one. Declared because it is reachable — the implementation has explicit internal-error sites plus a catch-all — and a client that has never been told 500 is possible will treat it as a protocol violation.application/problem+json