Skip to content

Quickstart

Five calls with a test key: everything a test key does is in test mode, so nothing is emailed and nothing is billed. Set it once:

Terminal window
export SEALPOST_KEY=sk_test_…

The responses below for calls 1 and 2 are real, captured from the API; ids and timestamps will differ for you. The file and envelope responses are shortened.

Terminal window
curl https://api.sealpost.app/v1/ping -H "Authorization: Bearer $SEALPOST_KEY"
{"ok":true,"request_id":"01a1669f-48e0-7ba3-bc5d-4bfe41df6295","test_mode":true}

Every response also carries a Sign-Request-Id header with the same id. Quote it if you ever write to support.

Terminal window
curl https://api.sealpost.app/v1/me -H "Authorization: Bearer $SEALPOST_KEY"
{
"tenant": {"id": "01a1669e-93c9-76a8-aaf0-108fa161e0bc", "name": "Docs Example", "kind": "external"},
"api_key": {
"id": "01a1669e-93f1-7b20-8358-bce84a66f3c3",
"name": "Initial test key",
"prefix": "sk_test_CU3NWLqM",
"mode": "test",
"scopes": ["envelopes:read", "envelopes:write", "…"],
"created_at": "2026-10-23T02:37:11+00:00",
"last_used_at": "2026-10-23T02:37:57+00:00",
"expires_at": null,
"revoked_at": null
},
"mode": "test",
"test_mode": true,
"scopes": ["envelopes:read", "envelopes:write", "…"],
"request_id": "01a1669f-4ab2-7314-aeaf-3e13dbc9a181"
}
Terminal window
curl -X POST https://api.sealpost.app/v1/files \
-H "Authorization: Bearer $SEALPOST_KEY" \
-F file=@agreement.pdf
{"id": "…", "name": "agreement.pdf", "bytes": 1921746, "sha256": "…", "page_count": 5,
"page_sizes": [{"w": 612, "h": 792, "rotate": 0}, "…"], "status": "ready", "upload_expires_at": "…"}

sha256 is the fingerprint of exactly the bytes you sent; it is printed on the certificate page of the sealed document. You can also send {"url": "…"} or {"base64": "…", "name": "…"} as JSON, and inline base64 is capped at 10 MB (multipart, URL and presigned uploads take up to 25 MB). See Files and envelopes.

Fields point at a recipient and a file by their position in the lists. Coordinates here are in points from the top-left of the page.

Terminal window
curl -X POST https://api.sealpost.app/v1/envelopes \
-H "Authorization: Bearer $SEALPOST_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: agreement-48213" \
-d '{
"title": "Merchant agreement",
"files": [{"file_id": "<id from step 3>"}],
"recipients": [{"name": "Ada Owner", "email": "ada@example.com"}],
"fields": [
{"type": "signature", "page": 1, "x": 375, "y": 744, "width": 110, "height": 20, "recipient": 0},
{"type": "date_signed", "page": 1, "x": 524, "y": 749, "width": 55, "height": 12, "recipient": 0}
],
"metadata": {"merchant_id": "48213"}
}'
{"id": "…", "status": "draft", "test_mode": true, "files": ["…"], "recipients": ["…"],
"fields": [{"identifier": "signature_1", "page": 1, "x": 375, "y": 744, "width": 110, "height": 20, "unit": "pt", "source": {"…": "…"}}, "…"]}

A box that leaves its page is refused with invalid_field_geometry, naming the field. A missing title or file is a validation_failed that names every problem at once (a real response):

{"type": "https://sealpost.app/errors/validation_failed", "title": "Unprocessable Content", "status": 422,
"detail": "The request has invalid values.", "instance": "/v1/envelopes", "code": "validation_failed",
"request_id": "01a1669f-50ae-7af1-86eb-541a026d93ff",
"errors": [{"param": "title", "message": "Required, 1 to 200 characters."},
{"param": "files", "message": "Required, a list of at least one file ({file_id} | {url} | {base64, name})."}]}
Terminal window
curl https://api.sealpost.app/v1/envelopes/<id> -H "Authorization: Bearer $SEALPOST_KEY"

The envelope comes back exactly as stored: files with their page sizes, recipients, and fields in points with the original request kept as source.

The envelope is a draft. Sending it to the signer, the signing page, the sealed PDF and webhooks are the next parts of the API to arrive; see Coming next. Until then, a draft is a safe way to check your coordinates and payloads against the real service.