API reference menu

API reference · v0.11.3

Phala Pay API

Phala Pay is a non-custodial crypto payments API for merchants: quotes and deposit addresses, deposits credited at a small confirmation depth and watched to finality, refunds you pay from your treasury, and webhooks signed with a key bound to a TDX attestation. The integration guide walks through an integration end to end.

Production: USDC and USDT on Ethereum, USDC on Base; live and test mode
https://pay-api.phala.com
Staging: Sepolia, for integration tests
https://pay-api-staging.phala.com

Authentication

Send an API key as Authorization: Bearer ppay_rk_test_… (test mode) or ppay_rk_live_… (live mode). A restricted key (ppay_rk_, Stripe) holds only the permissions it was created with and never manages keys, treasuries, webhook endpoints, webhook keys, or account settings: run production with one. A secret key (ppay_sk_) holds every permission; keep it offline, for administration. The key selects the account and the mode; every object carries livemode, and a key never sees the other mode's objects.

Request ids

Every response carries Request-Id: req_… (Stripe). Quote it when you contact support. An event caused by an API request names it in request.id, with the Idempotency-Key the request sent.

Idempotent requests

Every POST accepts an Idempotency-Key of up to 255 characters (Stripe). For 24 hours a repeat of the same request returns the first response, with Idempotent-Replayed: true, whatever it was, including a 500, so a retry never runs a request twice; a repeat with another request is 400 idempotency_key_reused, and one while the first still runs is 409 idempotency_key_in_use. A request that did not execute is not saved and runs again on a retry: one that failed validation (parameter_*), was rate limited (429), or met 503 unavailable.

Pagination

Lists are newest first with Stripe's cursor pagination (Stripe): limit (1 to 100, default 10), and starting_after or ending_before, the id of an object of the list; has_more says whether more follow. Lists with a created filter take created[gt], created[gte], created[lt], and created[lte] in Unix seconds.

Events

Every change is an event, delivered to your webhook endpoints and listed by GET /v1/events (Stripe). data.object is the object as it was when the event happened, rendered with the change and never changed afterwards; *.updated events add data.previous_attributes. Deliveries are retried until delivered and never given up on; a webhook endpoint's pending_deliveries, oldest_pending_at, and last_attempt show whether it is keeping up, and GET /v1/events?delivery_success=false lists what it has not received.

Errors

Errors are Stripe's error object (Stripe): {"error": {"type", "code", "message", "param", "doc_url"}}. 400 means the request cannot succeed as sent or in the objects' current state, 401 authentication, 403 permission, 404 a missing object, 409 only an Idempotency-Key still in use, 429 too many requests (with Retry-After in seconds), and 5xx the service. Branch on code; message may change.

refund_attachment_limit_exceeded

422. The environment has a configured attached-pending refund limit (production 2, staging 1), and permits one new attachment per rolling 24 hours, across all merchants and modes. This is not retryable; contact the operator before sending or attaching another payout. The refund stays pending and reserved. Repeating the same attachment does not consume quota; existing attachments continue verification.

address_capacity_reached

422. The chain has reached its permanent pilot limit of 1,000 issued addresses, including retired and expired addresses. This is not retryable; the operator must upgrade the scanning/provider plan before issuing more.

chain_unavailable

503. The requested chain is temporarily not ready. Retry after the indicated delay.

price_unavailable

503. Fresh dual-source prices are unavailable or the UTC daily snapshot cap is exhausted. Retry after the indicated delay; no stale price is returned.

parameter_invalid

400. A parameter is malformed or out of range; param names it. Fix the request.

parameter_missing

400. A required parameter is absent; param names it.

parameter_unknown

400. The operation does not take a parameter the request sent; param names it.

amount_too_small

400. The amount is below the minimum of the route, or nothing is left to refund.

amount_too_large

400. The amount is above the route's maximum deposit, or above what is left to refund.

exposure_cap_exceeded

400. The quote would take the open quotes of your account in this mode past a cap: their number (max_open_quotes of GET /v1/config), their credit (max_open_amount_per_account), or one customer's credit (max_open_amount_per_customer). Wait for quotes to be paid, expire, or be canceled, or ask the operator to raise the cap.

paused

400. A pause of the account, the customer, or the route blocks the operation (quotes, settlement, or refunds). Your own quotes pause lifts with POST /v1/account/resume; the operator lifts its own.

chain_frozen

400. Reconciliation froze the chain pending the operator's review; no quote is issued on it until the operator lifts the block.

asset_not_accepted

400. Your payment settings do not accept the asset on the chain in this mode, or accept nothing yet (GET /v1/payment_settings): quote an asset GET /v1/config lists, or accept it with POST /v1/payment_settings.

payment_settings_unconfirmed

400. After a restore of the service, your payment settings wait for your reconfirmation: send your complete configuration with POST /v1/payment_settings.

treasury_not_set

400. The account has no treasury on the chain: POST /v1/treasuries/challenge, then POST /v1/treasuries.

treasury_proof_invalid

400. The treasury proof does not prove the address: the message is not the challenge, or the signature does not verify.

treasury_challenge_expired

400. The treasury challenge expired; request a new one.

treasury_challenge_used

400. The treasury challenge was already used; request a new one.

treasury_not_deployed

400. The signature does not recover to the address and no contract is deployed there at the chain's finalized block; deploy the Safe first (ERC-6492 signatures are refused).

treasury_sanctioned

400. A sanctions list names the treasury address.

treasury_change_pending

400. A treasury change is already pending on the chain; cancel it first.

treasury_unchanged

400. The address is already the chain's treasury.

treasury_unexpected_state

400. Only a pending treasury can be canceled.

quote_payment_received

400. The quote's address already received a payment, so the quote cannot be canceled.

quote_window_closed

400. The quote's payment window has closed, so it cannot be canceled; it expires on its own.

quote_unexpected_state

400. The quote is complete or expired; only an open quote can be canceled.

deposit_unexpected_state

400. Admin: only a deposit the pump processes, detected or confirmed, can be nudged; a credited deposit waits for its sweep, which only a finalized Flushed event records.

deposit_not_refundable

400. The deposit cannot be refunded: it is not credited or rejected, or it was reversed.

deposit_not_final

400. The deposit is not final yet and could still be reversed; request the refund once final is true (about 15 minutes after its block on Ethereum).

destination_sanctioned

400. A sanctions list names the refund's destination address.

transfer_already_used

400. The transfer log already pays another refund.

refund_unexpected_state

400. The refund's status does not allow the action: it is not pending, it is already marked paid with another transaction, or, being marked paid, it cannot be canceled.

api_key_inactive

400. The API key is revoked or already rolled.

last_api_key

400. The account's last active key of the mode cannot be revoked; create or roll a key first.

deposit_address_cap_exceeded

400. The account has its maximum of active deposit addresses in the mode.

deposit_address_retired

400. The deposit address is retired; rotate the customer's active address instead.

webhook_endpoint_cap_exceeded

400. The account has 16 webhook endpoints in the mode; delete one first.

webhook_endpoint_disabled

400. The webhook endpoint is disabled; enable it before resending events to it.

idempotency_key_reused

400. The Idempotency-Key was used with a different request (type idempotency_error). Use a new key for a new request.

signature_invalid

401. Admin API only: the RFC 9421 request signature did not verify.

signature_replayed

401. Admin API only: the request signature was already used; sign the request again.

api_key_missing

401. No Authorization: Bearer header with an API key (ppay_rk_… or ppay_sk_…).

api_key_invalid

401. The API key is malformed, unknown, or revoked.

api_key_expired

401. The API key was rolled and its overlap has ended; use the key it was rolled to.

permission_denied

403. The key may not make this request: a restricted key lacks the permission, or the request manages keys, treasuries, webhook endpoints, webhook keys, or account settings, which needs a secret key.

testmode_charges_only

403. The account is not enabled for live mode; use a test key until the operator enables it.

resource_missing

404. No such object in the key's account and mode.

idempotency_key_in_use

409. A request with this Idempotency-Key is still running (type idempotency_error); retry shortly with the same key. The only 409.

rate_limit

429. Too many requests of the account and mode (100 per second live, 25 test), or reads of one quote's or deposit address's public view. Retry after Retry-After seconds, with exponential backoff.

customer_rate_limit

429. The customer made too many quotes in the last minute, or rotated its deposit address too often in the last hour. Retry after Retry-After seconds.

internal_error

500. The service failed. Retry with the same Idempotency-Key: a request that started executing replays this response, so it never runs twice; a new key runs it again.

unavailable

503. A dependency (pricing, sanctions screening, attestation) is temporarily unavailable. Retry with backoff; the same Idempotency-Key runs the request again.

service_maintenance

503. A planned upgrade temporarily pauses new mutations. Reads continue while the process is up. Retry after Retry-After with the same Idempotency-Key; the request has not executed. The pause expires automatically if deployment fails.

service_restoring

503. The service was restored from backup and is frozen until the operator has reconciled it with you: every request with an API key is refused, reads too, and nothing is credited or delivered meanwhile. Retry after Retry-After seconds; the operator contacts you for your records since the restore point.

restore_not_frozen

400. Admin API only: a restore reconciliation action needs the service frozen after a restore.

restore_rescan_incomplete

400. Admin API only: a chain is not rescanned since the restore (GET /v1/admin/restore); the freeze cannot be lifted yet.

Quotes

A locked price and a single-use address for one payment.

List quotes

get/v1/quotes

The account's quotes in the key's mode, newest first, with Stripe's cursor pagination.

Query parameters

client_reference_idstring

Only this customer's quotes

statusstring

open, complete, expired, or canceled

limitinteger (int64)

1 to 100, default 10

starting_afterstring

qt_ id: the page after it

ending_beforestring

qt_ id: the page before it

Responses

200

OK

Returns QuoteList

400

Bad Request

401

Unauthorized

403

permission_denied: the key lacks this permission, or testmode_charges_only: live mode is not enabled

429

rate_limit: retry after Retry-After seconds

503

unavailable: temporary service or database unavailability; service_restoring: restore reconciliation is in progress. Retry-After, when present, is the minimum delay in seconds

Request
curl \  https://pay-api.phala.com/v1/quotes \  -H "Authorization: Bearer $PHALA_PAY_API_KEY"

Response 200: QuoteList

Create quote

post/v1/quotes

Quotes amount cents payable in asset on chain_id: a locked price, the exact token amount, and a single-use address, valid until expires_at, on the terms your payment settings set for the asset; the quote keeps them for good. An asset your settings do not accept is asset_not_accepted.

Headers

Idempotency-Keystring or null

Up to 255 characters; for 24 hours a repeat of the same request returns the first response, and of another request is 400 idempotency_error.

Request body · CreateQuoteRequest

amountinteger (int64)required

The credit to quote, a positive integer in the currency's minor unit (US cents).

assetstringrequired

Asset code of the payment on that chain, such as usdc.

chain_idinteger (int64)required

EVM chain of the payment, one of GET /v1/config assets[].chain_id.

client_reference_idstringrequired

