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

# Platform REST APIs

> Tools, agents, outbound batches, call logs, billing (usage and credit summary), wallets, earnings, feature flags, and API keys — paths and usage patterns for integrations.

All routes below are under your API host (for example `https://api.kupe.in`) unless noted. Authenticate with **`Authorization: Bearer <supabase_jwt>`** from the dashboard, or **`x-api-key: <kupe_api_key>`** for server integrations.

## Tools — custom HTTP tools and MCP

### HTTP tool definitions (CRUD)

Base path: **`/api/v1/tool-endpoint-defs`**

| Method   | Path    | Purpose                                          |
| -------- | ------- | ------------------------------------------------ |
| `POST`   | `""`    | Create a tool definition (URL, schemas, method). |
| `GET`    | `""`    | List your tool definitions.                      |
| `GET`    | `/{id}` | Get one definition.                              |
| `PUT`    | `/{id}` | Update.                                          |
| `DELETE` | `/{id}` | Delete.                                          |

### MCP server tool definitions (CRUD)

Base path: **`/api/v1/tools-mcp-server-defs`**

Same idea as HTTP tools: `POST` / `GET` / `GET /{id}` / `PUT` / `DELETE` for MCP-backed tools.

### Attach tools to an agent

Base path: **`/api/v1/agents`**

| Method   | Path                          | Purpose                                                |
| -------- | ----------------------------- | ------------------------------------------------------ |
| `GET`    | `/{agent_id}/tools`           | List tools linked to the agent.                        |
| `POST`   | `/{agent_id}/tools`           | Add tool mappings (body: list of tool config objects). |
| `PATCH`  | `/{agent_id}/tools`           | Replace/update tool configuration.                     |
| `DELETE` | `/{agent_id}/tools/{tool_id}` | Remove one tool mapping.                               |

Create tools first (`tool-endpoint-defs` or `tools-mcp-server-defs`), then reference their IDs in the agent tools payload when calling `POST` / `PATCH` on `/{agent_id}/tools`.

***

## Post-call analysis — rules and agent mapping

### User-scoped rules (CRUD)

Base path: **`/api/v1/post-analysis`**

| Method   | Path                         | Purpose                  |
| -------- | ---------------------------- | ------------------------ |
| `GET`    | `/rules`                     | List rules.              |
| `POST`   | `/rules`                     | Create rule (JSON body). |
| `GET`    | `/rules/{rule_id}`           | Get one rule.            |
| `PUT`    | `/rules/{rule_id}`           | Update.                  |
| `DELETE` | `/rules/{rule_id}`           | Delete.                  |
| `POST`   | `/rules/{rule_id}/duplicate` | Duplicate.               |

### Map rules to an agent

Base path: **`/api/v1/agents/{agent_id}`**

| Method | Path                               | Purpose                                                                                      |
| ------ | ---------------------------------- | -------------------------------------------------------------------------------------------- |
| `POST` | `/post-analysis`                   | Upsert post-call analysis config for the agent (body includes `agent_id` aligned with path). |
| `GET`  | `/post-analysis`                   | Get post-call analysis rows for the agent.                                                   |
| `GET`  | `/post-analysis/attached-rules`    | Rules attached to the agent.                                                                 |
| `GET`  | `/post-analysis/attached-rule-ids` | IDs only.                                                                                    |
| `PUT`  | `/post-analysis/attached-rules`    | Set attached rules: body `{ "rule_ids": ["uuid", ...] }`.                                    |

***

## Outbound — batch campaigns (end-to-end API)

Base path: **`/api/v1/batch-call`**

Requires the **outbound** feature flag on your account. Authenticate with **`x-api-key`** or **Bearer** on every route below (except Twilio **`/status-callback`**, which is called by the carrier).

### Prerequisites

1. **`GET /api/v1/phone`** — list provisioned lines; note each row’s **`id`** (`caller_phone_id`).
2. **`GET /api/v1/agents`** — note your agent **`id`**, or use a workflow id instead.
3. In the agent system prompt, use variables like `{{name}}` that match **`variable_names`** on the batch.

### End-to-end flow

