API Documentation

This document provides comprehensive documentation for frontend developers integrating with the Morpheus API. It mirrors the exact behavior of the server.


Table of Contents

  1. Getting Started
  2. Authentication
  3. Error Handling
  4. Endpoints

Getting Started

Base URL

http://localhost:8000/api/v1

Authentication

Most endpoints require a Bearer token:

Authorization: Bearer <access_token>

Authentication

Overview

  • Access Token: Expires in 15 minutes.
  • Refresh Token: Expires in 7 days.
  • Email Verification: Required before creating a user.

Error Handling

Standard Error Response

All API errors follow a consistent JSON structure. The HTTP status code of the response will match the statusCode field in the body.

{
  "success": false,
  "statusCode": 404,
  "message": "Resource not found!!",
  "data": null,
  "requestInfo": {
    "url": "/api/v1/unknown-route",
    "method": "GET",
    "ip": "::1"
  }
}

Validation Errors (400)

When request data fails validation (e.g., invalid email), the response includes an errors array detailing the issues.

{
  "success": false,
  "statusCode": 400,
  "message": "Validation failed",
  "errors": [
    {
      "field": "email",
      "message": "Invalid email format"
    }
  ],
  "requestInfo": {
    "url": "/api/v1/auth/register",
    "method": "POST",
    "ip": "::1"
  }
}

Common Error Scenarios & Resolutions

400 Bad Request

Scenario: The client sent invalid data (e.g., missing fields, wrong data types, malformed JSON). Recommended Frontend Action:

  • Do not retry the request exactly as is.
  • Display the specific error message from the errors array near the relevant form field (e.g., "Email is invalid").
  • Check the browser console to ensure the JSON payload matches the documentation.

Response Example:

{
  "success": false,
  "statusCode": 400,
  "message": "Validation failed",
  "errors": [
    {
      "field": "email",
      "message": "Invalid email format"
    }
  ],
  "requestInfo": {
    "url": "/api/v1/auth/register",
    "method": "POST",
    "ip": "::1"
  }
}

401 Unauthorized

Scenario: The user is not logged in, the token has expired, or the token is invalid. Recommended Frontend Action:

  • If the message says "Token expired", attempt to use the Refresh Token endpoint to get a new Access Token.
  • If refresh fails or simpler auth is used, redirect the user to the Login page immediately.
  • Clear any stored local session data to prevent UI inconsistencies.

Response Example:

{
  "success": false,
  "statusCode": 401,
  "message": "Token expired",
  "data": null,
  "requestInfo": {
    "url": "/api/v1/customers/me",
    "method": "GET",
    "ip": "::1"
  }
}

403 Forbidden

Scenario: The user is logged in but does not have permission to access this specific resource. Recommended Frontend Action:

  • Show a "Permission Denied" UI or toast notification.
  • Do not redirect to login; the user is authenticated.
  • If appropriate, hide the button or link that triggered this action in the future based on the user's role.

Response Example:

{
  "success": false,
  "statusCode": 403,
  "message": "You do not have permission to access this resource",
  "data": null,
  "requestInfo": {
    "url": "/api/v1/admin/customers",
    "method": "GET",
    "ip": "::1"
  }
}

404 Not Found

Scenario: The requested resource (ID) does not exist or the URL is incorrect. Recommended Frontend Action:

  • Show a "Not Found" state (e.g., empty state or 404 page).
  • Verify the ID being passed in the URL.
  • If this happens on a list detail page, redirect the user back to the list view.

Response Example:

{
  "success": false,
  "statusCode": 404,
  "message": "Agent with ID 123 does not exist",
  "data": null,
  "requestInfo": {
    "url": "/api/v1/agents/123",
    "method": "GET",
    "ip": "::1"
  }
}

500 Internal Server Error

Scenario: An unexpected error occurred on the server (e.g., database connection failed, unhandled exception). Recommended Frontend Action:

  • Show a generic "Something went wrong" error message to the user.
  • Contact the Backend Developer immediately. Provide them with the requestInfo from the response and the exact time of the error.
  • Optionally, implement a retry mechanism with exponential backoff if the error seems transient (like a network blip), but persistent 500s require code fixes.

Response Example:

