Skip to content
PerionPayments

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.

Public API2026-07-15
PerionPayments APIOpenAPI 3.1 · 113 matching operations
Source YAML

Authentication

1
POST/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-urlencoded

Responses

200A short-lived opaque bearer token.application/json
400Invalid grant or scope.application/json
401Client 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/json
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+json
500The 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
503Token service temporarily unavailable.application/json

API client

1
GET/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

NameLocationRequirementDescription
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Responses

200This API client's own record.application/json
400Request validation failed.application/problem+json
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+json
403Scope 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+json
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+json
500The 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

Payment intents

6
POST/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-Key and 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_operations lists payment_intents:create

Parameters

NameLocationRequirementDescription
Idempotency-KeyheaderRequired unless previewingStable 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-PreviewheaderOptional`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-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15
X-Request-IdheaderOptionalstringUp to 128 characters

Request body Required

application/json · PaymentIntentCreate

Responses

200A preview, answered because the request sent `Perion-Preview: true`. Nothing was created, reserved or sent, and no provider or phone was reached.application/json
201Intent committed; provider dispatch may still be pending or ambiguous.application/json
400Request validation failed.application/problem+json
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+json
403Scope 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+json
409Idempotency or lifecycle conflict.application/problem+json
422The 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+json
429Nothing 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+json
500The 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
503Dependency or rail is unavailable; retry safely where documented.application/problem+json
GET/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

NameLocationRequirementDescription
limitqueryOptionalintegerFrom 1 to 100 · Default 20
starting_afterqueryOptionalstring
ending_beforequeryOptionalstring
created[gte]queryOptionalstring · date-time
created[lte]queryOptionalstring · date-time
statusqueryOptionalstringOne of requires_payment_method, requires_confirmation, requires_action, processing, succeeded, partially_refunded, refunded, failed, cancelled, expired
currencyqueryOptionalstringPattern ^[A-Z]{3}$
railqueryOptionalstringUp to 64 characters
merchant_referencequeryOptionalExact merchant-owned reference. Search never performs a fuzzy or cross-tenant match.stringUp to 128 characters
api_clientqueryOptionalOnly 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_last4queryOptionalExactly 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_referencequeryOptionalExact PerionPayments support reference (`req_…`).stringUp to 128 characters · Pattern ^req_[A-Za-z0-9]+$
payer_referencequeryOptionalThe payer's `PER-` reference in any spoken or typed form; see PayerReference.stringUp to 32 characters
order_referencequeryOptionalExact order reference. Every payment for the order, newest first.stringUp to 128 characters
payment_linkqueryOptionalPayments made through this payment link.stringUp to 128 characters · Pattern ^pl_[A-Za-z0-9]+$
attempt_idqueryOptionalExact 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_ownerqueryOptionalExact 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_investigationqueryOptionaltrue 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]queryOptionalinteger · int64At least 0
amount[lte]queryOptionalinteger · int64At least 0
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Responses

200Newest-first merchant-scoped page.application/json
400Request validation failed.application/problem+json
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+json
403Scope 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+json
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+json
500The 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
GET/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

NameLocationRequirementDescription
payment_intent_idpathRequiredstringPattern ^pi_[A-Za-z0-9]+$
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Responses

200Current intent projection.application/json
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+json
404Resource is absent or belongs to another merchant.application/problem+json
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+json
500The 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
GET/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

NameLocationRequirementDescription
payment_intent_idpathRequiredstringPattern ^pi_[A-Za-z0-9]+$
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Responses

200Current payment projection with its merchant-safe evidence history.application/json
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+json
404Resource is absent or belongs to another merchant.application/problem+json
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+json
500The 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
POST/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-Key and 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_operations lists payment_intents:confirm

Parameters

NameLocationRequirementDescription
payment_intent_idpathRequiredstringPattern ^pi_[A-Za-z0-9]+$
Idempotency-KeyheaderRequiredStable opaque key for this semantic command. Reuse it after timeouts.string16–255 characters
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Request body Required

application/json

Responses

200Confirmed intent; inspect its state and next action.application/json
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+json
403Scope 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+json
409Idempotency or lifecycle conflict.application/problem+json
422The 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+json
429Nothing 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+json
500The 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
POST/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_operations lists payment_intents:cancel

Parameters

NameLocationRequirementDescription
payment_intent_idpathRequiredstringPattern ^pi_[A-Za-z0-9]+$
Idempotency-KeyheaderRequiredStable opaque key for this semantic command. Reuse it after timeouts.string16–255 characters
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Request body Optional

application/json

Responses

200Cancelled intent.application/json
202The 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/json
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+json
403Scope 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+json
409Idempotency or lifecycle conflict.application/problem+json
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+json
500The 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

Checkout sessions

3
POST/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_operations lists checkout_sessions:create

Parameters

NameLocationRequirementDescription
Idempotency-KeyheaderRequired unless previewingStable 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-PreviewheaderOptional`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-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Request body Required

application/json · CheckoutSessionCreate

Responses

200A preview, answered because the request sent `Perion-Preview: true`. Nothing was created, reserved or sent, and no provider or phone was reached.application/json
201Hosted checkout session.application/json
400Request validation failed.application/problem+json
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+json
403Scope 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+json
409Idempotency or lifecycle conflict.application/problem+json
422The 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+json
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+json
500The 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
GET/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

NameLocationRequirementDescription
checkout_session_idpathRequiredstringPattern ^cs_[A-Za-z0-9]+$
Perion-VersionheaderOptionalstringPattern ^\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/json
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+json
403Scope 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+json
404Resource is absent or belongs to another merchant.application/problem+json
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+json
500The 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
POST/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_operations lists checkout_sessions:revoke_saved_cards

Parameters

NameLocationRequirementDescription
checkout_session_idpathRequiredstringPattern ^cs_[A-Za-z0-9]+$
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15
Idempotency-KeyheaderRequiredStable 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+json
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+json
403Scope 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+json
404Resource is absent or belongs to another merchant.application/problem+json
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+json
500The 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
503Dependency or rail is unavailable; retry safely where documented.application/problem+json

Customers

5
GET/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

