API Keys
Create, scope, rotate, and revoke API keys for programmatic access to the VeriWorkly API.
API Keys
API keys authenticate programmatic requests to the VeriWorkly API. Session cookies are designed for browser use; API keys let you integrate VeriWorkly into your own scripts and applications.
Getting an API Key
Key management lives on its own page in Studio, not inside the settings panels (the Settings page links to it).
- Log in to app.veriworkly.com.
- Go to
/api-keys— reachable from Settings → Developer API keys, or directly. - Click Create key.
- Give the key a descriptive name, pick its scopes, and optionally set a rate limit and expiry.
- Copy the key immediately. The full value is shown exactly once and is never recoverable.
Keys are prefixed vw_ followed by 64 hex characters.
Key safety model
VeriWorkly never stores the key itself. Only an irreversible HMAC-SHA256 hash is persisted, using
a hashing secret (API_KEY_HASH_SECRET) that production configuration requires to be distinct from
the general auth secret. The stored record also keeps the key's first and last 8 characters; the
list endpoint returns only the leading keyPrefix, which is enough to tell keys apart without
being able to reconstruct one.
Each key carries:
| Property | Default | Notes |
|---|---|---|
| Scopes | user:read | Applied when a key is created without explicit scopes. |
| Expiry | 365 days | Configurable per key at creation. |
| Rate limit | 20 requests / 15 minutes | Configurable per key, capped by a server-side maximum. |
Using your API Key
Send the key in the X-API-Key header:
curl -H "X-API-Key: YOUR_API_KEY" https://api.veriworkly.com/api/v1/users/meAn Authorization bearer token is accepted as an equivalent alternative, which is often easier
with HTTP clients that assume standard auth headers:
curl -H "Authorization: Bearer YOUR_API_KEY" https://api.veriworkly.com/api/v1/users/meScopes
A key may only carry scopes the backend recognises. Requesting an unknown scope fails the create or
rotate call with 400 Unsupported API key scope(s).
| Scope | Grants |
|---|---|
user:read | Read your account profile and identity details. |
user:write | Update user-facing profile fields (name, username, auto-sync setting). |
resume:read | Read resume-backed document content and metadata. |
resume:write | Create, edit, delete, sync, and share resume-backed documents. |
roadmap:read | Read public roadmap items and release-planning data. |
changelog:read | Read changelog entries and changelog statistics. |
github:read | Read the synced GitHub issue and repository statistics. |
ai:write | Call /ai/generate, /ats/analyze, and /ats/convert-resume, spending AI credits. |
`changelog:read` is API-only today
All eight scopes above are accepted by the backend. The Studio scope picker currently surfaces
seven of them — changelog:read can be requested through the API-key create/rotate endpoints, but
has no checkbox in the UI yet. The endpoints it unlocks are documented under
Changelog.
There is no write scope for roadmap or GitHub
Both the roadmap and GitHub data surfaces are read-only for API keys. roadmap:write and
github:write do not exist and will be rejected.
Rate limits
| Limit type | Rate |
|---|---|
| Per-key default | 20 requests per 15 minutes |
| Per-key maximum | 600 requests per 15 minutes (API_KEY_MAX_RATE_LIMIT) |
A key's rate limit is set at creation and can be raised on rotation, up to the server-side maximum. A requested value above the maximum is clamped down to it rather than rejected.
Exceeding the limit returns 429 Too Many Requests with headers indicating when to retry:
Retry-After— seconds to wait before the next request.X-RateLimit-Limit— maximum requests allowed in the window.X-RateLimit-Remaining— remaining requests in the current window.X-RateLimit-Reset— Unix timestamp when the limit resets.
Per-key limits sit on top of the general per-route IP rate limiter, so a burst can be throttled by either.
Rotation and revocation
- Rotate — issues a replacement key and retires the old one. Use this when the integration is still needed.
- Revoke — turns the key off permanently. Use this when the key should stop existing.
Authentication results are cached in Redis for 5 minutes by default
(API_KEY_AUTH_CACHE_TTL_SECONDS), and that cache entry is dropped immediately when a key is
revoked, so a revoked key stops working right away rather than at the end of its cache window.
Keys are invalidated when a subscription lapses
If the owning account's subscription moves to a cancelled or inactive state, its API keys stop authenticating. The billing webhook busts the auth cache the moment it processes the change, so the effect is immediate rather than delayed by the normal 5-minute TTL.
The lastUsed timestamp is written at a throttled interval
(API_KEY_LAST_USED_TOUCH_INTERVAL_SECONDS, default 300 seconds) rather than on every request, so it
is approximate by design.
Security best practices
- Never share a key, and never commit one to version control — use environment variables.
- Prefer the smallest scope set that makes the integration work.
- Use shorter expiries for risky or short-lived integrations.
- Revoke compromised keys immediately and issue a replacement.
- Use descriptive names so an unfamiliar key is easy to trace back to its integration.
For production operating procedure — rotation schedules, incident response, release checks — see the API Key Security Runbook.