Phala Pay API (0.10.0-rc.6)

Download OpenAPI specification:

License: Apache-2.0

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.

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.

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

Authorizations:
api_key
query Parameters
client_reference_id
string

Only this customer's quotes

status
string

open, complete, expired, or canceled

limit
integer <int64>

1 to 100, default 10

starting_after
string

qt_ id: the page after it

ending_before
string

qt_ id: the page before it

Responses

Response samples

Content type
application/json
{
  • "data": [
    ],
  • "has_more": false,
  • "object": "list",
  • "url": "/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`.

Authorizations:
api_key
header Parameters
Idempotency-Key
string 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 schema: application/json
required
amount
required
integer <int64> >= 0

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

asset
required
string

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

chain_id
required
integer <int64> >= 0

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

client_reference_id
required
string

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

currency
required
string

Lowercase ISO currency code; only usd.

object or string (MetadataParam)

Responses

Request samples

Content type
application/json
{
  • "amount": 2500,
  • "asset": "usdc",
  • "chain_id": 1,
  • "client_reference_id": "team-42",
  • "currency": "usd",
  • "metadata": {
    }
}

Response samples

Content type
application/json
{
  • "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": {
    },
  • "object": "quote",
  • "payment": {
    },
  • "payment_uri": "ethereum:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48@1/transfer?address=0x2f3e91325b2288bce392711f85f5359661062a91&uint256=25000000",
  • "status": "open",
  • "terms": {
    },
  • "treasury": "0x936c1991f8da9a919fa11b557a3514719f5a4504"
}

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.

Authorizations:
api_keyNone
path Parameters
id
required
string

Quote id, qt_…

query Parameters
expand[]
Array of strings

deposit; API key requests only

client_secret
string

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

Response samples

Content type
application/json
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": {
    },
  • "object": "quote",
  • "payment": {
    },
  • "payment_uri": "ethereum:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48@1/transfer?address=0x2f3e91325b2288bce392711f85f5359661062a91&uint256=25000000",
  • "status": "open",
  • "terms": {
    },
  • "treasury": "0x936c1991f8da9a919fa11b557a3514719f5a4504"
}

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

Authorizations:
api_key
path Parameters
id
required
string

Quote id, qt_…

header Parameters
Idempotency-Key
string 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 schema: application/json
required
object or string (MetadataParam)

Responses

Request samples

Content type
application/json
{
  • "metadata": {
    }
}

Response samples

Content type
application/json
{
  • "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": {
    },
  • "object": "quote",
  • "payment": {
    },
  • "payment_uri": "ethereum:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48@1/transfer?address=0x2f3e91325b2288bce392711f85f5359661062a91&uint256=25000000",
  • "status": "open",
  • "terms": {
    },
  • "treasury": "0x936c1991f8da9a919fa11b557a3514719f5a4504"
}

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

Authorizations:
api_key
path Parameters
id
required
string

Quote id, qt_…

header Parameters
Idempotency-Key
string 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

Response samples

Content type
application/json
{
  • "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": {
    },
  • "object": "quote",
  • "payment": {
    },
  • "payment_uri": "ethereum:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48@1/transfer?address=0x2f3e91325b2288bce392711f85f5359661062a91&uint256=25000000",
  • "status": "open",
  • "terms": {
    },
  • "treasury": "0x936c1991f8da9a919fa11b557a3514719f5a4504"
}

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

Authorizations:
api_keyNone
path Parameters
id
required
string

Quote identifier

query Parameters
client_secret
string

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

Request Body schema: application/json
required
transaction_hash
required
string^0x[0-9a-fA-F]{64}$

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

Responses

Request samples

Content type
application/json
{
  • "transaction_hash": "0x7d3c1e5a9b2f4d6c8e0a1b3d5f7c9e2a4b6d8f0c1e3a5b7d9f1c3e5a7b9d1f3e"
}

Response samples

Content type
application/json
{
  • "object": "transaction_submission",
  • "status": "received",
  • "transaction_hash": "0x7d3c1e5a9b2f4d6c8e0a1b3d5f7c9e2a4b6d8f0c1e3a5b7d9f1c3e5a7b9d1f3e"
}