NameLocationRequirementDescription
command_keypathRequiredstring16–255 characters
operationqueryRequiredstringOne of create, update
customerqueryOptionalExact customer ID, required for update and omitted for create.stringPattern ^cust_[A-Za-z0-9]+$
Perion-VersionheaderOptionalstringPattern ^\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/json
400Request validation failed.application/problem+json
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+json
403Scope 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+json
409Idempotency or lifecycle conflict.application/problem+json
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+json
500The 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
POST/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

NameLocationRequirementDescription
Idempotency-KeyheaderRequiredStable opaque key for this semantic command. Reuse it after timeouts.string16–255 characters
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Request body Required

application/json · CustomerCreate

Responses

201Customer identity committed once.application/json
400Request validation failed.application/problem+json
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+json
403Scope 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+json
409Idempotency or lifecycle conflict.application/problem+json
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+json
500The 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
GET/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

NameLocationRequirementDescription
limitqueryOptionalintegerFrom 1 to 100 · Default 20
starting_afterqueryOptionalstring
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Responses

200Newest-first customer page.application/json
400Request validation failed.application/problem+json
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+json
403Scope 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+json
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+json
500The 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
GET/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

NameLocationRequirementDescription
customer_idpathRequiredstringPattern ^cust_[A-Za-z0-9]+$
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Responses

200Exact customer projection.application/json
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+json
403Scope 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+json
404Resource is absent or belongs to another merchant.application/problem+json
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+json
500The 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
POST/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

NameLocationRequirementDescription
customer_idpathRequiredstringPattern ^cust_[A-Za-z0-9]+$
Idempotency-KeyheaderRequiredStable opaque key for this semantic command. Reuse it after timeouts.string16–255 characters
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Request body Required

application/json · CustomerUpdate

Responses

200Updated customer projection.application/json
400Request validation failed.application/problem+json
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+json
403Scope 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+json
404Resource is absent or belongs to another merchant.application/problem+json
409Idempotency or lifecycle conflict.application/problem+json
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+json
500The 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

Billing

25
POST/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

NameLocationRequirementDescription
Idempotency-KeyheaderRequiredStable opaque key for this semantic command. Reuse it after timeouts.string16–255 characters
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Request body Required

application/json · BillingPlanCreate

Responses

201Billing plan committed once.application/json
400Request validation failed.application/problem+json
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+json
403Scope 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+json
409Idempotency or lifecycle conflict.application/problem+json
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+json
500The 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
GET/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

NameLocationRequirementDescription
limitqueryOptionalintegerFrom 1 to 100 · Default 20
starting_afterqueryOptionalstring
statusqueryOptionalExact status from the lifecycle of the billing object being listed.stringUp to 40 characters
qqueryOptionalCase-insensitive plan name or public-ID search across the safe identifiers exposed by this billing ledger.stringUp to 128 characters
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Responses

200Newest-first bounded plan page.application/json
400Request validation failed.application/problem+json
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+json
403Scope 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+json
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+json
500The 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
GET/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

NameLocationRequirementDescription
plan_idpathRequiredstringPattern ^plan_[A-Za-z0-9]+$
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Responses

200Exact plan projection.application/json
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+json
403Scope 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+json
404Resource is absent or belongs to another merchant.application/problem+json
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+json
500The 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
POST/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

NameLocationRequirementDescription
plan_idpathRequiredstringPattern ^plan_[A-Za-z0-9]+$
Idempotency-KeyheaderRequiredStable opaque key for this semantic command. Reuse it after timeouts.string16–255 characters
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Request body Required

application/json · BillingPlanArchive

Responses

200Archived plan projection.application/json
400Request validation failed.application/problem+json
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+json
403Scope 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+json
404Resource is absent or belongs to another merchant.application/problem+json
409Idempotency or lifecycle conflict.application/problem+json
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+json
500The 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
GET/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

NameLocationRequirementDescription
limitqueryOptionalintegerFrom 1 to 100 · Default 20
starting_afterqueryOptionalstring
statusqueryOptionalExact status from the lifecycle of the billing object being listed.stringUp to 40 characters
qqueryOptionalCase-insensitive plan name or public-ID search across the safe identifiers exposed by this billing ledger.stringUp to 128 characters
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Responses

200Newest-first bounded agreement page.application/json
400Request validation failed.application/problem+json
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+json
403Scope 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+json
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+json
500The 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
GET/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

NameLocationRequirementDescription
agreement_idpathRequiredstringPattern ^agr_[A-Za-z0-9]+$
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Responses

200Exact agreement projection.application/json
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+json
403Scope 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+json
404Resource is absent or belongs to another merchant.application/problem+json
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+json
500The 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
POST/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

