merlon
Log In
Pricing
Reference

merlon API v1

A resource-oriented REST API for creating documents, provisioning secure vaults, orchestrating approval workflows, and reading tamper-evident audit logs. All requests are JSON over HTTPS, authenticated with a bearer token, and served from the region that matches your data-residency configuration.

Base URL
https://api.merlon.ch/v1
Regional URLs
https://api.us.merlon.ch/v1 · https://api.eu.merlon.ch/v1
Content type
application/json for request and response bodies
Timestamps
RFC 3339 / ISO 8601, always UTC (e.g. 2026-07-27T09:41:08Z)
Object IDs
Prefixed, opaque strings — doc_, vault_, wf_, evt_

Authentication

merlon supports two authentication schemes: API keys for server-to-server integrations, and OAuth2 for apps that act on behalf of a user. All requests must be made over HTTPS; calls over plain HTTP fail before reaching the application.

API keys

Pass your secret key as a bearer token. Keys are environment-scoped: sk_test_… hits the sandbox, sk_live_… hits production. Never expose a secret key in client-side code.

bash
curl "https://api.merlon.ch/v1/documents" \
  -H "Authorization: Bearer sk_live_51Kf9c1Za8Xq2Wn4dPmR0"

OAuth2

For user-context apps, use the authorization-code flow. Exchange the code for an access token, then call the API with that token. Scopes map to the same permissions a user holds in the web app.

bash
curl -X POST "https://api.merlon.ch/v1/oauth/token" \
  -d "grant_type=authorization_code" \
  -d "code=ac_9c1Za8Xq" \
  -d "client_id=cl_7Qd2" \
  -d "client_secret=cs_••••" \
  -d "redirect_uri=https://app.example.com/callback"
json · 200 OK
{
  "access_token": "at_5Rk21m…",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "documents:write vaults:read"
}

Rate limits

Limits are applied per API key on a sliding one-minute window. Every response includes rate-limit headers so you can back off gracefully before you hit a wall.

PlanSustainedBurstScope
Sandbox120 req/min200 req/minper test key
Standard600 req/min1,000 req/minper live key
EnterpriseCustomCustomper account

When you exceed the limit the API returns 429 Too Many Requests with a Retry-After header (seconds). Response headers on every call: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset.

Errors

merlon uses conventional HTTP status codes. Codes in the 2xx range mean success, 4xx indicate a problem with your request, and 5xx indicate a problem on our side. Every error body carries a machine-readable type, a human message, and a request_id you can quote to support.

StatusTypeMeaning
400bad_requestMalformed request — invalid JSON or missing body.
401authentication_errorMissing, invalid, or revoked API key.
403permission_errorKey is valid but lacks the required scope.
404not_foundThe requested resource does not exist in this region.
409conflictIdempotency-Key reused with a different payload, or state conflict.
422validation_errorBody parsed but a field failed validation.
429rate_limit_errorToo many requests — see Retry-After.
500api_errorSomething went wrong on our end. Safe to retry idempotent calls.
json · 403 error
{
  "error": {
    "type": "permission_error",
    "message": "This key is missing the 'vaults:write' scope.",
    "request_id": "req_9c1Za8Xq"
  }
}

Versioning & deprecation policy

The API is versioned in the URL path (/v1). We add fields and endpoints without bumping the version — your integration should ignore unknown fields. Breaking changes only ship under a new major version.

Additive changes
New optional fields and endpoints may appear at any time within /v1. Treat responses as forward-compatible.
Deprecations
Announced in the changelog with at least a 12-month sunset window and a Sunset response header on affected endpoints.
Regional endpoints
Every version is available on all three hosts; residency is enforced at the edge regardless of host.
Resource

Documents

A document is a versioned file living inside a vault. Documents move through a lifecycle — draftin_reviewsignedlocked — and every transition is recorded in the audit log.

GET /v1/documents

List documents visible to the authenticated key, newest first. Cursor-paginated.