{
  "success": false,
  "statusCode": 500,
  "message": "Internal server error!!",
  "data": null,
  "requestInfo": {
    "url": "/api/v1/users",
    "method": "POST",
    "ip": "::1"
  }
}

Endpoints

Health

GET /health

Description: This endpoint performs a comprehensive health check of the entire system. It is necessary for load balancers, uptime monitors, and administrators to verify that the API server is reachable and functioning correctly. Internally, the server calculates its uptime, captures current memory usage (RSS, Heap), and executes a lightweight SELECT 1 query against the PostgreSQL database to verify connectivity. It also gathers system-level metrics like load average and platform information. This ensures that a response of 200 OK truly means the system is operational.

cURL Request:

curl -X GET http://localhost:8000/api/v1/health \
  -H "Content-Type: application/json"

Response (200 OK):

{
  "success": true,
  "status": 200,
  "message": "System status retrieved",
  "data": {
    "status": "healthy",
    "uptime": "2d 4h 12m 30s",
    "timestamp": "2026-02-05T21:30:00.000Z",
    "database": "connected",
    "memory": {
      "rss": "50.5 MB",
      "heapTotal": "30.1 MB",
      "heapUsed": "15.2 MB"
    },
    "system": {
      "platform": "linux",
      "nodeVersion": "v20.10.0",
      "pid": 1234,
      "loadAvg": [0.52, 0.35, 0.12]
    }
  },
  "requestInfo": {
    "url": "/api/v1/health",
    "ip": "::1",
    "method": "GET"
  }
}

Auth

POST /auth/register/request-verification

Description: This endpoint initiates the registration process by verifying the user's email address first. It is necessary to prevent spam registrations and ensure the email belongs to the user before creating any account data. Internally, the endpoint first validates the email format using Zod schemas. It checks the database to ensure the email is not already registered. If valid, it generates a cryptographically signed JWT containing the email and a 24-hour expiration claim. This token is then emailed to the user as a magic link, completely stateless until the user clicks it.

cURL Request:

curl -X POST http://localhost:8000/api/v1/auth/register/request-verification \
  -H "Content-Type: application/json" \
  -d '{
    "email": "user@example.com"
  }'

Response (200 OK):

{
  "success": true,
  "status": 200,
  "message": "Verification email sent. Please check your inbox.",
  "data": {
    "verification": {
      "email": "user@example.com",
      "expiresIn": "24 hours"
    }
  },
  "requestInfo": {
    "url": "/api/v1/auth/register/request-verification",
    "ip": "::1",
    "method": "POST"
  }
}

POST /auth/register/complete

Description: This endpoint finalizes the user registration after they have clicked the email verification link. It is necessary to securely create the user account only after email ownership is proven. Internally, it verifies the JWT token signature to extract the email. It checks for race conditions (e.g., if the email was registered by someone else in the interim). It then hashes the provided password using bcrypt for security. Finally, it creates the user record in the database with emailVerified: true and immediately issues an Access Token and Refresh Token, logging the user in automatically.

cURL Request:

curl -X POST http://localhost:8000/api/v1/auth/register/complete \
  -H "Content-Type: application/json" \
  -d '{
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "name": "Jane User",
    "password": "SecurePassword123!"
  }'

Response (201 Created):

{
  "success": true,
  "status": 201,
  "message": "Registration completed successfully",
  "data": {
    "user": {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "email": "user@example.com",
      "name": "Jane User",
      "customerId": null,
      "role": "member",
      "status": "active",
      "provider": "local",
      "providerId": null,
      "emailVerified": true,
      "lastLoginAt": null,
      "needsOnboarding": true,
      "tokens": {
        "accessToken": "eyJhbGciOiJIUzI1Ni...",
        "refreshToken": "d290f1ee-6c54-4b01-90e6-d701748f0851"
      },
      "createdAt": "2026-02-05T21:30:00.000Z",
      "updatedAt": "2026-02-05T21:30:00.000Z",
      "deletedAt": null
    }
  },
  "requestInfo": {
    "url": "/api/v1/auth/register/complete",
    "ip": "::1",
    "method": "POST"
  }
}

POST /auth/login

