Developers

API reference

Every endpoint in the FolioSign REST API, generated from the OpenAPI specification — so it always matches the running code. For concepts, auth and error shapes, start with the REST API guide.

Authentication

Send a bearer credential on every request — an org API key (dctr_live_…) for machine-to-machine access, or a session token for a signed-in user.

curl https://foliosign.com/api/v1/documents \
  -H "Authorization: Bearer dctr_live_…"

Base URL https://foliosign.com · spec version 1.0.0 · download openapi.json

Identity & session

GET/api/v1/me

Current user, active org, and all memberships

Responses

  • 200The signed-in user
  • 401Not authenticated
DELETE/api/v1/me

Delete the account (App Store requirement)

Deletes the user and everything keyed to them (sessions, memberships, device tokens). Refused while the user is the sole owner of a workspace that still has other members — ownership must be transferred first. Workspaces where they were the only member are left orphaned rather than destroyed: signed documents are legal artifacts with an audit chain that other parties rely on.

Responses

  • 200Deleted
  • 400Sole owner of a shared workspace
  • 401Not authenticated
POST/api/v1/auth/send-verification

Resend the email-verification link to the signed-in user

Responses

  • 200Sent
  • 401Not authenticated
GET/api/v1/organizations

List the organizations the user belongs to

Responses

  • 200Memberships
  • 401Not authenticated
POST/api/v1/organizations

Create a workspace and set it active (new-user onboarding)

Takes a JSON request body — see the schema in openapi.json.

Responses

  • 200Created workspace
  • 400Invalid name
  • 401Not authenticated
POST/api/v1/organizations/{orgId}/switch

Set the active organization for this session

Parameters

NameInTypeNotes
orgId*pathstring

Responses

  • 200Switched
  • 401Not authenticated
  • 403Not a member of that organization
POST/api/v1/auth/sign-out

Revoke the current session token

Responses

  • 200Signed out
  • 401Not authenticated

Devices & push

POST/api/v1/devices

Register this device's APNs token for push notifications

Takes a JSON request body — see the schema in openapi.json.

Responses

  • 200Registered
  • 401Not authenticated
DELETE/api/v1/devices/{token}

Unregister a device token

Parameters

NameInTypeNotes
token*pathstring

Responses

  • 200Unregistered
  • 401Not authenticated

Dashboard

GET/api/v1/dashboard/pipeline

Value-weighted pipeline KPIs for the active org

Responses

  • 200Pipeline analytics
  • 401Not authenticated

Documents

GET/api/v1/documents

List documents (cursor-paginated, newest first)

Parameters

NameInTypeNotes
statusqueryDocumentStatus
sourcequeryDocumentSource
qquerystringFree-text search over document title and recipient name/email
cursorquerystring
limitqueryinteger
X-FolioSign-OrgheaderstringWorkspace to act on. Required when authenticating with an API key, which has no session and therefore no active workspace; ignored for session tokens, which use `POST /api/v1/organizations/{orgId}/switch` instead. A key may only name workspaces its own billing account parents — anything else is a 404. Omitting it on an API-key request is a 400 rather than a silent default, because a wrong-but-plausible default files one customer's signed documents under another.

Responses

  • 200A page of documents
  • 401Not authenticated
GET/api/v1/documents/{id}

Document detail with recipients

Parameters

NameInTypeNotes
id*pathstring
X-FolioSign-OrgheaderstringWorkspace to act on. Required when authenticating with an API key, which has no session and therefore no active workspace; ignored for session tokens, which use `POST /api/v1/organizations/{orgId}/switch` instead. A key may only name workspaces its own billing account parents — anything else is a 404. Omitting it on an API-key request is a 400 rather than a silent default, because a wrong-but-plausible default files one customer's signed documents under another.

Responses

  • 200The document
  • 401Not authenticated
  • 404Not found
GET/api/v1/documents/{id}/content

