API Reference

Payment Links

The payer’s view of one payment link, served without a key to the hosted checkout on payments.cosmospay.lat. The link id is the capability: anyone holding it can read the amount, the address to pay and the live status, and nothing about the merchant.

GET
/v1/payment-links/{id}

For a hosted checkout page: amount, asset, network, the address to pay (payTo), the link and its QR, and the live status, so the page can poll until the payment settles. Reachable without an API key or the gateway secret.

The id is the capability. Anyone who holds a payment link can read it here, which is what a payment link is for. Nothing about the owning merchant account, the payer’s own account, the envelope, the merchant’s reference or callback, or the status history is returned. uri is the link verbatim, so whatever the wallet needs from it is in it.

Answered with Cache-Control: no-store. Budgeted per client address (x-cosmos-rate-limit): poll at most every few seconds and honour Retry-After.

id*string

The payment intent id (a cuid), as in the link https://payments.cosmospay.lat/<id>.

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 payment intent has this id: it never existed or it was deleted. The two are the same answer, and the same one GET /v1/payment-intents/{id} gives its owner.

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.

Example Request
curl -X GET 'https://api.cosmospay.lat/cosmos-api/v1/payment-links/cmh4x2k9a0001l70g8v5q3z2w'
Example Response
{  "id": "cmh4x2k9a0001l70g8v5q3z2w",  "kind": "PAY",  "chain": "stellar",  "network": "public",  "status": "PENDING",  "payTo": "GCALNQQBXAPZ2WIRSDDBMSTAKCUH5SG6U76YBFLQLIXJTF7FE5AX7AOO",  "amount": "25.5",  "asset": "native",  "assetIssuer": null,  "memo": "4127759120438726917",  "msg": "Order #24",  "uri": "web+stellar:pay?destination=GCALNQQBXAPZ2WIRSDDBMSTAKCUH5SG6U76YBFLQLIXJTF7FE5AX7AOO&amount=25.5&memo=4127759120438726917&memo_type=MEMO_ID&msg=Order+%2324",  "qr": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA…",  "txHash": null,  "networkFee": null,  "merchantFee": {    "bps": 150,    "fixed": "0.25",    "amount": "1.75",    "asset": "XLM",    "wallet": "GBDHAQXQQ75WVBUZ2IX3O7ME7JOKJUOUPUXRNDCORUJODWQCTVUEQ62R",    "paidBy": "recipient"  },  "payerAccountRequired": false,  "expiresAt": "2026-10-24T13:34:56.000Z",  "createdAt": "2026-10-24T12:34:56.000Z",  "checkoutTheme": "classic"}
POST
/v1/payment-links/{id}/transaction

A SEP-7 pay link pays one account, so a Stellar payment link with a merchant fee (payerAccountRequired on the link) asks for its payer: given their account, this builds the unsigned envelope with both payments (to the merchant, and the fee to its wallet) and the link’s MEMO_ID, and its web+stellar:tx link and QR. The link settles on any transaction that pays both with the memo, so nothing is stored and a lapsed envelope is simply built again.

Only for an open link (PENDING). Budgeted per client address.

id*string

The payment intent id, as in the link.

application/json
  1. body

The payer of a Stellar payment link with a merchant fee, for whom the service builds the envelope to sign.

account*string

The Stellar account that will pay and sign: the envelope is built on its sequence number, so it must exist on the link’s network.

OK

validation_failed: the link pays its destination directly (open its uri), or account is not a Stellar account. invalid_state_transition: the link is no longer open. trustline_missing: the merchant no longer trusts the asset.

No payment intent has this id.

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/payment-links/cmh4x2k9a0001l70g8v5q3z2w/transaction' \  -H 'Content-Type: application/json' \  -d '{  "account": "GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ"}'
Example Response
{  "xdr": "AAAAAgAAAAA...",  "uri": "web+stellar:tx?xdr=AAAAAgAAAAA...",  "qr": "data:image/png;base64,iVBORw0KGgo..."}
POST
/v1/payment-links/{id}/events

The hosted checkout tells what the payer did with a wallet while the link is pending: walletOpened (the wallet link, the web wallet, the extension or Freighter was opened), walletClosed (the wallet came back without paying) and sent (the page saw the wallet send the payment). The owner reads them as checkoutWalletAt, checkoutWalletClosedAt and checkoutSentAt on the intent, to follow a payment that is not on-chain yet.

Informational only: the status changes on what the chain says, never on these. An event for a link that is no longer pending is ignored. Budgeted per client address.

id*string

The payment intent id, as in the link.

application/json
  1. body

What the payer did with a wallet, as the hosted checkout page reports it. Informational: the intent status changes only on the chain.

event*string

walletOpened: the payer opened a wallet from the page (the wallet link, the web wallet, the extension, Freighter). walletClosed: the wallet came back without paying (it declined, or the page was shown again first). sent: the page saw the wallet send the payment.

Value in"walletOpened""walletClosed""sent"
204

Noted (or ignored: the link is not pending).

event is not one of the three.

No payment intent has this id.

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.

Example Request
curl -X POST 'https://api.cosmospay.lat/cosmos-api/v1/payment-links/cmh4x2k9a0001l70g8v5q3z2w/events' \  -H 'Content-Type: application/json' \  -d '{  "event": "walletOpened"}'
Example Response
Empty
GET
/v1/payment-links/{id}/solana-pay

A Solana payment link with a merchant fee is a Solana Pay transaction request (solana:<this URL>), because a transfer request names one recipient. A wallet reads this first, then POSTs the payer’s account.

id*string

The payment intent id.

OK

validation_failed: the link is not a Solana Pay transaction request (only a Solana link with a merchant fee is), or account is not a Solana address. invalid_state_transition: the link is no longer open.

No payment intent has this id.

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.

Example Request
curl -X GET 'https://api.cosmospay.lat/cosmos-api/v1/payment-links/cmh4x2k9a0001l70g8v5q3z2w/solana-pay'
Example Response
{  "label": "Cosmos Pay",  "icon": "https://payments.cosmospay.lat/android-chrome-512x512.png"}
POST
/v1/payment-links/{id}/solana-pay

Given the payer’s account, the unsigned transaction (base64) with the link’s memo, the transfer to the merchant carrying the link’s reference, and the merchant fee’s transfer to its wallet (creating their token accounts first when missing, paid by the payer). The link settles from the ledger, found by its reference; nothing is stored. Only for an open link.

id*string

The payment intent id.

application/json
  1. body

What a wallet POSTs to a Solana Pay transaction request: the account that will sign and pay.

account*string

The payer’s account (base58), which pays the fee and signs.

OK

validation_failed: the link is not a Solana Pay transaction request (only a Solana link with a merchant fee is), or account is not a Solana address. invalid_state_transition: the link is no longer open.

No payment intent has this id.

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.

The provider named in x-cosmos-upstream refused the request (provider_error) or could not be reached at all (provider_unavailable). Nothing was charged; retry is safe with the same Idempotency-Key.

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.

The provider in x-cosmos-upstream did not answer in time. Whether it acted on the request is unknown. Retry with the same Idempotency-Key, never with a fresh one.

Example Request
curl -X POST 'https://api.cosmospay.lat/cosmos-api/v1/payment-links/cmh4x2k9a0001l70g8v5q3z2w/solana-pay' \  -H 'Content-Type: application/json' \  -d '{  "account": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU"}'
Example Response
{  "transaction": "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA...",  "message": "Order #24"}