Skip to main content
The Harly REST API is available at:
The OpenAPI document is available from a running installation at /api/v1/openapi.json. Use it as the source of truth for exact schemas and route parameters. The repository also includes a generated snapshot at /openapi.json. With the Harly dev server running on port 3000, refresh it after changing an API contract with:

Authenticate

Create a key from Settings → Developers → API keys, copy the raw value once, and send it as a bearer token:
Keys are scoped. Give an integration only the resources it needs. Rotate or revoke keys when an owner or vendor changes.

Response envelopes

Success

Error

Common error codes: validation_error, not_found, forbidden, conflict, rate_limited.

Pagination

List endpoints use cursor-based pagination:
  • Do not assume a stable sort order or page number.
  • meta.nextCursor is absent when you have reached the last page.
  • limit defaults to 25 and caps at 100.

Idempotency

POST requests that support it accept an Idempotency-Key header. Use a unique value per logical operation — for example a UUID or a stable key derived from the operation’s inputs:
A 409 may mean a real concurrency conflict or an idempotency collision. Inspect the error envelope before retrying a mutation. Do not retry a 409 blindly — the operation may have already succeeded.

Rate limits

The API applies per-key rate limits. When a response returns 429, back off using the Retry-After header value before retrying. Do not hammer the API with immediate retries.

HTTP status codes

Main resources

Jobs, candidates, applications, interviews, offers, scorecards, tasks, pool entries, activity events, webhooks, and API keys are available through the versioned API. Use webhooks to react to changes instead of polling every resource. See API resource reference for the full scope and operation inventory.

Try it

The OpenAPI document at /api/v1/openapi.json is importable into Insomnia, Postman, or any OpenAPI-compatible tool:
See the API integration tutorial for an end-to-end walkthrough with webhook verification.

Public jobs and applications API

The public API is the same API used by Harly’s embedded job widget. It is CORS-enabled and intentionally exposes only published, open jobs and the application intake flow. It never exposes candidate or application records after submission. Every request must identify the workspace in one of these ways:
  • Add ?workspace=<workspace-slug> to the URL. This is zero-configuration and is suitable when the public workspace slug is already known.
  • Send a publishable key (pk_) in X-API-Key, Authorization: Bearer, or ?pk=. The key is bound to one workspace and is useful for browser embeds, analytics, and revocation.
The public routes do not infer a workspace automatically, even on a single-workspace installation. Never send a secret (sk_) key to a browser.

1. List open jobs

With a publishable key:
The list endpoint supports the optional department, location, workplaceType, and q query filters. It returns a standard { data } success envelope containing the workspace branding and serialized public jobs. Use the returned job’s slug as the public job identifier. A custom frontend should use the slug rather than the internal job id.

2. Fetch a job and its application configuration

The response includes applicationConfig. Its questions array is the source of truth for custom questions:
The question’s id is the key used in questionAnswers. Supported question types are text, textarea, url, and select; select questions also return an options array. The same response describes standard fields under applicationConfig.sections, including resume, links, education, experience, and cover letter visibility (required, optional, or disabled).

3. Submit the application

The endpoint is:
It returns 201 with this success envelope:
The API validates required standard fields and every custom answer, so the frontend should render from applicationConfig instead of duplicating the form configuration. If CAPTCHA is configured for the workspace, the application request must include a valid token in captchaToken (the legacy turnstileToken name is also accepted). The public application endpoint is rate-limited to protect the intake flow. Clients must handle 429 and retry after the Retry-After response header. The request also accepts the _hp honeypot field; real forms should leave it empty.

Uploads

For a resume or profile image, request a presigned upload URL first, upload the file directly to that URL, and send the returned key and file metadata in the application payload:
Both endpoints accept { filename, contentType, contentLength } and are scoped to the same workspace or publishable key. The resume fields are resumeKey, resumeFileName, resumeFileType, and resumeFileSize; the image field is photoUrl. For a browser integration, the publishable-key variant is usually preferable:
Never expose a secret (sk_) key in frontend code.

Public API errors

Public routes use the same error envelope as the authenticated API:
Common statuses are 400 for a missing or malformed workspace selector, 403 for a failed CAPTCHA or missing publishable-key scope, 404 for a job that is not public, 422 for invalid application fields, and 429 for rate limiting.