| Step | Method | Path                      | Purpose                                                                                                         |
| ---- | ------ | ------------------------- | --------------------------------------------------------------------------------------------------------------- |
| 1    | `POST` | `/create`                 | Create batch: `agent_id` **or** `workflow_id`, `caller_phone_id`, `batch_name`, `variable_names`, `batch_size`. |
| 2a   | `POST` | `/upload-json/{batch_id}` | Add targets as JSON (`records[]` with `to_phonenumber` + variable keys).                                        |
| 2b   | `POST` | `/upload/{batch_id}`      | Or upload CSV (`multipart/form-data`, column `to_phonenumber` + variables).                                     |
| 2c   | `POST` | `/{batch_id}/data/upsert` | Or upsert rows one-by-one / in bulk (`items[]` with optional `id` to update).                                   |
| 3    | `GET`  | `/{batch_id}/data`        | Verify recipients (optional `?status=not_started`).                                                             |
| 4    | `POST` | `/start/{batch_id}`       | **Launch campaign** — dials up to `batch_size` numbers at a time.                                               |
| 5    | `GET`  | `/{batch_id}/status`      | Poll batch **`status`** + **`status_counts`** (not\_started, calling, completed, failed, no\_answer).           |
| 5    | `GET`  | `/{batch_id}/data`        | Poll per-number status and `error_message`.                                                                     |

**Batch-level status:** `not_started` → `in_progress` (after launch) → `completed` (all rows terminal).

**Recipient status:** `not_started` → `calling` → `completed` | `failed` | `no_answer`.

### All routes

| Method   | Path                         | Purpose                                                             |
| -------- | ---------------------------- | ------------------------------------------------------------------- |
| `POST`   | `/create`                    | Create batch (`user_id` optional — defaults to authenticated user). |
| `GET`    | `/me`                        | List batches for the authenticated user.                            |
| `GET`    | `/{batch_id}`                | Batch metadata only.                                                |
| `GET`    | `/{batch_id}/status`         | Metadata + aggregated status counts.                                |
| `GET`    | `/{batch_id}/data`           | All target numbers (optional `?status=`).                           |
| `POST`   | `/{batch_id}/data/upsert`    | Insert/update recipients (before launch).                           |
| `PATCH`  | `/{batch_id}/variables`      | Update `variable_names` (before launch).                            |
| `DELETE` | `/{batch_id}/data/{item_id}` | Remove one recipient (before launch).                               |
| `POST`   | `/upload/{batch_id}`         | CSV upload (`to_phonenumber` + variable columns).                   |
| `POST`   | `/upload-json/{batch_id}`    | JSON bulk upload.                                                   |
| `POST`   | `/start/{batch_id}`          | Launch campaign.                                                    |
| `DELETE` | `/{batch_id}`                | Delete batch and all recipients.                                    |
| `GET`    | `/browse`                    | Paginated list (super-admin scoping query params).                  |
| `GET`    | `/user/{user_id}`            | List batches for a user (self or super-admin).                      |
| `POST`   | `/status-callback`           | Twilio status webhook (internal; no API key).                       |

### Example: create → add numbers → launch → poll

```bash theme={null}
export KUPE_API_KEY="your_key"
export BASE="https://api.kupe.in"

# 1. Create batch
BATCH=$(curl -s -X POST "$BASE/api/v1/batch-call/create" \
  -H "x-api-key: $KUPE_API_KEY" -H "Content-Type: application/json" \
  -d '{
    "agent_id": "YOUR_AGENT_UUID",
    "caller_phone_id": "YOUR_PHONE_NUMBER_UUID",
    "batch_name": "API demo",
    "variable_names": ["name"],
    "batch_size": 3
  }' | jq -r '.data.id')

# 2. Add targets
curl -s -X POST "$BASE/api/v1/batch-call/upload-json/$BATCH" \
  -H "x-api-key: $KUPE_API_KEY" -H "Content-Type: application/json" \
  -d '{"records":[{"to_phonenumber":"+919876543210","name":"Ada"}]}'

# 3. Launch
curl -s -X POST "$BASE/api/v1/batch-call/start/$BATCH" \
  -H "x-api-key: $KUPE_API_KEY"

# 4. Poll progress
curl -s "$BASE/api/v1/batch-call/$BATCH/status" -H "x-api-key: $KUPE_API_KEY" | jq .
curl -s "$BASE/api/v1/batch-call/$BATCH/data?status=calling" -H "x-api-key: $KUPE_API_KEY" | jq .
```

