/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:Response envelopes
Success
Error
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.nextCursoris absent when you have reached the last page.limitdefaults to25and caps at100.
Idempotency
POST requests that support it accept anIdempotency-Key header. Use a
unique value per logical operation — for example a UUID or a stable key
derived from the operation’s inputs:
Rate limits
The API applies per-key rate limits. When a response returns429, 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:
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_) inX-API-Key,Authorization: Bearer, or?pk=. The key is bound to one workspace and is useful for browser embeds, analytics, and revocation.
sk_) key to a browser.
1. List open jobs
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
applicationConfig. Its questions array is the source
of truth for custom questions:
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
201 with this success envelope:
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 returnedkey and file metadata in the
application payload:
{ 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.
Normalize a profile image
After you upload a profile image, call the normalize endpoint to convert it to a stable raster format before you use it:- Call
POST /api/public/v1/image/presignand keep the returnedkey. PUTthe file to the returneduploadUrl.- Call
POST /api/public/v1/image/normalizewith{ "key": "<key>" }.
key, its contentType,
and a fileUrl for the normalized image.
The endpoint requires the applications:write scope, is CORS-enabled, and is
rate-limited to 20 requests per minute per IP address. It only accepts keys
returned by the public image presign endpoint. Harly deletes the temporary
upload after a successful conversion, so resubmitting the same key returns
404.
For a browser integration, the publishable-key variant is usually preferable:
sk_) key in frontend code.
Public API errors
Public routes use the same error envelope as the authenticated API: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.