Your identifier of the customer to credit, 1 to 200 characters (Stripe Checkout's client_reference_id); the customer is created on first use.

currencystringrequired

Lowercase ISO currency code; only usd.

metadataMetadataParam

Stripe's metadata: up to 50 string key/value pairs for your own use, keys of up to 40 characters without square brackets, values of up to 500 characters. A key set to "" is omitted. The deposit that pays the quote starts with a copy of it. Phala Pay never reads it. Do not store sensitive information in it, such as personal or payment details.

Responses

200

OK

Returns Quote

400

Bad Request, asset_not_accepted, payment_settings_unconfirmed, amount_too_small, amount_too_large, exposure_cap_exceeded, paused, chain_frozen, or treasury_not_set

401

Unauthorized

403

permission_denied: the key lacks this permission, or testmode_charges_only: live mode is not enabled

409

idempotency_key_in_use: a request with this Idempotency-Key is still running; retry with the same key

422

Permanent chain address_capacity_reached; not retryable

429

rate_limit, or customer_rate_limit: the customer's quotes per minute; retry after Retry-After seconds

503

chain_unavailable, price_unavailable or Service Unavailable

Request
curl -X POST \  https://pay-api.phala.com/v1/quotes \  -H "Authorization: Bearer $PHALA_PAY_API_KEY" \  -H "Content-Type: application/json" \  -d '{    "amount": 2500,    "asset": "usdc",    "chain_id": 1,    "client_reference_id": "team-42",    "currency": "usd",    "metadata": {      "order_id": "ord_1001"    }  }'

Response 200: Quote

Get quote

get/v1/quotes/{id}

One quote, for example to resume a checkout page. The payer's browser can read the quote's public view with its client_secret instead of an API key, as Stripe.js reads a PaymentIntent.

Path parameters

idstringrequired

Quote id, qt_…

Query parameters

expand[]array of string

deposit; API key requests only

client_secretstring

The quote's client_secret, to read its public view without an API key. Send the request without Authorization; the response then allows any origin.

Responses

200

OK: a Quote to a request with an API key, a ClientQuote to a request by client_secret

Returns QuoteView

401

Unauthorized

403

permission_denied: the key lacks this permission, or testmode_charges_only: live mode is not enabled

404

Not Found, also for a client_secret that is not this quote's

429

Too Many Requests: reads by client_secret

503

unavailable: temporary service or database unavailability; service_restoring: restore reconciliation is in progress. Retry-After, when present, is the minimum delay in seconds

Request
curl \  https://pay-api.phala.com/v1/quotes/{id} \  -H "Authorization: Bearer $PHALA_PAY_API_KEY"

Response 200: QuoteView

Update quote

post/v1/quotes/{id}

Updates a quote's metadata, in any status; parameters not sent are left unchanged.

Path parameters

idstringrequired

Quote id, qt_…

Headers

Idempotency-Keystring or null

Up to 255 characters; for 24 hours a repeat of the same request returns the first response, and of another request is 400 idempotency_error.

Request body · UpdateMetadataRequest

metadataMetadataParam

Stripe's metadata: up to 50 string key/value pairs for your own use, keys of up to 40 characters without square brackets, values of up to 500 characters. Merged into the object's: a key set to a value is set, a key set to "" is unset, other keys are kept, and metadata: "" unsets every key. Phala Pay never reads it. Do not store sensitive information in it, such as personal or payment details.

Responses

200

OK

Returns Quote

400

Bad Request

401

Unauthorized

403

permission_denied: the key lacks this permission, or testmode_charges_only: live mode is not enabled

404

Not Found

409

idempotency_key_in_use: a request with this Idempotency-Key is still running; retry with the same key

429

rate_limit: retry after Retry-After seconds

503

unavailable: temporary service or database unavailability; service_restoring: restore reconciliation is in progress. Retry-After, when present, is the minimum delay in seconds

Request
curl -X POST \  https://pay-api.phala.com/v1/quotes/{id} \  -H "Authorization: Bearer $PHALA_PAY_API_KEY" \  -H "Content-Type: application/json" \  -d '{    "metadata": {      "note": "",      "order_id": "ord_1001"    }  }'

Response 200: Quote

Cancel quote

post/v1/quotes/{id}/cancel

Cancels an open, unpaid quote; a canceled quote is returned unchanged. Later payments to its address are credited at spot.

Path parameters

idstringrequired

Quote id, qt_…

Headers

Idempotency-Keystring or null

Up to 255 characters; for 24 hours a repeat of the same request returns the first response, and of another request is 400 idempotency_error.

Responses

200

OK

Returns Quote

400

quote_payment_received: the address already received a payment; quote_window_closed: past expires_at; quote_unexpected_state: complete or expired

401

Unauthorized

403

permission_denied: the key lacks this permission, or testmode_charges_only: live mode is not enabled

404

Not Found

409

idempotency_key_in_use: a request with this Idempotency-Key is still running; retry with the same key

429

rate_limit: retry after Retry-After seconds

503

unavailable: temporary service or database unavailability; service_restoring: restore reconciliation is in progress. Retry-After, when present, is the minimum delay in seconds

Request
curl -X POST \  https://pay-api.phala.com/v1/quotes/{id}/cancel \  -H "Authorization: Bearer $PHALA_PAY_API_KEY"

Response 200: Quote

Submit quote transaction

post/v1/quotes/{id}/transactions

Submit a quote transaction hint. The stored quote selects the chain and recipient.

Path parameters

idstringrequired

Quote identifier

Query parameters

client_secretstring

Object's browser client secret; omit with a merchant key

Request body · SubmitQuoteTransactionRequest

transaction_hashstringrequired

Transaction hash, exactly 32 hexadecimal bytes prefixed by 0x.

Responses

202

Received, including ignored hints. No payment result is disclosed.

Returns TransactionSubmission

Request
curl -X POST \  https://pay-api.phala.com/v1/quotes/{id}/transactions \  -H "Authorization: Bearer $PHALA_PAY_API_KEY" \  -H "Content-Type: application/json" \  -d '{    "transaction_hash": "0x7d3c1e5a9b2f4d6c8e0a1b3d5f7c9e2a4b6d8f0c1e3a5b7d9f1c3e5a7b9d1f3e"  }'

Response 202: TransactionSubmission

Deposit addresses

A customer's persistent address, credited at spot on every chain and asset.

List deposit addresses

get/v1/deposit_addresses

The account's deposit addresses in the key's mode, newest first, with Stripe's cursor pagination.

Query parameters

client_reference_idstring

Only this customer's addresses

statusstring

active or retired

limitinteger (int64)

1 to 100, default 10

starting_afterstring

da_ id: the page after it

ending_beforestring

da_ id: the page before it

Responses

200

OK

Returns DepositAddressList

400

Bad Request

401

Unauthorized

403

permission_denied: the key lacks this permission, or testmode_charges_only: live mode is not enabled

429

rate_limit: retry after Retry-After seconds

503

unavailable: temporary service or database unavailability; service_restoring: restore reconciliation is in progress. Retry-After, when present, is the minimum delay in seconds

Request
curl \  https://pay-api.phala.com/v1/deposit_addresses \  -H "Authorization: Bearer $PHALA_PAY_API_KEY"

Response 200: DepositAddressList

Create deposit address

post/v1/deposit_addresses

Returns the customer's active deposit address, one address for every token your payment settings accept on every network of the key's mode where you have a treasury (an account that accepts nothing gets asset_not_accepted), issuing it if the customer has none: the same request always returns the same address until it is rotated. It also adds the address's network on a chain supported, or given a treasury, since it was issued, and replaces a chain's network whose treasury changed.

Headers

Idempotency-Keystring or null

Up to 255 characters; for 24 hours a repeat of the same request returns the first response, and of another request is 400 idempotency_error.

Request body · CreateDepositAddressRequest

client_reference_idstringrequired

Your identifier of the customer, 1 to 200 characters; the customer is created on first use.

metadataMetadataParam

Stripe's metadata: up to 50 string key/value pairs for your own use, keys of up to 40 characters without square brackets, values of up to 500 characters. Merged into the returned address's, as POST /v1/deposit_addresses/{id} does: a key set to "" is unset. Every deposit to the address starts with a copy of it, and a rotation carries it to the next version. Phala Pay never reads it. Do not store sensitive information in it, such as personal or payment details.

Responses

200

OK

Returns DepositAddress

400

Bad Request, asset_not_accepted (your payment settings accept nothing in this mode), payment_settings_unconfirmed, deposit_address_cap_exceeded, paused, chain_frozen (a new address and every chain is frozen or paused), or treasury_not_set (no treasury on any chain that takes one)

401

Unauthorized

403

permission_denied: the key lacks this permission, or testmode_charges_only: live mode is not enabled

409

idempotency_key_in_use: a request with this Idempotency-Key is still running; retry with the same key

422

Permanent chain address_capacity_reached; not retryable

429

rate_limit: retry after Retry-After seconds

503

unavailable: temporary service or database unavailability; service_restoring: restore reconciliation is in progress. Retry-After, when present, is the minimum delay in seconds

Request
curl -X POST \  https://pay-api.phala.com/v1/deposit_addresses \  -H "Authorization: Bearer $PHALA_PAY_API_KEY" \  -H "Content-Type: application/json" \  -d '{    "client_reference_id": "team-42",    "metadata": {      "plan": "pro"    }  }'

Response 200: DepositAddress

Get deposit address

get/v1/deposit_addresses/{id}

One deposit address. The customer's page can read the address's public view, with the payments seen and credited in the last 24 hours, by a client_secret instead of an API key, as a quote's page does.

Path parameters

idstringrequired

Deposit address id, da_…

Query parameters

client_secretstring

A client_secret of the address, to read its public view without an API key. Send the request without Authorization; the response then allows any origin.

Responses

200

OK: a DepositAddress to a request with an API key, a ClientDepositAddress to a request by client_secret

Returns DepositAddressView

401

Unauthorized

403

permission_denied: the key lacks this permission, or testmode_charges_only: live mode is not enabled

404

Not Found, also for a client_secret that is not this address's

429

Too Many Requests: reads by client_secret

503

unavailable: temporary service or database unavailability; service_restoring: restore reconciliation is in progress. Retry-After, when present, is the minimum delay in seconds

Request
curl \  https://pay-api.phala.com/v1/deposit_addresses/{id} \  -H "Authorization: Bearer $PHALA_PAY_API_KEY"

Response 200: DepositAddressView

Update deposit address

post/v1/deposit_addresses/{id}

Updates a deposit address's metadata, active or retired; parameters not sent are left unchanged. Deposits already recorded keep their own copy.

Path parameters

idstringrequired

Deposit address id, da_…

Headers

Idempotency-Keystring or null

Up to 255 characters; for 24 hours a repeat of the same request returns the first response, and of another request is 400 idempotency_error.

Request body · UpdateMetadataRequest

metadataMetadataParam

Stripe's metadata: up to 50 string key/value pairs for your own use, keys of up to 40 characters without square brackets, values of up to 500 characters. Merged into the object's: a key set to a value is set, a key set to "" is unset, other keys are kept, and metadata: "" unsets every key. Phala Pay never reads it. Do not store sensitive information in it, such as personal or payment details.

Responses

200

OK

Returns DepositAddress

400

Bad Request

401

Unauthorized

403

permission_denied: the key lacks this permission, or testmode_charges_only: live mode is not enabled

404

Not Found

409

idempotency_key_in_use: a request with this Idempotency-Key is still running; retry with the same key

429

rate_limit: retry after Retry-After seconds

503

unavailable: temporary service or database unavailability; service_restoring: restore reconciliation is in progress. Retry-After, when present, is the minimum delay in seconds

Request
curl -X POST \  https://pay-api.phala.com/v1/deposit_addresses/{id} \  -H "Authorization: Bearer $PHALA_PAY_API_KEY" \  -H "Content-Type: application/json" \  -d '{    "metadata": {      "note": "",      "order_id": "ord_1001"    }  }'

Response 200: DepositAddress

Rotate deposit address

post/v1/deposit_addresses/{id}/rotate

Retires an active deposit address and returns the customer's new one, a new address on every network. Payments to the retired address are still credited at spot; stop showing it.

Path parameters

idstringrequired

Deposit address id, da_…

Headers

Idempotency-Keystring or null

Up to 255 characters; for 24 hours a repeat of the same request returns the first response, and of another request is 400 idempotency_error.

Responses

200

OK: the new active address

Returns DepositAddress

400

deposit_address_retired: already rotated; paused, chain_frozen (every chain is frozen or paused), asset_not_accepted, payment_settings_unconfirmed, or treasury_not_set

401

Unauthorized

403

permission_denied: the key lacks this permission, or testmode_charges_only: live mode is not enabled

404

Not Found

409

idempotency_key_in_use: a request with this Idempotency-Key is still running; retry with the same key

422

Permanent chain address_capacity_reached; not retryable

429

rate_limit, or customer_rate_limit: the customer's rotations per hour; retry after Retry-After seconds

503

unavailable: temporary service or database unavailability; service_restoring: restore reconciliation is in progress. Retry-After, when present, is the minimum delay in seconds

Request
curl -X POST \  https://pay-api.phala.com/v1/deposit_addresses/{id}/rotate \  -H "Authorization: Bearer $PHALA_PAY_API_KEY"

Response 200: DepositAddress

Submit deposit address transaction

post/v1/deposit_addresses/{id}/transactions

Submit a deposit-address transaction hint on one of its issued networks.

Path parameters

idstringrequired

Deposit-address identifier

Query parameters

client_secretstring

Object's browser client secret; omit with a merchant key

Request body · SubmitDepositAddressTransactionRequest

chain_idinteger (int64)required

One of this object's issued network identifiers.

transaction_hashstringrequired

Transaction hash, exactly 32 hexadecimal bytes prefixed by 0x.

Responses

202

Received, including ignored hints. No payment result is disclosed.

Returns TransactionSubmission

Request
curl -X POST \  https://pay-api.phala.com/v1/deposit_addresses/{id}/transactions \  -H "Authorization: Bearer $PHALA_PAY_API_KEY" \  -H "Content-Type: application/json" \  -d '{    "chain_id": 84532,    "transaction_hash": "0x7d3c1e5a9b2f4d6c8e0a1b3d5f7c9e2a4b6d8f0c1e3a5b7d9f1c3e5a7b9d1f3e"  }'

Response 202: TransactionSubmission

Deposits

Payments recorded on chain: credited, rejected, or reversed, and when they are final.

List deposits

get/v1/deposits

The account's deposits in the credential's mode, newest first, with Stripe's cursor pagination.

Query parameters

client_reference_idstring

Only this customer's deposits

quotestring

Only deposits to this quote's address

deposit_addressstring

Only deposits to this deposit address, da_…

statusstring

Only deposits in this status: pending, credited, rejected, or reversed

tx_hashstring

Only deposits in this transaction

created[gt]integer (int64)

Created after, Unix seconds

created[gte]integer (int64)

Created at or after, Unix seconds

created[lt]integer (int64)

Created before, Unix seconds

created[lte]integer (int64)

Created at or before, Unix seconds

limitinteger (int64)

1 to 100, default 10

starting_afterstring

dep_ id: the page after it

ending_beforestring

dep_ id: the page before it

expand[]array of string

data.quote

Responses

200

OK

Returns DepositList

400

Bad Request

401

Unauthorized

403

permission_denied: the key lacks this permission, or testmode_charges_only: live mode is not enabled

429

rate_limit: retry after Retry-After seconds

503

unavailable: temporary service or database unavailability; service_restoring: restore reconciliation is in progress. Retry-After, when present, is the minimum delay in seconds

Request
curl \  https://pay-api.phala.com/v1/deposits \  -H "Authorization: Bearer $PHALA_PAY_API_KEY"

Response 200: DepositList

Get deposit

get/v1/deposits/{id}

One deposit.

Path parameters

idstringrequired

Deposit id, dep_…

Query parameters

expand[]array of string

quote

Responses

200

OK

Returns Deposit

401

Unauthorized

403

permission_denied: the key lacks this permission, or testmode_charges_only: live mode is not enabled

404

Not Found

429

rate_limit: retry after Retry-After seconds

503

unavailable: temporary service or database unavailability; service_restoring: restore reconciliation is in progress. Retry-After, when present, is the minimum delay in seconds

Request
curl \  https://pay-api.phala.com/v1/deposits/{id} \  -H "Authorization: Bearer $PHALA_PAY_API_KEY"

Response 200: Deposit

Update deposit

post/v1/deposits/{id}

Updates a deposit's metadata; parameters not sent are left unchanged. The quote's metadata is not changed.

Path parameters

idstringrequired

Deposit id, dep_…

Headers

Idempotency-Keystring or null

Up to 255 characters; for 24 hours a repeat of the same request returns the first response, and of another request is 400 idempotency_error.

Request body · UpdateMetadataRequest

metadataMetadataParam

Stripe's metadata: up to 50 string key/value pairs for your own use, keys of up to 40 characters without square brackets, values of up to 500 characters. Merged into the object's: a key set to a value is set, a key set to "" is unset, other keys are kept, and metadata: "" unsets every key. Phala Pay never reads it. Do not store sensitive information in it, such as personal or payment details.

Responses

200

OK

Returns Deposit

400

Bad Request

401

Unauthorized

403

permission_denied: the key lacks this permission, or testmode_charges_only: live mode is not enabled

404

Not Found

409

idempotency_key_in_use: a request with this Idempotency-Key is still running; retry with the same key

429

rate_limit: retry after Retry-After seconds

503

unavailable: temporary service or database unavailability; service_restoring: restore reconciliation is in progress. Retry-After, when present, is the minimum delay in seconds

Request
curl -X POST \  https://pay-api.phala.com/v1/deposits/{id} \  -H "Authorization: Bearer $PHALA_PAY_API_KEY" \  -H "Content-Type: application/json" \  -d '{    "metadata": {      "note": "",      "order_id": "ord_1001"    }  }'

Response 200: Deposit

Refunds

Refunds you pay from your treasury and attach with mark_paid.

List refunds

get/v1/refunds

The account's refunds in the key's mode, newest first, with Stripe's cursor pagination.

Query parameters

depositstring

Only this deposit's refunds, dep_…

statusstring

pending, succeeded, failed, or canceled

limitinteger (int64)

1 to 100, default 10

starting_afterstring

re_ id: the page after it

ending_beforestring

re_ id: the page before it

Responses

200

OK

Returns RefundList

400

Bad Request

401

Unauthorized

403

permission_denied: the key lacks this permission, or testmode_charges_only: live mode is not enabled

429

rate_limit: retry after Retry-After seconds

503

unavailable: temporary service or database unavailability; service_restoring: restore reconciliation is in progress. Retry-After, when present, is the minimum delay in seconds

Request
curl \  https://pay-api.phala.com/v1/refunds \  -H "Authorization: Bearer $PHALA_PAY_API_KEY"

Response 200: RefundList

Create refund

post/v1/refunds

Creates a pending refund of a final deposit (design D5): a rejected deposit other than a sanctioned or dust one, or a credited one. The amount, the unrefunded remainder by default, is reserved until the refund is canceled or fails. The destination must pass sanctions screening (400 destination_sanctioned). The merchant then pays it from the refund's treasury and attaches the transaction with mark_paid.

Headers

Idempotency-Keystring or null

Up to 255 characters; for 24 hours a repeat of the same request returns the first response, and of another request is 400 idempotency_error.

Request body · CreateRefundRequest

amount_atomicstring or null

Amount in base units, as a decimal string; the unrefunded remainder when absent.

depositstringrequired

dep_ id of the deposit to refund.

destination_addressstringrequired

Address the customer controls; never default it to the sender, which may be an exchange.

metadataMetadataParam

Stripe's metadata: up to 50 string key/value pairs for your own use, keys of up to 40 characters without square brackets, values of up to 500 characters. A key set to "" is omitted. Phala Pay never reads it. Do not store sensitive information in it, such as personal or payment details.

Responses

200

OK

Returns Refund

400

Bad Request, destination_sanctioned, amount_too_small, amount_too_large, deposit_not_refundable, deposit_not_final, or paused

401

Unauthorized

403

permission_denied: the key lacks this permission, or testmode_charges_only: live mode is not enabled

409

idempotency_key_in_use: a request with this Idempotency-Key is still running; retry with the same key

429

rate_limit: retry after Retry-After seconds

503

Destination screening is unavailable; retry

Request
curl -X POST \  https://pay-api.phala.com/v1/refunds \  -H "Authorization: Bearer $PHALA_PAY_API_KEY" \  -H "Content-Type: application/json" \  -d '{    "amount_atomic": "25000000",    "deposit": "dep_8a1f4e2b6c3d49e0a7b5c1d2e3f40516",    "destination_address": "0x1775c1326aa633546b0b5634ae2bef0ba7cbfc9a",    "metadata": {      "ticket": "support-311"    }  }'

Response 200: Refund

Get refund

get/v1/refunds/{id}

One refund.

Path parameters

idstringrequired

Refund id, re_…

Query parameters

expand[]array of string

deposit

Responses

200

OK

Returns Refund

401

Unauthorized

403

permission_denied: the key lacks this permission, or testmode_charges_only: live mode is not enabled

404

Not Found

429

rate_limit: retry after Retry-After seconds

503

unavailable: temporary service or database unavailability; service_restoring: restore reconciliation is in progress. Retry-After, when present, is the minimum delay in seconds

Request
curl \  https://pay-api.phala.com/v1/refunds/{id} \  -H "Authorization: Bearer $PHALA_PAY_API_KEY"

Response 200: Refund

Update refund

post/v1/refunds/{id}

Updates a refund's metadata, in any status; parameters not sent are left unchanged.

Path parameters

idstringrequired

Refund id, re_…

Headers

Idempotency-Keystring or null

Up to 255 characters; for 24 hours a repeat of the same request returns the first response, and of another request is 400 idempotency_error.

Request body · UpdateMetadataRequest

metadataMetadataParam

Stripe's metadata: up to 50 string key/value pairs for your own use, keys of up to 40 characters without square brackets, values of up to 500 characters. Merged into the object's: a key set to a value is set, a key set to "" is unset, other keys are kept, and metadata: "" unsets every key. Phala Pay never reads it. Do not store sensitive information in it, such as personal or payment details.

Responses

200

OK

Returns Refund

400

Bad Request

401

Unauthorized

403

permission_denied: the key lacks this permission, or testmode_charges_only: live mode is not enabled

404

Not Found

409

idempotency_key_in_use: a request with this Idempotency-Key is still running; retry with the same key

429

rate_limit: retry after Retry-After seconds

503

unavailable: temporary service or database unavailability; service_restoring: restore reconciliation is in progress. Retry-After, when present, is the minimum delay in seconds

Request
curl -X POST \  https://pay-api.phala.com/v1/refunds/{id} \  -H "Authorization: Bearer $PHALA_PAY_API_KEY" \  -H "Content-Type: application/json" \  -d '{    "metadata": {      "note": "",      "order_id": "ord_1001"    }  }'

Response 200: Refund

Cancel refund

post/v1/refunds/{id}/cancel

Cancels a pending refund that has no transaction attached and releases its reservation of the deposit; canceling a canceled refund returns it. Once mark_paid attached a transaction, the refund cannot be canceled, so that the deposit is never paid back twice: it stays reserved until dual-source finalized verification ends it, succeeded, or failed when the transaction does not pay it. A transaction never seen for 24 hours raises an alert and remains pending; contact the operator before taking any further refund action.

Path parameters

idstringrequired

Refund id, re_…

Headers

Idempotency-Keystring or null

Up to 255 characters; for 24 hours a repeat of the same request returns the first response, and of another request is 400 idempotency_error.

Responses

200

OK

Returns Refund

400

refund_unexpected_state: marked paid, succeeded, or failed

401

Unauthorized

403

permission_denied: the key lacks this permission, or testmode_charges_only: live mode is not enabled

404

Not Found

409

idempotency_key_in_use: a request with this Idempotency-Key is still running; retry with the same key

429

rate_limit: retry after Retry-After seconds

503

unavailable: temporary service or database unavailability; service_restoring: restore reconciliation is in progress. Retry-After, when present, is the minimum delay in seconds

Request
curl -X POST \  https://pay-api.phala.com/v1/refunds/{id}/cancel \  -H "Authorization: Bearer $PHALA_PAY_API_KEY"

Response 200: Refund

Mark refund paid

post/v1/refunds/{id}/mark_paid

Attaches the transaction that pays a pending refund, as BTCPay's payout mark-paid. At finalized, both providers must show a Transfer of the deposit's token from the refund's treasury to destination_address for exactly amount_atomic, in a log no other refund uses (receipt_log_index, or any such log when absent). Then the refund is succeeded and deposit.refunded is sent; otherwise it is failed with a failure_reason. Repeating the same transaction returns the refund. From here on the refund cannot be canceled: it is failed only when its transaction is proven not to pay it. Each environment has a configured attached-pending refund limit (production 2, staging 1), and permits one new attachment per rolling 24 hours across all accounts and modes. Repeating the same attachment consumes no quota. A limit refusal preserves the reservation; contact the operator before another payout.

Path parameters

idstringrequired

Refund id, re_…

Headers

Idempotency-Keystring or null

Up to 255 characters; for 24 hours a repeat of the same request returns the first response, and of another request is 400 idempotency_error.

Request body · MarkRefundPaidRequest

receipt_log_indexinteger (int64) or null

Position of the Transfer log that pays the refund among the logs of the transaction's receipt (0 for the first), not the block-wide logIndex, which changes if the transaction is re-included in another block; any matching log when absent.

transaction_hashstringrequired

Hash of the transaction that pays the refund from the treasury of the deposit's address.

Responses

200

OK

Returns Refund

400

Bad Request, refund_unexpected_state (not pending, or marked paid with another transaction), or transfer_already_used

401

Unauthorized

403

permission_denied: the key lacks this permission, or testmode_charges_only: live mode is not enabled

404

Not Found

409

idempotency_key_in_use: a request with this Idempotency-Key is still running; retry with the same key

422

Non-retryable refund_attachment_limit_exceeded; contact the operator. The reservation is preserved.

429

rate_limit: retry after Retry-After seconds

503

unavailable: temporary service or database unavailability; service_restoring: restore reconciliation is in progress. Retry-After, when present, is the minimum delay in seconds

Request
curl -X POST \  https://pay-api.phala.com/v1/refunds/{id}/mark_paid \  -H "Authorization: Bearer $PHALA_PAY_API_KEY" \  -H "Content-Type: application/json" \  -d '{    "receipt_log_index": 0,    "transaction_hash": "0x4b6d8f0a2c4e6a8c0e2b4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c"  }'

Response 200: Refund

Balance

Unswept amounts per chain and token.

Get balance

get/v1/balance

What the account's forwarders hold in the key's mode, per chain and token: deposits not reversed minus finalized sweeps, and the part of it from final deposits, which is safe to sweep. A forwarder's funds can only ever reach its treasury.

Responses

200

OK

Returns Balance

401

Unauthorized

403

permission_denied: the key lacks this permission, or testmode_charges_only: live mode is not enabled

429

rate_limit: retry after Retry-After seconds

503

unavailable: temporary service or database unavailability; service_restoring: restore reconciliation is in progress. Retry-After, when present, is the minimum delay in seconds

Request
curl \  https://pay-api.phala.com/v1/balance \  -H "Authorization: Bearer $PHALA_PAY_API_KEY"

Response 200: Balance

Sweeps

Finalized sweeps of forwarders to your treasuries.

List sweeps

get/v1/sweeps

The sweeps of the key's mode, newest first: every finalized Flushed event of a forwarder of the account, whoever sent the flush. A deposit is swept once a sweep after it moved its forwarder's balance.

Query parameters

chain_idinteger (int64)

Only this chain's sweeps

forwarderstring

Only this forwarder's sweeps, fwd_…

tokenstring

Only sweeps of this token contract

limitinteger (int64)

1 to 100, default 10

starting_afterstring

sw_ id: the page after it

ending_beforestring

sw_ id: the page before it

Responses

200

OK

Returns SweepList

400

Bad Request

401

Unauthorized

403

permission_denied: the key lacks this permission, or testmode_charges_only: live mode is not enabled

429

rate_limit: retry after Retry-After seconds

503

unavailable: temporary service or database unavailability; service_restoring: restore reconciliation is in progress. Retry-After, when present, is the minimum delay in seconds

Request
curl \  https://pay-api.phala.com/v1/sweeps \  -H "Authorization: Bearer $PHALA_PAY_API_KEY"

Response 200: SweepList

Forwarders

Every issued address, with what you need to sweep it.

List forwarders

get/v1/forwarders

Every forwarder issued in the key's mode, for quotes and for deposit address networks (current and superseded), with the (factory, salt, treasury) its address derives from: the export that keeps funds recomputable and sweepable without Phala Pay (design §13). With sweepable, the forwarders to pass to the SDK's flush_transaction or safe_batch, one call per chain and treasury. Pages follow id order.

Query parameters

chain_idinteger (int64)

Only this chain's forwarders

quotestring

Only this quote's forwarder, qt_…

deposit_addressstring

Only this deposit address's networks, da_…

sweepablestring

A token contract: only forwarders with a final unswept balance of it that may be swept, never one holding a deposit rejected as sanctioned or paying a treasury a sanctions list names

limitinteger (int64)

1 to 100, default 10

starting_afterstring

fwd_ id: the page after it

ending_beforestring

fwd_ id: the page before it

Responses

200

OK

Returns ForwarderList

400

Bad Request

401

Unauthorized

403

permission_denied: the key lacks this permission, or testmode_charges_only: live mode is not enabled

429

rate_limit: retry after Retry-After seconds

503

sweepable: treasury screening is unavailable; retry

Request
curl \  https://pay-api.phala.com/v1/forwarders \  -H "Authorization: Bearer $PHALA_PAY_API_KEY"

Response 200: ForwarderList

Treasuries

Where each chain's forwarders pay, proven and time-locked.

List treasuries

get/v1/treasuries

The account's treasuries in the key's mode, newest first, with Stripe's cursor pagination: each chain's active one, any pending change, and the replaced and canceled ones.

Query parameters

chain_idinteger (int64)

Only this chain's treasuries

statusstring

pending, active, replaced, or canceled

limitinteger (int64)

1 to 100, default 10

starting_afterstring

trs_ id: the page after it

ending_beforestring

trs_ id: the page before it

Responses

200

OK

Returns TreasuryList

400

Bad Request

401

Unauthorized

403

permission_denied: the key lacks this permission, or testmode_charges_only: live mode is not enabled

429

rate_limit: retry after Retry-After seconds

503

unavailable: temporary service or database unavailability; service_restoring: restore reconciliation is in progress. Retry-After, when present, is the minimum delay in seconds

Request
curl \  https://pay-api.phala.com/v1/treasuries \  -H "Authorization: Bearer $PHALA_PAY_API_KEY"

Response 200: TreasuryList

Create treasury

post/v1/treasuries

Sets the chain's treasury with a signed challenge. An EOA's personal_sign signature must recover to the address; otherwise a contract deployed at the address must return 0x1626ba7e from EIP-1271 isValidSignature for the message's EIP-191 hash at the chain's finalized block on both of the service's RPC providers. The address is screened against sanctions lists.

The chain's first treasury, and any test-mode change, applies at once. A later live change is pending for 48 hours, then applies (treasury.updated) unless canceled first: new quotes and deposit address networks then pay it, while addresses issued before keep paying the former treasury, which becomes replaced (treasury.updated), and are still credited. Every new treasury is announced as treasury.created; treasury events go to every enabled webhook endpoint of the mode.

Headers

Idempotency-Keystring or null

Up to 255 characters; for 24 hours a repeat of the same request returns the first response, and of another request is 400 idempotency_error.

Request body · CreateTreasuryRequest

chain_idinteger (int64)required

The treasury's chain, the challenge's.

messagestringrequired

The challenge's message, unchanged.

signaturestringrequired

Hex signature of the message: an EOA's 65-byte personal_sign signature, or what a deployed contract's isValidSignature accepts (for a Safe, the owners' signatures of the Safe message, or 0x after SignMessageLib approved it). ERC-6492 signatures are refused.

Responses

200

OK: active, or pending for a later live change

Returns Treasury

400

treasury_proof_invalid, treasury_challenge_expired, treasury_challenge_used, treasury_not_deployed (no contract at the address at the chain's finalized block; ERC-6492 signatures are refused), treasury_sanctioned, treasury_change_pending, or treasury_unchanged

401

Unauthorized

403

Forbidden

409

idempotency_key_in_use: a request with this Idempotency-Key is still running; retry with the same key

429

rate_limit: retry after Retry-After seconds

503

The chain or sanctions screening could not be read; retry

Request
curl -X POST \  https://pay-api.phala.com/v1/treasuries \  -H "Authorization: Bearer $PHALA_PAY_API_KEY" \  -H "Content-Type: application/json" \  -d '{    "chain_id": 1,    "message": "pay-api.phala.com wants you to sign in with your Ethereum account:\n0x936c1991f8dA9a919fa11b557a3514719f5A4504\n\nSet this address as the test mode treasury of acct_0c6e1d0a9b3f4c2e8d7a6b5c4d3e2f10 on Phala Pay.\n\nURI: https://pay-api.phala.com\nVersion: 1\nChain ID: 1\nNonce: Kq3nV8xZt2mP6wRa\nIssued At: 2026-09-28T12:00:00Z\nExpiration Time: 2026-09-28T12:10:00Z",    "signature": "0x5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e1b"  }'

Response 200: Treasury

Create treasury challenge

post/v1/treasuries/challenge

Issues the EIP-4361 message that proves address as your treasury on chain_id in the key's mode. Sign it and send it to POST /v1/treasuries before expires_at: 10 minutes for an EOA, 24 hours for an address that holds code (a Safe, whose owners sign it as a Safe message); it can be used once.

Headers

Idempotency-Keystring or null

Up to 255 characters; for 24 hours a repeat of the same request returns the first response, and of another request is 400 idempotency_error.

Request body · CreateTreasuryChallengeRequest

addressstringrequired

The treasury address to prove: an EOA, or a contract deployed on the chain such as a Safe.

chain_idinteger (int64)required

The chain of the treasury: a chain of the key's mode (GET /v1/config).

Responses

200

OK

Returns TreasuryChallenge

400

Bad Request

401

Unauthorized

403

Forbidden

409

idempotency_key_in_use: a request with this Idempotency-Key is still running; retry with the same key

429

rate_limit: retry after Retry-After seconds

503

unavailable: temporary service or database unavailability; service_restoring: restore reconciliation is in progress. Retry-After, when present, is the minimum delay in seconds

Request
curl -X POST \  https://pay-api.phala.com/v1/treasuries/challenge \  -H "Authorization: Bearer $PHALA_PAY_API_KEY" \  -H "Content-Type: application/json" \  -d '{    "address": "0x936c1991f8da9a919fa11b557a3514719f5a4504",    "chain_id": 1  }'

Response 200: TreasuryChallenge

Get treasury

get/v1/treasuries/{id}

One treasury.

Path parameters

idstringrequired

Treasury id, trs_…

Responses

200

OK

Returns Treasury

401

Unauthorized

403

permission_denied: the key lacks this permission, or testmode_charges_only: live mode is not enabled

404

Not Found

429

rate_limit: retry after Retry-After seconds

503

unavailable: temporary service or database unavailability; service_restoring: restore reconciliation is in progress. Retry-After, when present, is the minimum delay in seconds

Request
curl \  https://pay-api.phala.com/v1/treasuries/{id} \  -H "Authorization: Bearer $PHALA_PAY_API_KEY"

Response 200: Treasury

Cancel treasury

post/v1/treasuries/{id}/cancel

Cancels a pending treasury change before it applies (treasury.canceled); the chain's current treasury stays. If you did not request the change, also roll your keys.

Path parameters

idstringrequired

Treasury id, trs_…

Headers

Idempotency-Keystring or null

Up to 255 characters; for 24 hours a repeat of the same request returns the first response, and of another request is 400 idempotency_error.

Responses

200

OK: canceled

Returns Treasury

400

treasury_unexpected_state: not pending

401

Unauthorized

403

permission_denied: the key lacks this permission, or testmode_charges_only: live mode is not enabled

404

Not Found

409

idempotency_key_in_use: a request with this Idempotency-Key is still running; retry with the same key

429

rate_limit: retry after Retry-After seconds

503

unavailable: temporary service or database unavailability; service_restoring: restore reconciliation is in progress. Retry-After, when present, is the minimum delay in seconds

Request
curl -X POST \  https://pay-api.phala.com/v1/treasuries/{id}/cancel \  -H "Authorization: Bearer $PHALA_PAY_API_KEY"

Response 200: Treasury

Pause treasury

post/v1/treasuries/{id}/pause

Pauses crediting of deposits to every forwarder over the treasury's address, for an incident such as a compromised former treasury: new deposits stay pending, uncredited, and no deposit.credited is sent until you resume; nothing already credited changes. Announced as treasury.updated. Pausing a paused treasury returns it unchanged.

Path parameters

idstringrequired

Treasury id, trs_…

Headers

Idempotency-Keystring or null

Up to 255 characters; for 24 hours a repeat of the same request returns the first response, and of another request is 400 idempotency_error.

Responses

200

OK: crediting_paused

Returns Treasury

401

Unauthorized

403

Forbidden

404

Not Found

409

idempotency_key_in_use: a request with this Idempotency-Key is still running; retry with the same key

429

rate_limit: retry after Retry-After seconds

503

unavailable: temporary service or database unavailability; service_restoring: restore reconciliation is in progress. Retry-After, when present, is the minimum delay in seconds

Request
curl -X POST \  https://pay-api.phala.com/v1/treasuries/{id}/pause \  -H "Authorization: Bearer $PHALA_PAY_API_KEY"

Response 200: Treasury

Resume treasury

post/v1/treasuries/{id}/resume

Lifts your crediting pause of the treasury: the deposits it held are credited, each with its deposit.credited. An operator's pause stays in crediting_paused_by until the operator lifts it. Announced as treasury.updated.

Path parameters

idstringrequired

Treasury id, trs_…

Headers

Idempotency-Keystring or null

Up to 255 characters; for 24 hours a repeat of the same request returns the first response, and of another request is 400 idempotency_error.

Responses

200

OK

Returns Treasury

401

Unauthorized

403

Forbidden

404

Not Found

409

idempotency_key_in_use: a request with this Idempotency-Key is still running; retry with the same key

429

rate_limit: retry after Retry-After seconds

503

unavailable: temporary service or database unavailability; service_restoring: restore reconciliation is in progress. Retry-After, when present, is the minimum delay in seconds

Request
curl -X POST \  https://pay-api.phala.com/v1/treasuries/{id}/resume \  -H "Authorization: Bearer $PHALA_PAY_API_KEY"

Response 200: Treasury

Events

Notifications and the audit log: every change, as it was when it happened.

List events

get/v1/events

The account's events in the key's mode, newest first, with Stripe's cursor pagination: the notifications webhooks deliver, and the audit log of every key, endpoint, and account change with its actor. An event stays listed whether or not any endpoint received it.

Query parameters

typestring

Only events of this type, such as deposit.credited, or of a group, such as deposit.*

types[]array of string

Only events of these types, up to 20, each a type or a group; not with type (https://docs.stripe.com/api/events/list)

delivery_successboolean

false: only events with a delivery to a webhook endpoint that has not succeeded, pending or stopped; true: only events whose every delivery succeeded

created[gt]integer (int64)

Created after, Unix seconds

created[gte]integer (int64)

Created at or after, Unix seconds

created[lt]integer (int64)

Created before, Unix seconds

created[lte]integer (int64)

Created at or before, Unix seconds

limitinteger (int64)

1 to 100, default 10

starting_afterstring

evt_ id: the page after it

ending_beforestring

evt_ id: the page before it

Responses

200

OK

Returns EventList

400

Bad Request

401

Unauthorized

403

permission_denied: the key lacks this permission, or testmode_charges_only: live mode is not enabled

429

rate_limit: retry after Retry-After seconds

503

unavailable: temporary service or database unavailability; service_restoring: restore reconciliation is in progress. Retry-After, when present, is the minimum delay in seconds

Request
curl \  https://pay-api.phala.com/v1/events \  -H "Authorization: Bearer $PHALA_PAY_API_KEY"

Response 200: EventList

Get event

get/v1/events/{id}

One event.

Path parameters

idstringrequired

Event id, evt_…

Responses

200

OK

Returns EventObjectResponse

401

Unauthorized

403

permission_denied: the key lacks this permission, or testmode_charges_only: live mode is not enabled

404

Not Found

429

rate_limit: retry after Retry-After seconds

503

unavailable: temporary service or database unavailability; service_restoring: restore reconciliation is in progress. Retry-After, when present, is the minimum delay in seconds

Request
curl \  https://pay-api.phala.com/v1/events/{id} \  -H "Authorization: Bearer $PHALA_PAY_API_KEY"

Response 200: EventObjectResponse

Resend event

post/v1/events/{id}/resend

Delivers an event again to one enabled endpoint, whether it was delivered there, stopped, or never sent there (the Stripe CLI's events resend), with the same webhook-id and body. Use it after re-enabling an endpoint for the events it missed.

Path parameters

idstringrequired

Event id, evt_…

Headers

Idempotency-Keystring or null

Up to 255 characters; for 24 hours a repeat of the same request returns the first response, and of another request is 400 idempotency_error.

Request body · ResendEventRequest

webhook_endpointstringrequired

The enabled endpoint to deliver the event to again, we_….

Responses

200

OK: queued for delivery

Returns EventObjectResponse

400

Bad Request, or webhook_endpoint_disabled: enable the endpoint first

401

Unauthorized

403

permission_denied: the key lacks this permission, or testmode_charges_only: live mode is not enabled

404

Not Found: no such event or endpoint

409

idempotency_key_in_use: a request with this Idempotency-Key is still running; retry with the same key

429

rate_limit: retry after Retry-After seconds

503

unavailable: temporary service or database unavailability; service_restoring: restore reconciliation is in progress. Retry-After, when present, is the minimum delay in seconds

Request
curl -X POST \  https://pay-api.phala.com/v1/events/{id}/resend \  -H "Authorization: Bearer $PHALA_PAY_API_KEY" \  -H "Content-Type: application/json" \  -d '{    "webhook_endpoint": "we_9e1c3a5b7d2f40c6e8a0b2d4f6a8c0e1"  }'

Response 200: EventObjectResponse

Webhook endpoints

Where events are delivered, with delivery health.

List webhook endpoints

get/v1/webhook_endpoints

The key's mode's webhook endpoints, newest first, with Stripe's cursor pagination.

Query parameters

limitinteger (int64)

1 to 100, default 10

starting_afterstring

we_ id: the page after it

ending_beforestring

we_ id: the page before it

Responses

200

OK

Returns WebhookEndpointList

400

Bad Request, or webhook_endpoint_cap_exceeded: the mode already has 16 endpoints

401

Unauthorized

403

permission_denied: the key lacks this permission, or testmode_charges_only: live mode is not enabled

429

rate_limit: retry after Retry-After seconds

503

unavailable: temporary service or database unavailability; service_restoring: restore reconciliation is in progress. Retry-After, when present, is the minimum delay in seconds

Request
curl \  https://pay-api.phala.com/v1/webhook_endpoints \  -H "Authorization: Bearer $PHALA_PAY_API_KEY"

Response 200: WebhookEndpointList

Create webhook endpoint

post/v1/webhook_endpoints

Registers a webhook endpoint in the key's mode, at most 16 per mode. It receives the events it subscribes to and, whatever it subscribes to, every account event (account.*, api_key.*, webhook_endpoint.*), starting with webhook_endpoint.created about itself. Deliveries are signed with the account's webhook key of the mode (GET /v1/attestation).

Headers

Idempotency-Keystring or null

Up to 255 characters; for 24 hours a repeat of the same request returns the first response, and of another request is 400 idempotency_error.

Request body · CreateWebhookEndpointRequest

descriptionstring or null

Your description, up to 5000 characters.

enabled_eventsarray of stringrequired

The event types to deliver, such as deposit.credited, or ["*"] for all.

metadataMetadataParam

Stripe's metadata: up to 50 string key/value pairs for your own use, keys of up to 40 characters without square brackets, values of up to 500 characters.

urlstringrequired

Where to deliver events, up to 2048 characters, without credentials or fragment: https on port 443; in test mode also http on port 80. Redirects are not followed.

Responses

400

Bad Request, or webhook_endpoint_cap_exceeded: the mode already has 16 endpoints

401

Unauthorized

403

permission_denied: the key lacks this permission, or testmode_charges_only: live mode is not enabled

409

idempotency_key_in_use: a request with this Idempotency-Key is still running; retry with the same key

429

rate_limit: retry after Retry-After seconds

503

unavailable: temporary service or database unavailability; service_restoring: restore reconciliation is in progress. Retry-After, when present, is the minimum delay in seconds

Request
curl -X POST \  https://pay-api.phala.com/v1/webhook_endpoints \  -H "Authorization: Bearer $PHALA_PAY_API_KEY" \  -H "Content-Type: application/json" \  -d '{    "description": "Order fulfillment",    "enabled_events": [      "deposit.credited",      "deposit.reversed",      "refund.failed"    ],    "metadata": {      "team": "payments"    },    "url": "https://example.com/phala-pay/webhooks"  }'

Response 200: WebhookEndpointObject

Get webhook endpoint

get/v1/webhook_endpoints/{id}

One webhook endpoint.

Path parameters

idstringrequired

Endpoint id, we_…

Responses

401

Unauthorized

403

permission_denied: the key lacks this permission, or testmode_charges_only: live mode is not enabled

404

Not Found

429

rate_limit: retry after Retry-After seconds

503

unavailable: temporary service or database unavailability; service_restoring: restore reconciliation is in progress. Retry-After, when present, is the minimum delay in seconds

Request
curl \  https://pay-api.phala.com/v1/webhook_endpoints/{id} \  -H "Authorization: Bearer $PHALA_PAY_API_KEY"

Response 200: WebhookEndpointObject

Update webhook endpoint

post/v1/webhook_endpoints/{id}

Updates a webhook endpoint; parameters not sent are left unchanged. A change is announced as webhook_endpoint.updated, with the replaced values in data.previous_attributes, to every enabled endpoint, and first to this endpoint at the URL it had before, even when the change disables it. Disabling stops its pending deliveries; enabling does not restart them (resend with POST /v1/events/{id}/resend).

Path parameters

idstringrequired

Endpoint id, we_…

Headers

Idempotency-Keystring or null

Up to 255 characters; for 24 hours a repeat of the same request returns the first response, and of another request is 400 idempotency_error.

Request body · UpdateWebhookEndpointRequest

descriptionstring or null

A new description; "" unsets it.

disabledboolean or null

true disables the endpoint, false enables it. A disabled endpoint receives nothing and its pending deliveries stop; resend missed events with POST /v1/events/{id}/resend.

enabled_eventsarray of string

New event types, or ["*"].

metadataMetadataParam

Merged into the endpoint's metadata: a key set to "" is unset, and metadata: "" unsets every key.

urlstring or null

A new URL, as on creation.

Responses

400

Bad Request, or webhook_endpoint_cap_exceeded: the mode already has 16 endpoints

401

Unauthorized

403

permission_denied: the key lacks this permission, or testmode_charges_only: live mode is not enabled

404

Not Found

409

idempotency_key_in_use: a request with this Idempotency-Key is still running; retry with the same key

429

rate_limit: retry after Retry-After seconds

503

unavailable: temporary service or database unavailability; service_restoring: restore reconciliation is in progress. Retry-After, when present, is the minimum delay in seconds

Request
curl -X POST \  https://pay-api.phala.com/v1/webhook_endpoints/{id} \  -H "Authorization: Bearer $PHALA_PAY_API_KEY" \  -H "Content-Type: application/json" \  -d '{    "disabled": false,    "enabled_events": [      "*"    ]  }'

Response 200: WebhookEndpointObject

Delete webhook endpoint

delete/v1/webhook_endpoints/{id}

Deletes a webhook endpoint. webhook_endpoint.deleted goes to every enabled endpoint, and first to the deleted one; then it receives nothing more, and its pending deliveries stop.

Path parameters

idstringrequired

Endpoint id, we_…

Responses

401

Unauthorized

403

permission_denied: the key lacks this permission, or testmode_charges_only: live mode is not enabled

404

Not Found

429

rate_limit: retry after Retry-After seconds

503

unavailable: temporary service or database unavailability; service_restoring: restore reconciliation is in progress. Retry-After, when present, is the minimum delay in seconds

Request
curl -X DELETE \  https://pay-api.phala.com/v1/webhook_endpoints/{id} \  -H "Authorization: Bearer $PHALA_PAY_API_KEY"

Response 200: DeletedWebhookEndpoint

Test webhook endpoint

post/v1/webhook_endpoints/{id}/test

Sends a webhook_endpoint.test event about the endpoint to this endpoint only, enabled or not, signed like every delivery: check your receiver and its signature verification with it. There is no URL challenge.

Path parameters

idstringrequired

Endpoint id, we_…

Headers

Idempotency-Keystring or null

Up to 255 characters; for 24 hours a repeat of the same request returns the first response, and of another request is 400 idempotency_error.

Responses

200

OK: the test event, queued

Returns EventObjectResponse

401

Unauthorized

403

permission_denied: the key lacks this permission, or testmode_charges_only: live mode is not enabled

404

Not Found

409

idempotency_key_in_use: a request with this Idempotency-Key is still running; retry with the same key

429

rate_limit: retry after Retry-After seconds

503

unavailable: temporary service or database unavailability; service_restoring: restore reconciliation is in progress. Retry-After, when present, is the minimum delay in seconds

Request
curl -X POST \  https://pay-api.phala.com/v1/webhook_endpoints/{id}/test \  -H "Authorization: Bearer $PHALA_PAY_API_KEY"

Response 200: EventObjectResponse

Api keys

Your secret and restricted keys: create, roll, revoke.

List api keys

get/v1/api_keys

The keys of the requesting key's account and mode, newest first, without their secrets, with Stripe's cursor pagination.

Query parameters

limitinteger (int64)

1 to 100, default 10

starting_afterstring

key_ id: the page after it

ending_beforestring

key_ id: the page before it

Responses

200

OK

Returns ApiKeyList

400

Bad Request

401

Unauthorized

403

Forbidden

429

rate_limit: retry after Retry-After seconds

503

unavailable: temporary service or database unavailability; service_restoring: restore reconciliation is in progress. Retry-After, when present, is the minimum delay in seconds

Request
curl \  https://pay-api.phala.com/v1/api_keys \  -H "Authorization: Bearer $PHALA_PAY_API_KEY"

Response 200: ApiKeyList

Create api key

post/v1/api_keys

Creates a key in the requesting key's mode: a secret key, or with type: restricted a restricted key (ppay_rk_…) holding only permissions, Stripe's restricted keys. Run production servers with a restricted key and keep secret keys for administration. The response is the only time its secret is shown; a replay of the request (Idempotency-Key) returns the key without it.

Headers

Idempotency-Keystring or null

Up to 255 characters; for 24 hours a repeat of the same request returns the first response, and of another request is 400 idempotency_error.

Request body · CreateApiKeyRequest

namestring

The key's label, at most 200 characters.

permissionsarray of string

A restricted key's permissions, required with type: restricted: codes such as quotes.write or deposits.read, where a write includes its read. Grantable: account.read, api_keys.read, quotes.*, deposit_addresses.*, deposits.*, refunds.*, events.read, endpoints.read, treasury.read, sweeps.read, forwarders.read. Keys, treasuries, webhook endpoints, webhook keys, and account settings are managed only with a secret key.

typestring or null

secret, the default, or restricted (Stripe's restricted keys): a key that holds only permissions.

Responses

200

OK: the key with its secret, shown once

Returns ApiKeyObject

400

Bad Request

401

Unauthorized

403

Forbidden

409

idempotency_key_in_use: a request with this Idempotency-Key is still running; retry with the same key

429

rate_limit: retry after Retry-After seconds

503

unavailable: temporary service or database unavailability; service_restoring: restore reconciliation is in progress. Retry-After, when present, is the minimum delay in seconds

Request
curl -X POST \  https://pay-api.phala.com/v1/api_keys \  -H "Authorization: Bearer $PHALA_PAY_API_KEY" \  -H "Content-Type: application/json" \  -d '{    "name": "fulfillment worker",    "permissions": [      "quotes.write",      "deposit_addresses.write",      "deposits.read",      "events.read",      "refunds.read"    ],    "type": "restricted"  }'

Response 200: ApiKeyObject

Get api key

get/v1/api_keys/{id}

One key of the requesting key's account and mode, without its secret.

Path parameters

idstringrequired

Key id, key_…

Responses

200

OK

Returns ApiKeyObject

401

Unauthorized

403

permission_denied: the key lacks this permission, or testmode_charges_only: live mode is not enabled

404

Not Found

429

rate_limit: retry after Retry-After seconds

503

unavailable: temporary service or database unavailability; service_restoring: restore reconciliation is in progress. Retry-After, when present, is the minimum delay in seconds

Request
curl \  https://pay-api.phala.com/v1/api_keys/{id} \  -H "Authorization: Bearer $PHALA_PAY_API_KEY"

Response 200: ApiKeyObject

Revoke api key

delete/v1/api_keys/{id}

Revokes a key at once. The mode's last key that is neither revoked nor expiring cannot be revoked, so the account always keeps a working key; to replace a leaked last key, roll it and revoke it with the new key.

Path parameters

idstringrequired

Key id, key_…

Responses

200

OK: revoked, or already revoked

Returns ApiKeyObject

400

last_api_key: the mode's last key that is neither revoked nor expiring; create or roll a key first

401

Unauthorized

403

permission_denied: the key lacks this permission, or testmode_charges_only: live mode is not enabled

404

Not Found

429

rate_limit: retry after Retry-After seconds

503

unavailable: temporary service or database unavailability; service_restoring: restore reconciliation is in progress. Retry-After, when present, is the minimum delay in seconds

Request
curl -X DELETE \  https://pay-api.phala.com/v1/api_keys/{id} \  -H "Authorization: Bearer $PHALA_PAY_API_KEY"

Response 200: ApiKeyObject

Roll api key

post/v1/api_keys/{id}/roll

Rolls a key: returns a new key of the same type, name, and permissions, and the old key keeps working for expires_in seconds (at most 7 days), Stripe's roll; 0, the default, revokes it at once. A secret key may roll itself, keeping itself working for at least an hour (expires_in ≥ 3600): the new key's secret is shown only in this response, and a replay omits it, so if the response is lost, roll the new key (its id is in the replay) with the old key while it still works. To stop the old key sooner, revoke it with the new key.

Path parameters

idstringrequired

Key id, key_…

Headers

Idempotency-Keystring or null

Up to 255 characters; for 24 hours a repeat of the same request returns the first response, and of another request is 400 idempotency_error.

Request body · RollApiKeyRequest

expires_ininteger (int32)

Seconds the old key keeps working, up to 604800 (7 days); 0, the default, revokes it at once. A key rolling itself needs at least 3600.

Responses

200

OK: the new key with its secret, shown once

Returns ApiKeyObject

400

Bad Request, parameter_invalid for a key rolling itself with expires_in under 3600, or api_key_inactive: revoked or already rolled

401

Unauthorized

403

permission_denied: the key lacks this permission, or testmode_charges_only: live mode is not enabled

404

Not Found

409

idempotency_key_in_use: a request with this Idempotency-Key is still running; retry with the same key

429

rate_limit: retry after Retry-After seconds

503

unavailable: temporary service or database unavailability; service_restoring: restore reconciliation is in progress. Retry-After, when present, is the minimum delay in seconds

Request
curl -X POST \  https://pay-api.phala.com/v1/api_keys/{id}/roll \  -H "Authorization: Bearer $PHALA_PAY_API_KEY" \  -H "Content-Type: application/json" \  -d '{    "expires_in": 86400  }'

Response 200: ApiKeyObject

Account

Your account: settings, pauses, webhook signing keys.

Get account

get/v1/account

The account the API key belongs to, in the key's mode.

Responses

200

OK

Returns AccountObject

401

Unauthorized

403

permission_denied: the key lacks this permission, or testmode_charges_only: live mode is not enabled

429

rate_limit: retry after Retry-After seconds

503

unavailable: temporary service or database unavailability; service_restoring: restore reconciliation is in progress. Retry-After, when present, is the minimum delay in seconds

Request
curl \  https://pay-api.phala.com/v1/account \  -H "Authorization: Bearer $PHALA_PAY_API_KEY"

Response 200: AccountObject

Pause account

post/v1/account/pause

Pauses the account's quotes in both modes, for an emergency such as a leaked key during a treasury time-lock (design §12): no quote, deposit address, or network is issued until you resume. Payments to existing addresses keep being credited. Announced as account.updated.

Headers

Idempotency-Keystring or null

Up to 255 characters; for 24 hours a repeat of the same request returns the first response, and of another request is 400 idempotency_error.

Request body · AccountSelfPauseRequest

scopesarray of stringrequired

["quotes"], the one scope a merchant pauses itself: no quote, deposit address, or network is issued while it is paused. Existing addresses keep being credited.

Responses

200

OK

Returns AccountObject

400

Bad Request

401

Unauthorized

403

permission_denied: the key lacks this permission, or testmode_charges_only: live mode is not enabled

409

idempotency_key_in_use: a request with this Idempotency-Key is still running; retry with the same key

429

rate_limit: retry after Retry-After seconds

503

unavailable: temporary service or database unavailability; service_restoring: restore reconciliation is in progress. Retry-After, when present, is the minimum delay in seconds

Request
curl -X POST \  https://pay-api.phala.com/v1/account/pause \  -H "Authorization: Bearer $PHALA_PAY_API_KEY" \  -H "Content-Type: application/json" \  -d '{    "scopes": [      "quotes"    ]  }'

Response 200: AccountObject

Resume account

post/v1/account/resume

Resumes the quotes you paused. A pause the operator set stays in paused_scopes until the operator lifts it. Announced as account.updated.

Headers

Idempotency-Keystring or null

Up to 255 characters; for 24 hours a repeat of the same request returns the first response, and of another request is 400 idempotency_error.

Request body · AccountSelfPauseRequest

scopesarray of stringrequired

["quotes"], the one scope a merchant pauses itself: no quote, deposit address, or network is issued while it is paused. Existing addresses keep being credited.

Responses

200

OK

Returns AccountObject

400

Bad Request

401

Unauthorized

403

permission_denied: the key lacks this permission, or testmode_charges_only: live mode is not enabled

409

idempotency_key_in_use: a request with this Idempotency-Key is still running; retry with the same key

429

rate_limit: retry after Retry-After seconds

503

unavailable: temporary service or database unavailability; service_restoring: restore reconciliation is in progress. Retry-After, when present, is the minimum delay in seconds

Request
curl -X POST \  https://pay-api.phala.com/v1/account/resume \  -H "Authorization: Bearer $PHALA_PAY_API_KEY" \  -H "Content-Type: application/json" \  -d '{    "scopes": [      "quotes"    ]  }'

Response 200: AccountObject

Roll webhook key

post/v1/account/webhook_keys/roll

Rolls the webhook signing key of the key's mode: the next version signs every delivery from now on, and the current one keeps signing beside it for expires_in seconds, so every delivery carries one v1a signature per key until then. The overlap is 48 hours (the default, the treasury time-lock) to 7 days in live mode, so a leaked key cannot cut off the key you pinned; test mode also accepts 0, which stops it at once. The roll is announced as account.updated, signed by the retiring key as well even after its overlap. Fetch and verify the new public key with GET /v1/attestation, pin it next to the old one, and drop the old one when it expires.

Headers

Idempotency-Keystring or null

Up to 255 characters. A retry with the same key and request within 24 hours returns the first response, and of another request is 400 idempotency_error.

Request body · RollWebhookKeyRequest

expires_ininteger (int32)

Seconds the current key keeps signing beside the new one: 172800 (48 hours, the treasury time-lock) to 604800 (7 days) in live mode, 0 to 604800 in test mode, where 0 stops it at once. Default 172800.

Responses

200

OK: the account with its new webhook key version

Returns AccountObject

400

Bad Request

401

Unauthorized

403

Forbidden

409

idempotency_key_in_use: a request with this Idempotency-Key is still running; retry with the same key

429

rate_limit: retry after Retry-After seconds

503

unavailable: temporary service or database unavailability; service_restoring: restore reconciliation is in progress. Retry-After, when present, is the minimum delay in seconds

Request
curl -X POST \  https://pay-api.phala.com/v1/account/webhook_keys/roll \  -H "Authorization: Bearer $PHALA_PAY_API_KEY" \  -H "Content-Type: application/json" \  -d '{    "expires_in": 172800  }'

Response 200: AccountObject

Attestation

TDX evidence binding your webhook signing keys.

Get attestation

get/v1/attestation

TDX evidence binding a fresh nonce to the webhook public keys of the key's account and mode (design D11). Verify the quote once with the dstack verifier, check that its report data is report_data zero-padded to 64 bytes and that report_data binds your nonce, account, mode, and the listed keys, then pin the public keys: they are stable across releases.

Query parameters

noncestringrequired

Non-empty hexadecimal nonce of at most 32 bytes.

Responses

200

OK

Returns AttestationResponse

400

Bad Request

401

Unauthorized

403

permission_denied: the key lacks this permission, or testmode_charges_only: live mode is not enabled

429

rate_limit: retry after Retry-After seconds

503

Service Unavailable

Request
curl \  https://pay-api.phala.com/v1/attestation \  -H "Authorization: Bearer $PHALA_PAY_API_KEY"

Response 200: AttestationResponse

Config

The payable assets and their terms in the key's mode.

Get config

get/v1/config

Your effective payment config in the key's mode: every asset your payment settings accept on a chain where you have a treasury, with its terms (GET /v1/payment_settings), and your open-quote caps. An account that accepts nothing yet gets no asset.

Responses

200

OK

Returns Config

401

Unauthorized

403

permission_denied: the key lacks this permission, or testmode_charges_only: live mode is not enabled

429

rate_limit: retry after Retry-After seconds

503

unavailable: temporary service or database unavailability; service_restoring: restore reconciliation is in progress. Retry-After, when present, is the minimum delay in seconds

Request
curl \  https://pay-api.phala.com/v1/config \  -H "Authorization: Bearer $PHALA_PAY_API_KEY"

Response 200: Config

Payment settings

Get payment settings

get/v1/payment_settings

Your payment settings in the key's mode: the chains and assets you accept and your terms on each, with the operator's catalog of the mode in available. A new account accepts nothing until you configure it.

Responses

401

Unauthorized

403

permission_denied: the key lacks this permission, or testmode_charges_only: live mode is not enabled

429

rate_limit: retry after Retry-After seconds

503

unavailable: temporary service or database unavailability; service_restoring: restore reconciliation is in progress. Retry-After, when present, is the minimum delay in seconds

Request
curl \  https://pay-api.phala.com/v1/payment_settings \  -H "Authorization: Bearer $PHALA_PAY_API_KEY"

Response 200: PaymentSettingsObject

Update payment settings

post/v1/payment_settings

Updates your payment settings in the key's mode. A parameter not sent is unchanged; chains, when sent, replaces the whole list, and a term an element does not send takes the operator's default. Writes are last-write-wins. The settings govern quotes and deposit addresses issued from now on, and every payment recorded after the change; a quote keeps the terms it was issued with. After a restore of the service the settings are held until a POST with your complete configuration, even unchanged, reconfirms them: chains is then required, and a parameter not sent takes its default. Announced as payment_settings.updated.

Headers

Idempotency-Keystring or null

Up to 255 characters; for 24 hours a repeat of the same request returns the first response, and of another request is 400 idempotency_error.

Request body · UpdatePaymentSettingsRequest

chainsarray of PaymentSettingsChain

The chains to accept, replacing the list: each chain and asset of the key's mode once. An element's term not sent resets to the operator's default. [] accepts nothing.

quote_creations_per_customer_per_minuteinteger (int64) or null

One customer's quote creations in a rolling minute, from 1 to the operator's maximum; null restores the default.

Responses

400

Bad Request

401

Unauthorized

403

permission_denied: the key lacks this permission, or testmode_charges_only: live mode is not enabled

409

idempotency_key_in_use: a request with this Idempotency-Key is still running; retry with the same key

429

rate_limit: retry after Retry-After seconds

503

unavailable: temporary service or database unavailability; service_restoring: restore reconciliation is in progress. Retry-After, when present, is the minimum delay in seconds

Request
curl -X POST \  https://pay-api.phala.com/v1/payment_settings \  -H "Authorization: Bearer $PHALA_PAY_API_KEY" \  -H "Content-Type: application/json" \  -d '{    "chains": [      {        "assets": [          {            "asset": "usdc",            "quote_spread_bps": 0          },          {            "asset": "usdt"          }        ],        "chain_id": 1,        "confirmations": "12"      }    ]  }'

Response 200: PaymentSettingsObject

Objects

AccountObject

The account of the request's API key (GET /v1/account), in the key's mode.

charges_enabledbooleanrequired

Whether the operator enabled live mode.

createdinteger (int64)required

Creation time, Unix seconds.

idstringrequired

Account id, acct_….

livemodebooleanrequired

The mode of the key that reads it.

namestringrequired

Display name.

object"account"required

Always account.

paused_scopesarray of stringrequired

Active account-level pause scopes, the operator's and your own (POST /v1/account/pause): while quotes is listed, no quote, deposit address, or network is issued. Your resume lifts only your own pause.

webhook_keysarray of WebhookKeyVersionrequired

The keys that sign this mode's webhooks: the current one first, then any previous one still signing during a rotation. Their public keys come from GET /v1/attestation.

Example
{  "charges_enabled": true,  "created": 1787961600,  "id": "acct_0c6e1d0a9b3f4c2e8d7a6b5c4d3e2f10",  "livemode": false,  "name": "Example Cloud",  "object": "account",  "paused_scopes": [],  "webhook_keys": [    {      "expires_at": null,      "version": 2    },    {      "expires_at": 1790640000,      "version": 1    }  ]}

AccountSelfPauseRequest

POST /v1/account/pause and POST /v1/account/resume body.

scopesarray of stringrequired

["quotes"], the one scope a merchant pauses itself: no quote, deposit address, or network is issued while it is paused. Existing addresses keep being credited.

Example
{  "scopes": [    "quotes"  ]}

ApiKeyList

GET /v1/api_keys response.

dataarray of ApiKeyObjectrequired

The mode's keys, newest first.

has_morebooleanrequired

Always false: every key of the mode is listed.

object"list"required

Always list.

urlstringrequired

The list's path, /v1/api_keys.

Example
{  "data": [    {      "created": 1790467200,      "expires_at": null,      "id": "key_6a8c0e2b4d1f43a5c7e9b1d3f5a7c9e1",      "last_used": 1790553600,      "livemode": false,      "name": "fulfillment worker",      "object": "api_key",      "permissions": [        "account.read",        "deposit_addresses.read",        "deposit_addresses.write",        "deposits.read",        "events.read",        "quotes.read",        "quotes.write",        "refunds.read"      ],      "redacted": "ppay_rk_test_…Yz4x",      "status": "active",      "type": "restricted"    }  ],  "has_more": false,  "object": "list",  "url": "/v1/api_keys"}

ApiKeyObject

An API key (design D7). secret is present only in the response that created it.

createdinteger (int64)required

Creation time, Unix seconds.

expires_atinteger (int64) or null

When a rolled key stops working, Unix seconds.

idstringrequired

Key id, key_….

last_usedinteger (int64) or null

Last use, Unix seconds, to the minute.

livemodebooleanrequired

The key's mode.

namestringrequired

The key's label.

object"api_key"required

Always api_key.

permissionsarray of string

A restricted key's permissions, such as quotes.write; null for a secret key.

redactedstringrequired

The key's prefix and last four characters, such as ppay_sk_test_…a1B2.

secretstring or null

The whole key, ppay_sk_… or ppay_rk_…, shown once. Store it in a secret manager.

statusstringrequired

active; expiring for a rolled key that still works until expires_at; expired; revoked.

typestringrequired

secret, holding every permission, or restricted, holding only permissions.

Example
{  "created": 1790467200,  "expires_at": null,  "id": "key_6a8c0e2b4d1f43a5c7e9b1d3f5a7c9e1",  "last_used": 1790553600,  "livemode": false,  "name": "fulfillment worker",  "object": "api_key",  "permissions": [    "account.read",    "deposit_addresses.read",    "deposit_addresses.write",    "deposits.read",    "events.read",    "quotes.read",    "quotes.write",    "refunds.read"  ],  "redacted": "ppay_rk_test_…Yz4x",  "status": "active",  "type": "restricted"}

AttestationResponse

TDX evidence binding a nonce to the webhook public keys of the caller's account in the caller's mode (design D11).

accountstringrequired

The caller's account, acct_….

livemodebooleanrequired

The caller's mode; each mode has its own key.

object"attestation"required

Always attestation.

report_datastringrequired

sha256(len(nonce) ‖ nonce ‖ len(account) ‖ account ‖ livemode ‖ (version ‖ public_key)*) as lowercase hexadecimal: lengths are one byte, account is UTF-8, livemode is one byte (1 live, 0 test), and each key of webhook_keys, in order, is its version as 4 big-endian bytes and its 32 raw public-key bytes.

tdx_quotestringrequired

Versioned dstack TDX quote bytes as lowercase hexadecimal.

webhook_keysarray of WebhookKeyObjectrequired

The keys that sign the account's deliveries in this mode: the current one first, then any previous one still signing during a rotation.

Example
{  "account": "acct_0c6e1d0a9b3f4c2e8d7a6b5c4d3e2f10",  "livemode": false,  "object": "attestation",  "report_data": "9f2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e2b4d6f8a0c1e3a5b7d9f1c3e5a7b9d1f",  "tdx_quote": "040002008100000000000000939a7233f79c4ca9940a0db3957f0607",  "webhook_keys": [    {      "expires_at": null,      "public_key": "whpk_O2onvM62pC1io6jQKm8Nc2UyFXcd4kOmOsBIoYtZ2ik=",      "version": 1    }  ]}

AvailableAsset

An asset of the operator's catalog and its bounds.

acceptedbooleanrequired

Whether your settings list it.

assetstringrequired

Asset code.

contractstringrequired

Token contract address.

decimalsinteger (int32)required

Token decimals.

enabledbooleanrequired

Whether its terms, each clamped to its bounds, can be used together; an accepted asset that is not enabled is not offered or credited until you or the operator change it.

max_deposit_atomicBoundsAtomicrequired

Bounds of max_deposit_atomic.

min_amountBoundsU64required

Bounds of min_amount.

min_deposit_atomicBoundsAtomicrequired

Bounds of min_deposit_atomic.

min_refund_atomicBoundsAtomicrequired

Bounds of min_refund_atomic.

pricingstringrequired

spot or stablecoin.

quote_amount_decimalsinteger (int32)required

Token decimals a quote's amount is rounded up to (the operator's).

quote_spread_bpsBoundsU64required

Bounds of quote_spread_bps.

quote_tolerance_bpsBoundsU64required

Bounds of quote_tolerance_bps.

quote_ttl_secondsBoundsU64required

Bounds of quote_ttl_seconds.

AvailableChain

A chain of the operator's catalog in the key's mode.

assetsarray of AvailableAssetrequired

The chain's assets.

chain_idinteger (int64)required

EVM chain identifier.

confirmationsAvailableConfirmationsrequired

The chain's confirmation floor, also its default.

statusstringrequired

active (accepted, with a treasury), treasury_not_set (accepted, without a treasury: nothing is offered on it until you set one), or not_configured.

AvailableConfirmations

A chain's confirmation floor.

defaultstringrequired

The confirmation of a chain whose confirmations is null: the floor.

floorstringrequired

The weakest confirmation you may require, a depth, safe, or finalized.

Balance

The account's balance held in its forwarders, in the key's mode (Stripe's Balance): what payments put there and no finalized Flushed event has moved to a treasury yet.

livemodebooleanrequired

The mode.

object"balance"required

Always balance.

unsweptarray of BalanceAmountrequired

One entry per chain and token held.

Example
{  "livemode": false,  "object": "balance",  "unswept": [    {      "amount_atomic": "25000000",      "asset": "usdc",      "chain_id": 1,      "final_amount_atomic": "25000000",      "token": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"    }  ]}

BalanceAmount

A token's unswept amounts on one chain.

amount_atomicstringrequired

Every deposit not reversed, minus finalized sweeps, in base units, as a decimal string.

assetstring or null

Asset code; null for a token without a route.

chain_idinteger (int64)required

EVM chain identifier.

final_amount_atomicstringrequired

The part of amount_atomic from final deposits, which can no longer be reversed: what is safe to sweep.

tokenstringrequired

The token contract.

BoundsAtomic

The operator's default of a base-unit amount and its inclusive bounds, as decimal strings.

defaultstringrequired

The value when you set none.

maxstringrequired

The highest value you may set.

minstringrequired

The lowest value you may set.

BoundsU64

The operator's default of an integer term and its inclusive bounds.

defaultinteger (int64)required

The value when you set none.

maxinteger (int64)required

The highest value you may set.

mininteger (int64)required

The lowest value you may set.

ClientDepositAddress

The public view of a deposit address, read with its client_secret and without an API key, for the customer's page. It has no account, customer, treasury, or metadata fields.

addressstring or null

The address shared by every network, or null when a network's differs.

idstringrequired

da_ id.

livemodebooleanrequired

Whether the address is in live mode; a test-mode page should say so.

networksarray of ClientDepositAddressNetworkrequired

The address on each supported network, with the tokens it takes there.

object"deposit_address"required

Always deposit_address.

paymentsarray of ClientDepositAddressPaymentrequired

Payments to the address in the last 24 hours, newest first, at most 10: display only, never a reason to deliver anything.

statusstringrequired

active, or retired by a rotation (still credited; show the new address instead).

ClientDepositAddressNetwork

A deposit address on one network, as its public view shows it.

addressstringrequired

The forwarder address to pay on this chain.

assetsarray of DepositAddressAssetrequired

The tokens accepted on this chain.

chain_idinteger (int64)required

EVM chain identifier.

typical_credit_secondsinteger (int64)required

Typical time from payment to credit, in seconds, at the confirmation this chain's payments are credited at, as GET /v1/config reports it for each of the chain's tokens, which share the chain's one floor.

ClientDepositAddressPayment

A payment to a deposit address, as its public view shows it.

amount_atomicstringrequired

Token amount in base units, as a decimal string.

assetstring or null

Asset code; null for a token without a route.

chain_idinteger (int64)required

EVM chain identifier.

confirmationsinteger (int64) or nullrequired

While seen: blocks on top of and including the payment's block; otherwise null.

createdinteger (int64)required

When the payment was first seen or recorded, Unix seconds.

decimalsinteger (int32) or null

The token's decimals, to display amount_atomic; null with asset.

statusstringrequired

seen (in a block, below the route's confirmation, and may still disappear); confirming (at the confirmation, being valued and screened); credited; rejected (not credited; the payer should contact the merchant's support); or reversed (its transaction left the chain before finality: the payment did not happen).

tx_hashstringrequired

Transaction hash.

ClientQuote

The public view of a quote, read with its client_secret and without a signature, for the payer's checkout page. It has no account or internal fields.

addressstringrequired

Single-use forwarder address to pay.

amountinteger (int64)required

Credit in the currency's minor unit.

amount_atomicstringrequired

The exact token amount to pay, in base units, as a decimal string.

amount_creditedinteger (int64) or nullrequired

While credited: the credit of the payment in the currency's minor unit, the credited deposit's amount. It differs from amount for a payment valued at spot (another amount, or paid late); otherwise null.

assetstringrequired

Asset code.

cancel_requested_atinteger (int64) or null

Deferred cancellation request time, Unix seconds.

chain_idinteger (int64)required

EVM chain identifier.

confirmationsinteger (int64) or nullrequired

While seen: blocks on top of and including the payment's block; otherwise null.

currencystringrequired

usd.

decimalsinteger (int32)required

The token's decimals, to display amount_atomic.

expires_atinteger (int64)required

End of the payment window, Unix seconds.

idstringrequired

qt_ id.

livemodebooleanrequired

Whether the quote is in live mode; a test-mode page should say so.

object"quote"required

Always quote.

payment_statusstringrequired

Progress of the payment shown on the page; display only, never a reason to deliver anything: none; seen (in a block, below the route's confirmation, and may still disappear); confirming (at the route's confirmation, being valued and screened); credited; rejected (not credited; the payer should contact the merchant's support); or reversed (credited, then its transaction left the chain before finality: the payment did not happen, and the credit is taken back).

payment_uristringrequired

EIP-681 URI carrying the token, chain, address, and amount.

statusstringrequired

open, complete, expired, or canceled, as on Quote; hide the address once expires_at has passed.

typical_credit_secondsinteger (int64)required

Typical time from payment to credit, in seconds, at the confirmation the quote's payments are credited at, as GET /v1/config reports it.

Example
{  "address": "0x2f3e91325b2288bce392711f85f5359661062a91",  "amount": 2500,  "amount_atomic": "25000000",  "amount_credited": null,  "asset": "usdc",  "chain_id": 1,  "confirmations": 1,  "currency": "usd",  "decimals": 6,  "expires_at": 1790554500,  "id": "qt_5f1c0b6a2d9e4f3a8b7c6d5e4f3a2b10",  "livemode": false,  "object": "quote",  "payment_status": "seen",  "payment_uri": "ethereum:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48@1/transfer?address=0x2f3e91325b2288bce392711f85f5359661062a91&uint256=25000000",  "status": "open",  "typical_credit_seconds": 30}

Config

What a product's UI reads instead of hardcoding: assets, limits, and quote terms.

assetsarray of ConfigAssetrequired

One entry per asset your payment settings accept on a chain where you have a treasury, with its terms: your effective payment config. Empty until you configure POST /v1/payment_settings.

currencystringrequired

Credit currency, usd.

livemodebooleanrequired

The mode of the key that reads it: assets lists that mode's routes.

max_open_amount_per_accountinteger (int64)required

Cap on the credit of your open quotes in this mode, in cents. Test-mode quotes never count against live mode's cap.

max_open_amount_per_customerinteger (int64)required

Cap on the credit of one customer's open quotes, in cents; no single quote can exceed it.

max_open_quotesinteger (int64)required

Cap on the number of your open quotes in this mode.

object"config"required

Always config.

quote_creations_per_customer_per_minuteinteger (int64)required

One customer's quote creations in a rolling minute, from your payment settings.

Example
{  "assets": [    {      "asset": "usdc",      "chain_id": 1,      "confirmations": "12",      "contract": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",      "decimals": 6,      "max_deposit_atomic": "10000000000",      "min_amount": 100,      "min_deposit_atomic": "0",      "min_refund_atomic": "1000000",      "pricing": "stablecoin",      "quote_amount_decimals": 4,      "quote_spread_bps": 0,      "quote_tolerance_bps": 100,      "quote_ttl_seconds": 900,      "typical_credit_seconds": 150,      "typical_finality_seconds": 900    }  ],  "currency": "usd",  "livemode": false,  "max_open_amount_per_account": 1000000,  "max_open_amount_per_customer": 500000,  "max_open_quotes": 100,  "object": "config",  "quote_creations_per_customer_per_minute": 10}

ConfigAsset

A payable asset and its terms.

assetstringrequired

Asset code.

chain_idinteger (int64)required

EVM chain identifier.

confirmationsstringrequired

The confirmation a payment's block must reach before it is credited: a depth ("2": the block and one more), "safe", or "finalized": the stricter of the chain's floor and the confirmations of your payment settings. A credit before finality can still be reversed (deposit.reversed).

contractstringrequired

Token contract address.

decimalsinteger (int32)required

Token decimals.

max_deposit_atomicstringrequired

Maximum creditable deposit in base units, as a decimal string.

min_amountinteger (int64)required

Minimum credit in cents, for quotes and deposits; smaller deposits are not credited.

min_deposit_atomicstringrequired

Minimum creditable deposit in base units, as a decimal string.

min_refund_atomicstringrequired

Minimum refundable amount in base units, as a decimal string.

pricingstringrequired

spot or stablecoin.

quote_amount_decimalsinteger (int32)required

Token decimals a quote's amount is rounded up to (the operator's).

quote_spread_bpsinteger (int32)required

A quote's price is spot / (1 + spread_bps / 10 000); spot-valued payments carry no spread.

quote_tolerance_bpsinteger (int32)required

A payment within this many basis points of the quoted amount, either way, completes the quote at its amount.

quote_ttl_secondsinteger (int64)required

Payment window of a quote, in seconds.

typical_credit_secondsinteger (int64)required

Typical time from payment to the deposit.credited event, in seconds, at confirmations.

typical_finality_secondsinteger (int64)required

Typical time from payment to finality, in seconds; refunds wait for it.

CreateApiKeyRequest

POST /v1/api_keys body.

namestring

The key's label, at most 200 characters.

permissionsarray of string

A restricted key's permissions, required with type: restricted: codes such as quotes.write or deposits.read, where a write includes its read. Grantable: account.read, api_keys.read, quotes.*, deposit_addresses.*, deposits.*, refunds.*, events.read, endpoints.read, treasury.read, sweeps.read, forwarders.read. Keys, treasuries, webhook endpoints, webhook keys, and account settings are managed only with a secret key.

typestring or null

secret, the default, or restricted (Stripe's restricted keys): a key that holds only permissions.

Example
{  "name": "fulfillment worker",  "permissions": [    "quotes.write",    "deposit_addresses.write",    "deposits.read",    "events.read",    "refunds.read"  ],  "type": "restricted"}

CreateDepositAddressRequest

POST /v1/deposit_addresses body.

client_reference_idstringrequired

Your identifier of the customer, 1 to 200 characters; the customer is created on first use.

metadataMetadataParam

Stripe's metadata: up to 50 string key/value pairs for your own use, keys of up to 40 characters without square brackets, values of up to 500 characters. Merged into the returned address's, as POST /v1/deposit_addresses/{id} does: a key set to "" is unset. Every deposit to the address starts with a copy of it, and a rotation carries it to the next version. Phala Pay never reads it. Do not store sensitive information in it, such as personal or payment details.

Example
{  "client_reference_id": "team-42",  "metadata": {    "plan": "pro"  }}

CreateQuoteRequest

POST /v1/quotes body.

amountinteger (int64)required

The credit to quote, a positive integer in the currency's minor unit (US cents).

assetstringrequired

Asset code of the payment on that chain, such as usdc.

chain_idinteger (int64)required

EVM chain of the payment, one of GET /v1/config assets[].chain_id.

client_reference_idstringrequired

Your identifier of the customer to credit, 1 to 200 characters (Stripe Checkout's client_reference_id); the customer is created on first use.

currencystringrequired

Lowercase ISO currency code; only usd.

metadataMetadataParam

Stripe's metadata: up to 50 string key/value pairs for your own use, keys of up to 40 characters without square brackets, values of up to 500 characters. A key set to "" is omitted. The deposit that pays the quote starts with a copy of it. Phala Pay never reads it. Do not store sensitive information in it, such as personal or payment details.

Example
{  "amount": 2500,  "asset": "usdc",  "chain_id": 1,  "client_reference_id": "team-42",  "currency": "usd",  "metadata": {    "order_id": "ord_1001"  }}

CreateRefundRequest

POST /v1/refunds body.

amount_atomicstring or null

Amount in base units, as a decimal string; the unrefunded remainder when absent.

depositstringrequired

dep_ id of the deposit to refund.

destination_addressstringrequired

Address the customer controls; never default it to the sender, which may be an exchange.

metadataMetadataParam

Stripe's metadata: up to 50 string key/value pairs for your own use, keys of up to 40 characters without square brackets, values of up to 500 characters. A key set to "" is omitted. Phala Pay never reads it. Do not store sensitive information in it, such as personal or payment details.

Example
{  "amount_atomic": "25000000",  "deposit": "dep_8a1f4e2b6c3d49e0a7b5c1d2e3f40516",  "destination_address": "0x1775c1326aa633546b0b5634ae2bef0ba7cbfc9a",  "metadata": {    "ticket": "support-311"  }}

CreateTreasuryChallengeRequest

POST /v1/treasuries/challenge body.

addressstringrequired

The treasury address to prove: an EOA, or a contract deployed on the chain such as a Safe.

chain_idinteger (int64)required

The chain of the treasury: a chain of the key's mode (GET /v1/config).

Example
{  "address": "0x936c1991f8da9a919fa11b557a3514719f5a4504",  "chain_id": 1}

CreateTreasuryRequest

POST /v1/treasuries body.

chain_idinteger (int64)required

The treasury's chain, the challenge's.

messagestringrequired

The challenge's message, unchanged.

signaturestringrequired

Hex signature of the message: an EOA's 65-byte personal_sign signature, or what a deployed contract's isValidSignature accepts (for a Safe, the owners' signatures of the Safe message, or 0x after SignMessageLib approved it). ERC-6492 signatures are refused.

Example
{  "chain_id": 1,  "message": "pay-api.phala.com wants you to sign in with your Ethereum account:\n0x936c1991f8dA9a919fa11b557a3514719f5A4504\n\nSet this address as the test mode treasury of acct_0c6e1d0a9b3f4c2e8d7a6b5c4d3e2f10 on Phala Pay.\n\nURI: https://pay-api.phala.com\nVersion: 1\nChain ID: 1\nNonce: Kq3nV8xZt2mP6wRa\nIssued At: 2026-09-28T12:00:00Z\nExpiration Time: 2026-09-28T12:10:00Z",  "signature": "0x5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e1b"}

CreateWebhookEndpointRequest

POST /v1/webhook_endpoints body.

descriptionstring or null

Your description, up to 5000 characters.

enabled_eventsarray of stringrequired

The event types to deliver, such as deposit.credited, or ["*"] for all.

metadataMetadataParam

Stripe's metadata: up to 50 string key/value pairs for your own use, keys of up to 40 characters without square brackets, values of up to 500 characters.

urlstringrequired

Where to deliver events, up to 2048 characters, without credentials or fragment: https on port 443; in test mode also http on port 80. Redirects are not followed.

Example
{  "description": "Order fulfillment",  "enabled_events": [    "deposit.credited",    "deposit.reversed",    "refund.failed"  ],  "metadata": {    "team": "payments"  },  "url": "https://example.com/phala-pay/webhooks"}

DeletedWebhookEndpoint

A deleted webhook endpoint.

deletedbooleanrequired

Always true.

idstringrequired

Endpoint id, we_….

object"webhook_endpoint"required

Always webhook_endpoint.

Example
{  "deleted": true,  "id": "we_9e1c3a5b7d2f40c6e8a0b2d4f6a8c0e1",  "object": "webhook_endpoint"}

DeliveryAttempt

A delivery attempt to a webhook endpoint.

atinteger (int64)required

When it was made, Unix seconds.

status_codeinteger (int32) or null

The endpoint's HTTP status; null when no response arrived (a timeout, a refused connection, or a URL the egress proxy refused).

Deposit

A transfer to a quote's address or a deposit address at the route's confirmation: valued, screened, and credited, or rejected; reversed if its transaction left the chain before finality.

Every deposit.* event carries the whole deposit, with cumulative amounts, so the customer's balance can be recomputed from the latest snapshot whatever order events arrive in: the deposit contributes amount - amount_refunded - amount_reversed cents while its status is credited or reversed, and nothing while it is pending or rejected. status only moves forward (pending, then credited or rejected, then possibly reversed) and amount_refunded only grows, so of two snapshots the later one has the later status or, for the same status, the larger amount_refunded.

addressstringrequired

Receiving forwarder address.

adminDepositAdmin or any or null
amountinteger (int64) or null

Credit in the currency's minor unit (cents), once valued.

amount_atomicstringrequired

Token amount in base units, as a decimal string.

amount_refundedinteger (int64)required

Cents of amount its succeeded refunds take back: amount times amount_refunded_atomic over amount_atomic, rounded down, so it never exceeds the refunded share, and all of amount once fully refunded. Computed from the cumulative refunded amount, it only grows. 0 without amount.

amount_refunded_atomicstringrequired

Refunded token amount in base units, as a decimal string: the sum of succeeded refunds.

amount_reversedinteger (int64)required

Cents of amount the reversal takes back: amount once status is reversed (a deposit is refunded only once final, and a final deposit is never reversed, so a reversed deposit has no refunds); 0 otherwise.

assetstring or null

Asset code; null for a token without a route.

asset_contractstringrequired

Token contract address.

block_hashstringrequired

Hash of the block the transfer is in; it changes if the transaction is re-included.

block_numberinteger (int64)required

Number of the block the transfer is in; it changes if the transaction is re-included.

block_timeinteger (int64)required

Time of the block the transfer is in, Unix seconds.

chain_idinteger (int64)required

EVM chain identifier.

client_reference_idstringrequired

Your identifier of the customer the deposit is credited to.

createdinteger (int64)required

Detection time, Unix seconds.

currencystringrequired

usd.

deposit_addressstring or null

The deposit address that received the transfer, da_…, on chain_id at address; null for a quote's address. Payments to a deposit address, active or retired, are credited at spot.

exchange_ratestring or null

USD per token, a decimal string with 8 places, once valued.

finalbooleanrequired

Whether the deposit's block is final on both providers: a final deposit can no longer be reversed, and only a final deposit can be refunded. A deposit is credited at the route's confirmation, before it is final (GET /v1/config typical_finality_seconds).

final_atinteger (int64) or null

When the finality watch found the deposit's block final on both providers, Unix seconds; null until final.

from_addressstringrequired

Sender of the transfer.

idstringrequired

dep_ and the hex of the deposit's deterministic UUID, uuid_v5(DEPOSIT_NAMESPACE, "{chain_id}:{tx_hash}:{receipt_log_index}"), where receipt_log_index is the transfer's position among its transaction's receipt logs. A deposit recorded at a position after the deposit there was reversed (replaces) has another id, uuid_v5(DEPOSIT_NAMESPACE, "{chain_id}:{tx_hash}:{receipt_log_index}:{revision}").

livemodebooleanrequired

Whether the deposit is on a live-mode route.

log_indexinteger (int64)required

Block-wide log index of the transfer; it changes if the transaction is re-included.

metadatamap of stringrequired

Your key/value pairs (metadata): a copy of the quote's or the deposit address's when the deposit is recorded, independent of it afterwards; {} when none.

object"deposit"required

Always deposit.

price_sourcestring or null

quote (the quoted price) or spot, once valued.

quoteExpandableQuote or any or null
receipt_log_indexinteger (int64)required

Position of the transfer among its transaction's receipt logs: with chain_id, tx_hash, and revision, what id is derived from.

refundedbooleanrequired

Whether the deposit is fully refunded.

rejection_reasonstring or null

Why the deposit was rejected: unsupported_asset, asset_not_accepted (a routed asset the payment settings the deposit is bound to do not accept), below_minimum, out_of_bounds, out_of_range, or sanctioned.

replaced_bystring or null

The deposit that took this reversed deposit's place, dep_… (its replaces is this one); null otherwise, or when that deposit is in another account or mode.

replacesstring or null

The reversed deposit whose place this one took, dep_…: its transaction was re-included before finality against other state (a router or swap output), and the transfer at the same position in the final chain is this deposit. null otherwise, or when that deposit is in another account or mode.

revisioninteger (int64)required

How many deposits at the same receipt position were reversed before this one: 0, or the revision of the deposit it replaces plus one.

statusstringrequired

pending (recorded at the route's confirmation and being valued and screened, or held while the account's or customer's settlement is paused), credited, rejected (see rejection_reason), or reversed (its transaction is not in the final chain: its credit is taken back, amount_reversed). New values may be added.

sweptbooleanrequired

Whether a finalized Flushed event after the deposit moved its forwarder's balance of its token to the treasury (GET /v1/sweeps), whoever sent the flush.

tx_hashstringrequired

Transaction hash.

valued_atinteger (int64) or null

Valuation time, Unix seconds.

Example
{  "address": "0x2f3e91325b2288bce392711f85f5359661062a91",  "amount": 2500,  "amount_atomic": "25000000",  "amount_refunded": 0,  "amount_refunded_atomic": "0",  "amount_reversed": 0,  "asset": "usdc",  "asset_contract": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",  "block_hash": "0x9a1c3e5b7d0f2a4c6e8b0d2f4a6c8e0b2d4f6a8c0e2b4d6f8a0c2e4b6d8f0a2c",  "block_number": 21000000,  "block_time": 1790553612,  "chain_id": 1,  "client_reference_id": "team-42",  "created": 1790553624,  "currency": "usd",  "deposit_address": null,  "exchange_rate": "1.00000000",  "final": true,  "final_at": 1790554572,  "from_address": "0x1775c1326aa633546b0b5634ae2bef0ba7cbfc9a",  "id": "dep_8a1f4e2b6c3d49e0a7b5c1d2e3f40516",  "livemode": false,  "log_index": 212,  "metadata": {    "order_id": "ord_1001"  },  "object": "deposit",  "price_source": "quote",  "quote": "qt_5f1c0b6a2d9e4f3a8b7c6d5e4f3a2b10",  "receipt_log_index": 0,  "refunded": false,  "rejection_reason": null,  "replaced_by": null,  "replaces": null,  "revision": 0,  "status": "credited",  "swept": false,  "tx_hash": "0x7d3c1e5a9b2f4d6c8e0a1b3d5f7c9e2a4b6d8f0c1e3a5b7d9f1c3e5a7b9d1f3e",  "valued_at": 1790553630}

DepositAddress

A customer's persistent deposit address, like a bank-transfer virtual account: one address for every supported token on every supported network. Eligible transfers within the account’s per-transfer deposit bounds are credited at the market (spot) price after confirmation. Rotation retires it and issues a new one on every network; eligible payments to a retired address are still credited.

addressstring or null

The address shared by every network, when all of networks have the same one; null when a network's treasury differs, and so its address (see networks), or when there is no network.

client_reference_idstringrequired

Your identifier of the customer.

client_secretstring or null

Lets the customer's page read the address's public view, ClientDepositAddress, from GET /v1/deposit_addresses/{id}?client_secret=… without an API key, to show a payment as soon as it is seen. Returned only by POST /v1/deposit_addresses and …/rotate, each time a new one; only its hash is stored, and the newest 10 of an address stay valid. Give it only to the customer's page, and do not log it.

createdinteger (int64)required

Creation time, Unix seconds.

idstringrequired

da_ id.

livemodebooleanrequired

Whether the address is in live mode.

metadatamap of stringrequired

Your key/value pairs (metadata); {} when none. Each deposit to the address starts with a copy.

networksarray of DepositAddressNetworkrequired

The address on each supported network of the mode it was issued on, by chain_id, with the tokens it takes there.

object"deposit_address"required

Always deposit_address.

paymentsarray of Paymentrequired

Payments to the address in the last 24 hours, newest first, at most 10, as a quote's payment: seen in a block within about a block time of arriving, then recorded as a deposit. Display only; credit from deposit.credited.

retired_atinteger (int64) or null

Retirement time, Unix seconds; null while active.

saltstringrequired

CREATE2 salt, 32 bytes of hex; the same on every network.

statusstringrequired

active, or retired by a rotation; payments to either are credited.

versioninteger (int64)required

The address's version among the customer's addresses, from 1. The salt is keccak256(abi.encode(account, livemode, client_reference_id, "deposit_address", version)), with the types (string, bool, string, string, uint256) and account your acct_ id; it names no chain or asset. On each network the address is the factory's CREATE2 over that network's treasury and the salt.

Example
{  "address": "0x0f45147a02e4c9d91aff20024e22095536fd5053",  "client_reference_id": "team-42",  "client_secret": "da_7b2e9c4a1f6d48b3a5c0e2d4f6a8b1c3_secret_0a1b2c3d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f9",  "created": 1790553600,  "id": "da_7b2e9c4a1f6d48b3a5c0e2d4f6a8b1c3",  "livemode": false,  "metadata": {    "plan": "pro"  },  "networks": [    {      "address": "0x0f45147a02e4c9d91aff20024e22095536fd5053",      "assets": [        {          "asset": "usdc",          "contract": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",          "decimals": 6,          "payment_uri": "ethereum:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48@1/transfer?address=0x0f45147a02e4c9d91aff20024e22095536fd5053"        }      ],      "chain_id": 1,      "treasury": "0x936c1991f8da9a919fa11b557a3514719f5a4504"    }  ],  "object": "deposit_address",  "payments": [],  "retired_at": null,  "salt": "0x4e9767dd0c2ab5b953a305c3f10dc1e0d1f7c9d3cbab8463509d2edb06ca4b52",  "status": "active",  "version": 1}

DepositAddressAsset

A token a deposit address takes on one network.

assetstringrequired

Asset code, such as usdc.

contractstringrequired

ERC-20 contract address.

decimalsinteger (int32)required

ERC-20 decimal count.

max_deposit_atomicstring

Inclusive maximum per-transfer deposit at view time, in atomic units as a decimal string. Always populated from resolved terms in merchant and client deposit-address views; omitted (never null) in the admin restore response, which ignores held payment settings.

min_amountinteger (int64)

Minimum per-transfer credit at view time, in the account currency's minor units (USD cents). Enforced independently of the atomic bounds; smaller spot-valued deposits are not credited. Always populated from resolved terms in merchant and client deposit-address views; omitted (never null) in the admin restore response, which ignores held payment settings.

min_deposit_atomicstring

Inclusive minimum per-transfer deposit at view time, in atomic units as a decimal string. A zero atomic minimum does not waive the independent min_amount credit minimum. Always populated from resolved terms in merchant and client deposit-address views; omitted (never null) in the admin restore response, which ignores held payment settings.

payment_uristringrequired

EIP-681 ERC-20 transfer URI carrying the token, chain, and address, and no amount: the payer chooses it.

DepositAddressList

A page of deposit addresses, newest first (https://docs.stripe.com/api/pagination).

dataarray of DepositAddressrequired

The deposit addresses.

has_morebooleanrequired

Whether more addresses follow in the direction of this page.

object"list"required

Always list.

urlstringrequired

The list's path, /v1/deposit_addresses.

Example
{  "data": [    {      "address": "0x0f45147a02e4c9d91aff20024e22095536fd5053",      "client_reference_id": "team-42",      "client_secret": "da_7b2e9c4a1f6d48b3a5c0e2d4f6a8b1c3_secret_0a1b2c3d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f9",      "created": 1790553600,      "id": "da_7b2e9c4a1f6d48b3a5c0e2d4f6a8b1c3",      "livemode": false,      "metadata": {        "plan": "pro"      },      "networks": [        {          "address": "0x0f45147a02e4c9d91aff20024e22095536fd5053",          "assets": [            {              "asset": "usdc",              "contract": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",              "decimals": 6,              "payment_uri": "ethereum:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48@1/transfer?address=0x0f45147a02e4c9d91aff20024e22095536fd5053"            }          ],          "chain_id": 1,          "treasury": "0x936c1991f8da9a919fa11b557a3514719f5a4504"        }      ],      "object": "deposit_address",      "payments": [],      "retired_at": null,      "salt": "0x4e9767dd0c2ab5b953a305c3f10dc1e0d1f7c9d3cbab8463509d2edb06ca4b52",      "status": "active",      "version": 1    }  ],  "has_more": false,  "object": "list",  "url": "/v1/deposit_addresses"}

DepositAddressNetwork

A deposit address on one network (EVM chain).

addressstringrequired

The forwarder address to pay on this chain.

assetsarray of DepositAddressAssetrequired

The tokens your payment settings accept on this chain; any other token sent to the address is not credited.

chain_idinteger (int64)required

EVM chain identifier.

treasurystringrequired

The treasury the forwarder pays. The address is the same on every network whose treasury is the same address.

DepositAddressView

GET /v1/deposit_addresses/{id} returns a DepositAddress to a request with an API key and a ClientDepositAddress to a request by client_secret.

Example
{  "address": "0x0f45147a02e4c9d91aff20024e22095536fd5053",  "client_reference_id": "team-42",  "client_secret": "da_7b2e9c4a1f6d48b3a5c0e2d4f6a8b1c3_secret_0a1b2c3d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f9",  "created": 1790553600,  "id": "da_7b2e9c4a1f6d48b3a5c0e2d4f6a8b1c3",  "livemode": false,  "metadata": {    "plan": "pro"  },  "networks": [    {      "address": "0x0f45147a02e4c9d91aff20024e22095536fd5053",      "assets": [        {          "asset": "usdc",          "contract": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",          "decimals": 6,          "payment_uri": "ethereum:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48@1/transfer?address=0x0f45147a02e4c9d91aff20024e22095536fd5053"        }      ],      "chain_id": 1,      "treasury": "0x936c1991f8da9a919fa11b557a3514719f5a4504"    }  ],  "object": "deposit_address",  "payments": [],  "retired_at": null,  "salt": "0x4e9767dd0c2ab5b953a305c3f10dc1e0d1f7c9d3cbab8463509d2edb06ca4b52",  "status": "active",  "version": 1}

DepositAdmin

The operator's view of a deposit's internals (GET /v1/admin/deposits/{id}), returned as the admin field of the deposit; never present in a merchant response or an event.

accountstringrequired

The merchant account the deposit belongs to, acct_….

block_timestring (date-time)required

Including block time.

eventsarray of DepositEventDeliveryrequired

Events about the deposit in ascending creation order, with their delivery.

final_atstring (date-time) or null

When both providers showed the transfer at or below finalized.

price_scaledstring or null

Eight-decimal scaled price as a decimal string.

receipt_log_indexinteger (int64)required

Position of the transfer log in its transaction's receipt; with the chain and transaction, the deposit's identity.

routestring or null

Selected route.

route_versioninteger (int64) or null

Selected route version.

settings_holdstring (uuid) or null

The restore whose hold the deposit was recorded under; it waits for the merchant's reconfirmation, which binds it. null when settings_revision is set.

settings_revisionstring or null

The payment settings revision the deposit is bound to (psrev_…): current in the snapshot of the statement that recorded it. null while settings_hold is set.

statestringrequired

The processing state: detected, confirmed, credited, swept, rejected, or reversed (status is its merchant view).

transitionsarray of DepositTransitionrequired

Transitions in ascending creation order.

updated_atstring (date-time)required

Last processing update time.

DepositEventDelivery

An event about a deposit and its delivery state.

created_atstring (date-time)required

Event creation time.

delivered_atstring (date-time) or null

When the last of the account's webhook endpoints accepted the event, or null while one has not or the account has none.

idstringrequired

Event id, evt_….

typestringrequired

Event type, such as deposit.credited.

DepositList

A page of a list, newest first (https://docs.stripe.com/api/pagination).

dataarray of Depositrequired

The deposits.

has_morebooleanrequired

Whether more deposits follow in the direction of this page.

object"list"required

Always list.

urlstringrequired

The list's path, /v1/deposits.

Example
{  "data": [    {      "address": "0x2f3e91325b2288bce392711f85f5359661062a91",      "amount": 2500,      "amount_atomic": "25000000",      "amount_refunded": 0,      "amount_refunded_atomic": "0",      "amount_reversed": 0,      "asset": "usdc",      "asset_contract": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",      "block_hash": "0x9a1c3e5b7d0f2a4c6e8b0d2f4a6c8e0b2d4f6a8c0e2b4d6f8a0c2e4b6d8f0a2c",      "block_number": 21000000,      "block_time": 1790553612,      "chain_id": 1,      "client_reference_id": "team-42",      "created": 1790553624,      "currency": "usd",      "deposit_address": null,      "exchange_rate": "1.00000000",      "final": true,      "final_at": 1790554572,      "from_address": "0x1775c1326aa633546b0b5634ae2bef0ba7cbfc9a",      "id": "dep_8a1f4e2b6c3d49e0a7b5c1d2e3f40516",      "livemode": false,      "log_index": 212,      "metadata": {        "order_id": "ord_1001"      },      "object": "deposit",      "price_source": "quote",      "quote": "qt_5f1c0b6a2d9e4f3a8b7c6d5e4f3a2b10",      "receipt_log_index": 0,      "refunded": false,      "rejection_reason": null,      "replaced_by": null,      "replaces": null,      "revision": 0,      "status": "credited",      "swept": false,      "tx_hash": "0x7d3c1e5a9b2f4d6c8e0a1b3d5f7c9e2a4b6d8f0c1e3a5b7d9f1c3e5a7b9d1f3e",      "valued_at": 1790553630    }  ],  "has_more": false,  "object": "list",  "url": "/v1/deposits"}

DepositTransition

One immutable state transition of a deposit.

attemptinteger (int32)required

Retry attempt recorded for this transition.

created_atstring (date-time)required

Transition creation time.

evidenceanyrequired

Durable transition evidence.

from_statestringrequired

State before the transition attempt.

idstring (uuid)required

Timeline row identifier.

to_statestringrequired

State after the transition attempt.

ErrorDetail

Stable error fields safe to expose to callers.

codestringrequired

Stable machine-readable error code; clients accept future codes.

doc_urlstring

The documentation of code in the API reference. Every error of this service carries it; it is optional in the schema, as in Stripe's, so a client never fails on an error without it.

messagestringrequired

Human-readable summary without internal details; it may change.

paramstring or null

The request parameter the error is about, when there is one.

typeErrorTyperequired

Error category: invalid_request_error for any 4xx except an idempotency conflict, idempotency_error for an Idempotency-Key reused with another request or still in use, api_error for 5xx.

ErrorResponse

Machine-readable error envelope returned by every API failure, Stripe's error object (https://docs.stripe.com/api/errors).

errorErrorDetailrequired

Error details.

Example
{  "error": {    "code": "deposit_not_final",    "doc_url": "https://phala-network.github.io/phala-pay/#section/Errors/deposit_not_final",    "message": "the deposit is not final yet; request the refund once it is (about 15 minutes after its block on Ethereum)",    "type": "invalid_request_error"  }}

ErrorType

Error category of [ErrorDetail].

EventData

An event's data.

objectobjectrequired

The object's API representation when the event was created: a deposit, quote, refund, API key, treasury, webhook endpoint, or the account, as its GET returned it then.

previous_attributesobject or null

On *.updated events: the fields that changed, with their values before the change (a changed metadata holds only its changed keys; a field that was added is null).

EventList

A page of events, newest first (https://docs.stripe.com/api/pagination).

dataarray of EventObjectResponserequired

The events.

has_morebooleanrequired

Whether more events follow in the direction of this page.

object"list"required

Always list.

urlstringrequired

The list's path, /v1/events.

Example
{  "data": [    {      "account": "acct_0c6e1d0a9b3f4c2e8d7a6b5c4d3e2f10",      "actor": "system",      "created": 1790553630,      "data": {        "object": {          "address": "0x2f3e91325b2288bce392711f85f5359661062a91",          "amount": 2500,          "amount_atomic": "25000000",          "amount_refunded": 0,          "amount_refunded_atomic": "0",          "amount_reversed": 0,          "asset": "usdc",          "asset_contract": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",          "block_hash": "0x9a1c3e5b7d0f2a4c6e8b0d2f4a6c8e0b2d4f6a8c0e2b4d6f8a0c2e4b6d8f0a2c",          "block_number": 21000000,          "block_time": 1790553612,          "chain_id": 1,          "client_reference_id": "team-42",          "created": 1790553624,          "currency": "usd",          "deposit_address": null,          "exchange_rate": "1.00000000",          "final": false,          "final_at": 1790554572,          "from_address": "0x1775c1326aa633546b0b5634ae2bef0ba7cbfc9a",          "id": "dep_8a1f4e2b6c3d49e0a7b5c1d2e3f40516",          "livemode": false,          "log_index": 212,          "metadata": {            "order_id": "ord_1001"          },          "object": "deposit",          "price_source": "quote",          "quote": "qt_5f1c0b6a2d9e4f3a8b7c6d5e4f3a2b10",          "receipt_log_index": 0,          "refunded": false,          "rejection_reason": null,          "replaced_by": null,          "replaces": null,          "revision": 0,          "status": "credited",          "swept": false,          "tx_hash": "0x7d3c1e5a9b2f4d6c8e0a1b3d5f7c9e2a4b6d8f0c1e3a5b7d9f1c3e5a7b9d1f3e",          "valued_at": 1790553630        }      },      "id": "evt_2b4d6f8a0c1e43b5d7f9a1c3e5b7d9f0",      "livemode": false,      "object": "event",      "pending_webhooks": 0,      "request": null,      "type": "deposit.credited"    }  ],  "has_more": false,  "object": "list",  "url": "/v1/events"}

EventObjectResponse

An event (https://docs.stripe.com/api/events/object): what happened to an object of the account in one mode, and who caused it. The same object is the body of every webhook delivery; GET /v1/events is also the account's audit log.

accountstringrequired

The account, acct_….

actorstringrequired

Who caused it: an API key id (key_…), admin (the operator), or system.

createdinteger (int64)required

Creation time, Unix seconds.

dataEventDatarequired

The object when the event happened: object is its API representation, rendered in the same transaction as the change and never changed afterwards, so it can differ from a later GET of the object. *.updated events add previous_attributes, the former values of the fields that changed (https://docs.stripe.com/api/events/object).

idstringrequired

Event id, evt_…, also the webhook-id header of its deliveries.

livemodebooleanrequired

The event's mode.

object"event"required

Always event.

pending_webhooksinteger (int64)required

Deliveries to webhook endpoints that are neither delivered nor stopped.

requestEventRequest or any or null
typestringrequired

Event type, such as deposit.credited.

Example
{  "account": "acct_0c6e1d0a9b3f4c2e8d7a6b5c4d3e2f10",  "actor": "system",  "created": 1790553630,  "data": {    "object": {      "address": "0x2f3e91325b2288bce392711f85f5359661062a91",      "amount": 2500,      "amount_atomic": "25000000",      "amount_refunded": 0,      "amount_refunded_atomic": "0",      "amount_reversed": 0,      "asset": "usdc",      "asset_contract": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",      "block_hash": "0x9a1c3e5b7d0f2a4c6e8b0d2f4a6c8e0b2d4f6a8c0e2b4d6f8a0c2e4b6d8f0a2c",      "block_number": 21000000,      "block_time": 1790553612,      "chain_id": 1,      "client_reference_id": "team-42",      "created": 1790553624,      "currency": "usd",      "deposit_address": null,      "exchange_rate": "1.00000000",      "final": false,      "final_at": 1790554572,      "from_address": "0x1775c1326aa633546b0b5634ae2bef0ba7cbfc9a",      "id": "dep_8a1f4e2b6c3d49e0a7b5c1d2e3f40516",      "livemode": false,      "log_index": 212,      "metadata": {        "order_id": "ord_1001"      },      "object": "deposit",      "price_source": "quote",      "quote": "qt_5f1c0b6a2d9e4f3a8b7c6d5e4f3a2b10",      "receipt_log_index": 0,      "refunded": false,      "rejection_reason": null,      "replaced_by": null,      "replaces": null,      "revision": 0,      "status": "credited",      "swept": false,      "tx_hash": "0x7d3c1e5a9b2f4d6c8e0a1b3d5f7c9e2a4b6d8f0c1e3a5b7d9f1c3e5a7b9d1f3e",      "valued_at": 1790553630    }  },  "id": "evt_2b4d6f8a0c1e43b5d7f9a1c3e5b7d9f0",  "livemode": false,  "object": "event",  "pending_webhooks": 0,  "request": null,  "type": "deposit.credited"}

EventRequest

The API request that caused an event (https://docs.stripe.com/api/events/object).

idstringrequired

The request's Request-Id, req_….

idempotency_keystring or null

The Idempotency-Key the request sent; null when it sent none.

ExpandableDeposit

A deposit id, or the deposit with expand[].

ExpandableQuote

A quote id, or the quote with expand[].

Forwarder

A forwarder the account was issued (design §13): everything needed to recompute its address and sweep it without Phala Pay. The address is factory's CREATE2 clone of the pinned implementation over treasury and salt.

addressstringrequired

The forwarder address.

chain_idinteger (int64)required

EVM chain identifier.

deposit_addressstring or null

The deposit address it is a network of, da_…; null for a quote's.

factorystringrequired

The forwarder factory.

idstringrequired

Forwarder id, fwd_….

livemodebooleanrequired

The mode.

object"forwarder"required

Always forwarder.

quotestring or null

The quote it was issued for, qt_…; null for a deposit address's network.

saltstringrequired

The CREATE2 salt, 32 bytes of hex.

superseded_atinteger (int64) or null

When a treasury change replaced this deposit address network, Unix seconds; it is still watched and credited, and pays its own treasury.

treasurystringrequired

The treasury the forwarder pays, fixed in its address.

ForwarderList

A page of forwarders (https://docs.stripe.com/api/pagination), in id order.

dataarray of Forwarderrequired

The forwarders.

has_morebooleanrequired

Whether more forwarders follow in the direction of this page.

object"list"required

Always list.

urlstringrequired

The list's path, /v1/forwarders.

Example
{  "data": [    {      "address": "0x2f3e91325b2288bce392711f85f5359661062a91",      "chain_id": 1,      "deposit_address": null,      "factory": "0x9e5f1d3c7a2b4e6f8a0c1d3e5f7a9b2c4d6e8f01",      "id": "fwd_5c7e9a1b3d2f44c6e8a0b2d4f6c8e0a2",      "livemode": false,      "object": "forwarder",      "quote": "qt_5f1c0b6a2d9e4f3a8b7c6d5e4f3a2b10",      "salt": "0x4e9767dd0c2ab5b953a305c3f10dc1e0d1f7c9d3cbab8463509d2edb06ca4b52",      "superseded_at": null,      "treasury": "0x936c1991f8da9a919fa11b557a3514719f5a4504"    }  ],  "has_more": false,  "object": "list",  "url": "/v1/forwarders"}

KnownErrorCode

MarkRefundPaidRequest

POST /v1/refunds/{id}/mark_paid body: the merchant's refund transaction.

receipt_log_indexinteger (int64) or null

Position of the Transfer log that pays the refund among the logs of the transaction's receipt (0 for the first), not the block-wide logIndex, which changes if the transaction is re-included in another block; any matching log when absent.

transaction_hashstringrequired

Hash of the transaction that pays the refund from the treasury of the deposit's address.

Example
{  "receipt_log_index": 0,  "transaction_hash": "0x4b6d8f0a2c4e6a8c0e2b4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c"}

MetadataClear

"": unset every key of the object's metadata.

MetadataParam

A metadata parameter: an object of string values, where "" unsets the key, or "" to unset every key.

Payment

A payment observed at a quote's address or a deposit address. Display only: while status is seen it may still disappear in a reorg, and nothing has been credited.

amount_atomicstringrequired

Token amount in base units, as a decimal string.

assetstring or null

Asset code; null for a token without a route.

chain_idinteger (int64)required

EVM chain identifier.

confirmationsinteger (int64) or null

Blocks on top of and including the transfer's block at the last head scan; seen only.

depositstringrequired

dep_ id the deposit has, or will have once recorded.

estimated_final_atinteger (int64) or null

Estimated finality time, Unix seconds: block time plus 15 minutes; seen only.

matches_quoteboolean or null

On a quote: whether the payment is the quote's asset, in time, and within tolerance, so it is credited at the quoted price (otherwise at spot). null on a deposit address, whose payments are all credited at spot.

statusstringrequired

seen (in a block, not recorded as a deposit yet) or recorded (recorded as a deposit at the route's confirmation; follow it as deposit). New values may be added.

tx_hashstringrequired

Canonical transaction hash.

PaymentSettingsAsset

An accepted asset and your terms on it; a term null or not sent takes the operator's default.

assetstringrequired

An asset code routed on the chain, such as usdc.

max_deposit_atomicstring or null

The maximum creditable deposit in base units, a decimal string.

min_amountinteger (int64) or null

The minimum credit in cents of a quote or a deposit valued at spot.

min_deposit_atomicstring or null

The minimum creditable deposit in base units, a decimal string.

min_refund_atomicstring or null

The refund dust floor in base units, a decimal string.

quote_spread_bpsinteger (int32) or null

A quote's spread below spot, in basis points.

quote_tolerance_bpsinteger (int32) or null

A quote's two-sided payment tolerance, in basis points.

quote_ttl_secondsinteger (int64) or null

A quote's payment window, in seconds.

PaymentSettingsChain

An accepted chain of your payment settings.

assetsarray of PaymentSettingsAssetrequired

The accepted assets of the chain, at least one.

chain_idinteger (int64)required

A chain of the key's mode.

confirmationsstring or null

The confirmation you require on the chain: a depth ("12": the block and eleven more), "safe", or "finalized", never weaker than the chain's floor and of the chain's kind (a depth or finalized on Ethereum; a depth, safe, or finalized on an OP-stack chain). null for the floor.

PaymentSettingsObject

Your payment settings in the key's mode (GET /v1/payment_settings): what you accept and on what terms, chosen from the operator's catalog within its bounds (docs/design/payment-settings.md).

availablearray of AvailableChainrequired

The operator's catalog of the mode: every chain and asset you may accept, with its defaults and bounds, and whether you accept it.

chainsarray of PaymentSettingsChainrequired

The chains you accept, each with its accepted assets. A chain or asset not listed is not accepted.

livemodebooleanrequired

The mode of the key that reads it.

object"payment_settings"required

Always payment_settings.

quote_creations_per_customer_per_minuteinteger (int64) or nullrequired

One customer's quote creations in a rolling minute; null for the default.

revisionstringrequired

The current revision, psrev_…: unique and never reused, with no order.

statusstringrequired

unconfigured (accepts nothing: never configured), configured, or held (after a restore of the service, until you reconfirm with POST /v1/payment_settings; nothing is accepted meanwhile, and payments recorded wait).

updatedinteger (int64)required

When the current revision was written, Unix seconds.

Example
{  "available": [    {      "assets": [        {          "accepted": true,          "asset": "usdc",          "contract": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",          "decimals": 6,          "enabled": true,          "max_deposit_atomic": {            "default": "10000000000",            "max": "10000000000",            "min": "0"          },          "min_amount": {            "default": 100,            "max": 18446744073709552000,            "min": 100          },          "min_deposit_atomic": {            "default": "0",            "max": "115792089237316195423570985008687907853269984665640564039457584007913129639935",            "min": "0"          },          "min_refund_atomic": {            "default": "1000000",            "max": "1000000",            "min": "1000000"          },          "pricing": "stablecoin",          "quote_amount_decimals": 4,          "quote_spread_bps": {            "default": 0,            "max": 500,            "min": 0          },          "quote_tolerance_bps": {            "default": 100,            "max": 500,            "min": 0          },          "quote_ttl_seconds": {            "default": 900,            "max": 3600,            "min": 30          }        },        {          "accepted": true,          "asset": "usdt",          "contract": "0xdac17f958d2ee523a2206206994597c13d831ec7",          "decimals": 6,          "enabled": true,          "max_deposit_atomic": {            "default": "10000000000",            "max": "10000000000",            "min": "0"          },          "min_amount": {            "default": 100,            "max": 18446744073709552000,            "min": 100          },          "min_deposit_atomic": {            "default": "0",            "max": "115792089237316195423570985008687907853269984665640564039457584007913129639935",            "min": "0"          },          "min_refund_atomic": {            "default": "1000000",            "max": "1000000",            "min": "1000000"          },          "pricing": "stablecoin",          "quote_amount_decimals": 4,          "quote_spread_bps": {            "default": 0,            "max": 500,            "min": 0          },          "quote_tolerance_bps": {            "default": 100,            "max": 500,            "min": 0          },          "quote_ttl_seconds": {            "default": 900,            "max": 3600,            "min": 30          }        }      ],      "chain_id": 1,      "confirmations": {        "default": "2",        "floor": "2"      },      "status": "active"    }  ],  "chains": [    {      "assets": [        {          "asset": "usdc",          "quote_spread_bps": 0        },        {          "asset": "usdt"        }      ],      "chain_id": 1,      "confirmations": "12"    }  ],  "livemode": false,  "object": "payment_settings",  "quote_creations_per_customer_per_minute": null,  "revision": "psrev_5b0e4f1a9c3d4e7f8a2b6c1d0e9f8a7b",  "status": "configured",  "updated": 1790467200}

Quote

A quote: a locked price, an exact token amount, and a single-use address to pay it to.

addressstringrequired

Single-use forwarder address to pay.

amountinteger (int64)required

Credit in the currency's minor unit.

amount_atomicstringrequired

The exact token amount to pay, in base units, as a decimal string.

assetstringrequired

Asset code.

cancel_requested_atinteger (int64) or null

Deferred cancellation request time, Unix seconds; null before a request.

chain_idinteger (int64)required

EVM chain identifier.

client_reference_idstringrequired

Your identifier of the customer the quote credits.

client_secretstring or null

Lets the payer's browser read the quote's public view, ClientQuote, from GET /v1/quotes/{id}?client_secret=… without an API key. Returned only by POST /v1/quotes; a repeat with the same Idempotency-Key within 24 hours replays the first response, the same secret included. Give it only to the paying customer's page, and do not log it.

createdinteger (int64)required

Creation time, Unix seconds.

currencystringrequired

usd.

depositExpandableDeposit or any or null
exchange_ratestringrequired

The locked price in USD per token, a decimal string with 8 decimal places.

expires_atinteger (int64)required

End of the payment window, Unix seconds.

idstringrequired

qt_ id. The quote's address salt is keccak256(abi.encode(account, client_reference_id, "quote", id)) with the types (string, string, string, string), where account is your acct_ id.

livemodebooleanrequired

Whether the quote was created with a live key.

metadatamap of stringrequired

Your key/value pairs (metadata); {} when none.

object"quote"required

Always quote.

paymentPayment or any or null
payment_uristringrequired

EIP-681 URI carrying the token, chain, address, and amount.

statusstringrequired

open, complete (a matching payment consumed it), expired, or canceled. A quote stays open after expires_at until the finalized chain passes it, so a payment mined in time is never reported as expired; hide the address once expires_at has passed.

termsQuoteTermsrequired

The terms the quote was issued with, from your payment settings then; the quote keeps them whatever the settings say later.

treasurystringrequired

The treasury the address pays: your treasury of the chain when the quote was created. The address is the factory's CREATE2 over it and the salt.

Example
{  "address": "0x2f3e91325b2288bce392711f85f5359661062a91",  "amount": 2500,  "amount_atomic": "25000000",  "asset": "usdc",  "chain_id": 1,  "client_reference_id": "team-42",  "client_secret": "qt_5f1c0b6a2d9e4f3a8b7c6d5e4f3a2b10_secret_9f8e7d6c5b4a39281706f5e4d3c2b1a0f9e8d7c6b5a4938271605f4e3d2c1b0a",  "created": 1790553600,  "currency": "usd",  "deposit": null,  "exchange_rate": "1.00000000",  "expires_at": 1790554500,  "id": "qt_5f1c0b6a2d9e4f3a8b7c6d5e4f3a2b10",  "livemode": false,  "metadata": {    "order_id": "ord_1001"  },  "object": "quote",  "payment": {    "amount_atomic": "25000000",    "asset": "usdc",    "chain_id": 1,    "confirmations": 1,    "deposit": "dep_8a1f4e2b6c3d49e0a7b5c1d2e3f40516",    "estimated_final_at": 1790554572,    "matches_quote": true,    "status": "seen",    "tx_hash": "0x7d3c1e5a9b2f4d6c8e0a1b3d5f7c9e2a4b6d8f0c1e3a5b7d9f1c3e5a7b9d1f3e"  },  "payment_uri": "ethereum:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48@1/transfer?address=0x2f3e91325b2288bce392711f85f5359661062a91&uint256=25000000",  "status": "open",  "terms": {    "confirmations": "12",    "max_deposit_atomic": "10000000000",    "min_amount": 100,    "min_deposit_atomic": "0",    "min_refund_atomic": "1000000",    "quote_amount_decimals": 4,    "quote_spread_bps": 0,    "quote_tolerance_bps": 100,    "quote_ttl_seconds": 900  },  "treasury": "0x936c1991f8da9a919fa11b557a3514719f5a4504"}

QuoteList

A page of quotes, newest first (https://docs.stripe.com/api/pagination).

dataarray of Quoterequired

The quotes.

has_morebooleanrequired

Whether more quotes follow in the direction of this page.

object"list"required

Always list.

urlstringrequired

The list's path, /v1/quotes.

Example
{  "data": [    {      "address": "0x2f3e91325b2288bce392711f85f5359661062a91",      "amount": 2500,      "amount_atomic": "25000000",      "asset": "usdc",      "chain_id": 1,      "client_reference_id": "team-42",      "client_secret": "qt_5f1c0b6a2d9e4f3a8b7c6d5e4f3a2b10_secret_9f8e7d6c5b4a39281706f5e4d3c2b1a0f9e8d7c6b5a4938271605f4e3d2c1b0a",      "created": 1790553600,      "currency": "usd",      "deposit": null,      "exchange_rate": "1.00000000",      "expires_at": 1790554500,      "id": "qt_5f1c0b6a2d9e4f3a8b7c6d5e4f3a2b10",      "livemode": false,      "metadata": {        "order_id": "ord_1001"      },      "object": "quote",      "payment": {        "amount_atomic": "25000000",        "asset": "usdc",        "chain_id": 1,        "confirmations": 1,        "deposit": "dep_8a1f4e2b6c3d49e0a7b5c1d2e3f40516",        "estimated_final_at": 1790554572,        "matches_quote": true,        "status": "seen",        "tx_hash": "0x7d3c1e5a9b2f4d6c8e0a1b3d5f7c9e2a4b6d8f0c1e3a5b7d9f1c3e5a7b9d1f3e"      },      "payment_uri": "ethereum:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48@1/transfer?address=0x2f3e91325b2288bce392711f85f5359661062a91&uint256=25000000",      "status": "open",      "terms": {        "confirmations": "12",        "max_deposit_atomic": "10000000000",        "min_amount": 100,        "min_deposit_atomic": "0",        "min_refund_atomic": "1000000",        "quote_amount_decimals": 4,        "quote_spread_bps": 0,        "quote_tolerance_bps": 100,        "quote_ttl_seconds": 900      },      "treasury": "0x936c1991f8da9a919fa11b557a3514719f5a4504"    }  ],  "has_more": false,  "object": "list",  "url": "/v1/quotes"}

QuoteTerms

The terms a quote was issued with.

confirmationsstringrequired

The confirmation the quote required when issued: a depth, safe, or finalized. A payment not credited yet waits for the stricter of it and the chain's current floor.

max_deposit_atomicstringrequired

Maximum creditable deposit in base units, as a decimal string.

min_amountinteger (int64)required

Minimum credit in cents of a payment valued at spot.

min_deposit_atomicstringrequired

Minimum creditable deposit in base units, as a decimal string.

min_refund_atomicstringrequired

Refund dust floor in base units, as a decimal string.

quote_amount_decimalsinteger (int32)required

Token decimals amount_atomic was rounded up to.

quote_spread_bpsinteger (int32)required

The spread below spot of the locked price, in basis points.

quote_tolerance_bpsinteger (int32)required

A payment within this many basis points of amount_atomic, either way, completes the quote at its amount.

quote_ttl_secondsinteger (int64)required

The payment window, in seconds.

QuoteView

GET /v1/quotes/{id} returns a Quote to a signed request and a ClientQuote to a request by client_secret.

Example
{  "address": "0x2f3e91325b2288bce392711f85f5359661062a91",  "amount": 2500,  "amount_atomic": "25000000",  "asset": "usdc",  "chain_id": 1,  "client_reference_id": "team-42",  "client_secret": "qt_5f1c0b6a2d9e4f3a8b7c6d5e4f3a2b10_secret_9f8e7d6c5b4a39281706f5e4d3c2b1a0f9e8d7c6b5a4938271605f4e3d2c1b0a",  "created": 1790553600,  "currency": "usd",  "deposit": null,  "exchange_rate": "1.00000000",  "expires_at": 1790554500,  "id": "qt_5f1c0b6a2d9e4f3a8b7c6d5e4f3a2b10",  "livemode": false,  "metadata": {    "order_id": "ord_1001"  },  "object": "quote",  "payment": {    "amount_atomic": "25000000",    "asset": "usdc",    "chain_id": 1,    "confirmations": 1,    "deposit": "dep_8a1f4e2b6c3d49e0a7b5c1d2e3f40516",    "estimated_final_at": 1790554572,    "matches_quote": true,    "status": "seen",    "tx_hash": "0x7d3c1e5a9b2f4d6c8e0a1b3d5f7c9e2a4b6d8f0c1e3a5b7d9f1c3e5a7b9d1f3e"  },  "payment_uri": "ethereum:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48@1/transfer?address=0x2f3e91325b2288bce392711f85f5359661062a91&uint256=25000000",  "status": "open",  "terms": {    "confirmations": "12",    "max_deposit_atomic": "10000000000",    "min_amount": 100,    "min_deposit_atomic": "0",    "min_refund_atomic": "1000000",    "quote_amount_decimals": 4,    "quote_spread_bps": 0,    "quote_tolerance_bps": 100,    "quote_ttl_seconds": 900  },  "treasury": "0x936c1991f8da9a919fa11b557a3514719f5a4504"}

Refund

A refund of (part of) a deposit to the customer, which the merchant pays from the treasury of the deposit's address and attaches with mark_paid (design D5).

amount_atomicstringrequired

Token amount in base units, as a decimal string.

createdinteger (int64)required

Request time, Unix seconds.

depositExpandableDepositrequired

The refunded deposit: its dep_ id, or the object with expand[]=deposit.

destination_addressstringrequired

Destination address.

failure_reasonstring or null

Why the refund failed: transaction_failed, transfer_not_found, sender_mismatch, destination_mismatch, amount_mismatch, or transfer_already_used. Historical refunds may retain transaction_dropped or transaction_not_found; missing transactions now remain pending with their reservation and alert after 24 hours. New values may be added.

idstringrequired

re_ id.

livemodebooleanrequired

Whether the refund was requested with a live key.

metadatamap of stringrequired

Your key/value pairs (metadata); {} when none.

object"refund"required

Always refund.

receipt_log_indexinteger (int64) or null

Position of the paying Transfer log among the logs of the transaction's receipt: as named when marked paid, or found at verification.

statusstringrequired

pending (awaiting payment, or its transaction's finality), succeeded (the transfer is final), failed (the attached transaction does not pay the refund; see failure_reason), or canceled (only before a transaction is attached). A refund marked paid stays pending, reserving its amount of the deposit, until it is succeeded or failed.

transaction_hashstring or null

The attached refund transaction, once marked paid.

treasurystringrequired

The treasury the refund must be paid from: the one the deposit's address pays, which may differ from the account's current treasury.

Example
{  "amount_atomic": "25000000",  "created": 1790557200,  "deposit": "dep_8a1f4e2b6c3d49e0a7b5c1d2e3f40516",  "destination_address": "0x1775c1326aa633546b0b5634ae2bef0ba7cbfc9a",  "failure_reason": null,  "id": "re_3c9e7a1b5d2f4a6c8e0b1d3f5a7c9e02",  "livemode": false,  "metadata": {    "ticket": "support-311"  },  "object": "refund",  "receipt_log_index": 0,  "status": "pending",  "transaction_hash": "0x4b6d8f0a2c4e6a8c0e2b4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c",  "treasury": "0x936c1991f8da9a919fa11b557a3514719f5a4504"}

RefundList

A page of refunds, newest first (https://docs.stripe.com/api/pagination).

dataarray of Refundrequired

The refunds.

has_morebooleanrequired

Whether more refunds follow in the direction of this page.

object"list"required

Always list.

urlstringrequired

The list's path, /v1/refunds.

Example
{  "data": [    {      "amount_atomic": "25000000",      "created": 1790557200,      "deposit": "dep_8a1f4e2b6c3d49e0a7b5c1d2e3f40516",      "destination_address": "0x1775c1326aa633546b0b5634ae2bef0ba7cbfc9a",      "failure_reason": null,      "id": "re_3c9e7a1b5d2f4a6c8e0b1d3f5a7c9e02",      "livemode": false,      "metadata": {        "ticket": "support-311"      },      "object": "refund",      "receipt_log_index": 0,      "status": "pending",      "transaction_hash": "0x4b6d8f0a2c4e6a8c0e2b4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c",      "treasury": "0x936c1991f8da9a919fa11b557a3514719f5a4504"    }  ],  "has_more": false,  "object": "list",  "url": "/v1/refunds"}

ResendEventRequest

POST /v1/events/{id}/resend body.

webhook_endpointstringrequired

The enabled endpoint to deliver the event to again, we_….

Example
{  "webhook_endpoint": "we_9e1c3a5b7d2f40c6e8a0b2d4f6a8c0e1"}

RollApiKeyRequest

POST /v1/api_keys/{id}/roll body.

expires_ininteger (int32)

Seconds the old key keeps working, up to 604800 (7 days); 0, the default, revokes it at once. A key rolling itself needs at least 3600.

Example
{  "expires_in": 86400}

RollWebhookKeyRequest

POST /v1/account/webhook_keys/roll body.

expires_ininteger (int32)

Seconds the current key keeps signing beside the new one: 172800 (48 hours, the treasury time-lock) to 604800 (7 days) in live mode, 0 to 604800 in test mode, where 0 stops it at once. Default 172800.

Example
{  "expires_in": 172800}

SubmitDepositAddressTransactionRequest

The deposit address must already have a network for this chain.

chain_idinteger (int64)required

One of this object's issued network identifiers.

transaction_hashstringrequired

Transaction hash, exactly 32 hexadecimal bytes prefixed by 0x.

Example
{  "chain_id": 84532,  "transaction_hash": "0x7d3c1e5a9b2f4d6c8e0a1b3d5f7c9e2a4b6d8f0c1e3a5b7d9f1c3e5a7b9d1f3e"}

SubmitQuoteTransactionRequest

A quote's chain is derived from its stored terms.

transaction_hashstringrequired

Transaction hash, exactly 32 hexadecimal bytes prefixed by 0x.

Example
{  "transaction_hash": "0x7d3c1e5a9b2f4d6c8e0a1b3d5f7c9e2a4b6d8f0c1e3a5b7d9f1c3e5a7b9d1f3e"}

Sweep

A sweep: one finalized Flushed event of the factory, which moved a forwarder's whole balance of a token to its treasury (Stripe's Payout). Anyone can send the flush; the merchant usually does, with the SDK's flush_transaction or safe_batch.

addressstringrequired

The forwarder's address.

amount_atomicstringrequired

Amount moved, in base units, as a decimal string.

assetstring or null

Asset code; null for a token without a route.

block_numberinteger (int64)required

Block number of the transaction.

chain_idinteger (int64)required

EVM chain identifier.

createdinteger (int64)required

When the finalized event was indexed, Unix seconds.

forwarderstringrequired

The forwarder swept, fwd_….

idstringrequired

Sweep id, sw_….

livemodebooleanrequired

The mode.

log_indexinteger (int64)required

Block-wide index of the Flushed log.

object"sweep"required

Always sweep.

tokenstringrequired

The token contract.

treasurystringrequired

The treasury paid, fixed in the forwarder's address.

tx_hashstringrequired

The flush transaction.

SweepList

A page of sweeps, newest first (https://docs.stripe.com/api/pagination).

dataarray of Sweeprequired

The sweeps.

has_morebooleanrequired

Whether more sweeps follow in the direction of this page.

object"list"required

Always list.

urlstringrequired

The list's path, /v1/sweeps.

Example
{  "data": [    {      "address": "0x2f3e91325b2288bce392711f85f5359661062a91",      "amount_atomic": "25000000",      "asset": "usdc",      "block_number": 21000420,      "chain_id": 1,      "created": 1790560800,      "forwarder": "fwd_5c7e9a1b3d2f44c6e8a0b2d4f6c8e0a2",      "id": "sw_1e3c5a7b9d0f42e4c6a8b0d2f4e6a8c0",      "livemode": false,      "log_index": 7,      "object": "sweep",      "token": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",      "treasury": "0x936c1991f8da9a919fa11b557a3514719f5a4504",      "tx_hash": "0x4b6d8f0a2c4e6a8c0e2b4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c"    }  ],  "has_more": false,  "object": "list",  "url": "/v1/sweeps"}

TransactionSubmission

A quiet acknowledgement, including for ignored hints.

objectTransactionSubmissionObjectrequired

Object discriminator.

statusTransactionSubmissionStatusrequired

Acknowledgement only; poll the original object for payment status.

transaction_hashstringrequired

Hash echoed from the submission.

Example
{  "object": "transaction_submission",  "status": "received",  "transaction_hash": "0x7d3c1e5a9b2f4d6c8e0a1b3d5f7c9e2a4b6d8f0c1e3a5b7d9f1c3e5a7b9d1f3e"}

TransactionSubmissionObject

Constant submission object discriminator.

TransactionSubmissionStatus

Received acknowledges submission only, never detection or verification.

Treasury

An account's treasury of one chain and mode (design D10): the only address the forwarders issued over it can pay.

addressstringrequired

The treasury address.

canceled_atinteger (int64) or null

When it was canceled, Unix seconds.

cancellation_reasonstring or null

Why it was canceled: requested (you canceled it) or sanctioned (a sanctions list named the address when the change was due to apply, so it never applied).

chain_idinteger (int64)required

EVM chain identifier.

createdinteger (int64)required

When it was proven, Unix seconds.

crediting_pausedbooleanrequired

Whether crediting of deposits to forwarders over this address is paused: they stay pending and no deposit.credited is sent until it resumes.

crediting_paused_byarray of stringrequired

Who paused crediting: merchant (POST /v1/treasuries/{id}/pause) and, or, operator. Each lifts only its own pause.

effective_atinteger (int64)required

When the treasury applies or applied, Unix seconds: at once for a chain's first treasury and in test mode, 48 hours after the proof for a later live change.

idstringrequired

Treasury id, trs_….

kindstringrequired

eoa (an EIP-191 signature recovered to the address) or contract (a deployed contract's EIP-1271 approval).

livemodebooleanrequired

The mode.

object"treasury"required

Always treasury.

replaced_atinteger (int64) or null

When a later treasury replaced it, Unix seconds.

statusstringrequired

pending (a live change waiting for effective_at; cancel it with POST /v1/treasuries/{id}/cancel), active (the chain's current treasury: new quotes and deposit address networks pay it), replaced (a former treasury; addresses issued over it still pay it), or canceled.

Example
{  "address": "0x936c1991f8da9a919fa11b557a3514719f5a4504",  "canceled_at": null,  "cancellation_reason": null,  "chain_id": 1,  "created": 1790467200,  "crediting_paused": false,  "crediting_paused_by": [],  "effective_at": 1790467200,  "id": "trs_4d8a2c6e0b1f47a3c5e7d9b1a3c5e7f9",  "kind": "contract",  "livemode": false,  "object": "treasury",  "replaced_at": null,  "status": "active"}

TreasuryChallenge

An EIP-4361 (Sign-In with Ethereum) message proving a treasury, usable once: valid for 10 minutes for an EOA, 24 hours for an address that holds code (a Safe).

addressstringrequired

The treasury address, as sent.

chain_idinteger (int64)required

The treasury's chain.

expires_atinteger (int64)required

When the message stops being accepted, Unix seconds.

livemodebooleanrequired

The key's mode.

messagestringrequired

The EIP-4361 message to sign, exactly as given: domain and URI are the API's origin, the statement names your account and mode, and Chain ID is chain_id. An EOA signs it with personal_sign (EIP-191); a Safe's owners sign it as a Safe message (EIP-1271).

noncestringrequired

The message's single-use nonce.

object"treasury_challenge"required

Always treasury_challenge.

Example
{  "address": "0x936c1991f8da9a919fa11b557a3514719f5a4504",  "chain_id": 1,  "expires_at": 1790554200,  "livemode": false,  "message": "pay-api.phala.com wants you to sign in with your Ethereum account:\n0x936c1991f8dA9a919fa11b557a3514719f5A4504\n\nSet this address as the test mode treasury of acct_0c6e1d0a9b3f4c2e8d7a6b5c4d3e2f10 on Phala Pay.\n\nURI: https://pay-api.phala.com\nVersion: 1\nChain ID: 1\nNonce: Kq3nV8xZt2mP6wRa\nIssued At: 2026-09-28T12:00:00Z\nExpiration Time: 2026-09-28T12:10:00Z",  "nonce": "Kq3nV8xZt2mP6wRa",  "object": "treasury_challenge"}

TreasuryList

GET /v1/treasuries response.

dataarray of Treasuryrequired

The mode's treasuries, newest first.

has_morebooleanrequired

Whether more treasuries match than limit.

object"list"required

Always list.

urlstringrequired

The list's path, /v1/treasuries.

Example
{  "data": [    {      "address": "0x936c1991f8da9a919fa11b557a3514719f5a4504",      "canceled_at": null,      "cancellation_reason": null,      "chain_id": 1,      "created": 1790467200,      "crediting_paused": false,      "crediting_paused_by": [],      "effective_at": 1790467200,      "id": "trs_4d8a2c6e0b1f47a3c5e7d9b1a3c5e7f9",      "kind": "contract",      "livemode": false,      "object": "treasury",      "replaced_at": null,      "status": "active"    }  ],  "has_more": false,  "object": "list",  "url": "/v1/treasuries"}

UpdateMetadataRequest

POST /v1/quotes/{id}, POST /v1/deposits/{id}, POST /v1/refunds/{id}, and POST /v1/deposit_addresses/{id} body: the object's updatable parameters, of which metadata is the one.

metadataMetadataParam

Stripe's metadata: up to 50 string key/value pairs for your own use, keys of up to 40 characters without square brackets, values of up to 500 characters. Merged into the object's: a key set to a value is set, a key set to "" is unset, other keys are kept, and metadata: "" unsets every key. Phala Pay never reads it. Do not store sensitive information in it, such as personal or payment details.

Example
{  "metadata": {    "note": "",    "order_id": "ord_1001"  }}

UpdatePaymentSettingsRequest

POST /v1/payment_settings body. A parameter not sent is unchanged; chains, when sent, replaces the whole list. Writes are last-write-wins.

chainsarray of PaymentSettingsChain

The chains to accept, replacing the list: each chain and asset of the key's mode once. An element's term not sent resets to the operator's default. [] accepts nothing.

quote_creations_per_customer_per_minuteinteger (int64) or null

One customer's quote creations in a rolling minute, from 1 to the operator's maximum; null restores the default.

Example
{  "chains": [    {      "assets": [        {          "asset": "usdc",          "quote_spread_bps": 0        },        {          "asset": "usdt"        }      ],      "chain_id": 1,      "confirmations": "12"    }  ]}

UpdateWebhookEndpointRequest

POST /v1/webhook_endpoints/{id} body; parameters not sent are left unchanged.

descriptionstring or null

A new description; "" unsets it.

disabledboolean or null

true disables the endpoint, false enables it. A disabled endpoint receives nothing and its pending deliveries stop; resend missed events with POST /v1/events/{id}/resend.

enabled_eventsarray of string

New event types, or ["*"].

metadataMetadataParam

Merged into the endpoint's metadata: a key set to "" is unset, and metadata: "" unsets every key.

urlstring or null

A new URL, as on creation.

Example
{  "disabled": false,  "enabled_events": [    "*"  ]}

WebhookEndpointList

A page of webhook endpoints, newest first (https://docs.stripe.com/api/pagination).

dataarray of WebhookEndpointObjectrequired

The endpoints.

has_morebooleanrequired

Whether more endpoints follow in the direction of this page.

object"list"required

Always list.

urlstringrequired

The list's path, /v1/webhook_endpoints.

Example
{  "data": [    {      "created": 1790467200,      "description": "Order fulfillment",      "disabled_reason": null,      "enabled_events": [        "deposit.credited",        "deposit.reversed",        "refund.failed"      ],      "id": "we_9e1c3a5b7d2f40c6e8a0b2d4f6a8c0e1",      "last_attempt": {        "at": 1790553695,        "status_code": 503      },      "livemode": false,      "metadata": {        "team": "payments"      },      "object": "webhook_endpoint",      "oldest_pending_at": 1790553630,      "pending_deliveries": 2,      "status": "enabled",      "url": "https://example.com/phala-pay/webhooks"    }  ],  "has_more": false,  "object": "list",  "url": "/v1/webhook_endpoints"}

WebhookEndpointObject

A webhook endpoint (design D11): where the account's events of one mode are delivered, signed with the account's webhook key of that mode.

createdinteger (int64)required

Creation time, Unix seconds.

deletedboolean or null

true in the webhook_endpoint.deleted event; absent otherwise.

descriptionstring or null

Your description.

disabled_reasonstring or null

gone when Phala Pay disabled the endpoint because it answered 410 Gone; null otherwise. Failing deliveries never disable an endpoint: they are retried until delivered.

enabled_eventsarray of stringrequired

The event types delivered, or ["*"] for all. Account events (account.*, api_key.*, treasury.*, webhook_endpoint.*) are delivered to every enabled endpoint whatever this lists.

idstringrequired

Endpoint id, we_….

last_attemptDeliveryAttempt or any or null
livemodebooleanrequired

The endpoint's mode.

metadatamap of stringrequired

Your key/value pairs (metadata); {} when none.

object"webhook_endpoint"required

Always webhook_endpoint.

oldest_pending_atinteger (int64) or null

Creation time of the oldest event not delivered to the endpoint yet, Unix seconds; null when none is pending.

pending_deliveriesinteger (int64)required

Deliveries to the endpoint not delivered yet. They are retried with backoff (capped at an hour) until delivered and are never given up on; a count that keeps growing means the endpoint is failing: fix it, then list what it missed with GET /v1/events?delivery_success=false.

statusstringrequired

enabled or disabled.

urlstringrequired

Where events are delivered.

Example
{  "created": 1790467200,  "description": "Order fulfillment",  "disabled_reason": null,  "enabled_events": [    "deposit.credited",    "deposit.reversed",    "refund.failed"  ],  "id": "we_9e1c3a5b7d2f40c6e8a0b2d4f6a8c0e1",  "last_attempt": {    "at": 1790553695,    "status_code": 503  },  "livemode": false,  "metadata": {    "team": "payments"  },  "object": "webhook_endpoint",  "oldest_pending_at": 1790553630,  "pending_deliveries": 2,  "status": "enabled",  "url": "https://example.com/phala-pay/webhooks"}

WebhookKeyObject

One version of an account's webhook signing key, with its public key.

expires_atinteger (int64) or null

When a rolled key stops signing, Unix seconds; null for the current key.

public_keystringrequired

The ed25519 public key in Standard Webhooks' form: whpk_ and the standard base64 of its 32 raw bytes, which report_data binds. Pin it after verifying the attestation: every delivery carries a v1a signature by it.

versioninteger (int32)required

Key version, from 1; it grows by one per roll.

WebhookKeyVersion

One version of an account's webhook signing key; its public key comes from GET /v1/attestation.

expires_atinteger (int64) or null

When a rolled key stops signing, Unix seconds; null for the current key.

versioninteger (int32)required

Key version, from 1.