API Reference
Manage contracts, counterparties, obligations, templates, signatures, webhooks, and members programmatically over a REST API.
The Fusial API is a REST API for managing your workspace: contracts and their document versions, counterparties and contacts, obligations, templates, signature requests, outbound webhooks, team members, and the audit log. Responses are JSON unless an endpoint returns a document download. Workspace endpoints require an API key; the OpenAPI document is public.
Connecting an AI assistant? Use the MCP server for tools, semantic contract search, and OAuth sign-in. MCP also accepts the API keys described here.
The reference is generated from the API's own OpenAPI document, which you can
fetch directly from
GET /openapi.json — no key
required.
Base URL
https://app.fusial.com/api/v1
Every path in this reference is relative to that base URL.
Authentication
Authenticate by sending your API key in the x-api-key header:
curl https://app.fusial.com/api/v1/me \
-H "x-api-key: $FUSIAL_API_KEY"
Create and manage keys in your workspace settings. Each key belongs to a single workspace and is minted as one of two presets:
- Full access — read and write on every resource (templates, analytics, signatures, and audit remain read-only, as they have no write endpoints).
- Read-only — read on every resource except the admin-only ones (webhooks and audit).
Use GET /me to confirm which workspace and
scopes a key carries.
Scopes
Keys carry scopes of the form resource:action. Each endpoint lists the scope
it requires; a key without it receives 403 insufficient_scope. An endpoint
that touches more than one resource requires every scope it touches — attaching
a counterparty to a contract, for example, needs both contracts:write and
counterparties:write.
| Resource | Read | Write | Notes |
|---|---|---|---|
contracts | contracts:read | contracts:write | |
counterparties | counterparties:read | counterparties:write | |
obligations | obligations:read | obligations:write | |
members | members:read | members:write | |
templates | templates:read | — | Read-only. |
analytics | analytics:read | — | Read-only. |
signatures | signatures:read | — | Read-only; sending stays a human action. |
webhooks | webhooks:read | webhooks:write | Full-access keys only. |
audit | audit:read | — | Read-only; full-access keys only. |
search | search:read | — | Semantic search, exposed through the MCP server rather than a REST endpoint. |
Errors
Errors return a consistent JSON envelope with a stable code, a human-readable
message, and optional details:
{
"error": {
"code": "insufficient_scope",
"message": "This API key does not have the \"contracts:write\" scope.",
"details": null
}
}
Validation failures use 422 validation_error and include the offending fields:
{
"error": {
"code": "validation_error",
"message": "Invalid request input.",
"details": {
"issues": [{ "path": "title", "message": "String must contain at least 1 character(s)" }]
}
}
}
Common status codes:
| Status | When |
|---|---|
400 | Malformed request body (invalid_body). |
401 | Missing or invalid API key (missing_api_key, invalid_api_key). |
402 | Inactive subscription or seat limit reached. |
403 | Missing scope (insufficient_scope) or forbidden action (forbidden). |
404 | Resource not found (not_found). |
409 | Conflict — e.g. illegal status transition, duplicate document, no signed PDF yet. |
413 | Uploaded file exceeds 50 MB (file_too_large). |
422 | Input failed validation (validation_error). |
429 | Rate limit exceeded (rate_limited). |
Pagination
Larger collections — contracts,
obligations,
signature requests, a
contract's signature requests,
and a request's signing events — are
paginated and return a { data, page, pageSize, total, pageCount } envelope.
Page through results with ?page=N (1-based). Contracts use a fixed page size
of 50; obligations use 25. Only pass pageSize where the endpoint lists it:
{
"data": [],
"page": 1,
"pageSize": 50,
"total": 124,
"pageCount": 3
}
The audit feed is cursor-paginated
instead: follow nextCursor until it is null.
Smaller collections — counterparties, contacts, members, invitations,
document versions, templates, and a contract's own obligations — return a bare
{ "data": [ ... ] } with no page metadata.
Webhook endpoint lists return { "endpoints": [ ... ] }, and delivery lists
return { "deliveries": [ ... ] }.
Webhooks
Register an endpoint with
POST /webhook-endpoints and
Fusial POSTs a JSON envelope to it for every subscribed event. Each event's
payload is documented under Webhooks → Events in the sidebar. Deliveries
are signed following the Standard Webhooks
specification (webhook-id, webhook-timestamp, webhook-signature), so any
Standard Webhooks library can verify them with the secret returned when the
endpoint was created.
Use the webhook-id header when verifying the signature. It identifies the
delivery and differs from the JSON envelope's id, which identifies the event.
Automatic retries reuse the delivery ID; manual redelivery creates a new one
while preserving the event ID.
Conventions
- Timestamps are ISO 8601 strings (or
null). - Money — a contract's
valueCentsis in minor units and encoded as a string to preserve precision, with a separate ISO 4217valueCurrency. - Single resources are returned under a named key (
{ "contract": { ... } }), while collections use{ "data": [ ... ] }.
Quickstart
List your most recently active contracts:
curl "https://app.fusial.com/api/v1/contracts?sort=lastActivityAt&dir=desc" \
-H "x-api-key: $FUSIAL_API_KEY"
Create a contract:
curl -X POST https://app.fusial.com/api/v1/contracts \
-H "x-api-key: $FUSIAL_API_KEY" \
-H "content-type: application/json" \
-d '{
"title": "Acme MSA",
"type": "MSA",
"ourRole": "VENDOR",
"ownerId": "usr_123"
}'
Browse the endpoints in the sidebar, or jump to a resource below.