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).
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.
apiKeyAuthorizationBearer <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.
curl -X GET 'https://api.cosmospay.lat/cosmos-api/v1/zk-payments/config'{ "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"}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.
apiKeyAuthorizationBearer <API key>Your Cosmos Pay secret API key, sent as Authorization: Bearer <apiKey>.
take?numberPage size: how many items to return (1 to 100).
1 <= value <= 10020skip?numberHow many items to skip before this page (offset).
0 <= value0status?stringOnly payments in this status, as it reads now: EXPIRED includes a PENDING payment past expiresAt, and PENDING excludes one.
"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.
curl -X GET 'https://api.cosmospay.lat/cosmos-api/v1/zk-payments'{ "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}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.
apiKeyAuthorizationBearer <API key>Your Cosmos Pay secret API key, sent as Authorization: Bearer <apiKey>.
Idempotency-Key?stringOptional 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- 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*stringWhat 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*stringThe 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?stringShown to the payer by the checkout. Not secret, and not on-chain: the public read returns it to anyone holding the payment id.
length <= 280expiresInMinutes?numberHow long the payment stays payable, in minutes. Both transfers must close before it ends.
1 <= value <= 1008060idempotencyKey?stringIdempotency 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.
length <= 255merchantFee?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.
curl -X POST 'https://api.cosmospay.lat/cosmos-api/v1/zk-payments' \ -H 'Content-Type: application/json' \ -d '{ "amount": "25.5", "recipient": "GCALNQQBXAPZ2WIRSDDBMSTAKCUH5SG6U76YBFLQLIXJTF7FE5AX7AOO"}'{ "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"}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.
apiKeyAuthorizationBearer <API key>Your Cosmos Pay secret API key, sent as Authorization: Bearer <apiKey>.
id*stringOK
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.
curl -X GET 'https://api.cosmospay.lat/cosmos-api/v1/zk-payments/string'{ "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"}USDT0 Transfers
USDT0 out of Stellar through LayerZero: quote, build the Soroban transaction the holder signs, submit it and follow the message to its destination. Native USDT on Ethereum, USDT0 elsewhere; mainnet only.
Private Checkout
What the payer's browser reads and calls without a key: one private payment, the network's confidential-token setup, and the confirmation of the two confidential transfers that pay it.