> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kapso.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# WhatsApp funding and usage

> Read funding status and recorded messaging and calling charges, and stop portfolio funding

Project-scoped endpoints under `/platform/v1/whatsapp`, authenticated with your `X-API-Key`.

IDs in these paths are **Meta WABA and Business Portfolio IDs**, not Kapso UUIDs. Reads use
persisted evidence and never make a synchronous Meta request. IDs that are unknown or not
visible to your project return `404`, and a portfolio read includes only the accounts your
project can see.

| Method | Path                                                                    | Result                                              |
| ------ | ----------------------------------------------------------------------- | --------------------------------------------------- |
| GET    | `/whatsapp/accounts/{waba_id}/funding`                                  | Funding evidence and local message pauses           |
| GET    | `/whatsapp/accounts/{waba_id}/usage`                                    | Recorded charges by usage kind for one WABA         |
| GET    | `/whatsapp/portfolios/{portfolio_id}/accounts`                          | Accounts in a portfolio with funding status         |
| GET    | `/whatsapp/portfolios/{portfolio_id}/usage`                             | Recorded charges by usage kind across the portfolio |
| POST   | `/whatsapp/portfolios/{portfolio_id}/funding/revoke`                    | Queue a portfolio funding stop                      |
| GET    | `/whatsapp/portfolios/{portfolio_id}/funding/operations/{operation_id}` | Revocation status                                   |

## Funding status

```bash theme={null}
curl https://api.kapso.ai/platform/v1/whatsapp/accounts/4188880514714289/funding \
  -H "X-API-Key: $KAPSO_API_KEY"
```

```json theme={null}
{
  "data": {
    "waba_id": "4188880514714289",
    "business_portfolio_id": "1991231921410797",
    "status": "not_funded",
    "reason": "existing_payment_method",
    "message": "Existing Meta payment method kept.",
    "currency": "USD",
    "waba_currency": "USD",
    "last_verified_at": null,
    "last_checked_at": "2026-09-13T02:45:00Z",
    "paid_messages": { "paused": false, "reasons": [] }
  }
}
```

* `funded` — funding is verified, the allocation is approved and observed funding IDs match.
* `pending` — an initial funding operation is in progress.
* `unknown` — previously verified, but current evidence cannot confirm funding.
* `not_funded` — funding was never verified, including an attempt retired because the customer
  kept their existing Meta payment method.
* `revoked` — Meta allocation evidence confirms the funding was deleted. Retiring an
  unsuccessful attempt locally does not mean Meta funding was revoked.

`currency` is the Kapso settlement currency; `waba_currency` is the funding snapshot, or the
observed WABA currency when there is no attachment. `last_verified_at` is the latest recorded
transition into verification. `last_checked_at` includes failed attempts.

`paid_messages.paused` reflects local billing pauses on your project's attachment only. It is
not an authorization promise — balance, credentials, Meta restrictions and the partner send
pipeline can still block sending, and a funded WABA can have paused messages. Treat `reason` as
an extensible machine-readable string and `message` as display copy.

## Portfolio accounts

`GET /whatsapp/portfolios/{portfolio_id}/accounts` always uses cursor pagination, ordered by
creation time descending. Use `limit` (default 20, max 100), `after` and `before`; pass
`paging.next` back unchanged as `after`.

Each item has the funding fields above. A listed account is not necessarily funded or currently
reachable in Meta — evidence is retained after disconnection.

## Usage

Both usage endpoints require ISO 8601 `start_time` and `end_time` with an offset or `Z`, at most
31 days apart. The range is `[start_time, end_time)`.

```bash theme={null}
curl -G https://api.kapso.ai/platform/v1/whatsapp/accounts/4188880514714289/usage \
  -H "X-API-Key: $KAPSO_API_KEY" \
  -d start_time=2026-09-12T00:00:00Z \
  -d end_time=2026-09-13T00:00:00Z
```

```json theme={null}
{
  "data": {
    "start_time": "2026-09-12T00:00:00Z",
    "end_time": "2026-09-13T00:00:00Z",
    "time_basis": "recorded_at",
    "currency": "USD",
    "charge_scope": "kapso_recorded_charges",
    "totals": { "customer_charge_micro_usd": 115000 },
    "breakdown": [
      {
        "usage_kind": "messaging",
        "customer_charge_micro_usd": 90000,
        "billable_messages": 1,
        "sync": {
          "status": "delayed",
          "last_synced_at": "2026-09-12T23:30:00Z",
          "usage_through": "2026-09-12T23:25:00Z"
        }
      },
      {
        "usage_kind": "calling",
        "customer_charge_micro_usd": 25000,
        "coverage": { "status": "supported", "reason": null },
        "sync": {
          "status": "synced",
          "last_synced_at": null,
          "usage_through": "2026-09-13T00:00:00Z"
        }
      }
    ]
  }
}
```

