API Reference

The AI Interview API allows you to programmatically create campaigns, manage invites, and retrieve interview data.

Base URL

https://api.interviewrelay.com

Authentication

All API requests require authentication using an API key. See Authentication for details.

curl https://api.interviewrelay.com/api/campaigns \
  -H "Authorization: Bearer YOUR_API_KEY"

Common Headers

Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

Campaigns

Create Campaign

POST/api/campaigns

Create a new interview campaign

Request Body:

NameTypeDescription
name*stringCampaign name (internal use)
script_id*stringUUID of published script
project_id*stringUUID of project
invite_valid_hoursnumberHours until invite expires (default: 168 = 7 days)

Example Request:

curl -X POST https://api.interviewrelay.com/api/campaigns \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Q4 Customer Feedback",
    "script_id": "550e8400-e29b-41d4-a716-446655440000",
    "project_id": "660e8400-e29b-41d4-a716-446655440001",
    "invite_valid_hours": 168
  }'

Response (201 Created):

{
  "id": "770e8400-e29b-41d4-a716-446655440002",
  "name": "Q4 Customer Feedback",
  "script_id": "550e8400-e29b-41d4-a716-446655440000",
  "project_id": "660e8400-e29b-41d4-a716-446655440001",
  "status": "active",
  "created_at": "2024-10-20T10:00:00Z"
}

List Campaigns

GET/api/campaigns

Retrieve all campaigns

Query Parameters:

NameTypeDescription
project_idstringFilter by project UUID
statusstringFilter by status: active, completed, archived
limitnumberNumber of results (default: 50, max: 100)
offsetnumberPagination offset (default: 0)

Example:

curl "https://api.interviewrelay.com/api/campaigns?project_id=abc123&limit=10" \
  -H "Authorization: Bearer YOUR_API_KEY"

Response:

{
  "campaigns": [
    {
      "id": "campaign-1",
      "name": "Q4 Feedback",
      "status": "active",
      "invites_sent": 50,
      "completed": 32,
      "created_at": "2024-10-01T00:00:00Z"
    }
  ],
  "total": 1,
  "limit": 10,
  "offset": 0
}

Get Campaign Details

GET/api/campaigns/:id

Get detailed information about a campaign

Example:

curl https://api.interviewrelay.com/api/campaigns/campaign-123 \
  -H "Authorization: Bearer YOUR_API_KEY"

Response:

{
  "id": "campaign-123",
  "name": "Q4 Customer Feedback",
  "script_id": "script-456",
  "project_id": "project-789",
  "status": "active",
  "created_at": "2024-10-01T00:00:00Z",
  "stats": {
    "invites_sent": 100,
    "started": 65,
    "completed": 48,
    "completion_rate": 0.74
  }
}

Invites

Create Invite

POST/api/campaigns/:id/invites

Send interview invites to participants

Request Body:

NameTypeDescription
emails*string[]Array of participant email addresses
send_emailbooleanWhether to send email (default: true)
custom_messagestringOptional custom email message

Example:

curl -X POST https://api.interviewrelay.com/api/campaigns/campaign-123/invites \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "emails": ["user1@example.com", "user2@example.com"],
    "send_email": true
  }'

Response (201 Created):

{
  "invites": [
    {
      "id": "invite-1",
      "email": "user1@example.com",
      "token": "inv_abc123",
      "url": "https://interviewrelay.com/interview/inv_abc123",
      "expires_at": "2024-10-27T10:00:00Z"
    },
    {
      "id": "invite-2",
      "email": "user2@example.com",
      "token": "inv_def456",
      "url": "https://interviewrelay.com/interview/inv_def456",
      "expires_at": "2024-10-27T10:00:00Z"
    }
  ],
  "sent": 2,
  "failed": 0
}

Get Invite Details

GET/api/invites/:token

Retrieve invite information by token

Example:

curl https://api.interviewrelay.com/api/invites/inv_abc123 \
  -H "Authorization: Bearer YOUR_API_KEY"

Response:

{
  "id": "invite-1",
  "email": "user@example.com",
  "token": "inv_abc123",
  "status": "pending",
  "campaign_id": "campaign-123",
  "expires_at": "2024-10-27T10:00:00Z",
  "created_at": "2024-10-20T10:00:00Z"
}

Sessions

List Sessions

GET/api/sessions

Retrieve interview sessions

Query Parameters:

NameTypeDescription
campaign_idstringFilter by campaign UUID
statusstringFilter by status: completed, in_progress, abandoned
start_datestringISO 8601 date (filter sessions after this date)
end_datestringISO 8601 date (filter sessions before this date)

Example:

curl "https://api.interviewrelay.com/api/sessions?campaign_id=campaign-123&status=completed" \
  -H "Authorization: Bearer YOUR_API_KEY"

Response:

{
  "sessions": [
    {
      "id": "session-1",
      "campaign_id": "campaign-123",
      "participant_email": "user@example.com",
      "status": "completed",
      "duration_minutes": 12,
      "started_at": "2024-10-20T10:00:00Z",
      "completed_at": "2024-10-20T10:12:00Z"
    }
  ],
  "total": 1
}

Get Session Details

GET/api/sessions/:id

Get detailed session information

Example:

curl https://api.interviewrelay.com/api/sessions/session-123 \
  -H "Authorization: Bearer YOUR_API_KEY"

Response:

{
  "id": "session-123",
  "campaign_id": "campaign-456",
  "participant_email": "user@example.com",
  "status": "completed",
  "duration_minutes": 12,
  "started_at": "2024-10-20T10:00:00Z",
  "completed_at": "2024-10-20T10:12:00Z",
  "transcript_url": "https://api.interviewrelay.com/api/session/session-123/transcript",
  "audio_url": "https://api.interviewrelay.com/api/session/session-123/audio"
}

Get Transcript

GET/api/session/:id/transcript

Download session transcript

Example:

curl https://api.interviewrelay.com/api/session/session-123/transcript \
  -H "Authorization: Bearer YOUR_API_KEY"

Response:

{
  "session_id": "session-123",
  "started_at": "2024-10-20T10:00:00Z",
  "completed_at": "2024-10-20T10:12:00Z",
  "turns": [
    {
      "timestamp": 0,
      "speaker": "ai",
      "text": "Hello! Thank you for joining today.",
      "sentiment": "neutral"
    },
    {
      "timestamp": 3.5,
      "speaker": "participant",
      "text": "Hi, happy to be here.",
      "sentiment": "positive"
    }
  ]
}

Download PDF

GET/api/session/:id/pdf

Download formatted PDF transcript

Example:

curl https://api.interviewrelay.com/api/session/session-123/pdf \
  -H "Authorization: Bearer YOUR_API_KEY" \
  --output transcript.pdf

Projects

Create Project

POST/api/projects

Create a new project

Request Body:

NameTypeDescription
name*stringProject name
descriptionstringOptional project description

List Projects

GET/api/projects

Retrieve all projects

Billing

Get Credit Balance

GET/api/billing/credits

Check current credit balance

Returns the starter, monthly, and top-up pool totals for the caller's primary organization (authentication required).

Response:

{
  "starter_credits": 600,
  "monthly_credits": 820,
  "topup_credits": 4000,
  "total_credits": 5420,
  "monthly_credits_amount": 1000,
  "monthly_credits_reset_at": "2025-02-01T00:00:00.000Z",
  "currency": "eur",
  "last_low_balance_warning_at": null,
  "updated_at": "2025-01-07T12:30:00.000Z",
  "low_balance_warning": {
    "shouldWarn": false,
    "severity": "info",
    "message": ""
  },
  "needs_topup": false,
  "estimated_sessions_remaining": 54
}

Get Usage

GET/api/billing/usage

Retrieve billing usage details

Query Parameters:

NameTypeDescription
start_datestringISO 8601 date
end_datestringISO 8601 date

Admin Credit Summary

Requires admin privileges. Intended for internal observability tooling.

