Authentication
API keys, scopes, and idempotency.
legesis authenticates every API request with a workspace-scoped API key
passed in the X-API-Key header. The base URL is https://app.legesis.com.
curl $LEGESIS_API_BASE/api/v1/envelopes \
-H "X-API-Key: live_sk_..."Where keys come from
API keys are minted in the dashboard at Settings → API tokens. Each key:
- Belongs to exactly one workspace.
- Carries a set of scopes (see below).
- Has a creation timestamp, last-used timestamp, and optional expiry.
- Can be rotated or revoked at any time.
A key without a required scope returns 401 Unauthorized (workspace context
missing) or 403 Forbidden (scope missing) when it tries to call a guarded
endpoint.
Scopes
Scopes follow a <resource>:<action> convention. The table below enumerates
every scope referenced by the public API surface in
ExternalApiController (apps/api/src/modules/integration/external-api.controller.ts):
| Scope | Endpoints |
|---|---|
files:write | POST /files |
files:read | POST /files/:id/smart_tag_analysis, GET /smart_tag_schema |
envelopes:write | POST /envelopes, /send, /void, /expire |
envelopes:read | GET /envelopes/:id, GET /envelopes/:id/final_document |
events:read | GET /envelopes/:id/audit, GET /events, GET /events/:id |
webhook_endpoints:read | GET /webhook_endpoints, GET /webhook_endpoints/:id/deliveries |
webhook_endpoints:write | POST, PATCH, DELETE /webhook_endpoints[/:id], /rotate_secret |
SmartTag analysis additionally requires the smartTags workspace feature
flag, enforced via EntitlementGuard. Sending and creating webhook endpoints
are quota-gated (envelopesPerMonth, webhookEndpoints).
Idempotency
Every state-mutating endpoint that takes payment-shaped input — POST /envelopes, POST /envelopes/:id/send, POST /envelopes/:id/void, POST /envelopes/:id/expire — requires an Idempotency-Key request header.
The server returns 400 Bad Request if it is missing or empty
(requireIdempotencyKey, line 381).
curl -X POST $LEGESIS_API_BASE/api/v1/envelopes \
-H "X-API-Key: $LEGESIS_API_KEY" \
-H "Idempotency-Key: 7f3c2a8f-9e1d-4b56-9c2e-2cb1d7c3aaaa" \
...Use a fresh UUIDv4 per logical operation:
const key = crypto.randomUUID();Persist the key alongside whatever local state you have for the operation (database row, queue message). When you retry, reuse the same key.
The cache lifetime, body-mismatch behavior, and replay semantics for idempotent requests are documented separately in the API reference once it ships in week 2. Until then, treat the key as a hard requirement on the listed endpoints — not as an optional safety net.
What about JWTs?
JWTs are used internally for browser sessions in the legesis dashboard and for recipient signing tokens. They are not part of the public REST surface — every integrator should use API keys.