Aller au contenu

Textos API Documentation

This document describes the Textos REST API. All endpoints are prefixed with /api/v1 unless otherwise noted.

Authentication

The API uses JWT (JSON Web Token) for authentication. Include the access token in the Authorization header:

Authorization: Bearer <access_token>

Obtaining Tokens

Login

POST /api/v1/auth/login

Request:

{
  "email": "user@example.com",
  "password": "your-password"
}

Response:

{
  "user": { ... },
  "access_token": "eyJ...",
  "refresh_token": "eyJ..."
}

Refresh Token

POST /api/v1/auth/refresh
Authorization: Bearer <refresh_token>

Response:

{
  "access_token": "eyJ..."
}

Using API Keys

For programmatic access, you can use API keys instead of JWT tokens. Include the API key in the X-API-Key header:

X-API-Key: your-api-key

Note: API keys inherit the permissions of the user who created them. When using API keys, you may need to specify the organization_id parameter on certain endpoints (like /teams) since there is no interactive session to track the current organization.


Authentication Endpoints

Register with Invitation

POST /api/v1/auth/register

Register a new user using an invitation token.

Request:

{
  "token": "invitation-token",
  "password": "secure-password",
  "name": "John Doe",
  "language": "fr"
}

Get Current User

GET /api/v1/auth/me

Returns the authenticated user's profile.

Update Current User

PATCH /api/v1/auth/me

Request:

{
  "name": "New Name",
  "language": "en",
  "password": "new-password",
  "default_organization_id": "org-id-here"
}

Note: The default_organization_id parameter sets the user's default organization. When the user accesses a domain, if their default organization belongs to that domain, they will be automatically switched to it.

User Object:

{
  "id": "user-id",
  "email": "user@example.com",
  "name": "John Doe",
  "role": "admin",
  "organization_id": "org-id",
  "team_id": "team-id",
  "language": "fr",
  "oauth_provider": null,
  "is_active": true,
  "created_at": "2024-01-15T10:30:00Z",
  "last_login": "2024-01-15T10:30:00Z",
  "default_organization_id": "org-id"
}

Field Type Description
id string Identifiant unique de l'utilisateur
email string Adresse email de l'utilisateur
name string Nom d'affichage
role string Rôle: super_admin, domain_admin, admin, manager, agent
organization_id string ID de l'organisation courante
team_id string ID de l'équipe courante (si assigné)
language string Langue préférée: fr, en
oauth_provider string Fournisseur OAuth si SSO: google, microsoft, apple
is_active boolean Si l'utilisateur est actif
default_organization_id string ID de l'organisation par défaut (utilisé lors du changement de domaine)
domain_ids array Liste des IDs de domaines que l'utilisateur peut gérer (pour le rôle domain_admin)

Forgot Password

POST /api/v1/auth/forgot-password

Request:

{
  "email": "user@example.com"
}

Reset Password

POST /api/v1/auth/reset-password

Request:

{
  "token": "reset-token",
  "password": "new-password"
}

OAuth Providers

GET /api/v1/auth/oauth/providers

Returns list of enabled OAuth providers for the current domain.


SMS & Conversations

Send SMS

POST /api/v1/sms/send

Request:

{
  "to": "+15141234567",
  "body": "Hello from Textos!",
  "team_id": "optional-team-id",
  "from_number": "optional-from-number",
  "media_urls": [
    {
      "url": "https://example.com/image.jpg",
      "content_type": "image/jpeg"
    }
  ]
}

Parameters: | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | to | string | Yes | Destination phone number in E.164 format | | body | string | No | Message text (required if no media_urls) | | team_id | string | No | Team ID to send from | | from_number | string | No | Specific phone number to send from | | media_urls | array | No | Array of media attachments for MMS |

Media URL Object: | Field | Type | Description | |-------|------|-------------| | url | string | Public URL of the media file | | content_type | string | MIME type (image/jpeg, image/png, video/mp4, etc.) |

