ADR-009: API Route Naming Convention
Status
Accepted
Context
We need a consistent API route naming convention across all services.
Decision
We will use the following conventions:
Route Structure
/api/v1/{module}/{resource}/{id?}/{action?}Module Prefixes
| Module | Base Path |
|---|---|
| Identity | /api/v1/auth |
| Organization | /api/v1/organizations |
| Doctor | /api/v1/doctors |
| Subscription | /api/v1/subscriptions |
| Doctor patient portal | /api/v1/doctors/patients (Patient business capabilities) |
| Prescription | /api/v1/prescriptions |
| Admin | /api/v1/admin |
| Notification | /api/v1/notifications |
Resource Routes
Standard CRUD
GET /api/v1/{resource} # List
POST /api/v1/{resource} # Create
GET /api/v1/{resource}/{id} # Get by ID
PUT /api/v1/{resource}/{id} # Update using that operation's contract
PATCH /api/v1/{resource}/{id} # Partial update; omitted fields are preserved
DELETE /api/v1/{resource}/{id} # DeleteNested Resources
GET /api/v1/organizations/{id}/members # List members
POST /api/v1/organizations/{id}/members # Add ordinary member
GET /api/v1/organizations/{id}/teams # List teams
POST /api/v1/organizations/{id}/teams # Create teamCustom Actions
POST /api/v1/organizations/{id}/activate # Set active context
POST /api/v1/prescriptions/{id}/issue # Issue prescription
POST /api/v1/prescriptions/{id}/cancel # Cancel and retain prescription history
POST /api/v1/admin/verifications/{id}/approve # Approve verification
POST /api/v1/admin/verifications/{id}/reject # Reject verification
POST /api/v1/notifications/send # Send notificationExamples
Identity Service
POST /api/v1/auth/register # Register
POST /api/v1/auth/login # Login
POST /api/v1/auth/refresh # Refresh token
GET /api/v1/auth/me # Get current user
PUT /api/v1/auth/me # Update profileOrganization Service
POST /api/v1/organizations # Create organization
GET /api/v1/organizations # List user's organizations
GET /api/v1/organizations/{id} # Get organization
POST /api/v1/organizations/{id}/activate # Set active context
POST /api/v1/organizations/{id}/members # Add ordinary member
GET /api/v1/organizations/{id}/members # List members
POST /api/v1/organizations/{id}/teams # Create team
GET /api/v1/organizations/{id}/teams # List teamsDoctor and Billing Contracts
POST /api/v1/doctors/register
GET /api/v1/doctors/profile
POST /api/v1/doctors/me/join-requests
GET /api/v1/subscriptions/plans
POST /api/v1/admin/subscription-plans
PATCH /api/v1/admin/subscription-plans/{planId}
POST /api/v1/admin/subscriptions
PATCH /api/v1/admin/subscriptions/{subscriptionId}
POST /api/v1/admin/subscriptions/{subscriptionId}/extend
POST /api/v1/admin/subscriptions/{subscriptionId}/invoices
POST /api/v1/admin/invoices/{invoiceId}/issue
POST /api/v1/admin/invoices/{invoiceId}/payments
POST /api/v1/admin/payments/{paymentId}/void
GET /api/v1/organizations/{organizationId}/subscription
GET /api/v1/organizations/{organizationId}/billing-historyThe /admin route surface represents the actor/workflow, not data ownership. Subscription owns plans, subscriptions, invoices and payments (ADR-014). DELETE archives a plan or immediately ends/soft-deletes a subscription; payment correction uses an explicit void action. These new contracts currently return 501 for valid requests. Organization member detail/edit/role routes use member IDs; doctor affiliations remain separate. See the workflow documents for complete inventories: Organization/Doctor and Subscription. Older verification/analytics examples below remain design examples rather than a claim that those routes are implemented.
Patient and Prescription Services
POST /api/v1/doctors/patients
GET /api/v1/doctors/patients?organization_id={id}&q={search}
GET /api/v1/doctors/patients/{patientId}
PATCH /api/v1/doctors/patients/{patientId}
POST /api/v1/prescriptions
GET /api/v1/prescriptions?organization_id={id}&patient_id={id}&doctor_id={id}&status=draft
GET /api/v1/prescriptions/{prescriptionId}
PATCH /api/v1/prescriptions/{prescriptionId}
POST /api/v1/prescriptions/{prescriptionId}/issue
POST /api/v1/prescriptions/{prescriptionId}/cancel
GET /api/v1/prescriptions/patient-history/{patientId}Patient CRUD is implemented through Doctor-owned routes, delegating to Patient public capabilities. Prescription clinical contracts still return 501. Legacy PUT updates and DELETE cancellation are removed; PATCH replaces supplied sections and actions require expected_version. Only organization_id is mandatory on collection queries; prescription filters are optional. See Patient/Prescription API.
Medicine Catalog Contracts
Read routes use /api/v1/medicines/{resource} and /{id}. Platform administration uses /api/v1/admin/medicines/{resource} with GET/POST, /{id} with GET/PATCH/DELETE, and /{id}/restore with POST. Resources are manufacturers, generics, brands and drugs. DELETE documents soft deletion with dependent-record conflicts, never cascades. All valid requests return 501. See Medicine API.
Admin Service
GET /api/v1/admin/organizations # List all organizations
POST /api/v1/admin/organizations/{id}/suspend # Suspend tenant
POST /api/v1/admin/organizations/{id}/activate # Activate tenant
POST /api/v1/admin/verifications # Submit verification
GET /api/v1/admin/verifications/pending # Pending queue
POST /api/v1/admin/verifications/{id}/approve # Approve
POST /api/v1/admin/verifications/{id}/reject # Reject
GET /api/v1/admin/analytics # System analyticsNotification Service
POST /api/v1/notifications/send # Send notification
GET /api/v1/notifications?recipient={email} # List notifications
POST /api/v1/notifications/templates # Create template
GET /api/v1/notifications/templates # List templatesConsequences
Positive
- Consistent across services
- Predictable for API consumers
- Easy to document
Negative
- Some routes may feel verbose
Related Decisions
ADR-008: Service Boundaries