Chaindoc REST API reference
Full endpoint reference for the Chaindoc REST API. Covers authentication, documents, signatures, media uploads, embedded sessions, and blockchain verification.
API basics
Base URL: https://api.chaindoc.io/api/v1 (Authentication: Bearer token (API key)) Business plan required. If you haven't set up API keys yet, see the API integration guide for setup and common patterns.
Overview
The API gives you programmatic access to everything in Chaindoc: documents, signatures, blockchain verification, and team management. It's designed for server-to-server use and supports both public and secret API keys. Learn more in the RFC 9110 — HTTP Semantics.
- Documents: create, update, and verify documents on the blockchain
- Signatures: send signature requests and track completion
- Media: upload PDFs, images, and videos (max 10 per request)
- Contracts: draft, send, cancel, and terminate contracts with optional payment terms
- Invoices & Transactions: bill contragents, charge saved payment methods, track settlements
- Templates: render documents, signature requests, and contracts from published templates
- Embedded sessions: create signing sessions for your frontend (uses the Embed SDK)
Authentication
Every request needs an API key in the Authorization header. There are two types:. Learn more in the RFC 6749 — OAuth 2.0.
Key types
- Public key (
pk_). read-only, safe for frontend code - Secret key (
sk_). full read/write, backend only. Never expose in client-side code.
Key security
Store keys in environment variables, not in your codebase. Rotate keys periodically and immediately after any suspected compromise. See the security guide for more.
Getting your keys
- 1Subscribe to Business planOnly Business plan users can create API keys
- 2Navigate to API AccessGo to Settings → API Access in your dashboard
- 3Create API keyClick Create API Key button
- 4Store securelyStore the secret key securely (shown only once)
Using API keys
Include your API key in the Authorization header with Bearer authentication:
curl -X GET https://api.chaindoc.io/api/v1/me \
-H "Authorization: Bearer sk_xxxxxxxxxxxxx"Rate limiting
All public API endpoints are limited to 10 requests per 60 seconds per API key. When the limit is exceeded, you'll receive a 429 Too Many Requests response. back off and retry after a short delay.
Error handling
HTTP status codes
- 200 - Success
- 201 - Resource created successfully
- 400 - Bad request (validation error)
- 401 - Unauthorized (invalid or missing API key)
- 403 - Forbidden (insufficient permissions)
- 404 - Resource not found
- 429 - Too many requests (rate limit exceeded)
- 500 - Internal server error
Error response format
{
"statusCode": 400,
"message": [
"name must be a string",
"recipients should not be empty"
],
"error": "Bad Request"
}Validation errors return message as an array of human-readable strings, one per failed constraint. For non-validation errors (401, 403, 404, 500), message is a single string.
General API
Get API key info
Get information about the current API key.
GET /me
Authorization: Bearer sk_xxxxxHealth check
Verify API connectivity and key validity.
GET /health
Authorization: Bearer sk_xxxxxDocuments API
Create document
Create a new document with blockchain verification. When status is set to 'published', the document is automatically verified on blockchain.
POST /documents
Headers:
Authorization: Bearer sk_xxxxx
Content-Type: application/jsonUpdate document
Update a document by creating a new version. Previous versions are preserved for audit trail.
PUT /documents/:documentId
Authorization: Bearer sk_xxxxx
Content-Type: application/jsonUpdate document access rights
Update document access control settings.
PUT /documents/:documentId/rights
Authorization: Bearer sk_xxxxx
Content-Type: application/jsonVerify document
Verify document authenticity using blockchain. Returns verification status with transaction hash and chain ID.
POST /documents/verify
Authorization: Bearer pk_xxxxx
Content-Type: application/json
{
"versionHash": "0x123abc...",
"certificateHash": "0x456def..."
}Get verification status
Get blockchain verification status for a document version.
GET /documents/versions/:versionId/verification
Authorization: Bearer sk_xxxxxSignatures API
Create signature request
Create a signature request for one or more recipients. Enable embedded flow for frontend integration.
curl -X POST https://api.chaindoc.io/api/v1/signatures/requests \
-H "Authorization: Bearer sk_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"versionId": "f0b7721f-0399-4035-9b69-7b95d3a367f0",
"recipients": [
{ "email": "signer@example.com", "signingMethod": "embedded" }
],
"deadline": "2026-12-31T23:59:59Z",
"embeddedFlow": true,
"isKycRequired": false
}'Pre-placed fields (advanced). If you upload your own PDF and want exact control over where signature, initials, date, text, or checkbox fields appear, pass an optional fields array alongside versionId. When you render a document from a template (see Templates API below), placed fields come from the template definition automatically. skip this option.
{
"fields": [
{
"signerEmail": "signer@example.com",
"fieldType": "signature",
"pageIndex": 0,
"xPct": 0.15,
"yPct": 0.78,
"wPct": 0.25,
"hPct": 0.05,
"required": true,
"label": "Client signature"
},
{
"signerEmail": "signer@example.com",
"fieldType": "date_signed",
"pageIndex": 0,
"xPct": 0.45,
"yPct": 0.78,
"wPct": 0.15,
"hPct": 0.03
}
]
}Placed field conventions
Coordinates are percentages of the page (xPct, yPct, wPct, hPct. all 0–1), so placements stay correct regardless of PDF page size
pageIndex is zero-based
fieldType accepts signature, initials, date_signed, text, checkbox
signerEmail must match one of the emails in your recipients array
Optional systemKey enables autofill from the signer's profile (e.g. full_name)
Get signature request status
Check the status of a signature request and see which signers have completed signing.
GET /signatures/requests/:requestId/status
Authorization: Bearer sk_xxxxxSign document
Sign a document (if API key owner is a signatory).
POST /signatures/sign
Authorization: Bearer sk_xxxxx
Content-Type: application/jsonGet user signatures
Get all signatures for the authenticated user.
GET /signatures?pageNumber=1&pageSize=10
Authorization: Bearer sk_xxxxxGet signature requests
Get all signature requests for the authenticated user with pagination support.
GET /signatures/requests?pageNumber=1&pageSize=10
Authorization: Bearer sk_xxxxxMedia upload API
Upload files for use in document creation. Supports PDF, images, and videos. Maximum 10 files per request.
Supported file types
Documents: PDF, DOC, DOCX, XLS, XLSX, PPT, PPTX, TXT
Images: JPG, JPEG, PNG, GIF, WEBP, SVG
Videos: MP4, AVI, MOV, WMV
curl -X POST https://api.chaindoc.io/api/v1/media/upload \
-H "Authorization: Bearer sk_xxxxx" \
-F "media=@contract.pdf"Contracts API
Create and manage contract lifecycles from draft through signing, active, and termination. Each contract wraps a document, contragent info, optional payment terms, and a signing policy. Payment-enabled contracts require a Stripe Connect account. see the security guide for setup.
Contract statuses
draft. editable, not yet sent to signers
pending_signature. sent, awaiting signatures from both parties
active. signed by both parties and in effect
pending_amendment. changes proposed, awaiting approval
suspended. temporarily paused
termination_pending. termination requested, awaiting approval (for mutual_approval contracts)
terminated. contract ended by termination
expired. reached endDate without renewal
rejected. declined or cancelled before activation
Create contract
Create a contract in draft status from an existing document. Payment terms are optional. you can add them later via payment setup.
POST /contracts
Authorization: Bearer sk_xxxxx
Content-Type: application/jsonPayment term types
one_time. single payment; requires dueDate and amount
recurring. periodic payments; requires frequency (weekly | biweekly | monthly | quarterly | yearly) and dayOfPeriod (1–28)
deposit. upfront payment; typically with dueDate
List contracts
List contracts created via the API, with pagination and optional status/search filters.
GET /contracts?page=1&limit=10&status=active&search=acme
Authorization: Bearer sk_xxxxxGet contract
Fetch full contract details including payment terms, signing status, and contragent info.
GET /contracts/:contractId
Authorization: Bearer sk_xxxxxGet contract status
Lightweight endpoint for monitoring contract lifecycle without fetching the full payload. Returns current status, signing progress, and a payment summary.
GET /contracts/:contractId/status
Authorization: Bearer sk_xxxxxGet contract activities
Paginated activity log (created, sent, signed, amended, terminated, etc.) for audit and webhook reconciliation.
GET /contracts/:contractId/activities?page=1&limit=20
Authorization: Bearer sk_xxxxxSet up payment terms
Attach or replace payment terms on a draft contract. Useful when you create the contract shell first and configure billing separately.
POST /contracts/:contractId/payment-setup
Authorization: Bearer sk_xxxxx
Content-Type: application/jsonSend contract for signing
Transition a draft contract to pending_signature and notify both parties. All body fields are optional.
POST /contracts/:contractId/send
Authorization: Bearer sk_xxxxx
Content-Type: application/jsonCancel contract
Cancel a draft contract (never sent) or a pending_signature contract before anyone signs. Irreversible.
POST /contracts/:contractId/cancel
Authorization: Bearer sk_xxxxxTerminate contract
Terminate an active contract. For mutual_approval contracts this initiates a termination_pending flow where the other party must confirm; for one_side contracts it terminates immediately.
POST /contracts/:contractId/terminate
Authorization: Bearer sk_xxxxx
Content-Type: application/jsonContract Invoices API
Bill contragents on an active contract. Invoices can be auto-generated from recurring payment terms or created manually for ad-hoc billing. Charging saved payment methods is supported for Stripe-enabled contracts.
Invoice statuses
draft. created but not sent
pending. sent to contragent, payment attempt in progress
unpaid. sent but not yet paid
paid. fully paid
partially_paid. partial payment recorded
overdue. past dueDate and unpaid
cancelled. voided
refunded. paid and later refunded
Create invoice
Create a manual invoice on an active contract. Set sendImmediately: true to dispatch to the contragent right away, and autoCharge: true to charge their saved payment method when sent.
POST /contracts/:contractId/invoices
Authorization: Bearer sk_xxxxx
Content-Type: application/jsonList contract invoices
List all invoices for a contract with pagination and optional status filter.
GET /contracts/:contractId/invoices?page=1&limit=10&status=unpaid
Authorization: Bearer sk_xxxxxGet invoice
Fetch full invoice details including line items, transactions, and Stripe checkout URL if applicable.
GET /contracts/:contractId/invoices/:invoiceUuid
Authorization: Bearer sk_xxxxxSend invoice
Send a draft invoice to the contragent. Set autoCharge: true to attempt immediate charge of a saved payment method.
POST /contracts/:contractId/invoices/:invoiceUuid/send
Authorization: Bearer sk_xxxxx
Content-Type: application/jsonCharge invoice
Charge an already-sent invoice using the contragent's saved payment method. Used to retry failed payments or charge on demand.
POST /contracts/:contractId/invoices/:invoiceUuid/charge
Authorization: Bearer sk_xxxxxMark invoice as paid
Record an offline/external settlement. wire transfer, cash, or payment through another rail. A manual transaction is recorded for audit.
POST /contracts/:contractId/invoices/:invoiceUuid/mark-paid
Authorization: Bearer sk_xxxxx
Content-Type: application/jsonTransactions API
Read payment transactions linked to contract invoices. Transactions capture every charge attempt (successful, failed, or pending) along with Stripe fee breakdown, net amount, and retry history.
Transaction statuses
INITIALISED. created in the system, payment not yet attempted
PENDING. payment in flight (Stripe processing)
SUCCESS. payment captured
FAILED. payment attempt failed; see failureReason
CANCELLED. transaction voided before capture
List contract transactions
List all transactions for a contract across its invoices.
GET /contracts/:contractId/transactions
Authorization: Bearer sk_xxxxxGet transaction
Fetch a single transaction by UUID with full details: amounts, fees, receipt URL, and retry metadata.
GET /transactions/:transactionUuid
Authorization: Bearer sk_xxxxxTemplates API
Render a published template into a draft document, a signature request, or a contract. passing variable values and slot assignments. The template system supports per-signer variables and role-based slot assignment for contract templates.
Create document from template
Render a template with variables and create a new draft document. Slot assignments aren't needed here. this endpoint only produces the document shell.
POST /templates/:templateId/documents
Authorization: Bearer sk_xxxxx
Content-Type: application/jsonCreate signature request from template
Render a template, create the document, and immediately send it for signing. Each slotAssignment binds a template signer key to a real recipient email.
POST /templates/:templateId/signature-requests
Authorization: Bearer sk_xxxxx
Content-Type: application/jsonCreate contract from template
Render a contract template with variables and contragent info, creating a contract and sending it for signing in one call. Slot assignments bind template signer keys to roles (business | contragent). emails are taken from API key owner (for business) and contragent.email.
POST /templates/:templateId/contracts
Authorization: Bearer sk_xxxxx
Content-Type: application/jsonEmbedded sessions API
Create embedded sessions for document or contract signing in your frontend application. Sessions are valid for 10 minutes. For standalone document signing, pass both documentId and signatureRequestId in metadata. For contract signing, pass contractId and Chaindoc resolves the active signing request.
POST /embedded/sessions
Authorization: Bearer sk_xxxxx
Content-Type: application/jsonEmbedded session flow
1. Create an embedded session via the API. an OTP is sent to the signer's email
2. The signer verifies the OTP and signs from an iframe on your site
3. The flow is driven by the Embed SDK; the session-scoped endpoints it calls are not part of the public integration surface
4. Your backend is notified of completion via webhooks
What to do next
- API integration. common patterns, best practices, and full workflow examples
- SDKs. Server SDK and Embed SDK with framework-specific guides
- Webhooks. set up real-time event notifications
- Installation. npm setup for all supported frameworks
- Security. API key management and compliance