Note: MMS support depends on the provider. Only providers that support MMS (e.g., ISP Telecom) can send media attachments. SMS-only providers (e.g., Ubity) will ignore media_urls.

Response:

{
  "message": {
    "id": "...",
    "direction": "outbound",
    "status": "sent",
    "body": "Hello from Textos!",
    "from_number": "+15149876543",
    "to_number": "+15141234567",
    "media_urls": [...],
    "created_at": "2024-01-15T10:30:00Z"
  },
  "conversation": { ... }
}

Upload File (MMS)

POST /api/v1/upload
Content-Type: multipart/form-data

Upload a file to use as an MMS attachment.

Request: - file: The file to upload (multipart/form-data)

Supported formats: - Images: JPG, JPEG, PNG, GIF, WebP - Videos: MP4, MOV - Audio: MP3, WAV, M4A

Limits: - Maximum file size: 10 MB

Response:

{
  "url": "/api/uploads/abc123.jpg",
  "content_type": "image/jpeg",
  "filename": "abc123.jpg"
}

Note: The returned URL should be used in the media_urls array of the Send SMS endpoint. For external API calls, prepend the base URL to create an absolute URL.

List Conversations

GET /api/v1/conversations

Query Parameters: | Parameter | Type | Description | |-----------|------|-------------| | team_id | string | Filter by team | | status | string | open or closed | | skip | integer | Pagination offset | | limit | integer | Results per page (max 100) |

Get Conversation

GET /api/v1/conversations/{conversation_id}

Returns conversation details with messages and provider capabilities.

Query Parameters: | Parameter | Type | Description | |-----------|------|-------------| | skip | integer | Message pagination offset | | limit | integer | Messages per page (max 100) |

Response:

{
  "conversation": {
    "id": "...",
    "phone_number": "+15141234567",
    "status": "open",
    "created_at": "2024-01-15T10:00:00Z",
    ...
  },
  "messages": [
    {
      "id": "...",
      "direction": "inbound",
      "body": "Hello!",
      "status": "received",
      "media_urls": [],
      "created_at": "2024-01-15T10:30:00Z"
    },
    ...
  ],
  "capabilities": ["SMS", "MMS"]
}

Capabilities: | Value | Description | |-------|-------------| | SMS | Basic SMS messaging (always present) | | MMS | Multimedia messaging (images, videos, audio) |

The capabilities array indicates what features are available for this conversation based on the provider configuration. Use this to conditionally show/hide MMS attachment controls in your UI.

Close Conversation

POST /api/v1/conversations/{conversation_id}/close

Reopen Conversation

POST /api/v1/conversations/{conversation_id}/reopen

Archive Conversation

POST /api/v1/conversations/{conversation_id}/archive

Archives a conversation. Requires manager role or higher.

Response:

{
  "conversation": { ... },
  "message": "Conversation archived"
}

Delete Conversation

DELETE /api/v1/conversations/{conversation_id}

Permanently deletes a conversation and all its messages. Requires admin role or higher.

Response:

{
  "message": "Conversation deleted"
}

List Messages

GET /api/v1/messages

Query Parameters: | Parameter | Type | Description | |-----------|------|-------------| | team_id | string | Filter by team | | direction | string | inbound or outbound | | status | string | Message status | | skip | integer | Pagination offset | | limit | integer | Results per page |


Teams

List Teams

GET /api/v1/teams

Returns teams from the user's current organization (selected in the sidebar).

Query Parameters: | Parameter | Type | Description | |-----------|------|-------------| | organization_id | string | Filter by organization (required for API key users, optional for JWT users) | | skip | integer | Pagination offset | | limit | integer | Results per page (max 100) |

Note: When using JWT authentication, the organization is determined by the user's current selection in the web interface. When using API key authentication, you should specify the organization_id parameter to indicate which organization's teams to retrieve.

Get Team

GET /api/v1/teams/{team_id}

