Skip to content

Record a cash payment

POST
/v1/terminal/cash_payments
curl --request POST \
--url https://terminal.api.example.com/v1/terminal/cash_payments \
--header 'Content-Type: application/json' \
--data '{ "idempotency_key": "sale-2026-10-08-0042", "amount": 25000, "tendered": 30000, "currency": "php" }'

Called by a paired terminal, over mutual TLS with its certificate, to record cash it took at the counter. The merchant and store are the terminal’s assignment, never the body’s. The payment is already made, so it is recorded as a succeeded payment intent on the terminal’s channel, with the receipt data to print and the change due. As with every cash payment it is accepted, not yet deposited: see Accepting cash.

The terminal’s own idempotency_key makes a retry safe. The same key with the same terms answers the same payment with 200 and records nothing twice; the same key with other terms is refused with 409. Use a new key for each sale.

Media typeapplication/json
object
idempotency_key
required

The terminal’s key for this sale.

string
<= 64 characters
amount
required

The price, in the currency’s minor unit.

integer
>= 1
tendered
required

The cash handed over. At least amount.

integer
>= 1
currency
required

A three-letter ISO 4217 code, in either case.

string
/^[A-Za-z]{3}$/

A sale already recorded under this key with the same terms, answered again. Also the answer to a retry after a 503 when the first call had recorded the sale, even when no answer was ever received for it. The same body as 201.

Media typeapplication/json
object
object
required
string
Allowed value: terminal_cash_payment
livemode
required
boolean
payment_intent
required

The id of the payment intent made for this payment.

string
status
required

succeeded: the cash was accepted.

string
amount
required

The price, in the currency’s minor unit.

integer
tendered
required

The cash the customer handed over.

integer
change_due
required

tendered less amount: the change to give back.

integer
currency
required

A three-letter ISO 4217 code, in lower case.

string
/^[a-z]{3}$/
receipt
required

What the terminal prints.

object
description
required
string
reference
required

The payment intent’s id.

string
amount
required
integer
tendered
required
integer
change_due
required
integer
currency
required

A three-letter ISO 4217 code, in lower case.

string
/^[a-z]{3}$/
store_label
required

The store the terminal is assigned to.

string
Example
{
"object": "terminal_cash_payment",
"status": "succeeded",
"currency": "php",
"receipt": {
"description": "Cash accepted",
"currency": "php"
}
}

The payment was recorded. Sent with the receipt data.

Media typeapplication/json
object
object
required
string
Allowed value: terminal_cash_payment
livemode
required
boolean
payment_intent
required

The id of the payment intent made for this payment.

string
status
required

succeeded: the cash was accepted.

string
amount
required

The price, in the currency’s minor unit.

integer
tendered
required

The cash the customer handed over.

integer
change_due
required

tendered less amount: the change to give back.

integer
currency
required

A three-letter ISO 4217 code, in lower case.

string
/^[a-z]{3}$/
receipt
required

What the terminal prints.

object
description
required
string
reference
required

The payment intent’s id.

string
amount
required
integer
tendered
required
integer
change_due
required
integer
currency
required

A three-letter ISO 4217 code, in lower case.

string
/^[a-z]{3}$/
store_label
required

The store the terminal is assigned to.

string
Example
{
"object": "terminal_cash_payment",
"livemode": true,
"payment_intent": "pi_01j9x4c7n2p5r8t1v3w6y9z0b2",
"status": "succeeded",
"amount": 25000,
"tendered": 30000,
"change_due": 5000,
"currency": "php",
"receipt": {
"description": "Cash accepted",
"reference": "pi_01j9x4c7n2p5r8t1v3w6y9z0b2",
"amount": 25000,
"tendered": 30000,
"change_due": 5000,
"currency": "php",
"store_label": "Makati branch"
}
}

validation_failure: invalid_parameter for a parameter missing or not valid, named in param; invalid_json for a body that is not JSON; unsupported_media_type for a body that is not sent as JSON; not_acceptable when the request will not accept JSON; method_not_allowed for an HTTP method the path does not take.