deposit_addresses

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

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

Authorizations:
api_key
query Parameters
client_reference_id
string

Only this customer's addresses

status
string

active or retired

limit
integer <int64>

1 to 100, default 10

starting_after
string

da_ id: the page after it

ending_before
string

da_ id: the page before it

Responses

Response samples

Content type
application/json
{
  • "data": [
    ],
  • "has_more": false,
  • "object": "list",
  • "url": "/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.

Authorizations:
api_key
header Parameters
Idempotency-Key
string 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 schema: application/json
required
client_reference_id
required
string

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

object or string (MetadataParam)

Responses

Request samples

Content type
application/json
{
  • "client_reference_id": "team-42",
  • "metadata": {
    }
}

Response samples

Content type
application/json
{
  • "address": "0x0f45147a02e4c9d91aff20024e22095536fd5053",
  • "client_reference_id": "team-42",
  • "client_secret": "da_7b2e9c4a1f6d48b3a5c0e2d4f6a8b1c3_secret_0a1b2c3d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f9",
  • "created": 1790553600,
  • "id": "da_7b2e9c4a1f6d48b3a5c0e2d4f6a8b1c3",
  • "livemode": false,
  • "metadata": {
    },
  • "networks": [
    ],
  • "object": "deposit_address",
  • "payments": [ ],
  • "retired_at": null,
  • "salt": "0x4e9767dd0c2ab5b953a305c3f10dc1e0d1f7c9d3cbab8463509d2edb06ca4b52",
  • "status": "active",
  • "version": 1
}

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.

Authorizations:
api_keyNone
path Parameters
id
required
string

Deposit address id, da_…

query Parameters
client_secret
string

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

Response samples

Content type
application/json
Example
{
  • "address": "0x0f45147a02e4c9d91aff20024e22095536fd5053",
  • "client_reference_id": "team-42",
  • "client_secret": "da_7b2e9c4a1f6d48b3a5c0e2d4f6a8b1c3_secret_0a1b2c3d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f9",
  • "created": 1790553600,
  • "id": "da_7b2e9c4a1f6d48b3a5c0e2d4f6a8b1c3",
  • "livemode": false,
  • "metadata": {
    },
  • "networks": [
    ],
  • "object": "deposit_address",
  • "payments": [ ],
  • "retired_at": null,
  • "salt": "0x4e9767dd0c2ab5b953a305c3f10dc1e0d1f7c9d3cbab8463509d2edb06ca4b52",
  • "status": "active",
  • "version": 1
}

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

Authorizations:
api_key
path Parameters
id
required
string

Deposit address id, da_…

header Parameters
Idempotency-Key
string 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 schema: application/json
required
object or string (MetadataParam)

Responses

Request samples

Content type
application/json
{
  • "metadata": {
    }
}

Response samples

Content type
application/json
{
  • "address": "0x0f45147a02e4c9d91aff20024e22095536fd5053",
  • "client_reference_id": "team-42",
  • "client_secret": "da_7b2e9c4a1f6d48b3a5c0e2d4f6a8b1c3_secret_0a1b2c3d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f9",
  • "created": 1790553600,
  • "id": "da_7b2e9c4a1f6d48b3a5c0e2d4f6a8b1c3",
  • "livemode": false,
  • "metadata": {
    },
  • "networks": [
    ],
  • "object": "deposit_address",
  • "payments": [ ],
  • "retired_at": null,
  • "salt": "0x4e9767dd0c2ab5b953a305c3f10dc1e0d1f7c9d3cbab8463509d2edb06ca4b52",
  • "status": "active",
  • "version": 1
}

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.

Authorizations:
api_key
path Parameters
id
required
string

Deposit address id, da_…

header Parameters
Idempotency-Key
string 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

Response samples

Content type
application/json
{
  • "address": "0x0f45147a02e4c9d91aff20024e22095536fd5053",
  • "client_reference_id": "team-42",
  • "client_secret": "da_7b2e9c4a1f6d48b3a5c0e2d4f6a8b1c3_secret_0a1b2c3d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f9",
  • "created": 1790553600,
  • "id": "da_7b2e9c4a1f6d48b3a5c0e2d4f6a8b1c3",
  • "livemode": false,
  • "metadata": {
    },
  • "networks": [
    ],
  • "object": "deposit_address",
  • "payments": [ ],
  • "retired_at": null,
  • "salt": "0x4e9767dd0c2ab5b953a305c3f10dc1e0d1f7c9d3cbab8463509d2edb06ca4b52",
  • "status": "active",
  • "version": 1
}

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

Authorizations:
api_keyNone
path Parameters
id
required
string

Deposit-address identifier

query Parameters
client_secret
string

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

Request Body schema: application/json
required
chain_id
required
integer <int64> >= 0

One of this object's issued network identifiers.

transaction_hash
required
string^0x[0-9a-fA-F]{64}$

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

Responses

Request samples

Content type
application/json
{
  • "chain_id": 84532,
  • "transaction_hash": "0x7d3c1e5a9b2f4d6c8e0a1b3d5f7c9e2a4b6d8f0c1e3a5b7d9f1c3e5a7b9d1f3e"
}

Response samples

Content type
application/json
{
  • "object": "transaction_submission",
  • "status": "received",
  • "transaction_hash": "0x7d3c1e5a9b2f4d6c8e0a1b3d5f7c9e2a4b6d8f0c1e3a5b7d9f1c3e5a7b9d1f3e"
}

deposits

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

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

Authorizations:
api_key
query Parameters
client_reference_id
string

Only this customer's deposits

quote
string

Only deposits to this quote's address

deposit_address
string

Only deposits to this deposit address, da_…

status
string

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

tx_hash
string

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

limit
integer <int64>

1 to 100, default 10

starting_after
string

dep_ id: the page after it

ending_before
string

dep_ id: the page before it

expand[]
Array of strings

data.quote

Responses

Response samples

Content type
application/json
{
  • "data": [
    ],
  • "has_more": false,
  • "object": "list",
  • "url": "/v1/deposits"
}

One deposit.

Authorizations:
api_key
path Parameters
id
required
string

Deposit id, dep_…

query Parameters
expand[]
Array of strings

quote

Responses

Response samples

Content type
application/json
{
  • "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": {
    },
  • "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
}

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

Authorizations:
api_key
path Parameters
id
required
string

Deposit id, dep_…

header Parameters
Idempotency-Key
string 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 schema: application/json
required
object or string (MetadataParam)

Responses

Request samples

Content type
application/json
{
  • "metadata": {
    }
}

Response samples

Content type
application/json
{
  • "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": {
    },
  • "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
}

refunds

Refunds you pay from your treasury and attach with mark_paid.

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

Authorizations:
api_key
query Parameters
deposit
string

Only this deposit's refunds, dep_…

status
string

pending, succeeded, failed, or canceled

limit
integer <int64>

1 to 100, default 10

starting_after
string

re_ id: the page after it

ending_before
string

re_ id: the page before it

Responses

Response samples

Content type
application/json
{
  • "data": [
    ],
  • "has_more": false,
  • "object": "list",
  • "url": "/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`.

Authorizations:
api_key
header Parameters
Idempotency-Key
string 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 schema: application/json
required
amount_atomic
string or null

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

deposit
required
string

dep_ id of the deposit to refund.

destination_address
required
string

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

object or string (MetadataParam)

Responses

Request samples

Content type
application/json
{
  • "amount_atomic": "25000000",
  • "deposit": "dep_8a1f4e2b6c3d49e0a7b5c1d2e3f40516",
  • "destination_address": "0x1775c1326aa633546b0b5634ae2bef0ba7cbfc9a",
  • "metadata": {
    }
}

Response samples

Content type
application/json
{
  • "amount_atomic": "25000000",
  • "created": 1790557200,
  • "deposit": "dep_8a1f4e2b6c3d49e0a7b5c1d2e3f40516",
  • "destination_address": "0x1775c1326aa633546b0b5634ae2bef0ba7cbfc9a",
  • "failure_reason": null,
  • "id": "re_3c9e7a1b5d2f4a6c8e0b1d3f5a7c9e02",
  • "livemode": false,
  • "metadata": {
    },
  • "object": "refund",
  • "receipt_log_index": 0,
  • "status": "pending",
  • "transaction_hash": "0x4b6d8f0a2c4e6a8c0e2b4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c",
  • "treasury": "0x936c1991f8da9a919fa11b557a3514719f5a4504"
}

One refund.

Authorizations:
api_key
path Parameters
id
required
string

Refund id, re_…

query Parameters
expand[]
Array of strings

deposit

Responses

Response samples

Content type
application/json
{
  • "amount_atomic": "25000000",
  • "created": 1790557200,
  • "deposit": "dep_8a1f4e2b6c3d49e0a7b5c1d2e3f40516",
  • "destination_address": "0x1775c1326aa633546b0b5634ae2bef0ba7cbfc9a",
  • "failure_reason": null,
  • "id": "re_3c9e7a1b5d2f4a6c8e0b1d3f5a7c9e02",
  • "livemode": false,
  • "metadata": {
    },
  • "object": "refund",
  • "receipt_log_index": 0,
  • "status": "pending",
  • "transaction_hash": "0x4b6d8f0a2c4e6a8c0e2b4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c",
  • "treasury": "0x936c1991f8da9a919fa11b557a3514719f5a4504"
}

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

Authorizations:
api_key
path Parameters
id
required
string

Refund id, re_…

header Parameters
Idempotency-Key
string 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 schema: application/json
required
object or string (MetadataParam)

Responses

Request samples

Content type
application/json
{
  • "metadata": {
    }
}

Response samples

Content type
application/json
{
  • "amount_atomic": "25000000",
  • "created": 1790557200,
  • "deposit": "dep_8a1f4e2b6c3d49e0a7b5c1d2e3f40516",
  • "destination_address": "0x1775c1326aa633546b0b5634ae2bef0ba7cbfc9a",
  • "failure_reason": null,
  • "id": "re_3c9e7a1b5d2f4a6c8e0b1d3f5a7c9e02",
  • "livemode": false,
  • "metadata": {
    },
  • "object": "refund",
  • "receipt_log_index": 0,
  • "status": "pending",
  • "transaction_hash": "0x4b6d8f0a2c4e6a8c0e2b4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c",
  • "treasury": "0x936c1991f8da9a919fa11b557a3514719f5a4504"
}

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.

Authorizations:
api_key
path Parameters
id
required
string

Refund id, re_…

header Parameters
Idempotency-Key
string 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

Response samples

Content type
application/json
{
  • "amount_atomic": "25000000",
  • "created": 1790557200,
  • "deposit": "dep_8a1f4e2b6c3d49e0a7b5c1d2e3f40516",
  • "destination_address": "0x1775c1326aa633546b0b5634ae2bef0ba7cbfc9a",
  • "failure_reason": null,
  • "id": "re_3c9e7a1b5d2f4a6c8e0b1d3f5a7c9e02",
  • "livemode": false,
  • "metadata": {
    },
  • "object": "refund",
  • "receipt_log_index": 0,
  • "status": "pending",
  • "transaction_hash": "0x4b6d8f0a2c4e6a8c0e2b4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c",
  • "treasury": "0x936c1991f8da9a919fa11b557a3514719f5a4504"
}

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.

Authorizations:
api_key
path Parameters
id
required
string

Refund id, re_…

header Parameters
Idempotency-Key
string 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 schema: application/json
required
receipt_log_index
integer or null <int64> >= 0

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_hash
required
string

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

Responses

Request samples

Content type
application/json
{
  • "receipt_log_index": 0,
  • "transaction_hash": "0x4b6d8f0a2c4e6a8c0e2b4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c"
}

Response samples

Content type
application/json
{
  • "amount_atomic": "25000000",
  • "created": 1790557200,
  • "deposit": "dep_8a1f4e2b6c3d49e0a7b5c1d2e3f40516",
  • "destination_address": "0x1775c1326aa633546b0b5634ae2bef0ba7cbfc9a",
  • "failure_reason": null,
  • "id": "re_3c9e7a1b5d2f4a6c8e0b1d3f5a7c9e02",
  • "livemode": false,
  • "metadata": {
    },
  • "object": "refund",
  • "receipt_log_index": 0,
  • "status": "pending",
  • "transaction_hash": "0x4b6d8f0a2c4e6a8c0e2b4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c",
  • "treasury": "0x936c1991f8da9a919fa11b557a3514719f5a4504"
}

balance

Unswept amounts per chain and token.

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.

Authorizations:
api_key

Responses

Response samples

Content type
application/json
{
  • "livemode": false,
  • "object": "balance",
  • "unswept": [
    ]
}

sweeps

Finalized sweeps of forwarders to your treasuries.

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.

Authorizations:
api_key
query Parameters
chain_id
integer <int64> >= 0

Only this chain's sweeps

forwarder
string

Only this forwarder's sweeps, fwd_…

token
string

Only sweeps of this token contract

limit
integer <int64>

1 to 100, default 10

starting_after
string

sw_ id: the page after it

ending_before
string

sw_ id: the page before it

Responses

Response samples

Content type
application/json
{
  • "data": [
    ],
  • "has_more": false,
  • "object": "list",
  • "url": "/v1/sweeps"
}

forwarders

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

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.

Authorizations:
api_key
query Parameters
chain_id
integer <int64> >= 0

Only this chain's forwarders

quote
string

Only this quote's forwarder, qt_…

deposit_address
string

Only this deposit address's networks, da_…

sweepable
string

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

limit
integer <int64>

1 to 100, default 10

starting_after
string

fwd_ id: the page after it

ending_before
string

fwd_ id: the page before it

Responses

Response samples

Content type
application/json
{
  • "data": [
    ],
  • "has_more": false,
  • "object": "list",
  • "url": "/v1/forwarders"
}

treasuries

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

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.

Authorizations:
api_key
query Parameters
chain_id
integer <int64> >= 0

Only this chain's treasuries

status
string

pending, active, replaced, or canceled

limit
integer <int64>

1 to 100, default 10

starting_after
string

trs_ id: the page after it

ending_before
string

trs_ id: the page before it

Responses

Response samples

Content type
application/json
{
  • "data": [
    ],
  • "has_more": false,
  • "object": "list",
  • "url": "/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.

Authorizations:
api_key
header Parameters
Idempotency-Key
string 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 schema: application/json
required
chain_id
required
integer <int64> >= 0

The treasury's chain, the challenge's.

message
required
string

The challenge's message, unchanged.

signature
required
string

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

Request samples

Content type
application/json
{
  • "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 samples

Content type
application/json
{
  • "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"
}

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.

Authorizations:
api_key
header Parameters
Idempotency-Key
string 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 schema: application/json
required
address
required
string

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

chain_id
required
integer <int64> >= 0

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

Responses

Request samples

Content type
application/json
{
  • "address": "0x936c1991f8da9a919fa11b557a3514719f5a4504",
  • "chain_id": 1
}

Response samples

Content type
application/json
{
  • "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"
}

One treasury.

Authorizations:
api_key
path Parameters
id
required
string

Treasury id, trs_…

Responses

Response samples

Content type
application/json
{
  • "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"
}

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.

Authorizations:
api_key
path Parameters
id
required
string

Treasury id, trs_…

header Parameters
Idempotency-Key
string 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

Response samples

Content type
application/json
{
  • "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"
}

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.

Authorizations:
api_key
path Parameters
id
required
string

Treasury id, trs_…

header Parameters
Idempotency-Key
string 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

Response samples

Content type
application/json
{
  • "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"
}

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`.

Authorizations:
api_key
path Parameters
id
required
string

Treasury id, trs_…

header Parameters
Idempotency-Key
string 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

Response samples

Content type
application/json
{
  • "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"
}

events

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

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.

Authorizations:
api_key
query Parameters
type
string

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

types[]
Array of strings

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_success
boolean

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

limit
integer <int64>

1 to 100, default 10

starting_after
string

evt_ id: the page after it

ending_before
string

evt_ id: the page before it

Responses

Response samples

Content type
application/json
{
  • "data": [
    ],
  • "has_more": false,
  • "object": "list",
  • "url": "/v1/events"
}

One event.

Authorizations:
api_key
path Parameters
id
required
string

Event id, evt_…

Responses

Response samples

Content type
application/json
{
  • "account": "acct_0c6e1d0a9b3f4c2e8d7a6b5c4d3e2f10",
  • "actor": "system",
  • "created": 1790553630,
  • "data": {
    },
  • "id": "evt_2b4d6f8a0c1e43b5d7f9a1c3e5b7d9f0",
  • "livemode": false,
  • "object": "event",
  • "pending_webhooks": 0,
  • "request": null,
  • "type": "deposit.credited"
}

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.

Authorizations:
api_key
path Parameters
id
required
string

Event id, evt_…

header Parameters
Idempotency-Key
string 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 schema: application/json
required
webhook_endpoint
required
string

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

Responses

Request samples

Content type
application/json
{
  • "webhook_endpoint": "we_9e1c3a5b7d2f40c6e8a0b2d4f6a8c0e1"
}

Response samples

Content type
application/json
{
  • "account": "acct_0c6e1d0a9b3f4c2e8d7a6b5c4d3e2f10",
  • "actor": "system",
  • "created": 1790553630,
  • "data": {
    },
  • "id": "evt_2b4d6f8a0c1e43b5d7f9a1c3e5b7d9f0",
  • "livemode": false,
  • "object": "event",
  • "pending_webhooks": 0,
  • "request": null,
  • "type": "deposit.credited"
}

webhook_endpoints

Where events are delivered, with delivery health.

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

Authorizations:
api_key
query Parameters
limit
integer <int64>

1 to 100, default 10

starting_after
string

we_ id: the page after it

ending_before
string

we_ id: the page before it

Responses

Response samples

Content type
application/json
{
  • "data": [
    ],
  • "has_more": false,
  • "object": "list",
  • "url": "/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`).

Authorizations:
api_key
header Parameters
Idempotency-Key
string 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 schema: application/json
required
description
string or null

Your description, up to 5000 characters.

enabled_events
required
Array of strings

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

object or string (MetadataParam)
url
required
string

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

Request samples

Content type
application/json
{}

Response samples

Content type
application/json
{
  • "created": 1790467200,
  • "description": "Order fulfillment",
  • "disabled_reason": null,
  • "enabled_events": [
    ],
  • "id": "we_9e1c3a5b7d2f40c6e8a0b2d4f6a8c0e1",
  • "last_attempt": {
    },
  • "livemode": false,
  • "metadata": {
    },
  • "object": "webhook_endpoint",
  • "oldest_pending_at": 1790553630,
  • "pending_deliveries": 2,
  • "status": "enabled",
}

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.

Authorizations:
api_key
path Parameters
id
required
string

Endpoint id, we_…

Responses

Response samples

Content type
application/json
{
  • "deleted": true,
  • "id": "we_9e1c3a5b7d2f40c6e8a0b2d4f6a8c0e1",
  • "object": "webhook_endpoint"
}

One webhook endpoint.

Authorizations:
api_key
path Parameters
id
required
string

Endpoint id, we_…

Responses

Response samples

Content type
application/json
{
  • "created": 1790467200,
  • "description": "Order fulfillment",
  • "disabled_reason": null,
  • "enabled_events": [
    ],
  • "id": "we_9e1c3a5b7d2f40c6e8a0b2d4f6a8c0e1",
  • "last_attempt": {
    },
  • "livemode": false,
  • "metadata": {
    },
  • "object": "webhook_endpoint",
  • "oldest_pending_at": 1790553630,
  • "pending_deliveries": 2,
  • "status": "enabled",
}

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`).

Authorizations:
api_key
path Parameters
id
required
string

Endpoint id, we_…

header Parameters
Idempotency-Key
string 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 schema: application/json
required
description
string or null

A new description; "" unsets it.

disabled
boolean 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_events
Array of strings or null

New event types, or ["*"].

object or string (MetadataParam)
url
string or null

A new URL, as on creation.

Responses

Request samples

Content type
application/json
{
  • "disabled": false,
  • "enabled_events": [
    ]
}

Response samples

Content type
application/json
{
  • "created": 1790467200,
  • "description": "Order fulfillment",
  • "disabled_reason": null,
  • "enabled_events": [
    ],
  • "id": "we_9e1c3a5b7d2f40c6e8a0b2d4f6a8c0e1",
  • "last_attempt": {
    },
  • "livemode": false,
  • "metadata": {
    },
  • "object": "webhook_endpoint",
  • "oldest_pending_at": 1790553630,
  • "pending_deliveries": 2,
  • "status": "enabled",
}

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.

Authorizations:
api_key
path Parameters
id
required
string

Endpoint id, we_…

header Parameters
Idempotency-Key
string 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

Response samples

Content type
application/json
{
  • "account": "acct_0c6e1d0a9b3f4c2e8d7a6b5c4d3e2f10",
  • "actor": "system",
  • "created": 1790553630,
  • "data": {
    },
  • "id": "evt_2b4d6f8a0c1e43b5d7f9a1c3e5b7d9f0",
  • "livemode": false,
  • "object": "event",
  • "pending_webhooks": 0,
  • "request": null,
  • "type": "deposit.credited"
}

api_keys

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

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

Authorizations:
api_key
query Parameters
limit
integer <int64>

1 to 100, default 10

starting_after
string

key_ id: the page after it

ending_before
string

key_ id: the page before it

Responses

Response samples

Content type
application/json
{
  • "data": [
    ],
  • "has_more": false,
  • "object": "list",
  • "url": "/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.

Authorizations:
api_key
header Parameters
Idempotency-Key
string 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 schema: application/json
required
name
string

The key's label, at most 200 characters.

permissions
Array of strings or null

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.

type
string or null

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

Responses

Request samples

Content type
application/json
{
  • "name": "fulfillment worker",
  • "permissions": [
    ],
  • "type": "restricted"
}

Response samples

Content type
application/json
{
  • "created": 1790467200,
  • "expires_at": null,
  • "id": "key_6a8c0e2b4d1f43a5c7e9b1d3f5a7c9e1",
  • "last_used": 1790553600,
  • "livemode": false,
  • "name": "fulfillment worker",
  • "object": "api_key",
  • "permissions": [
    ],
  • "redacted": "ppay_rk_test_…Yz4x",
  • "status": "active",
  • "type": "restricted"
}

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.

Authorizations:
api_key
path Parameters
id
required
string

Key id, key_…

Responses

Response samples

Content type
application/json
{
  • "created": 1790467200,
  • "expires_at": null,
  • "id": "key_6a8c0e2b4d1f43a5c7e9b1d3f5a7c9e1",
  • "last_used": 1790553600,
  • "livemode": false,
  • "name": "fulfillment worker",
  • "object": "api_key",
  • "permissions": [
    ],
  • "redacted": "ppay_rk_test_…Yz4x",
  • "status": "active",
  • "type": "restricted"
}

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

Authorizations:
api_key
path Parameters
id
required
string

Key id, key_…

Responses

Response samples

Content type
application/json
{
  • "created": 1790467200,
  • "expires_at": null,
  • "id": "key_6a8c0e2b4d1f43a5c7e9b1d3f5a7c9e1",
  • "last_used": 1790553600,
  • "livemode": false,
  • "name": "fulfillment worker",
  • "object": "api_key",
  • "permissions": [
    ],
  • "redacted": "ppay_rk_test_…Yz4x",
  • "status": "active",
  • "type": "restricted"
}

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.

Authorizations:
api_key
path Parameters
id
required
string

Key id, key_…

header Parameters
Idempotency-Key
string 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 schema: application/json
required
expires_in
integer <int32> >= 0

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

Request samples

Content type
application/json
{
  • "expires_in": 86400
}

Response samples

Content type
application/json
{
  • "created": 1790467200,
  • "expires_at": null,
  • "id": "key_6a8c0e2b4d1f43a5c7e9b1d3f5a7c9e1",
  • "last_used": 1790553600,
  • "livemode": false,
  • "name": "fulfillment worker",
  • "object": "api_key",
  • "permissions": [
    ],
  • "redacted": "ppay_rk_test_…Yz4x",
  • "status": "active",
  • "type": "restricted"
}

account

Your account: settings, pauses, webhook signing keys.

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

Authorizations:
api_key

Responses

Response samples

Content type
application/json
{
  • "charges_enabled": true,
  • "created": 1787961600,
  • "id": "acct_0c6e1d0a9b3f4c2e8d7a6b5c4d3e2f10",
  • "livemode": false,
  • "name": "Example Cloud",
  • "object": "account",
  • "paused_scopes": [ ],
  • "webhook_keys": [
    ]
}

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`.

Authorizations:
api_key
header Parameters
Idempotency-Key
string 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 schema: application/json
required
scopes
required
Array of strings

["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

Request samples

Content type
application/json
{
  • "scopes": [
    ]
}

Response samples

Content type
application/json
{
  • "charges_enabled": true,
  • "created": 1787961600,
  • "id": "acct_0c6e1d0a9b3f4c2e8d7a6b5c4d3e2f10",
  • "livemode": false,
  • "name": "Example Cloud",
  • "object": "account",
  • "paused_scopes": [ ],
  • "webhook_keys": [
    ]
}

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

Authorizations:
api_key
header Parameters
Idempotency-Key
string 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 schema: application/json
required
scopes
required
Array of strings

["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

Request samples

Content type
application/json
{
  • "scopes": [
    ]
}

Response samples

Content type
application/json
{
  • "charges_enabled": true,
  • "created": 1787961600,
  • "id": "acct_0c6e1d0a9b3f4c2e8d7a6b5c4d3e2f10",
  • "livemode": false,
  • "name": "Example Cloud",
  • "object": "account",
  • "paused_scopes": [ ],
  • "webhook_keys": [
    ]
}

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.

Authorizations:
api_key
header Parameters
Idempotency-Key
string 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 schema: application/json
required
expires_in
integer <int32> >= 0

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

Request samples

Content type
application/json
{
  • "expires_in": 172800
}

Response samples

Content type
application/json
{
  • "charges_enabled": true,
  • "created": 1787961600,
  • "id": "acct_0c6e1d0a9b3f4c2e8d7a6b5c4d3e2f10",
  • "livemode": false,
  • "name": "Example Cloud",
  • "object": "account",
  • "paused_scopes": [ ],
  • "webhook_keys": [
    ]
}

attestation

TDX evidence binding your webhook signing keys.

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.

Authorizations:
api_key
query Parameters
nonce
required
string

Non-empty hexadecimal nonce of at most 32 bytes.

Responses

Response samples

Content type
application/json
{
  • "account": "acct_0c6e1d0a9b3f4c2e8d7a6b5c4d3e2f10",
  • "livemode": false,
  • "object": "attestation",
  • "report_data": "9f2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e2b4d6f8a0c1e3a5b7d9f1c3e5a7b9d1f",
  • "tdx_quote": "040002008100000000000000939a7233f79c4ca9940a0db3957f0607",
  • "webhook_keys": [
    ]
}

config

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

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.

Authorizations:
api_key

Responses

Response samples

Content type
application/json
{
  • "assets": [
    ],
  • "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
}

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.

Authorizations:
api_key

Responses

Response samples

Content type
application/json
{
  • "available": [
    ],
  • "chains": [
    ],
  • "livemode": false,
  • "object": "payment_settings",
  • "quote_creations_per_customer_per_minute": null,
  • "revision": "psrev_5b0e4f1a9c3d4e7f8a2b6c1d0e9f8a7b",
  • "status": "configured",
  • "updated": 1790467200
}

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`.

Authorizations:
api_key
header Parameters
Idempotency-Key
string 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 schema: application/json
required
Array of objects or null (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_minute
integer or null <int64> >= 0

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

Responses

Request samples

Content type
application/json
{
  • "chains": [
    ]
}

Response samples

Content type
application/json
{
  • "available": [
    ],
  • "chains": [
    ],
  • "livemode": false,
  • "object": "payment_settings",
  • "quote_creations_per_customer_per_minute": null,
  • "revision": "psrev_5b0e4f1a9c3d4e7f8a2b6c1d0e9f8a7b",
  • "status": "configured",
  • "updated": 1790467200
}