Payments.lk
මෙම පිටුව දැනට ඉංග්‍රීසියෙන් පමණි. අයදුම්පත, මිල ගණන් සහ මුල් පිටුව සිංහල සහ දෙමළ භාෂාවලින් ලබා ගත හැක.

Developers / Errors

Every error, and what to do about it.

When the API refuses a request it says which rule it hit, in a code and a reason your code can match, a sentence a person can read, and a link to the entry on this page that explains it. This page is built from the same list the API reads.

The error body

Every error is JSON of the same shape, with the HTTP status on the response.

code
One of the codes below. Stable: match on it.
reason
The precise reason, in snake case, when there is one. Stable: match on it before the code. Absent when the code says it all.
message
A sentence written for a person. It may be reworded, so show it, but never match on it.
docUrl
This page, at the anchor for the reason, or for the code when there is no reason.
traceId
The id of the request in our logs. Quote it when you write to us. The x-trace-id header carries the same id.
fields
Validation failures only: the path of each field that was refused and what is wrong with it.
{
  "code": "CONFLICT",
  "reason": "merchant_not_live",
  "message": "Live payments open once the account is approved and activated.",
  "docUrl": "https://payments.lk/developers/errors#merchant_not_live",
  "traceId": "4f1c2d7e-9a0b-4c3d-8e5f-6a7b8c9d0e1f"
}
{
  "code": "VALIDATION_FAILED",
  "message": "Some of the details provided are not valid.",
  "docUrl": "https://payments.lk/developers/errors#validation_failed",
  "traceId": "0b8e7d6c-5a4f-4e3d-9c2b-1a0f9e8d7c6b",
  "fields": [
    {
      "path": "amountCents",
      "message": "Required"
    },
    {
      "path": "",
      "message": "Unrecognized key(s) in object: 'amount', 'currency'"
    }
  ]
}

What to retry

Retry only what time can change: a 429, a 500, a 503, and idempotency_key_in_progress. Wait a little, and send exactly the same request with the same Idempotency-Key, so a retry can never create a second payment. Every other error needs a change to the request, the key or the account first, and sends back the same answer until then.

An Idempotency-Key is remembered for 24 hours, separately for test and live keys. The same key with the same body inside that time gets the first answer back, marked with the header Idempotent-Replayed: true; after it, the key counts as new. More in the guide.

400 VALIDATION_FAILED

VALIDATION_FAILED

The request is not valid400 VALIDATION_FAILED, do not retry unchanged
Means
The body or the query string failed validation. Every request is checked against a strict schema: a missing field, a value of the wrong type, or a field the endpoint does not take is refused, never ignored.
Fix
Read fields: each entry names the path of a field and what is wrong with it. Correct those and send the request again. Amounts go in amountCents, whole cents of LKR; there is no amount or currency field.
Message
Some of the details provided are not valid.

json_required

The body was not sent as JSON400 VALIDATION_FAILED, do not retry unchanged
Means
Every write takes a JSON body. A body sent without Content-Type: application/json is not read as JSON, so none of its fields are found. curl -d sends a form unless the header is added.
Fix
Add -H "Content-Type: application/json" to curl, or set that header in your HTTP client. The SDKs set it for you.
Message
Send the request body as JSON, with the header Content-Type: application/json.

invalid_json

The body is not valid JSON400 VALIDATION_FAILED, do not retry unchanged
Means
The body was sent as JSON but could not be parsed.
Fix
Send one JSON object. Look for a trailing comma, single quotes, or an unescaped quote or line break inside a string.
Message
The request body is not valid JSON.

idempotency_key_missing

No Idempotency-Key header400 VALIDATION_FAILED, do not retry unchanged
Means
Every write needs an Idempotency-Key, so that a retry can never create a second payment, refund, link or charge.
Fix
Send a key made from your own record, such as order- followed by your order id: 8 to 255 letters, digits, dashes, underscores, colons or dots.
Message
Send an Idempotency-Key header (8 to 255 letters, digits, dashes, underscores, colons or dots) with every write.

amount

