gl2pdf can run as a FastAPI service that converts GitLab JSON reports to PDF over HTTP, plus an admin API for managing API keys.
ADMIN_TOKEN=your-secret-token uvicorn gl2pdf.api:app --host 0.0.0.0 --port 8080See Configuration for the full list of environment variables (ADMIN_TOKEN, DB_URL, MAX_UPLOAD_BYTES) and how they differ between local dev, Docker, and Kubernetes.
Interactive docs are auto-generated by FastAPI and served at:
GET /docs— Swagger UIGET /redoc— ReDoc
Two independent auth schemes are used:
| Scheme | Header | Protects | Configured via |
|---|---|---|---|
| API key | X-API-Key: <raw_key> |
POST /convert |
Keys are created/managed through the admin API and stored hashed (SHA-256) in the database |
| Admin bearer token | Authorization: Bearer <token> |
/admin/* |
ADMIN_TOKEN environment variable |
API keys are never stored in plaintext. The raw key is only ever shown once, in the response body of POST /admin/keys at creation time — store it immediately, it cannot be retrieved again.
If ADMIN_TOKEN is not set, all /admin/* routes return 503 Service Unavailable rather than silently allowing access.
| Method | Path | Response |
|---|---|---|
GET |
/healthz |
200 {"status": "ok", "version": "<version>"} — liveness probe |
GET |
/readyz |
200 {"status": "ready"} — readiness probe |
Converts a raw GitLab SAST or Code Quality JSON report (sent as the raw request body) into a PDF. Report type is auto-detected using the same logic as the CLI (object with vulnerabilities → SAST, array with check_name → Code Quality).
Headers:
| Header | Required | Description |
|---|---|---|
X-API-Key |
yes | A valid, active, non-expired API key |
Content-Type |
recommended | application/json |
Query parameters:
| Param | Default | Description |
|---|---|---|
title |
localized default | Cover page title |
repo |
— | Repository / project name on the cover |
lang |
en |
en or tr |
Example:
curl -X POST "http://localhost:8080/convert?title=My+Project&repo=myorg/myrepo&lang=tr" \
-H "X-API-Key: your-api-key" \
-H "Content-Type: application/json" \
--data-binary @gl-sast-report.json \
-o report.pdfSuccess response: 200, Content-Type: application/pdf, plus these headers on every response:
| Header | Description |
|---|---|
Content-Disposition |
attachment; filename="sast-report.pdf" or "codequality-report.pdf" |
X-Report-Type |
sast or codequality |
X-Total-Findings |
Total finding count |
X-Severity-Critical / -High / -Medium / -Low |
SAST reports only |
X-Severity-Major / -Minor |
Code Quality reports only |
Error responses:
| Status | Cause |
|---|---|
400 |
Empty body, invalid JSON, or JSON that isn't a recognized SAST/Code Quality shape |
401 |
Missing X-API-Key header |
403 |
API key is invalid, inactive, or expired |
413 |
Request body exceeds MAX_UPLOAD_BYTES (default 20 MB) — see Configuration |
500 |
Internal error while rendering the PDF |
All routes below require Authorization: Bearer <ADMIN_TOKEN>.
| Method | Path | Description |
|---|---|---|
GET |
/admin/keys |
List all API keys with usage stats |
POST |
/admin/keys |
Create a new API key |
PATCH |
/admin/keys/{id}/rename |
Rename a key |
PATCH |
/admin/keys/{id}/activate |
Reactivate a key |
PATCH |
/admin/keys/{id}/deactivate |
Deactivate a key (blocks /convert immediately, 403) |
DELETE |
/admin/keys/{id} |
Permanently delete a key |
curl -X POST http://localhost:8080/admin/keys \
-H "Authorization: Bearer your-secret-token" \
-H "Content-Type: application/json" \
-d '{"name": "my-ci-key", "expires_at": null}'expires_at is optional — an ISO-8601 UTC datetime, or omit/null for no expiry.
Response (201) includes raw_key — the only time the plaintext key is returned:
{
"id": 1,
"name": "my-ci-key",
"key_prefix": "aB3dEfGh",
"is_active": true,
"created_at": "2026-01-01T00:00:00Z",
"expires_at": null,
"last_used_at": null,
"use_count": 0,
"raw_key": "aB3dEfGh...<full 43-char token>"
}curl http://localhost:8080/admin/keys -H "Authorization: Bearer your-secret-token"Returns an array of the same object shape as above, minus raw_key, including last_used_at and use_count for auditing.
curl -X PATCH http://localhost:8080/admin/keys/1/deactivate -H "Authorization: Bearer your-secret-token"
curl -X PATCH http://localhost:8080/admin/keys/1/activate -H "Authorization: Bearer your-secret-token"
curl -X DELETE http://localhost:8080/admin/keys/1 -H "Authorization: Bearer your-secret-token"DELETE returns 204. Any of the three return 404 if the key ID doesn't exist.
The full machine-readable schema is available at GET /openapi.json once the server is running — useful for generating typed clients.