Skip to content

Document API Endpoints

PDF Generation Endpoints

GET /v1/reports/{id}/pdf

Generate or serve cached PDF for a report.

Query Parameters:

  • ?audience=patient|specialist|admin (default: based on caller role)
  • ?template_id=5 (optional, uses org default if omitted)

Response: 200

Content-Type: application/pdf

Headers:

Content-Type: application/pdf
Content-Disposition: inline; filename="report-{id}.pdf"

Access:

  • Patient (own report, audience=patient forced)
  • Specialist
  • Admin

Caching: If form.status=signed, returns cached S3 version if available

Errors:

  • 404 document_not_found - Document doesn't exist or not accessible
  • 400 form_not_attached - Document has no associated form
  • 500 pdf_generation_failed - Chrome rendering error

GET /v1/prescriptions/{id}/pdf

Generate or serve cached PDF for a prescription.

Query Parameters:

  • ?audience=patient|specialist|admin (default: based on caller role)
  • ?template_id=5 (optional, uses org default if omitted)

Response: 200

Content-Type: application/pdf

Access:

  • Patient (own prescription)
  • Specialist
  • Admin

Additional rule: Prescription PDF always includes specialist signature (generation fails if missing)

Errors:

  • 404 document_not_found
  • 400 form_not_attached
  • 400 specialist_signature_required - Prescription requires specialist signature
  • 500 pdf_generation_failed

Audience Filtering

The ?audience query parameter controls field visibility:

AudiencePrivate fieldsSpecialist signatureUse case
patient (default)ExcludedIncludedPatient downloads their report
specialistIncludedIncludedSpecialist reviews full report
adminIncludedIncludedAdmin/compliance review

Filtering happens at the data building step, not in the template. The template always renders what it receives.

PDF Template Management

Note: PDF template management (visual designer, block-based editor, component library) has been moved to a separate feature.

See PDF Templates API for:

  • Template CRUD (/v1/pdf-templates/*)
  • Component management (/v1/pdf-template-components/*)
  • Template versioning and publishing
  • Live preview and rendering

Form templates link to PDF templates via form_templates.pdf_template_id, and documents record which pdf_template_version was used for generation.

Report CRUD Endpoints

Reports are stored in appointment_documents with type=report.

GET /v1/reports

List reports. Org-scoped by RLS.

Query Parameters:

  • ?appointment_id=102
  • ?published=true
  • ?page=1&page_size=25

Response: 200

json
{
  "data": [
    {
      "id": 1,
      "organization_id": 1,
      "appointment_id": 102,
      "user_id": 42,
      "form_id": 204,
      "type": "report",
      "title": "Consultation Report",
      "document_url": null,
      "published": false,
      "created_at": "2025-01-15T10:00:00Z"
    }
  ],
  "meta": {
    "page": 1,
    "page_size": 25,
    "total": 1,
    "total_pages": 1
  }
}

POST /v1/reports

Create report for an appointment.

Request:

json
{
  "appointment_id": 102,
  "title": "Consultation Report",
  "form_id": 204
}

Response: 201

json
{
  "data": {
    "id": 1,
    "organization_id": 1,
    "appointment_id": 102,
    "user_id": 42,
    "form_id": 204,
    "type": "report",
    "title": "Consultation Report",
    "published": false,
    "created_at": "2025-01-15T10:00:00Z"
  }
}

Access: Specialist | Admin

GET /v1/reports/{id}

Get report with files.

Response: 200

json
{
  "data": {
    "id": 1,
    "organization_id": 1,
    "appointment_id": 102,
    "user_id": 42,
    "form_id": 204,
    "type": "report",
    "title": "Consultation Report",
    "document_url": null,
    "published": false,
    "files": [
      {
        "id": 1,
        "file_url": "https://s3.../file.pdf",
        "file_name": "report.pdf",
        "file_type": "application/pdf",
        "file_size": 102400,
        "created_at": "2025-01-15T10:00:00Z"
      }
    ],
    "created_at": "2025-01-15T10:00:00Z"
  }
}

Access: Patient (own) | Specialist | Admin

PUT /v1/reports/{id}

Update report metadata.

Request:

json
{
  "title": "Updated Report Title",
  "published": true
}

Response: 200

Access: Specialist | Admin

DELETE /v1/reports/{id}

Delete report.

Response: 204 No Content

Access: Admin only

Prescription CRUD Endpoints

Prescriptions are stored in appointment_documents with type=prescription.

GET /v1/prescriptions

List prescriptions. Org-scoped by RLS.

POST /v1/prescriptions

Create prescription for an appointment.

Request:

json
{
  "appointment_id": 102,
  "title": "Treatment Prescription",
  "form_id": 205
}

GET /v1/prescriptions/{id}

Get prescription.

PUT /v1/prescriptions/{id}

Update prescription.

DELETE /v1/prescriptions/{id}

Delete prescription.

Error Codes

ErrorHTTPWhen
document_not_found404Document ID doesn't exist or not accessible via RLS
form_not_attached400Document has no associated form
form_not_signed400Trying to publish/cache a PDF for an unsigned form
specialist_signature_required400Prescription PDF requested but specialist has no signature
template_not_found404Specified template_id doesn't exist; or no default template for org+type
template_render_error500Go template execution failed (syntax error in template HTML)
pdf_generation_failed500chromedp failed to render PDF
document_already_published409Trying to modify a published document