Reference

API reference

Every endpoint the XOsign API exposes. If it is not here, it does not exist.

Machine-readable

This page and /docs/api/openapi.json are generated from the same OpenAPI 3.1 document, so they cannot disagree. Import the JSON into Postman or feed it to a client generator.

Endpoints

Retrieve the current account

GEThttps://xosign.ai/api/v1/account
ScopeNone required

Returns the account behind the API key, plus the key's mode and scopes. The cheapest way to verify a key works and to see what it is allowed to do. Requires no scope.

Responses

StatusReturnsDescription
200AccountThe account.
401ErrorThe request carried no usable API key, so we could not tell who you are. Codes: missing_authorization, invalid_api_key.
403ErrorWe know who you are, but this key or this plan is not allowed to do that. Codes: insufficient_scope, api_access_required.
429ErrorYou sent more requests than your plan allows. Carries Retry-After. Codes: rate_limit_exceeded, ip_throttled.
500ErrorSomething failed on our side. Nothing is wrong with your request.

See the Account object below for its fields.

List documents

GEThttps://xosign.ai/api/v1/documents
Scopedocuments:read

Your documents, newest first, cursor-paginated. An account with no documents returns an empty list, never a 404. Templates are not included.

Parameters

NameInRequiredDescription
limitqueryOptionalHow many documents to return, 1–100.defaults to 20 · 1–100
starting_afterqueryOptionalA cursor from a previous response's `next_cursor`. Returns the page after it. Cannot be combined with `ending_before`.
ending_beforequeryOptionalA cursor from a previous response. Returns the page before it. Cannot be combined with `starting_after`.
statusqueryOptionalComma-separated statuses to include, e.g. `sent,completed`. Any unknown value rejects the whole request. One of: draft, sent, partially_signed, completed, voided, declined, expired, in_review.

Responses

StatusReturnsDescription
200DocumentListA page of documents.
400ErrorBad pagination or status filter. Codes: invalid_limit, invalid_cursor, conflicting_cursors, invalid_status.
401ErrorThe request carried no usable API key, so we could not tell who you are. Codes: missing_authorization, invalid_api_key.
403ErrorWe know who you are, but this key or this plan is not allowed to do that. Codes: insufficient_scope, api_access_required.
429ErrorYou sent more requests than your plan allows. Carries Retry-After. Codes: rate_limit_exceeded, ip_throttled.
500ErrorSomething failed on our side. Nothing is wrong with your request.

See the DocumentList object below for its fields.

Create a draft document

POSThttps://xosign.ai/api/v1/documents
Scopedocuments:write

Creates a draft and its recipients in one call. Nothing is delivered until you call send.

Field placement is not supported through the API — `content` accepts only the small metadata bag described below, and unknown properties are dropped silently.

Parameters

NameInRequiredDescription
Idempotency-KeyheaderOptionalOptional but strongly recommended on writes. A client-chosen string of at most 255 characters. Retrying with the same key and the same body replays the original response instead of performing the write twice.max 255 characters

Request body

FieldTypeRequiredDescription
titlestringRequiredmax 200 characters
typestringOptionalDefaults to `form`.one of 23 values · defaults to form
primary_languagestringOptionalone of: en, es · defaults to en
recipientsarrayRequired1–20 items
contentDocumentContentOptional

Responses

StatusReturnsDescription
201DocumentThe created draft.
400ErrorThe body was rejected. `param` names the exact field. See /docs/api/errors for every code.
401ErrorThe request carried no usable API key, so we could not tell who you are. Codes: missing_authorization, invalid_api_key.
403ErrorWe know who you are, but this key or this plan is not allowed to do that. Codes: insufficient_scope, api_access_required.
409ErrorIdempotency conflict. Codes: idempotency_key_reused, idempotency_in_progress.
429ErrorYou sent more requests than your plan allows. Carries Retry-After. Codes: rate_limit_exceeded, ip_throttled.
500ErrorSomething failed on our side. Nothing is wrong with your request.

See the Document object below for its fields.

Retrieve a document

GEThttps://xosign.ai/api/v1/documents/{id}
Scopedocuments:read

Poll this to watch a document progress from `sent` to `completed`.

Parameters

NameInRequiredDescription
idpathRequiredThe document id.

Responses

