Skip to content

Njogu23/ttms-api

Repository files navigation

API Developer Guide

Version: 1.0
Base URL: https://yourdomain.com/api/v1
Format: All requests and responses use JSON.


Table of Contents

  1. Getting Started
  2. Authentication
  3. Common Operations
  4. Error Handling
  5. Best Practices

1. Getting Started

Base URL

All API endpoints are prefixed with: https://yourdomain.com/api/v1

Prerequisites

  • All endpoints (except GET /health) require authentication.
  • All requests must include the header: Content-Type: application/json Accept: application/json

Health Check

Verify the API is reachable before integrating:

GET /api/v1/health

Response 200 OK:

{ "status": "ok" }

2. Authentication

The API uses token-based authentication via Devise. Tokens are issued on login and must be sent with every subsequent request.

Sign Up

POST /api/v1/auth/signup

Request body:

{
  "user": {
    "email": "dev@example.com",
    "password": "securepassword",
    "password_confirmation": "securepassword"
  }
}

Response 201 Created:

{
  "token": "eyJhbGciOiJIUzI1NiJ9...",
  "user": {
    "id": 1,
    "email": "dev@example.com"
  }
}

Log In

POST /api/v1/auth/login

Request body:

{
  "user": {
    "email": "dev@example.com",
    "password": "securepassword"
  }
}

Response 200 OK:

{
  "token": "eyJhbGciOiJIUzI1NiJ9...",
  "user": {
    "id": 1,
    "email": "dev@example.com"
  }
}

Log Out

DELETE /api/v1/auth/logout
Authorization: Bearer <token>

Response 200 OK:

{ "message": "Logged out successfully." }

Sending the Auth Token

Include the token in the Authorization header on every authenticated request:

Authorization: Bearer eyJhbGciOiJIUzI1NiJ9...

Example with curl:

curl -X GET https://yourdomain.com/api/v1/agencies \
  -H "Authorization: Bearer <your_token>" \
  -H "Accept: application/json"

3. Common Operations

3.1 Agency Management

Note: Agency endpoints are admin-only. Non-admin requests will receive 403 Forbidden.

Get Agency Details

GET /api/v1/agencies
Authorization: Bearer <token>

Response 200 OK:

{
  "id": 1,
  "name": "Acme Travel",
  "email": "admin@acme.com"
}

Update Agency Details

PATCH /api/v1/agencies
Authorization: Bearer <token>
Content-Type: application/json

Request body:

{
  "agency": {
    "name": "Acme Travel Co.",
    "email": "newadmin@acme.com"
  }
}

Response 200 OK:

{
  "id": 1,
  "name": "Acme Travel Co.",
  "email": "newadmin@acme.com"
}

3.2 Suppliers

Suppliers are the top level of the Suppliers → Services → Rates hierarchy.

List Suppliers

GET /api/v1/suppliers
Authorization: Bearer <token>

Create a Supplier

POST /api/v1/suppliers
Authorization: Bearer <token>

Request body:

{
  "supplier": {
    "name": "Safari Camps Ltd.",
    "contact_email": "info@safaricamps.com"
  }
}

Get a Supplier

GET /api/v1/suppliers/:id
Authorization: Bearer <token>

Update a Supplier

PATCH /api/v1/suppliers/:id
Authorization: Bearer <token>

Delete a Supplier

DELETE /api/v1/suppliers/:id
Authorization: Bearer <token>

3.3 Services

Services are scoped to a parent supplier.

List Services for a Supplier

GET /api/v1/suppliers/:supplier_id/services
Authorization: Bearer <token>

Create a Service

POST /api/v1/suppliers/:supplier_id/services
Authorization: Bearer <token>

Request body:

{
  "service": {
    "name": "Game Drive",
    "description": "Full-day game drive with guide"
  }
}

Get / Update / Delete a Service

GET    /api/v1/suppliers/:supplier_id/services/:id
PATCH  /api/v1/suppliers/:supplier_id/services/:id
DELETE /api/v1/suppliers/:supplier_id/services/:id

3.4 Rates

Rates are scoped to a specific service under a supplier.

List Rates

GET /api/v1/suppliers/:supplier_id/services/:service_id/rates
Authorization: Bearer <token>

Create a Rate

POST /api/v1/suppliers/:supplier_id/services/:service_id/rates
Authorization: Bearer <token>

Request body:

{
  "rate": {
    "amount": 150.00,
    "currency": "USD",
    "valid_from": "2026-01-01",
    "valid_to": "2026-12-31"
  }
}

Get / Update / Delete a Rate

GET    /api/v1/suppliers/:supplier_id/services/:service_id/rates/:id
PATCH  /api/v1/suppliers/:supplier_id/services/:service_id/rates/:id
DELETE /api/v1/suppliers/:supplier_id/services/:service_id/rates/:id

