CallingCard

API

A REST API for managing your organization's job postings and applicant statuses from your own systems — an ATS, a scheduling tool, a nightly sync job. Questions? Get in touch.

Generate a key from your organization's API keys page (Org dashboard → API — only the organization owner can create or revoke keys). Every request needs it:

Authorization: Bearer cc_live_...

The full OpenAPI 3.0 spec has every field. This page covers the common paths.

Requests and responses

  • Base URL: https://callingcard.work/api/v1
  • Request bodies are JSON (Content-Type: application/json).
  • Every response is JSON: { "data": ... } on success, { "error": { "message": "..." } } on failure.
  • Lists are paginated: pass ?cursor=<id> from a response's nextCursor to get the next page. nextCursor is null on the last page.
  • Rate limit: 120 requests per 60 seconds per key. A 429 means you've hit it.
StatusMeaning
401Missing or invalid API key
403Not allowed yet — usually an unverified organization trying to publish
404No such job/application for your organization
422The request body failed validation
429Rate limit exceeded

List jobs

GET /jobs

Query params: status (DRAFT, PUBLISHED, or CLOSED), limit (default 25, max 100), cursor.

curl https://callingcard.work/api/v1/jobs?status=PUBLISHED \
  -H "Authorization: Bearer cc_live_..."

Create a job

POST /jobs

title, description, and employmentType (FULL_TIME, PART_TIME, CONTRACT, INTERNSHIP, or VOLUNTEER) are required. status defaults to DRAFT — set it to PUBLISHED to publish immediately, which is checked against your plan's job quota and your organization's verification status the same way publishing from the dashboard is. Some states require salaryMin/salaryMax before a job can publish.

curl -X POST https://callingcard.work/api/v1/jobs \
  -H "Authorization: Bearer cc_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Warehouse Associate",
    "description": "Full-time role at our downtown facility.",
    "employmentType": "FULL_TIME",
    "payType": "HOURLY",
    "salaryMin": 18,
    "salaryMax": 22,
    "status": "PUBLISHED"
  }'

Update a job

PATCH /jobs/{jobId}

Send only the fields you're changing — everything else is left as-is. Include status to publish or close it in the same request.

curl -X PATCH https://callingcard.work/api/v1/jobs/JOB_ID \
  -H "Authorization: Bearer cc_live_..." \
  -H "Content-Type: application/json" \
  -d '{ "status": "CLOSED" }'

List a job's applications

GET /jobs/{jobId}/applications

Query params: limit, cursor. Each application includes the applicant's name and email, but never their résumé or full profile — this API is for pipeline status, not candidate data export.

curl https://callingcard.work/api/v1/jobs/JOB_ID/applications \
  -H "Authorization: Bearer cc_live_..."

Update an application's status

PATCH /applications/{applicationId}

status is required: SUBMITTED, REVIEWING, INTERVIEW, OFFER, REJECTED, or WITHDRAWN. Moving to most of these sends the applicant a status email — and a text, if they've opted in and verified a phone number — the same way changing it from the dashboard does. orgMessage is shown to the applicant and included in that email.

To schedule an interview, send interviewType, interviewAtLocal, and interviewTimezone together — a partial interview update is ignored and the application's existing interview details (if any) are left alone.

curl -X PATCH https://callingcard.work/api/v1/applications/APPLICATION_ID \
  -H "Authorization: Bearer cc_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "status": "INTERVIEW",
    "orgMessage": "Thanks for applying — we would like to talk.",
    "interviewType": "VIRTUAL",
    "interviewLocation": "https://meet.example.com/abc",
    "interviewAtLocal": "2026-09-20T14:00",
    "interviewTimezone": "America/Chicago"
  }'