StatusReturnsDescription
200DocumentThe document.
401ErrorThe request carried no usable API key, so we could not tell who you are. Codes: missing_authorization, invalid_api_key.
403ErrorWe know who you are, but this key or this plan is not allowed to do that. Codes: insufficient_scope, api_access_required.
404ErrorNo such document is visible to your account. Also returned for a malformed id and for templates. Code: document_not_found.
429ErrorYou sent more requests than your plan allows. Carries Retry-After. Codes: rate_limit_exceeded, ip_throttled.
500ErrorSomething failed on our side. Nothing is wrong with your request.

See the Document object below for its fields.

List imports

GEThttps://xosign.ai/api/v1/imports
Scopeimports:read

Your bulk imports, newest first, cursor-paginated. An account that has never imported returns an empty list, never a 404.

Parameters

NameInRequiredDescription
limitqueryOptionalHow many imports to return, 1–100.defaults to 20 · 1–100
starting_afterqueryOptionalA cursor from a previous response's `next_cursor`. Returns the page after it. Cannot be combined with `ending_before`.
ending_beforequeryOptionalA cursor from a previous response. Returns the page before it. Cannot be combined with `starting_after`.
statusqueryOptionalComma-separated statuses to include. Any unknown value rejects the whole request. One of: running, finished.

Responses

StatusReturnsDescription
200ImportListA page of imports.
400ErrorBad pagination or status filter. Codes: invalid_limit, invalid_cursor, conflicting_cursors, invalid_status.
401ErrorThe request carried no usable API key, so we could not tell who you are. Codes: missing_authorization, invalid_api_key.
403ErrorWe know who you are, but this key or this plan is not allowed to do that. Codes: insufficient_scope, api_access_required.
429ErrorYou sent more requests than your plan allows. Carries Retry-After. Codes: rate_limit_exceeded, ip_throttled.
500ErrorSomething failed on our side. Nothing is wrong with your request.

See the ImportList object below for its fields.

Start an import

POSThttps://xosign.ai/api/v1/imports
Scopeimports:write

Brings documents into XOsign from DocuSign, Google Drive or Dropbox.

**DocuSign** (`source: docusign`) sweeps the connected account and files every completed envelope's documents, in the background. It returns immediately; poll the returned import to watch it. The account must already have connected DocuSign in Settings: that is an OAuth sign-in through a browser and cannot be done with a key.

**Google Drive and Dropbox** (`source: google_drive` or `dropbox`) import up to 25 files you name and answer when they are in — usually within seconds. Give your client at least 90 seconds before it times out; if it does time out, retry with the same `Idempotency-Key` to receive the answer. The answer carries every file's outcome in `items`, in the order you sent them, and one file failing never stops the rest. A file you have imported before comes back as the same document rather than a copy, so after a partial failure you can send the whole list again — with a new `Idempotency-Key`, or none, since the same key replays the earlier answer. For Drive, send a Google access token your own app minted; it is used for this request and kept nowhere. For Dropbox, send file links you already hold; nothing on our side connects to your Dropbox. Needs the Pro plan or above. A request naming N files spends N of your rate limit, and every file counts against your plan's import limits: files per day and storage per month. A file that comes back as a document you imported before uses no storage again, and a retry that replays an earlier answer spends one unit of your rate limit, not N.

Each file is also unlocked as an XOdoc, which is what the Unlock box (checked by default) does on an import in the app; that conversion is charged at 1 credit a page when it runs. Send `unlock_xodoc: false` to file them as they are, for no credits.

Parameters

NameInRequiredDescription
Idempotency-KeyheaderOptionalOptional but strongly recommended on writes. A client-chosen string of at most 255 characters. Retrying with the same key and the same body replays the original response instead of performing the write twice.max 255 characters

Request body

