## POST /api/v2/billing/invoices/{id}/actions/pay

**Pay invoice by saved card**

Synchronously charge an unpaid invoice using the saved card on file. Send `{}` to use the primary saved card, or pass `savedCardId`. This endpoint is card-only: use `/actions/apply-credit` for account credit, and use `/actions/generate-payment-link` when the payer should choose Swish or another hosted payment method.

### Related Endpoints

- `GET /api/v2/billing/invoices/{id}`: Get invoice details
- `GET /api/v2/billing/invoices/{id}/payment-link`: Get invoice payment link state
- `POST /api/v2/billing/invoices/{id}/actions/generate-payment-link`: Generate invoice payment link

### Headers

- `Accept`: application/json
- `Authorization`: Bearer YOUR_API_KEY
- Required API scope: `write:billing`
- `Content-Type`: application/json

### Parameters

- `id` (path, string, required): Public invoice ID from `GET /api/v2/billing/invoices` `data[].id`, invoice detail, or an order response. Do not invent this value; use the exact ID returned by the referenced API response. Example: `inv_01hxa3b4c5d6e7f8g9h0j1k2m3`
- `Content-Type` (header, string): Send `application/json` when a request body is present. Example: `application/json`
- `Accept` (header, string): Request JSON responses from the API. Example: `application/json`

### Request Body

- `paymentMethod` (string, optional) Example: `card`
  Allowed values: card
- `savedCardId` (string, optional): Use `primary` for the primary saved card, or a public `card_...` ID from `GET /api/v2/billing/payment-methods`. Example: `primary`
- `amount` (number, optional) [min: 0.01, max: 1000000]: Optional partial payment amount in the invoice currency, in major currency units. Omit to charge the full outstanding amount. Example: `159`

### Request Examples

#### Use primary saved card

```bash
curl -X POST "https://cloud.hostup.se/api/v2/billing/invoices/inv_01hxa3b4c5d6e7f8g9h0j1k2m3/actions/pay" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Accept: application/json"
```

#### Use a specific saved card

```bash
curl -X POST "https://cloud.hostup.se/api/v2/billing/invoices/inv_01hxa3b4c5d6e7f8g9h0j1k2m3/actions/pay" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "paymentMethod": "card",
    "savedCardId": "card_01hxa3b4c5d6e7f8g9h0j1k2m3",
    "amount": 159
  }'
```

```json
{
  "paymentMethod": "card",
  "savedCardId": "card_01hxa3b4c5d6e7f8g9h0j1k2m3",
  "amount": 159
}
```

### Response Schema

- `id` (string, optional) Example: `inv_01hxa3b4c5d6e7f8g9h0j1k2m3`
- `orderId` (string, optional): Public order ID when the invoice is attached to an order. Domain renewal invoices with an uncancelled order must cancel this order first. Example: `ord_01hxa3b4c5d6e7f8g9h0j1k2m3`
- `number` (string, optional): Customer-facing invoice number. Example: `202600001`
- `status` (string, optional) Example: `unpaid`
  Allowed values: draft, unpaid, partially_paid, paid, cancelled, refunded
- `dates` (object, optional)
- `dates.issuedAt` (string, optional) Example: `2026-04-27T12:00:00.000Z`
- `dates.dueAt` (string, optional) Example: `2026-05-11T23:59:59.000Z`
- `dates.paidAt` (string, optional) Example: `2026-04-27T12:10:00.000Z`
- `totals` (object, optional)
- `totals.currencyCode` (string, required) Example: `SEK`
- `totals.subtotal` (number, required) Example: `127.2`
- `totals.taxAmount` (number, required) Example: `31.8`
- `totals.taxRateDecimal` (number, optional) Example: `0.25`
- `totals.creditApplied` (number, required) Example: `0`
- `totals.total` (number, required) Example: `159`
- `totals.amountPaid` (number, required) Example: `0`
- `totals.outstanding` (number, required) Example: `159`
- `lineItemCount` (integer, optional) Example: `1`
- `lineItems` (array<object>, optional)
- `payments` (array<object>, optional)
- `payments[].method` (string,null, required): Canonical payment method enum. Display labels and upstream gateway names never appear here; use `methodLabel` for text. Example: `card`
  Allowed values: card, accountCredit, swish, bankgiro, sepa, alipay, paypal, invoice, other, 
