JT
JobTalk.ai API Documentation
🚀 Campaign Uploader ← Dashboard

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.

API keys are created by an admin using the Create API Key endpoint. The raw key is returned only once at creation time — store it securely.

Request Header

X-API-Key: jt_ak_abc123def456...

Available Scopes

ScopeAccess
campaignsCreate/manage campaigns, upload contacts, view stats, client usage, job status
auditView 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.

StatusMeaning
200Success
201Created (POST operations)
400Bad request — invalid parameters
401Unauthorized — missing or invalid API key
403Forbidden — insufficient scope
404Resource not found
429Rate limit exceeded
500Internal server error
502Upstream service unavailable (circuit breaker open)

Campaigns

POST /api/v1/campaigns Create a new campaign

Creates a new outbound calling campaign. Contacts are enqueued for dialing based on priority and concurrency settings.

Request Body

FieldTypeRequiredDescription
client_idstringYesClient identifier
namestringYesCampaign name
voicestringNoOrpheus voice: tara, leah, jess, mia, zoe, leo, dan, zac (default: tara)
system_promptstringYesAI agent personality and instructions
caller_idstringYesCaller ID phone number (E.164 format)
max_concurrentintegerNoMax concurrent calls (default: 100)
priorityintegerNoQueue priority 1-10 (default: 5)
contactsarrayYesArray of contact objects
greeting_textstringNoPre-recorded greeting text (TTS)
voicemail_textstringNoVoicemail 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"
}
POST /api/v1/campaigns/{campaign_id}/pause Pause a running campaign

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" }
POST /api/v1/campaigns/{campaign_id}/resume Resume a paused campaign

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" }
DELETE /api/v1/campaigns/{campaign_id} Delete a campaign

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" }
GET /api/v1/campaigns/{campaign_id}/stats Get campaign statistics

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
}
POST /api/v1/campaigns/{campaign_id}/contacts Upload contacts (CSV/Excel)

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 }
POST /api/v1/campaigns/{campaign_id}/contacts/json Upload contacts (JSON)

Upload contacts as a JSON array. Each contact must have at minimum a phone field.

Contact Object Fields

FieldTypeRequiredDescription
phonestringYesPhone number (E.164 preferred)
first_namestringNoContact first name
last_namestringNoContact last name
emailstringNoEmail address
companystringNoCompany name
titlestringNoJob 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

GET /api/v1/clients/{client_id}/usage Get client usage statistics

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

GET /api/v1/jobs/{job_id} Get job status

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

GET /api/v1/audit/{call_id} Get audit record for a call

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"
}
GET /api/v1/audit List audit records

List audit records with optional filtering by campaign_id.

Query Parameters

ParamTypeDescription
campaign_idstringFilter by campaign ID
limitintegerMax results (default: 50, max: 200)
offsetintegerPagination 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 endpoints require the ADMIN_API_KEY environment variable, separate from user API keys. These endpoints are not rate-limited but should be restricted to internal use.
POST /admin/api-keys Create a new API key

Request Body

FieldTypeRequiredDescription
client_idstringYesClient to associate key with
namestringYesHuman-readable key name
scopesstring[]YesPermission 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."
}
DELETE /admin/api-keys Revoke an API key

Request Body

FieldTypeRequiredDescription
key_hashstringYesSHA256 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..." }
GET /admin/api-keys List all active API keys

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
}
GET /admin/api-keys/{client_id} List API keys for a client

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);