The amount is out of range400 VALIDATION_FAILED, do not retry unchanged
Means
A payment is between Rs. 10 and Rs. 1,000,000, which is amountCents 1000 to 100000000. A refund is at least Rs. 1 and at most what is still refundable on the payment.
Fix
Send amountCents as whole cents of LKR: Rs. 1,450 is 145000. To refund everything that is left on a payment, leave amountCents out.
Message
The amount is outside what is allowed.

billing_date_invalid

Date out of range400 VALIDATION_FAILED, do not retry unchanged
Means
A date that has passed would act at once without saying so, and one more than two years away is almost always a typing mistake.
Fix
Send an ISO 8601 time after now and before two years from now, or trialEnd "now" to end a trial at once.
Message
A trial's end, a cancellation date or a resume date is in the future and within two years.

billing_cycle_anchor_invalid

Billing cycle anchor out of range400 VALIDATION_FAILED, do not retry unchanged
Means
The anchor is where renewals fall, and the part period before it is billed at once. The 1st of the month suits monthly and yearly prices only, and an anchor more than one period away would bill more than a period up front.
Fix
Send now, first_of_month with a monthly or yearly price, or an ISO 8601 time within one period of now; or leave it out for your billing settings' default.
Message
A billing cycle anchor is now, first_of_month for a monthly or yearly price, or a time after now and at most one period ahead.

items_invalid

Items cannot go together400 VALIDATION_FAILED, do not retry unchanged
Means
Every item of a subscription renews together, so every price on it bills on the same interval and count, and a subscription keeps at least one item.
Fix
Use active prices from GET /v1/prices that share an interval, and change quantity rather than adding a price twice.
Message
A subscription's items are active prices of yours, each once, all on the same interval.

price_invalid

The price cannot be made400 VALIDATION_FAILED, do not retry unchanged
Means
A tiered price prices every quantity from its tiers, so each tier starts where the one before ends and the last covers every unit beyond.
Fix
Send the tiers in order, each upTo above the one before, and the last upTo null.
Message
The tiers cannot price anything: 2 to 10 tiers, each upTo above the one before, the last one open.

meter_invalid

No such meter400 VALIDATION_FAILED, do not retry unchanged
Means
A metered price bills a meter's usage, and a meter event is counted by the meter whose eventName it carries. Both name an active meter made with a key of the same mode.
Fix
Create the meter with POST /v1/meters, or use the eventName of an active one from GET /v1/meters, with a key of the same mode.
Message
No active meter of yours has that id or event name in this mode.

body_too_large

The body is too large413 VALIDATION_FAILED, do not retry unchanged
Means
The body is over 256 kB. No endpoint needs anything near that.
Fix
Send only the fields the endpoint takes.
Message
The request body is larger than the API accepts, which is 256 kB.

401 UNAUTHENTICATED

UNAUTHENTICATED

No valid API key401 UNAUTHENTICATED, do not retry unchanged
Means
The request did not carry an API key the API accepts. The reason says which of the cases below it is.
Fix
Send the header Authorization: Bearer followed by your secret key. Keys are created in the dashboard under Developers.
Message
Send a valid API key in the Authorization header, as Bearer followed by the key.

missing_api_key

No API key was sent401 UNAUTHENTICATED, do not retry unchanged
Means
The request had no Authorization header. Keys in the query string or the body are not read.
Fix
Send the header Authorization: Bearer sk_test_... with your own key. Keep a secret key on your server.
Message
No API key was sent. Send it in the Authorization header, as Bearer followed by the key.

malformed_api_key

That is not an API key401 UNAUTHENTICATED, do not retry unchanged
Means
The header is not of the form Bearer and a key, or the token is not shaped like a Payments.lk key: it was cut short when copied, has a space or a character too many, or is some other token. Basic authentication is not accepted.
Fix
Copy the key again from where you stored it when it was created; the dashboard shows only its first characters. If it is lost, create a new key under Developers and revoke the old one.
Message
The Authorization header does not carry a Payments.lk API key. It must be Bearer followed by one key, such as sk_test_...

unknown_api_key