Amounts are integer micro-USD: `1000000` is USD 1. The window measures **when charges were
recorded**, not when Meta delivered the messages. Signed corrections are included, so a
correction-only window can return a negative total. Free messages, unposted observations and
Meta charges paid outside Kapso are excluded. A zero total means zero recorded charges, not
proof of zero spend.

`totals.customer_charge_micro_usd` is the sum of every `breakdown` charge — what Kapso recorded,
not Meta's full invoice. New usage kinds can be added to `breakdown`, so handle unknown
`usage_kind` values, don't rely on array order, and read `totals` for the overall amount.
Quantities belong to their kind: `billable_messages` is messaging-only, and calling reports
aggregate fees rather than call counts, minutes or per-call charges.

### Freshness

Each breakdown entry has its own `sync`, describing current observation health, not completeness
of the requested range:

* `synced` — every relevant account is fresh (messaging settled within 15 minutes, calling
  coverage under one hour old).
* `delayed` — evidence exists but at least one account is older than that boundary.
* `unknown` — at least one relevant account has no successful observation.
* `not_available` — no coverage applies: a direct managed-billing account for messaging, or no
  active USD attachment for calling. Totals are still returned.

For messaging, `last_synced_at` is the oldest latest successful settlement and `usage_through`
is the conservative common end of the processed query windows, capped at fetch completion. For
calling, `last_synced_at` is always null — calling stores a reconciled coverage watermark rather
than a settlement completion timestamp, and `usage_through` is the oldest such watermark across
USD attachments. Neither guarantees Meta has reported everything for that period or will never
revise it.

### Calling coverage

Calling entries also carry `coverage`, based on the currency of your currently active
attachments:

* `supported` — every active attachment is a USD WABA.
* `partial` — mixed USD and non-USD (`reason: calling_requires_usd_waba`). Fresh USD
  observations say nothing about the non-USD WABAs.
* `unsupported` — no USD attachment (`reason: calling_requires_usd_waba`).
* `not_available` — no active attachment (`reason: no_active_attachment`).

Coverage is not a promise of billing activation, working credentials or complete observations,
and historical calling charges stay in the total even after support is lost.

Poll these endpoints if you need spend visibility, but do not use delayed usage as a real-time
hard credit limit. Portfolio totals include only your project's charges.

## Stop portfolio funding

```bash theme={null}
curl -X POST https://api.kapso.ai/platform/v1/whatsapp/portfolios/30458864570425307/funding/revoke \
  -H "X-API-Key: $KAPSO_API_KEY" \
  -H "Idempotency-Key: 9c1f0f2e-4a41-4d3d-9f0a-7b1f7d2a1c55"
```

```json theme={null}
{
  "data": {
    "operation_id": "2a2c446c-87c2-4f8a-ae74-aef1819e03f5",
    "business_portfolio_id": "30458864570425307",
    "status": "queued",
    "requested_at": "2026-09-13T02:45:00Z",
    "message": "Portfolio funding revocation is queued."
  }
}
```

No body is required. Use a stable unique `Idempotency-Key` (1–255 bytes) per logical request and
reuse it after an HTTP or network failure — the original operation is returned, and an
interrupted queue submission is recovered. Reusing a key for a different portfolio returns `409`.

`202` is acceptance, **not** confirmation that Meta funding stopped. Poll
`/whatsapp/portfolios/{portfolio_id}/funding/operations/{operation_id}` until `succeeded` or
`failed`. States are `queued`, `running`, `succeeded`, `failed` and `superseded`. A `failed`
operation can be partially completed — inspect WABA funding and contact support before starting a
new one. Operations are readable after the WABA moves or is disconnected.

The control disables portfolio auto-funding and revokes each approved allocation in the validated
scope, so **every WABA using that allocation is affected**, not just one number. Allocations
Kapso did not create, or whose liability includes another portfolio or project, are rejected.
Accounts that change between acceptance and execution make the operation fail safely.

Revoking funding does not disconnect numbers, remove a partner, erase billing history, or forgive
outstanding usage. Customers may need their own Meta payment method afterwards.

Errors: `400` invalid input or key, `401` invalid API key, `404` unknown or invisible resource,
`409` unsafe scope or conflicting key, `503` queue unavailable. Provider errors and secrets are
never included in operation responses.
