Authentication
All API requests require an API key passed via the X-API-Key header. API keys follow the format jt_ak_... and are scoped to specific permissions.
Request Header
X-API-Key: jt_ak_abc123def456...
Available Scopes
| Scope | Access |
|---|---|
| campaigns | Create/manage campaigns, upload contacts, view stats, client usage, job status |
| audit | View call audit records and transcripts |
Rate Limiting
The API enforces a sliding-window rate limit of 100 requests per minute per API key. When the limit is exceeded, the API returns 429 Too Many Requests.
HTTP/1.1 429 Too Many Requests
{
"detail": "Rate limit exceeded. Try again in 12 seconds.",
"retry_after": 12
}
Error Handling
The API returns standard HTTP status codes with JSON error bodies.
| Status | Meaning |
|---|---|
| 200 | Success |
| 201 | Created (POST operations) |
| 400 | Bad request — invalid parameters |
| 401 | Unauthorized — missing or invalid API key |
| 403 | Forbidden — insufficient scope |
| 404 | Resource not found |
| 429 | Rate limit exceeded |
| 500 | Internal server error |
| 502 | Upstream service unavailable (circuit breaker open) |
Campaigns
Creates a new outbound calling campaign. Contacts are enqueued for dialing based on priority and concurrency settings.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| client_id | string | Yes | Client identifier |
| name | string | Yes | Campaign name |
| voice | string | No | Orpheus voice: tara, leah, jess, mia, zoe, leo, dan, zac (default: tara) |
| system_prompt | string | Yes | AI agent personality and instructions |
| caller_id | string | Yes | Caller ID phone number (E.164 format) |
| max_concurrent | integer | No | Max concurrent calls (default: 100) |
| priority | integer | No | Queue priority 1-10 (default: 5) |
| contacts | array | Yes | Array of contact objects |
| greeting_text | string | No | Pre-recorded greeting text (TTS) |
| voicemail_text | string | No | Voicemail drop text (TTS) |
Example Request
curl -X POST https://api.jobtalk.ai/api/v1/campaigns \
-H "Content-Type: application/json" \
-H "X-API-Key: jt_ak_your_key_here" \
-d '{
"client_id": "acme-staffing",
"name": "Q1 Healthcare Outreach",
"voice": "tara",
"system_prompt": "You are a recruiter calling about healthcare jobs...",
"caller_id": "+15551234567",
"max_concurrent": 50,
"priority": 7,
"contacts": [
{"first_name": "John", "last_name": "Smith", "phone": "+15559876543"}
],
"greeting_text": "Hello, I am calling from Acme Staffing.",
"voicemail_text": "Hi, this is Acme Staffing. Please call us back."
}'
Example Response (201)
{
"campaign_id": "camp_a1b2c3d4",
"status": "queued",
"contacts_enqueued": 1,
"created_at": "2025-03-15T10:30:00Z"
}
Pauses an active campaign. No new calls will be placed. In-progress calls continue until completion.
Example
curl -X POST https://api.jobtalk.ai/api/v1/campaigns/camp_a1b2c3d4/pause \
-H "X-API-Key: jt_ak_your_key_here"
{ "campaign_id": "camp_a1b2c3d4", "status": "paused" }
Resumes a paused campaign. Dialing restarts from where it left off.
Example
curl -X POST https://api.jobtalk.ai/api/v1/campaigns/camp_a1b2c3d4/resume \
-H "X-API-Key: jt_ak_your_key_here"
{ "campaign_id": "camp_a1b2c3d4", "status": "active" }
Permanently deletes a campaign and cancels any pending calls. In-progress calls are terminated.
Example
curl -X DELETE https://api.jobtalk.ai/api/v1/campaigns/camp_a1b2c3d4 \
-H "X-API-Key: jt_ak_your_key_here"
{ "deleted": true, "campaign_id": "camp_a1b2c3d4" }
Returns real-time campaign performance statistics.
Example Response
{
"campaign_id": "camp_a1b2c3d4",
"status": "active",
"total_contacts": 500,
"contacts_enqueued": 500,
"calls_placed": 312,
"human_answers": 98,
"voicemails": 187,
"errors": 4,
"no_answer": 23,
"har_percent": 31.4,
"avg_call_duration_s": 47.2,
"elapsed_s": 1823
}
Upload contacts via multipart form data. Supports CSV and Excel files.
Example
curl -X POST https://api.jobtalk.ai/api/v1/campaigns/camp_a1b2c3d4/contacts \
-H "X-API-Key: jt_ak_your_key_here" \
-F "file=@contacts.csv"
{ "uploaded": 250, "duplicates_skipped": 3, "invalid_skipped": 1 }
Upload contacts as a JSON array. Each contact must have at minimum a phone field.
Contact Object Fields
| Field | Type | Required | Description |
|---|---|---|---|
| phone | string | Yes | Phone number (E.164 preferred) |
| first_name | string | No | Contact first name |
| last_name | string | No | Contact last name |
| string | No | Email address | |
| company | string | No | Company name |
| title | string | No | Job title |
Example
curl -X POST https://api.jobtalk.ai/api/v1/campaigns/camp_a1b2c3d4/contacts/json \
-H "Content-Type: application/json" \
-H "X-API-Key: jt_ak_your_key_here" \
-d '[
{"phone": "+15551234567", "first_name": "John", "last_name": "Smith"},
{"phone": "+15559876543", "first_name": "Jane", "company": "Tech Inc"}
]'
{ "uploaded": 2, "duplicates_skipped": 0, "invalid_skipped": 0 }
Clients
Returns aggregated usage metrics for a client across all campaigns.
Example Response
{
"client_id": "acme-staffing",
"total_campaigns": 12,
"total_calls": 8450,
"total_minutes": 6234.5,
"human_answers": 2810,
"voicemails_dropped": 4920,
"period": "2025-03"
}
Jobs
Check the status of an asynchronous job (e.g., contact upload processing).
Example Response
{
"job_id": "job_x1y2z3",
"type": "contact_upload",
"status": "completed",
"progress": 100,
"result": { "uploaded": 500, "errors": 2 },
"created_at": "2025-03-15T10:30:00Z",
"completed_at": "2025-03-15T10:30:45Z"
}
Audit
Retrieves the full audit trail for a specific call, including transcript, intents detected, and disposition.
Example Response
{
"call_id": "call_abc123",
"campaign_id": "camp_a1b2c3d4",
"contact": {"phone": "+15559876543", "first_name": "John"},
"disposition": "human_interested",
"duration_s": 62,
"transcript": [
{"role": "assistant", "content": "Hello, I'm calling from Acme Staffing..."},
{"role": "user", "content": "Hi, yes I'm interested..."}
],
"intents": [
{"intent": "schedule", "confidence": 0.87, "timestamp": "2025-03-15T10:31:02Z"}
],
"started_at": "2025-03-15T10:30:00Z",
"ended_at": "2025-03-15T10:31:02Z"
}
List audit records with optional filtering by campaign_id.
Query Parameters
| Param | Type | Description |
|---|---|---|
| campaign_id | string | Filter by campaign ID |
| limit | integer | Max results (default: 50, max: 200) |
| offset | integer | Pagination offset (default: 0) |
Example
curl "https://api.jobtalk.ai/api/v1/audit?campaign_id=camp_a1b2c3d4&limit=10" \
-H "X-API-Key: jt_ak_your_key_here"
{
"records": [...],
"total": 312,
"limit": 10,
"offset": 0
}
Admin
ADMIN_API_KEY environment variable, separate from user API keys. These endpoints are not rate-limited but should be restricted to internal use.Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| client_id | string | Yes | Client to associate key with |
| name | string | Yes | Human-readable key name |
| scopes | string[] | Yes | Permission scopes: "campaigns", "audit" |
Example
curl -X POST https://api.jobtalk.ai/admin/api-keys \
-H "Content-Type: application/json" \
-H "X-Admin-Key: your_admin_key" \
-d '{
"client_id": "acme-staffing",
"name": "Production API Key",
"scopes": ["campaigns", "audit"]
}'
{
"api_key": "jt_ak_abc123def456ghi789...",
"key_hash": "sha256:a1b2c3...",
"client_id": "acme-staffing",
"name": "Production API Key",
"scopes": ["campaigns", "audit"],
"created_at": "2025-03-15T10:00:00Z",
"warning": "Store this key securely. It will not be shown again."
}
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| key_hash | string | Yes | SHA256 hash of the key to revoke |
Example
curl -X DELETE https://api.jobtalk.ai/admin/api-keys \
-H "Content-Type: application/json" \
-H "X-Admin-Key: your_admin_key" \
-d '{"key_hash": "sha256:a1b2c3..."}'
{ "status": "revoked", "key_hash": "sha256:a1b2c3..." }
Returns metadata for all active API keys (the raw key is never returned after creation).
Example
curl https://api.jobtalk.ai/admin/api-keys \
-H "X-Admin-Key: your_admin_key"
{
"keys": [
{
"key_hash": "sha256:a1b2c3...",
"client_id": "acme-staffing",
"name": "Production API Key",
"scopes": ["campaigns", "audit"],
"created_at": "2025-03-15T10:00:00Z"
}
],
"count": 1
}
Returns metadata for all active API keys belonging to a specific client.
Example
curl https://api.jobtalk.ai/admin/api-keys/acme-staffing \
-H "X-Admin-Key: your_admin_key"
{
"client_id": "acme-staffing",
"keys": [...],
"count": 2
}
Code Examples
curl
# Create a campaign
curl -X POST https://api.jobtalk.ai/api/v1/campaigns \
-H "Content-Type: application/json" \
-H "X-API-Key: jt_ak_your_key_here" \
-d '{
"client_id": "my-client",
"name": "Test Campaign",
"system_prompt": "You are a friendly recruiter...",
"caller_id": "+15551234567",
"contacts": [{"phone": "+15559876543", "first_name": "John"}]
}'
# Check campaign stats
curl https://api.jobtalk.ai/api/v1/campaigns/camp_id/stats \
-H "X-API-Key: jt_ak_your_key_here"
# Get call audit record
curl https://api.jobtalk.ai/api/v1/audit/call_abc123 \
-H "X-API-Key: jt_ak_your_key_here"
Python (requests)
import requests
API_KEY = "jt_ak_your_key_here"
BASE_URL = "https://api.jobtalk.ai"
headers = {"X-API-Key": API_KEY, "Content-Type": "application/json"}
# Create campaign
resp = requests.post(f"{BASE_URL}/api/v1/campaigns", headers=headers, json={
"client_id": "my-client",
"name": "Python Test Campaign",
"system_prompt": "You are a friendly recruiter...",
"caller_id": "+15551234567",
"contacts": [{"phone": "+15559876543", "first_name": "John"}],
})
campaign = resp.json()
print(f"Campaign created: {campaign['campaign_id']}")
# Poll stats
import time
while True:
stats = requests.get(
f"{BASE_URL}/api/v1/campaigns/{campaign['campaign_id']}/stats",
headers=headers,
).json()
print(f"Status: {stats['status']} | Placed: {stats['calls_placed']}")
if stats["status"] in ("completed", "cancelled"):
break
time.sleep(5)
JavaScript (fetch)
const API_KEY = 'jt_ak_your_key_here';
const BASE_URL = 'https://api.jobtalk.ai';
const headers = {
'X-API-Key': API_KEY,
'Content-Type': 'application/json',
};
// Create campaign
const resp = await fetch(`${BASE_URL}/api/v1/campaigns`, {
method: 'POST',
headers,
body: JSON.stringify({
client_id: 'my-client',
name: 'JS Test Campaign',
system_prompt: 'You are a friendly recruiter...',
caller_id: '+15551234567',
contacts: [{ phone: '+15559876543', first_name: 'John' }],
}),
});
const campaign = await resp.json();
console.log('Campaign ID:', campaign.campaign_id);
// Get stats
const stats = await fetch(
`${BASE_URL}/api/v1/campaigns/${campaign.campaign_id}/stats`,
{ headers }
).then(r => r.json());
console.log('Calls placed:', stats.calls_placed);