Skip to content
On this page

Developers

Markdown

API quick start

Create an API key, make your first request, and learn how errors, limits, retries and pagination work in the eSignStack API.

Create an API key

  1. Open Developers → API keys and click Create key.
  2. Enter a Key name and, if you want, an Expiry.
  3. Choose the Key mode: Test for sandbox data or Live for real envelopes.
  4. Choose abilities. Read only, Send envelopes and Full access fill in common sets; you can change them one by one.
  5. Copy the secret from the dialog. It's shown once and can't be retrieved later.

Workspace owners, admins and developers can manage keys. Developers can only issue keys with the webhooks:read, webhooks:write and keys:write abilities. To revoke a key, open its ⋯ menu and click Revoke, or call DELETE /api/v1/api_keys/{key}.

Keep secrets on your server. Never put a key in browser code, a mobile app, logs or source control.

Key types

Prefix Key Scope
rk_live_ Workspace key, live One workspace. Created under Developers → API keys.
rk_test_ Workspace key, test The same workspace's sandbox data.
sk_live_ Platform secret key Every workspace the platform owns. Created in the platform console.
sk_test_ Platform secret key, test Sandbox data of the platform's workspaces.

A key only sees data in its own mode: a test key can't read live envelopes, and a live key can't read test ones. Test keys create and send watermarked test envelopes, from a file or a template, and nothing counts toward your limits. SMS verification is refused in test mode (422), and changing brand kits, folders, filing rules or identity providers needs a live key (403 live_key_required). See Sandbox for more. A platform key acts inside a workspace when you send Workspace-Id: ws_…; see the platform integration guide.

Abilities

Every key lists its abilities explicitly. There are no wildcards.

Ability Allows
envelopes:read Read envelopes, recipients, documents and fields
envelopes:write Create and edit drafts, preview, duplicate, signing sessions, archive and restore, place legal holds
envelopes:send Send, remind, extend and correct envelopes
envelopes:void Void envelopes
templates:read, templates:write Read or change templates
folders:read, folders:write Read or change folders and filing rules
files:write Upload files
artifacts:read Download completed PDFs, one by one or as a ZIP
webhooks:read, webhooks:write Read events; manage webhook endpoints
brand_kits:read, brand_kits:write Read or change branding
usage:read Read usage counters
workspaces:export Export workspace data
audit:read Read the workspace activity log (GET /audit_events, live keys only). Never in a preset
keys:write List, create and revoke keys

Platform keys can also hold platform:read (read the platform's settings and members), workspaces:read, workspaces:write, login_links:write and identity_providers:write. A key created through the API (POST /api/v1/api_keys) has the same mode as the key that created it, so a test key can only issue test keys. It also can't have abilities its creator doesn't have, and can't outlive it.

Make your first request

The base URL is https://esignstack.app/api/v1. Send the key as a bearer token. This request returns the key's own details and needs no ability:

bash
curl https://esignstack.app/api/v1/api_keys/current \
  -H "Authorization: Bearer $ESIGNSTACK_KEY"

Objects use prefixed IDs such as env_…, rcp_…, tpl_… and file_…. JSON keys are snake_case. Every object has object, id, created (a UTC timestamp such as 2026-11-02T18:15:00+00:00) and livemode.

Create an envelope from a template

Get the template's role labels with GET /api/v1/templates/{template}, then map each person to a role:

bash
curl -X POST https://esignstack.app/api/v1/templates/$TEMPLATE_ID/envelopes \
  -H "Authorization: Bearer $ESIGNSTACK_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-456-create" \
  -d '{
    "name": "Acme service agreement",
    "recipients": [
      {"role_label": "Client", "name": "Jane Doe", "email": "jane@example.com"}
    ],
    "external_id": "order-456",
    "send": false
  }'

Roles that the template always sends to the same person (recipient_email on the role) are filled in for you, so you can leave them out. Include one to send that role to someone else on this envelope.

send defaults to true. With send: false the envelope stays a draft so you can check it, then send it with POST /api/v1/envelopes/{envelope}/send. values fills template fields by label. To start from your own PDF instead, see the Envelopes API.

Idempotency keys

Send an Idempotency-Key header (up to 255 characters) on POST requests, and reuse it when you retry the same request after a timeout.

  • A repeat of a completed request returns the stored response with Idempotent-Replayed: true.
  • The same key with a different request returns 409 idempotency_key_reused.
  • A request still running returns 409 idempotency_key_in_progress with Retry-After.
  • Requests that fail don't use up the key. Keys are kept for 24 hours.
  • The header is ignored on POST /verify, POST /login_identities/{id}/deprovision and POST /identity_providers/{idp}/subjects/{sub}/deprovision.

Errors

Errors return JSON with an error object:

json
{
  "error": {
    "type": "invalid_request_error",
    "code": "validation_failed",
    "message": "The name field is required.",
    "param": "name",
    "doc_url": "https://esignstack.app/docs/api#validation_failed",
    "request_id": "req_01J…"
  }
}
Status Common codes
400 invalid_request, workspace_required (a platform key without Workspace-Id), api_version_unsupported
401 authentication_required: missing, invalid or expired key
403 permission_denied: missing ability, suspended workspace; live_key_required
404 resource_missing: not found in this workspace and mode
409 resource_conflict, correction_requires_void, idempotency codes
422 validation_failed
429 rate_limit_exceeded

Every response has a Request-Id header. Include it when you contact support.

API envelope limits

API and MCP envelopes have their own monthly allowance. An envelope counts when it's sent through the API or MCP in live mode, or when the API issues a signing session for an envelope that was sent another way. Test envelopes never count.

Plan API and MCP envelopes
Free Part of the plan's 5 envelopes a month (app and API together)
Starter 50 a month
Pro 200 a month
Platform 500 a month included, then 25¢ each

Yearly plans get 12 months of allowance up front (for example, 600 on Starter). On Platform, envelopes past the allowance are billed as you go. You can set a monthly spending cap on extra envelopes on the Billing page.

When a send is refused, the API returns 422 with code validation_failed, param set to document, and a quota object that says which limit was hit and when it resets:

json
"quota": { "code": "api_envelope_limit_reached", "resets_at": "2026-11-01T00:00:00Z" }
quota.code Meaning
envelope_limit_reached The Free plan's 5 envelopes are used
api_envelope_limit_reached The plan's API allowance is used
api_spending_cap_reached Platform: the spending cap on extra envelopes is reached
api_overage_unavailable Platform: extras are paused, for example an unpaid invoice

GET /api/v1/usage (ability usage:read) returns current usage, including api_envelopes with used, limit, remaining and resets_at. A platform key without Workspace-Id also gets platform, the platform's own allowance, extras and spending cap.

Rate limits

Each key can make 100 requests a second, and each workspace 6,000 requests a minute across all its keys. Responses carry RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset and RateLimit-Policy. Over the limit you get 429 with Retry-After; wait that long before retrying.

Versions

The current version is 2026-10-14. Each key is pinned to the version current when it was created. Send Api-Version to choose a version per request; responses echo the version used. New fields can appear in responses at any time, so ignore fields you don't recognize.

Pagination

List endpoints return object: "list", data, has_more and url, newest first. Use limit (1 to 100, default 20) and pass the last ID you received as starting_after to get the next page, or the first ID as ending_before to go back. Some endpoints take expand[], for example expand[]=recipients on envelopes.

The full list of endpoints, fields and filters is in the API reference.