Description: This endpoint authenticates existing users using their email and password. It is necessary to grant secure access to protected resources within the application. Internally, it retrieves the user record by email. It then compares the provided password against the stored bcrypt hash. If they match, a new pair of JWT tokens (Access and Refresh) is generated. The Refresh token is hashed and stored in the database for session management, while the unhashed versions are returned to the client. The user's lastLoginAt timestamp is also updated.

cURL Request:

curl -X POST http://localhost:8000/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "user@example.com",
    "password": "SecurePassword123!"
  }'

Response (200 OK):

{
  "success": true,
  "status": 200,
  "message": "Login successful",
  "data": {
    "auth": {
      "user": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "email": "user@example.com",
        "name": "Jane User",
        "customerId": "880e8400-e29b-41d4-a716-446655440000",
        "role": "owner",
        "status": "active",
        "provider": "local",
        "emailVerified": true,
        "needsOnboarding": false,
        "createdAt": "2026-02-05T21:30:00.000Z",
        "updatedAt": "2026-02-05T21:30:00.000Z"
      },
      "tokens": {
        "accessToken": "eyJhbGciOiJIUzI1Ni...",
        "refreshToken": "d290f1ee-6c54-4b01-90e6-d701748f0851"
      }
    }
  },
  "requestInfo": {
    "url": "/api/v1/auth/login",
    "ip": "::1",
    "method": "POST"
  }
}

POST /auth/refresh

Description: This endpoint issues a new short-lived Access Token using a valid long-lived Refresh Token. It is necessary to maintain the user's session without forcing them to re-enter credentials every 15 minutes. Internally, it first verifies the Refresh Token's signature. Then, it checks the database to confirm the token exists and hasn't been revoked. It also validates that the token hasn't expired. If all checks pass, it generates a fresh Access Token and a new Refresh Token (rotating the token family) and returns them to the client.

cURL Request:

curl -X POST http://localhost:8000/api/v1/auth/refresh \
  -H "Content-Type: application/json" \
  -d '{
    "refreshToken": "d290f1ee-6c54-4b01-90e6-d701748f0851"
  }'

Response (200 OK):

{
  "success": true,
  "status": 200,
  "message": "Token refreshed successfully",
  "data": {
    "tokens": {
      "accessToken": "eyJhbGciOiJIUzI1Ni...",
      "refreshToken": "new-refresh-token-uuid"
    }
  },
  "requestInfo": {
    "url": "/api/v1/auth/refresh",
    "ip": "::1",
    "method": "POST"
  }
}

GET /auth/profile

Description: This endpoint returns the current authenticated user's profile information. It is necessary for the frontend to display user details and manage permissions based on the user's role and customer association. Internally, the middleware first validates the Access Token in the header. The controller then extracts the userId from the token payload and queries the database for the user's full record, including their customer details. It strips out sensitive fields (like passwords) before returning the clean data object.

cURL Request:

curl -X GET http://localhost:8000/api/v1/auth/profile \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json"

Response (200 OK):

{
  "success": true,
  "status": 200,
  "message": "Profile retrieved successfully",
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "user@example.com",
    "name": "Jane User",
    "customerId": "880e8400-e29b-41d4-a716-446655440000",
    "role": "owner",
    "status": "active",
    "provider": "local",
    "providerId": null,
    "emailVerified": true,
    "lastLoginAt": "2026-02-05T21:35:00.000Z",
    "createdAt": "2026-02-05T21:30:00.000Z",
    "updatedAt": "2026-02-05T21:30:00.000Z",
    "deletedAt": null
  },
  "requestInfo": {
    "url": "/api/v1/auth/profile",
    "ip": "::1",
    "method": "GET"
  }
}

Customers

POST /customers/onboard

Description: This endpoint completes the onboarding process by creating an organization (Customer) for a newly registered user. It is necessary because users must belong to a Customer entity to access most platform features. Internally, it accepts company details like name and phone number. It wraps the operations in a transaction: first creating the new Customer record, then linking the current User to this Customer as the 'owner', and finally updating the User's status to remove the needsOnboarding flag. This atomic operation ensures data integrity.

cURL Request:

curl -X POST http://localhost:8000/api/v1/customers/onboard \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json" \
  -d '{
    "companyName": "Tech Corp",
    "phone": "+1234567890",
    "description": "AI Lab"
  }'

