Simulate a payment to an invoice
Test mode only. Creates a synthetic payment (tx_hash: sim_…, simulated: true) that drives the same invoice, settlement, ledger and webhook logic as a real one. The payment goes to the option named by option_id, or by asset and network; without either, to the selected option, or to the only option the invoice has. An option nobody selected yet is selected first, exactly as the checkout page would (rate locked, address assigned). The answer is the resulting payment; read the invoice for its new status.
Authorization
Section titled “Authorization”Send your API key as a bearer token in the Authorization header. Secret API key: Authorization: Bearer ctp_live_sk_…. A publishable key (ctp_…_pk_…) is accepted by these operations only, which serve reference data: getRate, listAssets, listNetworks (each marked x-publishable-key: true). Every other operation refuses it with 403 publishable_key_not_allowed, whatever Origin the request carries: that header binds browsers, not other clients, and nothing on this API relies on it.
Path parameters
Section titled “Path parameters”| Name | Type | Description |
|---|---|---|
id required |
string | At most 100 characters. |
Headers
Section titled “Headers”| Name | Type | Description |
|---|---|---|
Idempotency-Key |
string | Makes the request safe to retry: the same key with the same request replays the first response (Idempotent-Replayed: true) for 24 hours; the same key with a different request is 422 idempotency_key_reused; while the first request is still running, 409 idempotency_request_in_progress with Retry-After. Only POST honours it. At most 255 characters. Pattern ^[!-~]+$. |
Request body
Section titled “Request body”The body is optional.
| Field | Type | Description |
|---|---|---|
outcome |
string | Default paid. reorg confirms and then orphans the payment; dropped never confirms. One of paid, underpaid, overpaid, late, reorg, dropped. |
stage |
string | How far the payment gets. Default confirmed. A payment left at detected is confirmed later with POST /test/payments/{id}/confirm. One of detected, confirmed. |
settlement |
string | Also play the settlement: release it, or hold it for lack of master funds. One of released, held. |
amount |
string | Base units. Default: what the outcome needs. A whole number written as a string of digits. |
inferred |
boolean | true: the payment is one noticed as a rise of the address’s balance, with no transaction known yet (detected_by: balance). Only with outcome: paid (the default); use amount for another sum. POST /test/payments/{id}/attach_transaction then plays the transaction being found. |
option_id |
string | An option of the invoice, by id. At most 64 characters. |
asset |
string | An option of the invoice, by asset symbol (with network when the symbol is on several). At most 16 characters. |
network |
string | …and by network slug. At least 2 characters, at most 32 characters. |
Example request
Section titled “Example request”curl -X POST "https://api.ctpeway.com/v1/test/invoices/{id}/simulate_payment" \ -H "Authorization: Bearer $CTPEWAY_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: <a-unique-key>" \ -d '{ "outcome": "paid", "settlement": "held"}'import { CtpeWay } from '@ctpeway/sdk';
const ctpeway = new CtpeWay(process.env.CTPEWAY_API_KEY);
const result = await ctpeway.test.invoices.simulatePayment('<id>', { outcome: 'paid', settlement: 'held',});Response
Section titled “Response”200 OK
Section titled “200 OK”| Field | Type | Description |
|---|---|---|
id |
string | |
status |
string | One of detected, confirmed, orphaned, dropped. |
invoice_id optional |
string | |
option_id optional |
string | |
deposit_address_id optional |
string | |
network |
string | |
asset |
string | |
asset_id |
string | |
contract optional |
string | |
decimals |
integer | |
address |
string | |
from_address optional |
string | |
tx_hash optional |
string | The transaction that paid. Absent while the payment is known only from a balance change (detected_by: balance) and its transaction has not been identified; payment.transaction_attached announces it. A simulated payment (test mode, simulated: true) carries its sim_… id here. |
tx_index optional |
integer | Position of the transfer inside the transaction. Present exactly when tx_hash is. |
amount |
string | A whole number written as a string of digits. |
confirmations |
integer | |
block_height optional |
integer | |
block_hash optional |
string | |
usd_value optional |
string | Value at the price snapshot taken at confirmation. A decimal number written as a string, with up to 8 decimal places. |
late |
boolean | Confirmed after the invoice had expired or been canceled. |
simulated |
boolean | |
detected_by |
string | How the payment was found, fixed when it is first seen: poll (its transaction was seen while watching the address), hint (its transaction was reported through the checkout and found on the network), balance (the address’s balance rose; the transaction is identified later, and tx_hash is absent until then), simulated (test mode). One of poll, hint, balance, simulated. |
detected_at |
string (date-time) | |
confirmed_at optional |
string (date-time) | |
settlement optional |
object | The settlement this payment produced, in full: status, fee, what is held and why, release transactions. Absent until the payment confirms. Webhook events carry only { id, status } here. |
settlement. |
string | |
settlement. |
string | One of pending, held, releasing, released, failed, reverted. |
settlement. |
string | |
settlement. optional |
string | |
settlement. optional |
string | |
settlement. |
string | |
settlement. |
string | |
settlement. |
string | |
settlement. |
string | |
settlement. |
string | The deposit, base units of asset. A whole number written as a string of digits. |
settlement. |
string | A decimal number written as a string, with up to 8 decimal places. |
settlement. |
integer | |
settlement. |
string | Platform fee owed, base units of native_asset. A whole number written as a string of digits. |
settlement. |
string | One of deposit, master. |
settlement. |
string | A whole number written as a string of digits. |
settlement. |
string | A whole number written as a string of digits. |
settlement. optional |
string | Native coin the master wallet must hold for this release. A whole number written as a string of digits. |
settlement. optional |
string | |
settlement. optional |
string | Why it is held (status held) or why it failed (status failed); absent in any other status. insufficient_master_balance: Held: the master wallet has too little native coin to pay the platform fee and the network costs of the release (token deposits). Released by itself once the wallet is topped up. uneconomic: Held: the network fee of the release is estimated at more than half of what the deposit is worth. Looked at again on every planning run and released when the estimate falls. below_sweep_min: Held: the deposit is worth less than the merchant’s minimum for a sweep. It stays in its address until that setting allows it or another release from the same address takes it along. payment_orphaned: Failed: a chain reorganisation removed the payment while its release was under way. The settlement returns to the queue by itself if the payment confirms again. funds_missing: Failed: the deposit is no longer at its address and no release on record moved it. Needs an operator. not_releasable: Failed: the network cannot release this deposit as it stands (an asset or address it does not support, or a release plan that did not pass its checks). Needs an operator. transaction_failed: Failed: a transaction of the release was rejected or can no longer be included. Retried by an operator; what was already paid is not paid again. replanning: Failed for a moment: a transaction prepared for the release could not be used as it was, and the release is being planned again by itself. Nothing to do. unclassified: Failed: for a reason outside this list. Needs an operator. One of insufficient_master_balance, uneconomic, below_sweep_min, payment_orphaned, funds_missing, not_releasable, transaction_failed, replanning, unclassified. |
settlement. optional |
string | |
settlement. optional |
string | |
settlement. optional |
string | |
settlement. |
string | A whole number written as a string of digits. |
settlement. optional |
string | A whole number written as a string of digits. |
settlement. |
boolean | |
settlement. |
string (date-time) | |
settlement. optional |
string (date-time) | |
settlement. optional |
string (date-time) | |
settlement. optional |
string (date-time) | |
settlement. |
string | The platform fee in USD, fixed when the payment confirmed. A decimal number written as a string, with up to 8 decimal places. |
settlement. |
string | USD price of one whole native_asset in the price snapshot the fee was computed from: fee_native is fee_usd at this price. A decimal number written as a string, with up to 8 decimal places. |
settlement. |
boolean | false for objects of the test environment. |
invoice_number optional |
integer | number of the invoice that was paid. Payments to an invoice only. |
deposit_address_name optional |
string | Name of the deposit address that was paid, if it has one. Payments to a deposit address only. |
confirmations_required |
integer | Confirmations the network asks of a payment of this value before it is confirmed. Compare with confirmations. On networks that follow the chain’s own finality this is the depth used when the node cannot report finality. |
livemode |
boolean | false for objects of the test environment. |
{ "id": "string", "status": "detected", "invoice_id": "string", "option_id": "string", "deposit_address_id": "string", "network": "string", "asset": "string", "asset_id": "string", "contract": "string", "decimals": 0, "address": "string", "from_address": "string", "tx_hash": "string", "tx_index": 0, "amount": "1000000", "confirmations": 0, "block_height": 0, "block_hash": "string", "usd_value": "10.00", "late": true, "simulated": true, "detected_by": "poll", "detected_at": "2026-01-01T00:00:00.000Z", "confirmed_at": "2026-01-01T00:00:00.000Z", "settlement": { "id": "string", "status": "pending", "payment_id": "string", "invoice_id": "string", "deposit_address_id": "string", "network": "string", "asset": "string", "asset_id": "string", "native_asset": "string", "gross": "1000000", "usd_value": "10.00", "fee_bps": 0, "fee_native": "1000000", "fee_source": "deposit", "fee_paid": "1000000", "fee_carried": "1000000", "required_native": "1000000", "master_wallet_address": "string", "reason": "insufficient_master_balance", "fee_tx": "string", "topup_tx": "string", "sweep_tx": "string", "network_fees": "1000000", "net_released": "1000000", "simulated": true, "confirmed_at": "2026-01-01T00:00:00.000Z", "held_since": "2026-01-01T00:00:00.000Z", "released_at": "2026-01-01T00:00:00.000Z", "failed_at": "2026-01-01T00:00:00.000Z", "fee_usd": "10.00", "native_price": "10.00", "livemode": true }, "invoice_number": 0, "deposit_address_name": "string", "confirmations_required": 0, "livemode": true}The values are placeholders generated from the schema. They show the shape, not real data.
Errors
Section titled “Errors”A failed request answers with the error format described under Errors.
Besides the codes any endpoint can return, this endpoint can answer with these code values:
address_derivation_unavailableaddress_derivation_unverifiedamount_below_minimuminvalid_amountinvoice_expiredinvoice_not_foundinvoice_not_openinvoice_option_ambiguousinvoice_option_lockedinvoice_option_not_foundinvoice_option_not_selectedinvoice_option_unavailableprice_unavailabletest_mode_onlywallet_account_not_found

