legesis docs

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):

ScopeEndpoints
files:writePOST /files
files:readPOST /files/:id/smart_tag_analysis, GET /smart_tag_schema
envelopes:writePOST /envelopes, /send, /void, /expire
envelopes:readGET /envelopes/:id, GET /envelopes/:id/final_document
events:readGET /envelopes/:id/audit, GET /events, GET /events/:id
webhook_endpoints:readGET /webhook_endpoints, GET /webhook_endpoints/:id/deliveries
webhook_endpoints:writePOST, 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/expirerequires 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.

On this page