NameLocationRequirementDescription
Idempotency-KeyheaderRequired unless previewingStable 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-PreviewheaderOptional`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-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Request body Required

application/json · BillingSubscriptionCreate

Responses

200A preview, answered because the request sent `Perion-Preview: true`. Nothing was created, reserved or sent, and no provider or phone was reached.application/json
201Enrollment objects and first-payment checkout committed atomically.application/json
400Request validation failed.application/problem+json
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+json
403Scope 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+json
404Resource is absent or belongs to another merchant.application/problem+json
409Idempotency or lifecycle conflict.application/problem+json
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+json
500The 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
GET/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

NameLocationRequirementDescription
limitqueryOptionalintegerFrom 1 to 100 · Default 20
starting_afterqueryOptionalstring
statusqueryOptionalExact status from the lifecycle of the billing object being listed.stringUp to 40 characters
qqueryOptionalCase-insensitive plan name or public-ID search across the safe identifiers exposed by this billing ledger.stringUp to 128 characters
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Responses

200Newest-first bounded subscription page.application/json
400Request validation failed.application/problem+json
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+json
403Scope 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+json
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+json
500The 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
GET/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

NameLocationRequirementDescription
subscription_idpathRequiredstringPattern ^sub_[A-Za-z0-9]+$
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Responses

200Exact subscription projection.application/json
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+json
403Scope 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+json
404Resource is absent or belongs to another merchant.application/problem+json
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+json
500The 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
GET/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

NameLocationRequirementDescription
subscription_idpathRequiredstringPattern ^sub_[A-Za-z0-9]+$
Perion-VersionheaderOptionalstringPattern ^\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/json
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+json
403Scope 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+json
404Resource is absent or belongs to another merchant.application/problem+json
409Idempotency or lifecycle conflict.application/problem+json
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+json
500The 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
GET/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

NameLocationRequirementDescription
subscription_idpathRequiredstringPattern ^sub_[A-Za-z0-9]+$
limitqueryOptionalintegerFrom 1 to 100 · Default 20
starting_afterqueryOptionalstring
statusqueryOptionalRestrict 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-VersionheaderOptionalstringPattern ^\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/json
400Request validation failed.application/problem+json
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+json
403Scope 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+json
404Resource is absent or belongs to another merchant.application/problem+json
409Idempotency or lifecycle conflict.application/problem+json
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+json
500The 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
GET/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

NameLocationRequirementDescription
subscription_idpathRequiredstringPattern ^sub_[A-Za-z0-9]+$
Perion-VersionheaderOptionalstringPattern ^\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/json
400Request validation failed.application/problem+json
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+json
403Scope 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+json
404Resource is absent or belongs to another merchant.application/problem+json
409Idempotency or lifecycle conflict.application/problem+json
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+json
500The 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
POST/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

NameLocationRequirementDescription
subscription_idpathRequiredstringPattern ^sub_[A-Za-z0-9]+$
Idempotency-KeyheaderRequiredStable opaque key for this semantic command. Reuse it after timeouts.string16–255 characters
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Request body Required

application/json · BillingReconsentCreate

Responses

201A pending replacement enrollment and reveal-once consent checkout.application/json
400Request validation failed.application/problem+json
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+json
403Scope 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+json
404Resource is absent or belongs to another merchant.application/problem+json
409Idempotency or lifecycle conflict.application/problem+json
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+json
500The 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
POST/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

NameLocationRequirementDescription
subscription_idpathRequiredstringPattern ^sub_[A-Za-z0-9]+$
actionpathRequiredstringOne of pause, resume, cancel
Idempotency-KeyheaderRequiredStable opaque key for this semantic command. Reuse it after timeouts.string16–255 characters
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Request body Required

application/json · BillingSubscriptionControlRequest

Responses

200The agreement and subscription after the audited state transition.application/json
400Request validation failed.application/problem+json
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+json
403Scope 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+json
404Resource is absent or belongs to another merchant.application/problem+json
409Idempotency or lifecycle conflict.application/problem+json
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+json
500The 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
GET/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

NameLocationRequirementDescription
limitqueryOptionalintegerFrom 1 to 100 · Default 20
starting_afterqueryOptionalstring
statusqueryOptionalExact status from the lifecycle of the billing object being listed.stringUp to 40 characters
qqueryOptionalCase-insensitive plan name or public-ID search across the safe identifiers exposed by this billing ledger.stringUp to 128 characters
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Responses

200Newest-first bounded invoice page.application/json
400Request validation failed.application/problem+json
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+json
403Scope 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+json
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+json
500The 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
GET/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

NameLocationRequirementDescription
invoice_idpathRequiredstringPattern ^inv_[A-Za-z0-9]+$
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Responses

200Exact invoice projection.application/json
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+json
403Scope 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+json
404Resource is absent or belongs to another merchant.application/problem+json
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+json
500The 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
GET/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

NameLocationRequirementDescription
limitqueryOptionalintegerFrom 1 to 100 · Default 20
starting_afterqueryOptionalstring
statusqueryOptionalExact status from the lifecycle of the billing object being listed.stringUp to 40 characters
qqueryOptionalCase-insensitive plan name or public-ID search across the safe identifiers exposed by this billing ledger.stringUp to 128 characters
subscriptionqueryOptionalstringPattern ^sub_[A-Za-z0-9]+$
reasonqueryOptionalstringOne of prompt_timeout, payer_declined, insufficient_funds, provider_unavailable, provider_uncertainty, agreement_revoked
recoveredqueryOptionalSelect cycles paid after a succeeded attempt beyond sequence one, or its complement.boolean
attempt_sequencequeryOptionalSelect cycles containing this exact prompt-attempt sequence.integerFrom 1 to 12
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Responses

200Newest-first bounded cycle page; attempts are ordered by sequence.application/json
400Request validation failed.application/problem+json
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+json
403Scope 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+json
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+json
500The 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
GET/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

NameLocationRequirementDescription
collection_cycle_idpathRequiredstringPattern ^cyc_[A-Za-z0-9]+$
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Responses

200Exact collection-cycle projection.application/json
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+json
403Scope 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+json
404Resource is absent or belongs to another merchant.application/problem+json
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+json
500The 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
GET/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

NameLocationRequirementDescription
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Responses

200Environment-scoped collection-health snapshot.application/json
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+json
403Scope 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+json
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+json
500The 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
GET/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

NameLocationRequirementDescription
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Responses

200Effective policy and immutable version.application/json
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+json
403Scope 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+json
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+json
500The 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
POST/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

NameLocationRequirementDescription
Idempotency-KeyheaderRequiredStable opaque key for this semantic command. Reuse it after timeouts.string16–255 characters
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Request body Required

application/json · BillingCollectionPolicyUpdate

Responses

200New effective policy version, or the exact idempotent replay.application/json
400Request validation failed.application/problem+json
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+json
403Scope 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+json
409Idempotency or lifecycle conflict.application/problem+json
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+json
500The 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
POST/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

NameLocationRequirementDescription
Idempotency-KeyheaderRequiredStable opaque key for this semantic command. Reuse it after timeouts.string16–255 characters
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Request body Required

application/json · BillingTestClockCreate

Responses

201The single sandbox billing clock was created.application/json
400Request validation failed.application/problem+json
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+json
403Scope 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+json
409Idempotency or lifecycle conflict.application/problem+json
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+json
500The 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
GET/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

NameLocationRequirementDescription
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Responses

200Zero or one merchant-scoped clock.application/json
400Request validation failed.application/problem+json
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+json
403Scope 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+json
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+json
500The 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
GET/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

NameLocationRequirementDescription
test_clock_idpathRequiredstringPattern ^bclock_[A-Za-z0-9]+$
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Responses

200Exact advance-only logical clock.application/json
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+json
403Scope 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+json
404Resource is absent or belongs to another merchant.application/problem+json
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+json
500The 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
POST/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

NameLocationRequirementDescription
test_clock_idpathRequiredstringPattern ^bclock_[A-Za-z0-9]+$
Idempotency-KeyheaderRequiredStable opaque key for this semantic command. Reuse it after timeouts.string16–255 characters
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Request body Required

application/json · BillingTestClockAdvance

Responses

200Clock advanced and a task-queue promotion pass was scheduled.application/json
400Request validation failed.application/problem+json
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+json
403Scope 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+json
404Resource is absent or belongs to another merchant.application/problem+json
409Idempotency or lifecycle conflict.application/problem+json
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+json
500The 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

Payment methods

3
GET/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

NameLocationRequirementDescription
currencyqueryRequiredstringPattern ^[A-Z]{3}$
amountqueryRequiredinteger · int64At least 1
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Responses

200Capability-, amount-, currency-, and health-scoped methods.application/json
400Request validation failed.application/problem+json
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+json
403Scope 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+json
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+json
500The 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
GET/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

NameLocationRequirementDescription
customerqueryOptionalstringPattern ^cust_[A-Za-z0-9]+$
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Responses

200Stored cards, newest first, at most one hundred.application/json
400Request validation failed.application/problem+json
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+json
403Scope 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+json
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+json
POST/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

NameLocationRequirementDescription
payment_method_credential_idpathRequiredstringPattern ^pm_[A-Za-z0-9]+$
Idempotency-KeyheaderRequiredStable opaque key for this semantic command. Reuse it after timeouts.string16–255 characters
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Responses

200The retired stored card.application/json
400Request validation failed.application/problem+json
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+json
403Scope 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+json
404Resource is absent or belongs to another merchant.application/problem+json
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+json

Refunds

3
GET/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

NameLocationRequirementDescription
limitqueryOptionalintegerFrom 1 to 100 · Default 20
starting_afterqueryOptionalstring
payment_intentqueryOptionalstringPattern ^pi_[A-Za-z0-9]+$
statusqueryOptionalstringOne of pending, processing, succeeded, failed
currencyqueryOptionalstringPattern ^[A-Z]{3}$
settlement_evidencequeryOptionalstringOne of none, provider_response_only, provider_file_confirmed, bank_confirmed, provider_query_confirmed
merchant_referencequeryOptionalstringUp to 128 characters
api_clientqueryOptionalOnly 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_referencequeryOptionalExact 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]queryOptionalInclusive RFC 3339 lower bound.string · date-time
created[lte]queryOptionalInclusive RFC 3339 upper bound.string · date-time
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Responses

200Newest-first merchant-scoped refund page.application/json
400Request validation failed.application/problem+json
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+json
403Scope 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+json
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+json
500The 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
POST/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-Key and 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_operations lists refunds:create

Parameters

NameLocationRequirementDescription
Idempotency-KeyheaderRequired unless previewingStable 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-PreviewheaderOptional`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-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15
X-Request-IdheaderOptionalstringUp to 128 characters

