Ashby API (2026): a practical, production-ready integration guide

Ashby is a modern Applicant Tracking System (ATS) used by recruiting teams to manage jobs, candidates, applications, interviews, offers, and analytics. The Ashby API is designed for building internal tools, data sync pipelines, partner integrations (like assessments), and custom career experiences.

This page explains how Ashby’s API works in the real world: how endpoints are structured, how authentication works, how to paginate and incrementally sync large datasets, how to safely consume webhooks, and how to build robust systems that don’t break when data volume or hiring activity spikes.

API style: RPC endpoints (/resource.verb) Auth: HTTP Basic (API key) Webhooks: signed payloads (Ashby-Signature) Sync: cursor + syncToken

1) What the Ashby API is (and how it differs from REST)

Many developers expect an ATS to expose a classic REST API with GET /candidates, POST /applications, and similar patterns. Ashby is different: the Ashby API is an RPC-style API where endpoints follow a /CATEGORY.method pattern (for example: /candidate.list, /job.info, /application.create). Most endpoints accept POST requests even when you’re “reading” data, and request parameters are sent as JSON bodies with Content-Type: application/json (with a few exceptions). This is intentional and consistent across the platform’s public API conventions.

Browser usage warning Because Ashby API keys are long-lived, Ashby recommends not calling the API directly from browsers. CORS is not configured to allow this, and the safer approach is to proxy requests through your backend.

In practice, the RPC approach is very friendly for integrations that need “actions” and “batch-like operations.” Instead of mapping everything to a limited set of HTTP verbs, endpoints are explicit: .list is for syncing collections, .info is for fetching a single record, and .[action] endpoints perform updates or workflow steps (like changing a candidate stage). This convention makes it easier to reason about what each call is meant to do, and it matches how recruiting workflows actually behave.

Typical Ashby API projects include:

  • Data sync into a warehouse for recruiting analytics (jobs, applications, interviews, offers).
  • Internal tooling that augments recruiter workflows (routing, alerts, enrichment, follow-up).
  • Career site / job board experiences with custom UX and fast search.
  • Partner integrations like assessments providers (send tests, receive results).
  • Automation triggered by webhooks (e.g., notify Slack when a stage changes).

The remainder of this guide is structured like a build plan: authenticate, understand endpoint patterns, implement pagination + incremental sync, handle expansions and errors, then wire up webhooks and career flows.

2) Authentication & permissions

Ashby’s API uses HTTP Basic Authentication. You send your API key as the “username” in Basic Auth and leave the password blank. If you use cURL, the pattern commonly looks like:

curl https://api.ashbyhq.com/application.list \
  -u API_KEY: \
  -H "Accept: application/json; version=1" \
  -H "Content-Type: application/json" \
  --request POST \
  -d '{}' 

Authentication failures are intentionally distinct:

  • 401 when the API key is missing.
  • 403 when the key is wrong, deactivated, or lacks required permissions for an endpoint.

Permissions are a first-class concept. Each API key is granted module-based scopes that control which endpoints can be read or written. If a key doesn’t have the necessary endpoint permission, the API returns a 403 with an error like missing_endpoint_permission. This is extremely useful for security because it lets you create “least privilege” keys for specific integrations (for example, a careers site key should not be able to edit candidates).

Best practice Create separate API keys for separate systems: one for your data warehouse sync, one for your internal tools, and one for partner integrations. If one key is compromised or needs rotation, you won’t have to rebuild everything.

In many organizations, you’ll also want a clear process for:

  • Rotation: periodically create a new key, deploy it, then retire the old one.
  • Auditing: track which system uses which key (and store the key name in your secrets manager).
  • Environment separation: if you maintain a test Ashby workspace, use separate keys and separate webhook endpoints.

3) Endpoint naming, verbs, and request conventions

Ashby endpoints follow the format /.. The verb tells you how the endpoint behaves and what it’s intended for:

.info Returns a single instance of a resource (example: /application.info).
.list Returns pages of a collection and is intended for syncing records (example: /application.list).
.search Returns matching resources for “quick lookups” and is not paginated (example: /candidate.search). This is best for targeted queries like searching by email or name.
.[action] Performs an action (create/update/transition) and returns the updated resource (example: /application.create).