Response (201 Created):

{
  "success": true,
  "status": 201,
  "message": "Customer onboarded successfully",
  "data": {
    "customer": {
      "id": "880e8400-e29b-41d4-a716-446655440000",
      "companyName": "Tech Corp",
      "phone": "+1234567890",
      "description": "AI Lab",
      "status": "active",
      "avatar": null,
      "settings": {},
      "allowedIps": null,
      "createdBy": "550e8400-e29b-41d4-a716-446655440000",
      "createdAt": "2026-02-05T21:40:00.000Z",
      "updatedAt": "2026-02-05T21:40:00.000Z",
      "deletedAt": null
    },
    "user": {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "customerId": "880e8400-e29b-41d4-a716-446655440000",
      "role": "owner"
    }
  },
  "requestInfo": {
    "url": "/api/v1/customers/onboard",
    "ip": "::1",
    "method": "POST"
  }
}

GET /customers/me

Description: This endpoint retrieves the organization details associated with the current user. It is necessary for displaying company settings and information in the dashboard. Internally, it strictly enforces that the user must already have a customerId. It performs a lookup on the Customers table using this ID. The response includes the company profile, settings JSON, and status. It does not return sensitive platform-level metadata unless the user has specific administrative privileges.

cURL Request:

curl -X GET http://localhost:8000/api/v1/customers/me \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json"

Response (200 OK):

{
  "success": true,
  "status": 200,
  "message": "Customer details retrieved",
  "data": {
    "id": "880e8400-e29b-41d4-a716-446655440000",
    "companyName": "Tech Corp",
    "phone": "+1234567890",
    "description": "AI Lab",
    "status": "active",
    "avatar": "https://example.com/logo.png",
    "settings": {
      "theme": "dark"
    },
    "allowedIps": [],
    "createdBy": "550e8400-e29b-41d4-a716-446655440000",
    "createdAt": "2026-02-05T21:40:00.000Z",
    "updatedAt": "2026-02-05T21:40:00.000Z",
    "deletedAt": null
  },
  "requestInfo": {
    "url": "/api/v1/customers/me",
    "ip": "::1",
    "method": "GET"
  }
}

PATCH /customers/me

Description: This endpoint allows authorized users (Owners/Admins) to update their organization's details. It is necessary for managing company branding and contact information. Internally, it validates the payload against partial schemas (allowing updates to single fields like companyName or settings). It checks the user's role to ensure they have permission to modify organizational data. It then executes an SQL UPDATE query on the specific fields provided, updates the updatedAt timestamp, and returns the fresh customer object.

cURL Request:

curl -X PATCH http://localhost:8000/api/v1/customers/me \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json" \
  -d '{
    "companyName": "Updated Corp"
  }'

Response (200 OK):

{
  "success": true,
  "status": 200,
  "message": "Customer details updated",
  "data": {
    "id": "880e8400-e29b-41d4-a716-446655440000",
    "companyName": "Updated Corp",
    "phone": "+1234567890",
    "description": "AI Lab",
    "status": "active",
    "avatar": null,
    "settings": {},
    "allowedIps": [],
    "createdBy": "550e8400-e29b-41d4-a716-446655440000",
    "createdAt": "2026-02-05T21:40:00.000Z",
    "updatedAt": "2026-02-05T21:45:00.000Z",
    "deletedAt": null
  },
  "requestInfo": {
    "url": "/api/v1/customers/me",
    "ip": "::1",
    "method": "PATCH"
  }
}

Users

GET /users

Description: This endpoint lists all users belonging to the current user's customer organization. It is necessary for team management and viewing member roles. Internally, it scopes the query strictly to the authenticated user's customerId to ensure data isolation (multi-tenancy). It supports pagination via query parameters (page, limit). It counts the total number of matching records and retrieves the specific slice of data, returning both the user list and the pagination metadata.

cURL Request:

curl -X GET "http://localhost:8000/api/v1/users?page=1&limit=10" \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json"

Response (200 OK):