Request body Required

application/json · RefundCreate

Responses

200A preview, answered because the request sent `Perion-Preview: true`. Nothing was created, reserved or sent, and no provider or phone was reached.application/json
201Refund committed; inspect status and settlement evidence separately.application/json
400Request validation failed.application/problem+json
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+json
403Scope 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+json
404Resource is absent or belongs to another merchant.application/problem+json
409Idempotency or lifecycle conflict.application/problem+json
422The 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+json
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+json
500The 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
503Dependency or rail is unavailable; retry safely where documented.application/problem+json
GET/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

NameLocationRequirementDescription
refund_idpathRequiredstringPattern ^re_[A-Za-z0-9]+$
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Responses

200Current refund and its strongest settlement evidence.application/json
400Request validation failed.application/problem+json
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+json
403Scope 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+json
404Resource is absent or belongs to another merchant.application/problem+json
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+json
500The 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

Balances

1
GET/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

NameLocationRequirementDescription
currencyqueryOptionalstringPattern ^[A-Z]{3}$
paid_directly[gte]queryOptionalInclusive start of the window for paid_directly totals only. Ledger balances are always current and are not filtered.string · date-time
paid_directly[lte]queryOptionalInclusive end of the window for paid_directly totals only. It must not precede paid_directly[gte].string · date-time
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Responses

200One projection per ledger book and currency.application/json
400Request validation failed.application/problem+json
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+json
403Scope 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+json
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+json
500The 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

Settlements

5
GET/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

NameLocationRequirementDescription
limitqueryOptionalintegerFrom 1 to 100 · Default 20
starting_afterqueryOptionalstring
statusqueryOptionalstringOne of pending_approval, approved, dispatched, evidence_pending, confirmed, failed, returned
currencyqueryOptionalstringPattern ^[A-Z]{3}$
search_referencequeryOptionalExact 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]queryOptionalInclusive RFC 3339 lower bound.string · date-time
created[lte]queryOptionalInclusive RFC 3339 upper bound.string · date-time
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Responses

200Newest-first merchant-scoped settlement batches.application/json
400Request validation failed.application/problem+json
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+json
403Scope 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+json
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+json
500The 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
GET/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

NameLocationRequirementDescription
settlement_batch_idpathRequiredstringPattern ^se_[A-Za-z0-9]+$
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Responses

200Current immutable composition, merchant-safe manifest rows, and evidence projection.application/json
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+json
403Scope 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+json
404Resource is absent or belongs to another merchant.application/problem+json
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+json
500The 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
GET/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

NameLocationRequirementDescription
settlement_batch_idpathRequiredstringPattern ^se_[A-Za-z0-9]+$
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Responses

200RFC 4180 activity detail using the immutable stmt_v1 columns.text/csv
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+json
403Scope 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+json
404Resource is absent or belongs to another merchant.application/problem+json
409Idempotency or lifecycle conflict.application/problem+json
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+json
500The 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
GET/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

NameLocationRequirementDescription
business_datepathRequiredstring · date
Perion-VersionheaderOptionalstringPattern ^\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/json
400Request validation failed.application/problem+json
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+json
403Scope 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+json
404Resource is absent or belongs to another merchant.application/problem+json
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+json
500The 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
GET/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

NameLocationRequirementDescription
business_datepathRequiredstring · date
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Responses

200RFC 4180 merchant-account entries carrying the merchant_daily_close_v1 version.text/csv
400Request validation failed.application/problem+json
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+json
403Scope 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+json
404Resource is absent or belongs to another merchant.application/problem+json
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+json
500The 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