Interactive request/response shapes: **Voice Agent API** OpenAPI tab → **Batch calling** (`kupe-voice-agent.openapi.yaml`).

***

## Call logs — list, pagination, single session, post-call data

Base path: **`/api/v1/call-analytics`**

| Query / path                           | Behavior                                                                                                                                    |
| -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| `GET /call-analytics?request_id=<id>`  | **Single call** by `request_id`. Response includes session fields; when HIPAA-style, transcript/recording/post-call fields may be stripped. |
| `GET /call-analytics?page=&page_size=` | **Paginated list** (server-side). Use `filter` (alias) for search on request id / call type.                                                |
| `GET /call-analytics` (no page)        | Full list for dashboards (subject to feature flags and scope).                                                                              |
| Super-admin scoping                    | Optional query params: `scope`, `organization_ids`, `owner_user_ids`, `platform_roles`, etc., as supported by your deployment.              |

Post-call analysis fields (when not redacted) appear on the session object, e.g. `post_call_analysis_results` and related keys returned by the service layer.

### Export (ZIP, optional date range)

`GET /call-analytics/export` — supports `request_id` for a single downloadable export, or bulk export with `start_date` / `end_date` (`YYYY-MM-DD`) and email delivery for large ranges.

***

## Billing and usage (usage, cost, credit summary)

Base path: **`/api/v1/billing`**

Typical **read** endpoints (also available under `/billing/...` where the router is mounted without the `/api/v1` prefix):

| GET path                       | Purpose                                                                                                                |
| ------------------------------ | ---------------------------------------------------------------------------------------------------------------------- |
| `/usage-records`               | Usage organized by call sessions.                                                                                      |
| `/usage/records`               | Service usage records with filters (`time_filter`, `usage_type`, search, `limit`/`offset`).                            |
| `/usage/summary`               | Aggregated summary for charts.                                                                                         |
| `/usage/overview`              | Totals and this-month usage for the authenticated scope.                                                               |
| `/usage/sessions/{session_id}` | Usage and cost for one session.                                                                                        |
| `/usage/export`                | Export usage (e.g. CSV by email; filters align with `/usage/records`).                                                 |
| `/credit-balance`              | Credit balance summary — backed by the unified **wallets** row (`available_balance_usd`, monthly cap fields when set). |

**Removed** from the product (do not call): self-serve **pricing plans**, **payment checkout**, **Razorpay** webhooks, **`/balance-history`** (legacy ledger). Historical balance movements and grants are returned from **`GET /api/v1/wallets/{wallet_id}`** (see **Wallets** below).

Other **`GET /api/v1/billing/**`** routes your deployment may expose (e.g. forex quotes, service pricing) remain read-only catalog helpers where implemented.

### API key vs session (important)

When you authenticate with **`x-api-key`**, **only `GET` (and `HEAD`/`OPTIONS`)** are allowed on **`/api/v1/billing/**`**. There is no API-key billing **write** surface.

**Wallets** and **earnings** live under **`/api/v1/wallets/**`** and **`/api/v1/earnings/**`**. Assigning credits, caps, org business model, markup, and commission are **POST** operations and require a **Bearer (session) token** with the appropriate org or super-admin role.

### Feature flags

Base path: **`/api/v1/feature-flags`**

| Method | Path         | Purpose                                                                                                                                                                                                        |
| ------ | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `GET`  | `/me`        | Boolean feature flags for the signed-in user.                                                                                                                                                                  |
| `GET`  | `/{user_id}` | Read another user’s flags when RBAC allows.                                                                                                                                                                    |
| `PUT`  | `/{user_id}` | Update boolean flags only. **Per-user billing markup** fields are no longer accepted here — retail markup is configured at the **organization** via **`POST /api/v1/orgs/{org_id}/markup`** (see **Wallets**). |

***

## Wallets (credits, grants, ledger, org business model)

Base path: **`/api/v1/wallets`** (plus org-scoped helpers under **`/api/v1/orgs`** for business model / commission / markup).

