{"openapi":"3.1.0","info":{"title":"SigPen API","version":"1.0","description":"SigPen's REST API for sending documents for electronic signature.\n\n## Authentication\nInclude your API key in every request:\n- `Authorization: Bearer sp_live_your_key_here` (preferred)\n- `X-API-Key: sp_live_your_key_here` (alternative)\n\n## Test Mode\nUse keys starting with `sp_test_` for development. Test documents don't count toward your monthly limit.\n\n## Rate Limits\n- Developer (Free): 10 req/min, 200 req/day\n- Professional: 30 req/min, 500 req/day\n- Business: 100 req/min, 5,000 req/day\n","contact":{"name":"SigPen Support","url":"https://www.sigpen.com/contact","email":"support@sigpen.com"},"license":{"name":"Proprietary"}},"servers":[{"url":"https://www.sigpen.com/api/v1","description":"Production"}],"security":[{"BearerAuth":[]},{"ApiKeyHeader":[]}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","description":"API key as Bearer token: `Authorization: Bearer sp_live_...`"},"ApiKeyHeader":{"type":"apiKey","in":"header","name":"X-API-Key","description":"API key in header: `X-API-Key: sp_live_...`"}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","authorization_error","not_found","validation_error","state_conflict","rate_limit_exceeded","quota_exceeded","internal_error"]},"message":{"type":"string"},"code":{"type":"string"},"doc_url":{"type":"string"},"details":{"type":"object","additionalProperties":{"type":"string"}}}}}},"Pagination":{"type":"object","properties":{"page":{"type":"integer"},"per_page":{"type":"integer"},"total":{"type":"integer"},"total_pages":{"type":"integer"}}},"Document":{"type":"object","properties":{"id":{"type":"string"},"external_id":{"type":"string","nullable":true,"description":"Client-provided ID for correlating webhooks with your own records."},"title":{"type":"string"},"file_name":{"type":"string"},"status":{"type":"string","enum":["draft","sent","completed","voided"]},"metadata":{"type":"object","additionalProperties":{"type":"string"}},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"Signer":{"type":"object","properties":{"id":{"type":"string"},"email":{"type":"string"},"name":{"type":"string"},"status":{"type":"string","enum":["pending","waiting","viewed","signed","declined"],"description":"pending = invited, awaiting signature; waiting = a later signer in a sequential flow whose turn has not arrived yet; viewed = opened but not signed; signed = completed; declined = refused to sign."},"order":{"type":"integer","description":"Signing order. Give signers distinct order numbers to make signing sequential — lower numbers sign first and each is invited only after the previous one completes. Numbers need not start at 0 or be contiguous (0,1 / 1,2 / 3,7,9 all work); signers sharing the same number sign in parallel. Omit on all signers for parallel signing."},"signed_at":{"type":"string","format":"date-time","nullable":true},"viewed_at":{"type":"string","format":"date-time","nullable":true,"description":"First time this signer opened the signing page."}}},"WebhookEndpoint":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"},"events":{"type":"array","items":{"type":"string"}},"active":{"type":"boolean"},"description":{"type":"string","nullable":true},"created_at":{"type":"string","format":"date-time"}}}}},"paths":{"/documents/upload-url":{"post":{"summary":"Request a presigned direct upload URL","description":"For PDFs too large to send base64-encoded in the POST /documents body (request bodies over 4.5MB are rejected, roughly 3MB of PDF after base64 inflation). PUT the raw PDF to the returned upload_url with Content-Type application/pdf, then call POST /documents with upload_key instead of file. URLs expire after 10 minutes. Hard cap 25MB.\n","tags":["Documents"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["file_name","file_size"],"properties":{"file_name":{"type":"string"},"file_size":{"type":"integer","description":"Size of the PDF in bytes (max 26214400)"}}}}}},"responses":{"200":{"description":"Presigned upload URL issued","content":{"application/json":{"schema":{"type":"object","properties":{"upload_url":{"type":"string"},"upload_key":{"type":"string"},"expires_in":{"type":"integer"},"max_file_size":{"type":"integer"}}}}}},"422":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited or quota exceeded"}}}},"/documents":{"post":{"summary":"Upload a document","description":"Create a document from a PDF. Provide either file (base64-encoded, for PDFs up to ~3MB; larger request bodies are rejected by the platform) or upload_key (from POST /documents/upload-url, for PDFs up to 25MB). Counts toward monthly document limit.\n","tags":["Documents"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["file_name"],"properties":{"file":{"type":"string","description":"Base64-encoded PDF. Mutually exclusive with upload_key."},"upload_key":{"type":"string","description":"Staging key from POST /documents/upload-url after PUTting the PDF. Mutually exclusive with file."},"file_name":{"type":"string"},"title":{"type":"string"},"external_id":{"type":"string","description":"Your own record ID, stored on the document and returned in every webhook."},"metadata":{"type":"object","additionalProperties":{"type":"string"}}}}}}},"responses":{"201":{"description":"Document created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Document"}}}},"422":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited or quota exceeded"}}},"get":{"summary":"List documents","tags":["Documents"],"parameters":[{"name":"status","in":"query","schema":{"type":"string"}},{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"per_page","in":"query","schema":{"type":"integer","default":20,"maximum":100}},{"name":"search","in":"query","schema":{"type":"string"}},{"name":"sort","in":"query","schema":{"type":"string","enum":["created_at","updated_at"]}},{"name":"order","in":"query","schema":{"type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"Document list","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Document"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}}}}},"/documents/{id}":{"get":{"summary":"Get a document","tags":["Documents"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Document details"},"404":{"description":"Not found"}}},"delete":{"summary":"Delete a document (trash)","description":"Moves a draft document to trash (30-day soft delete).","tags":["Documents"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Deleted"},"409":{"description":"Not in draft status"}}}},"/documents/{id}/send":{"post":{"summary":"Send document for signature","tags":["Signing"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["signers"],"properties":{"signers":{"type":"array","items":{"type":"object","required":["email","name"],"properties":{"email":{"type":"string"},"name":{"type":"string"},"order":{"type":"integer","description":"Signing order. With order set, signing is sequential and each signer is invited when the previous one completes."},"fields":{"type":"array","description":"Inline field placement. Places this signer's fields without the visual editor. Coordinates are PDF points from the top-left of the page.","items":{"type":"object","required":["type","page","x","y","width","height"],"properties":{"type":{"type":"string","enum":["signature","initials","date","text","checkbox","number"]},"page":{"type":"integer","description":"1-based page number."},"x":{"type":"number"},"y":{"type":"number"},"width":{"type":"number"},"height":{"type":"number"},"required":{"type":"boolean","default":true}}}}}}},"cc":{"type":"array","items":{"type":"object","properties":{"email":{"type":"string"},"name":{"type":"string"}}}},"message":{"type":"string"},"expires_in_days":{"type":"integer","default":30},"skip_email":{"type":"boolean","default":false,"description":"Create the signing sessions without sending invitation emails, for embedded signing where your app surfaces the sign URL. With sequential signing (order set), later signers are still emailed at their turn."}}}}}},"responses":{"200":{"description":"Document sent"}}}},"/documents/{id}/void":{"post":{"summary":"Void a document","tags":["Documents"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["reason"],"properties":{"reason":{"type":"string","minLength":10}}}}}},"responses":{"200":{"description":"Document voided"},"409":{"description":"Cannot void in current state"},"422":{"description":"Reason too short"}}}},"/documents/{id}/download":{"get":{"summary":"Download signed PDF","description":"Returns the completed, signed PDF. Files over ~4MB return a 302 redirect to a short-lived download URL instead of the bytes; HTTP clients follow redirects by default.\n","tags":["Documents"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"PDF file","content":{"application/pdf":{}}},"302":{"description":"Redirect to a short-lived download URL (files over ~4MB)"},"409":{"description":"Document not completed"}}}},"/documents/{id}/remind":{"post":{"summary":"Send reminder to pending signers","tags":["Signing"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"signer_id":{"type":"string"},"message":{"type":"string"}}}}}},"responses":{"200":{"description":"Reminders sent"}}}},"/documents/{id}/embedded-sign-url":{"post":{"summary":"Generate embedded signing URL","tags":["Embedded Signing"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["signer_id"],"properties":{"signer_id":{"type":"string"}}}}}},"responses":{"200":{"description":"Signing URL generated","content":{"application/json":{"schema":{"type":"object","properties":{"sign_url":{"type":"string"},"expires_at":{"type":"string","format":"date-time"}}}}}}}}},"/documents/{id}/bulk-send":{"post":{"summary":"Bulk send document","tags":["Bulk Send"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["recipients"],"properties":{"recipients":{"type":"array","items":{"type":"object","required":["email","name"],"properties":{"email":{"type":"string"},"name":{"type":"string"}}}},"subject":{"type":"string","description":"Stored with each copy and shown in the dashboard. Invitation email subject stays the SigPen standard."},"skip_email":{"type":"boolean","default":false,"description":"Create the signing sessions without sending invitation emails, so you can distribute the signing URLs yourself."}}}}}},"responses":{"202":{"description":"Bulk send started"}}}},"/documents/from-template":{"post":{"summary":"Create document from template","tags":["Templates"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["template_id"],"properties":{"template_id":{"type":"string"},"role_assignments":{"type":"object","description":"Keyed by the template role name. Each value is an object with the signer email. The signer's name is supplied later at send time.","additionalProperties":{"type":"object","properties":{"email":{"type":"string"}}}},"prefill":{"type":"object","description":"Keyed by the field label (not field ID). Flat string values.","additionalProperties":{"type":"string"}},"title":{"type":"string"},"external_id":{"type":"string","description":"Your own record ID, stored on the document and returned in every webhook."},"metadata":{"type":"object","additionalProperties":{"type":"string"}}}}}}},"responses":{"201":{"description":"Document created from template"}}}},"/documents/from-form":{"post":{"summary":"Create document from form (Business only)","tags":["Forms Library"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["form_id"],"properties":{"form_id":{"type":"string"},"prefill":{"type":"object"},"title":{"type":"string"}}}}}},"responses":{"201":{"description":"Document created from form"}}}},"/account":{"get":{"summary":"Get account info and usage","tags":["Account"],"responses":{"200":{"description":"Account info"}}}},"/webhooks":{"get":{"summary":"List webhook endpoints","tags":["Webhooks"],"responses":{"200":{"description":"Webhook list"}}},"post":{"summary":"Register a webhook endpoint","tags":["Webhooks"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url","events"],"properties":{"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"type":"string","enum":["document.sent","document.viewed","document.signed","document.completed","document.declined","document.voided","document.expired"]}},"description":{"type":"string"}}}}}},"responses":{"201":{"description":"Webhook created (secret shown only once)"}}}},"/webhooks/{id}":{"get":{"summary":"Get webhook details","tags":["Webhooks"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Webhook details"}}},"patch":{"summary":"Update webhook endpoint","tags":["Webhooks"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Webhook updated"}}},"delete":{"summary":"Delete webhook endpoint","tags":["Webhooks"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Webhook deleted"}}}},"/webhooks/{id}/test":{"post":{"summary":"Send test webhook event","tags":["Webhooks"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Test result"}}}},"/templates":{"get":{"summary":"List templates","tags":["Templates"],"responses":{"200":{"description":"Template list"}}},"post":{"summary":"Create template from document","tags":["Templates"],"responses":{"201":{"description":"Template created"}}}},"/templates/{id}":{"get":{"summary":"Get template details","tags":["Templates"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Template details with fields"}}},"patch":{"summary":"Update template","tags":["Templates"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Template updated"}}},"delete":{"summary":"Delete template","tags":["Templates"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Template deleted"}}}},"/forms":{"get":{"summary":"List available forms (Business only)","tags":["Forms Library"],"parameters":[{"name":"state","in":"query","schema":{"type":"string"}},{"name":"category","in":"query","schema":{"type":"string"}},{"name":"search","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Form list"},"403":{"description":"Business tier required"}}}},"/forms/{id}":{"get":{"summary":"Get form details (Business only)","tags":["Forms Library"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Form details"},"403":{"description":"Business tier required"}}}},"/bulk-sends/{id}":{"get":{"summary":"Check bulk send status","tags":["Bulk Send"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Bulk send status"}}}}}}