Introduction
Overview of the SignSecure REST API.
The SignSecure API lets you programmatically create documents, add recipients, send for signing, track progress, and manage templates and credits.
Base URL
https://api.signpad.signsecure.in/api/v1All endpoints are relative to this base URL. For local development, the server runs at http://localhost:3000/api/v1.
Authentication
Every request (except /health) requires an API key sent as a Bearer token in the Authorization header:
Authorization: Bearer signsecure_xxxxxxxx...API keys are created from Settings > API Keys in the dashboard. The key is shown once on creation — store it securely.
Keys can be scoped with granular permissions per resource:
| Resource | Actions |
|---|---|
documents | read, write, delete |
signing | read, write |
templates | read, write, delete |
credits | read |
webhooks | read, write, delete |
Keys can also have an optional expiration date (1–365 days).
Rate Limits
Each API key is limited to 1,000 requests per hour. When the limit is exceeded, requests return 403.
Error Format
All errors return a consistent JSON envelope. Use code for programmatic handling and message for display. The details object carries structured context that helps you fix the problem — its shape depends on the error code.
{
"code": "VALIDATION_ERROR",
"message": "fileName: Required",
"details": {
"validation": {
"fieldErrors": { "fileName": ["Required"] },
"formErrors": [],
"issues": [
{ "path": "fileName", "message": "Required", "code": "invalid_type" }
]
}
},
"requestId": "req_abc123",
"timestamp": "2026-03-11T10:30:00.000Z"
}| Field | Type | Description |
|---|---|---|
code | string | Machine-readable constant — switch on this in your code |
message | string | Human-readable explanation — safe to show to users |
details | object? | Structured context (shape varies by code, omitted when not applicable) |
requestId | string | Unique request ID — include this when contacting support |
timestamp | string | ISO 8601 timestamp of when the error occurred |
Error Codes
Authentication & Authorization
| Code | HTTP | When it happens | How to fix |
|---|---|---|---|
UNAUTHORIZED | 401 | Missing, invalid, or revoked API key | Check the key is correct and not deleted in Settings > API Keys |
FORBIDDEN | 403 | Key is disabled, expired, rate-limited, or lacks the required permission | Re-enable the key, create a new one, or add the missing permission scope |
UNSUPPORTED_AUTH_HEADER | 400 | Sent the key via x-api-key header | Use Authorization: Bearer <key> instead |
INVALID_AUTHORIZATION_HEADER | 400 | Authorization header is malformed (e.g., missing Bearer prefix) | Format as Authorization: Bearer signsecure_xxxxx... |
Validation & Input
| Code | HTTP | When it happens | details shape | How to fix |
|---|---|---|---|---|
VALIDATION_ERROR | 400 | Request body or query params failed schema validation | { validation: { fieldErrors, formErrors, issues[] } } | Check details.validation.issues for the exact field paths and messages |
BAD_REQUEST | 400 | Invalid parameters that aren't covered by schema validation | { invalidRecipientIds[] } (when applicable) | Read the message and fix the indicated parameter |
INVALID_FILE_TYPE | 400 | fileType is not application/pdf | — | Only PDFs are supported |
FILE_TOO_LARGE | 400 | fileSize exceeds 10 MB | { maxSize, providedSize } | Compress or split the PDF to fit under 10,485,760 bytes |
DUPLICATE_RECIPIENT | 400 | A recipient email already exists on the document, or the same email appears twice in your request | { duplicateEmails[] } | Remove the duplicate email(s) or set replaceExisting: true |
Document & Signing
| Code | HTTP | When it happens | details shape | How to fix |
|---|---|---|---|---|
NOT_FOUND | 404 | Document, template, recipient, or form field does not exist (or you don't own it) | — | Verify the ID is correct and belongs to your account |
INVALID_STATUS | 400 | Operation requires a specific document status (usually draft) but the document is in a different state | — | Check message for the required status; you may need to create a new document |
NO_RECIPIENTS | 400 | Tried to send a document that has no signers or approvers | — | Add at least one recipient with role signer or approver before sending |
NOT_AVAILABLE | 400 | Requested the download URL but the PDF file hasn't been uploaded yet | — | Upload the PDF via the presigned uploadUrl first |
INVALID_SIGNATURE_POSITIONS | 400 | Signature fields reference page numbers that exceed the PDF's actual page count | { pdfPageCount, invalidPositions[], message } | Reposition fields to valid pages (check details.pdfPageCount) |
INVALID_SIGNATURE_PLACEMENT | 400 | Used text-based placement (type: "text") with a non-electronic signature method | { invalidRecipients[], recommendation } | Switch to signatureMethod: "electronic" or use type: "coordinates" placement |
TEXT_NOT_FOUND_IN_PDF | 400 | The searchText for text-based signature placement was not found anywhere in the PDF | { missingTexts[], totalPages } | Update the PDF to include the text, or change to coordinate-based placement |
PDF_VALIDATION_FAILED | 400 | The PDF file is corrupted, unreadable, or couldn't be downloaded from S3 | { details } | Re-upload the PDF file |
Database & Server
| Code | HTTP | When it happens | details shape | How to fix |
|---|---|---|---|---|
DUPLICATE_ENTRY | 409 | A unique database constraint was violated (e.g., duplicate email) | { constraint, detail } | Use a different value for the conflicting field |
CONSTRAINT_VIOLATION | 400 | A database integrity constraint was violated | { constraint, detail } | Check details.constraint for the specific rule that failed |
INTERNAL_SERVER_ERROR | 500 | Unexpected server error | — | Retry the request; if it persists, contact support with the requestId |
Validation Error Details
VALIDATION_ERROR is the most common error. The details.validation object gives you everything you need to show per-field error messages in your UI:
{
"code": "VALIDATION_ERROR",
"message": "fileName: Required",
"details": {
"validation": {
"fieldErrors": {
"fileName": ["Required"],
"fileSize": ["Expected number, received string"]
},
"formErrors": [],
"issues": [
{ "path": "fileName", "message": "Required", "code": "invalid_type" },
{ "path": "fileSize", "message": "Expected number, received string", "code": "invalid_type" }
]
}
},
"requestId": "req_abc123",
"timestamp": "2026-03-11T10:30:00.000Z"
}fieldErrors— keyed by field path (e.g.,"recipients.0.email"), each value is an array of error messages for that fieldformErrors— array of errors not tied to a specific field (e.g., cross-field validation)issues— flat array with each Zod validation issue including thecode(e.g.,invalid_type,too_small,invalid_enum_value)
Available Resources
| Resource | Description |
|---|---|
| Documents | Create, read, update, delete documents and manage file uploads |
| Recipients | Add and remove document recipients (signers, approvers, CC) |
| Form Fields | Place interactive fields on document pages |
| Signing Workflow | Send documents for signing, track progress, send reminders |
| Templates | Create reusable document templates |
| Credits | Check balance, view transactions, get usage stats |
| Webhooks | Receive real-time event notifications via HTTP |