# Build the customer account area

> Let signed-in customers see their services, pay invoices, add credit, save payment methods and edit their profile.

Source: https://www.coritan.com/docs/organizations/storefront/customer-portal/

The account area is the part of your storefront a customer sees once signed in: their services, invoices, credit, saved payment methods 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

- Get a customer token as [Sign customers in to your storefront](/docs/organizations/storefront/customer-sign-in/) 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](/docs/organizations/billing/paynow/).

## Show the customer's services

```bash
curl "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](/docs/organizations/customer-services/#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` and `next_due_date`. `awaiting_payment` and `open_invoice_id` point at an unpaid invoice for it, and `pending_plan_change` at an upgrade waiting for payment. 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.

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

1. 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, and `current` marks the plan it is on. Each has its pricing `id`, `name`, `price`, `currency`, `ram_mb`, `vcpu` and `disk_mb`.
2. Show the cost with `GET /portal/services/{service_id}/plan-preview?org_pricing_id=88`. The answer says whether the move is an `upgrade`, a `downgrade` or `lateral` in `change_type`, what is `due_today`, and for a downgrade whether credit will be issued (`credit_will_be_issued`, `credit_estimate`, and `credit_declined_because` when it will not).
3. Make the change with an `Idempotency-Key`, so a retry does not ask twice:

```bash
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.

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.

## Cancel a service

1. Show what the customer gets back with `GET /portal/services/{service_id}/cancel-preview?immediate=true`. The answer carries `will_credit` and `credit_amount`, `declined_because` when there is no credit, and `falls_back_to_free` with the `free_plan_name` when the server moves to your free plan instead of ending.
2. Cancel:

```bash
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` | Container Apps 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`. |

We cancel the service's open invoices and email the customer. 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` and `moved_to_free`.

## Show invoices

`GET /portal/invoices` lists the customer's invoices, newest first. `status_filter` takes one of the [invoice statuses](/docs/organizations/billing/invoices/#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.

`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.

## Take a payment

Choose the way that suits your page. Each works on an `unpaid` or `overdue` invoice.

Hosted checkout
: `POST /portal/invoices/{invoice_id}/checkout` answers a `checkout_url` to send the customer to. It follows the same rules as `POST /storefront/checkout/{invoice_id}`; see [Pay an invoice](/docs/organizations/storefront/storefront-api/#pay-an-invoice). `POST /portal/invoices/{invoice_id}/pay` does the same. `GET /portal/invoices/{invoice_id}/gateways?currency=EUR` lists the gateways that can take the payment.

A saved payment method
: `POST /portal/invoices/{invoice_id}/charge?payment_method_id=7` charges a saved method, or the default one without `payment_method_id`. When the bank asks the customer to confirm, the answer is `requires_action` with a `client_secret`; after the customer confirms, call `POST /portal/invoices/{invoice_id}/confirm-payment?gateway_name=...&payment_intent_id=...`.

A card form in your page
: `GET /portal/payment-config` returns each gateway's `public_config`, such as the publishable key your card form needs. `POST /portal/invoices/{invoice_id}/pay-intent` returns a `client_secret` for the form, with `save_method=true` to keep the card for renewals. Once the customer has paid, call `confirm-payment` as above.

PayPal buttons
: Save the approved order with `POST /portal/invoices/{invoice_id}/paypal-stash?order_id=...&gateway_name=...`, then take the money with `POST /portal/invoices/{invoice_id}/paypal-capture` and the same parameters.

Account credit
: `POST /portal/invoices/{invoice_id}/apply-credit` pays what it can from the customer's balance and answers `amount_applied`, `fully_paid` and `amount_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`.

## Handle refund requests

A customer can ask for a paid invoice's money back, and your staff decide in the [staff console](/docs/organizations/staff-console/billing/).

1. Call `GET /portal/invoices/{invoice_id}/refund-eligibility` before showing the form. `eligible` says whether the customer can ask; `blocker_messages` says why not, and `reason_codes` lists the reasons to offer.
2. Send the request:

```bash
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, and a full refund ends the service at once. `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.

## Add credit

`GET /portal/credit` returns the customer's `balance`, which we hold in US dollars, and its `history`, newest first. 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=25` answers a hosted checkout. Without `return_url` and `cancel_url`, the customer returns to `/billing?paid=1` or `/billing?cancelled=1` on your site.
- `POST /portal/credit/topup/charge?amount=25&payment_method_id=7` charges a saved method and answers the `new_balance`.
- `POST /portal/credit/topup/pay-intent?amount=25` returns a `client_secret` for a card form. After the customer pays, `POST /portal/credit/topup/confirm-payment?gateway_name=...&payment_intent_id=...` adds the credit.
- `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

1. `GET /portal/crypto/assets` lists what the customer can send: each `network` and `asset`, the `min_deposit_usd`, the `confirmations` a deposit waits for, and the `applied_rate_usd`.
2. `GET /portal/crypto/plan?amount=25` lists every way to pay that amount, cheapest first. Add `invoice_id` to plan for what an invoice still owes.
3. `GET /portal/crypto/quote?network=base&asset=USDC&amount=25&invoice_id=5021` says exactly how much to send. With `invoice_id`, the deposit pays that invoice when it arrives; without it, the deposit becomes credit.
4. `GET /portal/crypto/address?network=base` returns the customer's deposit address. It stays the same, and one address serves every network of the same family.
5. `POST /portal/crypto/check` with `{"network": "base"}` looks for the payment now. `GET /portal/crypto/deposits` lists deposits, including those still confirming, and `GET /portal/crypto/deposits/{deposit_id}` returns one.

## Save payment methods

1. Start with `POST /portal/payment-methods/setup?return_url=...&cancel_url=...`. The answer has a `redirect_url` to send the customer to, or a `client_secret` for a card form, and the `session_id`.
2. When the customer comes back, call `POST /portal/payment-methods/confirm?gateway_name=...&session_id=...`. The method becomes the default unless you send `set_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