Conventionally, you send JSON request bodies and explicitly set Content-Type: application/json. Even for read operations, you’ll often POST an empty JSON object to begin a list or sync. This is a common pattern in Ashby’s pagination + sync flow and makes “full sync vs incremental sync” more explicit (you control it with request parameters like cursor, limit, and syncToken).

If you are integrating multiple Ashby objects, a practical approach is to group them by what you are trying to achieve:

  • Jobs and openings: powering job visibility, internal approvals, and hiring plan analysis.
  • Candidates and applications: the heart of recruiting activity, stage changes, and pipeline metrics.
  • Interviews: scheduling, stage workflows, interviewer load, and calendar coordination.
  • Career flows: jobPosting endpoints + application form submission endpoints.
  • Partner workflows: assessments framework endpoints and callbacks.

The biggest mental shift is: treat the API as a set of explicit “operations” rather than a set of “resources with verbs.” Once you embrace that, most integration designs become simpler: each integration path is a set of operations you call, plus events you subscribe to via webhooks.

4) Pagination + incremental sync (cursor + syncToken)

Syncing ATS data is rarely a one-time operation. Recruiting teams create jobs, move candidates through stages, schedule interviews, and update offers continuously. Ashby supports this reality by designing many .list endpoints to work well for both an initial full sync and ongoing incremental sync.

Full sync with cursor pagination

A typical full sync begins by sending an empty request body (or a body with a limit) to a list endpoint. The response includes:

  • results: the records for this page
  • moreDataAvailable: whether additional pages exist
  • nextCursor: an opaque token used to request the next page
{
  "success": true,
  "results": [ /* ... */ ],
  "moreDataAvailable": true,
  "nextCursor": "Rl"
}

You then repeat requests, passing cursor with the latest nextCursor. Continue until moreDataAvailable becomes false. On the last page, many list endpoints also return a syncToken you can store for incremental sync.

Incremental sync with syncToken

After your initial full sync, you typically want “only what changed since last time.” That’s what syncToken is for: it’s an opaque token returned by the API that you store. The next time you sync, you send the token and Ashby returns only records updated since that token was issued.

{
  "syncToken": "previous_sync_token",
  "limit": 100
}

Incremental sync still respects pagination; you may still get multiple pages. The key is to keep using the same syncToken while you walk pages via cursor. When you reach the final page, store the new syncToken from that response as your checkpoint for the next run.

How to tell if an endpoint supports incremental sync In Ashby’s schema, endpoints that support incremental sync typically accept a syncToken parameter. If syncToken isn’t in the request schema, the endpoint may still paginate but only supports full sync.

Practical sync design tips

  • Checkpointing: persist your latest syncToken only after your job completes successfully.
  • Idempotency: upsert records in your database/warehouse by the Ashby record ID, not by array position.
  • Backfills: keep a manual “full resync” runbook for schema changes or logic changes.
  • Throttling: implement retry/backoff for transient errors, and treat 429 as a signal to slow down.

5) Expansions: fetch related data in one call

Many Ashby endpoints support an expand parameter. Expansions are a performance feature: they let you retrieve related resources in the same API response, reducing the need for multiple calls. This is especially useful when you need a record plus its “child objects” (like a job plus its openings).

Expansions are typically provided as an array of expansion types:

{
  "id": "JOB_ID",
  "includeUnpublishedJobPostingsIds": true,
  "expand": ["openings"]
}

When you request an expansion, the response includes the additional data inline. A well-designed integration often uses expansions strategically:

  • Use expansions when you already know you’ll need related data immediately (reduces API chatter).
  • Avoid expansions when you’re doing large-scale data pulls and prefer normalized, separate syncing.
  • Measure payload size and latency—expanding too much can make responses heavy and slower.
Rule of thumb Expansions are great for interactive tooling (a UI that loads “job details” on demand). For warehouse syncing, you often prefer separate list endpoints with incremental sync.

6) Responses, warnings, request IDs, and errors