FieldTypeRequiredDescription
sourcestringRequired`docusign` sweeps an account that is already connected in Settings (that sign-in is an OAuth redirect through a browser, so a key cannot make it) and runs in the background. `google_drive` and `dropbox` import the files you name, and answer when they are in.one of: docusign, google_drive, dropbox
earlieststringOptionalDocuSign only. Bring envelopes completed on or after this instant. Omit to sweep everything.
access_tokenstringOptionalGoogle Drive only, and required there. A Google OAuth access token minted by your own Google app with the `drive.file` or `drive.readonly` scope. It is used for this request only and never stored or logged. Google tokens last about an hour; a retry with a refreshed token counts as the same request for idempotency.
filesarrayOptionalGoogle Drive and Dropbox, and required there: the files to import, each up to 150 MB. PDFs are accepted; Google Docs, Sheets and Slides arrive as PDFs exported by Google, which caps an export at 10 MB. Other kinds of file, and folders, come back failed with `unsupported_type`. What a file is gets decided from its contents, never its name.1–25 items
unlock_xodocbooleanOptionalGoogle Drive and Dropbox. Unlock each file as an XOdoc — what the Unlock box, checked by default, does on an import in the app. Each file reports what came of it in `unlock`, and the conversion is charged at 1 credit a page when it runs, as the app charges it. Send `false` to file them as they are: they consume no credits, and any of them can be unlocked from the document later.defaults to true

Responses

StatusReturnsDescription
201StartedImportThe import. A DocuSign migration has every count at zero and runs on; a Google Drive or Dropbox import is normally already finished and carries `items`.
400ErrorThe body was rejected, and nothing was created. Codes: invalid_source, invalid_earliest, docusign_not_connected, invalid_files, invalid_file_url, invalid_file_id, invalid_access_token, invalid_unlock_xodoc, google_token_rejected.
401ErrorThe request carried no usable API key, so we could not tell who you are. Codes: missing_authorization, invalid_api_key.
403ErrorWe know who you are, but this key or this plan is not allowed to do that. Codes: insufficient_scope, api_access_required, cloud_import_requires_pro, cloud_import_unavailable, cloud_import_test_key, import_quota_exceeded.
409ErrorA migration is already running for this connection, or an idempotency conflict. A retry with the same key while a Google Drive or Dropbox import is still running gets idempotency_in_progress; retry a few seconds later to receive its answer. Codes: import_already_running, idempotency_key_reused, idempotency_in_progress.
429ErrorYou sent more requests than your plan allows. Carries Retry-After. Codes: rate_limit_exceeded, ip_throttled.
500ErrorSomething failed on our side. Nothing is wrong with your request.
502ErrorNothing was started. Codes: import_not_started, google_unavailable.

See the StartedImport object below for its fields.

Retrieve an import

GEThttps://xosign.ai/api/v1/imports/{id}
Scopeimports:read

Poll this while a migration runs. `remaining` reaching zero with `status: finished` is the end; `total_files` grows while a DocuSign sweep is still listing.

Parameters

NameInRequiredDescription
idpathRequiredThe import id.

Responses

StatusReturnsDescription
200ImportThe import.
401ErrorThe request carried no usable API key, so we could not tell who you are. Codes: missing_authorization, invalid_api_key.
403ErrorWe know who you are, but this key or this plan is not allowed to do that. Codes: insufficient_scope, api_access_required.
404ErrorNo import with that id. Code: import_not_found.
429ErrorYou sent more requests than your plan allows. Carries Retry-After. Codes: rate_limit_exceeded, ip_throttled.
500ErrorSomething failed on our side. Nothing is wrong with your request.

See the Import object below for its fields.

List an import's files

GEThttps://xosign.ai/api/v1/imports/{id}/items
Scopeimports:read

Every file inside one import, each with its own outcome, oldest first. For an import started from Google Drive or Dropbox that is the order you sent the files, and each carries its `index` in that request. A DocuSign migration or a browser drop lists its files here the same way, while it runs and after.

Parameters

NameInRequiredDescription
idpathRequiredThe import id.
limitqueryOptionalHow many files to return, 1–100.defaults to 20 · 1–100
starting_afterqueryOptionalA cursor from a previous response's `next_cursor`. Returns the page after it. Cannot be combined with `ending_before`.
ending_beforequeryOptionalA cursor from a previous response. Returns the page before it. Cannot be combined with `starting_after`.

Responses

StatusReturnsDescription
200ImportItemListA page of files.
400ErrorBad pagination. Codes: invalid_limit, invalid_cursor, conflicting_cursors.
401ErrorThe request carried no usable API key, so we could not tell who you are. Codes: missing_authorization, invalid_api_key.
403ErrorWe know who you are, but this key or this plan is not allowed to do that. Codes: insufficient_scope, api_access_required.
404ErrorNo import with that id. Code: import_not_found.
429ErrorYou sent more requests than your plan allows. Carries Retry-After. Codes: rate_limit_exceeded, ip_throttled.
500ErrorSomething failed on our side. Nothing is wrong with your request.