- `payments[].methodLabel` (string,null, required): Human-readable payment method label for display. Example: `Card`
- `payments[].amount` (number, required) Example: `98.75`
- `payments[].currencyCode` (string, required): ISO-4217 currency for `amount`. Example: `SEK`
- `note` (string, optional) Example: `Thank you for your order.`
- `actions` (object, optional)
- `actions.canPay` (object, required)
- `actions.canPay.allowed` (boolean, required) Example: `true`
- `actions.canPay.reason` (string,null, required) Example: `null`
- `actions.canPay.code` (string,null, optional): Machine-readable reason code when an action is blocked. Example: `pending_order`
- `actions.canGeneratePaymentLink` (object, required)
- `actions.canGeneratePaymentLink.allowed` (boolean, required) Example: `true`
- `actions.canGeneratePaymentLink.reason` (string,null, required) Example: `null`
- `actions.canGeneratePaymentLink.code` (string,null, optional): Machine-readable reason code when an action is blocked. Example: `pending_order`
- `actions.canBulkPay` (object, required)
- `actions.canBulkPay.allowed` (boolean, required) Example: `true`
- `actions.canBulkPay.reason` (string,null, required) Example: `null`
- `actions.canBulkPay.code` (string,null, optional): Machine-readable reason code when an action is blocked. Example: `pending_order`
- `actions.canCancel` (object, required)
- `actions.canCancel.allowed` (boolean, required) Example: `true`
- `actions.canCancel.reason` (string,null, required) Example: `null`
- `actions.canCancel.code` (string,null, optional): Machine-readable reason code when an action is blocked. Example: `pending_order`
- `actions.canEmail` (object, required)
- `actions.canEmail.allowed` (boolean, required) Example: `true`
- `actions.canEmail.reason` (string,null, required) Example: `null`
- `actions.canEmail.code` (string,null, optional): Machine-readable reason code when an action is blocked. Example: `pending_order`
- `actions.canDownload` (object, required)
- `actions.canDownload.allowed` (boolean, required) Example: `true`
- `actions.canDownload.reason` (string,null, required) Example: `null`
- `actions.canDownload.code` (string,null, optional): Machine-readable reason code when an action is blocked. Example: `pending_order`
- `paymentMethods` (object, optional): Per-method payment availability. Keys include `card`, `accountCredit`, `swish`, `bankgiro`, `sepa`, and `alipay`. Check these server-owned gates before starting a payment flow.
- `paymentMethods.card` (object, required)
- `paymentMethods.card.method` (string, required): Canonical v2 payment method. Card-backed hosted checkout and wallet flows are represented as `card`; provider names are not public v2 method values. Example: `card`
  Allowed values: card, accountCredit, swish, bankgiro, sepa, alipay
- `paymentMethods.card.label` (string, required) Example: `Card`
- `paymentMethods.card.available` (boolean, required) Example: `true`
- `paymentMethods.card.reason` (string,null, required): Human-readable blocker when `available` is false. Example: `null`
- `paymentMethods.card.checkoutMode` (string,null, required): Hosted checkout mode used by the existing payment session endpoint, or null for methods handled without hosted checkout. Example: `payment`
  Allowed values: payment, sepa_bank_transfer_payment, alipay_payment, 
- `paymentMethods.card.requirements` (object, required): Machine-readable requirements for the payment method. Examples: card minimum amount, Swish/Bankgiro Swedish account requirement, SEPA bank transfer EUR requirement, account-credit balance limit.
- `paymentMethods.card.requirements.invoiceCurrencyCode` (string, optional) Example: `SEK`
- `paymentMethods.card.requirements.invoiceCurrencyCodes` (array<string>, optional) Example: `["EUR","USD"]`
- `paymentMethods.card.requirements.accountCountryCode` (string, optional) Example: `SE`
- `paymentMethods.card.requirements.accountCurrencyCode` (string, optional) Example: `SEK`
- `paymentMethods.card.requirements.availableBalance` (object, optional)
- `paymentMethods.card.requirements.availableBalance.amount` (number, required) Example: `100`
- `paymentMethods.card.requirements.availableBalance.currencyCode` (string, required) Example: `SEK`
- `paymentMethods.card.requirements.minimumAmount` (object, optional)
- `paymentMethods.card.requirements.minimumAmount.amount` (number, required) Example: `3`
- `paymentMethods.card.requirements.minimumAmount.currencyCode` (string, required) Example: `SEK`
- `paymentMethods.card.requirements.minimumAmount.comparison` (string, required) Example: `greater_than`
  Allowed values: greater_than, less_than_or_equal
