REST API
The endpoints a developer key can use, with request and response examples, error formats and limits.
What you will achieve
You will read and change your workspace from code, and place an outbound call.
Base URL and authentication
Base URL: https://phynxa.com/api. All bodies are JSON. Authenticate with Authorization: Bearer nxa_live_... (see API keys).
Note. Examples below use values made up for illustration. Replace the key and ids with your own.
Endpoints a key can use
| Area | Endpoints |
|---|---|
| Agents | GET /agents, POST /agents, GET /agents/{id}, PATCH /agents/{id}, DELETE /agents/{id}, GET and PUT /agents/{id}/tools, GET and PUT /agents/{id}/knowledge |
| Calls | GET /calls, GET /calls/{id}, GET /calls/{id}/transcript, POST /calls/{id}/review, POST /calls/outbound |
| Contacts | GET /contacts, POST /contacts, POST /contacts/import, PATCH /contacts/{id}, DELETE /contacts/{id}, POST /contacts/{id}/call, POST /contacts/{id}/schedule |
| Scheduled calls | GET /scheduled-calls, DELETE /scheduled-calls/{id} |
| Campaigns | GET /campaigns, POST /campaigns, GET /campaigns/{id}, POST /campaigns/{id}/start, POST /campaigns/{id}/cancel, DELETE /campaigns/{id} |
| Tools | GET /tools, POST /tools, GET, PATCH and DELETE /tools/{id}, POST /tools/{id}/test |
| Knowledge | GET and POST /knowledge, GET, PATCH and DELETE /knowledge/{id}, documents, POST /knowledge/{id}/search |
| Webhooks | GET and POST /webhooks, GET, PATCH and DELETE /webhooks/{id}, PUT /webhooks/{id}/agents, GET /webhooks/{id}/deliveries, POST /webhooks/{id}/test |
| Forms and captures | /forms, /captures |
| Reports | GET /stats, GET /insights |
List agents
curl https://phynxa.com/api/agents -H "Authorization: Bearer nxa_live_YOUR_KEY"Returns a JSON array. One element (shortened):
{
"id": "c2997c6f-9d1c-41bb-9ba7-f2e3c6e2a648",
"name": "Reception Marina",
"description": "",
"language": "en",
"model": "openai:gpt-4o-mini",
"stt_provider": "deepgram-nova-3",
"tts_provider": "cartesia",
"voice": "a0e99841-438c-4a64-b679-ae501e7d6091",
"greeting": "Hello! How can I help you today?",
"temperature": 0.6,
"can_end_call": true,
"can_transfer_call": false,
"transfer_number": "",
"call_direction": "inbound",
"phone_number": "",
"active": true,
"webhook_id": "",
"timezone": "UTC",
"created_at": "2026-10-10T23:27:33.841629+00:00",
"updated_at": "2026-10-10T23:27:33.841629+00:00"
}active is true for a published agent. A few flags such as capture_enabled come back as 0 or 1.
Create and change an agent
curl -X POST https://phynxa.com/api/agents \
-H "Authorization: Bearer nxa_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "API example agent", "language": "en"}'Creating takes name (required), and optionally language (en, ur, hi, ar, fr, es, zh), timezone, template_id, business_name and template_inputs. The reply is the new agent. On the Free plan the new agent has active: false.
Change fields with PATCH. Only what you send changes, and unknown fields are rejected so a typo cannot pass silently:
curl -X PATCH https://phynxa.com/api/agents/AGENT_ID \
-H "Authorization: Bearer nxa_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"greeting": "Thanks for calling Acme. How can I help?", "temperature": 0.4}'Fields you can change include name, description, model (as provider:model, for example openai:gpt-4.1), system_prompt, greeting, stt_provider, tts_provider, voice, language, temperature, max_turn_seconds, idle_prompts, idle_message, can_end_call, can_transfer_call, transfer_number, phone_number, call_direction, webhook_id, capture_form_id, capture_enabled, call_summary_enabled, timezone, business_name, business_address, business_hours and active (publish or unpublish). timezone is the agent's clock only; business_address is what the agent gives as its location. DELETE /agents/{id} answers 204.
Place an outbound call
curl -X POST https://phynxa.com/api/calls/outbound \
-H "Authorization: Bearer nxa_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"agent_id": "AGENT_ID", "to_number": "+14155552671"}'On success you receive 202:
{ "call_sid": "CA0123456789abcdef0123456789abcdef", "to": "+14155552671" }The agent must be published and set to Outbound or Inbound / Outbound, and your workspace needs Twilio connected. Errors:
| Status | detail |
|---|---|
| 404 | Agent not found |
| 409 | This agent is paused, or That number belongs to a blocked contact. |
| 422 | This agent is inbound-only and cannot place calls., or Twilio's own message |
| 429 | Call limit reached. Try again later. |
Read calls and transcripts
GET /calls returns finished calls, newest first, up to 200. Each has id, agent_id, agent_name, started_at, ended_at, seconds, turns, direction, from_number, to_number, outcome, cost_usd and the review fields summary, intent, sentiment, outcome_label, score, action_items and entities, plus the cost breakdown (llm_cost_usd, stt_cost_usd, tts_cost_usd and so on).
GET /calls/{id} returns one call with its transcript and tool_calls. GET /calls/{id}/transcript returns just the lines, each with role (user or assistant), text and at.
GET /stats returns totals:
{
"agents": 4,
"active_agents": 3,
"calls": 29,
"minutes": 64.28,
"avg_call_seconds": 133.0,
"total_cost": 1.59,
"avg_cost_per_call": 0.0548,
"p95_latency_ms": 0.0
}Contacts
curl -X POST https://phynxa.com/api/contacts \
-H "Authorization: Bearer nxa_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "Sara K.", "phone_number": "+971501234567", "country_code": "AE", "timezone": "Asia/Dubai", "status": "lead"}'status is lead, customer, engaged or blocked. POST /contacts/import takes {"contacts": [ ... ]} of up to 5,000 rows with name, phone_number, country_code and timezone.
Webhooks
POST /webhooks with {"name": "CRM sync"} creates one; set its details with PATCH /webhooks/{id}, which accepts url, method, headers, secret, events, payload_fields, active, timeout_secs (up to 60) and retries (1 to 5):
curl -X PATCH https://phynxa.com/api/webhooks/WEBHOOK_ID \
-H "Authorization: Bearer nxa_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://yoursite.com/hooks/calls", "secret": "whsec_your_secret", "payload_fields": ["call", "review", "transcript"]}'POST /webhooks/{id}/test sends a sample and returns {"ok": true, "status_code": 200, "error": "", "duration_ms": 2}. The secret is never returned: responses show secret_configured.
Errors
Errors are JSON with a detail.
| Status | Meaning | Example |
|---|---|---|
| 401 | No or invalid key, or a path a key may not use | {"detail": "Sign in to continue."} |
| 403 | Not allowed for this role | |
| 404 | Not found, or not in your workspace | {"detail": "Agent not found"} |
| 409 | Conflict | {"detail": "This agent is paused"} |
| 413 | Request body over 25 MB | |
| 422 | Invalid input | A message string, or a list of problems (below) |
| 429 | Rate limit | {"detail": "Rate limit reached for this key."} |
A validation error lists each problem:
{
"detail": [
{
"type": "string_too_short",
"loc": ["body", "name"],
"msg": "String should have at least 1 character",
"input": "",
"ctx": { "min_length": 1 }
}
]
}Rate limits
| Limit | Value |
|---|---|
| Requests per key | 600 per minute |
| Outbound calls | 20 per person and 200 per workspace per hour |
| Webhook and tool test calls | 30 per minute |
| Knowledge upload and text | 30 per minute; web crawls 5 per minute; searches 60 per minute |
Testing
Run the list-agents example. Then create an agent and delete it again.
Expected result
JSON responses as shown, and 204 on deleting.
Troubleshooting
- 401 on every request. Check the
Bearerprefix and that the key was not revoked. - 422 "Extra inputs are not permitted". A field name is misspelled.
- 429. Slow down and retry after a pause.
Related guides
Something here does not match what you see in the dashboard? Let us know.