Reconciliation

2
GET/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

NameLocationRequirementDescription
limitqueryOptionalintegerFrom 1 to 100 · Default 20
starting_afterqueryOptionalstring
statusqueryOptionalstringOne of unresolved, open, investigating, pending_approval, resolved
classqueryOptionalstringOne 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
severityqueryOptionalstringOne of low, medium, high, critical
settlement_batchqueryOptionalExact settlement pivot used by the settlement evidence view.stringPattern ^se_[A-Za-z0-9]+$
created[gte]queryOptionalInclusive RFC 3339 lower bound.string · date-time
created[lte]queryOptionalInclusive RFC 3339 upper bound.string · date-time
Perion-VersionheaderOptionalstringPattern ^\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/json
400Request validation failed.application/problem+json
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+json
403Scope 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+json
409The selected reconciliation set changed. Code reconciliation_list_changed requires a fresh first page with the same filters; no continuation records are returned.application/problem+json
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+json
500The 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
GET/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

NameLocationRequirementDescription
reconciliation_exception_idpathRequiredstringPattern ^rex_[A-Za-z0-9]+$
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Responses

200Exact merchant-safe exception state and related public financial objects.application/json
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+json
403Scope 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+json
404Resource is absent or belongs to another merchant.application/problem+json
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+json
500The 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

Exports

5
GET/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

NameLocationRequirementDescription
limitqueryOptionalintegerFrom 1 to 100 · Default 20
starting_afterqueryOptionalstring
reportqueryOptionalstringOne of payments, refunds, settlements, fees, performance
statusqueryOptionalstringOne of active, queued, processing, ready, failed, expired
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Responses

200Newest-first merchant and environment scoped export jobs.application/json
400Request validation failed.application/problem+json
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+json
403Scope 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+json
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+json
500The 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
POST/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

NameLocationRequirementDescription
Idempotency-KeyheaderRequiredStable opaque key for this semantic command. Reuse it after timeouts.string16–255 characters
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Request body Required

application/json · ExportJobCreate

Responses

202Durable export job accepted for asynchronous generation.application/json
400Request validation failed.application/problem+json
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+json
403Scope 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+json
409Idempotency or lifecycle conflict.application/problem+json
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+json
500The 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
GET/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

NameLocationRequirementDescription
export_job_idpathRequiredstringPattern ^exj_[A-Za-z0-9]+$
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Responses

200Exact immutable-scope export projection.application/json
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+json
403Scope 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+json
404Resource is absent or belongs to another merchant.application/problem+json
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+json
500The 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
POST/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

NameLocationRequirementDescription
export_job_idpathRequiredstringPattern ^exj_[A-Za-z0-9]+$
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Responses

201One-use download URL; bearer authorization remains required.application/json
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+json
403Scope 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+json
404Resource is absent or belongs to another merchant.application/problem+json
409Idempotency or lifecycle conflict.application/problem+json
410The retained artifact has expired.application/problem+json
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+json
500The 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
GET/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

NameLocationRequirementDescription
export_job_idpathRequiredstringPattern ^exj_[A-Za-z0-9]+$
tokenqueryRequiredOpaque one-use token returned by the download-session endpoint; only its SHA-256 hash is retained.stringPattern ^dlt_[A-Za-z0-9]+$
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Responses

200RFC 4180 CSV matching the job's immutable schema version and checksum.text/csv
400Request validation failed.application/problem+json
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+json
403Scope 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+json
404Resource is absent or belongs to another merchant.application/problem+json
409Idempotency or lifecycle conflict.application/problem+json
410The artifact or one-use token is no longer usable.application/problem+json
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+json
500The 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

Payment links

4

Public checkout

15
POST/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

NameLocationRequirementDescription
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Request body Required

application/json

Responses

200Exact payer-safe target state and the capability needed to continue it.application/json
400Request validation failed.application/problem+json
404Resource is absent or belongs to another merchant.application/problem+json
429Rate limit exceeded; honor Retry-After.application/problem+json
500The 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
503Dependency or rail is unavailable; retry safely where documented.application/problem+json
POST/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

NameLocationRequirementDescription
Idempotency-KeyheaderRequiredStable opaque key for this semantic command. Reuse it after timeouts.string16–255 characters
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Request body Required

application/json

Responses

202Idempotent status reply queued against the exact sandbox target.application/json
400Request validation failed.application/problem+json
404Resource is absent or belongs to another merchant.application/problem+json
429Rate limit exceeded; honor Retry-After.application/problem+json
500The 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
503Dependency or rail is unavailable; retry safely where documented.application/problem+json
GET/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

NameLocationRequirementDescription
payment_link_idpathRequiredstringPattern ^pl_[A-Za-z0-9]+$

Responses

200Payer-safe checkout shell HTML for an active payment link.text/html
404Generic HTML page for an unknown, inactive, or scope-mismatched link.text/html
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+json
500The 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
503Generic HTML page shown while payment-link truth is unavailable.text/html
GET/c/{payment_link_id}View and share a script-free payment-link card

Renders current merchant, amount, environment, continuation, and checkout truth as semantic HTML with Open Graph metadata. Reading or sharing the page has no payment effect.

Operation ID
getPaymentLinkSharePage
Authentication
No authentication requirement is declared.
Safety class
Read · changes nothing
Agent key
Allowed

Parameters

NameLocationRequirementDescription
payment_link_idpathRequiredstringPattern ^pl_[A-Za-z0-9]+$

Responses

200Script-free payment-link landing HTML.text/html
404Generic HTML page for an unknown, expired, consumed, or inactive link.text/html
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+json
500The 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
503Generic HTML page shown while payment-link truth is unavailable.text/html
GET/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

NameLocationRequirementDescription
payment_link_idspathRequiredOne 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}$
titlequeryOptionalOptional 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/html
400Generic HTML page when the collection title is invalid.text/html
404Generic HTML page when no valid same-merchant link remains.text/html
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+json
500The 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
503Generic HTML page shown while payment-link truth is unavailable.text/html
GET/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

NameLocationRequirementDescription
checkout_session_idpathRequiredstringPattern ^cs_[A-Za-z0-9]+$
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15
Perion-Embed-OriginheaderOptionalCanonical 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/json
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+json
409Idempotency or lifecycle conflict.application/problem+json
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+json
500The 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
503Dependency or rail is unavailable; retry safely where documented.application/problem+json
GET/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