- `paymentMethods.card.requirements.maximumAmount` (object, optional)
- `paymentMethods.card.requirements.maximumAmount.amount` (number, required) Example: `3`
- `paymentMethods.card.requirements.maximumAmount.currencyCode` (string, required) Example: `SEK`
- `paymentMethods.card.requirements.maximumAmount.comparison` (string, required) Example: `greater_than`
  Allowed values: greater_than, less_than_or_equal
- `paymentMethods.accountCredit` (object, required)
- `paymentMethods.accountCredit.method` (string, required): Canonical v2 payment method. Card-backed hosted checkout and wallet flows are represented as `card`; provider names are not public v2 method values. Example: `card`
  Allowed values: card, accountCredit, swish, bankgiro, sepa, alipay
- `paymentMethods.accountCredit.label` (string, required) Example: `Card`
- `paymentMethods.accountCredit.available` (boolean, required) Example: `true`
- `paymentMethods.accountCredit.reason` (string,null, required): Human-readable blocker when `available` is false. Example: `null`
- `paymentMethods.accountCredit.checkoutMode` (string,null, required): Hosted checkout mode used by the existing payment session endpoint, or null for methods handled without hosted checkout. Example: `payment`
  Allowed values: payment, sepa_bank_transfer_payment, alipay_payment, 
- `paymentMethods.accountCredit.requirements` (object, required): Machine-readable requirements for the payment method. Examples: card minimum amount, Swish/Bankgiro Swedish account requirement, SEPA bank transfer EUR requirement, account-credit balance limit.
- `paymentMethods.accountCredit.requirements.invoiceCurrencyCode` (string, optional) Example: `SEK`
- `paymentMethods.accountCredit.requirements.invoiceCurrencyCodes` (array<string>, optional) Example: `["EUR","USD"]`
- `paymentMethods.accountCredit.requirements.accountCountryCode` (string, optional) Example: `SE`
- `paymentMethods.accountCredit.requirements.accountCurrencyCode` (string, optional) Example: `SEK`
- `paymentMethods.accountCredit.requirements.availableBalance` (object, optional)
- `paymentMethods.accountCredit.requirements.availableBalance.amount` (number, required) Example: `100`
- `paymentMethods.accountCredit.requirements.availableBalance.currencyCode` (string, required) Example: `SEK`
- `paymentMethods.accountCredit.requirements.minimumAmount` (object, optional)
- `paymentMethods.accountCredit.requirements.minimumAmount.amount` (number, required) Example: `3`
- `paymentMethods.accountCredit.requirements.minimumAmount.currencyCode` (string, required) Example: `SEK`
- `paymentMethods.accountCredit.requirements.minimumAmount.comparison` (string, required) Example: `greater_than`
  Allowed values: greater_than, less_than_or_equal
- `paymentMethods.accountCredit.requirements.maximumAmount` (object, optional)
- `paymentMethods.accountCredit.requirements.maximumAmount.amount` (number, required) Example: `3`
- `paymentMethods.accountCredit.requirements.maximumAmount.currencyCode` (string, required) Example: `SEK`
- `paymentMethods.accountCredit.requirements.maximumAmount.comparison` (string, required) Example: `greater_than`
  Allowed values: greater_than, less_than_or_equal
- `paymentMethods.swish` (object, required)
- `paymentMethods.swish.method` (string, required): Canonical v2 payment method. Card-backed hosted checkout and wallet flows are represented as `card`; provider names are not public v2 method values. Example: `card`
  Allowed values: card, accountCredit, swish, bankgiro, sepa, alipay