The key is not recognised401 UNAUTHENTICATED, do not retry unchanged
Means
The key is shaped correctly, but no active key matches it: it was revoked in the dashboard, an agent key passed its end date, or it belongs to a different Payments.lk environment.
Fix
Check which key your server reads from its configuration. If the key was revoked, create a new one in the dashboard under Developers.
Message
This API key is not recognised. It may have been revoked or have expired, or it was made for another environment.

403 FORBIDDEN

FORBIDDEN

This key cannot do that403 FORBIDDEN, do not retry unchanged
Means
The key is valid, but its kind does not allow this endpoint.
Fix
Call the endpoint from your server with your secret key.
Message
This API key is not allowed to call this endpoint.

key_not_permitted

This kind of key cannot do that403 FORBIDDEN, do not retry unchanged
Means
A publishable key (pk_) may only create checkouts. An agent key (ak_) works only at the MCP endpoint, https://api.payments.lk/mcp, and a secret key does not open that endpoint. Everything else on the REST API needs a secret key (sk_).
Fix
Call the endpoint from your server with your secret key. Never put a secret key in a browser or an app. Connect an agent with an agent key from the dashboard's AI agents page.
Message
This kind of API key cannot call this endpoint. Use your secret key, from your server.

404 NOT_FOUND

NOT_FOUND

No such object for this key404 NOT_FOUND, do not retry unchanged
Means
The id does not name an object this key can see. It is mistyped, it belongs to another account, or it was made in the other mode.
Fix
Check the id. Test and live are kept apart: an id made with a test key works only with test keys, and one made with a live key only with live keys.
Message
No such object for this key. A test key sees only test mode objects, and a live key only live ones.

unknown_endpoint

No such endpoint404 NOT_FOUND, do not retry unchanged
Means
The path, or the method used on it, is not part of the API. Paths are lower case and start with /v1/.
Fix
Compare the method and the path with the API reference on the developers page.
Message
There is no endpoint at this path for this method. Check both against the API reference.

mode_mismatch

The object is in the other mode404 NOT_FOUND, do not retry unchanged
Means
The id names an object of your account, but it was made in the other mode: a live object asked for with a test key, or a test object with a live key.
Fix
Use a key of the object's own mode. A checkout made with a test key is paid, read and refunded with test keys only.
Message
This object belongs to the other mode. A test key sees only test mode objects, and a live key only live ones.

409 CONFLICT

CONFLICT

Not allowed in the current state409 CONFLICT, do not retry unchanged
Means
The request is valid, but the account or the object is not in a state that allows it. The reason says which.
Fix
Read the object again and act on the reason. Sending the same request again will get the same answer until the state changes.
Message
That change conflicts with the current state.

idempotency_key_reused

Key already used for another request409 CONFLICT, do not retry unchanged
Means
Within the last 24 hours this key was sent, in the same mode, with a different body, method or path. A key stands for one request, so the second one is refused rather than guessed at.
Fix
Use a new key for a new request. To retry the first request, send exactly the same body to the same path again.
Message
This Idempotency-Key was already used with a different request.

idempotency_key_in_progress

The first request is still running409 CONFLICT, safe to retry
Means
Two requests with the same key overlapped. The first is still being processed, and its answer is what a retry will get back.
Fix
Wait a second or two, then send the same request again.
Message
The first request with this Idempotency-Key is still running. Retry in a moment.

merchant_not_live

Live mode is not open for this account yet409 CONFLICT, do not retry unchanged
Means
A live payment, link, page or saved card setting was asked for before the account was approved and activated, or while it is not active.
Fix
Use a test key until the dashboard says the account is live, then create live keys there.
Message
Live payments open once the account is approved and activated.

merchant_unavailable

The account cannot take payments409 CONFLICT, do not retry unchanged
Means
The account is suspended or closed.
Fix
Write to [email protected] from the account's email address.
Message
This account cannot take payments right now.

not_refundable

The payment cannot be refunded409 CONFLICT, do not retry unchanged
Means
Only a payment that succeeded, or is partly refunded, can be refunded. One that is processing, failed, or already refunded in full cannot.
Fix
Refund after payment.succeeded has arrived. Check refundedCents to see what is left.
Message
Only a successful payment can be refunded.

