Seal Docs

API Reference

Complete REST API documentation for all Seal endpoints

API Reference

The Seal API is organized around REST principles. Our API has predictable resource-oriented URLs, accepts JSON-encoded request bodies, returns JSON-encoded responses, and uses standard HTTP response codes, authentication, and verbs.

Base URL

All API requests should be made to:

https://seal.convex.site/api/v1

Authentication

All API endpoints require authentication using a Clerk API key. Include your API key in the Authorization header:

Authorization: Bearer ak_your_api_key_here

See the Authentication Guide for details on creating and managing API keys.

Interactive Reference

Explore all endpoints in the interactive API playground:

Open API Playground →

Try every endpoint live — browse schemas, fill in parameters, and run real requests against the Seal API.

API Resources

The Seal API is organized into the following resource categories:

URL Routing

The Seal API uses query-parameter-based routing for resource operations. Since the underlying Convex HTTP router does not support path parameters, resource IDs are passed as query parameters:

GET  /api/v1/documents              # List documents
GET  /api/v1/documents/get?id={id}  # Get a specific document
PUT  /api/v1/documents/update?id={id}  # Update a document
DELETE /api/v1/documents/delete?id={id}  # Delete a document
POST /api/v1/documents/send?id={id}  # Send a document

For nested resources like recipients and signatures, the parent document ID is also passed as a query parameter:

GET  /api/v1/recipients?document_id={docId}  # List recipients
POST /api/v1/recipients?document_id={docId}  # Add a recipient

Request Format

All POST and PUT requests must include a Content-Type: application/json header and a JSON-encoded body.

Example Request

const response = await fetch("https://seal.convex.site/api/v1/documents", {
  method: "POST",
  headers: {
    Authorization: "Bearer ak_your_api_key_here",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    title: "Service Agreement",
    description: "Annual service contract",
  }),
});

Response Format

All responses are returned as JSON with appropriate HTTP status codes.

Success Response

{
  "id": "jd7k8l9m0n1p2q3r4s5t6u7v",
  "title": "Service Agreement",
  "status": "draft",
  "created_at": "2024-01-27T10:30:00Z"
}

Error Response

{
  "type": "https://seal.nyc/errors/validation-error",
  "title": "Validation Error",
  "status": 400,
  "detail": "Field 'title' is required",
  "instance": "/api/v1/documents"
}

See the Error Handling Guide for complete error documentation.

HTTP Status Codes

CodeDescription
200OK - Request succeeded
201Created - Resource created successfully
204No Content - Request succeeded with no response body
400Bad Request - Invalid request parameters
401Unauthorized - Missing or invalid API key
403Forbidden - Insufficient permissions
404Not Found - Resource doesn't exist
429Too Many Requests - Rate limit exceeded
500Internal Server Error - Server error

Rate Limiting

Rate limiting infrastructure is in place and will be enforced in a future release. Planned limits:

  • 60 requests per minute per API key
  • 1000 requests per hour per API key

When enforced, rate limit information will be included in response headers:

X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1706356800

We recommend implementing exponential backoff and retry logic to handle future rate limits gracefully.

Pagination

List endpoints support cursor-based pagination:

Request Parameters

ParameterTypeDescription
limitnumberNumber of results to return (max 100, default 20)
cursorstringPagination cursor from previous response

Response Format

{
  "data": [...],
  "has_more": true,
  "next_cursor": "eyJpZCI6ImFiYzEyMyJ9"
}

Example

// First page
const page1 = await fetch("https://seal.convex.site/api/v1/documents?limit=20");
const { data, has_more, next_cursor } = await page1.json();

// Next page
if (has_more) {
  const page2 = await fetch(
    `https://seal.convex.site/api/v1/documents?limit=20&cursor=${next_cursor}`,
  );
}

Timestamps

All timestamps are returned in ISO 8601 format with UTC timezone:

2024-01-27T10:30:00Z

Idempotency

POST requests that create resources support idempotency keys to safely retry requests without creating duplicate resources. Include an Idempotency-Key header with a unique value:

const response = await fetch('https://seal.convex.site/api/v1/documents', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer ak_your_api_key_here',
    'Content-Type': 'application/json',
    'Idempotency-Key': 'unique-key-123'
  },
  body: JSON.stringify({...})
});

Requests with the same idempotency key will return the same response without creating duplicate resources.

Next Steps

Last updated on

On this page