Back to Developers & API

How do I use the ASHR.work API?

Create an API key with the scopes you need, send it as a Bearer token to /api/v1, and read or write your workspace data — with cursor pagination, idempotent writes and RFC 9457 errors.

~5 min read · For admin · Updated 4 Aug 2026

Quick answer

The ASHR.work API lives at /api/v1. Product metadata is open; your own workspace data needs an API key carrying the right scope, sent as Authorization: Bearer <key>. Reads are cursor-paginated, writes are idempotent, and errors are RFC 9457 problem+json.

Quickstart

  1. Create a key

    Open Admin → Settings → Developer & API, create a key, tick the module permissions you need (e.g. leave:read, leave:write), and copy it — it's shown once.
  2. Call the API

    Send it as a Bearer token. The base URL is https://ashr.work/api.
  3. Explore live

    Open the API reference, click Authenticate, paste your key, and use Test Request on any endpoint.
# Read holidays (needs holidays:read)
curl -s https://ashr.work/api/v1/holidays \
  -H "Authorization: Bearer dmk_live_…"

# Apply for leave (needs leave:write), idempotent
curl -s https://ashr.work/api/v1/leave-requests \
  -H "Authorization: Bearer dmk_live_…" \
  -H "Idempotency-Key: 6f1c…" \
  -H "Content-Type: application/json" \
  -d '{"employee_id":"…","leave_type_id":"…","start_date":"2026-09-01","end_date":"2026-09-03","days_count":3,"reason":"Family trip"}'

Scopes

Each key carries module:action scopes — leave:read, leave:write, leave:approve, payroll:run, and so on. The console only offers the scopes for modules your workspace has enabled. An endpoint returns 403 insufficient_scope if the key is missing the scope it needs.

Pagination

List endpoints return { data, next_cursor, has_more }. Pass ?limit= (max 100) and follow next_cursor with ?cursor= until has_more is false.

Idempotency & errors

Send an Idempotency-Key on writes so a retry never double-posts. Errors are problem+json with a stable code and a request_id you can quote to support. Every response carries X-Request-Id and RateLimit-* headers.

SDKs

Dependency-free TypeScript and Python SDKs wrap all of this (list, get, applyLeave, whoami, …), and the spec at /api/openapi.json imports into Postman, Insomnia or Swagger UI.

Frequently asked questions

Do I need a key to read public data?
No. Product and module metadata (/api/v1/health, /capabilities, /modules) is anonymous. A key is only needed for your tenant's data and for writes.
How do I avoid double-posting a write on a retry?
Send an Idempotency-Key header. If the same key is retried, the first response is replayed instead of running twice; reusing a key with a different body is a 409.
What do errors look like?
RFC 9457 problem+json with type, title, status, code, detail and request_id fields. Common codes are api_key_required (401), insufficient_scope (403), invalid_parameter (400) and rate_limited (429).