ParameterTypeDescription
vault_idstringOptional. Filter to a single vault.
statusstringOptional. One of draft, in_review, signed, locked.
limitinteger1–100, default 20.
cursorstringPagination cursor from a previous response.
curl
curl "$MERLON_BASE/documents?vault_id=vault_9f2c&status=signed&limit=2" \
  -H "Authorization: Bearer $MERLON_API_KEY"
json · 200 OK
{
  "object": "list",
  "data": [
    { "id": "doc_3kf9c1Za", "title": "MSA — Acme", "status": "signed", "version": 4 },
    { "id": "doc_7Qd2Wn4d", "title": "NDA — Nordwind", "status": "signed", "version": 2 }
  ],
  "has_more": false,
  "next_cursor": null
}
POST /v1/documents

Create a new document in a vault. Supports Idempotency-Key.

ParameterTypeDescription
titlestringRequired. Human-readable title.
vault_idstringRequired. Destination vault.
metadataobjectOptional. Arbitrary key/value pairs (counterparty, retention…).
curl
curl -X POST "$MERLON_BASE/documents" \
  -H "Authorization: Bearer $MERLON_API_KEY" \
  -H "Idempotency-Key: 3f0c-b12a-7d91" \
  -d '{ "title": "MSA — Acme", "vault_id": "vault_9f2c" }'
json · 201 Created
{
  "id": "doc_3kf9c1Za",
  "object": "document",
  "status": "draft",
  "version": 1,
  "created_at": "2026-07-27T09:41:08Z"
}
GET /v1/documents/{id}

Retrieve a single document, including its version history and current signers.

curl
curl "$MERLON_BASE/documents/doc_3kf9c1Za" \
  -H "Authorization: Bearer $MERLON_API_KEY"
json · 200 OK
{
  "id": "doc_3kf9c1Za",
  "title": "MSA — Acme",
  "status": "signed",
  "version": 4,
  "vault_id": "vault_9f2c",
  "signers": [ "gc@acme.com", "legal@merlon.ch" ],
  "sha256": "9f2c…a81e"
}
DELETE /v1/documents/{id}

Soft-delete a document. Documents under legal hold or retention cannot be deleted and return 409.

curl
curl -X DELETE "$MERLON_BASE/documents/doc_3kf9c1Za" \
  -H "Authorization: Bearer $MERLON_API_KEY"
json · 200 OK
{ "id": "doc_3kf9c1Za", "deleted": true }
Resource

Secure Vaults

A vault is an encrypted, access-scoped container for documents. Each vault has its own region, encryption envelope, and least-privilege member list.

GET /v1/vaults

List vaults the key can access.

curl
curl "$MERLON_BASE/vaults" -H "Authorization: Bearer $MERLON_API_KEY"
json · 200 OK
{
  "object": "list",
  "data": [
    { "id": "vault_9f2c", "name": "Legal — Contracts", "region": "eu", "members": 6 }
  ]
}
POST /v1/vaults

Provision a new vault with a chosen region and initial members.

ParameterTypeDescription
namestringRequired. Display name.
regionstringRequired. us or eu — sets data residency.
membersarrayOptional. Email addresses to grant access at creation.
curl
curl -X POST "$MERLON_BASE/vaults" \
  -H "Authorization: Bearer $MERLON_API_KEY" \
  -d '{ "name": "HR — Personnel", "region": "eu" }'
json · 201 Created
{
  "id": "vault_5Rk21m",
  "name": "HR — Personnel",
  "region": "eu",
  "encryption": "aes-256-gcm · envelope"
}
GET /v1/vaults/{id}

Retrieve a vault with its member list and document count.

json · 200 OK
{
  "id": "vault_9f2c",
  "name": "Legal — Contracts",
  "region": "eu",
  "document_count": 42,
  "members": [
    { "email": "gc@acme.com", "role": "owner" }
  ]
}
Resource

Workflows

A workflow is an ordered set of approval steps attached to a document. Steps advance in sequence; each transition is captured with the actor, timestamp, and decision.

POST /v1/workflows

Start a workflow on a document with an ordered list of approver steps.