- `GET /portal/currencies` lists the currencies a customer can pay in, each with its `quote_currency`, `name` and `rate` against the US dollar.
- `GET /portal/countries` lists the billing countries by region, with the one `selected` for this customer and the one `detected` from the connection.
- `GET /portal/geo-currency` suggests a currency from the visitor's country. It needs no token, so your pages can use it before sign-in.
- `GET /portal/payment-preference` returns the customer's `preferred_payment_currency`, `country_code`, `auto_pay_enabled` and a `suggested_currency`. `PATCH` on the same path changes them:

```bash
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.

## Edit the profile or close the account

`PATCH /portal/profile` changes the profile exactly as `PATCH /auth/me` does; see [Keep the session going](/docs/organizations/storefront/customer-sign-in/#keep-the-session-going).

To close the account, the customer confirms who they are again:

```bash
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`.

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

`GET /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

Customers 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](/docs/organizations/staff-console/).

## Troubleshooting

`401` on every call
: The customer token is missing, expired or belongs to another organization. See [Troubleshooting](/docs/organizations/storefront/customer-sign-in/#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}`.

`No payment gateway available` or `No Stripe gateway available`
: No gateway takes that currency for the customer's country. Try `USD`, or list what works with `GET /portal/invoices/{invoice_id}/gateways`.

`402` with 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. Offer only the plans `GET /portal/services/{service_id}/plans` returns.

`Plan change already in progress`
: A request with the same `Idempotency-Key` is still running. Wait for it rather than sending again.

`Service already cancelled`
: The service is ending or has ended.

`The minimum top-up is $5.00`
: Send an `amount` from 5 to 10,000.

`Pick one of the reasons listed` or `Tell us briefly what happened`
: Send a `reason_code` from `reason_codes`. With `other`, write at least 10 characters in `reason_text`.

`409` when closing an account
: The `X-Close-Refused-Reason` header says why: `active_services`, `unpaid_invoices` or `already_closed`. Cancel the services or settle the invoices first.

`409` from a crypto call
: Deposits on that network are not available right now. Offer another network from `GET /portal/crypto/assets`.

## Related

- [Build a storefront on the Organization API](/docs/organizations/storefront/)
- [Sign customers in to your storefront](/docs/organizations/storefront/customer-sign-in/)
- [Show your catalogue with the Storefront API](/docs/organizations/storefront/storefront-api/)
- [Organization billing](/docs/organizations/billing/)

## API

- `POST /api/v1/orgs/{org_slug}/portal/account/close`: Close and anonymise the signed-in customer's own account (https://www.coritan.com/docs/api/reference/organizations/customer-portal/account/#op-post-api-v1-orgs-org-slug-portal-account-close)
- `GET /api/v1/orgs/{org_slug}/portal/countries`: Countries a customer can bill from, and the one we think they are in (https://www.coritan.com/docs/api/reference/organizations/customer-portal/countries/#op-get-api-v1-orgs-org-slug-portal-countries)
- `GET /api/v1/orgs/{org_slug}/portal/credit`: Get my credit balance (https://www.coritan.com/docs/api/reference/organizations/customer-portal/credit/#op-get-api-v1-orgs-org-slug-portal-credit)
- `POST /api/v1/orgs/{org_slug}/portal/credit/topup/charge`: Charge a saved payment method and credit the org customer balance (USD) (https://www.coritan.com/docs/api/reference/organizations/customer-portal/credit/#op-post-api-v1-orgs-org-slug-portal-credit-topup-charge)
- `POST /api/v1/orgs/{org_slug}/portal/credit/topup/checkout`: Hosted checkout to buy USD credit for an org customer (https://www.coritan.com/docs/api/reference/organizations/customer-portal/credit/#op-post-api-v1-orgs-org-slug-portal-credit-topup-checkout)
- `POST /api/v1/orgs/{org_slug}/portal/credit/topup/confirm-payment`: Finalize a credit top-up PaymentIntent after SCA and credit the balance (https://www.coritan.com/docs/api/reference/organizations/customer-portal/credit/#op-post-api-v1-orgs-org-slug-portal-credit-topup-confirm-payment)
- `POST /api/v1/orgs/{org_slug}/portal/credit/topup/pay-intent`: Create an in-page Stripe Payment Element intent for a credit top-up (https://www.coritan.com/docs/api/reference/organizations/customer-portal/credit/#op-post-api-v1-orgs-org-slug-portal-credit-topup-pay-intent)
- `POST /api/v1/orgs/{org_slug}/portal/credit/topup/paypal-capture`: Capture PayPal order and credit org customer balance (https://www.coritan.com/docs/api/reference/organizations/customer-portal/credit/#op-post-api-v1-orgs-org-slug-portal-credit-topup-paypal-capture)
- `GET /api/v1/orgs/{org_slug}/portal/crypto/address`: This customer's permanent deposit address for the network's family (https://www.coritan.com/docs/api/reference/organizations/customer-portal/crypto/#op-get-api-v1-orgs-org-slug-portal-crypto-address)
- `GET /api/v1/orgs/{org_slug}/portal/crypto/assets`: Assets this storefront can accept right now (https://www.coritan.com/docs/api/reference/organizations/customer-portal/crypto/#op-get-api-v1-orgs-org-slug-portal-crypto-assets)
- `POST /api/v1/orgs/{org_slug}/portal/crypto/check`: Look for this customer's payment now, and say where it stands (https://www.coritan.com/docs/api/reference/organizations/customer-portal/crypto/#op-post-api-v1-orgs-org-slug-portal-crypto-check)
- `GET /api/v1/orgs/{org_slug}/portal/crypto/deposits`: Deposit history, including transfers still confirming (https://www.coritan.com/docs/api/reference/organizations/customer-portal/crypto/#op-get-api-v1-orgs-org-slug-portal-crypto-deposits)
- `GET /api/v1/orgs/{org_slug}/portal/crypto/deposits/{deposit_id}`: One deposit, for polling while it confirms (https://www.coritan.com/docs/api/reference/organizations/customer-portal/crypto/#op-get-api-v1-orgs-org-slug-portal-crypto-deposits-deposit-id)
- `GET /api/v1/orgs/{org_slug}/portal/crypto/plan`: Every way to pay this amount in crypto, cheapest first (https://www.coritan.com/docs/api/reference/organizations/customer-portal/crypto/#op-get-api-v1-orgs-org-slug-portal-crypto-plan)
- `GET /api/v1/orgs/{org_slug}/portal/crypto/quote`: How much to send for a target USD credit, itemised (https://www.coritan.com/docs/api/reference/organizations/customer-portal/crypto/#op-get-api-v1-orgs-org-slug-portal-crypto-quote)
- `GET /api/v1/orgs/{org_slug}/portal/currencies`: List portal currencies (https://www.coritan.com/docs/api/reference/organizations/customer-portal/currencies/#op-get-api-v1-orgs-org-slug-portal-currencies)
- `GET /api/v1/orgs/{org_slug}/portal/geo-currency`: Unauthenticated country → suggested pay currency for storefront preselect (https://www.coritan.com/docs/api/reference/organizations/customer-portal/geo-currency/#op-get-api-v1-orgs-org-slug-portal-geo-currency)
- `GET /api/v1/orgs/{org_slug}/portal/invoices`: Newest first, ties by id (https://www.coritan.com/docs/api/reference/organizations/customer-portal/invoices/#op-get-api-v1-orgs-org-slug-portal-invoices)
- `GET /api/v1/orgs/{org_slug}/portal/invoices/{invoice_id}`: Get my invoice (https://www.coritan.com/docs/api/reference/organizations/customer-portal/invoices/#op-get-api-v1-orgs-org-slug-portal-invoices-invoice-id)
- `POST /api/v1/orgs/{org_slug}/portal/invoices/{invoice_id}/apply-credit`: Apply the customer's credit balance toward an unpaid invoice (https://www.coritan.com/docs/api/reference/organizations/customer-portal/invoices/#op-post-api-v1-orgs-org-slug-portal-invoices-invoice-id-apply-credit)
- `POST /api/v1/orgs/{org_slug}/portal/invoices/{invoice_id}/charge`: Pay an invoice using a saved payment method (merchant-initiated charge) (https://www.coritan.com/docs/api/reference/organizations/customer-portal/invoices/#op-post-api-v1-orgs-org-slug-portal-invoices-invoice-id-charge)
- `POST /api/v1/orgs/{org_slug}/portal/invoices/{invoice_id}/checkout`: Canonical hosted checkout for an org-customer invoice (alias of /pay) (https://www.coritan.com/docs/api/reference/organizations/customer-portal/invoices/#op-post-api-v1-orgs-org-slug-portal-invoices-invoice-id-checkout)
- `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 (https://www.coritan.com/docs/api/reference/organizations/customer-portal/invoices/#op-get-api-v1-orgs-org-slug-portal-invoices-invoice-id-checkout-session)
- `POST /api/v1/orgs/{org_slug}/portal/invoices/{invoice_id}/confirm-payment`: Finalize a charge after customer completes SCA (3-D Secure) (https://www.coritan.com/docs/api/reference/organizations/customer-portal/invoices/#op-post-api-v1-orgs-org-slug-portal-invoices-invoice-id-confirm-payment)
- `GET /api/v1/orgs/{org_slug}/portal/invoices/{invoice_id}/gateways`: Gateway accounts that can checkout this invoice's pay currency (https://www.coritan.com/docs/api/reference/organizations/customer-portal/invoices/#op-get-api-v1-orgs-org-slug-portal-invoices-invoice-id-gateways)
- `POST /api/v1/orgs/{org_slug}/portal/invoices/{invoice_id}/pay`: Hosted checkout for an invoice (legacy path; prefer /checkout) (https://www.coritan.com/docs/api/reference/organizations/customer-portal/invoices/#op-post-api-v1-orgs-org-slug-portal-invoices-invoice-id-pay)
- `POST /api/v1/orgs/{org_slug}/portal/invoices/{invoice_id}/pay-intent`: Create an in-page Stripe Payment Element intent for an org invoice (https://www.coritan.com/docs/api/reference/organizations/customer-portal/invoices/#op-post-api-v1-orgs-org-slug-portal-invoices-invoice-id-pay-intent)
- `POST /api/v1/orgs/{org_slug}/portal/invoices/{invoice_id}/paypal-capture`: Capture paypal order (https://www.coritan.com/docs/api/reference/organizations/customer-portal/invoices/#op-post-api-v1-orgs-org-slug-portal-invoices-invoice-id-paypal-capture)
- `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 (https://www.coritan.com/docs/api/reference/organizations/customer-portal/invoices/#op-post-api-v1-orgs-org-slug-portal-invoices-invoice-id-paypal-stash)
- `GET /api/v1/orgs/{org_slug}/portal/invoices/{invoice_id}/pdf`: The invoice as a document to keep (https://www.coritan.com/docs/api/reference/organizations/customer-portal/invoices/#op-get-api-v1-orgs-org-slug-portal-invoices-invoice-id-pdf)
- `GET /api/v1/orgs/{org_slug}/portal/invoices/{invoice_id}/refund-eligibility`: My invoice refund eligibility (https://www.coritan.com/docs/api/reference/organizations/customer-portal/invoices/#op-get-api-v1-orgs-org-slug-portal-invoices-invoice-id-refund-eligibility)
- `POST /api/v1/orgs/{org_slug}/portal/invoices/{invoice_id}/refund-request`: Request my invoice refund (https://www.coritan.com/docs/api/reference/organizations/customer-portal/invoices/#op-post-api-v1-orgs-org-slug-portal-invoices-invoice-id-refund-request)
- `GET /api/v1/orgs/{org_slug}/portal/notices`: Live notices for the signed-in customer, by whether they pay (https://www.coritan.com/docs/api/reference/organizations/customer-portal/notices/#op-get-api-v1-orgs-org-slug-portal-notices)
- `GET /api/v1/orgs/{org_slug}/portal/payment-config`: Get portal payment config (https://www.coritan.com/docs/api/reference/organizations/customer-portal/payment-config/#op-get-api-v1-orgs-org-slug-portal-payment-config)
- `GET /api/v1/orgs/{org_slug}/portal/payment-methods`: List customer's saved payment methods (https://www.coritan.com/docs/api/reference/organizations/customer-portal/payment-methods/#op-get-api-v1-orgs-org-slug-portal-payment-methods)
- `POST /api/v1/orgs/{org_slug}/portal/payment-methods/confirm`: Confirm payment method setup after customer approves on gateway side (https://www.coritan.com/docs/api/reference/organizations/customer-portal/payment-methods/#op-post-api-v1-orgs-org-slug-portal-payment-methods-confirm)
- `POST /api/v1/orgs/{org_slug}/portal/payment-methods/setup`: Initiate payment method tokenization on a regional gateway account (https://www.coritan.com/docs/api/reference/organizations/customer-portal/payment-methods/#op-post-api-v1-orgs-org-slug-portal-payment-methods-setup)
- `DELETE /api/v1/orgs/{org_slug}/portal/payment-methods/{method_id}`: Remove (deactivate) a saved payment method (https://www.coritan.com/docs/api/reference/organizations/customer-portal/payment-methods/#op-delete-api-v1-orgs-org-slug-portal-payment-methods-method-id)
- `PUT /api/v1/orgs/{org_slug}/portal/payment-methods/{method_id}/default`: Set a payment method as the default for this customer (https://www.coritan.com/docs/api/reference/organizations/customer-portal/payment-methods/#op-put-api-v1-orgs-org-slug-portal-payment-methods-method-id-default)
- `GET /api/v1/orgs/{org_slug}/portal/payment-preference`: Get portal payment preference (https://www.coritan.com/docs/api/reference/organizations/customer-portal/payment-preference/#op-get-api-v1-orgs-org-slug-portal-payment-preference)
- `PATCH /api/v1/orgs/{org_slug}/portal/payment-preference`: Update account-wide preferred payment currency (https://www.coritan.com/docs/api/reference/organizations/customer-portal/payment-preference/#op-patch-api-v1-orgs-org-slug-portal-payment-preference)
- `PATCH /api/v1/orgs/{org_slug}/portal/profile`: Alias for PATCH /auth/me (account page compatibility) (https://www.coritan.com/docs/api/reference/organizations/customer-portal/profile/#op-patch-api-v1-orgs-org-slug-portal-profile)
- `GET /api/v1/orgs/{org_slug}/portal/refund-requests`: List my refund requests (https://www.coritan.com/docs/api/reference/organizations/customer-portal/refund-requests/#op-get-api-v1-orgs-org-slug-portal-refund-requests)
- `POST /api/v1/orgs/{org_slug}/portal/refund-requests/{request_id}/withdraw`: Withdraw my refund request (https://www.coritan.com/docs/api/reference/organizations/customer-portal/refund-requests/#op-post-api-v1-orgs-org-slug-portal-refund-requests-request-id-withdraw)
- `GET /api/v1/orgs/{org_slug}/portal/services`: List my services (https://www.coritan.com/docs/api/reference/organizations/customer-portal/services/#op-get-api-v1-orgs-org-slug-portal-services)
- `GET /api/v1/orgs/{org_slug}/portal/services/live`: What the customer's servers are doing right now, in one request (https://www.coritan.com/docs/api/reference/organizations/customer-portal/services/#op-get-api-v1-orgs-org-slug-portal-services-live)
- `GET /api/v1/orgs/{org_slug}/portal/services/{service_id}`: Get my service (https://www.coritan.com/docs/api/reference/organizations/customer-portal/services/#op-get-api-v1-orgs-org-slug-portal-services-service-id)
- `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 (https://www.coritan.com/docs/api/reference/organizations/customer-portal/services/#op-post-api-v1-orgs-org-slug-portal-services-service-id-cancel)
- `POST /api/v1/orgs/{org_slug}/portal/services/{service_id}/cancel-plan-change`: Cancel an unpaid upgrade so a different plan can be chosen (https://www.coritan.com/docs/api/reference/organizations/customer-portal/services/#op-post-api-v1-orgs-org-slug-portal-services-service-id-cancel-plan-change)
- `GET /api/v1/orgs/{org_slug}/portal/services/{service_id}/cancel-preview`: What cancelling right now would return, before committing to it (https://www.coritan.com/docs/api/reference/organizations/customer-portal/services/#op-get-api-v1-orgs-org-slug-portal-services-service-id-cancel-preview)
- `POST /api/v1/orgs/{org_slug}/portal/services/{service_id}/change-plan`: Change my service plan (https://www.coritan.com/docs/api/reference/organizations/customer-portal/services/#op-post-api-v1-orgs-org-slug-portal-services-service-id-change-plan)
- `GET /api/v1/orgs/{org_slug}/portal/services/{service_id}/community-listing`: Get community listing (https://www.coritan.com/docs/api/reference/organizations/customer-portal/services/#op-get-api-v1-orgs-org-slug-portal-services-service-id-community-listing)
- `PUT /api/v1/orgs/{org_slug}/portal/services/{service_id}/community-listing`: Upsert community listing (https://www.coritan.com/docs/api/reference/organizations/customer-portal/services/#op-put-api-v1-orgs-org-slug-portal-services-service-id-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 (https://www.coritan.com/docs/api/reference/organizations/customer-portal/services/#op-patch-api-v1-orgs-org-slug-portal-services-service-id-gameproxy)
- `GET /api/v1/orgs/{org_slug}/portal/services/{service_id}/plan-preview`: What a plan change costs today, before committing to it (https://www.coritan.com/docs/api/reference/organizations/customer-portal/services/#op-get-api-v1-orgs-org-slug-portal-services-service-id-plan-preview)
- `GET /api/v1/orgs/{org_slug}/portal/services/{service_id}/plans`: Sizes this service can move to (https://www.coritan.com/docs/api/reference/organizations/customer-portal/services/#op-get-api-v1-orgs-org-slug-portal-services-service-id-plans)
- `GET /api/v1/orgs/{org_slug}/portal/transactions`: List my transactions (https://www.coritan.com/docs/api/reference/organizations/customer-portal/transactions/#op-get-api-v1-orgs-org-slug-portal-transactions)
