Complete REST API documentation for Ackify.
https://your-domain.com/api/v1
Most endpoints require authentication via session cookie (OAuth2 or MagicLink).
Headers:
X-CSRF-Token- Required for POST/PUT/DELETE requests
Get CSRF token:
GET /api/v1/csrfGET /api/v1/healthResponse (200 OK):
{
"status": "healthy",
"database": "connected"
}POST /api/v1/auth/startBody:
{
"redirect": "/?doc=policy_2025"
}POST /api/v1/auth/magic-link/requestBody:
{
"email": "user@example.com",
"redirect": "/?doc=policy_2025"
}GET /api/v1/auth/magic-link/verify?token=xxxGET /api/v1/auth/logoutGET /api/v1/users/meResponse (200 OK):
{
"data": {
"sub": "google-oauth2|123456",
"email": "user@example.com",
"name": "John Doe",
"isAdmin": false,
"canCreateDocuments": true
}
}GET /api/v1/documents/find-or-create?doc=policy_2025Response (200 OK):
{
"data": {
"docId": "policy_2025",
"title": "Security Policy 2025",
"url": "https://example.com/policy.pdf",
"checksum": "sha256:abc123...",
"checksumAlgorithm": "SHA-256",
"signatureCount": 42,
"isNew": false
}
}Fields:
signatureCount- Total number of signatures (visible to all users)isNew- Whether the document was just created
GET /api/v1/documents/{docId}GET /api/v1/documents/{docId}/signaturesAccess Control:
| User Type | Result |
|---|---|
| Document owner or Admin | All signatures with emails |
| Authenticated user (not owner) | Only their own signature (if signed) |
| Non-authenticated | Empty list |
Note: The signature count is always available via
signatureCountin the document response. This endpoint returns the detailed list with email addresses.
Response (200 OK):
{
"data": [
{
"id": 1,
"docId": "policy_2025",
"userEmail": "alice@example.com",
"userName": "Alice Smith",
"signedAt": "2025-01-15T14:30:00Z",
"payloadHash": "sha256:e3b0c44...",
"signature": "ed25519:3045022100..."
}
]
}GET /api/v1/documents/{docId}/expected-signersAccess Control: Same as /signatures endpoint (owner/admin only).
Response (200 OK):
{
"data": [
{
"email": "bob@example.com",
"addedAt": "2025-01-10T10:00:00Z",
"hasSigned": false
}
]
}POST /api/v1/signatures
X-CSRF-Token: xxxBody:
{
"docId": "policy_2025"
}Response (201 Created):
{
"data": {
"id": 123,
"docId": "policy_2025",
"userEmail": "user@example.com",
"signedAt": "2025-01-15T14:30:00Z",
"payloadHash": "sha256:...",
"signature": "ed25519:..."
}
}Errors:
409 Conflict- User has already signed this document
GET /api/v1/signaturesReturns all signatures for the current authenticated user.
GET /api/v1/documents/{docId}/signatures/statusReturns whether the current user has signed the document.
All admin endpoints require the user to be in ACKIFY_ADMIN_EMAILS.
GET /api/v1/admin/documentsGET /api/v1/admin/documents/{docId}/signersPOST /api/v1/admin/documents/{docId}/signers
X-CSRF-Token: xxxBody:
{
"email": "newuser@example.com",
"notes": "Optional note"
}DELETE /api/v1/admin/documents/{docId}/signers/{email}
X-CSRF-Token: xxxPOST /api/v1/admin/documents/{docId}/reminders
X-CSRF-Token: xxxDELETE /api/v1/admin/documents/{docId}
X-CSRF-Token: xxxAll errors follow this format:
{
"error": {
"code": "ERROR_CODE",
"message": "Human readable message",
"details": {}
}
}Common Error Codes:
UNAUTHORIZED(401) - Authentication requiredFORBIDDEN(403) - Insufficient permissionsNOT_FOUND(404) - Resource not foundCONFLICT(409) - Resource already exists (e.g., duplicate signature)RATE_LIMITED(429) - Too many requestsVALIDATION_ERROR(400) - Invalid request body
| Endpoint Category | Limit |
|---|---|
| Authentication | 5 requests/minute |
| Signatures | 100 requests/minute |
| General API | 100 requests/minute |
The complete OpenAPI 3.0 specification is available at:
GET /api/v1/openapi.json