Builder blocks + variables (the reduced mobile editor's read)

Parameters

NameInTypeNotes
id*pathstring
X-FolioSign-OrgheaderstringWorkspace to act on. Required when authenticating with an API key, which has no session and therefore no active workspace; ignored for session tokens, which use `POST /api/v1/organizations/{orgId}/switch` instead. A key may only name workspaces its own billing account parents — anything else is a 404. Omitting it on an API-key request is a 400 rather than a silent default, because a wrong-but-plausible default files one customer's signed documents under another.

Responses

  • 200Blocks
  • 400Not a builder document
  • 401Not authenticated
  • 404Not found
PATCH/api/v1/documents/{id}/content

Update a draft's blocks (server re-validates; totals recomputed at render)

Parameters

NameInTypeNotes
id*pathstring
X-FolioSign-OrgheaderstringWorkspace to act on. Required when authenticating with an API key, which has no session and therefore no active workspace; ignored for session tokens, which use `POST /api/v1/organizations/{orgId}/switch` instead. A key may only name workspaces its own billing account parents — anything else is a 404. Omitting it on an API-key request is a 400 rather than a silent default, because a wrong-but-plausible default files one customer's signed documents under another.

Takes a JSON request body — see the schema in openapi.json.

Responses

  • 200Updated
  • 400Not a draft / invalid blocks
  • 401Not authenticated
GET/api/v1/documents/{id}/analytics

Per-recipient timeline and per-page view stats

Parameters

NameInTypeNotes
id*pathstring
X-FolioSign-OrgheaderstringWorkspace to act on. Required when authenticating with an API key, which has no session and therefore no active workspace; ignored for session tokens, which use `POST /api/v1/organizations/{orgId}/switch` instead. A key may only name workspaces its own billing account parents — anything else is a 404. Omitting it on an API-key request is a 400 rather than a silent default, because a wrong-but-plausible default files one customer's signed documents under another.

Responses

  • 200Analytics
  • 401Not authenticated
  • 404Not found
PUT/api/v1/documents/{id}/recipients

Replace the recipients on a draft

Parameters

NameInTypeNotes
id*pathstring
X-FolioSign-OrgheaderstringWorkspace to act on. Required when authenticating with an API key, which has no session and therefore no active workspace; ignored for session tokens, which use `POST /api/v1/organizations/{orgId}/switch` instead. A key may only name workspaces its own billing account parents — anything else is a 404. Omitting it on an API-key request is a 400 rather than a silent default, because a wrong-but-plausible default files one customer's signed documents under another.

Takes a JSON request body — see the schema in openapi.json.

Responses

  • 200Recipients
  • 400Not a draft
  • 401Not authenticated
POST/api/v1/documents/{id}/send

Send a draft for signature

Parameters

NameInTypeNotes
id*pathstring
X-FolioSign-OrgheaderstringWorkspace to act on. Required when authenticating with an API key, which has no session and therefore no active workspace; ignored for session tokens, which use `POST /api/v1/organizations/{orgId}/switch` instead. A key may only name workspaces its own billing account parents — anything else is a 404. Omitting it on an API-key request is a 400 rather than a silent default, because a wrong-but-plausible default files one customer's signed documents under another.

Takes a JSON request body — see the schema in openapi.json.

Responses

  • 200Sent or rendering
  • 400Not sendable
  • 401Not authenticated
POST/api/v1/documents/{id}/recipients/{rid}/resend

Re-mint a recipient's signing link and re-email it

Parameters

NameInTypeNotes
id*pathstring
rid*pathstring
X-FolioSign-OrgheaderstringWorkspace to act on. Required when authenticating with an API key, which has no session and therefore no active workspace; ignored for session tokens, which use `POST /api/v1/organizations/{orgId}/switch` instead. A key may only name workspaces its own billing account parents — anything else is a 404. Omitting it on an API-key request is a 400 rather than a silent default, because a wrong-but-plausible default files one customer's signed documents under another.

Responses

  • 200Fresh link
  • 401Not authenticated
  • 404Not found
POST/api/v1/documents/{id}/signing-link

Mint a fresh signing link for the caller's own recipient row

For a sender who is also a signer, so they can sign in-app without the email. Only ever returns the link for the recipient whose email matches the authenticated user; it cannot be used to obtain anyone else's link. Rotates the token, so any link previously emailed to that recipient stops working.

Parameters

NameInTypeNotes
id*pathstring
X-FolioSign-OrgheaderstringWorkspace to act on. Required when authenticating with an API key, which has no session and therefore no active workspace; ignored for session tokens, which use `POST /api/v1/organizations/{orgId}/switch` instead. A key may only name workspaces its own billing account parents — anything else is a 404. Omitting it on an API-key request is a 400 rather than a silent default, because a wrong-but-plausible default files one customer's signed documents under another.

Responses

  • 200Fresh link
  • 400Not signable by the caller
  • 401Not authenticated
  • 404Not found
POST/api/v1/documents/{id}/void

Void a draft or in-flight document

Parameters

NameInTypeNotes
id*pathstring
X-FolioSign-OrgheaderstringWorkspace to act on. Required when authenticating with an API key, which has no session and therefore no active workspace; ignored for session tokens, which use `POST /api/v1/organizations/{orgId}/switch` instead. A key may only name workspaces its own billing account parents — anything else is a 404. Omitting it on an API-key request is a 400 rather than a silent default, because a wrong-but-plausible default files one customer's signed documents under another.

Takes a JSON request body — see the schema in openapi.json.

Responses

  • 200Voided
  • 400Not voidable
  • 401Not authenticated
POST/api/v1/documents/{id}/remind

Manually nudge a recipient (or all outstanding signers)

Parameters

NameInTypeNotes
id*pathstring
X-FolioSign-OrgheaderstringWorkspace to act on. Required when authenticating with an API key, which has no session and therefore no active workspace; ignored for session tokens, which use `POST /api/v1/organizations/{orgId}/switch` instead. A key may only name workspaces its own billing account parents — anything else is a 404. Omitting it on an API-key request is a 400 rather than a silent default, because a wrong-but-plausible default files one customer's signed documents under another.

Takes a JSON request body — see the schema in openapi.json.

Responses

  • 200Reminder(s) sent
  • 401Not authenticated
  • 404Not found
POST/api/v1/documents/from-pdf

Create a document from a PDF, place a signature field, add the signer, and send

One call that uploads a PDF, adds a single signer, places their signature field, and (unless `send:false`) sends it — returning the signing link. Ideal for machine integrations that supply a ready-made PDF (e.g. a Letter of Authorization).

Parameters

NameInTypeNotes
X-FolioSign-OrgheaderstringWorkspace to act on. Required when authenticating with an API key, which has no session and therefore no active workspace; ignored for session tokens, which use `POST /api/v1/organizations/{orgId}/switch` instead. A key may only name workspaces its own billing account parents — anything else is a 404. Omitting it on an API-key request is a 400 rather than a silent default, because a wrong-but-plausible default files one customer's signed documents under another.

Takes a JSON request body — see the schema in openapi.json.

Responses

  • 200Created (and sent unless send=false)
  • 400Invalid PDF or field placement
  • 401Not authenticated
  • 403Missing scope
POST/api/v1/documents/upload

Create a draft document from a PDF

Uploads a PDF and leaves it as a DRAFT with no recipients or fields. Returns per-page geometry so a client can render the pages and place fields, then call PUT /documents/{id}/fields and POST /documents/{id}/send.

Parameters

NameInTypeNotes
X-FolioSign-OrgheaderstringWorkspace to act on. Required when authenticating with an API key, which has no session and therefore no active workspace; ignored for session tokens, which use `POST /api/v1/organizations/{orgId}/switch` instead. A key may only name workspaces its own billing account parents — anything else is a 404. Omitting it on an API-key request is a 400 rather than a silent default, because a wrong-but-plausible default files one customer's signed documents under another.

Takes a JSON request body — see the schema in openapi.json.

Responses

  • 200Draft created
  • 400Invalid PDF
  • 401Not authenticated
  • 403Missing scope
PUT/api/v1/documents/{id}/fields

Replace the fields on a draft

Coordinates are normalized 0..1 with a top-left origin, matching the signing ceremony's renderer. Drafts only.

Parameters

NameInTypeNotes
id*pathstring
X-FolioSign-OrgheaderstringWorkspace to act on. Required when authenticating with an API key, which has no session and therefore no active workspace; ignored for session tokens, which use `POST /api/v1/organizations/{orgId}/switch` instead. A key may only name workspaces its own billing account parents — anything else is a 404. Omitting it on an API-key request is a 400 rather than a silent default, because a wrong-but-plausible default files one customer's signed documents under another.

Takes a JSON request body — see the schema in openapi.json.

Responses

  • 200Fields replaced
  • 400Not a draft, or invalid placement
  • 401Not authenticated
  • 404No such document
POST/api/v1/documents/{id}/suggest-fields

Suggest where fields belong on an uploaded PDF

Reads the PDF's text layer and proposes signature/initials/date/text placements for a human to review. Nothing is saved — send what you accept to PUT /documents/{id}/fields. Costs 1 AI credit only when the model runs; the deterministic heuristics are free. A PDF with no text layer (a photo or flat scan) returns no suggestions.

Parameters

NameInTypeNotes
id*pathstring
X-FolioSign-OrgheaderstringWorkspace to act on. Required when authenticating with an API key, which has no session and therefore no active workspace; ignored for session tokens, which use `POST /api/v1/organizations/{orgId}/switch` instead. A key may only name workspaces its own billing account parents — anything else is a 404. Omitting it on an API-key request is a 400 rather than a silent default, because a wrong-but-plausible default files one customer's signed documents under another.

Responses

  • 200Suggestions
  • 400No uploaded PDF, or out of AI credits
  • 401Not authenticated
  • 404No such document
GET/api/v1/documents/{id}/source

Download the document's current PDF

The rendered PDF for a builder document, or the uploaded file for an upload — what the signer sees, before any signatures are applied. For the executed copy, use `/documents/{id}/sealed`.

Parameters

NameInTypeNotes
id*pathstring
X-FolioSign-OrgheaderstringWorkspace to act on. Required when authenticating with an API key, which has no session and therefore no active workspace; ignored for session tokens, which use `POST /api/v1/organizations/{orgId}/switch` instead. A key may only name workspaces its own billing account parents — anything else is a 404. Omitting it on an API-key request is a 400 rather than a silent default, because a wrong-but-plausible default files one customer's signed documents under another.

Responses

  • 200The PDF bytes
  • 401Not authenticated
  • 403API key is missing the documents:read scope
  • 404No such document here, or it has no PDF
GET/api/v1/documents/{id}/sealed

Download the sealed, certified PDF

The executed document: every signature applied, the certificate of completion appended, and the whole file digitally signed. This is the copy worth keeping — under a workspace-per-customer setup it is the only way the integration holds its customers' executed documents, since those workspaces have no sign-in of their own. Available once the document reaches `COMPLETED` and the seal job has run, which is shortly after the last signer finishes. Poll on `409`: it means not yet. A `404` means the document is not in this workspace, so stop. The response carries `X-Sealed-SHA256`, the same digest as `sealedSha256` on `GET /documents/{id}` — hash the bytes you received and compare, and you have proof the archived copy is the one that was signed.

Parameters

NameInTypeNotes
id*pathstring
X-FolioSign-OrgheaderstringWorkspace to act on. Required when authenticating with an API key, which has no session and therefore no active workspace; ignored for session tokens, which use `POST /api/v1/organizations/{orgId}/switch` instead. A key may only name workspaces its own billing account parents — anything else is a 404. Omitting it on an API-key request is a 400 rather than a silent default, because a wrong-but-plausible default files one customer's signed documents under another.

Responses

  • 200The sealed PDF bytes
  • 401Not authenticated
  • 403API key is missing the documents:read scope
  • 404No such document in this workspace
  • 409Not sealed yet — still awaiting signatures or the seal job

AI

POST/api/v1/ai/generate

Generate a proposal from an intake and create a draft document

Takes a JSON request body — see the schema in openapi.json.

Responses

  • 200Draft created
  • 400Out of AI credits or invalid intake
  • 401Not authenticated

Billing

GET/api/v1/billing/usage

Plan + usage snapshot for the active org

Responses

  • 200Usage summary
  • 401Not authenticated
GET/api/v1/billing/plans

The plan catalog (display copy + prices)

Responses

  • 200Plans
  • 401Not authenticated
POST/api/v1/billing/checkout

Start a Stripe Checkout to upgrade; returns a URL to open externally

Takes a JSON request body — see the schema in openapi.json.

Responses

  • 200Checkout link
  • 400Invalid plan
  • 401Not authenticated
  • 403Insufficient role
POST/api/v1/billing/apple/transaction

Apply a verified App Store subscription transaction

Takes the signed transaction (JWS) from StoreKit and verifies Apple's signature server-side before granting anything — the client's own verification result is not trusted. Idempotent: StoreKit re-delivers transactions until they are finished, and renewals arrive unprompted.

Takes a JSON request body — see the schema in openapi.json.

Responses

  • 200The plan now in force
  • 400Transaction failed verification
  • 401Not authenticated
  • 403Insufficient role
POST/api/v1/billing/portal

Open the Stripe customer portal; returns a URL to open externally

Responses

  • 200Portal link
  • 400No billing account yet
  • 401Not authenticated
  • 403Insufficient role

Admin

GET/api/v1/admin/users

List users across all workspaces

Parameters

NameInTypeNotes
searchquerystring
limitqueryinteger

Responses

  • 200Users
  • 401Not authenticated
  • 403Not a super-admin
POST/api/v1/admin/impersonate

Impersonate a user — returns a session token to use as the bearer

Takes a JSON request body — see the schema in openapi.json.

Responses

  • 200Impersonation token
  • 401Not authenticated
  • 403Not a super-admin
POST/api/v1/admin/impersonate/stop

Stop impersonating — returns the original admin session token

Responses

  • 200Original token (may be null)
  • 401Not authenticated

API keys

GET/api/v1/apikeys

List the active org's API keys (secrets never returned)

Responses

  • 200API keys
  • 401Not authenticated
  • 403Insufficient role / not available to API keys
POST/api/v1/apikeys

Create an API key; the full secret is returned exactly once

Takes a JSON request body — see the schema in openapi.json.

Responses

  • 201Created key (with secret)
  • 400Invalid name or scopes
  • 401Not authenticated
  • 403Insufficient role / not available to API keys
DELETE/api/v1/apikeys/{id}

Revoke an API key

Parameters

NameInTypeNotes
id*pathstring

Responses

  • 200Revoked
  • 401Not authenticated
  • 403Insufficient role / not available to API keys
  • 404Not found

Workspaces

GET/api/v1/workspaces

List the caller's workspaces and the plan's workspace allowance

For a signed-in user, the workspaces they are a member of. For an API key, every workspace in its billing group — a key has no memberships, and the workspaces it provisions have no members either. Use the returned `id` as `X-FolioSign-Org` on the document endpoints.

Responses

  • 200Workspaces
  • 401Not authenticated
  • 403API key is missing the workspaces:read scope
POST/api/v1/workspaces

Create a workspace under the same billing account

It bills through the same subscription while documents, templates and members stay separate. Refused when the plan's workspace allowance is already used, which on every plan but Corporate is one. Send `externalId` — your own id for this customer — to make the call idempotent: a repeat returns the workspace the first call created rather than a second one with the same name. There is no delete endpoint, so a duplicate cannot be undone through the API. A signed-in owner or admin becomes the new workspace's owner. An API key needs the `workspaces:write` scope; the workspace it creates has no members, and is reached by passing its `id` as `X-FolioSign-Org`.

Takes a JSON request body — see the schema in openapi.json.

Responses

  • 200Created, or the existing workspace for a repeated externalId
  • 400Allowance reached, or an invalid name
  • 401Not authenticated
  • 403Requires owner or admin, or the workspaces:write scope for an API key
DELETE/api/v1/workspaces/{id}

Delete an empty workspace

For undoing a duplicate — a provisioning call that was retried before you started sending `externalId`, say. It is not a way to close an account. Refused when the workspace holds **any** document, even a draft: a sent document's audit trail is evidence, and a cascade would destroy it silently. Delete or void the documents first. Also refused for the account's main workspace, which holds the subscription the others bill through. An API key needs the `workspaces:delete` scope, which is separate from `workspaces:write` and never granted by default.

Parameters

NameInTypeNotes
id*pathstring

Responses

  • 200Deleted
  • 400It holds documents, or it is the account's main workspace
  • 401Not authenticated
  • 403Requires owner or admin, or the workspaces:delete scope for an API key
  • 404No such workspace in this billing account

Settings

GET/api/v1/settings/branding

The workspace's brand colour

Responses

  • 200Branding
  • 401Not authenticated
PATCH/api/v1/settings/branding

Set the workspace's brand colour

Send null to clear it back to the FolioSign default. Owner or admin only.

Takes a JSON request body — see the schema in openapi.json.

Responses

  • 200Updated
  • 400Not a valid hex colour
  • 401Not authenticated
  • 403Requires owner or admin

oauth

GET/api/v1/oauth/grant

Health of the OAuth grant this token belongs to

Reports whether the calling token's grant is live, what it was granted, which billing account it acts on, and when each half of the credential expires. Intended to be polled (hourly is plenty) so an integration can surface connection health to its own operators rather than discovering a lapsed grant through documents silently not being sent. Requires an OAuth access token; an API key has no grant and gets a 403. No scope is required — a grant whose scopes have been narrowed must still be able to report that.

Responses

  • 200Grant health
  • 401Missing, expired (`token_expired`) or revoked (`grant_revoked`) credential
  • 403Authenticated with an API key, which has no grant