{
  "success": true,
  "status": 200,
  "message": "Users retrieved successfully",
  "data": {
    "users": [
      {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "Jane User",
        "email": "user@example.com",
        "role": "owner",
        "status": "active",
        "lastLoginAt": "2026-02-05T21:35:00.000Z",
        "createdAt": "2026-02-05T21:30:00.000Z"
      },
      {
        "id": "660e8400-e29b-41d4-a716-446655440001",
        "name": "Bob Member",
        "email": "bob@example.com",
        "role": "member",
        "status": "invited",
        "lastLoginAt": null,
        "createdAt": "2026-02-05T21:50:00.000Z"
      }
    ],
    "pagination": {
      "page": 1,
      "limit": 10,
      "total": 2,
      "totalPages": 1
    }
  },
  "requestInfo": {
    "url": "/api/v1/users",
    "ip": "::1",
    "method": "GET"
  }
}

POST /users

Description: This endpoint invites a new user to join the organization. It is necessary for expanding the team and granting access to colleagues. Internally, it creates a new user record with a status of invited and links it to the current customerId. It sets a temporary password or invites them to set one. It typically triggers an invitation email (though explicit email logic may vary). The new user is immediately visible in the member list but cannot login until they accept the invite or verify their email.

cURL Request:

curl -X POST http://localhost:8000/api/v1/users \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "colleague@tech.com",
    "role": "member",
    "name": "Bob"
  }'

Response (201 Created):

{
  "success": true,
  "status": 201,
  "message": "User invited successfully",
  "data": {
    "id": "770e8400-e29b-41d4-a716-446655440002",
    "email": "colleague@tech.com",
    "name": "Bob",
    "customerId": "880e8400-e29b-41d4-a716-446655440000",
    "role": "member",
    "status": "invited",
    "provider": "local",
    "emailVerified": false,
    "createdAt": "2026-02-05T21:55:00.000Z",
    "updatedAt": "2026-02-05T21:55:00.000Z"
  },
  "requestInfo": {
    "url": "/api/v1/users",
    "ip": "::1",
    "method": "POST"
  }
}

PATCH /users/:id

Description: This endpoint modifies the role of an existing team member. It is necessary for promoting members to admins or owners, or demoting them. Internally, it verifies that the requester has a higher or equal role (typically Owner) to perform this action. It updates the role column in the database for the specified userId, ensuring the user belongs to the same customer. This change takes effect immediately for future requests, though active sessions might persist until token refresh.

cURL Request:

curl -X PATCH http://localhost:8000/api/v1/users/770e8400-e29b-41d4-a716-446655440002 \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json" \
  -d '{
    "role": "admin"
  }'

Response (200 OK):

{
  "success": true,
  "status": 200,
  "message": "User role updated successfully",
  "data": {
    "id": "770e8400-e29b-41d4-a716-446655440002",
    "role": "admin",
    "email": "colleague@tech.com",
    "updatedAt": "2026-02-05T22:00:00.000Z"
  },
  "requestInfo": {
    "url": "/api/v1/users/770e8400-e29b-41d4-a716-446655440002",
    "ip": "::1",
    "method": "PATCH"
  }
}

DELETE /users/:id

Description: This endpoint removes a user from the organization. It is necessary for offboarding employees or removing incorrect invites. Internally, it performs a soft delete by setting the deletedAt timestamp (or hard delete if configured). It ensures the user being removed belongs to the requester's customer. The user's access tokens are not immediately revoked but will fail verification on the next refresh/api call check if deletedAt is respected in the auth middleware.

cURL Request:

curl -X DELETE http://localhost:8000/api/v1/users/770e8400-e29b-41d4-a716-446655440002 \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json"

Response (200 OK):

{
  "success": true,
  "status": 200,
  "message": "User removed successfully",
  "data": {
    "message": "User removed successfully"
  },
  "requestInfo": {
    "url": "/api/v1/users/770e8400-e29b-41d4-a716-446655440002",
    "ip": "::1",
    "method": "DELETE"
  }
}

Agents

GET /agents

Description: This endpoint lists all AI Voice Agents configured for the customer. It is necessary for the dashboard to display available agents for editing or assignment. Internally, it accepts pagination parameters and filters by customerId. It joins related provider tables (LLM, TTS, STT) to potentially return provider names (though primarily returns IDs). It formats the response to include the agent's current status (active/draft) and configuration details.

cURL Request:

curl -X GET "http://localhost:8000/api/v1/agents?page=1&limit=10" \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json"

Response (200 OK):

{
  "success": true,
  "status": 200,
  "message": "Agents retrieved successfully",
  "data": {
    "agents": [
      {
        "id": 1,
        "name": "Sales Bot",
        "description": "Handles inbound sales calls",
        "voiceId": "alloy",
        "status": "active",
        "createdAt": "2026-02-05T10:00:00.000Z"
      }
    ],
    "pagination": {
      "page": 1,
      "limit": 10,
      "total": 1,
      "totalPages": 1
    }
  },
  "requestInfo": {
    "url": "/api/v1/agents",
    "ip": "::1",
    "method": "GET"
  }
}

POST /agents

Description: This endpoint creates a new AI Voice Agent configuration. It is necessary to define how the AI behaves, which voice it uses, and which underlying models (LLM, STT, TTS) drive it. Internally, it validates complex configuration objects including the systemPrompt, voice settings, and provider IDs. It verifies that the referenced providers exist. It then inserts the record into the agents table, setting the initial status to draft. This agent ID can then be assigned to phone numbers.

cURL Request:

curl -X POST http://localhost:8000/api/v1/agents \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Support Bot",
    "voiceId": "echo",
    "systemPrompt": "You are a helpful assistant.",
    "llmProviderId": 1,
    "ttsProviderId": 1,
    "sttProviderId": 1
  }'

Response (201 Created):

{
  "success": true,
  "status": 201,
  "message": "Agent created successfully",
  "data": {
    "id": 2,
    "name": "Support Bot",
    "voiceId": "echo",
    "systemPrompt": "You are a helpful assistant.",
    "status": "draft",
    "customerId": "880e8400-e29b-41d4-a716-446655440000",
    "createdAt": "2026-02-05T22:05:00.000Z",
    "updatedAt": "2026-02-05T22:05:00.000Z"
  },
  "requestInfo": {
    "url": "/api/v1/agents",
    "ip": "::1",
    "method": "POST"
  }
}

PATCH /agents/:id

Description: This endpoint updates an existing agent's configuration. It is necessary for iterating on prompts, changing voices, or tweaking settings based on call performance. Internally, it accepts a partial payload. It checks that the agent belongs to the current customer. It parses the updates (which may include complex JSON objects for transfers or functions) and applies them to the database. It updates the updatedAt timestamp to track modification time.

cURL Request:

curl -X PATCH http://localhost:8000/api/v1/agents/2 \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Advanced Support Bot"
  }'

Response (200 OK):

{
  "success": true,
  "status": 200,
  "message": "Agent updated successfully",
  "data": {
    "id": 2,
    "name": "Advanced Support Bot",
    "updatedAt": "2026-02-05T22:10:00.000Z"
  },
  "requestInfo": {
    "url": "/api/v1/agents/2",
    "ip": "::1",
    "method": "PATCH"
  }
}

Phone Numbers

GET /phone-numbers

Description: This endpoint retrieves all phone numbers owned by the customer. It is necessary for managing inventory, assigning agents to numbers, and viewing routing configuration. Internally, it queries the phone numbers table filtering by customerId. It includes details such as the number itself, its capabilities (voice/sms), and the currently assigned agentId. This view allows the frontend to show which numbers are active and handling calls.

cURL Request:

curl -X GET "http://localhost:8000/api/v1/phone-numbers?page=1&limit=10" \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json"

Response (200 OK):

{
  "success": true,
  "status": 200,
  "message": "Phone numbers retrieved successfully",
  "data": {
    "phoneNumbers": [
      {
        "id": 1,
        "phoneNumber": "+15550001234",
        "friendlyName": "Main Line",
        "country": "US",
        "agentId": null,
        "createdAt": "2026-02-05T10:00:00.000Z"
      }
    ],
    "pagination": {
      "page": 1,
      "limit": 10,
      "total": 1,
      "totalPages": 1
    }
  },
  "requestInfo": {
    "url": "/api/v1/phone-numbers",
    "ip": "::1",
    "method": "GET"
  }
}

POST /phone-numbers