Create Team

POST /api/v1/teams

Request:

{
  "name": "Support Team",
  "phone_number": "+15149876543"
}

Update Team

PUT /api/v1/teams/{team_id}

Request:

{
  "name": "Updated Team Name",
  "phone_number": "+15149876543",
  "business_hours": [
    { "day": 0, "start": "09:00", "end": "17:00" },
    { "day": 1, "start": "09:00", "end": "17:00" }
  ],
  "outside_hours_behavior": "queue",
  "auto_reply_message": "We're currently closed...",
  "welcome_message": "Thank you for contacting us!",
  "timezone": "America/Montreal"
}

Delete Team

DELETE /api/v1/teams/{team_id}

Update Business Hours

PUT /api/v1/teams/{team_id}/hours

Request:

{
  "business_hours": [
    { "day": 0, "start": "09:00", "end": "17:00" },
    { "day": 1, "start": "09:00", "end": "17:00" },
    { "day": 2, "start": "09:00", "end": "17:00" },
    { "day": 3, "start": "09:00", "end": "17:00" },
    { "day": 4, "start": "09:00", "end": "17:00" }
  ],
  "outside_hours_behavior": "queue",
  "auto_reply_message": "We're currently closed. We'll respond during business hours.",
  "timezone": "America/Montreal"
}

Notes: - Day 0 = Monday, 6 = Sunday - outside_hours_behavior: queue or reject - auto_reply_message: optional, sent when SMS received outside hours (for both behaviors)

Team Members

List Members

GET /api/v1/teams/{team_id}/members

Add Member

POST /api/v1/teams/{team_id}/members

Request:

{
  "user_id": "user-id-to-add"
}

Remove Member

DELETE /api/v1/teams/{team_id}/members/{user_id}

Team Phone Numbers

GET /api/v1/teams/{team_id}/phone-numbers

Regenerate Webhook

POST /api/v1/teams/{team_id}/webhook/regenerate

Team Archives

List Archived Dates

GET /api/v1/teams/{team_id}/archives/dates

Returns a list of dates (YYYY-MM-DD format) that have archived conversations. Requires manager role or higher.

Response:

{
  "dates": ["2024-01-15", "2024-01-14", "2024-01-10"]
}

List Archived Conversations

GET /api/v1/teams/{team_id}/archives

Returns archived conversations for a team. Requires manager role or higher.

Query Parameters: | Parameter | Type | Description | |-----------|------|-------------| | date | string | Filter by date (YYYY-MM-DD format) | | skip | integer | Pagination offset | | limit | integer | Results per page (max 100) |

Response:

{
  "conversations": [
    {
      "id": "...",
      "phone_number": "+15141234567",
      "contact_name": "John Doe",
      "status": "archived",
      "archived_at": "2024-01-15T14:30:00Z",
      ...
    }
  ],
  "skip": 0,
  "limit": 50
}


Organizations

My Organizations

GET /api/v1/organizations/my

Returns all organizations the current user belongs to.

Switch Organization

POST /api/v1/organizations/switch

Request:

{
  "organization_id": "org-id"
}

Current Organization

GET /api/v1/organizations/current

Update Current Organization

PUT /api/v1/organizations/current

Request:

{
  "name": "New Organization Name"
}

Organization Members

GET /api/v1/organizations/current/members

Invitations

List Invitations

GET /api/v1/invitations

Create Invitation

POST /api/v1/invitations

Request:

{
  "email": "newuser@example.com",
  "role": "agent",
  "team_id": "optional-team-id"
}

Response includes token for the invitation URL.

Delete Invitation

DELETE /api/v1/invitations/{invitation_id}

Verify Invitation (Public)

GET /api/v1/invitations/verify/{token}

API Keys

List API Keys

GET /api/v1/api-keys

Create API Key

POST /api/v1/api-keys

Request:

{
  "name": "My Integration Key",
  "team_id": "optional-team-id"
}

