Files
ackify-ce/backend/openapi.yaml
Benjamin d3e7c9911c fix: rename API parameter 'ref' to 'doc' for privacy extensions compatibility
ClearURLs and similar privacy extensions block the 'ref' parameter
as it's commonly used for referrer tracking. Renamed to 'doc' which
is not targeted by these extensions.

Closes #19
2026-02-05 22:33:03 +01:00

937 lines
23 KiB
YAML

openapi: 3.0.3
info:
title: Ackify API
description: |
REST API for Ackify - Document signature tracking with cryptographic Ed25519 signatures.
## Authentication
Most endpoints require OAuth2 authentication via session cookies.
Admin endpoints additionally require the user's email to be in the ACKIFY_ADMIN_EMAILS list.
## CSRF Protection
Write operations (POST, PUT, DELETE) require a CSRF token obtained from `GET /api/v1/csrf`.
Include the token in the `X-CSRF-Token` header.
version: 1.0.0
contact:
name: Ackify Support
url: https://github.com/btouchard/ackify-ce
license:
name: AGPL-3.0-or-later
url: https://www.gnu.org/licenses/agpl-3.0.html
servers:
- url: /api/v1
description: API v1
tags:
- name: Health
description: System health checks
- name: Auth
description: OAuth2 authentication endpoints
- name: Users
description: User information
- name: Documents
description: Document management (public)
- name: Signatures
description: Signature creation and retrieval
- name: Admin - Documents
description: Admin document management
- name: Admin - Signers
description: Admin expected signers management
- name: Admin - Reminders
description: Admin email reminder management
paths:
/health:
get:
summary: Health check
description: Returns the health status of the API
tags:
- Health
responses:
'200':
description: Service is healthy
content:
application/json:
schema:
type: object
properties:
status:
type: string
example: ok
timestamp:
type: string
format: date-time
/csrf:
get:
summary: Get CSRF token
description: Returns a CSRF token required for write operations
tags:
- Auth
responses:
'200':
description: CSRF token generated
content:
application/json:
schema:
type: object
properties:
csrfToken:
type: string
example: abc123def456
/auth/start:
post:
summary: Start OAuth2 flow
description: Initiates OAuth2 authentication with the configured provider
tags:
- Auth
requestBody:
required: false
content:
application/json:
schema:
type: object
properties:
redirectTo:
type: string
description: URL to redirect to after successful authentication
example: /signatures
responses:
'302':
description: Redirect to OAuth provider
'400':
description: Invalid request
/auth/callback:
get:
summary: OAuth2 callback
description: Handles OAuth2 provider callback after user authentication
tags:
- Auth
parameters:
- name: code
in: query
required: true
schema:
type: string
- name: state
in: query
required: true
schema:
type: string
responses:
'302':
description: Redirect to application
'400':
description: Invalid callback parameters
'401':
description: Authentication failed
/auth/logout:
get:
summary: Logout
description: Logs out the current user and clears the session
tags:
- Auth
responses:
'302':
description: Redirect to home page
/auth/check:
get:
summary: Check authentication status
description: Checks if user has an active OAuth session (only available if ACKIFY_OAUTH_AUTO_LOGIN=true)
tags:
- Auth
responses:
'200':
description: Authentication status
content:
application/json:
schema:
type: object
properties:
authenticated:
type: boolean
/users/me:
get:
summary: Get current user
description: Returns information about the currently authenticated user
tags:
- Users
security:
- sessionAuth: []
responses:
'200':
description: Current user information
content:
application/json:
schema:
$ref: '#/components/schemas/User'
'401':
description: Not authenticated
/documents:
get:
summary: List documents
description: Returns a paginated list of all documents
tags:
- Documents
parameters:
- name: page
in: query
schema:
type: integer
default: 1
- name: limit
in: query
schema:
type: integer
default: 20
maximum: 100
responses:
'200':
description: List of documents
content:
application/json:
schema:
type: object
properties:
documents:
type: array
items:
$ref: '#/components/schemas/Document'
total:
type: integer
page:
type: integer
limit:
type: integer
post:
summary: Create document
description: Creates a new document with metadata
tags:
- Documents
security:
- csrfToken: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateDocumentRequest'
responses:
'201':
description: Document created
content:
application/json:
schema:
$ref: '#/components/schemas/Document'
'400':
description: Invalid request
'403':
description: CSRF token missing or invalid
/documents/{docId}:
get:
summary: Get document
description: Returns document metadata and signature count
tags:
- Documents
parameters:
- name: docId
in: path
required: true
schema:
type: string
responses:
'200':
description: Document details
content:
application/json:
schema:
$ref: '#/components/schemas/DocumentWithCount'
'404':
description: Document not found
/documents/{docId}/signatures:
get:
summary: Get document signatures
description: Returns all signatures for a document
tags:
- Documents
parameters:
- name: docId
in: path
required: true
schema:
type: string
responses:
'200':
description: List of signatures
content:
application/json:
schema:
type: object
properties:
signatures:
type: array
items:
$ref: '#/components/schemas/Signature'
/documents/{docId}/signatures/status:
get:
summary: Get user signature status
description: Checks if the current user has signed this document
tags:
- Signatures
security:
- sessionAuth: []
parameters:
- name: docId
in: path
required: true
schema:
type: string
responses:
'200':
description: Signature status
content:
application/json:
schema:
type: object
properties:
hasSigned:
type: boolean
signature:
$ref: '#/components/schemas/Signature'
/documents/{docId}/expected-signers:
get:
summary: Get expected signers
description: Returns the list of expected signers for a document
tags:
- Documents
parameters:
- name: docId
in: path
required: true
schema:
type: string
responses:
'200':
description: List of expected signers
content:
application/json:
schema:
type: object
properties:
expectedSigners:
type: array
items:
$ref: '#/components/schemas/ExpectedSigner'
/documents/find-or-create:
get:
summary: Find or create document
description: Finds a document by reference, or creates it if it doesn't exist
tags:
- Documents
parameters:
- name: doc
in: query
required: true
schema:
type: string
description: Document reference (URL, path, or custom ID)
responses:
'200':
description: Document found or created
content:
application/json:
schema:
$ref: '#/components/schemas/Document'
/signatures:
get:
summary: Get user signatures
description: Returns all signatures created by the current user
tags:
- Signatures
security:
- sessionAuth: []
responses:
'200':
description: List of user signatures
content:
application/json:
schema:
type: object
properties:
signatures:
type: array
items:
$ref: '#/components/schemas/Signature'
post:
summary: Create signature
description: Creates a cryptographic Ed25519 signature for a document
tags:
- Signatures
security:
- sessionAuth: []
- csrfToken: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateSignatureRequest'
responses:
'201':
description: Signature created
content:
application/json:
schema:
$ref: '#/components/schemas/Signature'
'400':
description: Invalid request
'409':
description: User has already signed this document
/admin/documents:
get:
summary: List all documents (admin)
description: Returns paginated list of all documents with admin metadata
tags:
- Admin - Documents
security:
- sessionAuth: []
- adminRole: []
parameters:
- name: page
in: query
schema:
type: integer
default: 1
- name: limit
in: query
schema:
type: integer
default: 20
responses:
'200':
description: List of documents
content:
application/json:
schema:
type: object
properties:
documents:
type: array
items:
$ref: '#/components/schemas/Document'
total:
type: integer
/admin/documents/{docId}:
get:
summary: Get document details (admin)
description: Returns detailed document information
tags:
- Admin - Documents
security:
- sessionAuth: []
- adminRole: []
parameters:
- name: docId
in: path
required: true
schema:
type: string
responses:
'200':
description: Document details
content:
application/json:
schema:
$ref: '#/components/schemas/Document'
delete:
summary: Delete document (admin)
description: Soft deletes a document
tags:
- Admin - Documents
security:
- sessionAuth: []
- adminRole: []
- csrfToken: []
parameters:
- name: docId
in: path
required: true
schema:
type: string
responses:
'204':
description: Document deleted
'404':
description: Document not found
/admin/documents/{docId}/metadata:
put:
summary: Update document metadata (admin)
description: Updates document title, URL, checksum, and description
tags:
- Admin - Documents
security:
- sessionAuth: []
- adminRole: []
- csrfToken: []
parameters:
- name: docId
in: path
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateDocumentMetadataRequest'
responses:
'200':
description: Metadata updated
content:
application/json:
schema:
$ref: '#/components/schemas/Document'
/admin/documents/{docId}/signers:
get:
summary: Get document with signers (admin)
description: Returns document with both expected and actual signers
tags:
- Admin - Signers
security:
- sessionAuth: []
- adminRole: []
parameters:
- name: docId
in: path
required: true
schema:
type: string
responses:
'200':
description: Document with signers
content:
application/json:
schema:
$ref: '#/components/schemas/DocumentWithSigners'
post:
summary: Add expected signer (admin)
description: Adds one or more expected signers to a document
tags:
- Admin - Signers
security:
- sessionAuth: []
- adminRole: []
- csrfToken: []
parameters:
- name: docId
in: path
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/AddExpectedSignerRequest'
responses:
'201':
description: Signer(s) added
'400':
description: Invalid request
/admin/documents/{docId}/signers/{email}:
delete:
summary: Remove expected signer (admin)
description: Removes an expected signer from a document
tags:
- Admin - Signers
security:
- sessionAuth: []
- adminRole: []
- csrfToken: []
parameters:
- name: docId
in: path
required: true
schema:
type: string
- name: email
in: path
required: true
schema:
type: string
responses:
'204':
description: Signer removed
/admin/documents/{docId}/status:
get:
summary: Get document status (admin)
description: Returns completion statistics for a document
tags:
- Admin - Documents
security:
- sessionAuth: []
- adminRole: []
parameters:
- name: docId
in: path
required: true
schema:
type: string
responses:
'200':
description: Document status
content:
application/json:
schema:
$ref: '#/components/schemas/DocumentStatus'
/admin/documents/{docId}/reminders:
get:
summary: Get reminder history (admin)
description: Returns email reminder send history for a document
tags:
- Admin - Reminders
security:
- sessionAuth: []
- adminRole: []
parameters:
- name: docId
in: path
required: true
schema:
type: string
responses:
'200':
description: Reminder history
content:
application/json:
schema:
type: object
properties:
reminders:
type: array
items:
$ref: '#/components/schemas/ReminderLog'
post:
summary: Send reminders (admin)
description: Sends email reminders to pending signers
tags:
- Admin - Reminders
security:
- sessionAuth: []
- adminRole: []
- csrfToken: []
parameters:
- name: docId
in: path
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/SendRemindersRequest'
responses:
'200':
description: Reminders queued
content:
application/json:
schema:
type: object
properties:
queued:
type: integer
description: Number of emails queued for sending
/openapi.json:
get:
summary: Get OpenAPI specification
description: Returns this OpenAPI specification in JSON format
tags:
- Health
responses:
'200':
description: OpenAPI spec
content:
application/json:
schema:
type: object
components:
securitySchemes:
sessionAuth:
type: apiKey
in: cookie
name: session
description: OAuth2 session cookie
csrfToken:
type: apiKey
in: header
name: X-CSRF-Token
description: CSRF protection token
adminRole:
type: http
scheme: bearer
description: Admin email must be in ACKIFY_ADMIN_EMAILS
schemas:
User:
type: object
properties:
id:
type: string
description: User unique identifier (OAuth sub claim)
email:
type: string
format: email
name:
type: string
isAdmin:
type: boolean
Document:
type: object
properties:
docId:
type: string
example: abc123
title:
type: string
url:
type: string
checksum:
type: string
checksumAlgorithm:
type: string
enum: [SHA-256, SHA-512, MD5]
description:
type: string
createdAt:
type: string
format: date-time
updatedAt:
type: string
format: date-time
createdBy:
type: string
DocumentWithCount:
allOf:
- $ref: '#/components/schemas/Document'
- type: object
properties:
signatureCount:
type: integer
Signature:
type: object
properties:
id:
type: integer
format: int64
docId:
type: string
userSub:
type: string
userEmail:
type: string
format: email
userName:
type: string
signedAt:
type: string
format: date-time
payloadHash:
type: string
signature:
type: string
description: Ed25519 signature (hex-encoded)
nonce:
type: string
createdAt:
type: string
format: date-time
referer:
type: string
prevHash:
type: string
docChecksum:
type: string
ExpectedSigner:
type: object
properties:
id:
type: integer
format: int64
docId:
type: string
email:
type: string
format: email
name:
type: string
addedAt:
type: string
format: date-time
addedBy:
type: string
notes:
type: string
ReminderLog:
type: object
properties:
id:
type: integer
format: int64
docId:
type: string
recipientEmail:
type: string
format: email
sentAt:
type: string
format: date-time
sentBy:
type: string
templateUsed:
type: string
status:
type: string
enum: [sent, failed, bounced, queued]
errorMessage:
type: string
DocumentStatus:
type: object
properties:
docId:
type: string
expectedCount:
type: integer
signedCount:
type: integer
pendingCount:
type: integer
completionPercentage:
type: number
format: float
DocumentWithSigners:
allOf:
- $ref: '#/components/schemas/Document'
- type: object
properties:
expectedSigners:
type: array
items:
$ref: '#/components/schemas/ExpectedSigner'
signatures:
type: array
items:
$ref: '#/components/schemas/Signature'
CreateDocumentRequest:
type: object
required:
- reference
properties:
reference:
type: string
description: Document URL, path, or custom ID
title:
type: string
description:
type: string
UpdateDocumentMetadataRequest:
type: object
properties:
title:
type: string
url:
type: string
checksum:
type: string
checksumAlgorithm:
type: string
enum: [SHA-256, SHA-512, MD5]
description:
type: string
CreateSignatureRequest:
type: object
required:
- docId
properties:
docId:
type: string
referer:
type: string
description: Source service (Google Docs, GitHub, etc.)
docChecksum:
type: string
description: Document checksum at signing time
AddExpectedSignerRequest:
type: object
required:
- emails
properties:
emails:
type: array
items:
type: string
format: email
notes:
type: string
SendRemindersRequest:
type: object
properties:
emails:
type: array
items:
type: string
format: email
description: Specific emails to send to (omit to send to all pending)
docURL:
type: string
description: Custom document URL for email
locale:
type: string
enum: [en, fr, es, de, it]
default: en
description: Email language