Skip to content
Coritan Docs

Pay an invoice

Find your unpaid invoices, pay one with credit, a saved method or a new one, and read an invoice's lines and status.

View as Markdown

Coritan raises an invoice for every order, every renewal and every plan upgrade. Invoices are in US dollars. Pay one to start a new service, to keep a service running past its renewal date, or to lift a suspension. Every invoice downloads as a PDF for your records.

  • Sign in to the dashboard.
  • To pay with credit, have credit on your balance. Add credit to your balance explains how.
  • To pay with a saved method, such as a card, a bank account or a PayPal account, save it first on the Payment methods tab (Manage payment methods). You can also enter a new card, use another method open to you, or use PayPal while you pay. Ways to pay lists every method and says which currencies and countries each one takes.
  • To pay with Apple Pay or Google Pay, have a card in that wallet. On a computer, Apple Pay asks you to scan a QR code with an iPhone on iOS 18 or later.
  1. In the sidebar, select Billing, then the Invoices tab.
  2. Choose a filter:
    • Unpaid lists every invoice you still owe on: unpaid and overdue ones, however old.
    • Paid lists the invoices you have paid.
    • All lists everything, newest first.
  3. Select View beside an invoice, or the row itself, to open it as a page (Read an invoice).

The table shows each invoice's number, Status, Total, the date it was Issued and the date it is Due. Choose how many rows a page shows at the bottom of the table, and move between pages with Previous and Next.

  1. Select Pay beside the invoice. When only one invoice is unpaid, the Overview tab of Billing has the same button under Due now, and an invoice's own page has a pay button too. The page Pay invoice and the invoice's number opens, at /dashboard/billing/invoices/<id>/pay. What you are paying shows the Amount due: the invoice total less anything already paid. When your account's currency is not US dollars, it shows what we charge in your currency, with the invoice's amount in US dollars under it, for example €12.10 over ≈ $12.99 USD. The invoice itself stays in US dollars. The Your payment card beside it lists the invoice's lines and Due now.

  2. Under Currency, check the currency we charge. Choose another one if you want to pay in it, and the Amount due changes at once. The choice is your account's currency, the same one as in Settings.

  3. Choose how to pay:

    • Account credit takes the amount from your balance. It is greyed out when your balance is empty.
    • A saved card or PayPal account pays with that method. Your default method is marked Default.
    • Card opens the payment form, where you choose from the methods open to you. It is also how you pay with a new method when you already have a saved one.
    • PayPal shows PayPal's buttons on the page. Approve the payment in the PayPal window that opens; you stay on the page.
    • Crypto shows where to send cryptocurrency for an invoice in US dollars. It is offered wherever Add credit offers it. The transfer pays the invoice when it lands, as Pay with cryptocurrency describes for credit.
    • Any other provider opens that provider's checkout page, then brings you back to this page.

    An Apple Pay or Google Pay button above these choices pays in one step instead, as Pay with Apple Pay or Google Pay describes.

  4. Select the button in the Your payment card (on a phone, the button at the foot of the page). It says what happens next:

    • Pay with credit when your credit covers the whole amount. Credit is in US dollars whatever currency you pay in.
    • Apply credit when it covers part. The rest stays due, and you pay it the same way.
    • Pay $12.99 (with the amount due) for a saved method or a new card. In another currency it shows the charge in that currency, for example Pay €12.10. For a saved method it reads Pay about €12.10, because we price that charge when it is made.
    • Continue to and the provider's name for a checkout page.
  5. If a payment form opens in place of the choices (Payment details, or Confirm with your bank when your bank asks for a check), complete it and select the button under it, which reads Pay and the amount. Choose another way goes back to the choices. You enter your details in a secure form; Coritan does not store them. The form lists the methods open to you for the Currency and billing country you have. When one of your country's own methods is open, a line under the form names it, for example iDEAL is available for your payment. A method that takes you to another page returns you to the pay page afterwards (When a payment is still processing).

While a payment is running, Cancel and the button are held. If you select a link or a sidebar entry meanwhile, the page asks Leave while paying?. Select Stay to wait for the answer, or Leave if you must; leaving does not cancel the payment, so check Invoices before you pay again. A page you opened from a list, an email or an order's Order placed page returns you there when the payment is done.

When you choose Card, a Keep this payment method for renewals box sits under the choices and is ticked. Ticked, the method is saved to your account when it can be kept again, and we charge it when your services renew. Clear it to pay this invoice only. A kept method appears on the Payment methods tab, where you can remove it (Manage payment methods).