NameLocationRequirementDescription
checkout_session_idpathRequiredstringPattern ^cs_[A-Za-z0-9]+$

Responses

200Payer-safe checkout shell HTML for the current checkout session.text/html
404Generic HTML page for an unknown or scope-mismatched checkout session.text/html
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+json
500The 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
503Generic HTML page shown while checkout truth is unavailable.text/html
GET/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

NameLocationRequirementDescription
checkout_session_idpathRequiredstringPattern ^cs_[A-Za-z0-9]+$
attempt_idpathRequiredThe payment attempt the hosted card page belongs to.stringPattern ^pa_[A-Za-z0-9]{8,64}$
equeryRequiredWhen the signed hosted card link expires, in Unix seconds.integer · int64At least 1
tqueryRequiredThe 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/html
404Generic HTML page for an incomplete, altered or foreign link.text/html
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+json
500The 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
503Generic HTML page shown while the hosted card page cannot be prepared. No payment was started from it.text/html
GET/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

NameLocationRequirementDescription
checkout_session_idpathRequiredstringPattern ^cs_[A-Za-z0-9]+$
attempt_idpathRequiredThe payment attempt the hosted card page belongs to.stringPattern ^pa_[A-Za-z0-9]{8,64}$
equeryRequiredWhen the signed hosted card link expires, in Unix seconds.integer · int64At least 1
tqueryRequiredThe 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/html
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+json
500The 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
POST/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

NameLocationRequirementDescription
checkout_session_idpathRequiredstringPattern ^cs_[A-Za-z0-9]+$
attempt_idpathRequiredThe payment attempt the hosted card page belongs to.stringPattern ^pa_[A-Za-z0-9]{8,64}$
equeryRequiredWhen the signed hosted card link expires, in Unix seconds.integer · int64At least 1
tqueryRequiredThe 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/html
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+json
500The 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
GET/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

NameLocationRequirementDescription
checkout_session_idpathRequiredstringPattern ^cs_[A-Za-z0-9]+$
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15
Perion-Embed-OriginheaderOptionalCanonical 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/json
400Request validation failed.application/problem+json
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+json
409Idempotency or lifecycle conflict.application/problem+json
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+json
500The 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
503Dependency or rail is unavailable; retry safely where documented.application/problem+json
GET/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

NameLocationRequirementDescription
checkout_session_idpathRequiredstringPattern ^cs_[A-Za-z0-9]+$
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15
Perion-Embed-OriginheaderOptionalCanonical 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/json
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+json
409Idempotency or lifecycle conflict.application/problem+json
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+json
500The 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
503Dependency or rail is unavailable; retry safely where documented.application/problem+json
POST/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-Key and 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

NameLocationRequirementDescription
checkout_session_idpathRequiredstringPattern ^cs_[A-Za-z0-9]+$
Idempotency-KeyheaderRequiredStable opaque key for this semantic command. Reuse it after timeouts.string16–255 characters
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15
X-Request-IdheaderOptionalstringUp to 128 characters
Perion-Embed-OriginheaderOptionalCanonical 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-AgentheaderOptionalOptional 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 · PublicCheckoutConfirm

Responses

200Confirmation committed; inspect the nested payment intent and next action.application/json
400Request validation failed.application/problem+json
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+json
409Idempotency or lifecycle conflict.application/problem+json
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+json
500The 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
503Dependency or rail is unavailable; retry safely where documented.application/problem+json

Public presentation

1
GET/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

NameLocationRequirementDescription
font_namepathRequiredstringOne of inter-latin-wght-normal.woff2, bricolage-grotesque-latin-600-normal.woff2

Responses

200Immutable same-origin WOFF2 font bytes.font/woff2
304The caller already holds the exact immutable font.
404The requested name is outside the closed font vocabulary.text/plain

Public receipts

2
GET/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

NameLocationRequirementDescription
receipt_idpathRequiredstringPattern ^rcpt_[A-Za-z0-9]{16,128}$
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Responses

200Forward-safe payment receipt with evidence-qualified refund history.application/json
404Resource is absent or belongs to another merchant.application/problem+json
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+json
500The 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
503Dependency or rail is unavailable; retry safely where documented.application/problem+json
GET/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

NameLocationRequirementDescription
receipt_idpathRequiredstringPattern ^rcpt_[A-Za-z0-9]{16,128}$

Responses

200Script-free, print-safe receipt HTML.text/html
404Generic HTML page for an unknown, malformed, or never-issued capability.text/html
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+json
500The 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
503Generic HTML page shown while authoritative receipt truth is unavailable.text/html

Public billing portal

10
GET/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

NameLocationRequirementDescription
billing_portal_tokenpathRequiredOpaque bearer capability delivered only to the payer; clients must not log it.stringPattern ^bpt_[A-Za-z0-9]+$
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Responses

200Capability-minimized agreement, subscription, plan, controls, and cycle history.application/json
404Resource is absent or belongs to another merchant.application/problem+json
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+json
500The 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
POST/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

NameLocationRequirementDescription
billing_portal_tokenpathRequiredOpaque bearer capability delivered only to the payer; clients must not log it.stringPattern ^bpt_[A-Za-z0-9]+$
billing_portal_actionpathRequiredstringOne of pause, resume, cancel
Idempotency-KeyheaderRequiredStable opaque key for this semantic command. Reuse it after timeouts.string16–255 characters
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Responses

200Exact post-command portal state, or its byte-identical idempotent replay.application/json
400Request validation failed.application/problem+json
404Resource is absent or belongs to another merchant.application/problem+json
409Idempotency or lifecycle conflict.application/problem+json
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+json
500The 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
GET/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

NameLocationRequirementDescription
billing_portal_tokenpathRequiredOpaque 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/html
404Generic HTML page for an unknown, malformed, expired, or inactive capability.text/html
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+json
500The 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
503Generic HTML page shown while authoritative billing truth is unavailable.text/html
GET/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

NameLocationRequirementDescription
billing_portal_tokenpathRequiredOpaque bearer capability delivered only to the payer; clients must not log it.stringPattern ^bpt_[A-Za-z0-9]+$
invoice_idpathRequiredstringPattern ^inv_[A-Za-z0-9]+$

