Skip to content

Getting started

Authentication

Halyard authenticates every request with an API key sent as a Bearer token. Use test keys while you build, restricted keys in production, and rotate without downtime.

On this page

API keys

Each project has its own keys, created in the dashboard under Developers → API keys or with the Keys API. A key identifies the project, the environment and what the caller may do. Every key has a public ID such as key_2Mx8Rc6Jd3 that is safe to log, and a secret you only see once.

hy_test_51Hq8Zx2rTmV9cKpL3d

  • hy_Halyard secret key
  • test_Environment: test (sandbox)
  • 51Hq…Random part, unique per secret
Secrets are shown once at creation. If you lose one, roll the key.

Test and live mode

The prefix tells you the environment. Test and live data are completely separate: a job created with a test key can only be seen and worked by test keys.

PrefixEnvironmentBehavior
hy_test_TestSandbox. Free, rate-limited to 25 req/s, data deleted after 30 days.
hy_live_LiveProduction. Billed, full rate limits, data kept per your retention plan.

Sending the key

Send the secret in the Authorization header using the Bearer scheme. All requests must use HTTPS; plain HTTP is refused before authentication. The SDKs set the header for you.

Request
GET /v3/jobs?limit=3 HTTP/1.1Host: api.halyard.exampleAuthorization: Bearer hy_test_51Hq8Zx2rTmV9cKpL3dHalyard-Version: 2026-09-01
curl https://api.halyard.example/v3/jobs?limit=3 \  -H "Authorization: Bearer hy_test_51Hq8Zx2rTmV9cKpL3d"

Restricted keys and scopes

A secret key without restrictions can do everything in its environment. For anything that runs in production, create a restricted key with only the scopes it needs, and optionally limit it to specific queues. A worker that only sends email needs jobs:work on emails and nothing else.

ScopeGrantsTypical caller
jobs:readList and retrieve jobs, attempts and logs.Dashboards, status pages
jobs:writeCreate, cancel and retry jobs. Includes jobs:read.Web servers enqueuing work
jobs:workClaim jobs, heartbeat and report results.Worker processes
events:publishPublish events to topics.Services emitting domain events
events:subscribeCreate and change event subscriptions.Deploy pipelines
schedules:writeCreate, pause and delete schedules.halyard deploy in CI
queues:manageChange queue limits, pause and drain queues.Operators, CI
keys:manageCreate, roll and revoke API keys.Admin tooling only
Write scopes do not imply other resources: jobs:write cannot publish events.
curl https://api.halyard.example/v3/keys \  -H "Authorization: Bearer hy_test_51Hq8Zx2rTmV9cKpL3d" \  -H "Content-Type: application/json" \  -d '{    "name": "email-worker (production)",    "scopes": ["jobs:work"],    "queues": ["emails"],    "expires_at": "2027-10-01T00:00:00Z"  }'

Rotating keys

Roll a key on a regular schedule, when someone with access leaves, or immediately if you think it leaked. Rolling issues a new secret for the same key ID, so scopes and audit history stay intact.

  1. Roll the key with an overlap window

    Set expires_in so the old secret keeps working while you deploy. Use 0 to revoke it at once if the key leaked.

    curl https://api.halyard.example/v3/keys/key_2Mx8Rc6Jd3/roll \  -H "Authorization: Bearer hy_test_51Hq8Zx2rTmV9cKpL3d" \  -d expires_in=86400
  2. Deploy the new secret

    Update the secret in your host or CI and redeploy every service and worker that uses it.

  3. Confirm the old secret is unused

    The key's page in the dashboard shows Last used per secret. When the old one shows no traffic, let it expire or revoke it early.

Keeping keys secret

  • Store keys in your host's secret manager or environment, never in code.
  • Use one restricted key per service, so revoking one never takes down the others.
  • Set expires_at on keys for contractors, demos and one-off scripts.
  • Log the key ID, not the secret. The SDKs redact secrets in their own debug logs.

Authentication errors

A missing, malformed or revoked key returns 401. A valid key without the needed scope or queue access returns 403. Both include a request_id to quote when you contact support.

401 Unauthorized
{  "error": {    "type": "authentication_error",    "code": "invalid_api_key",    "message": "The API key provided is not valid. Check that it is complete and has not been revoked.",    "request_id": "req_6Gt3Yb8Qe2",    "doc_url": "https://docs.halyard.example/docs/authentication#auth-errors"  }}
403 Forbidden
{  "error": {    "type": "permission_error",    "code": "missing_scope",    "message": "This key does not have the 'schedules:write' scope required for POST /v3/schedules.",    "required_scope": "schedules:write",    "key_id": "key_2Mx8Rc6Jd3",    "request_id": "req_6Gt3Yb8Qe2"  }}
StatuscodeWhat to check
401missing_api_keyNo Authorization header, or the scheme is not Bearer.
401invalid_api_keyTypo, truncated secret, or a revoked or expired key.
401environment_mismatchA test key used on a live-only resource, or the reverse.
403missing_scopeAdd the scope named in required_scope, or use another key.
403queue_not_allowedThe key is limited to other queues.

Suggested