API Reference
Resellers
One reseller API key works across every client workspace it reaches: your client list, usage and invoices per client, each client's agents, calls, conversations and contacts, and the changes you allow it. Every request names exactly one client.
Reseller keys
Bearer rk_…, created by the reseller's owners and admins in Settings → Reseller API keys. Workspace keys (sk_…) never reach another workspace.
One client per request
Name the client with the NuTalk-Client-Id header (REST) or the client_id argument (MCP). There is no default client.
Changes you allow
A key reads; with a write scope it also manages clients, their campaigns, their invoice settings and who on your team reaches them. Everything else happens in the dashboard.
Endpoints
/v1/reseller/meVerify a reseller keyGET/v1/reseller/clientsList clientsPOST/v1/reseller/clientsCreate a clientPATCH/v1/reseller/clients/:client_idUpdate a clientGET/v1/reseller/clients/:client_idGet a clientGET/v1/reseller/usageUsage per clientGET/v1/reseller/clients/:client_id/invoicesList a client's invoicesGET/v1/reseller/clients/:client_id/invoices/:invoice_idGet a client invoiceGET/v1/reseller/clients/:client_id/transactionsList a client's credit transactionsGET/v1/reseller/clients/:client_id/accessGet a client's team accessPATCH/v1/reseller/clients/:client_id/accessChange a client's team accessGET/v1/reseller/clients/:client_id/invoice-settingsGet a client's invoice settingsPATCH/v1/reseller/clients/:client_id/invoice-settingsUpdate a client's invoice settingsWhat a key reaches
On every request, a reseller key reaches only the clients that are in all three of these sets at that moment:
- the reseller's clients (a client that leaves the reseller drops out at once);
- the key's clients: all clients, including those added later, or a list chosen when the key was created;
- the clients its creator reaches: the reseller's owner reaches every client, an admin only the clients they were given access to. Removing that access, or the admin, takes effect on the next request. A key is revoked for good when its creator stops being an owner or admin of the reseller: promoting them back doesn't revive it.
A key also holds scopes: clients:read, billing:read and access:read for the reseller endpoints below (with their :write pair for changes), and the workspace read scopes (agents:read, calls:read, conversations:read, …) for what it may read inside each client. The same scopes apply to every client the key reaches; create one key per access level you need. Keys can expire, and any owner or admin can revoke one.
Clients never mix
Each client is a separate workspace. Only GET /v1/reseller/clients and GET /v1/reseller/usage span clients, and they return one row per client. Everything else answers about the one client the request names.
Reading a client's workspace
Every read endpoint of the API works for a client: send the reseller key and the client's id in the NuTalk-Client-Id header. The endpoint answers exactly as it would for that workspace's own key with the same scopes. Of the changes, only starting and pausing a campaign are open to a reseller key (with campaigns:write, and not in a suspended client); every other change is refused.
# YOUR_API_KEY: your reseller key (rk_…)# 1. The clients this key reachescurl "https://www.nutalk.ai/v1/reseller/clients" \ -H "Authorization: Bearer YOUR_API_KEY" # 2. One client's calls: any read endpoint, with the client's id in the headercurl "https://www.nutalk.ai/v1/calls?limit=5" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "NuTalk-Client-Id: CLIENT_ID"| Status | Code | When |
|---|---|---|
| 400 | client_id_required | A reseller key called a workspace endpoint without the NuTalk-Client-Id header. |
| 400 | invalid_client_id | The client id is not a UUID. |
| 400 | client_context_not_supported | A workspace key (sk_…) sent the NuTalk-Client-Id header. Workspace keys always act on their own workspace. |
| 403 | reseller_write_not_allowed | A reseller key tried a change it can't make in a client workspace (it may start and pause campaigns; everything else is read-only). |
| 409 | client_suspended | A change in a suspended client's workspace, other than pausing a campaign. Reactivate it first (PATCH /v1/reseller/clients/{client_id}). |
| 403 | issuer_inactive | The member who created the key is no longer an owner or admin of the reseller. |
| 403 | reseller_suspended | The reseller workspace is suspended. |
| 404 | client_not_found | The key does not reach that client: another reseller's client, a client off the key's list or outside its creator's grants, or an id that does not exist. |
Managing clients
With clients:write, a key creates clients (POST /v1/reseller/clients) and renames, re-slugs, suspends or reactivates them (PATCH /v1/reseller/clients/{client_id}), with the same rules as the dashboard. Only a key the reseller's owner created can create clients, as only the owner can in the dashboard. Portal logins are made in the dashboard.
With billing:write, a key sets who you bill for a client and on which terms (PATCH /v1/reseller/clients/{client_id}/invoice-settings). With access:read and access:write, a key the owner created sees and changes which members of your team reach a client (/v1/reseller/clients/{client_id}/access), as the client's Access tab does.
A suspended client keeps its data and stays readable, but its workspace refuses changes until you reactivate it, except pausing a campaign, which stops work and so stays possible. Its campaigns and queued outbound calls stop where they are (calls in progress finish) and resume when you reactivate it. Every change is recorded in the audit log under the key (api-key:rk_…), and changes are rate limited per reseller. Send an Idempotency-Key to retry safely.
MCP server
AI assistants connect to https://www.nutalk.ai/v1/reseller/mcp with the reseller key as a Bearer token (Streamable HTTP, stateless). Tools appear only for the scopes the key holds. The client tools are the workspace server's read tools, each with a required client_id.
claude mcp add --transport http nutalk-reseller https://www.nutalk.ai/v1/reseller/mcp --header "Authorization: Bearer YOUR_API_KEY"| Tool | What it returns | Scope |
|---|---|---|
| whoami | Verify this reseller API key and return its reseller, its scopes, whether it reaches every client or a list, and how many clients it reaches now. Needs no scope. | none |
| list_clients | List the reseller's client workspaces this key reaches (id, name, slug, status), by name. Use an id from here as client_id in every other tool. | clients:read |
| get_client | Get one client: its workspace (name, slug, status, timezone) and the contact details the reseller keeps for it. | clients:read |
| get_usage_summary | Usage per client in a window (default: this UTC month so far, at most 92 days): calls that started, their seconds, the charges on each client's own ledger at your retail prices (client_charges) and the draws on your pool tagged with it at platform cost (pool_draws), never added together. One row per client; pass client_id for one client. Also returns the pool's balance. Credit fields are whole credits (a sum drops its fraction, a balance is rounded down); each has an *_exact twin with up to 2 decimals. | billing:read |
| list_client_invoices | List the invoices the reseller issued to one client, newest first. | billing:read |
| get_client_invoice | Get one invoice of one client with its quantities, rates and costs. | billing:read |
| list_client_transactions | List one client's credit rows from both ledgers (its own charges, and the reseller's rows tagged with it), newest first, each marked with its ledger; optionally within from/to. amount is whole credits (its fraction dropped); amount_exact has up to 2 decimals. | billing:read |
| get_client_access | List the reseller's team members other than its owners (who reach every client), and whether each reaches one client. Only keys the reseller's owner created. | access:read |
| get_client_invoice_settings | Get who the reseller bills for one client and on which terms. An empty term (null) falls back to the reseller's default, also returned. | billing:read |
| list_agents, get_agent, list_channels, get_channel, list_contacts, get_contact, list_contact_lists, get_contact_list, list_calls, get_call, get_call_job, list_conversations, get_conversation, list_conversation_messages, list_campaigns, get_campaign, list_campaign_enrollments, list_goals, get_goal, list_competencies, get_competency, list_webhooks, get_webhook, list_contact_fields, get_contact_field, get_contact_import, get_contact_import_rejects, list_clinic_locations, get_clinic_location, list_clinic_rooms, get_clinic_room, list_clinic_doctors, get_clinic_doctor, get_clinic_doctor_weekly_hours, list_clinic_doctor_days_off, list_clinic_services, get_clinic_service, get_clinic_settings, list_clinic_appointments, get_clinic_appointment, list_business_hosts, get_business_host, list_business_host_availability, list_business_host_days_off, list_business_closures, list_business_meeting_types, get_business_meeting_type, list_business_host_calendar_connections, list_business_appointments, get_business_appointment, list_test_scenarios, get_test_scenario, list_test_runs, get_test_run, list_knowledge_sources, get_knowledge_source | The workspace read tools, run in the one client named by client_id. | The workspace scope of each tool |
| create_client | Ask to create a client workspace (name, slug, contact email). Nothing is created until an owner or admin of the reseller approves it in NuTalk; only keys the reseller's owner created may ask. | clients:write |
| update_client | Ask to rename, re-slug, suspend or reactivate one client (client_id). Nothing changes until an owner or admin of the reseller approves it in NuTalk. | clients:write |
| update_client_access | Ask to give team members access to one client (grant) or take it from them (revoke), by the member_id get_client_access returns. Nothing changes until the reseller's owner approves it in NuTalk; only keys the owner created may ask. | access:write |
| update_client_invoice_settings | Ask to change who the reseller bills for one client and on which terms: only the fields sent change, and null clears one or returns a term to the reseller's default. Nothing changes until an owner or admin of the reseller approves it in NuTalk. | billing:write |
| get_change_request | Whether a change this key asked for is pending, approved and made (with its result), failed, rejected or expired. | none |
Changes through MCP wait for a person
Messages, transcripts, contact notes and agent instructions come from your clients and their customers, and an assistant reads them, so a line written there could make it ask for a change. That is why the change tools (create_client, update_client, update_client_invoice_settings and update_client_access) appear only for a key created with “Let AI assistants ask for client changes over MCP”, and never change anything themselves: each one records a request that an owner or admin approves or rejects in Settings → API keys → Changes waiting for approval (it expires after 24 hours). A key can have 20 requests waiting at once and your workspace 1000; past that, the tool answers too_many_pending until some are decided. Client creation and team access are approved by the owner. Approving makes the change once, after checking the key and your access again. The REST API is not gated: your own programs call it directly.
Verify a reseller key
/v1/reseller/meReturns the reseller key's reseller, its scopes, whether it reaches every client or a list, and how many clients it reaches right now.
none (any valid key)Example request
curl -X GET "https://www.nutalk.ai/v1/reseller/me" \ -H "Authorization: Bearer YOUR_API_KEY"The key and what it reaches.
{
"success": true,
"data": {
"authenticated": true,
"api_key": {
"id": "7b7a0ce4-0000-4000-8000-000000000001",
"name": "Agency dashboard",
"prefix": "rk_3f9a1c2e",
"scopes": [
"clients:read",
"billing:read",
"agents:read",
"calls:read"
],
"client_access": "all",
"expires_at": null
},
"reseller": {
"id": "0b1c2d3e-4f50-4617-8293-a4b5c6d7e8f9",
"name": "Agencia Delta",
"slug": "agencia-delta"
},
"clients_reachable": 12,
"verified_at": "2026-10-02T18:00:00.000Z"
}
}Errors
| Status | Code | When |
|---|---|---|
| 403 | issuer_inactive | The member who created the key is no longer an owner or admin of the reseller. |
| 403 | reseller_suspended | The reseller workspace is suspended. |
Plus the errors every request can return (401, 403, 429, 500): Errors.
List clients
/v1/reseller/clientsThe reseller's client workspaces this key reaches, by name. Each row is the client itself, never data from inside its workspace.
clients:readQuery parameters
| Name | Type | Description |
|---|---|---|
limit | integer | Results per page. 1–100. Default: |
offset | integer | Results to skip. At least 0. Default: |
status | string | Only clients in this status. One of: trialing, active, suspended. |
search | string | Part of the client's name or slug. Up to 100 characters. |
Example request
curl -X GET "https://www.nutalk.ai/v1/reseller/clients?status=active" \ -H "Authorization: Bearer YOUR_API_KEY"One page of clients.
{
"success": true,
"data": [
{
"id": "1c2d3e4f-5061-4728-93a4-b5c6d7e8f901",
"name": "Clínica Norte",
"slug": "clinica-norte",
"status": "active",
"created_at": "2026-09-01T16:00:00.000Z"
}
],
"pagination": {
"total": 1,
"limit": 20,
"offset": 0,
"has_more": false
}
}Errors
| Status | Code | When |
|---|---|---|
| 400 | validation_error | A query parameter is invalid (details.errors lists each one). |
Plus the errors every request can return (401, 403, 429, 500): Errors.
Create a client
/v1/reseller/clientsCreates a client workspace under the reseller, as the dashboard's Add client does without a portal login (portal logins are made in the dashboard). Like the dashboard, only the reseller's owner creates clients: the key must have been created by the owner. A key limited to a list of clients does not reach the new one until it is added to its list.
clients:writeSupports Idempotency-KeyRequest body (JSON)
| Name | Type | Description |
|---|---|---|
nameRequired | string | The client's name. 2–100 characters. |
slugRequired | string | Lowercase letters, numbers and inner hyphens; unique across NuTalk. 2–63 characters. |
contact_emailRequired | string | The client's contact, who gets suspension notices. Up to 320 characters. |
Example request
curl -X POST "https://www.nutalk.ai/v1/reseller/clients" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Idempotency-Key: 11111111-2222-4333-8444-555555555555" \ -H "Content-Type: application/json" \ -d '{ "name": "Clínica Norte", "slug": "clinica-norte", "contact_email": "admin@clinicanorte.example"}'The new client.
{
"success": true,
"data": {
"id": "1c2d3e4f-5061-4728-93a4-b5c6d7e8f901",
"name": "Clínica Norte",
"slug": "clinica-norte",
"status": "active"
}
}Errors
| Status | Code | When |
|---|---|---|
| 400 | validation_error | A field is missing or invalid (details.errors). |
| 403 | forbidden | The key lacks clients:write, or its creator is not the reseller's owner. |
| 409 | slug_in_use | Another workspace already uses this slug. |
Plus the errors every request can return (401, 403, 429, 500): Errors.
Update a client
/v1/reseller/clients/:client_idRenames, re-slugs, suspends or reactivates one client: the dashboard's client Settings change, with the same rules. A suspended client keeps its data and stays readable; its workspace refuses changes made with a reseller key until it is reactivated, except pausing a campaign. Its campaigns and queued outbound calls stop where they are (calls in progress finish) and resume when it is reactivated.
clients:writeSupports Idempotency-KeyPath parameters
| Name | Type | Description |
|---|---|---|
client_idRequired | uuid | The client's id (from GET /reseller/clients). |
Request body (JSON)
| Name | Type | Description |
|---|---|---|
name | string | The client's name. 2–100 characters. |
slug | string | A new slug (same rule as on create). 2–63 characters. |
status | string | Suspend or reactivate. One of: active, suspended. |
notify_client | boolean | With status suspended: email the client's contact once. |
reason | string | The reason in that email. Up to 500 characters. |
Example request
curl -X PATCH "https://www.nutalk.ai/v1/reseller/clients/1c2d3e4f-5061-4728-93a4-b5c6d7e8f901" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Idempotency-Key: 11111111-2222-4333-8444-555555555555" \ -H "Content-Type: application/json" \ -d '{ "status": "suspended", "notify_client": true, "reason": "Unpaid invoice DELTA-2026-0042"}'The client as stored, and whether the suspension email went out (null when none was asked for).
{
"success": true,
"data": {
"id": "1c2d3e4f-5061-4728-93a4-b5c6d7e8f901",
"name": "Clínica Norte",
"slug": "clinica-norte",
"status": "suspended",
"email_sent": true
}
}Errors
| Status | Code | When |
|---|---|---|
| 400 | validation_error | Nothing to update, or a field is invalid. |
| 400 | invalid_client_id | The client id is not a UUID. |
| 404 | client_not_found | No client of this reseller with this id is reachable with this key: another reseller's client, a client off the key's list or outside its creator's grants, and ids that do not exist all answer the same. |
| 409 | slug_in_use | Another workspace already uses this slug. |
| 409 | already_suspended | A notified suspension raced another one: the client was suspended a moment ago. |
Plus the errors every request can return (401, 403, 429, 500): Errors.
Get a client
/v1/reseller/clients/:client_idOne client: its workspace (name, slug, status, timezone) and the contact details the reseller keeps for it.
clients:readPath parameters
| Name | Type | Description |
|---|---|---|
client_idRequired | uuid | The client's id (from GET /reseller/clients). |
Example request
curl -X GET "https://www.nutalk.ai/v1/reseller/clients/1c2d3e4f-5061-4728-93a4-b5c6d7e8f901" \ -H "Authorization: Bearer YOUR_API_KEY"The client.
{
"success": true,
"data": {
"id": "1c2d3e4f-5061-4728-93a4-b5c6d7e8f901",
"name": "Clínica Norte",
"slug": "clinica-norte",
"status": "active",
"created_at": "2026-09-01T16:00:00.000Z",
"timezone": "America/Monterrey",
"contact": {
"email": "admin@clinicanorte.example",
"phone": "+528112345678",
"website": "https://clinicanorte.example",
"billing_email": "facturas@clinicanorte.example",
"billing_reminder_days": 5,
"notes": null
}
}
}Errors
| Status | Code | When |
|---|---|---|
| 400 | invalid_client_id | The client id is not a UUID. |
| 404 | client_not_found | No client of this reseller with this id is reachable with this key: another reseller's client, a client off the key's list or outside its creator's grants, and ids that do not exist all answer the same. |
Plus the errors every request can return (401, 403, 429, 500): Errors.
Usage per client
/v1/reseller/usageUsage per client in a window: calls that started and their seconds, and two credit sums at different prices, never added together. client_charges are the charges on the client's own ledger at your retail prices (calls and replies; what invoices bill). pool_draws are the rows on your pool tagged with the client, at platform cost (pool deductions and the platform cost of replies); a call's pool debit has no ledger row, so calls are missing from it. Each has a by-type breakdown. Debits only; refunds show in the client's transactions. One row per client, in the order of GET /reseller/clients; pass client_id for one client. pool is your own credit balance.
billing:readCredits keep 2 decimals (1 credit = 1 MXN; a price can be 5.5 credits a minute or 0.75 a message). Every credit field keeps its whole-number type: a charge or a sum drops its fraction (16.5 reads 16), a balance is rounded down (-0.25 reads -1), so nothing reads larger than it is. Each has an _exact twin with the exact amount (a number with up to 2 decimals: 16.5 is 16.50 credits).
Query parameters
| Name | Type | Description |
|---|---|---|
from | datetime | Start of the window, inclusive (ISO 8601). Default: the start of the current UTC month. |
to | datetime | End of the window, exclusive. Default: now. The window spans at most 92 days. |
client_id | uuid | Only this client. |
limit | integer | Results per page. 1–100. Default: |
offset | integer | Results to skip. At least 0. Default: |
Example request
curl -X GET "https://www.nutalk.ai/v1/reseller/usage?from=2026-09-01T00:00:00Z&to=2026-10-01T00:00:00Z" \ -H "Authorization: Bearer YOUR_API_KEY"One page of clients with their usage.
{
"success": true,
"data": [
{
"client": {
"id": "1c2d3e4f-5061-4728-93a4-b5c6d7e8f901",
"name": "Clínica Norte",
"status": "active"
},
"calls": 412,
"call_seconds": 51840,
"client_charges": 2455,
"client_charges_exact": 2455.5,
"client_charges_by_type": {
"usage_voice_answered": {
"transactions": 380,
"credits": 2160,
"credits_exact": 2160
},
"usage_whatsapp": {
"transactions": 185,
"credits": 295,
"credits_exact": 295.5
}
},
"pool_draws": 138,
"pool_draws_exact": 138.75,
"pool_draws_by_type": {
"usage_whatsapp": {
"transactions": 185,
"credits": 138,
"credits_exact": 138.75
}
}
}
],
"period": {
"from": "2026-09-01T00:00:00.000Z",
"to": "2026-10-01T00:00:00.000Z"
},
"pool": {
"credits_available": 48210,
"credit_balance": 48210,
"credits_available_exact": 48210.5,
"credit_balance_exact": 48210.5
},
"pagination": {
"total": 1,
"limit": 20,
"offset": 0,
"has_more": false
}
}Errors
| Status | Code | When |
|---|---|---|
| 400 | validation_error | from or to is not an ISO 8601 date-time, from is not before to, or the window is longer than 92 days. |
| 400 | invalid_client_id | The client id is not a UUID. |
| 404 | client_not_found | No client of this reseller with this id is reachable with this key: another reseller's client, a client off the key's list or outside its creator's grants, and ids that do not exist all answer the same. |
Plus the errors every request can return (401, 403, 429, 500): Errors.
List a client's invoices
/v1/reseller/clients/:client_id/invoicesThe invoices the reseller issued to one client, newest first.
billing:readPath parameters
| Name | Type | Description |
|---|---|---|
client_idRequired | uuid | The client's id (from GET /reseller/clients). |
Query parameters
| Name | Type | Description |
|---|---|---|
limit | integer | Results per page. 1–100. Default: |
offset | integer | Results to skip. At least 0. Default: |
status | string | Only invoices in this status. One of: draft, sent, paid, cancelled. |
Example request
curl -X GET "https://www.nutalk.ai/v1/reseller/clients/1c2d3e4f-5061-4728-93a4-b5c6d7e8f901/invoices" \ -H "Authorization: Bearer YOUR_API_KEY"One page of invoices.
{
"success": true,
"data": [
{
"id": "3e4f5061-7283-494a-b5c6-d7e8f9011223",
"invoice_number": "DELTA-2026-0042",
"status": "sent",
"period_start": "2026-09-01T00:00:00.000Z",
"period_end": "2026-09-30T23:59:59.000Z",
"total_amount": 4890,
"currency": "MXN",
"created_at": "2026-10-01T15:00:00.000Z",
"sent_at": "2026-10-01T15:05:00.000Z",
"paid_at": null
}
],
"pagination": {
"total": 1,
"limit": 20,
"offset": 0,
"has_more": false
}
}Errors
| Status | Code | When |
|---|---|---|
| 400 | validation_error | A query parameter is invalid (details.errors lists each one). |
| 400 | invalid_client_id | The client id is not a UUID. |
| 404 | client_not_found | No client of this reseller with this id is reachable with this key: another reseller's client, a client off the key's list or outside its creator's grants, and ids that do not exist all answer the same. |
Plus the errors every request can return (401, 403, 429, 500): Errors.
Get a client invoice
/v1/reseller/clients/:client_id/invoices/:invoice_idOne invoice of one client, with its quantities, rates and costs per channel.
billing:readPath parameters
| Name | Type | Description |
|---|---|---|
client_idRequired | uuid | The client's id (from GET /reseller/clients). |
invoice_idRequired | uuid | The invoice id. |
Example request
curl -X GET "https://www.nutalk.ai/v1/reseller/clients/1c2d3e4f-5061-4728-93a4-b5c6d7e8f901/invoices/3e4f5061-7283-494a-b5c6-d7e8f9011223" \ -H "Authorization: Bearer YOUR_API_KEY"200 The invoice.
Errors
| Status | Code | When |
|---|---|---|
| 400 | invalid_client_id | The client id is not a UUID. |
| 404 | client_not_found | No client of this reseller with this id is reachable with this key: another reseller's client, a client off the key's list or outside its creator's grants, and ids that do not exist all answer the same. |
| 404 | not_found | No such invoice for this client. |
Plus the errors every request can return (401, 403, 429, 500): Errors.
List a client's credit transactions
/v1/reseller/clients/:client_id/transactionsOne client's credit rows from both ledgers, newest first: the client's own (a call's or a reply's charge) and the reseller's rows tagged with the client (pool deductions, refunds, and the platform-cost twin of a reply, marked platform_charge). ledger says which ledger a row is in. Without from/to, every row.
billing:readCredits keep 2 decimals (1 credit = 1 MXN; a price can be 5.5 credits a minute or 0.75 a message). Every credit field keeps its whole-number type: a charge or a sum drops its fraction (16.5 reads 16), a balance is rounded down (-0.25 reads -1), so nothing reads larger than it is. Each has an _exact twin with the exact amount (a number with up to 2 decimals: 16.5 is 16.50 credits).
Path parameters
| Name | Type | Description |
|---|---|---|
client_idRequired | uuid | The client's id (from GET /reseller/clients). |
Query parameters
| Name | Type | Description |
|---|---|---|
from | datetime | Start of the window, inclusive (ISO 8601). Default: the start of the current UTC month. |
to | datetime | End of the window, exclusive. Default: now. The window spans at most 92 days. |
limit | integer | Results per page. 1–100. Default: |
offset | integer | Results to skip. At least 0. Default: |
Example request
curl -X GET "https://www.nutalk.ai/v1/reseller/clients/1c2d3e4f-5061-4728-93a4-b5c6d7e8f901/transactions" \ -H "Authorization: Bearer YOUR_API_KEY"One page of transactions.
{
"success": true,
"data": [
{
"id": "4f506172-8394-4a5b-c6d7-e8f901122334",
"type": "usage_voice_answered",
"amount": -16,
"amount_exact": -16.5,
"description": "Voice call (3 min)",
"reference_type": "call",
"reference_id": "1ba11348-e440-44de-a5cd-5fe62f4d9df6",
"created_at": "2026-10-02T17:42:10.000Z",
"ledger": "client",
"platform_charge": false
}
],
"pagination": {
"total": 1,
"limit": 20,
"offset": 0,
"has_more": false
}
}Errors
| Status | Code | When |
|---|---|---|
| 400 | validation_error | A query parameter is invalid, or the from/to window is longer than 92 days. |
| 400 | invalid_client_id | The client id is not a UUID. |
| 404 | client_not_found | No client of this reseller with this id is reachable with this key: another reseller's client, a client off the key's list or outside its creator's grants, and ids that do not exist all answer the same. |
Plus the errors every request can return (401, 403, 429, 500): Errors.
Get a client's team access
/v1/reseller/clients/:client_id/accessThe reseller's team members other than its owners (who reach every client), and whether each reaches this client. Only keys the reseller's owner created: in the dashboard only the owner sees and changes this.
access:readPath parameters
| Name | Type | Description |
|---|---|---|
client_idRequired | uuid | The client's id (from GET /reseller/clients). |
Example request
curl -X GET "https://www.nutalk.ai/v1/reseller/clients/1c2d3e4f-5061-4728-93a4-b5c6d7e8f901/access" \ -H "Authorization: Bearer YOUR_API_KEY"The team, each member with their access to this client.
{
"success": true,
"data": {
"client": {
"id": "1c2d3e4f-5061-4728-93a4-b5c6d7e8f901",
"name": "Clínica Norte"
},
"members": [
{
"member_id": "5a617283-94a5-4b6c-97d8-e9f012233445",
"user_id": "6b728394-a5b6-4c7d-88e9-f01223344556",
"role": "admin",
"email": "ana@agencia.example",
"name": "Ana Treviño",
"has_access": true,
"granted_at": "2026-09-15T15:00:00.000Z"
},
{
"member_id": "7c8394a5-b6c7-4d8e-99f0-012233445566",
"user_id": "8d94a5b6-c7d8-4e9f-a001-122334455667",
"role": "builder",
"email": "luis@agencia.example",
"name": "Luis Garza",
"has_access": false,
"granted_at": null
}
]
}
}Errors
| Status | Code | When |
|---|---|---|
| 403 | forbidden | The key was not created by the reseller's owner (only the owner manages team access). |
| 400 | invalid_client_id | The client id is not a UUID. |
| 404 | client_not_found | No client of this reseller with this id is reachable with this key: another reseller's client, a client off the key's list or outside its creator's grants, and ids that do not exist all answer the same. |
Plus the errors every request can return (401, 403, 429, 500): Errors.
Change a client's team access
/v1/reseller/clients/:client_id/accessGives team members access to this client (grant) and takes it from others (revoke), as the dashboard's client Access tab does. Every id must be a member of the reseller other than an owner, or nothing changes. Granting a member who has access, or revoking one who has none, changes nothing. Only keys the reseller's owner created.
access:writeSupports Idempotency-KeyPath parameters
| Name | Type | Description |
|---|---|---|
client_idRequired | uuid | The client's id (from GET /reseller/clients). |
Request body (JSON)
| Name | Type | Description |
|---|---|---|
grant | uuid[] | member_id values (from GET …/access) to give access to. 0–100 items. |
revoke | uuid[] | member_id values to take access from. 0–100 items. |
Example request
curl -X PATCH "https://www.nutalk.ai/v1/reseller/clients/1c2d3e4f-5061-4728-93a4-b5c6d7e8f901/access" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Idempotency-Key: 11111111-2222-4333-8444-555555555555" \ -H "Content-Type: application/json" \ -d '{ "grant": [ "7c8394a5-b6c7-4d8e-99f0-012233445566" ]}'With access:read, the team as GET answers it, after the change. A key without access:read gets back only the member ids it granted and revoked (client.id, granted, revoked).
{
"success": true,
"data": {
"client": {
"id": "1c2d3e4f-5061-4728-93a4-b5c6d7e8f901",
"name": "Clínica Norte"
},
"members": [
{
"member_id": "5a617283-94a5-4b6c-97d8-e9f012233445",
"user_id": "6b728394-a5b6-4c7d-88e9-f01223344556",
"role": "admin",
"email": "ana@agencia.example",
"name": "Ana Treviño",
"has_access": true,
"granted_at": "2026-09-15T15:00:00.000Z"
},
{
"member_id": "7c8394a5-b6c7-4d8e-99f0-012233445566",
"user_id": "8d94a5b6-c7d8-4e9f-a001-122334455667",
"role": "builder",
"email": "luis@agencia.example",
"name": "Luis Garza",
"has_access": true,
"granted_at": "2026-10-02T18:00:00.000Z"
}
]
}
}Errors
| Status | Code | When |
|---|---|---|
| 400 | validation_error | Neither list names a member, an id is in both, or an id is not a UUID. |
| 400 | invalid_member_ids | An id is not a member of the reseller's team, or is an owner. |
| 403 | forbidden | The key was not created by the reseller's owner (only the owner manages team access). |
| 400 | invalid_client_id | The client id is not a UUID. |
| 404 | client_not_found | No client of this reseller with this id is reachable with this key: another reseller's client, a client off the key's list or outside its creator's grants, and ids that do not exist all answer the same. |
Plus the errors every request can return (401, 403, 429, 500): Errors.
Get a client's invoice settings
/v1/reseller/clients/:client_id/invoice-settingsWho the reseller bills for this client and on which terms. Until they are saved once, the values invoices use (customized false). An empty term (null) falls back to the reseller's default, in reseller_defaults.
billing:readPath parameters
| Name | Type | Description |
|---|---|---|
client_idRequired | uuid | The client's id (from GET /reseller/clients). |
Example request
curl -X GET "https://www.nutalk.ai/v1/reseller/clients/1c2d3e4f-5061-4728-93a4-b5c6d7e8f901/invoice-settings" \ -H "Authorization: Bearer YOUR_API_KEY"The client's invoice settings.
{
"success": true,
"data": {
"client": {
"id": "1c2d3e4f-5061-4728-93a4-b5c6d7e8f901",
"name": "Clínica Norte"
},
"customized": true,
"settings": {
"billing_company_name": "Clínica Norte S.A. de C.V.",
"billing_contact_name": "Laura Garza",
"billing_email": "facturas@clinicanorte.example",
"billing_address_line1": "Av. Constitución 100",
"billing_address_line2": null,
"billing_city": "Monterrey",
"billing_state": "Nuevo León",
"billing_postal_code": "64000",
"billing_country": "Mexico",
"billing_tax_id": "CNO200101AB1",
"currency": null,
"payment_terms": "net_30",
"tax_rate": null,
"custom_notes": null
},
"reseller_defaults": {
"currency": "MXN",
"payment_terms": "net_15",
"tax_rate": 0.16
},
"updated_at": "2026-10-02T18:00:00.000Z"
}
}Errors
| Status | Code | When |
|---|---|---|
| 400 | invalid_client_id | The client id is not a UUID. |
| 404 | client_not_found | No client of this reseller with this id is reachable with this key: another reseller's client, a client off the key's list or outside its creator's grants, and ids that do not exist all answer the same. |
Plus the errors every request can return (401, 403, 429, 500): Errors.
Update a client's invoice settings
/v1/reseller/clients/:client_id/invoice-settingsSets the fields sent, as the client's Settings → Invoices form saves them; the others keep their value. null clears a field, or returns currency, payment_terms or tax_rate to the reseller's default.
billing:writeSupports Idempotency-KeyPath parameters
| Name | Type | Description |
|---|---|---|
client_idRequired | uuid | The client's id (from GET /reseller/clients). |
Request body (JSON)
| Name | Type | Description |
|---|---|---|
billing_company_name | string | null | The company invoices are made out to (the client's name until set). Up to 200 characters. |
billing_contact_name | string | null | The person invoices are addressed to. Up to 200 characters. |
billing_email | string | null | Where invoices go. |
billing_address_line1 | string | null | Address, first line. Up to 200 characters. |
billing_address_line2 | string | null | Address, second line. Up to 200 characters. |
billing_city | string | null | City. Up to 100 characters. |
billing_state | string | null | State. Up to 100 characters. |
billing_postal_code | string | null | Postal code. Up to 20 characters. |
billing_country | string | null | Country (Mexico until set). Up to 100 characters. |
billing_tax_id | string | null | The client's tax id (RFC in Mexico). Up to 50 characters. |
currency | string | null | null: the reseller's default. One of: MXN, USD, EUR. |
payment_terms | string | null | null: the reseller's default. One of: due_on_receipt, net_15, net_30. |
tax_rate | number | null | A fraction: 0.16 is 16%. null: the reseller's default. 0–1. |
custom_notes | string | null | A note printed on this client's invoices. Up to 2000 characters. |
Example request
curl -X PATCH "https://www.nutalk.ai/v1/reseller/clients/1c2d3e4f-5061-4728-93a4-b5c6d7e8f901/invoice-settings" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Idempotency-Key: 11111111-2222-4333-8444-555555555555" \ -H "Content-Type: application/json" \ -d '{ "billing_email": "facturas@clinicanorte.example", "payment_terms": "net_30"}'With billing:read, the client's invoice settings as GET answers them. A key without billing:read gets back only the fields it sent, as stored (client.id, settings, updated_at).
{
"success": true,
"data": {
"client": {
"id": "1c2d3e4f-5061-4728-93a4-b5c6d7e8f901",
"name": "Clínica Norte"
},
"customized": true,
"settings": {
"billing_company_name": "Clínica Norte S.A. de C.V.",
"billing_contact_name": "Laura Garza",
"billing_email": "facturas@clinicanorte.example",
"billing_address_line1": "Av. Constitución 100",
"billing_address_line2": null,
"billing_city": "Monterrey",
"billing_state": "Nuevo León",
"billing_postal_code": "64000",
"billing_country": "Mexico",
"billing_tax_id": "CNO200101AB1",
"currency": null,
"payment_terms": "net_30",
"tax_rate": null,
"custom_notes": null
},
"reseller_defaults": {
"currency": "MXN",
"payment_terms": "net_15",
"tax_rate": 0.16
},
"updated_at": "2026-10-02T18:00:00.000Z"
}
}Errors
| Status | Code | When |
|---|---|---|
| 400 | validation_error | Nothing to update, an unknown field, or a value that is not allowed. |
| 400 | invalid_client_id | The client id is not a UUID. |
| 404 | client_not_found | No client of this reseller with this id is reachable with this key: another reseller's client, a client off the key's list or outside its creator's grants, and ids that do not exist all answer the same. |
Plus the errors every request can return (401, 403, 429, 500): Errors.