| Method | Path                             | Purpose                                                                                                           |
| ------ | -------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| `GET`  | `/wallets/me`                    | Current user’s wallet summary (materialized balance, monthly cap usage when configured).                          |
| `GET`  | `/wallets/{wallet_id}`           | Wallet detail: grants, **append-only ledger**, upcoming expiry (access controlled by role and org scope).         |
| `GET`  | `/wallets/users`                 | List user wallets (**super\_admin**).                                                                             |
| `GET`  | `/wallets/orgs`                  | List organization wallets (**super\_admin**).                                                                     |
| `GET`  | `/wallets/orgs/{org_id}/members` | Member wallets in an organization (**org\_admin** or **super\_admin**).                                           |
| `POST` | `/wallets/{wallet_id}/grants`    | Assign credits (org admin transfers from org wallet; super admin creates grants as configured).                   |
| `POST` | `/wallets/{wallet_id}/cap`       | Set or clear **monthly spend cap** (USD) on a wallet.                                                             |
| `POST` | `/wallets/{wallet_id}/adjust`    | Super-admin-only ledger adjustment (no credit-grant row).                                                         |
| `POST` | `/orgs/{org_id}/business-model`  | Set `org_type`: `internal`, `channel_partner`, or `distributor` (**super\_admin**).                               |
| `POST` | `/orgs/{org_id}/commission`      | Set **commission** percentage for the org (**super\_admin**).                                                     |
| `POST` | `/orgs/{org_id}/markup`          | Set **markup** percentage and currency for reseller pricing (**org\_admin** of reseller org or **super\_admin**). |

Legacy organization billing routes such as **`/organizations/{id}/billing/assign-credits`** return **410 Gone**; use **`POST /api/v1/wallets/{wallet_id}/grants`** instead.

***

## Earnings (reseller markup and commission)

Base path: **`/api/v1/earnings`**

For **org\_admin** users whose organization is a **channel\_partner** or **distributor** (not `internal`):

| Method | Path                      | Purpose                                                                                                          |
| ------ | ------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| `GET`  | `/earnings/me`            | Summary for the caller’s org. Query: `period` = `day` \| `week` \| `month` \| `year` \| `all` (default `month`). |
| `GET`  | `/earnings/me/breakdown`  | Time-bucketed breakdown; same `period` query.                                                                    |
| `GET`  | `/earnings/orgs/{org_id}` | **Super\_admin** view of any org’s earnings summary; same `period` query.                                        |

***

## API keys — multiple keys, names, revoke

Base path: **`/api/v1/api-keys`**

| Method   | Path               | Purpose                                                                                                                                         |
| -------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `POST`   | `""`               | Create key. Body: `{ "api_key": "<secret>", "user_id": "<uuid>",  , "name": "optional label" }`. Response: `{ "message", "api_key": { ... } }`. |
| `GET`    | `/fetch/{user_id}` | List **active** keys for a user (same user or org-admin scope).                                                                                 |
| `POST`   | `/exists`          | Body `{ user_id, provider_name }` → `true` if any active key exists for that provider.                                                          |
| `PATCH`  | `/{key_id}`        | Body `{ "name": "new label" }` (empty string clears the label).                                                                                 |
| `DELETE` | `/{key_id}`        | **Revokes** the key (soft revoke); it stops working immediately.                                                                                |

The dashboard **API Keys** page supports multiple keys, optional names on create, rename, and revoke.

***

## Voice catalog — TTS voices

Base path: **`/api/v1/tts-voices`**

| Method | Path                      | Purpose                     |
| ------ | ------------------------- | --------------------------- |
| `GET`  | `""`                      | List all TTS voices.        |
| `POST` | `""`                      | Create a voice row.         |
| `GET`  | `/{voice_id}`             | Get by id.                  |
| `GET`  | `/provider/{provider_id}` | List voices for a provider. |

Use **`GET /api/v1/tts-voices`** (no trailing slash required).

***

For interactive request/response shapes, continue to use the **Voice Agent API** OpenAPI tab and [`kupe-voice-agent.openapi.yaml`](./kupe-voice-agent.openapi.yaml).