- `paymentMethods.swish.label` (string, required) Example: `Card`
- `paymentMethods.swish.available` (boolean, required) Example: `true`
- `paymentMethods.swish.reason` (string,null, required): Human-readable blocker when `available` is false. Example: `null`
- `paymentMethods.swish.checkoutMode` (string,null, required): Hosted checkout mode used by the existing payment session endpoint, or null for methods handled without hosted checkout. Example: `payment`
  Allowed values: payment, sepa_bank_transfer_payment, alipay_payment, 
- `paymentMethods.swish.requirements` (object, required): Machine-readable requirements for the payment method. Examples: card minimum amount, Swish/Bankgiro Swedish account requirement, SEPA bank transfer EUR requirement, account-credit balance limit.
- `paymentMethods.swish.requirements.invoiceCurrencyCode` (string, optional) Example: `SEK`
- `paymentMethods.swish.requirements.invoiceCurrencyCodes` (array<string>, optional) Example: `["EUR","USD"]`
- `paymentMethods.swish.requirements.accountCountryCode` (string, optional) Example: `SE`
- `paymentMethods.swish.requirements.accountCurrencyCode` (string, optional) Example: `SEK`
- `paymentMethods.swish.requirements.availableBalance` (object, optional)
- `paymentMethods.swish.requirements.availableBalance.amount` (number, required) Example: `100`
- `paymentMethods.swish.requirements.availableBalance.currencyCode` (string, required) Example: `SEK`
- `paymentMethods.swish.requirements.minimumAmount` (object, optional)
- `paymentMethods.swish.requirements.minimumAmount.amount` (number, required) Example: `3`
- `paymentMethods.swish.requirements.minimumAmount.currencyCode` (string, required) Example: `SEK`
- `paymentMethods.swish.requirements.minimumAmount.comparison` (string, required) Example: `greater_than`
  Allowed values: greater_than, less_than_or_equal
- `paymentMethods.swish.requirements.maximumAmount` (object, optional)
- `paymentMethods.swish.requirements.maximumAmount.amount` (number, required) Example: `3`
- `paymentMethods.swish.requirements.maximumAmount.currencyCode` (string, required) Example: `SEK`
- `paymentMethods.swish.requirements.maximumAmount.comparison` (string, required) Example: `greater_than`
  Allowed values: greater_than, less_than_or_equal
- `paymentMethods.bankgiro` (object, required)
- `paymentMethods.bankgiro.method` (string, required): Canonical v2 payment method. Card-backed hosted checkout and wallet flows are represented as `card`; provider names are not public v2 method values. Example: `card`
  Allowed values: card, accountCredit, swish, bankgiro, sepa, alipay
- `paymentMethods.bankgiro.label` (string, required) Example: `Card`
- `paymentMethods.bankgiro.available` (boolean, required) Example: `true`
- `paymentMethods.bankgiro.reason` (string,null, required): Human-readable blocker when `available` is false. Example: `null`
- `paymentMethods.bankgiro.checkoutMode` (string,null, required): Hosted checkout mode used by the existing payment session endpoint, or null for methods handled without hosted checkout. Example: `payment`
  Allowed values: payment, sepa_bank_transfer_payment, alipay_payment, 
- `paymentMethods.bankgiro.requirements` (object, required): Machine-readable requirements for the payment method. Examples: card minimum amount, Swish/Bankgiro Swedish account requirement, SEPA bank transfer EUR requirement, account-credit balance limit.
- `paymentMethods.bankgiro.requirements.invoiceCurrencyCode` (string, optional) Example: `SEK`
- `paymentMethods.bankgiro.requirements.invoiceCurrencyCodes` (array<string>, optional) Example: `["EUR","USD"]`
- `paymentMethods.bankgiro.requirements.accountCountryCode` (string, optional) Example: `SE`
- `paymentMethods.bankgiro.requirements.accountCurrencyCode` (string, optional) Example: `SEK`
- `paymentMethods.bankgiro.requirements.availableBalance` (object, optional)
- `paymentMethods.bankgiro.requirements.availableBalance.amount` (number, required) Example: `100`
- `paymentMethods.bankgiro.requirements.availableBalance.currencyCode` (string, required) Example: `SEK`
- `paymentMethods.bankgiro.requirements.minimumAmount` (object, optional)
- `paymentMethods.bankgiro.requirements.minimumAmount.amount` (number, required) Example: `3`
- `paymentMethods.bankgiro.requirements.minimumAmount.currencyCode` (string, required) Example: `SEK`
- `paymentMethods.bankgiro.requirements.minimumAmount.comparison` (string, required) Example: `greater_than`
  Allowed values: greater_than, less_than_or_equal