Media typeapplication/json
object
error
required
object
type
required
string
Allowed values: validation_failure authentication_failure authorization_failure not_found conflict timeout_or_in_progress policy_rejection invariant_violation rate_limited dependency_failure
code
required

A stable name for this refusal. Branch on this, never on message.

string
message
required

For the developer reading a log. May be reworded.

string
param
required

The field or parameter at fault, when there is one.

string | null
request_id
required
string | null
Example
{
"error": {
"type": "validation_failure",
"code": "invalid_parameter",
"message": "A whole number of minor units, from 1 to 999999999999999999.",
"param": "amount",
"request_id": "req_4f1c0b2e9a7d"
}
}

authentication_failure with terminal_credential_refused: the certificate does not count. Pair the terminal again. See Pairing a terminal.

Media typeapplication/json
object
error
required
object
type
required
string
Allowed values: validation_failure authentication_failure authorization_failure not_found conflict timeout_or_in_progress policy_rejection invariant_violation rate_limited dependency_failure
code
required

A stable name for this refusal. Branch on this, never on message.

string
message
required

For the developer reading a log. May be reworded.

string
param
required

The field or parameter at fault, when there is one.

string | null
request_id
required
string | null
Example
{
"error": {
"type": "validation_failure"
}
}

conflict with idempotency_key_reused: this idempotency_key recorded a different sale. Use a new key for a new sale.

Media typeapplication/json
object
error
required
object
type
required
string
Allowed values: validation_failure authentication_failure authorization_failure not_found conflict timeout_or_in_progress policy_rejection invariant_violation rate_limited dependency_failure
code
required

A stable name for this refusal. Branch on this, never on message.

string
message
required

For the developer reading a log. May be reworded.

string
param
required

The field or parameter at fault, when there is one.

string | null
request_id
required
string | null
Example
{
"error": {
"type": "validation_failure"
}
}

policy_rejection: this payment cannot be taken now. code says why:

code Meaning
account_inactive Your account is not active.
not_permitted_for_account Your account may not use this method yet.
method_not_enabled The method is not enabled for your account.
method_not_set_up The method is enabled but its setup is not finished.
method_suspended The method is suspended for your account.
pricing_unavailable No price is set for this method and amount.
payment_method_unavailable The method cannot take this payment on this channel yet.
no_payment_method_available None of your methods can take this payment now.
test_mode_unavailable Confirming only: this method cannot be simulated in test mode.
limit_exceeded Confirming only: this payment would take your account past its limit.
restricted Confirming only: payments are restricted for your account, store or terminal at the moment.
risk_declined Confirming only: this payment was declined by a risk check.
not_available Unavailable for another reason.
Media typeapplication/json
object
error
required
object
type
required
string
Allowed values: validation_failure authentication_failure authorization_failure not_found conflict timeout_or_in_progress policy_rejection invariant_violation rate_limited dependency_failure
code
required

A stable name for this refusal. Branch on this, never on message.

string
message
required

For the developer reading a log. May be reworded.

string
param
required

The field or parameter at fault, when there is one.

string | null
request_id
required
string | null
Example
{
"error": {
"type": "policy_rejection",
"code": "method_suspended",
"message": "This payment method is suspended for your account.",
"param": null,
"request_id": "req_4f1c0b2e9a7d"
}
}

dependency_failure with service_unavailable: the platform did not answer, or failed part-way. Whether the sale was recorded is not known; the cash is in the till either way. Retry the same request with the same idempotency_key, and never make a new key for the retry: if the sale was recorded, in whole or in part, you are answered with that payment, with 200, and it is recorded once.

Media typeapplication/json
object
error
required
object
type
required
string
Allowed values: validation_failure authentication_failure authorization_failure not_found conflict timeout_or_in_progress policy_rejection invariant_violation rate_limited dependency_failure
code
required

A stable name for this refusal. Branch on this, never on message.

string
message
required

For the developer reading a log. May be reworded.

string
param
required

The field or parameter at fault, when there is one.

string | null
request_id
required
string | null
Example
{
"error": {
"type": "validation_failure"
}
}