Description: This endpoint allows manual addition of phone numbers to the customer's inventory. It is typically used for BYO (Bring Your Own) carrier setups where the number is purchased externally. Internally, it validates the E.164 format of the phone number. It creates a record in the database linked to the customer. It does NOT purchase the number from an upstream provider (Twilio/Telnyx) automatically in this version; it assumes the number is already routed to the platform's SIP URI or webhook.

cURL Request:

curl -X POST http://localhost:8000/api/v1/phone-numbers \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json" \
  -d '{
    "phoneNumber": "+15559998888",
    "friendlyName": "Support Line",
    "country": "US"
  }'

Response (201 Created):

{
  "success": true,
  "status": 201,
  "message": "Phone number added successfully",
  "data": {
    "id": 2,
    "phoneNumber": "+15559998888",
    "friendlyName": "Support Line",
    "createdAt": "2026-02-05T22:15:00.000Z"
  },
  "requestInfo": {
    "url": "/api/v1/phone-numbers",
    "ip": "::1",
    "method": "POST"
  }
}

Voice / Calls

GET /calls

Description: This endpoint lists the history of all voice calls processed for the customer. It is necessary for reporting, billing verification, and listening to call logs. Internally, it fetches call records from the calls table, filtered by customerId. It supports pagination. Each record includes the call duration, status (completed/failed), start/end times, and the agentId that handled the call. It provides a historical audit trail of voice interactions.

cURL Request:

curl -X GET "http://localhost:8000/api/v1/calls?page=1&limit=10" \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json"

Response (200 OK):

{
  "success": true,
  "status": 200,
  "message": "Calls retrieved successfully",
  "data": {
    "calls": [
      {
        "id": 101,
        "agentId": 1,
        "phoneNumberId": 1,
        "status": "completed",
        "duration": 120,
        "recordingUrl": "https://storage.example.com/rec-101.mp3",
        "startedAt": "2026-02-05T21:00:00.000Z",
        "endedAt": "2026-02-05T21:02:00.000Z"
      }
    ],
    "pagination": {
      "page": 1,
      "limit": 10,
      "total": 1,
      "totalPages": 1
    }
  },
  "requestInfo": {
    "url": "/api/v1/calls",
    "ip": "::1",
    "method": "GET"
  }
}

GET /calls/:id

Description: This endpoint retrieves detailed information for a specific call session. It is necessary for inspecting individual call metrics, potential errors, or accessing the transcript. Internally, it verifies ownership of the call ID. It joins data from the calls table and potentially the call_logs table (for transcripts, though sometimes separate). It returns the full context of the session, including metadata passed during the call setup.

cURL Request:

curl -X GET http://localhost:8000/api/v1/calls/101 \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json"

Response (200 OK):

{
  "success": true,
  "status": 200,
  "message": "Call retrieved successfully",
  "data": {
    "id": 101,
    "agentId": 1,
    "status": "completed",
    "duration": 120,
    "transcript": [
      { "role": "assistant", "content": "Hello!" },
      { "role": "user", "content": "Hi there." }
    ],
    "startedAt": "2026-02-05T21:00:00.000Z",
    "endedAt": "2026-02-05T21:02:00.000Z"
  },
  "requestInfo": {
    "url": "/api/v1/calls/101",
    "ip": "::1",
    "method": "GET"
  }
}

POST /calls/:id/end

Description: This endpoint manually terminates an active call. It is necessary for agents or admins to force-close a stuck connection or end a call from the dashboard console. Internally, it signals the Voice Pipeline service to shut down the LiveKit room and disconnect the SIP trunk. It updates the call status in the database to completed (or terminated), sets the endedAt timestamp, and calculates the final duration. It ensures resources are properly released.

cURL Request:

curl -X POST http://localhost:8000/api/v1/calls/101/end \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json"

Response (200 OK):

{
  "success": true,
  "status": 200,
  "message": "Call ended successfully",
  "data": {
    "id": 101,
    "status": "completed",
    "endedAt": "2026-02-05T21:02:00.000Z"
  },
  "requestInfo": {
    "url": "/api/v1/calls/101/end",
    "ip": "::1",
    "method": "POST"
  }
}

POST /calls/:id/join-agent