See the ImportItemList object below for its fields.

Send a document for signature

POSThttps://xosign.ai/api/v1/documents/{id}/send
Scopedocuments:send

Moves a draft to `sent` and delivers a signature request to each recipient over its channel.

Takes no body — send options come from the `content` you supplied at creation. Only a draft or in-review document can be sent; sending an already-sent document returns `document_not_sendable`.

A test-mode key still transitions the document to `sent` but delivers no email or SMS.

Parameters

NameInRequiredDescription
idpathRequiredThe document id.
Idempotency-KeyheaderOptionalOptional but strongly recommended on writes. A client-chosen string of at most 255 characters. Retrying with the same key and the same body replays the original response instead of performing the write twice.max 255 characters

Responses

StatusReturnsDescription
200DocumentThe document, now `sent`.
400ErrorThe document cannot be sent as it stands. Codes: document_not_sendable, no_recipients, no_signers, recipient_contact_required, approver_requires_sequential, pay_app_unsigned.
401ErrorThe request carried no usable API key, so we could not tell who you are. Codes: missing_authorization, invalid_api_key.
403ErrorWe know who you are, but this key or this plan is not allowed to do that. Codes: insufficient_scope, api_access_required.
404ErrorNo such document. Code: document_not_found.
409ErrorIdempotency conflict. Codes: idempotency_key_reused, idempotency_in_progress.
429ErrorYou sent more requests than your plan allows. Carries Retry-After. Codes: rate_limit_exceeded, ip_throttled.
500ErrorSomething failed on our side. Nothing is wrong with your request.

See the Document object below for its fields.

List a document's recipients

GEThttps://xosign.ai/api/v1/documents/{id}/recipients
Scoperecipients:read

Per-recipient progress: who was sent to, who opened it, who signed, who declined.

This needs its own `recipients:read` scope, separate from `documents:read`, so a key can list documents without reading signer contact details.

Parameters

NameInRequiredDescription
idpathRequiredThe document id.

Responses

StatusReturnsDescription
200RecipientListThe recipients, ordered by `sign_order`. A document with none returns an empty list.
401ErrorThe request carried no usable API key, so we could not tell who you are. Codes: missing_authorization, invalid_api_key.
403ErrorWe know who you are, but this key or this plan is not allowed to do that. Codes: insufficient_scope, api_access_required.
404ErrorNo such document. Code: document_not_found.
429ErrorYou sent more requests than your plan allows. Carries Retry-After. Codes: rate_limit_exceeded, ip_throttled.
500ErrorSomething failed on our side. Nothing is wrong with your request.

See the RecipientList object below for its fields.

Objects

The shapes returned by the endpoints above. Every field listed is always present — optional values arrive as null rather than being omitted, so you can read them without guarding for absence.

Document

A document in your account.

FieldTypeRequiredDescription
objectstringRequiredone of: document
idstringRequired
typestringRequiredThe kind of document. Determines which workflows apply to it.one of 23 values
statusstringRequiredone of: draft, sent, partially_signed, completed, voided, declined, expired, in_review
titlestringRequired
descriptionstring or nullRequired
primary_languagestringRequiredone of: en, es
secondary_languagestring or nullRequired
recipient_countintegerRequiredHow many recipients are on the document.
sent_atstring or nullRequired
completed_atstring or nullRequiredSet when every signer has signed.
voided_atstring or nullRequired
voided_reasonstring or nullRequired
expires_atstring or nullRequired
created_atstringRequired
updated_atstringRequired

Recipient

A party on a document. Signing links and any authentication material are never exposed.

FieldTypeRequiredDescription
objectstringRequiredone of: recipient
idstringRequired
document_idstringRequired
display_namestringRequired
emailstring or nullRequired
phonestring or nullRequired
party_rolestring or nullRequired
channelstringRequiredone of: email, sms, in_person
sign_orderintegerRequired
auth_levelstringRequiredone of: l0_email_link, l1_email_sms_otp, l0_account_session
statusstringRequired
sent_atstring or nullRequired
viewed_atstring or nullRequired
signed_atstring or nullRequired
declined_atstring or nullRequired
declined_reasonstring or nullRequired

Account

The account the calling API key belongs to.

