## GET /api/v2/billing/unpaid-summary

**Get unpaid-invoices summary**

Get a summary of the account's unpaid invoices: the total outstanding amount, one entry per unpaid invoice with due-date status, and whether a saved card will settle them automatically (`autoCharge`). Invoices already covered by a bulk-payment invoice are flagged with `isBulkPaymentChild` and their parent's ID. `uiShouldShow`, `uiDisplayKind`, and `uiSuppressReason` say whether a payment reminder needs the customer's attention at all — for example, everything upcoming may already be handled by automatic card charging.

### Related Endpoints

- `GET /api/v2/billing/cards`: List saved cards
- `POST /api/v2/billing/cards`: Store saved card
- `GET /api/v2/billing/account`: Get billing account

### Headers

- `Accept`: application/json
- `Authorization`: Bearer YOUR_API_KEY
- Required API scope: `read:billing`

### Request Example

```bash
curl -X GET "https://cloud.hostup.se/api/v2/billing/unpaid-summary" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Accept: application/json"
```

### Response Schema

- `totalAmount` (number, optional): Total outstanding amount across unpaid invoices, in major units of `currencyCode`.
- `currencyCode` (string, optional): ISO-4217 currency code for `totalAmount`.
- `count` (integer, optional)
- `uiDisplayKind` (string, optional)
  Allowed values: overdue, dueSoon, upcoming, none
- `uiShouldShow` (boolean, optional)
- `uiSuppressReason` (string, optional, nullable): Nullable (may be null when not applicable).
  Allowed values: no_unpaid_invoices, auto_charge_handles_upcoming
- `invoices` (array<object>, optional)
- `invoices[].id` (string, optional)
- `invoices[].number` (string, optional, nullable): Nullable (may be null when not applicable).
- `invoices[].amount` (number, optional): Outstanding amount for this invoice (not the invoice total), in major units of `currencyCode`.
- `invoices[].currencyCode` (string, optional): ISO-4217 currency code for `amount`.
- `invoices[].dueAt` (string, optional, nullable): Nullable (may be null when not applicable).
- `invoices[].dueStatus` (string, optional)
  Allowed values: overdue, dueSoon, upcoming, unknown
- `invoices[].daysOverdue` (number, optional, nullable): Nullable (may be null when not applicable).
- `invoices[].daysUntilDue` (number, optional, nullable): Nullable (may be null when not applicable).
- `invoices[].isBulkPaymentChild` (boolean, optional)
- `invoices[].bulkPaymentParentId` (string, optional, nullable): Nullable (may be null when not applicable).
- `autoCharge` (object, optional): Always present. Whether a saved card will settle unpaid invoices automatically — and whether the last automatic attempt actually went through. `status` is authoritative: `scheduled` means the next charge is ahead, `failed` means an invoice is past due while a card was armed, so the automatic charge did not go through and the customer must replace the card or pay another way.
- `autoCharge.enabled` (boolean, required): `true` when automatic card charging is on and a payment method is saved.
- `autoCharge.method` (object, required, nullable): The payment method that will be charged; null when auto-charge is disabled or no method is on file.
- `autoCharge.scheduledAt` (string, required, nullable): When the next automatic attempt is expected to run (20:00 Europe/Stockholm on the due date, or a possible daily retry shortly after a failed attempt); null when no further automatic attempt is expected — no unpaid invoices, auto-charge off, or a failure older than the short retry window. After a failure, treat any scheduled retry as best-effort: the customer should still replace the card or pay another way.
- `autoCharge.status` (string, required): `off`: auto-charge disabled or no card on file. `scheduled`: a card is armed and the earliest unpaid invoice is not yet due. `failed`: an unpaid invoice is past its due date while a card was armed — the automatic charge did not go through (declined, expired, or blocked card). Never treat `failed` as 'no action needed'. Example: `scheduled`
  Allowed values: off, scheduled, failed
- `autoCharge.reason` (string, required, nullable): Plain-language explanation when `status` is `failed`: what went wrong with the saved card, whether a retry is still pending, and that the customer must update the card or pay another way. Null for `off` and `scheduled`. Example: `null`
- `autoCharge.lastAttemptAt` (string, required, nullable): When the last automatic charge attempt failed, if the payment provider reported it to us. Null when no attempt record exists (the failure is then inferred from the invoice being past due) or when `status` is not `failed`. Example: `null`
- `autoCharge.failureKind` (string, required, nullable): Customer-facing classification of the last decline when `status` is `failed`; `unknown` when the failure is inferred from the overdue state only. Null otherwise. Example: `null`
  Allowed values: card_declined, insufficient_funds, card_expired, authentication_required, unknown

### Responses

#### 200 - Summary of unpaid invoices and automatic-charge status.
```json
{
  "totalAmount": 97.5,
  "currencyCode": "SEK",
  "count": 1,
  "uiDisplayKind": "dueSoon",
  "uiShouldShow": false,
  "uiSuppressReason": "auto_charge_handles_upcoming",
  "invoices": [
    {
      "id": "inv_abc123",
      "number": "202664539",
      "amount": 97.5,
      "currencyCode": "SEK",
      "dueAt": "2026-05-22T00:00:00.000Z",
      "dueStatus": "dueSoon",
      "daysOverdue": null,
      "daysUntilDue": 5,
      "isBulkPaymentChild": false,
      "bulkPaymentParentId": null
    }
  ],
  "autoCharge": {
    "enabled": true,
    "method": {
      "kind": "card",
      "last4": "8127",
      "brand": "visa"
    },
    "scheduledAt": "2026-05-22T18:00:00.000Z"
  }
}
```

#### 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"
}
```

#### 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"
}
```