Ashby responses commonly include a success boolean. Even when a request succeeds, you may see a warnings array for “partial success” situations. This matters in production because warnings are easy to miss if you only look at HTTP status codes.

{
  "success": true,
  "results": { /* ... */ },
  "warnings": ["unable_to_add_application_metadata"]
}

When you need help debugging, Ashby also provides request IDs. If you contact support about a specific API call, include the x-ashby-request-id response header (and note that error bodies can also include that requestId for convenience).

Production advice Log at least: endpoint name, timestamp, HTTP status, requestId, and the high-level error code. Avoid logging raw candidate PII unless you have an explicit security review and retention policy.

Error handling guidelines:

  • 403: check permissions first; many issues are scoped keys missing endpoint permissions.
  • 429: slow down; retry with backoff.
  • 5xx / timeouts: treat as transient; retry with jitter, and alert if persistent.
  • Validation failures: for endpoints like application submission, show validation errors to the user and allow resubmission.

7) Webhooks: setup, common payload, signing, and retries

Polling the API on a timer works, but it’s rarely ideal for recruiting workflows where teams want real-time updates: stage changes, new applications, interview scheduling, offer acceptance, and so on. Ashby webhooks are designed for that: they notify your system when certain events happen.

Setup basics

Webhooks are configured in the Ashby Admin panel (Admin → Integrations → Webhooks). You choose:

  • Webhook type (event type)
  • Request URL (your endpoint)
  • Optional secret token (for signature verification)
Ping behavior When you create or edit a webhook, Ashby sends a “ping” webhook to your endpoint. If your endpoint fails to respond or returns an error (> 400), the webhook can be created but disabled until you fix the endpoint and re-enable it.

Common payload structure

All webhook payloads include:

  • webhookActionId: unique identifier (stays the same across retries)
  • action: the webhook event type
  • data: the event-specific payload
{
  "webhookActionId": "75395d87-4044-4dc4-bc29-0cec185e5f06",
  "action": "candidateStageChange",
  "data": { /* event payload */ }
}

Authenticating webhooks (signature verification)

If you set a secret token, Ashby signs webhook payloads and sends the digest in the Ashby-Signature header. The format includes the algorithm and the digest (for example: sha256=...). Your server should compute the digest using the raw request body (before JSON parsing), then compare to the header.

Critical detail Verify against the raw payload bytes/string. If you parse JSON and re-stringify it, whitespace or key ordering can change and your digest won’t match.

Retries and idempotency

Ashby retries failed webhook deliveries using exponential backoff (up to 10 attempts). Not all status codes are retried: 401/403/404/405/410 are considered non-retryable. For all other errors and timeouts, Ashby will retry.

This implies two must-have practices:

  • Idempotency: store and dedupe by webhookActionId so the same event doesn’t apply twice.
  • Fast acknowledgements: return 2xx quickly, then process asynchronously (queue/job) to avoid timeouts.
// Example webhook handler outline (pseudo-code)
verify_signature(rawBody, headers["Ashby-Signature"], secretToken)

if is_duplicate(webhookActionId):
  return 200

enqueue_processing({ action, data, webhookActionId })
mark_seen(webhookActionId)

return 200

8) Building a custom careers page (end-to-end)

Ashby supports building a fully custom careers page powered by its API. The recommended flow is:

  • Step 1: list open job postings via jobPosting.list
  • Step 2: fetch details and application form definition via jobPosting.info
  • Step 3: submit applications via applicationForm.submit (and related endpoints such as survey submission)

The key idea is that Ashby can provide a machine-readable form definition for each job posting. Your front-end can use that definition to render an HTML form dynamically (text inputs, file uploads, required fields, validation rules). This makes your career site flexible: when recruiting changes the form in Ashby, your site updates automatically without a redeploy.

File uploads and form fields Application submission may include file fields (like resumes). Your backend should accept the file, then forward it using the required request structure for applicationForm.submit.