You can pay an invoice in any currency the Currency list offers. We convert the invoice's dollar amount at the exchange rate we publish for that currency and charge the result, so a card statement shows the amount in your currency. The amount we charge is the one on the page. When the rate moves while the page is open, the page shows the new amount and asks you to check it before you pay again.

A saved card pays in the currency you chose only when its account takes that currency. When it does not, the page stays as it is and says This card cannot pay in EUR. Choose another card or pay with a new card. A payment we cannot take in your currency at all shows the reason and Pay in US dollars, which changes your account's currency to US dollars.

Pay every unpaid invoice at once

Section titled Pay every unpaid invoice at once

When two or more invoices are unpaid, Pay all appears on the Invoices tab and under Due now on the Overview tab. It opens the page Pay all invoices, at /dashboard/billing/invoices/pay-all. The Invoices card lists every open invoice, overdue ones first, and Your payment shows the number of invoices and the total in Amount due. Account credit takes US dollars, so the total is in dollars. When your account's currency is not US dollars and you choose a saved card or PayPal account, Amount due shows what we charge in your currency with the dollar total under it, for example €26.06 over ≈ $27.98 USD. The Currency list on the page changes it.

  1. Under How to pay, choose Account credit or a saved card or PayPal account. A new card, a wallet and PayPal pay one invoice at a time. With no saved method and no credit, the page says so and offers Add a payment method.
  2. Select the button in Your payment, which reads Pay with credit or Pay and the total. For a saved method in another currency it reads Pay about €26.06, because we price each charge when it is made.
  3. Watch the list. We charge the invoices in turn, and each shows Paid, Submitted, Needs your bank, Credit ran out, Declined or Not tried.
  4. Select Done. You return to the page you came from.

If an invoice is declined, or your credit runs out, we stop there and the rest read Not tried. When a card cannot pay in your currency, we stop at the first invoice with This card cannot pay in EUR. Choose another card or pay with a new card. The page then shows We cannot charge this card in your currency and Pay in US dollars, which changes your account's currency to US dollars and brings back the choices for the invoices that are still due. Submitted means your bank is still settling the payment, so do not pay that invoice again. For Needs your bank, open the invoice from Invoices and confirm the payment there. The page ends with how many invoices were paid, and the unpaid ones stay under Unpaid.

Pay with Apple Pay or Google Pay

Section titled Pay with Apple Pay or Google Pay

When your phone or browser can pay with Apple Pay or Google Pay, the pay page shows that wallet's button above the other ways to pay. It appears once you first touch or click the page. The button stays when your credit covers the whole amount due. Paying with it charges the wallet's card for the full amount and leaves your credit on your account. While another payment is in progress, such as a saved card or PayPal, the button is greyed out and does nothing.

  1. Select Pay beside the invoice.
  2. Select the Apple Pay or Google Pay button at the top of How to pay.
  3. Check the amount on the payment sheet that opens. It is the Amount due, and it is what we charge.
  4. Approve the payment on the sheet.

The page says Confirming your payment… while we confirm the payment, then returns you to the invoice. Until then, the other ways to pay wait. Like any card you pay with in the dashboard, the card then appears on the Payment methods tab, named after its wallet: for example Apple Pay (Visa ending in 4242) (Manage payment methods).

When a payment is still processing

Section titled When a payment is still processing

A bank debit, a bank transfer and a voucher confirm days later (How long a bank payment takes). After you pay, a message says Payment submitted. The invoice updates once your bank settles it. or Your payment is being processed. The invoice updates when it is done. The pay page stays and shows Your payment is still settling with See the invoice. The invoice stays unpaid until the money arrives, and then moves to Paid. In Pay all, the invoice reads Submitted.

Do not pay again while it processes. Coritan holds the invoice: a second payment on it waits, and renewal retries do not charge it again. The page reads the invoice again for a short time after you pay, and leaves for the invoice when it is paid. When it is still unpaid, open the invoice later.

