merlon
Log In
Pricing
API Reference

merlon API v1

A resource-oriented REST API for documents, secure vaults, approval workflows, tamper-evident audit logs and webhooks. JSON over HTTPS, bearer-token auth, served from the region that matches your data-residency configuration.

  • Base URLapi.merlon.ch/v1
  • AuthBearer token / OAuth2
  • VersionPinned in path
  • FormatJSON · UTF-8
bash
curl https://api.merlon.ch/v1/vaults \
  -H "Authorization: Bearer sk_live_••••"
json · 200 OK
{
  "object": "list",
  "data": [ { "id": "vault_9f2c" } ]
}
Reference

At a glance

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

Keep your documents, vaults, and audit data secure with AES-256 encryption, immutable audit trail, and regional residency on every plan.Learn more