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.
- What the Ashby API is (and how it’s different from REST)
- Authentication & permissions
- Endpoint naming, verbs, and request conventions
- Pagination + incremental sync (cursor + syncToken)
- Expansions: fetching related data in one call
- Responses, warnings, request IDs, and errors
- Webhooks: setup, common payload, signing, retries
- Building a custom careers page (end-to-end flow)
- Public Job Postings API (posting-api)
- Dedicated partner job feeds
- Assessments partner framework
- Production architecture patterns
- Security, privacy, and compliance tips
- FAQ
- Official references
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.
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).
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 /
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.
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.
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).
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)
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.
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.
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.
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.
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:
- A recruiter chooses an assessment in an interview plan; Ashby calls the partner’s assessment.list.
- A recruiter triggers the assessment; Ashby calls partner’s assessment.start.
- The partner sends progress updates to Ashby via assessment.update (implemented by Ashby).
- If canceled, Ashby calls partner’s assessment.cancel.
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).
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:
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:
- Introduction (RPC-style API, Basic auth, JSON bodies, browser note)
- Authentication (Basic auth, permission errors)
- Endpoint Naming (info/list/search/action verbs)
- Pagination (cursor, nextCursor, moreDataAvailable)
- Pagination + Incremental Sync (syncToken pattern)
- Syncing Records (syncToken checkpointing)
- Expansions (expand array)
- Responses & Errors (warnings, success field)
- Setting up Webhooks (Admin path, ping behavior)
- Common Payload Data (webhookActionId/action/data)
- Authenticating Webhooks (Ashby-Signature, raw payload)
- Retries (webhook retry schedule, non-retryable codes)
- Creating a Custom Careers Page (jobPosting.list/info, applicationForm.submit)
- Ashby Job Postings API (posting-api/job-board)
- Dedicated Partner Job Feeds
- Creating an Assessments Integration (partner + Ashby endpoints)
- Support (x-ashby-request-id)