A method that opens another page (iDEAL, Bancontact, EPS, Przelewy24, Klarna, Alipay, or your bank's own check) returns you to the pay page, and Coritan reads the result:

  • You paid: a message says Invoice paid. and you return to the page you came from.
  • You cancelled: a message says Payment cancelled. The invoice is still due and you paid nothing.
  • The payment failed: a message says The payment did not go through, so you paid nothing. Try again or choose another way to pay.
  • Your bank wants one more step: a message says Your bank still needs to confirm this payment. Open the payment again to finish it. Open the pay page again and finish the check.
  • It is still clearing: a message says Your payment is still being processed. The invoice shows paid when it clears. Do not pay again.

A message confirms the payment, for example Invoice INV-20260925-48213 paid. The page ends on the page you opened it from, or on the invoice. After a saved method in another currency it adds what we charged, for example Invoice INV-20260925-48213 paid. We charged €12.10. The invoice moves to the Paid filter and Coritan emails you a receipt. Paying in full also does what the invoice was for:

  • A new service starts setting up.
  • A renewal moves the service's next renewal date on by one billing period.
  • An upgrade applies the new plan (Change a service's plan).
  • A service suspended over this invoice is resumed.

When a payment is accepted but not yet settled, you see Payment submitted. The invoice updates once your bank settles it. The invoice stays unpaid until the payment clears (When a payment is still processing). Every payment also appears on the Transactions tab (Transactions and payment attempts).

Select View, or the invoice's row, to open it. The page Invoice and its number, at /dashboard/billing/invoices/<id>, shows the status next to the heading, and a back link, All invoices, to the list with its filter. It has three cards:

  • Items: one line per charge, with the Item, Qty, Unit price and Amount. An invoice with use billed by the hour adds Usage detail, with Download rows (CSV) and a help button on each row that asks about that charge (See your usage).
  • Details: Issued, Due and Paid (the date and time it was paid, or Not yet). Refund appears while a refund request for it is open, with its status and amount, and Notes when the invoice has any.
  • Totals: the Subtotal, Tax and Total. When part of the invoice is paid, Already paid and Left to pay follow. Under them are Download PDF and, for an unpaid invoice, a pay button. A paid invoice has Ask for a refund instead, unless a request for it is open already (Ask for a refund).

An older link that ends in ?invoice= opens this page, and one that ends in ?pay= opens the pay page.

On the Invoices tab, select the download button at the end of the invoice's row, or open the invoice and select Download PDF under Totals. The PDF holds the invoice's lines and totals, and the payments and refunds made on it. It names the Coritan company that issued the invoice, and who the invoice is made out to:

  • With a billing address saved, its Legal name, its postal address with the country, your email address and its VAT ID. When Legal name is empty, your name and company stand in for it.
  • Without one, your name, company, email address and country code from your profile.

The PDF shows the billing address as it is when you download it, and that includes older invoices. Keep the PDF you downloaded at the time if you need a record of what an invoice showed.

Each invoice has one of these statuses:

Status Meaning
unpaid Issued and waiting for payment.
overdue Its due date has passed and it is still unpaid. The services on it are suspended soon after; Failed payments and suspended services has the timeline.
paid Paid in full.
cancelled Voided. You owe nothing on it. Coritan cancels an invoice when you cancel its service, or when a newer upgrade replaces an unpaid one.
refunded Paid, then refunded.
draft Not issued yet.
No way to pay is available right now
Nothing is set up to take a payment for this invoice. Contact support.
Could not load the ways to pay
The page could not read the payment options. Select Try again.
Could not take the payment
We could not take the payment from a saved method, Apple Pay or Google Pay. The message under it gives the reason, for example Payment method 812 not found or inactive when the saved method has been removed, or Your card was declined. from the wallet's card. Try again, or choose another way to pay.
The card was declined. Try another card.
The card form shows the reason in a sentence, for example Your card was declined. Try another card. or The security code did not match. Check it and try again. Nothing was charged. Enter the card again, or choose another way to pay.
The payment is processing. The invoice updates once it settles.
The card processor has accepted the payment but not finished it, as with a bank debit. The invoice stays unpaid until it settles.
We have not heard back from the card processor yet. Do not pay again until your invoice updates. If the payment went through, it updates within a few minutes.
The card processor did not answer in time, so we cannot say whether it took the payment. Wait for the invoice to update, then check the Unpaid filter before you pay again. If the invoice stays unpaid, contact support with the date and amount.
Could not start the payment
The card form, the provider's checkout page or the Apple Pay or Google Pay payment could not be created. The message under it gives the reason. Try again, or choose another way to pay.
The Apple Pay or Google Pay button is missing
The button appears only where your browser and device can pay with that wallet, and only while the invoice has something left to pay. Choose another way to pay.
The Apple Pay or Google Pay button is greyed out
Another payment for the invoice is in progress, such as a saved card or PayPal. Wait for it to finish.
We cannot take this payment in your currency
The message under it gives the reason, for example Payment currency EUR is not enabled. Select Pay in US dollars to pay in US dollars, or choose another way to pay.
The amount changed to $214.20. Check it and pay again.
The amount due changed after the page opened, and we charged nothing. The page now shows the new Amount due. Check it, then select the Apple Pay or Google Pay button again.
The amount changed while the payment sheet was open. Check it and pay again.
The amount due changed while the Apple Pay or Google Pay sheet was open, so we charged nothing. Check the Amount due, then select the button again.
Another payment started while the payment sheet was open, so we did not take this one.
You paid the invoice another way while the Apple Pay or Google Pay sheet was open. We charged the wallet nothing. Check the invoice before you pay again.
We received your payment and are confirming it. You do not need to pay again.
The wallet took the payment, and we are still recording it. The invoice changes to Paid once we have, without you doing anything. Until you reload the page, it does not offer Apple Pay or Google Pay for this invoice again. If the invoice stays unpaid, contact support with the date and amount.
Could not confirm the payment
You approved the payment, but the invoice did not update. Your bank may already have taken the money, so check the invoice under the Unpaid filter, and your balance, before you pay again. If the invoice is still unpaid, contact support with the date and amount.
The payment was declined.
Your bank or PayPal refused the charge. The message may give the bank's reason instead. Pay another way, or see Failed payments and suspended services.
The payment did not go through, so you paid nothing. Try again or choose another way to pay.
You came back from another page (a bank, iDEAL or Klarna, for example) and the payment was not made. Try again, or pay another way.
Payment cancelled. The invoice is still due and you paid nothing.
You left the other page before paying. Nothing was charged.
Your bank still needs to confirm this payment. Open the payment again to finish it.
Your bank asked for a check that is not finished. Open the pay page again and finish it.
Your payment is still being processed. The invoice shows paid when it clears. Do not pay again.
The payment is clearing. Wait for the invoice to change to Paid.
Back from checkout. The invoice updates once the payment clears.
You came back from a checkout page before the provider confirmed the payment. Check the invoice again later; do not pay twice.
Your payment is still settling
The bank has not confirmed the payment yet. Select See the invoice and check it again later. Do not pay again.
Nothing is due on this invoice
You opened the pay page of an invoice that is already paid or cancelled. Select See the invoice.
We could not find this invoice
The address names an invoice that is not on your account. Select All invoices.
Could not open PayPal
PayPal did not load on the page. Select Try again. If the message says PayPal is not available in this browser. Choose another way to pay., use a card or another method.
Could not open the card form
The card form did not load. Select Try again.
Could not apply your credit
The message gives the reason, for example No credit balance available.
The Pay button is missing
Only unpaid and overdue invoices can be paid. The invoice is already paid, cancelled or refunded.
Could not download INV-20260925-48213
The PDF did not download. The message under it gives the reason. Try again, and contact support if it keeps failing.

GET /billing/invoices lists your invoices, newest first. It takes:

status_filter
open (unpaid or overdue, what the Unpaid filter shows), or one status: draft, unpaid, paid, cancelled, refunded or overdue. Leave it out for every invoice.
page and limit
The page to return (from 1) and how many invoices a page holds (default 50, at most 200).
with_total
true wraps the page in an object with the total and the count per status. Without it, the answer is a bare array of invoices.
Shell
curl "https://api.coritan.com/api/v1/billing/invoices?status_filter=open&with_total=true" \
  -H "Authorization: Bearer $CORITAN_TOKEN"
JSON
{
  "items": [
    {
      "id": 5011,
      "invoice_number": "INV-20260925-48213",
      "user_id": 4821,
      "subtotal": 12.99,
      "tax": 0.0,
      "total": 12.99,
      "amount_paid": 0.0,
      "currency": "USD",
      "status": "unpaid",
      "due_date": "2026-09-28T00:00:00",
      "paid_at": null,
      "notes": null,
      "items": [
        {
          "id": 9120,
          "service_id": 311,
          "description": "Service renewal - survival-smp",
          "item_type": "recurring",
          "quantity": 1.0,
          "unit_price": 12.99,
          "total": 12.99
        }
      ],
      "created_at": "2026-09-25T02:00:00"
    }
  ],
  "total": 1,
  "page": 1,
  "limit": 50,
  "counts": {"all": 14, "open": 1, "draft": 0, "unpaid": 1, "paid": 13, "cancelled": 0, "refunded": 0, "overdue": 0}
}

total counts the invoices that match the filter. counts holds every status whatever the filter, with all and open added.

In each invoice:

id and invoice_number
The number the API uses in paths, and the number printed on the invoice.
subtotal, tax and total
The amounts in US dollars.
amount_paid
What credit and earlier payments have covered. What is left to pay is total minus amount_paid.
currency
USD.
status
One of the statuses in the table above.
due_date, paid_at and created_at
When the invoice falls due, when it was paid (or null) and when it was issued.
items
The lines. service_id is the service a line bills, and item_type is recurring, one_time, proration, addon, discount or manual.

GET /billing/invoices/{invoice_id} returns one invoice in the same shape. It answers 404 with Invoice not found, or 403 with Access denied for an invoice on another account.

GET /billing/invoices/{invoice_id}/pdf returns the invoice as a PDF file, named after its number:

Shell
curl https://api.coritan.com/api/v1/billing/invoices/5011/pdf \
  -H "Authorization: Bearer $CORITAN_TOKEN" \
  -o INV-20260925-48213.pdf

An invoice that is not on your account answers 404 with Invoice not found. The PDF is made out to the billing address saved when you send the request, as GET /auth/me/billing-profile returns it, or to your profile when none is saved.

POST /billing/invoices/{invoice_id}/apply-credit takes as much of the amount due as your balance covers:

Shell
curl -X POST https://api.coritan.com/api/v1/billing/invoices/5011/apply-credit \
  -H "Authorization: Bearer $CORITAN_TOKEN"
JSON
{
  "invoice_id": 5011,
  "applied": "12.99",
  "fully_paid": true,
  "credit_balance": "12.01",
  "message": "Invoice paid with credit"
}

When credit covers only part, fully_paid is false and message is Partial credit applied. When nothing can be applied, the answer is 400 with the reason, such as No credit balance available.

POST /payments/invoices/{invoice_id}/charge charges a saved method. Find its id with GET /payments/methods (Manage payment methods).

Shell
curl -X POST https://api.coritan.com/api/v1/payments/invoices/5011/charge \
  -H "Authorization: Bearer $CORITAN_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: pay-inv-5011-1" \
  -d '{"payment_method_id": 812}'

The body takes:

payment_method_id
The saved method to charge. Required.
amount_usd
Pay part of the invoice: this many US dollars, at most what is left. Leave it out to pay the rest in full.
currency
The currency to charge the method in. Leave it out to use your account's currency (Currencies and countries).

Send an Idempotency-Key header so that retrying a request whose answer you did not receive does not charge twice (Idempotency).

The answer is the payment attempt:

JSON
{
  "id": 7730,
  "invoice_id": 5011,
  "user_id": 4821,
  "user_email": "alex@example.com",
  "gateway_name": "stripe",
  "gateway_config_id": 3,
  "payment_method_id": 812,
  "amount": 1299,
  "currency": "USD",
  "base_amount": "12.99",
  "fx_rate": "1",
  "status": "succeeded",
  "gateway_reference": "pi_3Qexample",
  "error_message": null,
  "decline_type": null,
  "decline_code": null,
  "is_auto_charge": false,
  "charge_schedule_id": null,
  "idempotency_key": "pay-inv-5011-1",
  "refunded_amount": null,
  "created_at": "2026-09-25T09:12:40",
  "completed_at": "2026-09-25T09:12:42",
  "gateway_response": {"id": "pi_3Qexample", "status": "succeeded"},
  "client_secret": null
}

amount is in the charged currency's smallest unit (cents here). base_amount is the US dollar amount it pays and fx_rate the exchange rate used, both as decimal strings. gateway_reference is the provider's id for the payment, and gateway_response holds the provider's own answer. status is one of:

succeeded
Paid.
processing
Accepted but not settled. The invoice updates when it settles.
requires_action
The bank wants the cardholder to confirm. client_secret lets a browser page finish it with Stripe.js; then call confirm-payment as below. A script alone cannot complete this step.
failed
Declined. error_message gives the reason, and decline_type says whether retrying can work (soft) or not (hard).

POST /payments/invoices/{invoice_id}/pay is the older path for the same charge, with the same body and answer.

Pay with a new card, PayPal or a checkout page

Section titled Pay with a new card, PayPal or a checkout page

These flows need a browser for the cardholder's part; the API creates and finishes each payment.

  1. List what can take this invoice with GET /payments/invoices/{invoice_id}/gateways. Each entry has a name to send as gateway_name, and adapter says what it is (stripe for cards, paypal, or another provider).
  2. For a card, create a payment with POST /payments/invoices/{invoice_id}/pay-intent. The answer's client_secret is for Stripe.js in the browser. Asking again for the same invoice and amount returns the same payment. After the card is confirmed, call POST /payments/invoices/{invoice_id}/confirm-payment with the query parameters gateway_name and payment_intent_id. It credits the invoice with the amount that payment was made for, never more than the invoice still owes, and only once. It answers succeeded, pending or requires_action, or 402 with Payment not completed. It writes nothing and answers 400 for a payment made for another invoice or to add credit, 403 for a payment another account made, and 409 for a payment that already settled something else or that does not name this invoice yet. In that last case the invoice updates by itself once the card processor confirms the payment.
  3. For PayPal or another provider, call POST /payments/invoices/{invoice_id}/checkout with gateway_name, return_url and cancel_url. Both must be absolute http or https URLs on a real host: the API answers 400 for a placeholder host such as example.com or localhost. Send the payer to checkout_url. For PayPal, session_id is the PayPal order; once the payer approves it, call POST /payments/invoices/{invoice_id}/paypal-capture with the query parameters order_id and gateway_name.
Shell
curl -X POST https://api.coritan.com/api/v1/payments/invoices/5011/checkout \
  -H "Authorization: Bearer $CORITAN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"gateway_name": "paypal", "return_url": "https://www.coritan.com/dashboard/billing/invoices", "cancel_url": "https://www.coritan.com/dashboard/billing/invoices"}'

A checkout that is still open for the invoice is returned again instead of a new one, with reused set to true. The checkout answers 400 when the invoice is already paid or cancelled.

Show Apple Pay and Google Pay buttons

Section titled Show Apple Pay and Google Pay buttons

Apple Pay and Google Pay buttons pay with a card kept in the payer's phone or browser, through Stripe's Express Checkout Element. The payment sheet shows the amount before the payment exists, so ask for a quote before you show the buttons, and create the payment only once the payer approves.

  1. Ask for the quote with GET /payments/invoices/{invoice_id}/pay-quote before you show the buttons, and again whenever the amount or the currency changes. It takes currency (default: your account's currency), country, gateway_name, amount_usd and save_method, as pay-intent takes them; country is the country_code you send to pay-intent. It also takes card_adapters, which Pay with a Square card explains: leave it out and the quote is always for Stripe. A quote creates nothing and does not contact the card processor.

    Shell
    curl "https://api.coritan.com/api/v1/payments/invoices/5011/pay-quote?currency=USD" \
      -H "Authorization: Bearer $CORITAN_TOKEN"
    
    JSON
    {
      "gateway_name": "stripe",
      "adapter": "stripe",
      "public": {"adapter": "stripe", "account": "stripe", "publishable_key": "pk_live_...", "payment_method_configuration": "pmc_..."},
      "publishable_key": "pk_live_...",
      "payment_method_configuration": "pmc_...",
      "currency": "USD",
      "charge_amount": 1299,
      "base_amount": "12.9900",
      "fx_rate": "1",
      "save_method": true,
      "business_name": "Coritan",
      "save_types": ["card", "link", "sepa_debit", "us_bank_account", "bacs_debit", "au_becs_debit", "cashapp", "amazon_pay", "revolut_pay", "ideal", "bancontact"],
      "label": "Invoice INV-20260925-48213",
      "renewal": {
        "amount": 1299,
        "label": "Monthly renewal",
        "interval_unit": "month",
        "interval_count": 1
      },
      "local_methods": []
    }
    
    • gateway_name is the account we charge through, adapter says which processor it is (stripe or square) and public holds the account's keys for its card form. For Stripe, publishable_key and payment_method_configuration are that account's. The configuration can be null.
    • charge_amount is what the payer pays, in the smallest unit of currency, such as cents. base_amount is the US dollars it pays and fx_rate the rate we converted at.
    • save_method says whether we keep the method for renewals. Without it, we keep the method for an invoice that renews a service.
    • save_types lists the method types the payment saves for later charges when save_method is true, and is empty otherwise. A method that cannot be charged again is paid once and never listed (What a renewal can use). ACSS debit is not listed either: Stripe.js refuses it in paymentMethodOptions and the wallet buttons then fail to load. The buttons pay by card, so leaving it out changes nothing they charge.
    • local_methods lists the methods made for the payer's billing country that the account can show in currency, such as ideal for a payer in the Netherlands paying in EUR. It is empty when there are none, and it can be empty on the first quote after a change.
    • label is the line for the payment sheet, and business_name the name at its top.
    • renewal is what the next renewal charges, when we keep the card and every service on the invoice renews on the same billing cycle. Otherwise it is null.
  2. Load Stripe.js with publishable_key. Create the elements with mode: "payment", amount: charge_amount, currency in lower case, paymentMethodConfiguration: payment_method_configuration, and setupFutureUsage: "off_session" when save_method is true. When save_method is true, also set the saving option of each type in save_types to off_session in paymentMethodOptions, so Stripe accepts the payment we create. Mount an expressCheckout element with business: {name: business_name} and paymentMethods set to {applePay: "always", googlePay: "always", link: "never", paypal: "never", amazonPay: "never", klarna: "never"}. always shows Apple Pay as a QR code outside Safari. The other four never show in this row. Show the row only once Stripe reports a wallet it can offer.

  3. In the element's click handler, resolve with one line item: label for charge_amount. With Apple Pay and a renewal, also send applePay.recurringPaymentRequest: renewal.label as its paymentDescription and regularBilling.label, renewal.amount as regularBilling.amount, interval_unit and interval_count as recurringPaymentIntervalUnit and recurringPaymentIntervalCount, and https://www.coritan.com/dashboard/billing/methods, where you manage saved methods, as managementURL.

  4. In the confirm handler, call elements.submit(). Then create the payment with POST /payments/invoices/{invoice_id}/pay-intent, sending the quote's gateway_name, currency and save_method, and its charge_amount as expected_amount:

    Shell
    curl -X POST https://api.coritan.com/api/v1/payments/invoices/5011/pay-intent \
      -H "Authorization: Bearer $CORITAN_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{"gateway_name": "stripe", "currency": "USD", "save_method": true, "expected_amount": 1299}'
    
  5. Pass the answer's client_secret to stripe.confirmPayment with the same elements, then call confirm-payment as for a card form above.

Charge the quote the sheet opened with. Keep a copy of the quote in the click handler and send that copy's values in step 4. A quote you ask for while the sheet is open waits until the sheet closes (cancel) or its payment ends. When that quote names another amount, or the payer started another payment meanwhile, call event.paymentFailed({reason: "fail"}) in confirm instead of creating the payment, then update the elements to the new quote and let the payer approve again.

When the amount changed after the quote, pay-intent answers 412 and creates nothing. detail.code is amount_changed, detail.message is The amount to pay changed. Check the new amount and pay again., and detail.quote is a new quote in the shape above. Call event.paymentFailed({reason: "fail"}), update the elements to the new charge_amount and currency, and let the payer approve again. Do not retry a 412 with the old amount.

The quote answers 400 for an invoice that is paid, cancelled or has nothing left to pay, and for a currency we do not take, such as Payment currency TRY is not enabled. It answers 503 with No Stripe gateway available when no Stripe account takes the currency. With card_adapters set, the 503 says No card gateway available when no card account takes it.

We no longer take payments with Square. No Square account is open, so a quote never names one, and square-pay refuses every payment and charges nothing. Draw the Stripe form. The rest of this section describes the route while it remains.

Square is a second card processor. A page that can draw Square's card form lists it in card_adapters, a comma list of the processors the page can show: stripe, square or stripe,square. The default is stripe, so a page that does not send it keeps getting Stripe. With square listed, the quote is for Square when the payment rules prefer it for this payment, and for Stripe otherwise. A payment that must keep the card for renewals (an invoice that renews a service, or a quote with save_method true) goes to Stripe while Square cannot keep cards, even when the rules prefer Square. A payment in a currency other than US dollars always goes to Stripe, because Square takes US dollars only.

  1. Ask for the quote with card_adapters=stripe,square. When adapter is square, public holds the account's application_id, the location_id of the storefront and can_save_cards, which is false until we switch saved Square cards on. save_method is false while can_save_cards is false, and renewal is always null.

    Shell
    curl "https://api.coritan.com/api/v1/payments/invoices/5011/pay-quote?currency=USD&card_adapters=stripe,square" \
      -H "Authorization: Bearer $CORITAN_TOKEN"
    
    JSON
    {
      "gateway_name": "square-coritan-americas",
      "adapter": "square",
      "public": {
        "adapter": "square",
        "account": "square-coritan-americas",
        "application_id": "sq0idp-example",
        "location_id": "LEXAMPLE0001",
        "sandbox": false,
        "can_save_cards": false,
        "google_pay": false,
        "apple_pay": false,
        "ach": false,
        "cash_app_pay": false,
        "afterpay": false
      },
      "publishable_key": null,
      "payment_method_configuration": null,
      "currency": "USD",
      "charge_amount": 1299,
      "base_amount": "12.9900",
      "fx_rate": "1",
      "save_method": false,
      "business_name": "Coritan",
      "label": "Invoice INV-20260925-48213",
      "renewal": null
    }
    
  2. Load Square's Web Payments SDK in the browser, create the card form with public.application_id and public.location_id, and call tokenize() when the payer approves. The call returns a one-use token, and sometimes a verification token.

  3. Send the token to POST /payments/invoices/{invoice_id}/square-pay. We charge it in that request, so there is no second step:

    Shell
    curl -X POST https://api.coritan.com/api/v1/payments/invoices/5011/square-pay \
      -H "Authorization: Bearer $CORITAN_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{"source_id": "cnon:example-token", "gateway_name": "square-coritan-americas", "expected_amount": 1299}'
    
    JSON
    {
      "status": "succeeded",
      "attempt_id": 7731,
      "gateway_reference": "OW0aoXS9VTEpMqKlTTYg7OsWY09YY",
      "charge_amount": 1299,
      "currency": "USD",
      "save_method": false,
      "base_amount": "12.99",
      "invoice_number": "INV-20260925-48213"
    }
    

The body takes:

source_id
The token from tokenize(). Required. It works once.
expected_amount
The quote's charge_amount. Send it so that a payment for a changed amount is refused.
gateway_name
The Square account from the quote. Leave it out and we pick the one the quote picks.
verification_token, buyer_email and billing
What Square's buyer verification and receipt use, when you have them.
source_kind
Which method made the token: card (the default), apple_pay, google_pay, ach, cash_app or afterpay. The quote's public says which of google_pay, apple_pay, ach, cash_app_pay and afterpay the account has switched on. We answer 400 and charge nothing for a method the account has not switched on, or when the token is not that kind of token. A payment made with ach answers pending, and the invoice updates when the bank confirms it, 2 to 3 business days later. Only a card can be kept for renewals: with any other kind, save_method answers saved_method false with a message.
currency and amount_usd
As for pay-intent. currency defaults to USD and must be USD. amount_usd pays part of the invoice.
save_method
true to keep the card for renewals. We honor it only while public.can_save_cards is true and ignore it otherwise. When a save was asked for and Square took the payment, the answer also holds saved_method: true when the card is saved, and false with a message when it could not be saved. The payment is succeeded either way.

status says what happened:

succeeded
Square took the payment and the invoice is updated. A later webhook from Square changes nothing.
pending
Square has not finished (a bank debit, or a payment it approved and has not captured), or the card processor did not answer in time. message says which. The invoice is unchanged. Do not send the payer to pay again: when the answer has unknown set to true, the card may already be charged, and Square tells us the result.
failed
Square declined the card. The answer is still 200. message is a sentence to show the payer. Ask for a new token with tokenize() and send it: a token that was used cannot be used again.

Send the same token twice and we charge once: the second request answers what the first did, with reused set to true. A new token for an invoice that has a payment still in progress answers 409 with a Retry-After header and A payment for this invoice is still being processed. Wait for the invoice to update before you pay again., and no charge, as does a second request while the first still waits for Square. Two different cards sent together never both charge: the second answers 409. When the amount changed after the quote, square-pay answers 412 and charges nothing, exactly as pay-intent does: detail.quote is a new quote to show. Square charges whole cents, so amount_usd is rounded to cents. It answers 400 for a currency other than USD (This way of paying takes US dollars only. Choose another way to pay., with or without gateway_name), for an invoice that is paid, cancelled or refunded or has nothing left to pay, and for an account that is not Square's (send Stripe payments to pay-intent), 404 for an unknown invoice, 403 for another account's, and 429 after 20 tries in 10 minutes for your account or 60 for your address. When Square took the money and our booking then failed, the answer is pending and the invoice updates when we finish the booking. When the card processor never answered (unknown is true), we look the payment up again within a few minutes: if it exists the invoice is paid, and if there is none after 30 minutes the try is closed and you can pay again. pay-intent called with a Square account answers 400 with Use square-pay to pay by Square.

API operations on this page

MethodPathWhat it does
GET/api/v1/billing/invoicesNewest first, ties by id so a page boundary never repeats or skips a row
GET/api/v1/billing/invoices/{invoice_id}Get invoice
GET/api/v1/billing/invoices/{invoice_id}/pdfThe invoice as a PDF to keep, for the account it belongs to
POST/api/v1/billing/invoices/{invoice_id}/apply-creditApply account credit to an unpaid invoice (unlocks provision / plan change when paid)
GET/api/v1/payments/invoices/{invoice_id}/gatewaysThe payment accounts that can take this invoice, in routing order
POST/api/v1/payments/invoices/{invoice_id}/chargeCanonical saved-method charge for an invoice (alias of /pay)
POST/api/v1/payments/invoices/{invoice_id}/payCharge a saved payment method for an invoice (legacy path; prefer /charge)
POST/api/v1/payments/invoices/{invoice_id}/checkoutCreate invoice checkout
GET/api/v1/payments/invoices/{invoice_id}/pay-quoteWhat a card payment for an invoice charges, and which card form to draw
POST/api/v1/payments/invoices/{invoice_id}/pay-intentCreate a Stripe PaymentIntent to pay an invoice in the page
POST/api/v1/payments/invoices/{invoice_id}/square-payPay an invoice with a Square card token
POST/api/v1/payments/invoices/{invoice_id}/confirm-paymentRecord a card payment the customer finished in the page, and answer how it settled
POST/api/v1/payments/invoices/{invoice_id}/paypal-captureCapture an approved PayPal order for an invoice and apply it