Confirm an invoice payment after customer authentication
const url = 'https://api.aetherplatform.cloud/api/v1/organizations/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/billing/invoices/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/pay/confirm';const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://api.aetherplatform.cloud/api/v1/organizations/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/billing/invoices/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/pay/confirm \ --header 'Authorization: Bearer <token>'Called with no request body after the browser has completed the
3-D Secure challenge of a requires_action answer. The server looks
up the payment it recorded for this invoice itself and marks the
invoice paid only if that payment succeeded for exactly this invoice
and amount — the caller supplies nothing, so an invoice can never be
pointed at some other payment.
Answers with the same 200 shapes as the pay endpoint (paid,
requires_action, processing, canceled; the status set is open in
the same way — treat a value you do not know as processing; a
provider that does not answer is processing, not an error). An
invoice that is already paid answers 200 paid. Unlike the pay
endpoint it does not follow a re-issue: a void invoice answers
409 invoice_void, with the replacement’s id in error.invoice_id
when it has one. Same role restriction as the pay endpoint. The
collection switch does not stop a confirm — it only records what a
payment already is.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”Organization UUID.
Invoice UUID.
Responses
Section titled “Responses”The state of the payment in flight (see status), with the invoice.
The 200 answer of the pay and pay/confirm endpoints. invoice is the live invoice the answer is about — the one that was charged; its id and number can differ from the invoice in the request URL (a re-issue, or a voided invoice that was followed to its replacement).
object
What the payment attempt came to. paid: the invoice is paid. requires_action: the customer must authenticate (3-D Secure) with client_secret, then call pay/confirm. processing: a payment is in flight and the caller has nothing to act on; check again later; it is also what a payment whose outcome the payment provider has not reported yet (it did not answer) is called. canceled: the attempt was called off without a decline; nothing was recorded and the invoice can be paid again. This set is open — additional values may be added, and a concurrent call can answer with any of the non-final values; a client must treat a value it does not know as processing. A declined card is not a status here: it is 402 payment_declined.
An invoice as issued. The document is this record: issuer, buyer and tax rule are frozen at issue time and an issued, numbered invoice is never edited — a change (a discount code applied to it) voids it and issues a replacement under the next number, the two linked by replaces_invoice_id / replaced_by_invoice_id. A billing period has exactly one invoice that is not void.
object
The customer-facing identity, AE-YYYY-NNNN, from a gapless series. Assigned once at issue and never reused; a re-issue gets the next number and the voided invoice keeps its own.
The tax rate applied, in basis points (1900 = 19 %); 0 when no tax is charged.
The statement printed on the invoice explaining the tax treatment (for example why no VAT is charged); empty when there is none.
The amount owed, and exactly the amount a payment charges — there is no separate charged amount.
issued until paid, then paid; void for an invoice that was re-issued (see replaced_by_invoice_id). A failed payment is not a status: the invoice stays issued and the failure is recorded in last_payment_error. An invoice whose total is 0 is paid from the moment it is issued. Clients must tolerate a value they do not know.
The selling entity as it was when the invoice was issued. A historical record: every field is always present, as an empty string when it has no value.
object
Whether the issuer was VAT-registered at issue time. It does not by itself mean VAT was charged — see the invoice’s tax_rate_bp.
The customer as they were when the invoice was issued. A historical record: every field is always present, as an empty string when it has no value. Contains personal data (names, addresses, email).
object
The address of a hosted PDF, when one exists; omitted otherwise. No invoice carries one today.
When the invoice was paid; omitted until it is.
How many payment attempts have been started for this invoice (automatic and manual together). Copied onto a replacement when the invoice is re-issued.
A sanitised decline code or short message from the most recent failed attempt — never a raw payment-provider error. Omitted when no attempt has failed; cleared when the invoice is paid.
When the most recent payment attempt was made; omitted when there has been none.
True while a payment for this invoice has been started and has not reached a final outcome (for example while a 3-D Secure challenge is open). No second payment is started while this is true; the pay endpoint answers requires_action or processing instead.
The organization’s discount (OrgDiscount.id) that was active when the invoice was issued, whether or not its scope matched any line; omitted when there was none. Provenance only — what the discount did is in each line’s discount_cents.
When this document was issued. A replacement carries its own, later issued_at.
Where the payment period counts from. Equal to issued_at for an invoice issued at month close, and copied unchanged onto a replacement, so re-issuing an invoice never extends the time to pay.
When the invoice was voided; omitted unless status is void.
On a replacement: the id of the voided invoice it replaces. Omitted on an invoice issued at month close.
On a voided invoice: the id of the invoice that replaced it — the one to show and to pay. Omitted otherwise.
Present only with status: requires_action: the payment provider’s client secret, with which the browser completes the 3-D Secure challenge. A credential for that one payment; do not log or store it.
Example
{ "status": "paid"}Malformed request — e.g. an invalid path UUID or an unparseable JSON body.
object
object
A stable, machine-readable error code.
object
The platform status page (https://status.aetherplatform.cloud). Present on 5xx answers written by the API’s error writer and on no other; absent, not null, on 4xx.
The payment provider’s decline code. Present only on 402 payment_declined; it is its own field and is never folded into message.
Present on exactly these errors of the invoice pay and pay/confirm endpoints: 402 payment_declined, 402 payment_method_required, 409 invoice_already_paid, 409 invoice_not_issued, 409 invoice_below_minimum, 409 payment_not_in_flight, and 409 invoice_void when the void invoice was replaced. It is the id of the live invoice, which after a re-issue is the replacement and not the id in the request URL (on 409 invoice_void from pay/confirm it is the replacement’s id). Absent on every other error — 400 (including discount_code_invalid), 403, 404, the discount_* 409s, 409 invoice_void with no replacement (nothing live to name), every 5xx and 503 code — and never null.
Examplegenerated
{ "error": { "code": "example", "message": "example", "details": [ { "field": "example", "code": "example", "message": "example" } ], "status_url": "https://example.com", "decline_code": "example", "invoice_id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0" }}Missing or invalid credentials.
object
object
A stable, machine-readable error code.
object
The platform status page (https://status.aetherplatform.cloud). Present on 5xx answers written by the API’s error writer and on no other; absent, not null, on 4xx.
The payment provider’s decline code. Present only on 402 payment_declined; it is its own field and is never folded into message.
Present on exactly these errors of the invoice pay and pay/confirm endpoints: 402 payment_declined, 402 payment_method_required, 409 invoice_already_paid, 409 invoice_not_issued, 409 invoice_below_minimum, 409 payment_not_in_flight, and 409 invoice_void when the void invoice was replaced. It is the id of the live invoice, which after a re-issue is the replacement and not the id in the request URL (on 409 invoice_void from pay/confirm it is the replacement’s id). Absent on every other error — 400 (including discount_code_invalid), 403, 404, the discount_* 409s, 409 invoice_void with no replacement (nothing live to name), every 5xx and 503 code — and never null.
Examplegenerated
{ "error": { "code": "example", "message": "example", "details": [ { "field": "example", "code": "example", "message": "example" } ], "status_url": "https://example.com", "decline_code": "example", "invoice_id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0" }}payment_declined — the payment in flight was declined; error.decline_code carries the decline code and error.invoice_id the invoice.
object
object
A stable, machine-readable error code.
object
The platform status page (https://status.aetherplatform.cloud). Present on 5xx answers written by the API’s error writer and on no other; absent, not null, on 4xx.
The payment provider’s decline code. Present only on 402 payment_declined; it is its own field and is never folded into message.
Present on exactly these errors of the invoice pay and pay/confirm endpoints: 402 payment_declined, 402 payment_method_required, 409 invoice_already_paid, 409 invoice_not_issued, 409 invoice_below_minimum, 409 payment_not_in_flight, and 409 invoice_void when the void invoice was replaced. It is the id of the live invoice, which after a re-issue is the replacement and not the id in the request URL (on 409 invoice_void from pay/confirm it is the replacement’s id). Absent on every other error — 400 (including discount_code_invalid), 403, 404, the discount_* 409s, 409 invoice_void with no replacement (nothing live to name), every 5xx and 503 code — and never null.
Examplegenerated
{ "error": { "code": "example", "message": "example", "details": [ { "field": "example", "code": "example", "message": "example" } ], "status_url": "https://example.com", "decline_code": "example", "invoice_id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0" }}insufficient_role — the caller is a member or viewer. token_not_permitted — the request was authenticated with an API token.
Also answered by the organization role policy (see Authorization): forbidden (not a member of the organization), insufficient_role (the caller’s organization role is below the operation’s minimum) or token_not_permitted (an API token on an operation tokens may not use).
object
object
A stable, machine-readable error code.
object
The platform status page (https://status.aetherplatform.cloud). Present on 5xx answers written by the API’s error writer and on no other; absent, not null, on 4xx.
The payment provider’s decline code. Present only on 402 payment_declined; it is its own field and is never folded into message.
Present on exactly these errors of the invoice pay and pay/confirm endpoints: 402 payment_declined, 402 payment_method_required, 409 invoice_already_paid, 409 invoice_not_issued, 409 invoice_below_minimum, 409 payment_not_in_flight, and 409 invoice_void when the void invoice was replaced. It is the id of the live invoice, which after a re-issue is the replacement and not the id in the request URL (on 409 invoice_void from pay/confirm it is the replacement’s id). Absent on every other error — 400 (including discount_code_invalid), 403, 404, the discount_* 409s, 409 invoice_void with no replacement (nothing live to name), every 5xx and 503 code — and never null.
Examplegenerated
{ "error": { "code": "example", "message": "example", "details": [ { "field": "example", "code": "example", "message": "example" } ], "status_url": "https://example.com", "decline_code": "example", "invoice_id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0" }}The requested resource was not found.
object
object
A stable, machine-readable error code.
object
The platform status page (https://status.aetherplatform.cloud). Present on 5xx answers written by the API’s error writer and on no other; absent, not null, on 4xx.
The payment provider’s decline code. Present only on 402 payment_declined; it is its own field and is never folded into message.
Present on exactly these errors of the invoice pay and pay/confirm endpoints: 402 payment_declined, 402 payment_method_required, 409 invoice_already_paid, 409 invoice_not_issued, 409 invoice_below_minimum, 409 payment_not_in_flight, and 409 invoice_void when the void invoice was replaced. It is the id of the live invoice, which after a re-issue is the replacement and not the id in the request URL (on 409 invoice_void from pay/confirm it is the replacement’s id). Absent on every other error — 400 (including discount_code_invalid), 403, 404, the discount_* 409s, 409 invoice_void with no replacement (nothing live to name), every 5xx and 503 code — and never null.
Examplegenerated
{ "error": { "code": "example", "message": "example", "details": [ { "field": "example", "code": "example", "message": "example" } ], "status_url": "https://example.com", "decline_code": "example", "invoice_id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0" }}payment_not_in_flight — the invoice has no payment in flight, so there is nothing to confirm (error.invoice_id is the invoice). invoice_void — the invoice was voided; when it was re-issued error.invoice_id is the replacement (replaced_by_invoice_id), and it is absent when nothing replaced it. invoice_not_issued — the invoice is not in the issued state (error.invoice_id is the invoice).
object
object
A stable, machine-readable error code.
object
The platform status page (https://status.aetherplatform.cloud). Present on 5xx answers written by the API’s error writer and on no other; absent, not null, on 4xx.
The payment provider’s decline code. Present only on 402 payment_declined; it is its own field and is never folded into message.
Present on exactly these errors of the invoice pay and pay/confirm endpoints: 402 payment_declined, 402 payment_method_required, 409 invoice_already_paid, 409 invoice_not_issued, 409 invoice_below_minimum, 409 payment_not_in_flight, and 409 invoice_void when the void invoice was replaced. It is the id of the live invoice, which after a re-issue is the replacement and not the id in the request URL (on 409 invoice_void from pay/confirm it is the replacement’s id). Absent on every other error — 400 (including discount_code_invalid), 403, 404, the discount_* 409s, 409 invoice_void with no replacement (nothing live to name), every 5xx and 503 code — and never null.
Examplegenerated
{ "error": { "code": "example", "message": "example", "details": [ { "field": "example", "code": "example", "message": "example" } ], "status_url": "https://example.com", "decline_code": "example", "invoice_id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0" }}collection_disabled — no payment engine is available on this platform (the switch itself does not stop a confirm, see above). payment_provider_unavailable — no payment provider is configured, or it rejected the platform’s credentials; the payment’s state could not be read, so nothing is known about it (not that money did not move). Neither carries error.invoice_id. The error carries status_url.
object
object
A stable, machine-readable error code.
object
The platform status page (https://status.aetherplatform.cloud). Present on 5xx answers written by the API’s error writer and on no other; absent, not null, on 4xx.
The payment provider’s decline code. Present only on 402 payment_declined; it is its own field and is never folded into message.
Present on exactly these errors of the invoice pay and pay/confirm endpoints: 402 payment_declined, 402 payment_method_required, 409 invoice_already_paid, 409 invoice_not_issued, 409 invoice_below_minimum, 409 payment_not_in_flight, and 409 invoice_void when the void invoice was replaced. It is the id of the live invoice, which after a re-issue is the replacement and not the id in the request URL (on 409 invoice_void from pay/confirm it is the replacement’s id). Absent on every other error — 400 (including discount_code_invalid), 403, 404, the discount_* 409s, 409 invoice_void with no replacement (nothing live to name), every 5xx and 503 code — and never null.
Examplegenerated
{ "error": { "code": "example", "message": "example", "details": [ { "field": "example", "code": "example", "message": "example" } ], "status_url": "https://example.com", "decline_code": "example", "invoice_id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0" }}