Responses

200Script-free printable invoice HTML.text/html
404Generic HTML page for an unavailable capability or invoice.text/html
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+json
500The 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
503Generic HTML page shown while authoritative billing truth is unavailable.text/html
POST/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

NameLocationRequirementDescription
billing_portal_tokenpathRequiredOpaque bearer capability delivered only to the payer; clients must not log it.stringPattern ^bpt_[A-Za-z0-9]+$
billing_portal_actionpathRequiredstringOne of pause, resume, cancel

Request body Required

application/x-www-form-urlencoded

Responses

303Command completed or safely conflicted; retrieve the current portal state.
400Generic HTML page for an unreadable form command.text/html
404Generic HTML page for an unavailable capability or action.text/html
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+json
500The 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
503Generic HTML page shown while authoritative billing truth is unavailable.text/html
GET/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

NameLocationRequirementDescription
billing_portal_tokenpathRequiredOpaque 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/html
404Generic HTML page for an unavailable capability.text/html
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+json
500The 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
503Generic HTML page shown while authoritative billing truth is unavailable.text/html
POST/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

NameLocationRequirementDescription
billing_portal_tokenpathRequiredOpaque 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-urlencoded

Responses

200Script-free review HTML with the confirmation form.text/html
303The reviewed plan changed; retrieve the current portal state.
404Generic HTML page for an unavailable capability.text/html
409HTML explaining why no change can start now.text/html
422HTML form with the number marked invalid.text/html
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+json
500The 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
503Generic HTML page shown while authoritative billing truth is unavailable.text/html
POST/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-Key and 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

NameLocationRequirementDescription
billing_portal_tokenpathRequiredOpaque 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-urlencoded

Responses

303Change recorded, already waiting, or the reviewed state changed; retrieve the current portal state.
404Generic HTML page for an unavailable capability.text/html
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+json
500The 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
503HTML that preserves the exact request for a safe retry when the result is unknown.text/html
GET/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

NameLocationRequirementDescription
billing_portal_tokenpathRequiredOpaque bearer capability delivered only to the payer; clients must not log it.stringPattern ^bpt_[A-Za-z0-9]+$
invoicequeryOptionalstringPattern ^inv_[A-Za-z0-9]+$
promptqueryOptionalstringPattern ^[1-4]$
autoqueryOptional`off` stops the waiting step from checking by itself.Always off

Responses

200Script-free review, waiting or result HTML.text/html
303Nothing 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/html
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+json
500The 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
503Generic HTML page shown while authoritative billing truth is unavailable.text/html
POST/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-Key and 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

NameLocationRequirementDescription
billing_portal_tokenpathRequiredOpaque 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-urlencoded

Responses

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/html
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+json
500The 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
503HTML that preserves the exact request for a safe retry when the result is unknown.text/html

Public status

2
GET/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

NameLocationRequirementDescription
cellqueryOptionalstringPattern ^[A-Z]{2}$ · Default ZW
environmentqueryOptionalstringOne of sandbox, live · Default live

Responses

200Current component posture, open incidents, and recent resolved incidents.application/json
400Request validation failed.application/problem+json
404Resource is absent or belongs to another merchant.application/problem+json
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+json
500The 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
503Dependency or rail is unavailable; retry safely where documented.application/problem+json
GET/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

NameLocationRequirementDescription
incident_idpathRequiredstringPattern ^inc_[A-Za-z0-9]{1,124}$
cellqueryRequiredstringPattern ^[A-Z]{2}$
environmentqueryRequiredstringOne of sandbox, live

Responses

200Exact published incident and its scope.application/json
400Request validation failed.application/problem+json
404Resource is absent or belongs to another merchant.application/problem+json
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+json
500The 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
503Dependency or rail is unavailable; retry safely where documented.application/problem+json

Public contact

1
POST/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 · PublicContactCreate

Responses

202The encrypted enquiry was durably accepted for review.application/json
303A 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+json
409Idempotency or lifecycle conflict.application/problem+json
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+json
500The 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
503Dependency or rail is unavailable; retry safely where documented.application/problem+json

Notifications

1
GET/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

NameLocationRequirementDescription
limitqueryOptionalintegerFrom 1 to 100 · Default 20
starting_afterqueryOptionalstring
categoryqueryOptionalRestrict the archive to one source-routing category.stringOne of incident, developers, money, account, data
action_requiredqueryOptionalRestrict the archive to notices that do or do not require merchant action.boolean
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Responses

200Merchant notification archive with deterministic newest-first continuation.application/json
400Request validation failed.application/problem+json
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+json
403Scope 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+json
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+json
500The 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

Events

4
GET/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