- `paymentMethods.bankgiro.requirements.maximumAmount` (object, optional)
- `paymentMethods.bankgiro.requirements.maximumAmount.amount` (number, required) Example: `3`
- `paymentMethods.bankgiro.requirements.maximumAmount.currencyCode` (string, required) Example: `SEK`
- `paymentMethods.bankgiro.requirements.maximumAmount.comparison` (string, required) Example: `greater_than`
  Allowed values: greater_than, less_than_or_equal
- `paymentMethods.sepa` (object, required)
- `paymentMethods.sepa.method` (string, required): Canonical v2 payment method. Card-backed hosted checkout and wallet flows are represented as `card`; provider names are not public v2 method values. Example: `card`
  Allowed values: card, accountCredit, swish, bankgiro, sepa, alipay
- `paymentMethods.sepa.label` (string, required) Example: `Card`
- `paymentMethods.sepa.available` (boolean, required) Example: `true`
- `paymentMethods.sepa.reason` (string,null, required): Human-readable blocker when `available` is false. Example: `null`
- `paymentMethods.sepa.checkoutMode` (string,null, required): Hosted checkout mode used by the existing payment session endpoint, or null for methods handled without hosted checkout. Example: `payment`
  Allowed values: payment, sepa_bank_transfer_payment, alipay_payment, 
- `paymentMethods.sepa.requirements` (object, required): Machine-readable requirements for the payment method. Examples: card minimum amount, Swish/Bankgiro Swedish account requirement, SEPA bank transfer EUR requirement, account-credit balance limit.
- `paymentMethods.sepa.requirements.invoiceCurrencyCode` (string, optional) Example: `SEK`
- `paymentMethods.sepa.requirements.invoiceCurrencyCodes` (array<string>, optional) Example: `["EUR","USD"]`
- `paymentMethods.sepa.requirements.accountCountryCode` (string, optional) Example: `SE`
- `paymentMethods.sepa.requirements.accountCurrencyCode` (string, optional) Example: `SEK`
- `paymentMethods.sepa.requirements.availableBalance` (object, optional)
- `paymentMethods.sepa.requirements.availableBalance.amount` (number, required) Example: `100`
- `paymentMethods.sepa.requirements.availableBalance.currencyCode` (string, required) Example: `SEK`
- `paymentMethods.sepa.requirements.minimumAmount` (object, optional)
- `paymentMethods.sepa.requirements.minimumAmount.amount` (number, required) Example: `3`
- `paymentMethods.sepa.requirements.minimumAmount.currencyCode` (string, required) Example: `SEK`
- `paymentMethods.sepa.requirements.minimumAmount.comparison` (string, required) Example: `greater_than`
  Allowed values: greater_than, less_than_or_equal
- `paymentMethods.sepa.requirements.maximumAmount` (object, optional)
- `paymentMethods.sepa.requirements.maximumAmount.amount` (number, required) Example: `3`
- `paymentMethods.sepa.requirements.maximumAmount.currencyCode` (string, required) Example: `SEK`
- `paymentMethods.sepa.requirements.maximumAmount.comparison` (string, required) Example: `greater_than`
  Allowed values: greater_than, less_than_or_equal
- `paymentMethods.alipay` (object, required)
- `paymentMethods.alipay.method` (string, required): Canonical v2 payment method. Card-backed hosted checkout and wallet flows are represented as `card`; provider names are not public v2 method values. Example: `card`
  Allowed values: card, accountCredit, swish, bankgiro, sepa, alipay
- `paymentMethods.alipay.label` (string, required) Example: `Card`
- `paymentMethods.alipay.available` (boolean, required) Example: `true`
- `paymentMethods.alipay.reason` (string,null, required): Human-readable blocker when `available` is false. Example: `null`
- `paymentMethods.alipay.checkoutMode` (string,null, required): Hosted checkout mode used by the existing payment session endpoint, or null for methods handled without hosted checkout. Example: `payment`
  Allowed values: payment, sepa_bank_transfer_payment, alipay_payment, 
