Build the customer account area
Let signed-in customers see their services, pay invoices, add credit, save payment methods and edit their profile.
The account area is the part of your storefront a customer sees once signed in: their services, invoices, credit, saved payment methods, billing details and profile. Every call on this page goes to /portal/... with the customer's token as Authorization: Bearer $CUSTOMER_TOKEN, and answers with that customer's own records only.
Before you begin
Section titled Before you begin- Get a customer token as Sign customers in to your storefront describes.
- Serve an invoice page at
/billing/invoices/{invoice_id}on your Custom domain. Invoice emails link to it, and hosted checkouts return to it. - Payments go through Coritan's payment gateways for the customer's currency and country, or through your own PayNow store when your billing mode says so. See PayNow.
Show the customer's services
Section titled Show the customer's servicescurl "https://api.coritan.com/api/v1/orgs/acme/portal/services?per_page=20" \
-H "Authorization: Bearer $CUSTOMER_TOKEN"
The list is newest first. status_filter takes one of the service statuses, page and per_page (1–200, default 50) page through it, and consistency=eventual suits a poll that runs while the page is open.
Each service carries id, status, hostname, product_name, plan_name, billing_cycle, amount, next_due_date and termination_date. termination_date is when the service is set to end, in UTC with its offset, such as 2026-10-13T12:00:00+00:00, and null when it is not. A cancellation for the end of the term writes it, and taking the cancellation back clears it. ends_at_term_end is true when the end date is such a cancellation, which the customer can take back, and false when there is no end date or our team set it. awaiting_payment and open_invoice_id point at an unpaid invoice for it, and pending_plan_change at an upgrade waiting for payment, or at a switch of billing period waiting for the next renewal. A provisioned service has a resource with its type, uuid, label, status, power and address. is_owner is false for a server another customer shared with this one. GET /portal/services/{service_id} returns one service in the same shape.
GET /portal/services/live?ids=41,42 says what the customer's servers are doing now: items with each service_id, kind and state, a checked_at time, and degraded when a server did not answer. We keep each answer for 10 seconds. Add refresh=true to ask again: requests for the same customer that arrive within a couple of seconds share one check.
For a game server behind a join address, PATCH /portal/services/{service_id}/gameproxy changes what players see in their server list: online_motd and offline_motd (up to 256 characters each), favicon, version_name, display_name, description, and status_cache_ttl_seconds (1–10). clear_favicon, clear_online_motd and clear_offline_motd remove a value.
Change a plan
Section titled Change a plan- List the plans a service can move to with
GET /portal/services/{service_id}/plans. They are sizes of the same product, for the same game and billing cycle, andcurrentmarks the plan it is on. Each has its pricingid,name,price,currency,ram_mb,vcpuanddisk_mb. - Show the cost with
GET /portal/services/{service_id}/plan-preview?org_pricing_id=88. The answer says whether the move is anupgrade, adowngradeorlateralinchange_type, what isdue_today, and for a downgrade whether credit will be issued (credit_will_be_issued,credit_estimate, andcredit_declined_becausewhen it will not). - Make the change with an
Idempotency-Key, so a retry does not ask twice:
curl -X POST "https://api.coritan.com/api/v1/orgs/acme/portal/services/41/change-plan" \
-H "Authorization: Bearer $CUSTOMER_TOKEN" \
-H "Idempotency-Key: 5c0e2a4e-plan-88" \
-H "Content-Type: application/json" \
-d '{"org_pricing_id": 88}'
An upgrade answers requires_payment: true with an invoice_id. The invoice charges the difference for the days left in the cycle, or a full cycle at the new price when no days are left, and the new plan applies once it is paid. Asking for a different upgrade before paying cancels the first invoice. POST /portal/services/{service_id}/cancel-plan-change cancels an unpaid upgrade.
An upgrade can take a coupon code of your store. Add coupon_code to plan-preview (as a query parameter) and to the change-plan body. The quote's coupon is {code, discount} and due_today is what is left to pay, and the upgrade invoice carries a discount line for the code. A code that does not apply answers 422 with errors, the sentence to show, and coupon, the reason (unknown, inactive, not_yet, expired, wrong_product, already_used, exhausted, disabled or nothing_off), as at checkout. The use is counted when the upgrade invoice is paid, so an upgrade left unpaid uses nothing up. A code that takes the whole charge applies the upgrade at once, and change-plan answers requires_payment: false.
A free server may move onto a paid plan of any billing period you sell, such as a weekly one, because it has no paid period to keep. When the period is not the free plan's own, plan-preview answers first_period: true with due_today set to the plan's price for one whole period, and days_remaining set to the period's length. The invoice charges that one period, and the period starts on the day the invoice is paid. Onto the free plan's own period, the upgrade charges the days left in the free month as for any other server, and first_period is false.
A downgrade or a move at the same price applies at once and answers "message": "Plan updated". Coritan sets whether your organization credits the unused days of a downgrade, and every credit keeps back at least one day.
Switch a rank between monthly and annual billing
Section titled Switch a rank between monthly and annual billingA service on a Standalone product, such as a rank, has no sizes. Its product has one plan for each billing period, such as a monthly plan and an annual plan, and the customer can move between them. The switch costs nothing today and waits for the next renewal, because the period already paid for is what the customer bought.
- List the plans with
GET /portal/services/{service_id}/plans. The list holds the product's active plans in the currency the service is billed in, shortest period first, andcurrentmarks the plan the service is on. A plan withapplies_atofnext_renewalis another billing period.scheduledistrueon the plan a switch is waiting for. A plan that is switched off, a one-time price, and a plan in another currency are not listed. - Show what happens with
GET /portal/services/{service_id}/plan-preview?org_pricing_id=2. The answer haschange_typeperiod,due_today0,applies_atnext_renewal,current_amountandnew_amount,current_billing_cycleandbilling_cycle, andeffective_at, the date of the first renewal at the new period.renewal_invoice_openistruewhen the next renewal is already invoiced, and theneffective_atis the renewal after it. - Ask for the switch with
POST /portal/services/{service_id}/change-plan, sending the same body andIdempotency-Keyas for any plan change:
{
"message": "Your plan will change at your next renewal",
"service_id": 41,
"org_pricing_id": 1,
"amount": 5.0,
"invoice_id": null,
"requires_payment": false,
"pending": true,
"scheduled": true,
"applies_at": "next_renewal",
"effective_at": "2026-10-13T12:00:00",
"new_org_pricing_id": 2,
"new_amount": 50.0,
"new_billing_cycle": "annually",
"plan_name": "Annual",
"currency": "USD",
"replayed": false
}
Until then the service keeps its plan, its amount and its due date, and the service's pending_plan_change holds the switch. Asking for the same plan again answers the same thing with replayed: true. Asking for another billing period replaces the first. POST /portal/services/{service_id}/cancel-plan-change calls it off and answers cancelled: true with invoice_id null and applies_at next_renewal.
When we invoice the renewal, the service moves onto the new plan first. The invoice bills the new plan's name and the price the customer was shown, the service's amount, billing_cycle and plan_name change, and paying the invoice moves next_due_date on by the new period. If the plan was switched off or changed currency in the meantime, the switch lapses and the service renews on the plan it is on.
A plan of another billing period is refused for a paid server and for any other product that Coritan runs for you, with Plan changes must keep the current billing cycle. A free server is the exception, as Change a plan describes. It is also refused with 409 while the service is set to end, and while an upgrade is waiting for payment. Cancelling the service clears a switch that is waiting.
Cancel a service
Section titled Cancel a service- Show what the customer gets back with
GET /portal/services/{service_id}/cancel-preview?immediate=true. The answer carrieswill_creditandcredit_amount,declined_becausewhen there is no credit, andfalls_back_to_freewith thefree_plan_namewhen the server moves to your free plan instead of ending. For a server it also lists the server'saddons, so the customer can choose which to keep. - Cancel:
curl -X POST "https://api.coritan.com/api/v1/orgs/acme/portal/services/41/cancel" \
-H "Authorization: Bearer $CUSTOMER_TOKEN" \
-H "Content-Type: application/json" \
-d '{"immediate": false, "reason": "Moving to a bigger plan elsewhere"}'
| Field | Meaning |
|---|---|
immediate |
false (the default) keeps the service until its next due date. true ends it now. |
reason |
Why the customer is leaving. It goes in your audit log. |
keep_snapshot |
Servers only. true (the default) saves a snapshot before the server goes. |
keep_ipv4 |
Cloud Compute only. true keeps the public IPv4 address on the account at its own price. |
delete_server |
true deletes the server even when your organization sells a free plan. It needs immediate: true. |
keep_addon_ids |
Servers only. The org_service_id of each add-on to keep when the server moves to your free plan. The others end with the server. |
We email the customer. An open invoice that bills only this service is cancelled. An open invoice that also bills other services, such as a basket, stays open for them: we take this service's lines off it, keep the coupon's share of what is left and work out the tax again. When nothing is left to pay, we settle it and start the services still on it. A shared invoice that has had a payment is cancelled whole instead. An invoice that a payment gateway took part of stays open, because a cancelled invoice cannot keep that money, and the answer lists it in invoices_left_open.
A server's add-ons are services of their own, so the customer cancels one the same way. Cancelling the server ends its add-ons with it, at once or at the end of the term. When the server moves to your free plan, the add-ons named in keep_addon_ids stay on it with billing of their own, and the rest end.
When your organization sells a free plan, a cancelled container moves to it and keeps its files, at once or at the end of the term. Coritan sets whether an immediate cancellation credits the unused days; an end-of-term cancellation uses every day it paid for. The answer has the status, the termination_date, the credit_issued, snapshot_taken, moved_to_free, and invoices_reduced, which lists each shorter invoice with its new total.
Take a cancellation back
Section titled Take a cancellation backA service cancelled for the end of the term runs until its termination_date. Until that date, the customer can keep it:
curl -X POST "https://api.coritan.com/api/v1/orgs/acme/portal/services/41/keep" \
-H "Authorization: Bearer $CUSTOMER_TOKEN" \
-H "Content-Type: application/json" \
-d '{}'
The answer is the service, as GET /portal/services/41 returns it, with termination_date set to null. A server that would have moved to your free plan on that date stays on its paid plan. Your webhooks receive service.cancellation_withdrawn (Service events).
The cancellation had cancelled any unpaid invoice for the service, and keeping the service does not reopen it. The next renewal is invoiced as usual, on the plan the service is on now, and a plan change the cancellation cleared is not brought back. A customer can keep the same service up to 20 times an hour. A support session can keep a service only where it can cancel one.
The call answers 409 with an error and a message when there is nothing to keep:
error |
When |
|---|---|
not_cancelled |
The service is not set to end. |
already_ended |
The service has ended or is being removed, or its termination_date has passed. |
not_active |
The service is suspended or not running. Contact support. |
scheduled_by_support |
Your team set the end date, as part of an abuse suspension. The customer cannot withdraw it. |
Another customer's service, and another organization's, answers 404.
Show invoices
Section titled Show invoicesGET /portal/invoices lists the customer's invoices, newest first. status_filter takes one of the invoice statuses, or open for unpaid and overdue together. q searches invoice numbers. limit and offset page through the list, and with_total=true wraps it as items, total and counts for each status.
Each invoice has coupon, the code of the coupon it used (or null), and discount, the amount its discount lines take off (0 with none), in the invoice's currency. Each line has product_slug and product_name, the product its service runs, or null for a line with no service. The analytics and ad tags use them as the item ID and name, and the server-side conversions send the same ones.
GET /portal/invoices/{invoice_id} adds the payments taken against the invoice, payment_processing while a slower payment method settles, and for an open invoice retry: when we will next try the saved payment method (next_retry_at), and how many attempts of max_attempts have run. GET /portal/invoices/{invoice_id}/pdf downloads the invoice as a PDF, and GET /portal/invoices/{invoice_id}/delivery shows how far each store item and server on it has got (see Follow the delivery of store items and servers).
Follow the delivery of store items and servers
Section titled Follow the delivery of store items and serversAfter a customer pays for Standalone products, such as the items in a basket, your game servers deliver them and record how each delivery went. A server in the basket is set up by Coritan. Show the customer how far each one has got:
curl "https://api.coritan.com/api/v1/orgs/acme/portal/invoices/5022/delivery" \
-H "Authorization: Bearer $CUSTOMER_TOKEN"
{
"invoice_id": 5022,
"status": "paid",
"items": [
{
"service_id": 7101,
"kind": "item",
"name": "VIP rank",
"plan": null,
"quantity": 1,
"player": {"name": "Steve", "edition": "java"},
"gift_from": null,
"address": null,
"server_uuid": null,
"status": "delivered",
"delivered_at": "2026-10-17T14:03:00Z",
"detail": "Your rank is active on every server."
},
{
"service_id": 7102,
"kind": "server",
"name": "Survival SMP",
"plan": "Standard 4 GB",
"quantity": 1,
"player": null,
"gift_from": null,
"address": "survival-smp.example.gg",
"server_uuid": "6f1c0a52-3c1d-4f0e-9a52-0d7d6c1c6f11",
"status": "setting_up",
"delivered_at": null,
"detail": null
}
]
}
itemslists the invoice's store items and servers in the order of the invoice, one entry for each bought, so three packs are three entries with aquantityof 1. Other charges on the same invoice, and a platform product that is not a server on a container plan, are left out.kindisitemfor a store item andserverfor a server.- A store item's
statusispending_paymentuntil the invoice is paid, thenwaitinguntil a game server records it, thendeliveredorfailed.detailis the game server's note, anddelivered_atsays when it delivered the item. playeris whom a store item was bought for, from the order form'sminecraft_nameandminecraft_edition, ornull.gift_fromis the sender's name the buyer gave for a gift.- A server's
statusispending_paymentuntil the invoice is paid, thensetting_upuntil the server exists and has finished installing, thenready. It isfailed, with a sentence indetail, when we could not set it up or the server has been deleted since.nameis the name the customer gave the server andplanthe plan it runs on. - A server's
addressis where players join. Once the server has an address of its own, it is that one. Until then it is the name the customer chose under your game proxy domain, so the page can show where the server will be, and it isnullwhen there is no domain to build it from.server_uuidis the ID the/portal/servers/{uuid}calls take, and it isnulluntil the server exists. Afailedserver keeps itsserver_uuidwhen it was created, so the customer can still open it.
Poll the call every few seconds until no entry is pending_payment or setting_up.
Your program records each store item's delivery as Record a delivery describes. An invoice that is not this customer's answers 404 with Invoice not found.
Take a payment
Section titled Take a paymentChoose the way that suits your page. Each works on an unpaid or overdue invoice.
- Hosted checkout
POST /portal/invoices/{invoice_id}/checkoutanswers acheckout_urlto send the customer to. It follows the same rules asPOST /storefront/checkout/{invoice_id}; see Pay an invoice. Leave outgateway_nameand we choose a gateway that takes the pay currency:currencywhen you send it, otherwise the customer's currency.POST /portal/invoices/{invoice_id}/payandGET /portal/invoices/{invoice_id}/gatewaysare deprecated and may stop answering after 31 March 2027, so callcheckoutin their place.- A saved payment method
POST /portal/invoices/{invoice_id}/charge?payment_method_id=7charges a saved method, or the default one withoutpayment_method_id. When the bank asks the customer to confirm, the answer isrequires_actionwith aclient_secret; after the customer confirms, callPOST /portal/invoices/{invoice_id}/confirm-payment?gateway_name=...&payment_intent_id=.... Sendcurrency, the code your page showed the customer, to charge in it. Without it we use the method's own currency, then the customer's. Acurrencythat customers cannot pay in answers400withPayment currency SEK is not enabled. When the payment account that holds the card does not take thecurrencyyou send, we answer400withThis card cannot pay in EUR. Choose another card or pay with a new card.and write and charge nothing. A Square card takes US dollars only. A saved bank method pays in one currency: a SEPA Direct Debit method pays in euros, a US bank account in dollars and a Bacs method in pounds. For any other currency we answer400withThis payment method cannot pay in USD. Choose another method.and write and charge nothing. A method whose bank ended the mandate answers400withYour bank ended the permission to charge this account. Choose another payment method., and we stop charging it. A bank debit answerspendingand settles days later.- A card form in your page
GET /portal/payment-configreturns each gateway'spublic_config, such as the publishable key your card form needs.POST /portal/invoices/{invoice_id}/pay-intentreturns aclient_secretfor the form, withsave_method=trueto keep the method for renewals. An invoice that renews a service saves each method that can be saved, and the methods that cannot be saved (Klarna, Przelewy24, TWINT and the like) stay on the form and are paid once. The answer'sstatusisrequires_payment_method,succeededorpending.pendingmeans a payment of this invoice is processing at the bank (SEPA, ACH and Bacs take days): it has noclient_secretand holds amessageto show, and we make no second payment, so the customer cannot pay twice. Once the customer has paid, callconfirm-paymentas above.payment-configlists Stripe accounts unless you sendcard_adapters=stripe,square, which says your page can also draw Square's card form.- Apple Pay and Google Pay buttons
- Ask for the amount with
GET /portal/invoices/{invoice_id}/pay-quotebefore you show the buttons, then send it topay-intentasexpected_amount. See Show Apple Pay and Google Pay buttons. - A Square card form
- We no longer take payments with Square, so a quote never names a Square account and
POST /portal/invoices/{invoice_id}/square-paycharges nothing. Draw the Stripe form. Take a card payment with Square describes the route while it remains. - PayPal buttons
- Save the approved order with
POST /portal/invoices/{invoice_id}/paypal-stash?order_id=...&gateway_name=..., then take the money withPOST /portal/invoices/{invoice_id}/paypal-captureand the same parameters. - Account credit
POST /portal/invoices/{invoice_id}/apply-creditpays what it can from the customer's balance and answersamount_applied,fully_paidandamount_remaining.
GET /portal/invoices/{invoice_id}/checkout-session resumes a checkout the customer left, for example after opening a new tab. It answers open, and for an open checkout the gateway_name, client_secret or paypal_order_id, and when it expires_at.
Show Apple Pay and Google Pay buttons
Section titled Show Apple Pay and Google Pay buttonsApple Pay and Google Pay buttons let a customer pay with a card kept in their phone or browser, through Stripe's Express Checkout Element. The sheet the customer approves already shows the amount, so your page asks us for a quote before it shows the buttons, and creates the payment only once the customer approves. The same quote also tells a page which card form to draw: see Take a card payment with Square.
- Ask for a quote before the customer selects a button, because Stripe gives the button's
clickhandler one second to answer. Ask again whenever the customer changes the amount or the currency.
curl "https://api.coritan.com/api/v1/orgs/acme/portal/invoices/5021/pay-quote?currency=EUR" \
-H "Authorization: Bearer $CUSTOMER_TOKEN"
For credit, ask GET /portal/credit/topup/pay-quote?amount=25. An invoice quote takes currency, country, gateway_name, save_method and card_adapters, and a credit quote takes amount, currency, gateway_name, save_method and card_adapters, each as its pay-intent takes them. card_adapters is a comma list of the card forms your page can draw, stripe and square. It defaults to stripe, so a page with no Square card form always gets a Stripe account, whatever your routing rules prefer. A payment that must keep the card for renewals (an invoice that renews a service, or a quote with save_method true) also gets a Stripe account while Square cannot keep cards. A quote creates nothing and does not contact the card processor. The answer for a Stripe account:
{
"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": "EUR",
"charge_amount": 990,
"base_amount": "11.0000",
"fx_rate": "0.90000000",
"save_method": true,
"business_name": "Acme Hosting Ltd",
"label": "Invoice INV-1042",
"renewal": {
"amount": 990,
"label": "Monthly renewal",
"interval_unit": "month",
"interval_count": 1
}
}
gateway_nameis the account we charge through, andadaptersays which card form to draw,stripeorsquare.publicholds that account's settings that are safe to show in a browser.publishable_keyandpayment_method_configurationare a Stripe account's, and the configuration can benull.charge_amountis what the customer pays, in the smallest unit ofcurrency, such as cents.base_amountis the US dollars it pays, andfx_ratethe rate we converted at.save_methodsays whether we keep the card for renewals. When you leave it out, it istruefor an invoice that renews a service andfalsefor credit.save_typeslists the payment method types the payment keeps for later charges, such ascard,sepa_debitorus_bank_account. It is empty whensave_methodisfalse.local_methodslists the methods made for the customer's country andcurrencythat this account can show, such asidealorblik, and is empty when there are none.business_nameis thecompany_namein your organization settings, or your organization's name when that is empty.labelisInvoiceand the invoice number, orAccount credit.renewalis what the next renewal charges, when we keep the card and every service on the invoice renews on the same billing cycle. Otherwise it isnull, and it is alwaysnullfor credit.
- Load Stripe.js with
publishable_key. Create the elements withmode: "payment",amount: charge_amount,currencyin lower case,paymentMethodConfiguration: payment_method_configuration, and, whensave_methodistrue, apaymentMethodOptionsobject that setssetup_future_usageto"off_session"for each type insave_types. Leave out a top-levelsetupFutureUsage: Stripe then hides every method that cannot be kept for later, such as iDEAL or Klarna. Mount anexpressCheckoutelement withbusiness: {name: business_name}. - In the element's
clickhandler, resolve with one line item:labelforcharge_amount. With Apple Pay and arenewal, also sendapplePay.recurringPaymentRequest:renewal.labelas itspaymentDescriptionandregularBilling.label,renewal.amountasregularBilling.amount,interval_unitandinterval_countasrecurringPaymentIntervalUnitandrecurringPaymentIntervalCount, and your payment methods page asmanagementURL. - In the
confirmhandler, callelements.submit(). Then create the payment with the quote'sgateway_name,currencyandsave_method, thecountryoramountyou asked about, andcharge_amountasexpected_amount:
curl -X POST "https://api.coritan.com/api/v1/orgs/acme/portal/invoices/5021/pay-intent?currency=EUR&gateway_name=stripe&save_method=true&expected_amount=990" \
-H "Authorization: Bearer $CUSTOMER_TOKEN"
For credit, call POST /portal/credit/topup/pay-intent?amount=25 with the same parameters. Pass the answer's client_secret to stripe.confirmPayment, then call confirm-payment as for a card form. Both confirm-payment calls write nothing and refuse a payment this customer did not make for that invoice or to add credit: 400 for another invoice, another organization or the other purpose, 403 for another customer's payment, and 409 for a payment that already settled something else or that does not name its invoice or top-up yet. The payment then settles by itself once the card processor confirms it.
When the amount changed after the quote, for example because the exchange rate moved, pay-intent answers 412 and creates nothing. detail.code is amount_changed, detail.message is a sentence you can show the customer, 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 customer pay again.
Stripe shows a button wherever the browser and device can pay with that wallet, and only on a domain registered with the Stripe account. The element is created with applePay and googlePay set to always, so a customer on a computer sees Apple Pay as a QR code to scan with an iPhone on iOS 18 or later, and Google Pay in browsers where auto would hide it, even before the browser can see a card. Set link, amazonPay and klarna to auto, so each shows where the customer can use it, and paypal to never: PayPal is a payment method of its own on the pay step. If your storefront runs on a domain of its own, ask support to register it for Apple Pay and Google Pay.
Take a card payment with Square
Section titled Take a card payment with SquareWe 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 account beside Stripe. It takes US dollars only. Saved Square cards are off until we switch them on for the Square account, so while they are off a Square payment does not keep the card and never renews by itself (Save a Square card). Square has no intent to create first. Your page tokenizes the card with Square's Web Payments SDK and sends the token, and we charge it and settle the invoice in the same request. We charge through the Square location of your store's brand, or our default location when your brand has none.
- Ask for a quote with
card_adapters=stripe,square. Withoutcard_adapterswe never pick Square.
curl "https://api.coritan.com/api/v1/orgs/acme/portal/invoices/5021/pay-quote?card_adapters=stripe,square" \
-H "Authorization: Bearer $CUSTOMER_TOKEN"
When adapter is stripe, follow Show Apple Pay and Google Pay buttons. When it is square, the answer looks like this:
{
"gateway_name": "square-coritan-americas",
"adapter": "square",
"public": {
"adapter": "square",
"account": "square-coritan-americas",
"application_id": "sq0idp-...",
"location_id": "L8F2...",
"sandbox": false,
"can_save_cards": false,
"google_pay": false,
"apple_pay": false,
"ach": false
},
"currency": "USD",
"charge_amount": 1100,
"base_amount": "11.0000",
"fx_rate": "1",
"save_method": false,
"business_name": "Acme Hosting Ltd",
"label": "Invoice INV-1042",
"renewal": null
}
charge_amount is in cents. It is the dollar amount of the invoice, converted when the invoice is in another currency. A customer who prefers another currency still pays Square in dollars, and a quote asked for another currency names a Stripe account. GET /portal/payment-config?card_adapters=stripe,square lists the same accounts, each with its public_config.
- Load Square's script from
https://web.squarecdn.com/v1/square.js, or fromhttps://sandbox.web.squarecdn.com/v1/square.jswhenpublic.sandboxistrue. Load it when the customer opens the card step, not when the page loads. Create the payments object withpublic.application_idandpublic.location_id, attach a card form, and reserve the form's height so the page does not move. - When the customer pays, call
tokenize()withverificationDetails:intentCHARGE,amountfromcharge_amountin dollars,currencyCodeUSD,billingContact, andcustomerInitiatedtrue. It answers atokenand, for a card that needs it, averificationToken. - Send them to
square-pay, with the quote'scharge_amountasexpected_amount:
curl -X POST "https://api.coritan.com/api/v1/orgs/acme/portal/invoices/5021/square-pay" \
-H "Authorization: Bearer $CUSTOMER_TOKEN" \
-H "Content-Type: application/json" \
-d '{"source_id": "cnon:...", "verification_token": "verf:...", "expected_amount": 1100}'
| Field | Meaning |
|---|---|
source_id |
Required. The token from tokenize(). A token works once. |
expected_amount |
The quote's charge_amount. When the amount due has changed, we answer 412 and charge nothing. |
verification_token |
The verificationToken from tokenize(), when it gave one. |
buyer_email |
Where Square sends its receipt. Leave it out for no Square receipt. |
billing |
The billing contact, as tokenize() was given it. |
gateway_name |
A Square account of ours. Leave it out and we use the account the quote named. |
currency |
USD. Any other value answers 400. |
save_method |
true to keep the card for renewals. We honour it only while saved Square cards are on, and ignore it otherwise. |
amount_usd |
Ignored for an invoice, which is paid in full. |
Every answer has status, attempt_id, gateway_reference, charge_amount and currency, and message when there is something to show. A succeeded answer for an invoice also has invoice_status and base_amount:
{
"status": "succeeded",
"attempt_id": null,
"gateway_reference": "bPhQ...",
"charge_amount": 1100,
"currency": "USD",
"invoice_status": "paid",
"base_amount": "11.0000"
}
status is one of:
succeeded. Square took the payment and we booked it on the invoice.failed. The card was declined and nothing was booked. The answer is still HTTP200. Showmessageand let the customer try another card. The new token starts a new try.pending. Square has not finished, or we could not read its answer. The payment may have gone through, so do not charge again.messagesays so. ReadGET /portal/invoices/{invoice_id}untilstatusispaid. While a payment is pending,GET /portal/invoices/{invoice_id}/checkout-sessionanswerspayment_processingtrue.
Sending the same token twice is one payment. While the first request for an invoice is still running, a second answers 409 with a Retry-After header, and so does a new card while an earlier payment is pending, so two cards sent together never both charge. Square charges whole cents, so a top-up amount is rounded to cents. 429 follows 20 tries in 10 minutes for a customer or 60 for one client address, and a currency other than USD answers 400. A pending answer, including one after Square took the money and our booking failed, is finished by Square's webhook: an organization's payment has no attempt row for a reconcile job to look up, so read the invoice or the balance until it changes. attempt_id is always null for a customer of an organization.
When you sent save_method true and Square took the payment, the answer also holds saved_method: true when we saved the card for this customer, and false with a plain message when we could not. The payment stays succeeded and the invoice stays paid either way. A wallet payment cannot be saved. The answer has no saved_method when you did not ask, or while saved cards are off.
For credit, send the same body to POST /portal/credit/topup/square-pay?amount=25, with the amount you asked the quote about. The answer has the same fields, and the credit is added once Square takes the payment.
Save a payment method with Stripe
Section titled Save a payment method with StripeCall POST /portal/payment-methods/setup with return_url, cancel_url and gateway_name. For a Stripe account the answer holds a client_secret for stripe.confirmSetup. The form offers the methods the account has switched on for saving, such as cards, Link, SEPA Direct Debit and US bank accounts. iDEAL and Bancontact are saved as a SEPA Direct Debit method. When the customer is back, call POST /portal/payment-methods/confirm?gateway_name=<account>&session_id=<session_id>. The answer always has a status.
succeeded. The method is saved, and the answer holds it. A method the customer already saves answers the method it already is.processing. The bank is still confirming the method, as it does for a US bank account after micro-deposits, which can take days. Nothing is saved yet. Showmessage. We save the method when the bank confirms, andGET /portal/payment-methodsthen lists it.requires_action. The customer has a step to finish. The answer holdsmessage, theclient_secretthat finishes it in the page and, when the step is a page of the bank's,next_action_url.
A setup that failed answers 400 with We could not save this payment method. Start again and enter the details again. A cancelled one answers 400 with This setup was canceled. Start again to save a payment method.
Save a Square card
Section titled Save a Square cardSaved Square cards are off until we switch them on for the Square account. While they are off, POST /portal/payment-methods/setup and POST /portal/payment-methods/confirm with a Square gateway_name answer 400 with Saved cards are not switched on for this card account. and create nothing, and no Square account is offered for saving.
When they are on, a customer can save a card with or without a payment.
- With a payment, send
save_methodtruetosquare-pay, as above. - Without one, call
POST /portal/payment-methods/setupwithreturn_url,cancel_urlandgateway_name(orcard_adapters=stripe,squareto let us pick). The answer hassession_idsquare,adaptersquare,requires_redirectfalse, noclient_secretand noredirect_url.public_configholds theapplication_idand thelocation_idof your store's brand for Square's card form. Then calltokenize()withintentSTORE, and send the token toPOST /portal/payment-methods/confirm?gateway_name=<account>&session_id=square&set_as_default=truewith the JSON body{"source_id": "<token>", "verification_token": "...", "cardholder_name": "...", "billing": {...}}. Onlysource_idis required. Apayment_idin the body is ignored: a card is saved from a token, or from a payment taken in the same request, and never from an id the customer names.
The answer is the saved method. A card the customer already saves answers the method it already is. A card of one organization is never charged for another, and a customer sees only their own cards. DELETE /portal/payment-methods/{method_id} also disables the card at Square.
We charge a saved Square card for renewals and for POST /portal/invoices/{invoice_id}/charge without asking the customer to confirm. We charge it in US dollars only, and we never charge it after the month it expires. A decline that a new card fixes, such as an expired card, stops us trying that card until the customer saves another or Square sends its new details. When the customer removes the Square card that was their default, their newest other Square card becomes the default.
Before we ask Square, we mark the invoice as being paid, with the reference_id we send, so Square's confirmation and our own look-up find the payment. When Square does not answer in time, POST /portal/invoices/{invoice_id}/charge answers 200 with status pending and a message that says not to pay again, and POST /portal/credit/topup/charge does the same. The charge is not a decline: we do not charge the invoice again until Square's confirmation arrives or our look-up finds no payment after 30 minutes. A second charge meanwhile answers pending with the same message.
If your page sets a Content Security Policy, allow https://web.squarecdn.com in script-src, frame-src and style-src, https://pci-connect.squareup.com and https://o160250.ingest.sentry.io in connect-src, and https://square-fonts-production-f.squarecdn.com, https://d1g145x70srn7h.cloudfront.net and https://cash-f.squarecdn.com in font-src. For the sandbox, use https://sandbox.web.squarecdn.com and https://pci-connect.squareupsandbox.com in place of the first two hosts.
Handle refund requests
Section titled Handle refund requestsA customer can ask for a paid invoice's money back, and your staff decide in the staff console.
- Call
GET /portal/invoices/{invoice_id}/refund-eligibilitybefore showing the form.eligiblesays whether the customer can ask;blocker_messagessays why not, andreason_codeslists the reasons to offer. - Send the request:
curl -X POST "https://api.coritan.com/api/v1/orgs/acme/portal/invoices/5021/refund-request" \
-H "Authorization: Bearer $CUSTOMER_TOKEN" \
-H "Content-Type: application/json" \
-d '{"reason_code": "downtime", "reason_text": "The server was offline for most of the weekend."}'
reason_code is not_delivered, duplicate_charge, downtime or other. reason_text takes up to 2,000 characters, and other needs at least 10. We email the customer that the request arrived.
An invoice takes one pending request at a time. Payments in cryptocurrency are never refunded, and neither are services ended for breaking the terms of service. A request within 24 hours of paying for a new service, or 48 hours for a renewal, is inside the refund window; a later one still reaches your staff, marked as outside it.
When your staff approve a request, the money goes back to the payment method or onto the customer's balance. A full refund ends every service the invoice paid for at once, each item of a basket included. A refund of part of an invoice ends nothing until the refunds on it add up to all of it. GET /portal/refund-requests lists the customer's requests with their status: pending, approved, rejected, withdrawn or failed. POST /portal/refund-requests/{request_id}/withdraw withdraws one that is still pending.
Coritan can switch the request form off for your organization, so that customers ask for a refund in a billing support ticket and your staff refund the invoice from its page. The eligibility answer's self_serve is then false, and POST /portal/invoices/{invoice_id}/refund-request answers 403 and creates nothing. Send the customer to a new ticket in your Billing department instead. The customer can still list their requests and withdraw a pending one.
Add credit
Section titled Add creditGET /portal/credit returns the customer's balance, which we hold in US dollars, and its history, newest first. credit_currency names the currency of balance and of every history amount. It is always USD, whatever currency the customer pays in, and currency repeats it. Each entry has the amount, the balance_after, a description, its kind, and the invoice_id or org_service_id it belongs to. limit (up to 100) and offset page through the history.
A top-up takes an amount in US dollars from $5 to $10,000, charged in the customer's currency:
POST /portal/credit/topup/checkout?amount=25answers a hosted checkout. Withoutreturn_urlandcancel_url, the customer returns to/billing?paid=1or/billing?cancelled=1on your site.POST /portal/credit/topup/charge?amount=25&payment_method_id=7charges a saved method and answers thenew_balance. Addcurrencyto charge in it. The400for a card whose account does not take it is the one under Take a payment.POST /portal/credit/topup/pay-intent?amount=25returns aclient_secretfor a card form. After the customer pays,POST /portal/credit/topup/confirm-payment?gateway_name=...&payment_intent_id=...adds the credit.GET /portal/credit/topup/pay-quote?amount=25answers the amount and the card account for Apple Pay and Google Pay buttons. See Show Apple Pay and Google Pay buttons.POST /portal/credit/topup/square-pay?amount=25charges a Square card token and adds the credit. See Take a card payment with Square.POST /portal/credit/topup/paypal-capture?order_id=...&gateway_name=...captures an approved PayPal order and adds the credit.
GET /portal/transactions lists every payment, refund, chargeback, credit added and credit spent. type_filter takes payment, refund, chargeback, credit_add or credit_deduct, and with_total=true adds the counts.
Accept cryptocurrency
Section titled Accept cryptocurrencyGET /portal/crypto/assetslists what the customer can send: eachnetworkandasset, themin_deposit_usd, theconfirmationsa deposit waits for, and theapplied_rate_usd.GET /portal/crypto/plan?amount=25lists every way to pay that amount, cheapest first. Addinvoice_idto plan for what an invoice still owes.GET /portal/crypto/quote?network=base&asset=USDC&amount=25&invoice_id=5021says exactly how much to send. Withinvoice_id, the deposit pays that invoice when it arrives; without it, the deposit becomes credit.GET /portal/crypto/address?network=basereturns the customer's deposit address. It stays the same, and one address serves every network of the same family.POST /portal/crypto/checkwith{"network": "base"}looks for the payment now.GET /portal/crypto/depositslists every deposit, with the ones still confirming.GET /portal/crypto/deposits/{deposit_id}returns one deposit, but it is deprecated and may stop answering after 31 March 2027, so find the deposit in the list instead.
Save payment methods
Section titled Save payment methods- Start with
POST /portal/payment-methods/setup?return_url=...&cancel_url=.... The answer has aredirect_urlto send the customer to, or aclient_secretfor a card form, and thesession_id. Addcountry(a two letter code) to set the customer's billing country for this call, andgateway_nameto name the account yourself. - When the customer comes back, call
POST /portal/payment-methods/confirm?gateway_name=...&session_id=.... The method becomes the default unless you sendset_as_default=false.
GET /portal/payment-methods lists the saved methods with their display_label, brand, last4, expiry and is_default. PUT /portal/payment-methods/{method_id}/default makes one the default, and DELETE /portal/payment-methods/{method_id} removes it.
We charge the saved method for open invoices on our own while the customer's auto_pay_enabled is true, which it is unless they turn it off.
Set the currency and country
Section titled Set the currency and countryGET /portal/currencieslists the currencies a customer can pay in, US dollars first, each with itsquote_currency,name,rateagainst the US dollar anddecimal_places. A currency is listed only when it is payable: it has a rate and at least one enabled payment account takes it. Every code in the list works forPATCH /portal/payment-preferenceand for a payment.GET /portal/countrieslists the billing countries by region, with the oneselectedfor this customer and the onedetectedfrom the connection.GET /portal/geo-currencysuggests a currency from the visitor's country, or US dollars when the country's currency is not payable. It needs no token, so your pages can use it before sign-in.GET /portal/payment-preferencereturns the customer'spreferred_payment_currency,credit_currency(alwaysUSD),country_code,billing_country,auto_pay_enabled, asuggested_currency, andcurrency_sourceandcountry_source, which say how each was set:default,geo,useroradmin.PATCHon the same path changes them. Acurrencythat is not payable answers400withCurrency SEK is not enabled, and US dollars are always accepted:
curl -X PATCH "https://api.coritan.com/api/v1/orgs/acme/portal/payment-preference" \
-H "Authorization: Bearer $CUSTOMER_TOKEN" \
-H "Content-Type: application/json" \
-d '{"currency": "EUR", "country_code": "DE", "auto_pay_enabled": true}'
Credit stays in US dollars. The preferred currency decides what we charge the customer in, converted when they pay.
Save billing details
Section titled Save billing detailsA checkout can ask for the customer's billing details and keep them on the account for next time:
curl -X PATCH "https://api.coritan.com/api/v1/orgs/acme/portal/billing-details" \
-H "Authorization: Bearer $CUSTOMER_TOKEN" \
-H "Content-Type: application/json" \
-d '{"first_name": "Alex", "last_name": "Stone", "country_code": "gb", "address": {"line1": "1 High Street", "city": "London", "postal_code": "SW1A 1AA"}}'
The answer is the details as saved, in the shape GET /portal/billing-details returns: email, first_name, last_name, company, country_code and address. address holds line1, line2, city, postal_code and state, or is null until the customer saves one.
- Send only the fields to change. An empty or
nullfirst_name,last_nameorcompanyclears it. They are the same fields the profile holds. - Names take up to 100 characters and
companyup to 255. Inaddress,line1,line2andcitytake up to 200 characters,postal_codeup to 20 andstateup to 100. country_codetakes a two-letter code thatGET /portal/countrieslists, such asGB, in either case. It is the billing countryPATCH /portal/payment-preferencealso sets.addressreplaces the whole address, andnullremoves it.emailis accepted only when it is the account's own address, so a form can send back whatGETanswered. To change the email address, use the profile, as Keep the session going describes.- A support session can read the details but not change them, in any mode:
PATCHanswers403.
Invoice PDFs show the name, the company, the address with the country's name under it, and the email. Without an address, they show the country's code after the email.
Edit the profile or close the account
Section titled Edit the profile or close the accountPATCH /portal/profile changes the profile exactly as PATCH /auth/me does; see Keep the session going.
To close the account, the customer confirms who they are again:
curl -X POST "https://api.coritan.com/api/v1/orgs/acme/portal/account/close" \
-H "Authorization: Bearer $CUSTOMER_TOKEN" \
-H "Content-Type: application/json" \
-d '{"password": "a long passphrase", "reason": "No longer needed"}'
A customer who signs in only with a social provider sends reauth_token instead of password. Get one from GET /auth/oauth/{provider}/authorize?intent=reauth with a provider already connected to the account; the callback returns it as reauth_token. A customer can also confirm with a code we email to the account's address, which works for an account with no password and no linked provider. POST /auth/reauth/code with {} sends it and answers a challenge. POST /auth/reauth/code/verify with the challenge and the code answers a reauth_token, which works for 5 minutes. A wrong, expired or used code answers 400 with detail.error set to wrong_code, expired or used, and wrong_code adds attempts_left. A support session cannot ask for a code.
Closing needs every service cancelled and no invoice unpaid or overdue. It removes the customer's name, email, phone, company, custom fields, social connections and password, ends every session, and cannot be undone. The answer is {"closed": true, "sessions_revoked": 2}.
Show notices
Section titled Show noticesGET /portal/notices returns the notices your staff published for this customer: those for everyone, and those for paying or free customers depending on whether this customer pays. Visitors who are not signed in get theirs from GET /storefront/notices.
Result
Section titled ResultCustomers can follow their services, pay and download invoices, keep a balance, save cards and leave, all from your own pages. Your staff see the same records in the staff console.
Troubleshooting
Section titled Troubleshooting401on every call- The customer token is missing, expired or belongs to another organization. See Troubleshooting for customer sign-in.
Invoice not found or already paid- The invoice is paid, cancelled or not this customer's. Read it again with
GET /portal/invoices/{invoice_id}. 404 Invoice not foundfrom/delivery- The invoice is not this customer's. List the customer's own with
GET /portal/invoices. Change your email address from your profile.PATCH /portal/billing-detailsreceived anemailother than the account's own. Leaveemailout, or change the address withPATCH /portal/profile.Use the two-letter code of a country, such as GB.country_codeis not a country we know. Send a code thatGET /portal/countrieslists.No payment gateway available,No Stripe gateway availableorNo card gateway available- No gateway takes that currency for the customer's country. Try again with
currencyset toUSD. This way of paying takes US dollars only. Pay in USD or choose another way to pay.square-paywas given acurrencyother thanUSD. SendUSD, or draw the Stripe form for that currency.Use square-pay to pay by Squarepay-intentwas given a Square account. Send the token tosquare-payinstead.That account is not a Square accountgateway_nameonsquare-paynames a Stripe account or an account that is not ours. Leavegateway_nameout.409fromsquare-pay- Another payment for the invoice is still running or pending. Wait for the
Retry-Afterseconds, read the invoice, and pay again only if it is still unpaid. pendingfromsquare-pay- Square has not said whether it took the payment. Do not charge again. Read
GET /portal/invoices/{invoice_id}until it ispaid. Payment currency TRY is not enabled- We do not take payments in that currency. Offer one that
GET /portal/currencieslists. 412withamount_changed- The amount changed after the quote, and we created nothing. Show the customer the amount in
detail.quoteand let them pay again with itscharge_amountasexpected_amount. 402with the gateway's message- The bank declined the payment. Ask the customer to try another method.
Plan changes must keep the current billing cycle- The chosen plan bills on another cycle, and the service is not a free server. Offer only the plans
GET /portal/services/{service_id}/plansreturns. Plan change already in progress- A request with the same
Idempotency-Keyis still running. Wait for it rather than sending again. This service is set to end. Keep it first, then change its billing period.- A switch of billing period needs a service that is not ending. Take the cancellation back with
POST /portal/services/{service_id}/keep, then ask again. 409withnot_cancelledfrom/keep- The service is not set to end, or the customer already kept it. Read it again with
GET /portal/services/{service_id}:termination_dateisnull. Service already cancelled- The service is ending or has ended.
The minimum top-up is $5.00- Send an
amountfrom 5 to 10,000. Pick one of the reasons listedorTell us briefly what happened- Send a
reason_codefromreason_codes. Withother, write at least 10 characters inreason_text. 409when closing an account- The
X-Close-Refused-Reasonheader says why:active_services,unpaid_invoicesoralready_closed. Cancel the services or settle the invoices first. 409from a crypto call- Deposits on that network are not available right now. Offer another network from
GET /portal/crypto/assets.
Related
Section titled RelatedAPI operations on this page
| Method | Path | What it does |
|---|---|---|
POST | /api/v1/orgs/{org_slug}/portal/account/close | Close and anonymise the signed-in customer's own account |
GET | /api/v1/orgs/{org_slug}/portal/billing-details | The customer's billing details: name, company, country and address |
PATCH | /api/v1/orgs/{org_slug}/portal/billing-details | Change the customer's billing details |
GET | /api/v1/orgs/{org_slug}/portal/countries | Countries a customer can bill from, and the one we think they are in |
GET | /api/v1/orgs/{org_slug}/portal/credit | The customer's credit balance and credit history, newest first |
POST | /api/v1/orgs/{org_slug}/portal/credit/topup/charge | Charge a saved payment method and add credit to the customer's balance |
POST | /api/v1/orgs/{org_slug}/portal/credit/topup/checkout | Hosted checkout to buy USD credit for an org customer |
POST | /api/v1/orgs/{org_slug}/portal/credit/topup/confirm-payment | Add credit for a card payment the customer finished in the page |
POST | /api/v1/orgs/{org_slug}/portal/credit/topup/pay-intent | Create a Stripe PaymentIntent to add credit in the page |
GET | /api/v1/orgs/{org_slug}/portal/credit/topup/pay-quote | The card account and amount for adding credit in the page |
POST | /api/v1/orgs/{org_slug}/portal/credit/topup/paypal-capture | Capture PayPal order and credit org customer balance |
POST | /api/v1/orgs/{org_slug}/portal/credit/topup/square-pay | Add credit with a Square card token, in one request |
GET | /api/v1/orgs/{org_slug}/portal/crypto/address | This customer's permanent deposit address for the network's family |
GET | /api/v1/orgs/{org_slug}/portal/crypto/assets | Assets this storefront can accept right now |
POST | /api/v1/orgs/{org_slug}/portal/crypto/check | Look for this customer's payment now, and say where it stands |
GET | /api/v1/orgs/{org_slug}/portal/crypto/deposits | Deposit history, including transfers still confirming |
GET | /api/v1/orgs/{org_slug}/portal/crypto/deposits/{deposit_id} | One deposit, for polling while it confirms |
GET | /api/v1/orgs/{org_slug}/portal/crypto/plan | Every way to pay this amount in crypto, cheapest first |
GET | /api/v1/orgs/{org_slug}/portal/crypto/quote | How much to send for a target USD credit, itemised |
GET | /api/v1/orgs/{org_slug}/portal/currencies | The currencies this customer can pay in, with the exchange rate of each |
GET | /api/v1/orgs/{org_slug}/portal/geo-currency | The country we place this request in, and the currency we suggest for it |
GET | /api/v1/orgs/{org_slug}/portal/invoices | Newest first, ties by id |
GET | /api/v1/orgs/{org_slug}/portal/invoices/{invoice_id} | One of the customer's invoices, with what was paid against it |
POST | /api/v1/orgs/{org_slug}/portal/invoices/{invoice_id}/apply-credit | Apply the customer's credit balance toward an unpaid invoice |
POST | /api/v1/orgs/{org_slug}/portal/invoices/{invoice_id}/charge | Pay an invoice with a saved payment method |
POST | /api/v1/orgs/{org_slug}/portal/invoices/{invoice_id}/checkout | Canonical hosted checkout for an org-customer invoice (alias of /pay) |
GET | /api/v1/orgs/{org_slug}/portal/invoices/{invoice_id}/checkout-session | Resume an in-flight checkout after a new tab, login, or API restart |
POST | /api/v1/orgs/{org_slug}/portal/invoices/{invoice_id}/confirm-payment | Record a card payment the customer finished in the page, and answer how it settled |
GET | /api/v1/orgs/{org_slug}/portal/invoices/{invoice_id}/delivery | How far each store item and server on an invoice has got |
GET | /api/v1/orgs/{org_slug}/portal/invoices/{invoice_id}/gateways | Gateway accounts that can checkout this invoice's pay currency |
POST | /api/v1/orgs/{org_slug}/portal/invoices/{invoice_id}/pay | Hosted checkout for an invoice (legacy path; prefer /checkout) |
POST | /api/v1/orgs/{org_slug}/portal/invoices/{invoice_id}/pay-intent | Create a Stripe PaymentIntent to pay an invoice in the page |
GET | /api/v1/orgs/{org_slug}/portal/invoices/{invoice_id}/pay-quote | The card account and amount for paying an invoice in the page |
POST | /api/v1/orgs/{org_slug}/portal/invoices/{invoice_id}/paypal-capture | Capture paypal order |
POST | /api/v1/orgs/{org_slug}/portal/invoices/{invoice_id}/paypal-stash | Persist a PayPal order id so a redirect or reboot can still capture it |
GET | /api/v1/orgs/{org_slug}/portal/invoices/{invoice_id}/pdf | The invoice as a document to keep |
GET | /api/v1/orgs/{org_slug}/portal/invoices/{invoice_id}/refund-eligibility | My invoice refund eligibility |
POST | /api/v1/orgs/{org_slug}/portal/invoices/{invoice_id}/refund-request | Ask for the money paid on one of your invoices back |
POST | /api/v1/orgs/{org_slug}/portal/invoices/{invoice_id}/square-pay | Pay an invoice with a Square card token, in one request |
GET | /api/v1/orgs/{org_slug}/portal/notices | Live notices for the signed-in customer, by whether they pay |
GET | /api/v1/orgs/{org_slug}/portal/payment-config | Get portal payment config |
GET | /api/v1/orgs/{org_slug}/portal/payment-methods | List customer's saved payment methods |
POST | /api/v1/orgs/{org_slug}/portal/payment-methods/confirm | Confirm payment method setup after customer approves on gateway side |
POST | /api/v1/orgs/{org_slug}/portal/payment-methods/setup | Initiate payment method tokenization on a regional gateway account |
DELETE | /api/v1/orgs/{org_slug}/portal/payment-methods/{method_id} | Remove (deactivate) a saved payment method |
PUT | /api/v1/orgs/{org_slug}/portal/payment-methods/{method_id}/default | Set a payment method as the default for this customer |
GET | /api/v1/orgs/{org_slug}/portal/payment-preference | The customer's pay currency and billing country, and how each was set |
PATCH | /api/v1/orgs/{org_slug}/portal/payment-preference | Save the customer's pay currency, billing country or auto-pay setting |
PATCH | /api/v1/orgs/{org_slug}/portal/profile | Alias for PATCH /auth/me (account page compatibility) |
GET | /api/v1/orgs/{org_slug}/portal/refund-requests | List my refund requests |
POST | /api/v1/orgs/{org_slug}/portal/refund-requests/{request_id}/withdraw | Withdraw one of your refund requests while it is still pending |
GET | /api/v1/orgs/{org_slug}/portal/services | List my services |
GET | /api/v1/orgs/{org_slug}/portal/services/live | What the customer's servers are doing right now, in one request |
GET | /api/v1/orgs/{org_slug}/portal/services/{service_id} | Get my service |
POST | /api/v1/orgs/{org_slug}/portal/services/{service_id}/cancel | Cancel one of the customer's own services, now or at the end of term |
POST | /api/v1/orgs/{org_slug}/portal/services/{service_id}/cancel-plan-change | Cancel my pending plan change |
GET | /api/v1/orgs/{org_slug}/portal/services/{service_id}/cancel-preview | What cancelling right now would return, before committing to it |
POST | /api/v1/orgs/{org_slug}/portal/services/{service_id}/change-plan | Move one of the customer's services to another plan |
GET | /api/v1/orgs/{org_slug}/portal/services/{service_id}/community-listing | Get community listing |
PUT | /api/v1/orgs/{org_slug}/portal/services/{service_id}/community-listing | Upsert community listing |
PATCH | /api/v1/orgs/{org_slug}/portal/services/{service_id}/gameproxy | Update join-address branding (MOTD/favicon) for a service's sidecar gameproxy route |
POST | /api/v1/orgs/{org_slug}/portal/services/{service_id}/keep | Withdraw a cancellation that is set for the end of the term, so the service keeps renewing |
GET | /api/v1/orgs/{org_slug}/portal/services/{service_id}/plan-preview | What a plan change costs today, before committing to it |
GET | /api/v1/orgs/{org_slug}/portal/services/{service_id}/plans | Sizes this service can move to |
GET | /api/v1/orgs/{org_slug}/portal/transactions | List my transactions |