GET/api/admin/credits/summary

Aggregate credit balances, alerts, and recent transactions

Response:

{
  "summary": {
    "totalOrganizations": 42,
    "totalStarterCredits": 25200,
    "totalMonthlyCredits": 318000,
    "totalTopupCredits": 127500,
    "totalCredits": 470700,
    "lowBalanceCount": 4,
    "criticalBalanceCount": 1
  },
  "lowBalanceOrganizations": [
    {
      "organizationId": "org-123",
      "organizationName": "Acme Labs",
      "organizationSlug": "acme-labs",
      "starter": 0,
      "monthly": 20,
      "topup": 15,
      "total": 35,
      "monthlyCreditsAmount": 1000,
      "monthlyCreditsResetAt": "2025-02-01T00:00:00.000Z",
      "updatedAt": "2025-01-07T08:12:00.000Z",
      "severity": "critical"
    }
  ],
  "recentTransactions": [
    {
      "id": "txn-789",
      "organizationId": "org-456",
      "organizationName": "Bright Water",
      "organizationSlug": "bright-water",
      "amountCredits": 10000,
      "creditType": "topup",
      "transactionType": "purchase",
      "description": "Credit top-up: 10,000 credits (€100.00)",
      "balanceAfterCredits": 15200,
      "paymentIntentId": "pi_test_123",
      "createdAt": "2025-01-07T10:15:00.000Z"
    }
  ],
  "alerts": [
    {
      "organizationId": "org-123",
      "severity": "critical",
      "message": "Acme Labs has only 35 credits remaining"
    }
  ]
}

Rate Limiting

API requests are limited to:

  • Free Plan: 100 requests/hour
  • Starter: 1,000 requests/hour
  • Professional: 10,000 requests/hour
  • Enterprise: Custom limits

Rate limit headers are included in all responses:

X-RateLimit-Limit: 10000
X-RateLimit-Remaining: 9847
X-RateLimit-Reset: 1634567890

When rate limited, the API returns 429 Too Many Requests. Implement exponential backoff in your client.

Error Codes

| Code | Description | |------|-------------| | 200 | Success | | 201 | Created | | 400 | Bad Request - Invalid parameters | | 401 | Unauthorized - Invalid API key | | 403 | Forbidden - Insufficient permissions | | 404 | Not Found | | 429 | Too Many Requests - Rate limited | | 500 | Internal Server Error |

Error Response Format:

{
  "error": {
    "code": "INVALID_PARAMETER",
    "message": "The 'email' field is required",
    "details": {
      "field": "email",
      "expected": "string"
    }
  }
}

Pagination

List endpoints support pagination:

curl "https://api.your-domain.com/api/campaigns?limit=50&offset=100" \
  -H "Authorization: Bearer YOUR_API_KEY"

Response includes:

{
  "data": [...],
  "pagination": {
    "total": 247,
    "limit": 50,
    "offset": 100,
    "has_more": true
  }
}

Best Practices

Handle Errors Gracefully

try {
  const response = await fetch('https://api.interviewrelay.com/api/campaigns', {
    headers: { Authorization: `Bearer ${API_KEY}` }
  });
  
  if (!response.ok) {
    const error = await response.json();
    console.error('API Error:', error);
    // Handle error...
  }
  
  const data = await response.json();
  // Process data...
} catch (error) {
  console.error('Network error:', error);
}

Use Webhooks for Real-time Updates

Instead of polling for session completion, use webhooks for instant notifications.

Cache Responses

Cache static data like projects and scripts to reduce API calls:

const cache = new Map();

async function getProject(id) {
  if (cache.has(id)) {
    return cache.get(id);
  }
  
  const project = await fetchProject(id);
  cache.set(id, project);
  return project;
}

SDKs and Libraries

Official SDKs:

  • JavaScript/TypeScript: @ai-interview/sdk
  • Python: Coming soon
  • Ruby: Coming soon

Community SDKs:

  • Check our GitHub for community contributions

Examples

See the Examples section for complete working code samples.

Support

Need help with the API?