3.5 Quotations

List Quotations

GET /api/v1/quotations
Authorization: Bearer <token>

Create a Quotation

POST /api/v1/quotations
Authorization: Bearer <token>

Request body:

{
  "quotation": {
    "title": "Kenya Safari 7 Days",
    "client_name": "John Doe",
    "start_date": "2026-07-01"
  }
}

Recalculate a Quotation

Triggers server-side repricing of all items in the quotation:

POST /api/v1/quotations/:id/recalculate
Authorization: Bearer <token>

Response 200 OK:

{
  "id": 42,
  "total": 3200.00,
  "status": "recalculated"
}

3.6 Quotation Days

Days represent individual itinerary days within a quotation.

List Days

GET /api/v1/quotations/:quotation_id/quotation_days
Authorization: Bearer <token>

Create a Day

POST /api/v1/quotations/:quotation_id/quotation_days
Authorization: Bearer <token>

Request body:

{
  "quotation_day": {
    "date": "2026-07-01",
    "label": "Arrival & Transfer"
  }
}

3.7 Quotation Items

Items are individual services or line entries within a quotation day.

List Items for a Day

GET /api/v1/quotations/:quotation_id/quotation_days/:quotation_day_id/quotation_items
Authorization: Bearer <token>

Create an Item

POST /api/v1/quotations/:quotation_id/quotation_days/:quotation_day_id/quotation_items
Authorization: Bearer <token>

Request body:

{
  "quotation_item": {
    "service_id": 5,
    "rate_id": 12,
    "quantity": 2,
    "notes": "Airport pickup for 2 pax"
  }
}

4. Error Handling

All errors return a JSON body with a consistent structure. Use the HTTP status code as the primary signal and the body for debugging detail.

Error Response Shapes

400 Bad Request

Malformed request syntax or missing required parameters.

{ "error": "param is missing or the value is empty: quotation" }

401 Unauthorized

Missing or invalid authentication token.

{ "error": "You need to sign in or sign up before continuing." }

403 Forbidden

Authenticated but not permitted for this action.

{ "error": "You are not authorized to perform this action" }

404 Not Found

The requested resource does not exist (or does not belong to your agency).

{ "error": "Couldn't find Supplier with 'id'=999" }

422 Unprocessable Entity

Validation failed. The errors array contains human-readable messages per field.

{
  "errors": [
    "Name can't be blank",
    "Amount must be greater than 0"
  ]
}

500 Internal Server Error

An unexpected server-side failure. Retry with exponential backoff; if the issue persists, contact support with the request ID if provided.


Troubleshooting Reference

Symptom Likely cause Fix
401 on every request Token missing or expired Re-authenticate via POST /auth/login
403 on agency endpoints User is not an admin Use an admin account
404 on nested routes Wrong parent ID Verify :supplier_id / :quotation_id belongs to your agency
422 on create/update Validation failure Read errors array and correct the payload
500 intermittently Transient server error Retry with backoff (see Best Practices)

5. Best Practices

Authentication

  • Store tokens in memory or a secure store — never in localStorage in browser environments.
  • Refresh tokens proactively: detect 401 responses and re-authenticate before retrying the original request.
  • Log out explicitly when a session ends to invalidate the server-side token.

Request Construction

  • Always send Content-Type: application/json and Accept: application/json.
  • Wrap request bodies in the resource key (e.g., { "supplier": { ... } }) to match Rails strong-parameters conventions.
  • Validate nested IDs before building deep URLs (/suppliers/:supplier_id/services/:service_id/rates).

Pagination

The API does not currently document pagination headers — default to requesting resources and implementing client-side limits. Monitor response sizes and coordinate with the backend team as data volumes grow.

Idempotency

  • GET, PATCH, and DELETE are safe to retry on network failure.
  • POST is not idempotent. Guard against duplicate submissions (e.g., disable the submit button after the first click, or check for an existing record before creating).

Retries & Backoff

For 5xx errors or network timeouts, use truncated exponential backoff: delay = min(base * 2^attempt + jitter, max_delay)

Example values: base = 500ms, max_delay = 10s, max_attempts = 4.

Do not retry 4xx errors — they indicate client-side issues that a retry will not resolve.

Scoping & Multi-tenancy

All data is scoped to the agency of the authenticated user. You will never see or be able to modify another agency's resources; a missing record returns 404, not a data leak.

Versioning

The current API version is v1, reflected in the base path /api/v1/. Future breaking changes will be introduced under /api/v2/ with an advance deprecation notice. Pin your integrations to a specific version path to avoid unexpected breakage.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors