API Reference
Fynex provides a REST API for programmatic access. All endpoints require authentication via a Supabase JWT token passed in the Authorization: Bearer <token> header.
Base URL:
- Development:
http://localhost:3001 - Production:
https://api.fynex.solutions
Dispatch
Send Email
POST /api/dispatch/email| Parameter | Type | Required | Description |
|---|---|---|---|
account_id | UUID | Yes | Target account |
template_id | UUID | No | Message template to use |
action_type | string | No | Action type (default: reminder) |
Responses: 200 Email sent, 401 Unauthorized, 422 Dispatch blocked.
Send SMS
POST /api/dispatch/sms| Parameter | Type | Required | Description |
|---|---|---|---|
account_id | UUID | Yes | Target account |
template_id | UUID | No | Message template to use |
action_type | string | No | Action type (default: reminder) |
Responses: 200 SMS sent, 422 Dispatch blocked.
Send WhatsApp
POST /api/dispatch/whatsapp| Parameter | Type | Required | Description |
|---|---|---|---|
account_id | UUID | Yes | Target account |
template_id | UUID | No | Message template to use |
action_type | string | No | Action type (default: reminder) |
Responses: 200 WhatsApp message sent, 422 Dispatch blocked.
Initiate Voice Call
POST /api/dispatch/voice| Parameter | Type | Required | Description |
|---|---|---|---|
account_id | UUID | Yes | Target account |
agent_type | string | No | ai (default) or human |
supervisor_user_id | UUID | No | User ID for supervised calls |
voice_opening_mode | string | No | AI only: inherit (default), callee_first, or agent_first. Ignored when agent_type is human. |
Responses: 200 Call initiated (includes call_sid and conversation_id), 422 Dispatch blocked, 502 Provider error.
Dispatch Validation
All dispatch endpoints enforce these rules before sending:
- Opt-out — Blocked if the contact has opted out.
- Frequency limits — Blocked if max contacts per day/week would be exceeded.
- Allowed hours — Blocked if outside the organization's configured contact hours.
- Account paused — Blocked if the account status is
paused.
When blocked, the response includes { "blocked": true, "error": "reason" }.
Admin
Phone Numbers
POST /api/admin/phone-numbers| Parameter | Type | Required | Description |
|---|---|---|---|
action | string | Yes | search, buy, or release |
country | string | No | Country code for search |
areaCode | string | No | Area code for search |
phoneNumber | string | No | Number to buy or release |
organizationId | UUID | No | Organization to assign |
channelConfigId | UUID | No | Channel config to update |
Email Domains
POST /api/admin/email-domains| Parameter | Type | Required | Description |
|---|---|---|---|
action | string | Yes | create or verify |
domain | string | No | Domain name |
organizationId | UUID | No | Organization |
channelConfigId | UUID | No | Channel config |
ElevenLabs Agent
POST /api/admin/elevenlabs-agent| Parameter | Type | Required | Description |
|---|---|---|---|
action | string | Yes | provision, status, or set_agent_id |
organizationId | UUID | No | Organization (usually inferred from auth) |
agent_id | string | For set_agent_id | ElevenLabs agent ID to store on the voice channel |
provision creates or updates the ConvAI agent and, when a Twilio number is configured but no ElevenLabs phone ID exists yet, registers the number with ElevenLabs automatically. Response may include phone_number_id.
set_agent_id is intended for self-managed orgs that bring their own agent ID.
Voice configuration
GET /api/admin/voice-config
PATCH /api/admin/voice-configGET returns current defaults: llm, voice_id, voices (per-language map), voice_opening_mode, agent_id, org_language, supported_llms, curated_voices.
PATCH updates organization and voice channel config in one request. Send at least one field:
| Field | Type | Description |
|---|---|---|
llm | string | Conversational AI LLM id (validated against supported list) |
voice_id | string | Default ElevenLabs voice for the org’s primary language |
voices | object | Map of language code → ElevenLabs voice id |
voice_opening_mode | string | callee_first or agent_first |
agent_id | string | ElevenLabs agent id (e.g. self-managed) |
Campaigns
Create Campaign
POST /api/admin/campaigns| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Campaign name (1-200 chars) |
objective | string | No | Campaign objective (max 1000 chars) |
strategy_id | UUID | No | Strategy to assign (required to activate) |
status | string | No | Initial status (default: draft) |
start_date | string | No | Start date (YYYY-MM-DD) |
end_date | string | No | End date (YYYY-MM-DD, must be >= start) |
Responses: 201 Campaign created, 422 Validation failed (invalid dates, missing strategy for active status).
Update Campaign
PATCH /api/admin/campaigns/:idAccepts the same fields as create. Status transitions are validated:
draft → active(requiresstrategy_id)active → paused(drains pending queue items)active → completedpaused → active,paused → completed
Responses: 200 Campaign updated, 422 Invalid status transition or validation error.
Delete Campaign
DELETE /api/admin/campaigns/:idRemoves the campaign. All assigned accounts have their campaign_id set to null. Pending queue items for this campaign are cancelled.
Responses: 200 Campaign deleted.
Campaign Summary
GET /api/admin/campaigns/:id/summaryReturns computed campaign metrics:
| Field | Type | Description |
|---|---|---|
campaign | object | Campaign details (id, name, status, dates) |
account_count | number | Total accounts assigned to this campaign |
contacted_count | number | Accounts with at least one interaction |
promise_count | number | Payment promises from campaign accounts |
total_recovered | number | Sum of payments from campaign accounts |
contact_rate | number | contacted_count / account_count (0.0 to 1.0) |
Responses: 200 Summary data.
Execution Engine
Pause Execution
POST /api/admin/execution/pausePauses automatic dispatch for your organization. Queue items remain but are not processed.
Responses: 200 Execution paused.
Resume Execution
POST /api/admin/execution/resumeResumes automatic dispatch processing.
Responses: 200 Execution resumed.
Get Queue Status
GET /api/admin/execution/statusReturns counts of pending, processing, completed, failed, and skipped items for today, plus the paused flag.
Enqueue Accounts
POST /api/admin/execution/enqueue| Parameter | Type | Required | Description |
|---|---|---|---|
campaign_id | UUID | No | Limit to one campaign |
Manually triggers account evaluation and enqueuing. Eligible accounts are added to the execution queue. When campaign_id is provided, the campaign must be active and within its date range.
Responses: 200 Returns { enqueued: <count> }, 422 Campaign not active or outside date range.
Bulk Operations
Bulk Account Actions
POST /api/admin/bulk/accounts| Parameter | Type | Required | Description |
|---|---|---|---|
account_ids | UUID[] | Yes | Accounts to modify (max 500) |
action | string | Yes | pause, resume, assign_campaign, assign_strategy, change_status |
campaign_id | UUID | No | Required for assign_campaign |
strategy_id | UUID | No | Required for assign_strategy |
status | string | No | Required for change_status |
Responses: 200 Returns { affected: <count> }.
Billing
Create Checkout Session
POST /api/billing/checkout| Parameter | Type | Required | Description |
|---|---|---|---|
price_id | string | Yes | Stripe price ID |
success_url | URL | Yes | Redirect URL after payment |
cancel_url | URL | Yes | Redirect URL on cancel |
Responses: 200 Returns { url: "https://checkout.stripe.com/..." }, 503 Billing not configured.
Billing Portal
POST /api/billing/portal| Parameter | Type | Required | Description |
|---|---|---|---|
return_url | URL | Yes | Redirect URL after portal |
Responses: 200 Returns { url: "https://billing.stripe.com/..." }, 503 Billing not configured.
Notifications
List Notifications
GET /api/notificationsReturns all notifications for the authenticated user, ordered by most recent.
Mark Notification as Read
PATCH /api/notifications/:id/readMarks a single notification as read.
Mark All as Read
POST /api/notifications/mark-all-readMarks all unread notifications for the authenticated user as read.
Voice
Get Signed URL
POST /api/voice/signed-urlReturns a signed WebSocket URL for browser-based voice sessions.
| Parameter | Type | Required | Description |
|---|---|---|---|
organization_id | UUID | Yes | Organization |
Response: { "signedUrl": "wss://..." }
Check Capabilities
POST /api/voice/capabilitiesChecks whether an organization is ready to make voice calls (Twilio credentials, ElevenLabs agent, phone number).
| Parameter | Type | Required | Description |
|---|---|---|---|
organization_id | UUID | Yes | Organization |
Interactions
Recover Voice Transcript
POST /api/interactions/:id/refresh-voiceFetches the conversation data from ElevenLabs for a voice interaction whose post-call webhook was missed. Updates transcript, disposition, contact result, sentiment, and all analysis metadata. If the strategy step was stuck in waiting_response, it is automatically unblocked.
This endpoint is idempotent — calling it on an interaction that already has a transcript will overwrite it with the latest data from ElevenLabs.
| Parameter | Type | Location | Required | Description |
|---|---|---|---|---|
id | UUID | path | Yes | Interaction ID |
Responses:
| Code | Description |
|---|---|
| 200 | Transcript recovered; returns updated interaction |
| 404 | Interaction not found or wrong organization |
| 422 | Not a voice interaction, no conversation ID, or call still in progress |
| 502 | ElevenLabs API fetch failed |
Public API v1
The v1 API provides programmatic access for external system integration. Authentication via X-API-Key header or Bearer JWT.
Authentication
| Method | Header | Use case |
|---|---|---|
| API Key | X-API-Key: fynex_pk_... | Machine-to-machine integrations |
| JWT | Authorization: Bearer <token> | Browser-based access |
Accounts
POST /api/v1/accountsCreate or upsert an account. If external_id is provided and matches an existing account, updates it.
| Parameter | Type | Required | Description |
|---|---|---|---|
| external_id | string | No | Your system's unique ID for this account |
| source_system | string | No | Label for the source system |
| contact | object | Yes | Contact info (name required, email/phone/whatsapp optional) |
| total_amount | number | Yes | Total debt amount |
| pending_balance | number | No | Defaults to total_amount |
| reference | string | No | Human-readable reference number |
| currency | string | No | ISO 4217 code (default: ARS) |
GET /api/v1/accountsList accounts with pagination.
| Parameter | Type | Required | Description |
|---|---|---|---|
| limit | number | No | Max results (default 50, max 1000) |
| offset | number | No | Skip first N results |
| status | string | No | Filter by collection_status |
| external_id | string | No | Filter by external_id |
GET /api/v1/accounts/:idGet account by Fynex ID. Use ?by=external_id to look up by external ID instead.
PATCH /api/v1/accounts/:idUpdate account fields.
Contacts
POST /api/v1/contacts
GET /api/v1/contacts
GET /api/v1/contacts/:id
PATCH /api/v1/contacts/:idSame pattern as accounts. Supports upsert by external_id.
Payments
POST /api/v1/paymentsRegister an external payment. Provide account_id or account_external_id.
Import & Export
POST /api/v1/importStart async bulk import. Returns { job_id, status }.
GET /api/v1/import/:jobIdCheck import job progress.
POST /api/v1/export/accountsExport accounts as JSON or CSV with filters.
Webhook Subscriptions
POST /api/v1/webhooks
GET /api/v1/webhooks
PATCH /api/v1/webhooks/:id
DELETE /api/v1/webhooks/:id
POST /api/v1/webhooks/:id/testManage outbound webhook subscriptions.
Rate Limits
All v1 endpoints: 100 requests per 15 minutes per API key.
Webhooks
These endpoints receive callbacks from external providers. They are not called by client applications.
| Endpoint | Provider | Validation |
|---|---|---|
POST /api/webhooks/twilio | Twilio | HMAC-SHA1 signature |
POST /api/webhooks/resend | Resend | Svix HMAC-SHA256 |
POST /api/webhooks/elevenlabs | ElevenLabs | HMAC-SHA256 |
POST /api/webhooks/agent-tool-handler | ElevenLabs | HMAC-SHA256 |
POST /api/webhooks/stripe | Stripe | Stripe signature |
System
Health Check
GET /healthReturns { "status": "ok", "timestamp": "..." } when the server is running.