Description: This endpoint connects the AI agent to an active call session. It is typically called by the webhook handler when a call is answered, or manually to bridge the AI into a conference. Internally, it initializes the VoicePipelineService. It connects the STT, LLM, and TTS providers to the LiveKit room associated with the call ID. It establishes the audio streams so the AI can hear and speak. It sets the pipeline status to active and begins the conversation flow (e.g., executing the initial greeting).

cURL Request:

curl -X POST http://localhost:8000/api/v1/calls/101/join-agent \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json"

Response (200 OK):

{
  "success": true,
  "status": 200,
  "message": "Agent joined call successfully",
  "data": {
    "pipelineStatus": "connected",
    "agentId": 1,
    "connectedAt": "2026-02-05T21:00:05.000Z"
  },
  "requestInfo": {
    "url": "/api/v1/calls/101/join-agent",
    "ip": "::1",
    "method": "POST"
  }
}

Call Simulation

POST /calls/simulate

Description: This endpoint starts a simulated voice call session. It is necessary for testing agent behavior and prompts without placing a real phone call. Internally, it creates a LiveKit room but marks it as a simulation. It does not connect to a SIP trunk. Instead, it expects audio or text messages to be sent via the simulation API or a specific frontend test harness. It allows developers to debug the AI's logic loop in a controlled environment.

cURL Request:

curl -X POST http://localhost:8000/api/v1/calls/simulate \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json"

Response (200 OK):

{
  "success": true,
  "status": 200,
  "message": "Simulation started",
  "data": {
    "callId": 999,
    "roomName": "sim-room-123",
    "token": "eyJ...",
    "status": "active"
  },
  "requestInfo": {
    "url": "/api/v1/calls/simulate",
    "ip": "::1",
    "method": "POST"
  }
}

8. Telephony (SIP/Carrier)

Inbound Call Webhook

POST /api/v1/webhooks/voice/inbound

Handles incoming calls from carriers like Twilio/Telnyx. Access: Public (No Auth Required, but should be IP whitelisted in production)

Body:

{
  "From": "+15550009999",
  "To": "+15551234567"
}

Response: (200 OK)

{
  "action": "connect",
  "roomName": "call_1234567...",
  "agentId": 1
}

Campaigns

Coming Soon: Campaign management and auto-dialing features.

Analytics

Coming Soon: Advanced analytics and dashboards.


Admin Portal

GET /admin/customers

Description: This endpoint is restricted to Platform Admins. It lists all tenants (Customers) on the platform. It is necessary for the super-admin to oversee platform usage, billing, and growth. Internally, it uses the requireRole(['platform_admin']) middleware to enforce strict security. It ignores the requester's own customerId and instead fetches records associated with ALL customers. It provides a global view of the system's tenant base.

cURL Request:

curl -X GET "http://localhost:8000/api/v1/admin/customers?page=1&limit=10" \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json"

Response (200 OK):

{
  "success": true,
  "status": 200,
  "message": "Customers retrieved successfully",
  "data": {
    "customers": [
      {
        "id": "880e8400-e29b-41d4-a716-446655440000",
        "companyName": "Tech Corp",
        "status": "active",
        "createdAt": "2026-02-05T21:40:00.000Z"
      }
    ],
    "pagination": {
      "page": 1,
      "limit": 10,
      "total": 1,
      "totalPages": 1
    }
  },
  "requestInfo": {
    "url": "/api/v1/admin/customers",
    "ip": "::1",
    "method": "GET"
  }
}

GET /admin/system/health

Description: This endpoint provides a deep inspection of system health for Platform Admins. It is necessary for debugging and infrastructure monitoring at a higher privilege level than the public health check. Internally, it may expose detailed metrics that are hidden from the public /health endpoint, such as database pool statistics, detailed memory breakdowns, and specific service connectivity statuses. It serves as a diagnostic tool for the platform maintainer.

cURL Request:

curl -X GET http://localhost:8000/api/v1/admin/system/health \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json"

Response (200 OK):

{
  "success": true,
  "status": 200,
  "message": "System health check passed",
  "data": {
    "health": {
      "status": "healthy",
      "database": "connected",
      "timestamp": "2026-02-05T22:20:00.000Z"
    }
  },
  "requestInfo": {
    "url": "/api/v1/admin/system/health",
    "ip": "::1",
    "method": "GET"
  }
}