UX and reliability tips for application submission

  • Always display validation errors returned by the API. If you don’t, candidates may think they applied when they didn’t.
  • Retry safely if you get transient network errors, but avoid duplicate submissions—use your own submission IDs if possible.
  • Track UTM and source metadata (where applicable) so recruiting analytics stays accurate.
  • Accessibility: render fields with labels, helper text, and clear required indicators.

Many teams implement the careers flow with a simple architecture:

  • A “jobs” page that pulls from jobPosting.list (cached for performance).
  • A “job detail” page that uses jobPosting.info (cached, but refreshed often).
  • A backend application endpoint that receives user input, validates it, and forwards it to applicationForm.submit.
  • Optional webhooks to sync application events into your analytics or CRM.

9) Public Job Postings API (posting-api)

In addition to the core RPC-style API, Ashby also offers a public “job postings” API designed for career sites and job boards. This endpoint returns all currently published job postings for a given job board, and can optionally include compensation details by using includeCompensation=true.

curl "https://api.ashbyhq.com/posting-api/job-board/{JOB_BOARD_NAME}?includeCompensation=true"

The response is structured for job listing display: title, location, department/team, and additional metadata that helps you build a user-friendly careers experience. Many organizations use this endpoint for fast job listing pages, because it’s optimized for “public jobs” rather than internal ATS operations.

When to use which API Use posting-api endpoints to power public job listings. Use the core RPC API (jobPosting.* and applicationForm.*) when you need deeper ATS workflows, application forms, or admin-level data access.

If you’re building a job board that aggregates multiple companies, you’ll often combine:

  • The public job postings API for each company’s job board name,
  • A caching layer (CDN or edge cache) so job pages load instantly,
  • A scheduled refresh or webhook-driven refresh, depending on how frequently postings change.

10) Dedicated partner job feeds

Ashby can provision a dedicated job posting feed for partners who ingest job postings (for example, a syndication partner, a job marketplace, or an analytics platform). Once provisioned, Ashby customers can opt-in by enabling the partner integration in Ashby Admin. After opt-in, their published job postings are published to the partner feed for ingestion.

Partner feed vs public job postings API The public job postings API is great for a single company’s job board. Dedicated partner feeds are designed for partners to ingest postings from multiple Ashby customers who opt in.

If you’re building a partner product, this matters because it changes the onboarding experience:

  • You may not need each customer to manually build a job board name integration on your side—opt-in can drive publishing.
  • You can focus on data normalization and search across customers rather than building custom scraping logic.
  • You should still document what customers should expect: publish/unpublish timing, job field mapping, and how to handle deletions/archives.

11) Assessments partner framework

Ashby provides an Assessments framework that supports third-party assessment providers (skills tests, reference checks, background checks, and similar workflows). This is a “two-sided” integration:

  • Ashby implements part of the API that partners call to update status and results.
  • The partner implements part of the API that Ashby calls to list assessments, start them, and cancel them.

A simplified high-level flow looks like:

  1. A recruiter chooses an assessment in an interview plan; Ashby calls the partner’s assessment.list.
  2. A recruiter triggers the assessment; Ashby calls partner’s assessment.start.
  3. The partner sends progress updates to Ashby via assessment.update (implemented by Ashby).
  4. If canceled, Ashby calls partner’s assessment.cancel.
Partner integration best practices Make your start/update/cancel operations idempotent, and handle duplicate calls gracefully. Webhooks and network retries are a fact of life.

If you’re an assessments provider, you’ll also want to think through:

  • Security: protect your partner endpoints, validate any shared secrets, and consider IP allowlists if supported.
  • Data minimization: only request the candidate fields you truly need, and redact/expire access when assessments complete.
  • UX: ensure recruiters can understand what “status” means (queued, in progress, completed, failed, canceled) and what actions are possible.

12) Production architecture patterns (what actually works)

A reliable Ashby integration usually combines three system types:

  • Batch sync (API-driven): for completeness and analytics (nightly/hourly sync using list + syncToken).
  • Event stream (webhooks): for real-time reactions (alerts, automation, short-latency updates).
  • Public listings (job postings API or jobPosting.*): for careers pages and job marketing workflows.

Pattern A: Data warehouse sync