- `paymentMethods.alipay.requirements` (object, required): Machine-readable requirements for the payment method. Examples: card minimum amount, Swish/Bankgiro Swedish account requirement, SEPA bank transfer EUR requirement, account-credit balance limit.
- `paymentMethods.alipay.requirements.invoiceCurrencyCode` (string, optional) Example: `SEK`
- `paymentMethods.alipay.requirements.invoiceCurrencyCodes` (array<string>, optional) Example: `["EUR","USD"]`
- `paymentMethods.alipay.requirements.accountCountryCode` (string, optional) Example: `SE`
- `paymentMethods.alipay.requirements.accountCurrencyCode` (string, optional) Example: `SEK`
- `paymentMethods.alipay.requirements.availableBalance` (object, optional)
- `paymentMethods.alipay.requirements.availableBalance.amount` (number, required) Example: `100`
- `paymentMethods.alipay.requirements.availableBalance.currencyCode` (string, required) Example: `SEK`
- `paymentMethods.alipay.requirements.minimumAmount` (object, optional)
- `paymentMethods.alipay.requirements.minimumAmount.amount` (number, required) Example: `3`
- `paymentMethods.alipay.requirements.minimumAmount.currencyCode` (string, required) Example: `SEK`
- `paymentMethods.alipay.requirements.minimumAmount.comparison` (string, required) Example: `greater_than`
  Allowed values: greater_than, less_than_or_equal
- `paymentMethods.alipay.requirements.maximumAmount` (object, optional)
- `paymentMethods.alipay.requirements.maximumAmount.amount` (number, required) Example: `3`
- `paymentMethods.alipay.requirements.maximumAmount.currencyCode` (string, required) Example: `SEK`
- `paymentMethods.alipay.requirements.maximumAmount.comparison` (string, required) Example: `greater_than`
  Allowed values: greater_than, less_than_or_equal
- `paymentLinkGeneratorUrl` (string,null, optional) Example: `/api/v2/billing/invoices/inv_01hxa3b4c5d6e7f8g9h0j1k2m3/actions/generate-payment-link`
- `isBulkPaymentChild` (boolean, optional) Example: `false`
- `bulkPaymentParentId` (string,null, optional) Example: `null`
- `coversInvoiceIds` (array<string>, optional) Example: `["inv_01hxa3b4c5d6e7f8g9h0j1k2m3"]`
- `renewalInvoicing` (object, optional): Present only when the invoice detail route can evaluate the same renewal invoicing preference logic used by invoice emails.
- `renewalInvoicing.preference` (string, required) Example: `consolidated`
  Allowed values: consolidated, separate
- `renewalInvoicing.generatedByAutomation` (boolean, required): True when the invoice was generated by the renewal automation path that also shows the invoice-email preference note. Example: `true`
- `renewalInvoicing.isConsolidated` (boolean, required): True only when this is an automated renewal invoice and the account preference was consolidated at generation time. Do not infer this from line-item count. Example: `true`
- `renewalInvoicing.label` (string, required) Example: `Consolidated renewal invoice`
- `renewalInvoicing.settingsUrl` (string, required) Example: `/account`

### Responses

#### 200 - Updated invoice after card payment.
```json
{
  "id": "inv_01hxa3b4c5d6e7f8g9h0j1k2m3",
  "orderId": "ord_01hxa3b4c5d6e7f8g9h0j1k2m3",
  "number": "202600001",
  "status": "paid",
  "dates": {
    "issuedAt": "2026-04-27T12:00:00.000Z",
    "dueAt": "2026-05-11T23:59:59.000Z",
    "paidAt": "2026-04-27T12:10:00.000Z"
  },
  "totals": {
    "currencyCode": "SEK",
    "subtotal": 127.2,
    "taxAmount": 31.8,
    "taxRateDecimal": 0.25,
    "creditApplied": 0,
    "total": 159,
    "amountPaid": 159,
    "outstanding": 0
  },
  "lineItemCount": 1,
  "lineItems": [
    {
      "description": "Cloud VPS monthly service",
      "displayDescription": "Cloud VPS monthly service",
      "kind": "vps",
      "productName": "Cloud VPS",
      "quantity": 1,
      "unitAmount": 127.2,
      "totalAmount": 127.2,
      "currencyCode": "SEK",
      "period": {
        "startAt": "2026-04-27T12:00:00.000Z",
        "endAt": "2026-05-27T12:00:00.000Z"
      },
      "resource": {
        "type": "vps",
        "id": "vps_01hxa3b4c5d6e7f8g9h0j1k2m3",
        "displayName": "example.com"
      },
      "configurableOptions": [
        {
          "key": "os",
          "label": "OS",
          "value": "Debian 13"
        },
        {
          "key": "blockStorageNvme",
          "label": "Block Storage (NVMe)",
          "value": "50 GB"
        },
        {
          "key": "bandwidthLimit",
          "label": "Bandwidth limit",
          "value": "2 TB"
        },
        {
          "key": "cephStoragePreference",
          "label": "Ceph storage preference",
          "value": "Replication 3"
        },
        {
          "key": "backups",
          "label": "Example Label",
          "value": "7"
        }
      ]
    }
  ],
  "actions": {
    "canPay": {
      "allowed": false,
      "reason": "Invoice is already paid."
    },
    "canGeneratePaymentLink": {
      "allowed": false,
      "reason": "Invoice is already paid."
    },
    "canBulkPay": {
      "allowed": false,
      "reason": "Invoice is already paid."
    },
    "canCancel": {
      "allowed": false,
      "reason": "Only unpaid invoices can be cancelled."
    },
    "canEmail": {
      "allowed": true,
      "reason": null
    },
    "canDownload": {
      "allowed": true,
      "reason": null
    }
  },
  "paymentMethods": {
    "card": {
      "method": "card",
      "label": "Card",
      "available": false,
      "reason": "Invoice is already paid.",
      "checkoutMode": "payment",
      "requirements": {
        "minimumAmount": {
          "amount": 3,
          "currencyCode": "SEK",
          "comparison": "greater_than"
        }
      }
    },
    "accountCredit": {
      "method": "accountCredit",
      "label": "Account credit",
      "available": false,
      "reason": "Invoice is already paid.",
      "checkoutMode": null,
      "requirements": {
        "invoiceCurrencyCode": "SEK",
        "accountCurrencyCode": "SEK",
        "availableBalance": {
          "amount": 0,
          "currencyCode": "SEK"
        },
        "maximumAmount": {
          "amount": 0,
          "currencyCode": "SEK",
          "comparison": "less_than_or_equal"
        }
      }
    },
    "swish": {
      "method": "swish",
      "label": "Swish",
      "available": false,
      "reason": "Invoice is already paid.",
      "checkoutMode": null,
      "requirements": {
        "invoiceCurrencyCode": "SEK",
        "accountCountryCode": "SE"
      }
    },
    "bankgiro": {
      "method": "bankgiro",
      "label": "Bankgiro",
      "available": false,
      "reason": "Invoice is already paid.",
      "checkoutMode": null,
      "requirements": {
        "invoiceCurrencyCode": "SEK",
        "accountCountryCode": "SE"
      }
    },
    "sepa": {
      "method": "sepa",
      "label": "SEPA bank transfer",
      "available": false,
      "reason": "Invoice is already paid.",
      "checkoutMode": "sepa_bank_transfer_payment",
      "requirements": {
        "invoiceCurrencyCode": "EUR"
      }
    },
    "alipay": {
      "method": "alipay",
      "label": "Alipay",
      "available": false,
      "reason": "Invoice is already paid.",
      "checkoutMode": "alipay_payment",
      "requirements": {
        "invoiceCurrencyCodes": [
          "EUR",
          "USD"
        ]
      }
    }
  },
  "paymentLinkGeneratorUrl": null,
  "isBulkPaymentChild": false,
  "bulkPaymentParentId": null
}
```