NameLocationRequirementDescription
limitqueryOptionalintegerFrom 1 to 100 · Default 20
starting_afterqueryOptionalstring
typequeryOptionalExact event name or one trailing wildcard, such as payment_intent.*.stringUp to 128 characters
related_objectqueryOptionalA payment intent, refund, checkout session, or settlement identifier.stringPattern ^(pi|re|cs|se)_[A-Za-z0-9]+$
created[gte]queryOptionalInclusive RFC 3339 lower bound.string · date-time
created[lte]queryOptionalInclusive RFC 3339 upper bound.string · date-time
ending_beforequeryOptionalIn 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
orderqueryOptional`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_eventqueryOptionalEvents written after this one, oldest first. Implies `order=asc`.stringUp to 128 characters · Pattern ^evt_[A-Za-z0-9]+$
Perion-VersionheaderOptionalstringPattern ^\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/json
400Request validation failed.application/problem+json
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+json
403Scope 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+json
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+json
500The 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
GET/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

NameLocationRequirementDescription
event_idpathRequiredstringPattern ^evt_[A-Za-z0-9]+$
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Responses

200Exact stored event envelope.application/json
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+json
403Scope 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+json
404Resource is absent or belongs to another merchant.application/problem+json
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+json
500The 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
GET/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

NameLocationRequirementDescription
event_idpathRequiredstringPattern ^evt_[A-Za-z0-9]+$
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Responses

200Tenant- and environment-scoped webhook delivery evidence.application/json
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+json
403Scope 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+json
404Resource is absent or belongs to another merchant.application/problem+json
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+json
500The 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
POST/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

NameLocationRequirementDescription
event_idpathRequiredstringPattern ^evt_[A-Za-z0-9]+$
Idempotency-KeyheaderRequiredStable opaque key for this semantic command. Reuse it after timeouts.string16–255 characters
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Request body Optional

application/json · EventReplayCreate

Responses

202Eligible deliveries were enqueued.application/json
400Request validation failed.application/problem+json
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+json
403Scope 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+json
404Resource is absent or belongs to another merchant.application/problem+json
409Idempotency or lifecycle conflict.application/problem+json
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+json
500The 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

Webhook endpoints

6
POST/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

NameLocationRequirementDescription
Idempotency-KeyheaderRequiredStable opaque key for this semantic command. Reuse it after timeouts.string16–255 characters
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Request body Required

application/json · WebhookEndpointCreate

Responses

200Exact replay of a previously committed create command.application/json
201Endpoint and one-time signing secret.application/json
400Request validation failed.application/problem+json
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+json
409Idempotency or lifecycle conflict.application/problem+json
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+json
500The 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
GET/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

NameLocationRequirementDescription
starting_afterqueryOptionalstring
limitqueryOptionalintegerFrom 1 to 100 · Default 20
statusqueryOptionalstringOne of enabled, disabled
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Responses

200Merchant endpoints; signing secrets are omitted.application/json
400Request validation failed.application/problem+json
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+json
403Scope 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+json
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+json
500The 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
GET/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

NameLocationRequirementDescription
webhook_endpoint_idpathRequiredstringPattern ^we_[A-Za-z0-9]+$
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Responses

200Current endpoint configuration without its signing secret.application/json
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+json
404Resource is absent or belongs to another merchant.application/problem+json
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+json
500The 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
POST/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

NameLocationRequirementDescription
webhook_endpoint_idpathRequiredstringPattern ^we_[A-Za-z0-9]+$
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15
Idempotency-KeyheaderRequiredStable opaque key for this semantic command. Reuse it after timeouts.string16–255 characters

Request body Required

application/json · WebhookEndpointUpdate

Responses

200Updated endpoint configuration.application/json
400Request validation failed.application/problem+json
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+json
404Resource is absent or belongs to another merchant.application/problem+json
409Idempotency or lifecycle conflict.application/problem+json
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+json
500The 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
DELETE/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

NameLocationRequirementDescription
webhook_endpoint_idpathRequiredstringPattern ^we_[A-Za-z0-9]+$
Perion-VersionheaderOptionalstringPattern ^\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+json
404Resource is absent or belongs to another merchant.application/problem+json
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+json
500The 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
POST/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

NameLocationRequirementDescription
webhook_endpoint_idpathRequiredstringPattern ^we_[A-Za-z0-9]+$
Idempotency-KeyheaderRequiredStable opaque key for this semantic command. Reuse it after timeouts.string16–255 characters
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Request body Optional

application/json · WebhookSecretRotate

Responses

200Endpoint and newly issued signing secret.application/json
400Request validation failed.application/problem+json
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+json
404Resource is absent or belongs to another merchant.application/problem+json
409Idempotency or lifecycle conflict.application/problem+json
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+json
500The 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

Event delivery

3
GET/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

NameLocationRequirementDescription
webhook_endpoint_idpathRequiredstringPattern ^we_[A-Za-z0-9]+$
latest_onlyqueryOptionalWhen 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
limitqueryOptionalintegerFrom 1 to 100 · Default 20
starting_afterqueryOptionalstring
outcomequeryOptionalstringOne of undelivered, delivered, failing, dead_lettered, cancelled
typequeryOptionalExact event name or one trailing wildcard, such as payment_intent.*.stringUp to 128 characters
occurred[gte]queryOptionalInclusive event-occurrence lower bound as an RFC 3339 instant.string · date-time
occurred[lte]queryOptionalInclusive event-occurrence upper bound as an RFC 3339 instant.string · date-time
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Responses

200Filtered health aggregate and deterministic endpoint-delivery page.application/json
400Request validation failed.application/problem+json
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+json
403Scope 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+json
404Resource is absent or belongs to another merchant.application/problem+json
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+json
500The 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
POST/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

NameLocationRequirementDescription
webhook_endpoint_idpathRequiredstringPattern ^we_[A-Za-z0-9]+$
Idempotency-KeyheaderRequiredStable opaque key for this semantic command. Reuse it after timeouts.string16–255 characters
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Request body Required

application/json · EndpointBulkReplayCreate

Responses

202One new pending logical delivery was durably queued for each reviewed event.application/json
400Request validation failed.application/problem+json
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+json
403Scope 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+json
404Resource is absent or belongs to another merchant.application/problem+json
409Idempotency or lifecycle conflict.application/problem+json
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+json
500The 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
GET/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

NameLocationRequirementDescription
webhook_replay_batch_idpathRequiredstringPattern ^wrb_[A-Za-z0-9]+$
Perion-VersionheaderOptionalstringPattern ^\d{4}-\d{2}-\d{2}$ · Default 2026-07-15

Responses

200Merchant- and environment-scoped replay progress.application/json
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+json
403Scope 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+json
404Resource is absent or belongs to another merchant.application/problem+json
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+json
500The 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

Sandbox callback ingress

1
POST/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

NameLocationRequirementDescription
provider_codepathRequiredProvider-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_idpathRequiredstringPattern ^pra_[A-Za-z0-9]+$
Perion-Sandbox-SignatureheaderRequiredComma-separated `t=<unix>,v1=<hex HMAC-SHA256>` over `t.body`; maximum skew is five minutes.stringUp to 512 characters

Request body Required

application/json · SandboxProviderCallback

Responses

204Authenticated receipt retained for asynchronous normalization.
400Request validation failed.application/problem+json
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+json
404Resource is absent or belongs to another merchant.application/problem+json
409Idempotency or lifecycle conflict.application/problem+json
413Callback 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+json
500The 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
503Dependency or rail is unavailable; retry safely where documented.application/problem+json

Health

3
GET/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/json
405The 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+json
500The 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
GET/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/json
405The 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+json
500The 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
503A dependency is unavailable, so the process must not receive traffic.application/json
GET/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/json
405The 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+json
500The 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
Next: Changelog