Response includes key field - save it as it's only shown once!

Get API Key

GET /api/v1/api-keys/{key_id}

Revoke API Key

DELETE /api/v1/api-keys/{key_id}
or
POST /api/v1/api-keys/{key_id}/revoke


Metrics

Overview

GET /api/v1/metrics/overview

Query Parameters: | Parameter | Type | Description | |-----------|------|-------------| | team_id | string | Filter by team (admin only) | | start_date | string | ISO date | | end_date | string | ISO date | | days | integer | Days to look back (default 30) |

Volume

GET /api/v1/metrics/volume

Query Parameters: | Parameter | Type | Description | |-----------|------|-------------| | team_id | string | Filter by team | | start_date | string | ISO date | | end_date | string | ISO date | | days | integer | Days to look back | | granularity | string | hour, day, week, or month |

Performance

GET /api/v1/metrics/performance

Team Metrics

GET /api/v1/metrics/team/{team_id}

User Metrics

GET /api/v1/metrics/user/{user_id}

Export Metrics

GET /api/v1/metrics/export

Webhooks

These endpoints are called by SMS providers to deliver incoming messages.

Receive SMS (Team)

POST /webhook/sms/{secret_token}

The secret_token is the team's webhook secret.

Receive SMS (Domain)

POST /webhook/domain/{provider}/{secret_token}
  • provider: ubity or isp_telecom
  • secret_token: Domain's webhook secret

Message Status Update

POST /webhook/sms/{secret_token}/status

Admin Endpoints (Super Admin Only)

Organizations

List All Organizations

GET /api/v1/organizations

Create Organization

POST /api/v1/organizations

Request:

{
  "name": "New Organization",
  "owner_email": "owner@example.com"
}

Get Organization

GET /api/v1/organizations/{org_id}

Notes: - Super admins can access any organization - Organization admins can only access their own organization

Get Organization Invitations

GET /api/v1/organizations/{org_id}/invitations

Notes: - Super admins can access any organization - Organization admins can only access their own organization

Update Organization

PUT /api/v1/organizations/{org_id}

Delete Organization

DELETE /api/v1/organizations/{org_id}

Update Organization Member

PUT /api/v1/organizations/{org_id}/members/{user_id}

Request:

{
  "role": "admin",
  "is_active": true
}

Delete Organization Member

DELETE /api/v1/organizations/{org_id}/members/{user_id}

Domains

List Domains

GET /api/v1/domains

Create Domain

POST /api/v1/domains

Request:

{
  "name": "my-domain",
  "hostnames": ["app.example.com", "app.example.com:8080"],
  "display_name": "My Domain"
}

Get Domain

GET /api/v1/domains/{domain_id}

Update Domain

PUT /api/v1/domains/{domain_id}

Delete Domain

DELETE /api/v1/domains/{domain_id}

Get Current Domain (Public)

GET /api/v1/domains/current

Domain Settings

SMTP Settings

GET /api/v1/domains/{domain_id}/settings/smtp
PUT /api/v1/domains/{domain_id}/settings/smtp

OAuth Settings

GET /api/v1/domains/{domain_id}/settings/oauth
PUT /api/v1/domains/{domain_id}/settings/oauth/{provider}

SMS Providers

GET /api/v1/domains/{domain_id}/sms-providers
PUT /api/v1/domains/{domain_id}/sms-providers/{provider}

Domain Phone Numbers

List Phone Numbers

GET /api/v1/domains/{domain_id}/phone-numbers

Create Phone Number(s)

POST /api/v1/domains/{domain_id}/phone-numbers

Request (batch):

{
  "numbers": ["+15141234567", "+15149876543"],
  "provider": "ubity"
}

Update Phone Number

PUT /api/v1/domains/{domain_id}/phone-numbers/{phone_id}

Configure Provider

PUT /api/v1/domains/{domain_id}/phone-numbers/{phone_id}/provider

