API Conventions
This document defines the API design and response conventions for the Tripinger backend.
Document Purpose
This document defines the API design and response conventions for the Tripinger backend. It establishes common rules for routes, payloads, response shapes, errors, pagination, filtering, versioning, timestamps, identifiers, and operational behavior so the public web app, partner portal, admin dashboard, and future clients can integrate consistently.
The API is the shared business layer for the Tripinger platform and is expected to serve traveler-facing, partner-facing, and internal administrative workflows. Because the same backend supports search, bookings, payments, partner operations, moderation, and AI-assisted planning, API consistency is a platform-level concern rather than a per-module preference.
Design Principles
The API should follow these principles across all modules.
-
Consistency over cleverness Similar operations should look and behave the same across hotels, vehicles, food, activities, bookings, reviews, partners, and admin modules. This is especially important because the product spans many domains but is delivered through one shared API platform.
-
API-first platform design The architecture explicitly states that clients should interact through documented backend APIs rather than embedding business rules inside frontend applications. Conventions must therefore be stable enough for the public web app, admin dashboard, and partner portal to build against safely.
-
Domain-based structure Routes should reflect business domains such as auth, users, hotels, vehicles, bookings, payments, reviews, planner, partners, and admin instead of being grouped only by technical layer. This matches the modular NestJS structure already defined in the API documentation.
-
Predictable errors and metadata Clients should be able to handle loading, validation failure, auth failure, conflict states, pagination, and operational problems without guessing how each module behaves. The frontend docs already emphasize intentional handling of loading, empty, and failure states, which depends on stable API behavior.
-
Security by default Authorization, ownership checks, sensitive actions, webhook verification, and privileged admin controls must be enforced server-side. The architecture and auth docs already define centralized auth, role-based control, and auditable privileged actions as core security requirements.
Base URL and Versioning
The current local-development examples already point to an API URL shape like http://localhost:4000/api/v1, which should be treated as the Phase 1 base path convention. The public web and partner docs both reference that structure for local integration.
Base path
/api/v1Examples
GET /api/v1/hotels
POST /api/v1/auth/login
GET /api/v1/bookings/:bookingId
PATCH /api/v1/partner/listings/:listingId
GET /api/v1/admin/partners/pendingVersioning rules
- Major breaking changes should produce a new API version such as
/api/v2. - Non-breaking additions may be introduced within the same major version.
- Version changes should be explicit in the URL, not hidden in undocumented behavior.
- Clients should not be forced to infer version from headers alone in Phase 1.
This approach keeps the contract simple for web, admin, and partner applications that are all being developed in parallel.
Resource Naming
Route naming should be simple, plural where appropriate, and domain-oriented.
Rules
- Use lowercase path segments.
- Use hyphenated words only when a segment contains multiple words.
- Prefer plural nouns for collections.
- Prefer stable business terminology already used across the docs.
- Avoid verbs in route names unless the route represents a non-CRUD action.
Good examples
/auth/login
/users/me
/hotels
/hotels/:hotelId
/vehicles
/bookings
/bookings/:bookingId/cancel
/reviews
/partner/listings
/admin/partners/pending
/payments/:paymentId
/planner/tripsAvoid
/getHotels
/createBooking
/userProfileDetails
/doPaymentConfirmationThe route vocabulary should stay aligned with the domain boundaries already defined in the architecture and API README, including auth, users, hotels, vehicles, experiences, bookings, payments, reviews, planner, partners, and admin.
Route Grouping Strategy
The API serves multiple access surfaces, but business domains should remain the primary grouping mechanism.
Public and traveler-oriented groups
/auth/users/profiles/hotels/vehicles/food/activities/search/planner/budgets/bookings/payments/reviews/social/notifications
These groups reflect the traveler-facing and shared business modules already listed in the API README and public web documentation.
Partner-oriented groups
/partner/profile/partner/onboarding/partner/listings/partner/availability/partner/pricing/partner/bookings/partner/documents/partner/reviews/partner/analytics/partner/payouts
These map directly to the partner portal capabilities already described in the partner README.
Admin-oriented groups
/admin/users/admin/partners/admin/hotels/admin/vehicles/admin/bookings/admin/payments/admin/reviews/admin/moderation/admin/compliance/admin/support/admin/reports/admin/audit
These align with the internal workflows and protected operational areas already defined for the admin surface.
HTTP Method Semantics
The API should use standard HTTP methods consistently.
| Method | Use |
|---|---|
GET | Read data without side effects |
POST | Create resources or trigger non-idempotent actions |
PUT | Full replacement when truly needed |
PATCH | Partial updates |
DELETE | Delete or archive resources where deletion is allowed |
Guidance
- Use
GETfor list and detail fetches. - Use
POSTfor create operations such as registration, booking creation, document upload initiation, and payment intent creation. - Use
PATCHfor most updates because the platform has many partial-edit workflows, especially in partner and admin tools. - Use
DELETEonly where true removal is acceptable; many operational records should instead use archive or status changes because bookings, payments, and compliance-sensitive records require auditability. The API docs already emphasize keeping payment, booking, and ledger-related actions explicit and auditable.
Action endpoints
When an action is not simple CRUD, use a clearly named sub-resource action.
Examples:
POST /bookings
POST /bookings/:bookingId/cancel
POST /payments/:paymentId/refund
POST /admin/partners/:partnerId/approve
POST /admin/partners/:partnerId/reject
POST /reviews/:reviewId/reportRequest Format
Content type
Use JSON for standard request and response bodies.
Content-Type: application/json
Accept: application/jsonMultipart uploads
Use multipart/form-data only for file-upload flows such as:
- listing images
- partner documents
- review media
- user-uploaded assets where supported
The architecture and app docs already define media and document workflows for hotels, vehicles, reviews, and partner verification, so file handling must be treated as a first-class API concern.
Body conventions
- Use objects, not primitive root values.
- Use camelCase for JSON property names.
- Use arrays only for true ordered collections.
- Keep field names descriptive and stable.
Example:
{
"email": "user@example.com",
"password": "example-password",
"displayName": "Example User"
}Response Envelope
The API should return a consistent response envelope for most application-facing endpoints. This helps frontend clients centralize parsing and error handling, which is already recommended in the public web app documentation.
Standard success response
{
"success": true,
"message": "Hotel list retrieved successfully.",
"data": [],
"meta": {}
}Minimal success response guidance
successshould always be present.messageshould be human-readable but not treated as the only source of truth.datashould contain the primary payload.metashould be included when additional metadata matters, especially for pagination, filters, counts, or processing context.
Standard error response
{
"success": false,
"message": "Validation failed.",
"error": {
"code": "VALIDATION_ERROR",
"details": [
{
"field": "email",
"message": "Email is required."
}
]
},
"meta": {
"requestId": "req_123"
}
}Why use an envelope
A shared envelope makes it easier for:
- the public web app to normalize errors and loading states
- the partner portal to handle form, table, and onboarding failures consistently
- the admin dashboard to manage operational states and action confirmations
- future mobile clients to integrate without per-module parsing logic
This is especially useful because all three web surfaces are expected to be API-driven and built in parallel.
Data Shape Rules
Collections
Return arrays inside data.
{
"success": true,
"message": "Vehicles retrieved successfully.",
"data": [
{
"id": "veh_123",
"name": "City Tuk Tuk",
"status": "active"
}
],
"meta": {
"pagination": {
"page": 1,
"limit": 20,
"totalItems": 1,
"totalPages": 1
}
}
}Single-resource responses
Return the object directly in data.
{
"success": true,
"message": "Booking retrieved successfully.",
"data": {
"id": "bkg_123",
"status": "confirmed"
}
}Mutation responses
For create, update, approve, reject, cancel, and similar actions:
- return the updated or created resource when useful
- include a meaningful message
- include metadata only when necessary
Pagination Conventions
The public web app already expects search, listing grids, filters, sorting, and pagination or infinite-scroll behavior across hotels, vehicles, food, and later activities. The partner and admin apps also need stable list handling for dashboards, tables, and operational queues.
Query parameters
Use:
pagelimitsortorder
Example:
GET /api/v1/hotels?page=1&limit=20&sort=createdAt&order=descPagination metadata
Return pagination details in meta.pagination.
{
"meta": {
"pagination": {
"page": 1,
"limit": 20,
"totalItems": 245,
"totalPages": 13,
"hasNextPage": true,
"hasPreviousPage": false
}
}
}Rules
- Default pagination should exist for list endpoints unless a route is intentionally small.
- The API should enforce a maximum
limit. - Infinite-scroll clients may still use page/limit behind the scenes.
- Cursor pagination may be added later for higher-scale feeds or activity streams, but page/limit is the simpler Phase 1 default.
Filtering and Sorting
Tripinger’s search-heavy product shape requires first-class filter and sort conventions, especially because traveler flows depend on destination, dates, availability, price range, and category-specific filters.
Filter rules
- Use query parameters for filters.
- Prefer explicit parameter names over overloaded blobs.
- Use repeated params or comma-separated values only when documented clearly.
- Keep filter keys domain-specific but predictable.
Examples
GET /api/v1/hotels?city=colombo&checkIn=2026-08-10&checkOut=2026-08-12&minPrice=50&maxPrice=150
GET /api/v1/vehicles?location=galle&type=tuk-tuk&availableFrom=2026-09-01&availableTo=2026-09-03
GET /api/v1/admin/partners?status=pending_verification
GET /api/v1/partner/bookings?status=upcomingSorting rules
- Use
sortfor field name. - Use
order=asc|desc. - Support multiple sort fields only when truly needed and documented.
- Reject unsupported sort fields with a validation error rather than silently ignoring them.
Search Endpoint Conventions
Search is a core product concern across traveler, partner, and operational flows, and the architecture already includes Elasticsearch as the planned derived search layer for discovery and filtering.
Recommended search patterns
- Use domain-specific list endpoints when filtering a domain collection.
- Use a dedicated
/searchnamespace for cross-domain or federated search. - Return a stable result shape with clear result typing when different entities are mixed.
Examples
GET /api/v1/hotels?city=kandy&stars=4
GET /api/v1/vehicles?location=ella&type=bike
GET /api/v1/search?q=surfing&types=activities,foodCross-domain search result suggestion
{
"success": true,
"data": [
{
"type": "hotel",
"id": "htl_123",
"title": "Ocean Breeze Villa"
},
{
"type": "activity",
"id": "act_456",
"title": "South Coast Surf Lesson"
}
]
}Identifier Conventions
The API should use stable string identifiers in responses rather than exposing fragile database assumptions to clients.
Guidance
- Use
idfor the primary identifier field. - IDs should be opaque to clients.
- Avoid requiring clients to infer entity type from integer ranges or database internals.
- Foreign keys returned in payloads should be named clearly, such as
hotelId,partnerId,bookingId,paymentId.
Example
{
"id": "bkg_01HXYZ...",
"partnerId": "par_01HXYZ...",
"travelerId": "usr_01HXYZ..."
}This keeps client contracts stable even if persistence implementation evolves.
Timestamp Conventions
The API should use ISO 8601 timestamps in UTC.
Standard fields
createdAtupdatedAtdeletedAtwhere soft deletion exists- domain-specific timestamps such as
approvedAt,paidAt,cancelledAt,verifiedAt
Example
{
"createdAt": "2026-07-18T17:12:57Z",
"updatedAt": "2026-07-18T18:05:12Z"
}Stable timestamp conventions are especially important for bookings, payments, admin actions, reviews, and partner verification workflows, all of which have timeline-sensitive operational meaning in the current platform design.
Status Field Conventions
Tripinger includes many workflow-driven modules such as bookings, partner onboarding, listings, payments, reviews, and moderation. Status fields should therefore be explicit and domain-owned rather than overloaded or implied.
Rules
- Use string enum-like values.
- Keep status vocabularies domain-specific.
- Do not overload one generic
statusdefinition across unrelated domains unless semantics actually match. - Document allowed values per module.
Examples
- booking status:
pending,confirmed,cancelled,completed - payment status:
pending,authorized,paid,failed,refunded - partner status:
registered,onboarding,pending_verification,approved,suspended - listing status:
draft,pending_review,active,inactive,rejected
The partner portal docs already define several partner-state examples, and the booking/payment/admin flows all depend on explicit state transitions.
Validation Rules
Validation should happen at the API boundary and should fail clearly.
Principles
- Validate input DTOs consistently.
- Reject invalid enum values, unsupported sort fields, malformed dates, and missing required fields with structured errors.
- Normalize common primitive types carefully.
- Do not silently coerce risky values when that could confuse client behavior.
Validation error response shape
{
"success": false,
"message": "Validation failed.",
"error": {
"code": "VALIDATION_ERROR",
"details": [
{
"field": "checkIn",
"message": "checkIn must be a valid ISO date."
},
{
"field": "guestCount",
"message": "guestCount must be greater than zero."
}
]
}
}This kind of predictable structure helps all frontend surfaces render field-level and form-level feedback consistently.
Error Taxonomy
The API should use a stable error taxonomy so clients can distinguish between auth problems, validation failures, conflict states, business-rule failures, and operational faults.
Suggested error codes
| Code | Meaning |
|---|---|
VALIDATION_ERROR | Request payload or query validation failed |
UNAUTHENTICATED | No valid authentication provided |
FORBIDDEN | Authenticated but lacks required permission |
NOT_FOUND | Target resource does not exist or is not visible |
CONFLICT | Current state conflicts with requested action |
RATE_LIMITED | Too many requests |
PAYMENT_FAILED | Payment operation failed |
WEBHOOK_VERIFICATION_FAILED | Provider callback could not be trusted |
PARTNER_NOT_APPROVED | Partner account lacks approval for requested action |
BUSINESS_RULE_VIOLATION | Domain rule prevents operation |
INTERNAL_ERROR | Unexpected server failure |
HTTP status guidance
| Status | Use |
|---|---|
200 | Successful read or mutation with response body |
201 | Successful creation |
202 | Accepted for async processing when applicable |
204 | Successful operation with no response body when justified |
400 | Invalid request format or generic bad request |
401 | Unauthenticated |
403 | Authenticated but forbidden |
404 | Resource not found |
409 | Conflict or invalid state transition |
422 | Semantically invalid payload where used consistently |
429 | Rate limited |
500 | Unexpected server error |
502/503/504 | Upstream or availability problems when relevant |
The architecture already highlights rate limiting, webhook safety, auditability, and operational monitoring as important API concerns, so error handling should support those realities directly.
Auth Header Conventions
The auth model already defines JWT-based access and refresh behavior for the shared API platform. Authenticated API requests should therefore use a standard bearer-token pattern for protected routes.
Authorization header
Authorization: Bearer <access-token>Rules
- Protected routes must reject missing or invalid access tokens.
- Role checks and ownership checks happen after successful authentication.
- Admin and partner routes must not trust client-side role declarations.
- Session refresh should use the dedicated refresh flow rather than overloading general endpoints.
Idempotency and Retry Safety
Tripinger includes high-risk write operations such as booking creation, payment processing, approvals, and webhook-driven state transitions. The API documentation already recommends idempotency for webhook handlers and booking confirmation paths.
Apply idempotency to
- payment webhook handlers
- booking confirmation paths
- retry-prone provider callbacks
- selected create operations where duplicate submission risk is high
Guidance
- Use idempotency keys where appropriate for payment or booking creation flows.
- Do not rely on frontend behavior alone to prevent duplicates.
- Log duplicate or replay attempts in a traceable way.
Async Operation Conventions
The architecture and API docs both define asynchronous side effects as part of the platform model, including notifications, search indexing, payout preparation, and booking-related background processing.
When async is appropriate
- notification dispatch
- email confirmation
- search indexing
- media processing
- payout preparation
- recommendation refresh
- AI post-processing
- scheduled reminders
API behavior
If an operation is accepted but completed later, return a response that makes that clear.
Example:
{
"success": true,
"message": "Document upload accepted for processing.",
"data": {
"id": "doc_123",
"status": "processing"
}
}Use 202 Accepted when the distinction matters operationally.
Nullability and Optional Fields
Rules
- Omit fields only when their absence has clear meaning and is documented.
- Use
nullwhen a field exists conceptually but has no value yet. - Avoid mixing omission and
nullrandomly for the same field across modules.
Example
Good:
{
"approvedAt": null,
"rejectionReason": null
}Less good:
{
}Consistency matters because partner verification, moderation, payouts, and bookings all include stateful workflows where “not yet set” is a meaningful business condition.
Date, Currency, and Localization Rules
Tripinger serves both international tourists and local Sri Lankan users, so APIs should treat dates, currencies, and location-sensitive fields consistently. The platform scope and traveler journeys explicitly include booking, budgeting, price comparison, and trip planning, which all depend on predictable data formatting.
Dates
- Accept and return ISO 8601 date or datetime values.
- Be explicit about whether a field is a date-only value or a datetime.
Currency
- Return monetary values in a documented numeric format.
- Include currency code alongside price fields where ambiguity exists.
- Avoid formatting prices for display in the API response.
Example:
{
"basePrice": 12500,
"currency": "LKR"
}Localization
- Keep translated display strings out of core API contracts unless a localized content domain specifically requires them.
- Return stable codes and raw values wherever possible.
Field Naming Conventions
Use camelCase consistently in JSON payloads.
Examples
Good:
createdAttotalPricepartnerIdaverageRatingcheckInDate
Avoid:
created_attotal_priceAverageRating
This helps keep DTOs, frontend models, and TypeScript contracts aligned across the monorepo.
OpenAPI and Documentation Rules
The API README explicitly recommends interactive API documentation in development and staging and cites endpoint discovery, DTO visibility, auth flow testing, partner integration support, admin tooling alignment, and future mobile use as reasons.
Documentation requirements
- Every public or client-facing endpoint should be represented in OpenAPI.
- DTOs, response shapes, auth requirements, and example payloads should be documented.
- Admin-only and partner-only routes should be clearly marked.
- Breaking changes should update docs at the same time as code changes.
- This conventions document should remain the platform-wide standard reference.
Health and Operational Endpoints
The API documentation already recommends exposing health-related endpoints and structured operational signals.
Recommended health routes
GET /api/v1/healthGET /api/v1/health/liveGET /api/v1/health/ready
Guidance
- Keep health payloads simple and automation-friendly.
- Do not expose sensitive infrastructure details in public health responses.
- Reserve deeper diagnostic information for protected internal tooling when needed.
Audit and Sensitive Action Conventions
The architecture and API docs both emphasize auditability for admin actions, payments, moderation, and privileged operations.
Rules
- Sensitive mutations should be attributable to an authenticated actor.
- Admin approvals, rejections, suspensions, moderation actions, and payout-relevant changes should be audit logged.
- Response payloads do not need to expose full audit internals, but API behavior should support traceability.
Examples of sensitive actions
- partner approval or rejection
- listing suspension
- payment-status override where allowed
- moderation hide/remove actions
- compliance review decisions
- support actions that affect user access
Example Response Patterns
Paginated list
{
"success": true,
"message": "Hotels retrieved successfully.",
"data": [
{
"id": "htl_123",
"name": "Ocean Breeze Villa",
"city": "Galle",
"averageRating": 4.7,
"currency": "LKR",
"startingPrice": 25000
}
],
"meta": {
"pagination": {
"page": 1,
"limit": 20,
"totalItems": 128,
"totalPages": 7,
"hasNextPage": true,
"hasPreviousPage": false
}
}
}Single resource
{
"success": true,
"message": "Partner profile retrieved successfully.",
"data": {
"id": "par_123",
"status": "pending_verification",
"partnerType": "vehicle_owner",
"createdAt": "2026-07-18T17:12:57Z"
}
}Validation error
{
"success": false,
"message": "Validation failed.",
"error": {
"code": "VALIDATION_ERROR",
"details": [
{
"field": "checkOut",
"message": "checkOut must be after checkIn."
}
]
},
"meta": {
"requestId": "req_abc123"
}
}Forbidden error
{
"success": false,
"message": "You do not have permission to access this resource.",
"error": {
"code": "FORBIDDEN"
},
"meta": {
"requestId": "req_abc123"
}
}Testing Expectations
The API README already identifies auth flow tests, booking lifecycle tests, partner permission tests, webhook tests, and end-to-end critical flows as Phase 1 priorities. API conventions should therefore be testable, not just descriptive.
Conventions to test
- consistent success envelope shape
- consistent error envelope shape
- pagination metadata correctness
- validation error structure
- auth failure response shape
- role/ownership failure response shape
- stable timestamp and identifier formatting
- route-level method correctness
- idempotent handling for sensitive repeated operations
Assumptions
This document uses the following planning assumptions:
- The Tripinger API remains the single shared backend contract for web, partner, and admin surfaces.
- The local API base path convention is
/api/v1. - OpenAPI or Swagger documentation will be enabled in development and staging.
- Role-based access control and resource ownership checks are already part of the API baseline.
- Search, booking, payment, partner, and admin workflows all require stable shared conventions because they are first-class platform modules.
Current Status
This document defines the planned Phase 1 API standard for Tripinger. Exact payload fields for each module will still be documented closer to implementation, but route structure, versioning, response envelopes, pagination, error handling, naming rules, and auth-aware behavior described here should be treated as the default contract pattern for all new API modules unless a documented exception is approved.