This pattern uses .list endpoints and stores the newest syncToken after each successful run. It’s ideal for BI dashboards and recruiting performance analysis.

  • Initial full sync of jobs, candidates, applications, interviews, and offers.
  • Incremental sync every 15–60 minutes depending on volume.
  • Upsert by record ID; store “lastSeenAt” and “sourceSyncToken” for debugging.
  • Backfill strategy for schema changes.

Pattern B: Operational automation with webhooks

Webhooks are best for operational tasks like notifications, SLA monitoring, and workflow routing. The best practice is to respond quickly and process asynchronously.

  • Receive webhook → verify signature → dedupe by webhookActionId.
  • Enqueue a job that calls the Ashby API if additional data is needed (e.g., fetch full application details).
  • Update your internal system (Slack, CRM, ticketing, dashboards).

Pattern C: Careers site caching + submission proxy

Careers pages should feel instant. The common architecture is:

  • Cache job listing data (edge cache/CDN) and refresh periodically.
  • Render job details with server-side caching for SEO and performance.
  • Proxy application submissions through your backend (never expose your API key in the browser).
Stability checklist Queue everything that can be queued, retry transient failures with jitter, store checkpoints (sync tokens), and build a small admin UI for replaying failed webhook events.

13) Security, privacy, and compliance tips

ATS data contains sensitive personal information (PII) and often confidential hiring details. A secure integration is not optional. Here are practical guardrails that help most teams:

Keys and secrets Store API keys in a secrets manager, not in source control. Rotate keys. Use separate keys per system and least-privilege permissions.
Webhook verification Always verify Ashby-Signature if you use secret tokens. Dedupe by webhookActionId.
Data minimization Only sync what you need. For analytics, consider hashing emails or removing direct identifiers if not required.
Logging discipline Don’t log raw resumes, notes, or candidate PII by default. Log request IDs and error codes for debugging instead.

If your integration touches public career sites, add additional protections:

  • Rate limit application submission endpoints to reduce abuse.
  • Bot protection (CAPTCHA or challenge) if you see spam.
  • Validation UI so candidates can fix errors instead of silently failing.
  • Secure uploads: virus scan files and enforce size/type limits before forwarding to Ashby.

Compliance is company-specific, but common requirements include:

  • Retention limits for candidate data in downstream systems.
  • Access controls and audit logs for any internal tools built on top of the Ashby API.
  • Security review for any partner integration that receives candidate data (especially assessments).

14) FAQ (Ashby API)

Is Ashby’s API REST or RPC?
Ashby’s public API is RPC-style with endpoints like /candidate.list and /application.create, and most calls use POST with JSON bodies.

Can I call the Ashby API from the browser?
It’s not recommended. API keys are long-lived and CORS is not configured to allow browser calls. Use a backend proxy.

How do I sync “only changes” after my first import?
Use incremental sync: store the syncToken returned on the last page of a list endpoint and pass it in the next run. Continue paging with cursor if needed, then store the new token at the end.

What’s the difference between .list and .search?
.list is paginated and intended for syncing entire collections; .search is not paginated and is meant for quick targeted lookups.

How do I verify webhooks are truly from Ashby?
Set a webhook secret token and verify the Ashby-Signature header by computing a digest of the raw request body and comparing it to the header.

Why am I getting 403 errors even though my key “works” for some endpoints?
Your API key permissions are scoped by module/endpoint. If the key lacks permission for a specific endpoint, Ashby returns 403 with a missing-permission error.

How should I handle webhook retries?
Treat retries as normal: dedupe by webhookActionId, return 2xx quickly, and process asynchronously.

What’s the easiest way to power a public job board?
Use the public Job Postings API: /posting-api/job-board/{JOB_BOARD_NAME} and cache results for performance.

Can Ashby provision a job feed for partners?
Yes—Ashby can provision dedicated partner job feeds where customers opt in to sharing published job postings with the partner.

What should I send to Ashby Support when something breaks?
Include the x-ashby-request-id from response headers (or the requestId in error responses) plus a timestamp and endpoint name.

15) Official references (recommended reading)

These are the core Ashby docs that back up the behaviors described above: