API Reference

Private Payments

Payments on Stellar whose amount stays hidden on-chain. Create a private payment, list and read them; the merchant receives the amount minus the private-payment commission (see https://cosmospay.lat/pricing).

GET
/v1/zk-payments/config

What a dashboard needs to set a merchant up on the confidential token (register, read the balance, withdraw). enabled is false on a network where private payments do not run yet (mainnet today). The same shape as the keyless GET /v1/zk-checkout/config?network=.

Requires the payments:read scope.

apiKey
headerAuthorizationBearer <API key>

Your Cosmos Pay secret API key, sent as Authorization: Bearer <apiKey>.

OK

no_authenticated_consumer: The gateway forwarded no API key identity

insufficient_scope: the API key does not hold the scope this route requires. The shared public API key also gets this on every route that is not marked x-cosmos-public-key, with a message saying so; more scopes will not help, the key is the wrong one.

gateway_required: the request did not arrive through APISIX.

Unexpected server error. The detail is logged server-side and never returned: there is nothing in the body to branch on beyond the code.

Example Request
curl -X GET 'https://api.cosmospay.lat/cosmos-api/v1/zk-payments/config'
Example Response
{  "enabled": true,  "network": "testnet",  "rpcUrl": "https://soroban-testnet.stellar.org",  "networkPassphrase": "Test SDF Network ; September 2015",  "token": {    "contractId": "CBQU5SGVPPYI5MVBVV5GYTYNHENHBY7J44WYYVDPTZ5UNK6JDEY232QX",    "symbol": "XLM",    "decimals": 7,    "underlying": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",    "deployedAtLedger": 5387137  },  "verifier": "CAN45PFA5CVUCU3JB77IE2JNWNTRCDWMRNG55U452L3N2IOCAGOLTUVQ",  "auditorRegistry": "CDKWSGQER4KNDTMZS2W7V4E32KSL7BVM3LBY7EBTPWZZ3SFG5CDAOLF2",  "auditorId": 0,  "feeBps": 18,  "feeAccount": "GDUYXOQZFVPDVIVBTJNUCGYQEC3XSI2LQOQ3SJWJJ6ZY4JLCJZZFGTNQ"}
GET
/v1/zk-payments

Newest first, optionally filtered by status as it reads now (a PENDING payment past expiresAt reads, and filters, as EXPIRED). Paginated with take (default 20, max 100) and skip; the answer is { data, total, take, skip }. Only payments on the key's network are listed (a prod key sees mainnet, a dev key testnet).

Requires the payments:read scope.

apiKey
headerAuthorizationBearer <API key>

Your Cosmos Pay secret API key, sent as Authorization: Bearer <apiKey>.

take?number

Page size: how many items to return (1 to 100).

Range1 <= value <= 100
Default20
skip?number

How many items to skip before this page (offset).

Range0 <= value
Default0
status?string

Only payments in this status, as it reads now: EXPIRED includes a PENDING payment past expiresAt, and PENDING excludes one.

Value in"PENDING""SUCCEEDED""EXPIRED"

OK

The body, query or path failed validation. message is an array of the individual failures.

Routes that reject a valid request for a reason of their own (an amount, a memo, a state) document the code for it on their own 400.

no_authenticated_consumer: The gateway forwarded no API key identity

insufficient_scope: the API key does not hold the scope this route requires. The shared public API key also gets this on every route that is not marked x-cosmos-public-key, with a message saying so; more scopes will not help, the key is the wrong one.

gateway_required: the request did not arrive through APISIX.

Unexpected server error. The detail is logged server-side and never returned: there is nothing in the body to branch on beyond the code.

Example Request
curl -X GET 'https://api.cosmospay.lat/cosmos-api/v1/zk-payments'
Example Response
{  "data": [    {      "id": "cmh4x2k9a0001l70g8v5q3z2w",      "status": "PENDING",      "network": "testnet",      "tokenContract": "CBQU5SGVPPYI5MVBVV5GYTYNHENHBY7J44WYYVDPTZ5UNK6JDEY232QX",      "amount": "25.5",      "netAmount": "25.49745",      "feeAmount": "0.00255",      "feeBps": 1,      "recipient": "GCALNQQBXAPZ2WIRSDDBMSTAKCUH5SG6U76YBFLQLIXJTF7FE5AX7AOO",      "feeAccount": "GDUYXOQZFVPDVIVBTJNUCGYQEC3XSI2LQOQ3SJWJJ6ZY4JLCJZZFGTNQ",      "payer": null,      "paymentTxHash": null,      "feeTxHash": null,      "merchantFee": {        "bps": 150,        "fixed": "0.25",        "amount": "1.75",        "asset": "XLM",        "wallet": "GBDHAQXQQ75WVBUZ2IX3O7ME7JOKJUOUPUXRNDCORUJODWQCTVUEQ62R",        "paidBy": "recipient"      },      "merchantFeeTxHash": null,      "description": "Order #24",      "idempotencyKey": "order-24",      "expiresAt": "2026-10-25T15:00:00.000Z",      "settledAt": null,      "createdAt": "2026-10-25T14:00:00.000Z",      "updatedAt": "2026-10-25T14:00:00.000Z"    }  ],  "total": 1,  "take": 20,  "skip": 0}
POST
/v1/zk-payments

A private payment hides its amount on-chain: it is paid with confidential transfers on Cosmos Pay's confidential token, proven with zero-knowledge proofs (hence zk in the paths). Prices the payment (amount = netAmount + feeAmount, the fee rounded up and at least one stroop) and checks on-chain that the recipient holds a confidential account on the token under auditor 0. The payer then makes two confidential transfers (net to the merchant, fee to the fee account) and confirms them at POST /v1/zk-checkout/{id}/confirm. With a merchantFee, a third transfer pays it to its wallet, which must hold a confidential account on the token too.

Requires the payments:write scope.

apiKey
headerAuthorizationBearer <API key>

Your Cosmos Pay secret API key, sent as Authorization: Bearer <apiKey>.

Idempotency-Key?string

Optional idempotency key. A retry with the same key and the same request returns the existing payment; the same key with a different request is 409 idempotency_conflict. Takes precedence over body.idempotencyKey.

application/json
  1. body

Request to create a private payment: an amount in XLM that the payer pays to recipient with confidential transfers, which hide it on-chain.

amount*string

What the payer pays in total, in XLM (up to 7 decimal places). The merchant receives it minus the 0.18% commission (netAmount); the commission (feeAmount, rounded up, at least one stroop) goes to Cosmos Pay's fee account. An amount whose net would be zero is refused.

recipient*string

The merchant's Stellar account (G...). It must already hold a confidential account on Cosmos Pay's token, registered under auditor id 0; otherwise the payment is refused with recipient_not_registered.

description?string

Shown to the payer by the checkout. Not secret, and not on-chain: the public read returns it to anyone holding the payment id.

Lengthlength <= 280
expiresInMinutes?number

How long the payment stays payable, in minutes. Both transfers must close before it ends.

Range1 <= value <= 10080
Default60
idempotencyKey?string

Idempotency key. A retry with the same key and the same request returns the existing payment; the same key with a different request is 409 idempotency_conflict. The Idempotency-Key header takes precedence over this field. One is generated when neither is sent.

Lengthlength <= 255
merchantFee?

Your own fee on this payment, in XLM, paid privately like the rest: a third confidential transfer from the payer to wallet, which must already hold a confidential account on Cosmos Pay's token (under auditor id 0) and be neither the recipient nor the fee account. paidBy: recipient takes it from amount (the merchant receives less); payer adds it on top (the payer pays amount plus the fee). The 0.18% commission is a share of amount either way. Confirm then takes merchantFeeTxHash too.

Created

invalid_amount: after the commission (and the merchant fee) the merchant would receive nothing, or the merchant fee rounds to nothing. recipient_not_registered: the recipient, or the merchant fee's wallet, has no confidential account on the token under auditor 0. network_unsupported: private payments do not run on this network yet (mainnet today; use a dev key).

no_authenticated_consumer: The gateway forwarded no API key identity

insufficient_scope: the API key does not hold the scope this route requires. The shared public API key also gets this on every route that is not marked x-cosmos-public-key, with a message saying so; more scopes will not help, the key is the wrong one.

gateway_required: the request did not arrive through APISIX.

idempotency_conflict: this key was already used for a different payment. operation_in_flight: a concurrent create with the same key changed it while this one ran; retry.

The budget in x-cosmos-rate-limit is spent for this caller. Honour Retry-After.

The ratelimit-* triple rides along on successful responses too, so a client can pace itself instead of being refused. If the counter store itself is unreachable the guard fails closed and answers 503 provider_unavailable.

Unexpected server error. The detail is logged server-side and never returned: there is nothing in the body to branch on beyond the code.

provider_unavailable: the provider in x-cosmos-upstream is down or unreachable; the message names it. Retry.

misconfigured: this deployment is missing configuration the route needs (a provider instance, a fee wallet, the plan header the gateway must forward). Retrying will not help; it is an operator problem.

Example Request
curl -X POST 'https://api.cosmospay.lat/cosmos-api/v1/zk-payments' \  -H 'Content-Type: application/json' \  -d '{  "amount": "25.5",  "recipient": "GCALNQQBXAPZ2WIRSDDBMSTAKCUH5SG6U76YBFLQLIXJTF7FE5AX7AOO"}'
Example Response
{  "id": "cmh4x2k9a0001l70g8v5q3z2w",  "status": "PENDING",  "network": "testnet",  "tokenContract": "CBQU5SGVPPYI5MVBVV5GYTYNHENHBY7J44WYYVDPTZ5UNK6JDEY232QX",  "amount": "25.5",  "netAmount": "25.49745",  "feeAmount": "0.00255",  "feeBps": 1,  "recipient": "GCALNQQBXAPZ2WIRSDDBMSTAKCUH5SG6U76YBFLQLIXJTF7FE5AX7AOO",  "feeAccount": "GDUYXOQZFVPDVIVBTJNUCGYQEC3XSI2LQOQ3SJWJJ6ZY4JLCJZZFGTNQ",  "payer": null,  "paymentTxHash": null,  "feeTxHash": null,  "merchantFee": {    "bps": 150,    "fixed": "0.25",    "amount": "1.75",    "asset": "XLM",    "wallet": "GBDHAQXQQ75WVBUZ2IX3O7ME7JOKJUOUPUXRNDCORUJODWQCTVUEQ62R",    "paidBy": "recipient"  },  "merchantFeeTxHash": null,  "description": "Order #24",  "idempotencyKey": "order-24",  "expiresAt": "2026-10-25T15:00:00.000Z",  "settledAt": null,  "createdAt": "2026-10-25T14:00:00.000Z",  "updatedAt": "2026-10-25T14:00:00.000Z"}
GET
/v1/zk-payments/{id}

One of your private payments: its amounts (amount, netAmount, feeAmount), recipient, payer and the hashes of the transfers that settled it. status reads as it is now: a PENDING payment past expiresAt reads EXPIRED, and can still settle with transfers that closed in time. The payer's view of it is the keyless GET /v1/zk-checkout/{id}.

Requires the payments:read scope.

apiKey
headerAuthorizationBearer <API key>

Your Cosmos Pay secret API key, sent as Authorization: Bearer <apiKey>.

id*string

OK

The body, query or path failed validation. message is an array of the individual failures.

Routes that reject a valid request for a reason of their own (an amount, a memo, a state) document the code for it on their own 400.

no_authenticated_consumer: The gateway forwarded no API key identity

insufficient_scope: the API key does not hold the scope this route requires. The shared public API key also gets this on every route that is not marked x-cosmos-public-key, with a message saying so; more scopes will not help, the key is the wrong one.

gateway_required: the request did not arrive through APISIX.

No such resource, or it exists and belongs to another consumer. The two are deliberately the same answer: "exists but not yours" is an ownership oracle.

Unexpected server error. The detail is logged server-side and never returned: there is nothing in the body to branch on beyond the code.

Example Request
curl -X GET 'https://api.cosmospay.lat/cosmos-api/v1/zk-payments/string'
Example Response
{  "id": "cmh4x2k9a0001l70g8v5q3z2w",  "status": "PENDING",  "network": "testnet",  "tokenContract": "CBQU5SGVPPYI5MVBVV5GYTYNHENHBY7J44WYYVDPTZ5UNK6JDEY232QX",  "amount": "25.5",  "netAmount": "25.49745",  "feeAmount": "0.00255",  "feeBps": 1,  "recipient": "GCALNQQBXAPZ2WIRSDDBMSTAKCUH5SG6U76YBFLQLIXJTF7FE5AX7AOO",  "feeAccount": "GDUYXOQZFVPDVIVBTJNUCGYQEC3XSI2LQOQ3SJWJJ6ZY4JLCJZZFGTNQ",  "payer": null,  "paymentTxHash": null,  "feeTxHash": null,  "merchantFee": {    "bps": 150,    "fixed": "0.25",    "amount": "1.75",    "asset": "XLM",    "wallet": "GBDHAQXQQ75WVBUZ2IX3O7ME7JOKJUOUPUXRNDCORUJODWQCTVUEQ62R",    "paidBy": "recipient"  },  "merchantFeeTxHash": null,  "description": "Order #24",  "idempotencyKey": "order-24",  "expiresAt": "2026-10-25T15:00:00.000Z",  "settledAt": null,  "createdAt": "2026-10-25T14:00:00.000Z",  "updatedAt": "2026-10-25T14:00:00.000Z"}