Request:

{
  "provider": "ubity",
  "config": { "api_key": "..." },
  "test_first": true
}

Assign to Organization

POST /api/v1/domains/{domain_id}/phone-numbers/{phone_id}/assign

Request:

{
  "organization_id": "org-id"
}

Delete Phone Number

DELETE /api/v1/domains/{domain_id}/phone-numbers/{phone_id}

Domain Webhooks

GET /api/v1/domains/{domain_id}/webhook
POST /api/v1/domains/{domain_id}/webhook/regenerate

Domain SMS Logs

GET /api/v1/domains/{domain_id}/sms-logs

Query Parameters: | Parameter | Type | Description | |-----------|------|-------------| | direction | string | inbound ou outbound | | provider | string | Filtrer par fournisseur | | start_date | string | Date ISO | | end_date | string | Date ISO | | skip | integer | Offset de pagination | | limit | integer | Résultats par page (max 100) |

Gestion des Admins de Domaine

Ces endpoints permettent de gérer les administrateurs de domaine. Accessible aux super_admin et domain_admin (pour leurs propres domaines).

Lister les Admins de Domaine

GET /api/v1/domains/{domain_id}/admins

Retourne tous les admins de domaine et les invitations en attente.

Réponse:

{
  "admins": [
    {
      "id": "user-id",
      "email": "admin@example.com",
      "first_name": "Jean",
      "last_name": "Dupont"
    }
  ],
  "pending_invitations": [
    {
      "id": "invitation-id",
      "email": "pending@example.com",
      "created_at": "2024-01-15T10:30:00Z",
      "expires_at": "2024-01-22T10:30:00Z"
    }
  ]
}

Ajouter un Admin de Domaine

POST /api/v1/domains/{domain_id}/admins

Ajoute un utilisateur comme admin de domaine. Si l'utilisateur existe, il est ajouté immédiatement. Sinon, une invitation est créée.

Requête:

{
  "email": "user@example.com"
}

Réponse (utilisateur existant):

{
  "admin": { ... },
  "message": "User user@example.com added as domain admin",
  "invited": false
}

Réponse (nouvelle invitation):

{
  "invitation": {
    "id": "...",
    "email": "user@example.com",
    "token": "...",
    "created_at": "...",
    "expires_at": "..."
  },
  "message": "Invitation sent to user@example.com",
  "invited": true
}

Retirer un Admin de Domaine

DELETE /api/v1/domains/{domain_id}/admins/{user_id}

Retire un utilisateur des admins de domaine. Si l'utilisateur n'a plus d'autres domaines, son rôle devient admin.

Réponse:

{
  "message": "User removed from domain admins",
  "new_role": "admin"
}

Supprimer une Invitation d'Admin de Domaine

DELETE /api/v1/domains/{domain_id}/admins/invitations/{invitation_id}

Supprime une invitation d'admin de domaine en attente.

Réponse:

{
  "message": "Invitation deleted successfully"
}


Billing

L'API de facturation permet de gérer les crédits, les plans tarifaires et l'utilisation.

Get Billing Info

GET /api/v1/billing

Retourne les informations de facturation de l'organisation courante.

Response:

{
  "billing": {
    "organization_id": "...",
    "balance": 150.00,
    "currency": "CAD",
    "pricing_plan": {
      "id": "...",
      "name": "Standard",
      "sms_rate": 0.05,
      "mms_rate": 0.15
    },
    "auto_recharge": {
      "enabled": true,
      "threshold": 50.00,
      "amount": 100.00
    }
  }
}

Get Balance

GET /api/v1/billing/balance

Response:

{
  "balance": 150.00,
  "currency": "CAD"
}

Check Balance

POST /api/v1/billing/check-balance

Vérifie si le solde est suffisant pour envoyer un message.

Request:

{
  "type": "sms"
}

Recharge Credits

POST /api/v1/billing/recharge

Recharge le compte avec une carte de crédit.

