Payment intents
Every request goes to https://api.lemak.cash. About the reference.
Create payment intent
POST /v1/payment_intents
Authentication
Bearer key. The merchant API key, sk_live_ or sk_test_. It reaches /v1 alone. A test key works from the moment the merchant exists. A live key answers 403 live_not_enabled until the merchant's review opens live mode, before any rate limit is spent.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
Idempotency-Key required | header | string | At most 255 characters. |
Api-Version optional | header | string | The version this request is answered at. Absent, the account's pinned version applies, and an account is pinned to info.version on its first request. A version this service does not render is refused with 400 invalid_api_version. api/CHANGELOG.md lists every version. Pattern ^[0-9]{4}-[0-9]{2}-[0-9]{2}$. |
Request body
application/json
PaymentIntentCreate
| Field | Type | Description |
|---|---|---|
amount required | integer (int64) | Minimum 1. |
currency required | string | Pattern ^[A-Z]{3}$. |
merchant_order_id required | string | At most 255 characters. |
payment_method optional | string | |
channel_preference optional | string | |
description optional | string | |
customer optional | string | |
return_url optional | string (uri) | The page the payer returns to after a successful payment. It must be an absolute https URL on a host name, with no user info. An IP literal and localhost are refused, in test mode too. Any other value answers 400 invalid_return_url. At most 2048 characters. |
expires_in optional | integer | Seconds. |
metadata optional | object | A map of string keys to string values. |
Responses
201
Created, or the replay of an earlier identical request.
application/json
PaymentIntent
| Field | Type | Description | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
id required | string | |||||||||||||||||||
object required | payment_intent | |||||||||||||||||||
mode required | string | One of live, test. | ||||||||||||||||||
amount required | integer (int64) | |||||||||||||||||||
currency required | string | Pattern ^[A-Z]{3}$. | ||||||||||||||||||
merchant_order_id required | string | |||||||||||||||||||
status required | string | One of created, requires_payment, processing, succeeded, channel_settled, failed, expired, canceled. | ||||||||||||||||||
payment_method optional | string | |||||||||||||||||||
fee optional | Money | Fields of fee
| ||||||||||||||||||
fx optional | FxLock | Fields of fx
| ||||||||||||||||||
net optional | Money | What the merchant receives, in the settlement currency.Fields of net
| ||||||||||||||||||
available_at optional | string (date-time) | |||||||||||||||||||
next_action optional | NextAction | Fields of next_action
| ||||||||||||||||||
checkout_url optional | string (uri) | The hosted checkout page. It is returned by the call that creates the intent and by no other, because the store keeps only a digest of the session token. | ||||||||||||||||||
created required | string (date-time) | |||||||||||||||||||
expires_at optional | string (date-time) | |||||||||||||||||||
metadata optional | object | A map of string keys to string values. |
Errors
Every error answers with the error object.
| Status | When |
|---|---|
| 400 | A parameter is invalid. A refused return_url answers invalid_return_url. |
| 409 | The idempotency key is in flight, or the merchant order id is taken. |
| 422 | The idempotency key was reused with a different body. |
| Other | 400 bad parameter, 401 authentication, 402 payment failed, 403 forbidden, 404 not found, 409 conflict, 413 request_too_large (a body over 64 KiB), 422 idempotency key reused, 429 rate limited, 5xx api error. |
Example
curl -X POST https://api.lemak.cash/v1/payment_intents \
-H "Authorization: Bearer sk_test_..." \
-H "Idempotency-Key: <Idempotency-Key>" \
-H "Api-Version: 2026-09-01" \
-H "Content-Type: application/json" \
-d '{
"amount": 1000,
"currency": "PHP",
"merchant_order_id": "<merchant_order_id>"
}'
List payment intents
GET /v1/payment_intents
Authentication
Bearer key. The merchant API key, sk_live_ or sk_test_. It reaches /v1 alone. A test key works from the moment the merchant exists. A live key answers 403 live_not_enabled until the merchant's review opens live mode, before any rate limit is spent.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
Api-Version optional | header | string | The version this request is answered at. Absent, the account's pinned version applies, and an account is pinned to info.version on its first request. A version this service does not render is refused with 400 invalid_api_version. api/CHANGELOG.md lists every version. Pattern ^[0-9]{4}-[0-9]{2}-[0-9]{2}$. |
limit optional | query | integer | Minimum 1. Maximum 100. Default 20. |
starting_after optional | query | string | The id of the last object on the previous page. |
status optional | query | string | One of created, requires_payment, processing, succeeded, channel_settled, failed, expired, canceled. |
merchant_order_id optional | query | string | |
created[gte] optional | query | string (date-time) |
Responses
200
A page of payment intents, newest first.
application/json
PaymentIntentList
| Field | Type | Description | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
object required | list | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
data required | array of PaymentIntent | Fields of data
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
has_more required | boolean |
Errors
Every error answers with the error object.
| Status | When |
|---|---|
| Other | 400 bad parameter, 401 authentication, 402 payment failed, 403 forbidden, 404 not found, 409 conflict, 413 request_too_large (a body over 64 KiB), 422 idempotency key reused, 429 rate limited, 5xx api error. |
Example
curl https://api.lemak.cash/v1/payment_intents \
-H "Authorization: Bearer sk_test_..." \
-H "Api-Version: 2026-09-01"
Payment intent
GET /v1/payment_intents/{id}
Authentication
Bearer key. The merchant API key, sk_live_ or sk_test_. It reaches /v1 alone. A test key works from the moment the merchant exists. A live key answers 403 live_not_enabled until the merchant's review opens live mode, before any rate limit is spent.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id required | path | string | Pattern ^pi_[0-9A-Za-z]+$. |
Api-Version optional | header | string | The version this request is answered at. Absent, the account's pinned version applies, and an account is pinned to info.version on its first request. A version this service does not render is refused with 400 invalid_api_version. api/CHANGELOG.md lists every version. Pattern ^[0-9]{4}-[0-9]{2}-[0-9]{2}$. |
Responses
200
The payment intent.
application/json
PaymentIntent
| Field | Type | Description | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
id required | string | |||||||||||||||||||
object required | payment_intent | |||||||||||||||||||
mode required | string | One of live, test. | ||||||||||||||||||
amount required | integer (int64) | |||||||||||||||||||
currency required | string | Pattern ^[A-Z]{3}$. | ||||||||||||||||||
merchant_order_id required | string | |||||||||||||||||||
status required | string | One of created, requires_payment, processing, succeeded, channel_settled, failed, expired, canceled. | ||||||||||||||||||
payment_method optional | string | |||||||||||||||||||
fee optional | Money | Fields of fee
| ||||||||||||||||||
fx optional | FxLock | Fields of fx
| ||||||||||||||||||
net optional | Money | What the merchant receives, in the settlement currency.Fields of net
| ||||||||||||||||||
available_at optional | string (date-time) | |||||||||||||||||||
next_action optional | NextAction | Fields of next_action
| ||||||||||||||||||
checkout_url optional | string (uri) | The hosted checkout page. It is returned by the call that creates the intent and by no other, because the store keeps only a digest of the session token. | ||||||||||||||||||
created required | string (date-time) | |||||||||||||||||||
expires_at optional | string (date-time) | |||||||||||||||||||
metadata optional | object | A map of string keys to string values. |
Errors
Every error answers with the error object.
| Status | When |
|---|---|
| Other | 400 bad parameter, 401 authentication, 402 payment failed, 403 forbidden, 404 not found, 409 conflict, 413 request_too_large (a body over 64 KiB), 422 idempotency key reused, 429 rate limited, 5xx api error. |
Example
curl https://api.lemak.cash/v1/payment_intents/pi_123 \
-H "Authorization: Bearer sk_test_..." \
-H "Api-Version: 2026-09-01"
Cancel payment intent
POST /v1/payment_intents/{id}/cancel
Only a payment intent in created or requires_payment can be canceled.
Authentication
Bearer key. The merchant API key, sk_live_ or sk_test_. It reaches /v1 alone. A test key works from the moment the merchant exists. A live key answers 403 live_not_enabled until the merchant's review opens live mode, before any rate limit is spent.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id required | path | string | Pattern ^pi_[0-9A-Za-z]+$. |
Idempotency-Key required | header | string | At most 255 characters. |
Api-Version optional | header | string | The version this request is answered at. Absent, the account's pinned version applies, and an account is pinned to info.version on its first request. A version this service does not render is refused with 400 invalid_api_version. api/CHANGELOG.md lists every version. Pattern ^[0-9]{4}-[0-9]{2}-[0-9]{2}$. |
Responses
200
The canceled payment intent.
application/json
PaymentIntent
| Field | Type | Description | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
id required | string | |||||||||||||||||||
object required | payment_intent | |||||||||||||||||||
mode required | string | One of live, test. | ||||||||||||||||||
amount required | integer (int64) | |||||||||||||||||||
currency required | string | Pattern ^[A-Z]{3}$. | ||||||||||||||||||
merchant_order_id required | string | |||||||||||||||||||
status required | string | One of created, requires_payment, processing, succeeded, channel_settled, failed, expired, canceled. | ||||||||||||||||||
payment_method optional | string | |||||||||||||||||||
fee optional | Money | Fields of fee
| ||||||||||||||||||
fx optional | FxLock | Fields of fx
| ||||||||||||||||||
net optional | Money | What the merchant receives, in the settlement currency.Fields of net
| ||||||||||||||||||
available_at optional | string (date-time) | |||||||||||||||||||
next_action optional | NextAction | Fields of next_action
| ||||||||||||||||||
checkout_url optional | string (uri) | The hosted checkout page. It is returned by the call that creates the intent and by no other, because the store keeps only a digest of the session token. | ||||||||||||||||||
created required | string (date-time) | |||||||||||||||||||
expires_at optional | string (date-time) | |||||||||||||||||||
metadata optional | object | A map of string keys to string values. |
Errors
Every error answers with the error object.
| Status | When |
|---|---|
| Other | 400 bad parameter, 401 authentication, 402 payment failed, 403 forbidden, 404 not found, 409 conflict, 413 request_too_large (a body over 64 KiB), 422 idempotency key reused, 429 rate limited, 5xx api error. |
Example
curl -X POST https://api.lemak.cash/v1/payment_intents/pi_123/cancel \
-H "Authorization: Bearer sk_test_..." \
-H "Idempotency-Key: <Idempotency-Key>" \
-H "Api-Version: 2026-09-01"
Create payment attempt
POST /v1/payment_intents/{id}/attempts
Start one payment attempt against a channel and return the payment credential. The PaymentAttempt object is not in this spec yet. PRODUCT.md §12.2 names the route and defines no response object. M3 adds the object.
Authentication
Bearer key. The merchant API key, sk_live_ or sk_test_. It reaches /v1 alone. A test key works from the moment the merchant exists. A live key answers 403 live_not_enabled until the merchant's review opens live mode, before any rate limit is spent.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id required | path | string | Pattern ^pi_[0-9A-Za-z]+$. |
Idempotency-Key required | header | string | At most 255 characters. |
Api-Version optional | header | string | The version this request is answered at. Absent, the account's pinned version applies, and an account is pinned to info.version on its first request. A version this service does not render is refused with 400 invalid_api_version. api/CHANGELOG.md lists every version. Pattern ^[0-9]{4}-[0-9]{2}-[0-9]{2}$. |
Request body
application/json
object
| Field | Type | Description |
|---|---|---|
payment_method required | string | |
channel optional | string |
Responses
201
The attempt and its payment credential. An intent that already holds a pending attempt answers with that one, so a second call places no second order with the channel.
application/json
PaymentAttempt
One try at a channel. An intent holds at most one PENDING attempt, and a failed one stays: the history of what was tried is what a dispute and a reconciliation are read against. The channel's own response body is NOT here — it is operator data, and a merchant reads the outcome rather than the wire.
| Field | Type | Description | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
id required | string | Pattern ^pa_[A-Z2-7]+$. | ||||||||||||
object required | payment_attempt | |||||||||||||
status required | string | One of pending, succeeded, failed. | ||||||||||||
amount required | integer (int64) | |||||||||||||
currency required | string | Pattern ^[A-Z]{3}$. | ||||||||||||
payment_method optional | string | |||||||||||||
next_action optional | NextAction | Fields of next_action
| ||||||||||||
failure_code optional | string | |||||||||||||
failure_message optional | string | |||||||||||||
succeeded_at optional | string (date-time) | |||||||||||||
created required | string (date-time) |
Errors
Every error answers with the error object.
| Status | When |
|---|---|
| Other | 400 bad parameter, 401 authentication, 402 payment failed, 403 forbidden, 404 not found, 409 conflict, 413 request_too_large (a body over 64 KiB), 422 idempotency key reused, 429 rate limited, 5xx api error. |
Example
curl -X POST https://api.lemak.cash/v1/payment_intents/pi_123/attempts \
-H "Authorization: Bearer sk_test_..." \
-H "Idempotency-Key: <Idempotency-Key>" \
-H "Api-Version: 2026-09-01" \
-H "Content-Type: application/json" \
-d '{
"payment_method": "<payment_method>"
}'
List payment attempts
GET /v1/payment_intents/{id}/attempts
Every attempt on one payment intent, oldest first, which is the order they were tried in. A failed attempt stays: it is what a dispute is read against.
Authentication
Bearer key. The merchant API key, sk_live_ or sk_test_. It reaches /v1 alone. A test key works from the moment the merchant exists. A live key answers 403 live_not_enabled until the merchant's review opens live mode, before any rate limit is spent.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id required | path | string | Pattern ^pi_[0-9A-Za-z]+$. |
Api-Version optional | header | string | The version this request is answered at. Absent, the account's pinned version applies, and an account is pinned to info.version on its first request. A version this service does not render is refused with 400 invalid_api_version. api/CHANGELOG.md lists every version. Pattern ^[0-9]{4}-[0-9]{2}-[0-9]{2}$. |
Responses
200
Every attempt on the intent, oldest first.
application/json
PaymentAttemptList
| Field | Type | Description | ||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
object required | list | |||||||||||||||||||||||||||||||||||||||||||||||||
has_more required | boolean | |||||||||||||||||||||||||||||||||||||||||||||||||
data required | array of PaymentAttempt | Fields of data
|
Errors
Every error answers with the error object.
| Status | When |
|---|---|
| Other | 400 bad parameter, 401 authentication, 402 payment failed, 403 forbidden, 404 not found, 409 conflict, 413 request_too_large (a body over 64 KiB), 422 idempotency key reused, 429 rate limited, 5xx api error. |
Example
curl https://api.lemak.cash/v1/payment_intents/pi_123/attempts \
-H "Authorization: Bearer sk_test_..." \
-H "Api-Version: 2026-09-01"
Simulate payment intent
POST /v1/test/payment_intents/{id}/simulate
Test mode only. Tell the channel that serves this payment intent what to report, then deliver the callback it answers with on the same path a real delivery takes, signature check included. A live key, or a channel that cannot be told what to report, is refused. The Idempotency-Key is claimed like every other POST: a retry answers the stored result, and the same key on another intent is 422.
Authentication
Bearer key. The merchant API key, sk_live_ or sk_test_. It reaches /v1 alone. A test key works from the moment the merchant exists. A live key answers 403 live_not_enabled until the merchant's review opens live mode, before any rate limit is spent.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id required | path | string | Pattern ^pi_[0-9A-Za-z]+$. |
Idempotency-Key required | header | string | At most 255 characters. |
Api-Version optional | header | string | The version this request is answered at. Absent, the account's pinned version applies, and an account is pinned to info.version on its first request. A version this service does not render is refused with 400 invalid_api_version. api/CHANGELOG.md lists every version. Pattern ^[0-9]{4}-[0-9]{2}-[0-9]{2}$. |
Request body
application/json
PaymentIntentSimulate
| Field | Type | Description |
|---|---|---|
outcome required | string | A payment outcome, or a dispute the channel reports on a paid intent. A dispute claims the whole ordered amount, and won or lost rules on the dispute opened before. A payment outcome replaces the outcome a magic amount set. One of succeeded, failed, pending, dispute_opened, dispute_won, dispute_lost. |
failure_code optional | string | The decline reason a failed outcome reports. It becomes the attempt failure_code. Allowed with outcome failed alone. One of insufficient_funds, payer_cancelled, risk_blocked. |
amount optional | integer (int64) | Minor units the callback reports for a payment outcome. It defaults to the ordered amount. A different value is how a caller exercises the confirming query, which is what decides a success; the callback amount alone never does. |
currency optional | string | Pattern ^[A-Z]{3}$. |
Responses
200
The payment intent, as it stands the moment the callback landed.
application/json
PaymentIntent
| Field | Type | Description | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
id required | string | |||||||||||||||||||
object required | payment_intent | |||||||||||||||||||
mode required | string | One of live, test. | ||||||||||||||||||
amount required | integer (int64) | |||||||||||||||||||
currency required | string | Pattern ^[A-Z]{3}$. | ||||||||||||||||||
merchant_order_id required | string | |||||||||||||||||||
status required | string | One of created, requires_payment, processing, succeeded, channel_settled, failed, expired, canceled. | ||||||||||||||||||
payment_method optional | string | |||||||||||||||||||
fee optional | Money | Fields of fee
| ||||||||||||||||||
fx optional | FxLock | Fields of fx
| ||||||||||||||||||
net optional | Money | What the merchant receives, in the settlement currency.Fields of net
| ||||||||||||||||||
available_at optional | string (date-time) | |||||||||||||||||||
next_action optional | NextAction | Fields of next_action
| ||||||||||||||||||
checkout_url optional | string (uri) | The hosted checkout page. It is returned by the call that creates the intent and by no other, because the store keeps only a digest of the session token. | ||||||||||||||||||
created required | string (date-time) | |||||||||||||||||||
expires_at optional | string (date-time) | |||||||||||||||||||
metadata optional | object | A map of string keys to string values. |
Errors
Every error answers with the error object.
| Status | When |
|---|---|
| Other | 400 bad parameter, 401 authentication, 402 payment failed, 403 forbidden, 404 not found, 409 conflict, 413 request_too_large (a body over 64 KiB), 422 idempotency key reused, 429 rate limited, 5xx api error. |
Example
curl -X POST https://api.lemak.cash/v1/test/payment_intents/pi_123/simulate \
-H "Authorization: Bearer sk_test_..." \
-H "Idempotency-Key: <Idempotency-Key>" \
-H "Api-Version: 2026-09-01" \
-H "Content-Type: application/json" \
-d '{
"outcome": "succeeded"
}'
Advance payment intent
POST /v1/test/payment_intents/{id}/advance
Test mode only. Move one timer of this payment intent to now: expiry moves expires_at, release moves available_at. Nothing else changes; the scheduled job that reads the timer acts on its next tick, on the same path it takes in live mode. A timer is never moved later, so a second call changes nothing. A live key is refused with test_mode_required, and a timer that is not running, such as release before channel_settled, is 409 invalid_state_transition.
Authentication
Bearer key. The merchant API key, sk_live_ or sk_test_. It reaches /v1 alone. A test key works from the moment the merchant exists. A live key answers 403 live_not_enabled until the merchant's review opens live mode, before any rate limit is spent.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id required | path | string | Pattern ^pi_[0-9A-Za-z]+$. |
Idempotency-Key required | header | string | At most 255 characters. |
Api-Version optional | header | string | The version this request is answered at. Absent, the account's pinned version applies, and an account is pinned to info.version on its first request. A version this service does not render is refused with 400 invalid_api_version. api/CHANGELOG.md lists every version. Pattern ^[0-9]{4}-[0-9]{2}-[0-9]{2}$. |
Request body
application/json
PaymentIntentAdvance
| Field | Type | Description |
|---|---|---|
clock required | string | expiry moves expires_at; release moves available_at. One of expiry, release. |
Responses
200
The payment intent, with the timer moved.
application/json
PaymentIntent
| Field | Type | Description | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
id required | string | |||||||||||||||||||
object required | payment_intent | |||||||||||||||||||
mode required | string | One of live, test. | ||||||||||||||||||
amount required | integer (int64) | |||||||||||||||||||
currency required | string | Pattern ^[A-Z]{3}$. | ||||||||||||||||||
merchant_order_id required | string | |||||||||||||||||||
status required | string | One of created, requires_payment, processing, succeeded, channel_settled, failed, expired, canceled. | ||||||||||||||||||
payment_method optional | string | |||||||||||||||||||
fee optional | Money | Fields of fee
| ||||||||||||||||||
fx optional | FxLock | Fields of fx
| ||||||||||||||||||
net optional | Money | What the merchant receives, in the settlement currency.Fields of net
| ||||||||||||||||||
available_at optional | string (date-time) | |||||||||||||||||||
next_action optional | NextAction | Fields of next_action
| ||||||||||||||||||
checkout_url optional | string (uri) | The hosted checkout page. It is returned by the call that creates the intent and by no other, because the store keeps only a digest of the session token. | ||||||||||||||||||
created required | string (date-time) | |||||||||||||||||||
expires_at optional | string (date-time) | |||||||||||||||||||
metadata optional | object | A map of string keys to string values. |
Errors
Every error answers with the error object.
| Status | When |
|---|---|
| Other | 400 bad parameter, 401 authentication, 402 payment failed, 403 forbidden, 404 not found, 409 conflict, 413 request_too_large (a body over 64 KiB), 422 idempotency key reused, 429 rate limited, 5xx api error. |
Example
curl -X POST https://api.lemak.cash/v1/test/payment_intents/pi_123/advance \
-H "Authorization: Bearer sk_test_..." \
-H "Idempotency-Key: <Idempotency-Key>" \
-H "Api-Version: 2026-09-01" \
-H "Content-Type: application/json" \
-d '{
"clock": "expiry"
}'