saved_cards_off

Saved cards are not switched on409 CONFLICT, do not retry unchanged
Means
The checkout asked to keep the card (saveCard: true), but saved cards are not switched on. They use Payable's Advanced plan.
Fix
Switch saved cards on in the dashboard under Business settings, or send saveCard: false.
Message
Saved cards are not switched on for this account.

card_not_reusable

This saved card cannot be charged again409 CONFLICT, do not retry unchanged
Means
The saved card is missing what the processor needs to charge it again, or it was saved by the local simulator, which Payable cannot charge. This does not change with time, so sending the request again gets the same answer.
Fix
Ask the customer to pay once at a checkout with saveCard: true, then charge the new card id that card.saved sends you.
Message
This card cannot be charged again. Ask the customer to save it at a new checkout.

price_unavailable

Price not available409 CONFLICT, do not retry unchanged
Means
A subscription starts on an active price made with a key of the same mode. An archived price keeps its subscriptions running but takes no new ones.
Fix
Create a price with POST /v1/prices, or use an active one from GET /v1/prices, with a key of the same mode.
Message
That price is archived, or belongs to the other mode.

subscription_ended

Subscription has ended409 CONFLICT, do not retry unchanged
Means
A canceled subscription, or one whose first payment never came (incomplete_expired), is final. Its invoices and payments stay readable.
Fix
Start a new subscription for the customer with POST /v1/subscriptions.
Message
This subscription has ended, so it can no longer change.

test_clock_unavailable

Test clocks are sandbox only409 CONFLICT, do not retry unchanged
Means
Moving a subscription's time forward charges its card for every period passed, so it is refused wherever real money would move.
Fix
Advance a subscription made with a sandbox key.
Message
Test clocks run only on Payable's sandbox. Use a sandbox key.

invoice_not_open

Invoice is not open409 CONFLICT, do not retry unchanged
Means
Charging, voiding and marking uncollectible act on an open invoice (voiding also on a draft). A paid, void or uncollectible invoice is final.
Fix
Read the invoice with GET /v1/invoices/{id} and act on its status. A draft is finalised with POST /v1/invoices/{id}/finalize.
Message
This invoice is not open, so it cannot be charged, voided or written off.

invoice_payment_pending

A payment for this invoice is with the processor409 CONFLICT, do not retry unchanged
Means
An invoice is charged once at a time. The outcome of the charge already sent arrives as payment.succeeded or payment.failed, usually within seconds.
Fix
Wait for invoice.paid or invoice.payment_failed, then act on the invoice if it is still open.
Message
A charge for this invoice is with the processor. Wait for its outcome before trying again.

no_card_on_file

No card on file409 CONFLICT, do not retry unchanged
Means
An invoice is charged to the subscription's card or the customer's default card, and neither is usable: never saved, or deleted since.
Fix
Send the customer the invoice's hostedInvoiceUrl: paying there saves the card for the next renewals.
Message
This customer has no card on file to charge. Send them the invoice's page to pay.

subscription_change_refused

Change not possible in this status409 CONFLICT, do not retry unchanged
Means
Some changes depend on where a subscription stands: a trial is ended or moved only while it is trialing, collection is paused only while it renews, a paused subscription is resumed only with a card on file.
Fix
Read the subscription with GET /v1/subscriptions/{id} and make the change its status allows.
Message
That change does not apply to this subscription in its current status.

coupon_invalid

Coupon cannot be used409 CONFLICT, do not retry unchanged
Means
A coupon is taken while it is active, has redemptions left and its redeem-by date has not passed, by a subscription of the same mode.
Fix
Use an active coupon from GET /v1/coupons, or create one with POST /v1/coupons.
Message
That coupon cannot be used: it is archived, used up, past its redeem-by date, or in the other mode.

tax_rate_invalid

Tax rate cannot be used409 CONFLICT, do not retry unchanged
Means
A subscription takes active tax rates of yours made with a key of the same mode.
Fix
Use active rates from GET /v1/tax_rates, or create one with POST /v1/tax_rates.
Message
A tax rate is archived, in the other mode, or not yours.

feature_exists