FieldTypeRequiredDescription
objectstringRequiredone of: account
idstringRequired
display_namestringRequired
tierstringRequiredThe account's current plan. Determines your rate limits.
created_atstringRequired
modestringRequiredEchoes which kind of key made this request.one of: live, test
scopesarrayRequiredThe scopes granted to the key that made this request.

DocumentList

FieldTypeRequiredDescription
objectstringRequiredone of: list
dataarrayRequired
has_morebooleanRequiredWhether another page exists after this one.
next_cursorstring or nullRequiredPass as `starting_after` to fetch the next page. Null when `has_more` is false. Opaque — never construct or parse one.

ImportList

FieldTypeRequiredDescription
objectstringRequiredone of: list
dataarrayRequired
has_morebooleanRequiredWhether another page exists after this one.
next_cursorstring or nullRequiredPass as `starting_after` to fetch the next page. Null when `has_more` is false. Opaque — never construct or parse one.

StartedImport

What starting an import answers. A DocuSign migration answers with the Import, every count at zero, and runs in the background. A Google Drive or Dropbox import answers when its files are in: the Import, normally already `finished`, plus `items` — every file's outcome, in the order you sent them.

FieldTypeRequiredDescription
objectstringRequiredone of: import
idstringRequired
sourcestringRequired`docusign` is a swept migration. `google_drive` and `dropbox` are imports started through this API. `upload` is everything else feeding the same lane: a browser drop, or a Drive or Dropbox pick made in the app. New values may be added; treat one you do not recognise as `upload`.one of: docusign, google_drive, dropbox, upload
statusstringRequired`finished` means every file is filed or failed. An import that finished with failures is still `finished` — the counts say what happened.one of: running, finished
total_filesintegerRequiredHow many files the lane knows about. On a DocuSign migration this GROWS while the sweep is still listing envelopes, so do not treat it as a fixed denominator until `status` is `finished` — poll `remaining` instead.
filedintegerRequiredFiles that landed as documents.
failedintegerRequiredFiles that did not land. Each carries its own reason on the import screen.
remainingintegerRequiredStill queued or in flight. Zero with `status: finished` is the end.
created_atstringRequired
finished_atstring or nullRequired
itemsarrayOptionalPresent for a Google Drive or Dropbox import; absent for DocuSign.

Import

One bulk import: a DocuSign migration, or a batch of files dropped or picked from cloud storage. All four counts come from a SQL aggregate, so they are exact however large the import is.

FieldTypeRequiredDescription
objectstringRequiredone of: import
idstringRequired
sourcestringRequired`docusign` is a swept migration. `google_drive` and `dropbox` are imports started through this API. `upload` is everything else feeding the same lane: a browser drop, or a Drive or Dropbox pick made in the app. New values may be added; treat one you do not recognise as `upload`.one of: docusign, google_drive, dropbox, upload
statusstringRequired`finished` means every file is filed or failed. An import that finished with failures is still `finished` — the counts say what happened.one of: running, finished
total_filesintegerRequiredHow many files the lane knows about. On a DocuSign migration this GROWS while the sweep is still listing envelopes, so do not treat it as a fixed denominator until `status` is `finished` — poll `remaining` instead.
filedintegerRequiredFiles that landed as documents.
failedintegerRequiredFiles that did not land. Each carries its own reason on the import screen.
remainingintegerRequiredStill queued or in flight. Zero with `status: finished` is the end.
created_atstringRequired
finished_atstring or nullRequired

ImportItemList

FieldTypeRequiredDescription
objectstringRequiredone of: list
dataarrayRequired
has_morebooleanRequiredWhether another page exists after this one.
next_cursorstring or nullRequiredPass as `starting_after` to fetch the next page. Null when `has_more` is false. Opaque — never construct or parse one.

RecipientList

Recipient sets are small and bounded, so this list is never paginated: `has_more` is always false and `next_cursor` always null.

FieldTypeRequiredDescription
objectstringRequiredone of: list
dataarrayRequired
has_morebooleanRequired
next_cursorstring or nullRequired

Errors

Every endpoint can return the shared error envelope. The full catalogue of types and codes is on the errors page.

json
{
  "error": {
    "type": "not_found",
    "code": "document_not_found",
    "message": "No document with that id.",
    "doc_url": "https://xosign.ai/docs/api/errors#not_found",
    "request_id": "req_b07b069f0a83492877e3fa31"
  }
}