Core concepts
Authentication and scopes
Every API request carries an organization API key as a Bearer token. A key belongs to exactly one organization and acts on behalf of the admin who created it.
Send the key#
GET /api/v1/documents HTTP/1.1
Host: sign.yt
Authorization: Bearer sk_live_9f2c...Keys start with sk_live_. Requests without a valid key return 401 with code unauthenticated and a WWW-Authenticate: Bearer header. Use HTTPS only and never ship a key to a browser or mobile app; call the API from your server.
Create and manage keys#
- Keys are created in the app under API keys by an organization admin. API keys cannot create other keys.
- The full key is shown once. sign.yt stores only a SHA-256 hash and a short prefix for display, so a lost key cannot be recovered: revoke it and create a new one.
- Each key has a name, one or more scopes and an optional expiry. Revoked or expired keys return
401. - API access is a plan feature (Business and Enterprise). If the organization's plan does not include it, every key request returns
402with codefeature_not_in_plan.
Scopes#
Scopes are checked centrally by path prefix and HTTP method, deny by default. GET and HEAD need the :read scope of the family; every other method needs :write. A :write scope does not imply :read, so grant both when you need both.
| Scope | Grants | Path prefixes |
|---|---|---|
documents:read | GET/HEAD | /api/v1/documents, /api/v1/lookup |
documents:write | POST/PUT/PATCH/DELETE | /api/v1/documents, /api/v1/lookup |
templates:read | GET/HEAD | /api/v1/templates, /api/v1/template-catalog |
templates:write | POST/PUT/PATCH/DELETE | /api/v1/templates, /api/v1/template-catalog |
webhooks:read | GET/HEAD | /api/v1/webhooks |
webhooks:write | POST/PUT/PATCH/DELETE | /api/v1/webhooks |
webhooks:manage | Umbrella (legacy, kept for existing keys) | webhooks:read + webhooks:write |
flows:read | GET/HEAD | /api/v1/flows, /api/v1/flow-runs |
flows:write | POST/PUT/PATCH/DELETE | /api/v1/flows, /api/v1/flow-runs |
admin | Umbrella | All of the above, read and write |
A request outside these prefixes (organization settings, billing, users, API keys, campaigns, smart document packages and other app-only areas) returns 403 with the message "API keys cannot access this endpoint". GET /api/v1/documents/inbox is personal to a logged-in user and is also blocked for keys. A key that lacks the needed scope gets:
{
"code": "insufficient_scope",
"message": "Missing scope documents:write",
"detail": "Missing scope documents:write",
"request_id": "9f2c1a7e4b0d3e11"
}Effective permissions#
A key's identity is the pair (key creator, key organization). What a request may do is the intersection of the key's scopes and the creator's current role in that organization:
- Role-gated endpoints apply the creator's role. For example, webhooks require the creator to be an organization admin, even with
webhooks:manage. - The key stops working (
401) when the organization is deleted, when the creator leaves the organization or is locked, or when the key is revoked or expires. Rotate keys owned by people who leave. - Platform-level roles of the creator are never carried by a key.
- Documents are visible to a key the same way they are visible to its creator in the app (team and folder access rules apply).
Tenancy and custom domains#
All data is scoped to the key's organization. Resources of other organizations are reported as 404 not_found, never 403, so the API does not reveal whether an ID exists elsewhere.
The API is served on https://api.sign.yt/v1 (also reachable as https://sign.yt/api/v1) and also on each organization's custom domain (for example https://sign.example.com/api/v1). On a custom domain the key must belong to that domain's organization, otherwise the request is rejected with 403. Using https://api.sign.yt/v1 everywhere is the simplest choice. That host accepts API keys only; browser session cookies are ignored there.
Restrict a key to IP addresses#
A key can carry an allowlist of IP addresses or CIDR ranges. Requests from any other address are rejected before the scope check and do not update the key's last-used time. Leave the list empty to accept any address (the default).
- Set it under API keys when creating a key, or edit it later (pencil icon). Admins see their current IP next to the field.
- IPv4 and IPv6 addresses and CIDR ranges, one per entry, up to 50 per key (for example
203.0.113.7,10.0.0.0/24,2001:db8::/32). Host bits are normalized away.0.0.0.0/0and::/0are rejected: leave the list empty instead. - IPv4-mapped IPv6 addresses (
::ffff:203.0.113.7) are treated as the IPv4 address. - The address is the one sign.yt sees for your connection. Proxy headers such as
X-Forwarded-Forsent by clients are ignored, so they cannot be used to bypass the list. If you call from behind a NAT or a proxy, allow its public egress address. - Each blocked address is recorded in the organization's audit log (
API_KEY_IP_DENIED), at most once per ten minutes per key and address. Changes to the list are audited too.
{
"code": "ip_not_allowed",
"message": "Requests from IP 198.51.100.4 are not allowed for this API key",
"detail": "Requests from IP 198.51.100.4 are not allowed for this API key",
"request_id": "9f2c1a7e4b0d3e11"
}Key hygiene#
- One key per integration and environment, with the smallest set of scopes it needs.
- Set an expiry for keys used by contractors or short projects.
- Keys are bearer secrets: keep them out of source control, logs, URLs and client-side code.
- Each key is limited to 100 requests per second; see Rate limits.