#### 400 - Invalid request. The response body is an RFC 7807 Problem Details document.
```json
{
  "type": "https://developer.hostup.se/errors/invalid_request",
  "title": "Invalid request",
  "status": 400,
  "detail": "The request body failed validation.",
  "code": "invalid_request",
  "instance": "/api/v2/resource",
  "requestId": "req_01hxa3b4c5d6e7f8g9h0j1k2m3",
  "timestamp": "2026-04-27T12:34:56.000Z",
  "errors": [
    {
      "pointer": "/items/0/domainName",
      "detail": "`domainName` is required.",
      "code": "invalid_request"
    }
  ]
}
```

#### 401 - Unauthorized. Authentication is required.
```json
{
  "type": "https://developer.hostup.se/errors/unauthorized",
  "title": "Unauthorized",
  "status": 401,
  "detail": "Authentication is required.",
  "code": "unauthorized",
  "instance": "/api/v2/resource",
  "requestId": "req_01hxa3b4c5d6e7f8g9h0j1k2m3",
  "timestamp": "2026-04-27T12:34:56.000Z"
}
```

#### 403 - Forbidden. The caller lacks a required scope or does not own the resource.
```json
{
  "type": "https://developer.hostup.se/errors/forbidden",
  "title": "Forbidden",
  "status": 403,
  "detail": "The caller lacks a required scope or does not own the resource.",
  "code": "forbidden",
  "instance": "/api/v2/resource",
  "requestId": "req_01hxa3b4c5d6e7f8g9h0j1k2m3",
  "timestamp": "2026-04-27T12:34:56.000Z"
}
```

#### 404 - Not found. The resource does not exist or is not owned by the caller.
```json
{
  "type": "https://developer.hostup.se/errors/not_found",
  "title": "Not found",
  "status": 404,
  "detail": "The requested resource could not be found.",
  "code": "not_found",
  "instance": "/api/v2/resource",
  "requestId": "req_01hxa3b4c5d6e7f8g9h0j1k2m3",
  "timestamp": "2026-04-27T12:34:56.000Z"
}
```

#### 409 - Conflict. See the Problem Details `code` for the route-specific blocker and recovery fields.
```json
{
  "status": 409,
  "instance": "/api/v2/billing/invoices/inv_01hxa3b4c5d6e7f8g9h0j1k2m3/actions/pay",
  "requestId": "req_01hxa3b4c5d6e7f8g9h0j1k2m3",
  "timestamp": "2026-04-27T12:34:56.000Z",
  "type": "https://developer.hostup.se/errors/payment_method_invalid",
  "title": "Payment method invalid",
  "detail": "Add a card on file before paying this invoice by saved card.",
  "code": "payment_method_invalid",
  "invoice": {
    "id": "inv_01hxa3b4c5d6e7f8g9h0j1k2m3",
    "number": "202600001",
    "status": "unpaid"
  },
  "actions": {
    "canPay": {
      "allowed": false,
      "reason": "Add a card on file before paying this invoice by saved card."
    },
    "canGeneratePaymentLink": {
      "allowed": true,
      "reason": null
    }
  },
  "paymentLinkGeneratorUrl": "/api/v2/billing/invoices/inv_01hxa3b4c5d6e7f8g9h0j1k2m3/actions/generate-payment-link"
}
```

#### 429 - Rate limited. Retry after the limit resets. 429 responses include `Retry-After` seconds plus `X-RateLimit-*` headers.
```json
{
  "type": "https://developer.hostup.se/errors/rate_limit_exceeded",
  "title": "Too many requests",
  "status": 429,
  "detail": "Too many requests. Retry after the limit resets.",
  "code": "rate_limit_exceeded",
  "instance": "/api/v2/resource",
  "requestId": "req_01hxa3b4c5d6e7f8g9h0j1k2m3",
  "timestamp": "2026-04-27T12:34:56.000Z"
}
```

#### 500 - Internal error. Retry later or contact support if the issue persists.
```json
{
  "type": "https://developer.hostup.se/errors/internal_error",
  "title": "Internal server error",
  "status": 500,
  "detail": "An unexpected error occurred. Retry later or contact support if the issue persists.",
  "code": "internal_error",
  "instance": "/api/v2/resource",
  "requestId": "req_01hxa3b4c5d6e7f8g9h0j1k2m3",
  "timestamp": "2026-04-27T12:34:56.000Z"
}
```