Request:

{
  "amount": 100.00
}

Configure Auto-Recharge

PUT /api/v1/billing/auto-recharge

Request:

{
  "enabled": true,
  "threshold": 50.00,
  "amount": 100.00
}

Get Usage

GET /api/v1/billing/usage

Query Parameters: | Parameter | Type | Description | |-----------|------|-------------| | start_date | string | Date de début (ISO) | | end_date | string | Date de fin (ISO) |

Response:

{
  "usage": {
    "sms_sent": 1234,
    "sms_received": 567,
    "mms_sent": 89,
    "mms_received": 12,
    "total_cost": 75.50
  }
}

Get Usage Summary

GET /api/v1/billing/usage/summary

Get Detailed Usage

GET /api/v1/billing/usage/detailed

Get Transactions

GET /api/v1/billing/transactions

Liste les transactions (recharges, déductions).

Get Invoices

GET /api/v1/billing/invoices

Get Invoice

GET /api/v1/billing/invoices/{invoice_id}

Pricing Plans (Super Admin)

List Plans

GET /api/v1/billing/pricing-plans

Create Plan

POST /api/v1/billing/pricing-plans

Request:

{
  "name": "Premium",
  "sms_rate": 0.04,
  "mms_rate": 0.12,
  "did_rate": 2.50,
  "is_default": false
}

Update Plan

PUT /api/v1/billing/pricing-plans/{plan_id}

Delete Plan

DELETE /api/v1/billing/pricing-plans/{plan_id}

Assign Plan to Organization

POST /api/v1/billing/admin/assign-plan

Request:

{
  "organization_id": "...",
  "plan_id": "..."
}

Add Credits to Organization

POST /api/v1/billing/admin/add-credits

Request:

{
  "organization_id": "...",
  "amount": 100.00,
  "description": "Crédit initial"
}


Multi-domaine

Pour le support multi-domaine, incluez le header X-Frontend-Host avec le hostname du domaine:

X-Frontend-Host: ort360.textos.ca

Ce header est utilisé pour: - Filtrer les organisations par domaine - Appliquer les configurations spécifiques au domaine (SMTP, OAuth, branding) - Charger les numéros de téléphone et providers du domaine

Note pour les applications mobiles: L'app mobile doit envoyer ce header pour accéder aux ressources du bon domaine.


Error Responses

All errors follow this format:

{
  "error": "error_code",
  "message": "Human-readable error message"
}

Common error codes: - validation_error - Invalid request data - unauthorized - Authentication required - forbidden - Insufficient permissions - not_found - Resource not found - send_failed - SMS sending failed - provider_error - SMS provider error


Rate Limits

Endpoint Limit
POST /auth/login 20/minute
POST /auth/register 10/hour
POST /auth/forgot-password 5/hour
POST /auth/reset-password 10/hour
POST /sms/send 100/hour

Rôles et Permissions

Rôle Description
super_admin Accès complet au système, peut gérer tous les domaines et organisations
domain_admin Peut gérer les domaines assignés: organisations, paramètres, logs SMS. Ne peut pas créer/supprimer de domaines ni ajouter de crédits.
admin Administrateur d'organisation, peut gérer les équipes et les membres
manager Gestionnaire d'équipe, peut configurer les paramètres d'équipe et voir les métriques
agent Peut gérer les conversations assignées à son équipe

Capacités de l'Admin de Domaine

Les admins de domaine ont accès uniquement à leurs domaines assignés. Ils peuvent:

  • Accéder à toutes les organisations de leurs domaines
  • Gérer les paramètres de domaine (SMTP, OAuth)
  • Voir les logs SMS de leurs domaines
  • Gérer les autres admins de domaine pour leurs domaines

Les admins de domaine ne peuvent pas:

  • Créer ou supprimer des domaines
  • Ajouter des crédits aux organisations
  • Accéder aux domaines qui ne leur sont pas assignés