A feature already has that lookup key409 CONFLICT, do not retry unchanged
Means
Your app checks a customer's entitlements by lookup key, so each key names one feature in each mode.
Fix
Use the existing feature from GET /v1/entitlements/features, or choose another lookup key.
Message
Another feature in this mode already has that lookup key.

meter_exists

A meter already counts that event409 CONFLICT, do not retry unchanged
Means
A meter event is counted by the one meter whose eventName it carries, so an eventName belongs to one meter in each mode.
Fix
Use the existing meter from GET /v1/meters, or choose another eventName.
Message
Another meter in this mode already counts that eventName. Choose another.

monthly_limit_reached

Monthly limit reached409 CONFLICT, do not retry unchanged
Means
Each plan takes card payments up to a monthly limit: Starter to the first pricing bracket's ceiling, Growth to the second's. Payments that succeeded this month and payments with the processor now count toward it, and a payment that would take the month past the limit is refused whole. Refunds do not free up room. The limit resets at midnight on the 1st, Sri Lankan time. Test mode has its own count against the same limit.
Fix
Request an upgrade to the next plan in the dashboard (Plans) or with POST /v1/account/upgrade_requests. In test mode, reset the sandbox's usage on the Developers page. Customers are told only that card payments are not available right now.
Message
This payment would take this month's card payments past your plan's limit. Request an upgrade in the dashboard, or try again after the 1st.

429 RATE_LIMITED

RATE_LIMITED

Too many requests429 RATE_LIMITED, safe to retry
Means
More requests arrived from one address than the API allows: 120 a minute in general, fewer on a few endpoints.
Fix
Wait a minute, then retry with the same Idempotency-Key. Spread bulk work out rather than sending it at once.
Message
Too many requests. Wait a moment and try again.

500 INTERNAL

INTERNAL

Something went wrong on our side500 INTERNAL, safe to retry
Means
An error we did not expect. It is logged in full behind the traceId.
Fix
Retry with the same Idempotency-Key. If it keeps happening, write to [email protected] with the traceId.
Message
Something went wrong on our side. Please try again.

501 NOT_SUPPORTED

NOT_SUPPORTED

Not available yet501 NOT_SUPPORTED, do not retry unchanged
Means
The endpoint exists, but what it does is not built or not switched on yet.
Fix
Nothing in your request will change this. The message says what is missing.
Message
This is not available yet.

503 SERVICE_UNAVAILABLE

SERVICE_UNAVAILABLE

Temporarily unavailable503 SERVICE_UNAVAILABLE, safe to retry
Means
Something the request depends on, such as the card processor, could not be reached or is not ready for this account.
Fix
Retry after a short wait with the same Idempotency-Key, so a retry can never create a second object.
Message
This is not available right now. Try again in a few minutes.

Seen on the hosted pages

These reasons belong to the hosted checkout, checkout pages, the dashboard and agent tools. The REST API does not answer with them today, but a customer sent back to a checkout, or an agent, may meet them.

promotion_invalid

The promotion code does not work400 VALIDATION_FAILED, do not retry unchanged
Means
The page takes no promotion codes, or the code is unknown, switched off or used up. In the customer portal, the code names no active coupon of the merchant's in that mode that can still be taken.
Fix
Check the code in the dashboard: on the checkout page's promotion codes, or, for the customer portal, on the coupon under Subscriptions, Billing settings.
Message
That promotion code is not valid, or has run out.

card_number_refused

A card number was typed on the checkout page400 VALIDATION_FAILED, do not retry unchanged
Means
Something the customer typed on a checkout page (an answer, the delivery address, the tax number or the name) looks like a payment card number: 13 to 19 digits that pass the Luhn check. It was refused and nothing was stored. Card numbers are entered only on the processor's payment page.
Fix
Remove the number and pay again. A page that asks customers for card details is refused when it is saved; report one you see to us.
Message
Never type a card number on this page. You enter your card only on the secure payment page that comes next.

order_invalid

The order does not match the page400 VALIDATION_FAILED, do not retry unchanged
Means
A quantity, an item or a delivery option is outside what the published page allows. The order is priced again on our side, so an edited order is refused.
Fix
Reload the page and order again.
Message
The order does not match what the page allows.

