Invoices API
Create an invoice from your own platform and send its link to your customer. We issue the invoice (PDF, payment page, email), collect the payment and tell you what happened through the invoice's own webhooks.
Every call needs a server key (sk_live_ or sk_test_). An invoice belongs to the key's business and mode: another business's invoice, or a test invoice read with a live key, is a 404. The invoice is issued by your business, under the legal name, TRN and GCT registration number in your settings.
Create an Invoice
/v1/invoicesScope: invoice.create
Request Body
{
"customer": { "name": "Marcia Thompson", "email": "[email protected]", "phone": "+18765550142" },
"currency": "JMD",
"items": [
{ "description": "Full wash", "quantity": 2, "unitPrice": 500.00, "discount": 100.00, "taxRate": 0.15 }
],
"pricesIncludeTax": false,
"dueDate": "2026-10-31",
"total": 1035.00,
"reference": "ORD-1042",
"metadata": { "orderId": "1042" },
"send": "none",
"successUrl": "https://yoursite.com/orders/1042",
"notificationUrl": "https://yoursite.com/webhooks/pay",
"idempotencyKey": "ord-1042-invoice"
}taxRateis a fraction: 0.15 is 15%. WithpricesIncludeTax: falseeach line's net is quantity × unit price − discount and its tax is net × rate. Withtrue, unit prices and discounts include tax and the tax is worked out of them.- Optional checks: an item's
taxAmount, and the invoice'stotalandtaxTotal. Each must match what the items work out to within 0.01, or the request is refused withvalidation_error. A matchingtaxAmountis used as given, so your rounding is kept. send:"email"emails the invoice tocustomer.emailnow, and we send payment reminders."none"(the default) means we never message your customer: send them thehostedUrlyourself, by SMS for example.dueDatedefaults to your payment terms.reference(at most 100 characters) is yours to search by.metadatatakes up to 50 string pairs and comes back in webhooks.notificationUrl/notificationSecretfollow the same rules as on checkout sessions: an https URL on a public host, and a secret of 16–200 characters. If you leave out the secret we generate one and return it once, asnotificationSecret.idempotencyKey(or anIdempotency-Keyheader): repeating the create with the same key returns the first invoice.issuerandnumberare for businesses allowed to issue invoices for others. Without that permission they are refused withcustom_issuer_not_allowed(403), never ignored.
Response
{
"object": "invoice",
"id": "Q7K2XM",
"number": "INV-0482",
"reference": "ORD-1042",
"status": "open",
"currency": "JMD",
"subtotal": 1000.00,
"discount": 100.00,
"net": 900.00,
"tax": 135.00,
"total": 1035.00,
"amountPaid": 0,
"amountRefunded": 0,
"amountDue": 1035.00,
"dueDate": "2026-10-31T00:00:00+00:00",
"createdAt": "2026-10-09T15:04:00+00:00",
"isLive": true,
"hostedUrl": "https://pay.mplex.net/view-invoice/Q7K2XM",
"pdfUrl": "https://checkout.mplex.net/v1/invoices/Q7K2XM/pdf",
"customer": { "name": "Marcia Thompson", "email": "[email protected]", "phone": "+18765550142" },
"items": [
{ "description": "Full wash", "quantity": 2, "unitPrice": 500.00, "discount": 100.00, "net": 900.00, "taxRate": 0.15, "tax": 135.00, "total": 1035.00 }
],
"metadata": { "orderId": "1042" },
"issuer": { "legalName": "Yard Shop Limited", "tradingName": "Yard Shop", "trn": "123-456-789", "gctNumber": "GCT-0099", "taxLabel": "GCT" },
"notificationSecret": "whsec_…"
}Statuses: draft, open (awaiting payment), partially_paid, paid, past_due, void. The customer pays on hostedUrlwith your business's payment methods.
Retrieve an Invoice
/v1/invoices/{id}Scope: invoice.read
Returns the invoice as above (without notificationSecret).
Find Invoices by Reference
/v1/invoices?reference=ORD-1042Scope: invoice.read
Your business's invoices with that reference, newest first (at most 100), as a list: { "object": "list", "data": [ …invoices ], "hasMore": false }.
Download the PDF
/v1/invoices/{id}/pdfScope: invoice.read
Returns application/pdf: the issued invoice with its issuer block, TRN, GCT number and tax breakdown.
Send (or Resend) an Invoice
/v1/invoices/{id}/sendScope: invoice.update
Emails the invoice to its customer and raises invoice.sent. From then on we also send payment reminders. A paid or void invoice is refused with invoice_not_payable (409).
Void an Invoice
/v1/invoices/{id}/voidScope: invoice.update
{ "reason": "Order cancelled" }An unpaid invoice can no longer be paid once voided, and invoice.voided follows. Voiding an invoice that is already void returns it unchanged. An invoice that has been paid, in full or in part, is refused with invoice_not_voidable (409): refund it instead.
Refund an Invoice
/v1/invoices/{id}/refundScope: invoice.refund
{ "reason": "Customer returned the item" }Refunds every payment on the invoice in full; partial refunds aren't available yet. Each refund follows the same rules as checkout session refunds: the same payment_not_refundable and refund_failed errors, including whether a manual refund is needed. A refund that failed is safe to retry. Repeating a refund that worked returns alreadyRefunded: true. An invoice with no payment is refused with nothing_to_refund (409).
{
"invoiceId": "Q7K2XM",
"refunds": [
{ "paymentId": 4821, "referenceNumber": "PAY-4821", "status": "refunded", "amount": 1035.00, "currency": "JMD", "alreadyRefunded": false }
],
"alreadyRefunded": false,
"invoice": { "id": "Q7K2XM", "status": "paid", "amountRefunded": 1035.00 }
}Webhooks
An invoice's events go to its own notificationUrl, signed with its secret (the X-Webhook-Signature header, sha256= plus the hex HMAC of the body), and also to any webhook endpoints set up in your dashboard:
invoice.sent: emailed to the customerinvoice.paid: paid in fullinvoice.payment_failed: a payment attempt failedinvoice.past_due: the due date passed unpaidinvoice.voided: voided; it can no longer be paidinvoice.refunded: a payment on it was refunded
{
"id": "evt_…",
"type": "invoice.paid",
"data": {
"object": {
"object": "invoice",
"identifier": "Q7K2XM",
"invoiceNumber": "INV-0482",
"reference": "ORD-1042",
"status": "Paid",
"total": 1035.00,
"taxAmount": 135.00,
"totalPaid": 1035.00,
"currency": "JMD",
"metadata": { "orderId": "1042" }
}
}
}