Skip to content

Requests and responses

These rules apply to every endpoint of the merchant API. Errors have their own page: Errors.

Base URL https://api.ctpeway.com
Paths Start with /v1, for example /v1/invoices.
Format JSON in requests and responses. Send Content-Type: application/json with a body.
Authentication Authorization: Bearer <your secret key>. See API keys.
Mode Decided by the key: a test key works on test data, a live key on live data.
Amounts Whole numbers of the asset’s smallest unit, as strings. See Networks and assets.
Names Fields are written in snake_case.
Ids 24 hexadecimal characters. Event ids are different: they start with evt_.

Call the API from your server. It is not meant to be called from a web page.

A request can fail in a way that leaves you unsure whether it worked, for example when the connection drops before the answer arrives. Sending it again could create a second invoice or, worse, a second payout.

An idempotency key removes that risk. Send a header with a value that is unique to the operation:

Terminal window
curl -X POST "https://api.ctpeway.com/v1/payouts" \
-H "Authorization: Bearer $CTPEWAY_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: payout-2026-10-13-supplier-7" \
-d '{
"asset": "USDT",
"network": "tron",
"amount": "250000000",
"destination": "<destination-address>"
}'
  • If you send the same key with the same request again, cTpeWay does not repeat the operation. It returns the answer it gave the first time, with the response header Idempotent-Replayed: true.
  • If you send the same key with a different request, it is refused with status 422 and the code idempotency_key_reused.
  • If the first request with that key is still running, the answer is status 409 and the code idempotency_request_in_progress, with a Retry-After header that says when to try again.
  • A key is remembered for 24 hours.
  • A stored answer belongs to the API key that made the request. It is given only to that key, or to a key that has all of its permissions, such as the one that replaced it when you rolled it. Any other key gets status 403 and the code idempotency_key_not_yours.
  • Only POST requests use it. Send it with every POST. Payouts and refunds, which move money, require it.

A good key comes from your own data, such as your order number or payout reference, so that a retry after a crash or a redeploy uses the same key.

The Node SDK sends an idempotency key with every POST by itself and reuses it when it retries. For calls that move money, pass your own: { idempotencyKey: 'payout-...' }. See Node SDK.

Endpoints that return a list return one page at a time.

Parameter Meaning
limit How many items to return, from 1 to 100. The default is 50.
starting_after Return the items after this point. Pass the next_cursor of the previous page.

A list response always has this shape:

{
"data": [],
"has_more": true,
"next_cursor": "..."
}
Field Meaning
data The items of this page.
has_more Whether there are more items after this page.
next_cursor What to pass as starting_after to get the next page. It is null on the last page.

To read everything, keep requesting with starting_after set to the last next_cursor until has_more is false.

Terminal window
# First page
curl "https://api.ctpeway.com/v1/events?limit=50" \
-H "Authorization: Bearer $CTPEWAY_API_KEY"
# Next page: pass next_cursor from the previous answer
curl "https://api.ctpeway.com/v1/events?limit=50&starting_after=<next_cursor>" \
-H "Authorization: Bearer $CTPEWAY_API_KEY"

Most list endpoints return the newest items first, and take filters as query parameters. Each endpoint’s reference page lists its own. The common ones:

Filter Example Meaning
Status ?status=paid Items in that status. Where the reference says so, you can give several, separated by commas: ?status=open,underpaid.
Network ?network=bsc Items on that network, or on any of several separated by commas.
Time ?created_after=2026-10-01T00:00:00Z Items created at or after that moment. created_before is the other end. Payments use detected_after and detected_before.
Text ?q=order-1042 Items that contain the text, for example in an order id, a customer email or a transaction hash.

Send the same filters with every page.

Every response has a Request-Id header, for example req_.... The same value is in the request_id field of an error.

Log it. If you ask cTpeWay support about a request, the request id lets them find it at once.

Limit Value
Requests per API key 100 per second, with short bursts of up to 300.
Payouts created 10 per hour for each account, by default.

These limits come from the v2 design and can change before launch.

A request over the limit is answered with status 429 and an error of type rate_limited. Wait and try again, waiting longer after each failure. The Node SDK does this for you.

The version is part of the path: /v1. Within a version cTpeWay only adds things. It does not remove or rename what is already there. Additions include new endpoints, new fields in responses, new optional request fields and new event types.

Write your code so that additions do not break it:

  • ignore response fields you do not know;
  • ignore webhook event types you do not know;
  • do not assume that a list of possible values, such as statuses, will never grow.

Changes are listed in the changelog.