details_invalid

Details not accepted400 VALIDATION_FAILED, do not retry unchanged
Means
An answer, the delivery address, the terms, or a setting of a checkout page was not accepted. The message names which.
Fix
Correct what the message names and try again.
Message
Some of the details were not accepted.

not_open

Already paid or closed409 CONFLICT, do not retry unchanged
Means
The checkout was paid or closed, so it cannot be paid again. For an agent, it also means 20 prepared actions are already waiting for a person.
Fix
Create a new checkout for a new payment. An agent should ask the merchant to approve or decline what is waiting.
Message
This checkout has already been paid or closed.

expired

The checkout expired409 CONFLICT, do not retry unchanged
Means
A checkout lasts 30 minutes from when it was made; after that it cannot be paid, and checkout.expired is sent.
Fix
Create a new checkout when the customer is ready to pay.
Message
This checkout has expired.

page_inactive

The checkout page cannot do that409 CONFLICT, do not retry unchanged
Means
The checkout page is not published, is archived, or cannot move to the status asked for.
Fix
Publish the page first. An archived page cannot come back; make a new one.
Message
This page cannot be changed that way.

page_closed

The checkout page is not taking payments409 CONFLICT, do not retry unchanged
Means
The page is paused, has passed its end date, or has taken as many payments as it allows.
Fix
Resume the page in the dashboard, or change its end date or its limit.
Message
This page is not taking payments right now.

portal_action_refused

Not available in the customer portal409 CONFLICT, do not retry unchanged
Means
The customer portal offers only what the merchant's billing settings allow: cancelling (at the period's end or at once), switching to the prices they chose, changing the card, and, where the merchant turned them on, a quantity within their bounds, a promotion code, a pause of a few months, the customer's own details and a retention offer. A subscription that has ended, is paused, is set to end, or has a change waiting cannot be changed there.
Fix
The merchant can turn these on under Subscriptions, Billing settings, Customer portal, or make the change for the customer in the dashboard.
Message
This change is not available here. Contact the business to make it.

page_busy

The last payments on this page are being made409 CONFLICT, do not retry unchanged
Means
The page takes a fixed number of payments, and open checkouts hold every one that is left. A place is held for 30 minutes from when its checkout opened and freed if that checkout is not paid, so a page never takes more payments than its limit.
Fix
Try again in a few minutes. The merchant can raise the limit in the dashboard.
Message
The last payments this page allows are being made right now. Try again in a few minutes.

page_changed

The checkout page was saved somewhere else409 CONFLICT, do not retry unchanged
Means
Two saves of one checkout page arrived together. Every save is a new numbered version that is never rewritten, so only one of them could take the number and the other is refused instead of overwriting it.
Fix
Reload the page in the dashboard and save again.
Message
This page was saved somewhere else at the same moment. Reload it and make your change again.

page_not_ready

The page cannot be published yet409 CONFLICT, do not retry unchanged
Means
A test page is published on the Payable sandbox, which is set up once the application is submitted.
Fix
Submit your application, then publish the page.
Message
Test pages can be published once your application is submitted.

promotion_limited

Too many wrong promotion codes on this page429 RATE_LIMITED, safe to retry
Means
A checkout page allows a fixed number of wrong promotion codes every ten minutes, counted across everyone who opens it, so codes cannot be guessed. Until the count falls, the page takes no promotion code at all; paying without one still works.
Fix
Wait ten minutes and try the code again, or pay without it.
Message
Too many wrong promotion codes were tried on this page. Try again in a few minutes, or pay without a code.

processor_unavailable

The processor is not available503 SERVICE_UNAVAILABLE, safe to retry
Means
The card processor could not be reached, or this account's processor keys are not set up yet: live keys arrive once the account is activated, and sandbox keys once the application is submitted.
Fix
Try again in a few minutes. In the sandbox, submit your application first.
Message
Card payments are not available for this account right now.

Something not explained here, or an error that keeps coming back? Write to [email protected] with the traceId. The developer guide walks through a first payment step by step.

API errors · Payments.lk