ParameterTypeDescription
document_idstringRequired. Document the workflow governs.
stepsarrayRequired. Ordered approver objects with assignee and optional condition.
curl
curl -X POST "$MERLON_BASE/workflows" \
  -H "Authorization: Bearer $MERLON_API_KEY" \
  -d '{
    "document_id": "doc_3kf9c1Za",
    "steps": [
      { "assignee": "controller@acme.com" },
      { "assignee": "cfo@acme.com", "condition": "amount > 50000" }
    ]
  }'
json · 201 Created
{
  "id": "wf_8Xq2Wn4d",
  "document_id": "doc_3kf9c1Za",
  "status": "in_progress",
  "current_step": 1
}
POST /v1/workflows/{id}/advance

Record a decision on the current step. A decision of reject halts the workflow.

ParameterTypeDescription
decisionstringRequired. approve or reject.
commentstringOptional. Reviewer note stored on the audit trail.
json · 200 OK
{
  "id": "wf_8Xq2Wn4d",
  "status": "in_progress",
  "current_step": 2,
  "last_decision": { "by": "controller@acme.com", "decision": "approve" }
}
GET /v1/workflows/{id}

Retrieve a workflow with the full decision history for each step.

json · 200 OK
{
  "id": "wf_8Xq2Wn4d",
  "status": "completed",
  "steps": [
    { "assignee": "controller@acme.com", "decision": "approve" },
    { "assignee": "cfo@acme.com", "decision": "approve" }
  ]
}
Resource

Audit Logs

Every action in merlon writes an immutable, hash-chained audit event. The audit API is read-only — you can list and export events but never mutate them.

GET /v1/audit_logs

List audit events, filterable by resource, actor, and time range.

ParameterTypeDescription
resource_idstringOptional. Filter to one document or vault.
sincestringOptional. ISO 8601 lower bound.
untilstringOptional. ISO 8601 upper bound.
json · 200 OK
{
  "object": "list",
  "data": [
    { "id": "evt_5Rk21m", "type": "signature.completed", "actor": "gc@acme.com", "at": "2026-07-27T09:44:12Z" },
    { "id": "evt_4dPmR0", "type": "document.locked", "actor": "system", "at": "2026-07-27T09:44:13Z" }
  ]
}
POST /v1/audit_logs/export

Request a signed export of the audit log for a period. Returns a job you can poll; when ready, a time-limited download URL is issued.

json · 202 Accepted
{
  "id": "exp_7Qd2",
  "status": "processing",
  "format": "csv",
  "period": "2026-07-01/2026-07-31"
}
Resource

Webhooks

Register HTTPS endpoints to receive signed, retried event notifications. Each endpoint has its own signing secret used to compute the X-Merlon-Signature header.

POST /v1/webhook_endpoints

Create a webhook endpoint subscribed to one or more event types.

ParameterTypeDescription
urlstringRequired. HTTPS endpoint to receive events.
eventsarrayRequired. Event types, e.g. signature.completed.
curl
curl -X POST "$MERLON_BASE/webhook_endpoints" \
  -H "Authorization: Bearer $MERLON_API_KEY" \
  -d '{ "url": "https://app.example.com/hooks", "events": ["signature.completed"] }'
json · 201 Created
{
  "id": "whk_3kf9c1",
  "url": "https://app.example.com/hooks",
  "signing_secret": "whsec_••••",
  "status": "active"
}
GET /v1/webhook_endpoints

List all registered webhook endpoints and their subscribed events.

json · 200 OK
{
  "object": "list",
  "data": [
    { "id": "whk_3kf9c1", "url": "https://app.example.com/hooks", "events": ["signature.completed"] }
  ]
}
DELETE /v1/webhook_endpoints/{id}

Delete a webhook endpoint. In-flight deliveries are allowed to finish; no new events are sent.

json · 200 OK
{ "id": "whk_3kf9c1", "deleted": true }

Regional endpoints

Every endpoint above is available on all three hosts. Use api.us.merlon.ch/v1 or api.eu.merlon.ch/v1 to pin a region; api.merlon.ch/v1 routes to your account default.

Start building today

Read the quickstart, grab an API key, or request sandbox access to try every endpoint against seed data.

Developer hub