Référence de l’API de démonstration

Cette page décrit l’API telle qu’elle est conçue aujourd’hui : authentification, idempotence, pagination, erreurs, points d’accès et webhooks. C’est une version de démonstration. Tous les exemples sont fictifs.

Mis à jour le

Statut de cette référence

Il s’agit d’une proposition de conception, susceptible d’évoluer sans préavis. Aucune API de production n’est ouverte à ce jour.

Tant qu’aucun fournisseur n’est configuré, les appels, commandes de numéros et SMS sont des simulations. Les réponses portent alors le champ simulated: true.

Les exemples utilisent le domaine fictif api.example.test, la clé fictive tq_test_EXEMPLE et des numéros d’une plage fictive. Aucun n’ouvre un accès réel.

Adresse de base et authentification

Toutes les requêtes passent par la base https://api.example.test/v1, en HTTPS. Authentifiez-vous avec une clé d’API dans l’en-tête Authorization, au schéma Bearer.

Une clé est limitée à un projet et à un environnement. Elle ne doit jamais figurer dans un code exécuté côté navigateur ni dans une URL.

Exemple fictif : en-tête d’authentification. La clé est inventée.
Authorization: Bearer tq_test_EXEMPLE
Content-Type: application/json

Idempotence

Toute requête POST exige un en-tête Idempotency-Key contenant un identifiant unique, par exemple un UUID. Sans lui, l’API répond 400 invalid_request.

Si vous renvoyez la même clé avec le même corps, l’API rejoue la réponse d’origine et ne crée rien de plus : un double clic ou une nouvelle tentative réseau reste sans effet. Si vous renvoyez la même clé avec un corps différent, l’API répond 409 idempotency_conflict.

Générez une clé neuve pour chaque nouvelle opération. Si une réponse n’est jamais arrivée, rejouez la requête avec la même clé plutôt qu’avec une nouvelle.

Pagination par curseur

Les listes acceptent limit et cursor. La réponse contient le tableau data et next_cursor. Pour lire la page suivante, passez la valeur de next_cursor dans cursor. Quand next_cursor est nul, la liste est terminée.

Un curseur est opaque : ne le décodez pas et ne le construisez pas vous-même.

Exemple fictif de fin de liste.
{
  "data": [],
  "next_cursor": null
}

Quotas et limites de débit

L’API limite le débit des requêtes. Au-delà de la limite, elle répond 429 rate_limited avec un en-tête Retry-After indiquant, en secondes, le temps d’attente avant de réessayer.

Les limites applicables à votre projet dépendent de votre contrat. Aucun chiffre n’est publié sur cette page.

Exemple fictif de réponse 429.
HTTP/1.1 429 Too Many Requests
Retry-After: 2
Content-Type: application/json

{ "error": { "code": "rate_limited", "message": "Trop de requêtes. Réessayez après le délai indiqué.", "request_id": "req_EXEMPLE_001" } }

Format des erreurs

Toute erreur renvoie un objet error avec trois champs : code (stable, à utiliser dans votre logique), message (destiné à une personne, susceptible de changer) et request_id (à communiquer à l’assistance).

Exemple fictif de réponse d’erreur.
{
  "error": {
    "code": "invalid_request",
    "message": "Le champ « to » doit être un numéro au format E.164.",
    "request_id": "req_EXEMPLE_002"
  }
}
HTTPcodeSignificationAction conseillée
400invalid_requestRequête mal formée : champ manquant ou invalide, Idempotency-Key absente sur un POST.Corrigez la requête.
401unauthorizedClé absente, invalide ou révoquée.Vérifiez la clé et l’en-tête Authorization.
403forbiddenLa clé n’a pas le droit d’accéder à cette ressource ou à ce projet.Utilisez une clé disposant des droits.
404not_foundRessource inexistante ou hors de votre périmètre.Vérifiez l’identifiant.
409idempotency_conflictMême Idempotency-Key utilisée avec un corps différent.Générez une nouvelle clé.
429rate_limitedDébit trop élevé.Attendez la durée de Retry-After.

GET /numbers

Liste les numéros de votre compte.

  • limit : nombre d’éléments par page (facultatif).
  • cursor : curseur de la page suivante (facultatif).
  • Chaque numéro porte id, e164, country, type, capabilities (voice, sms), project_id et status.
Exemple fictif de réponse. Données de démonstration.
{
  "data": [
    {
      "id": "num_EXEMPLE_001",
      "e164": "+33199001234",
      "country": "FR",
      "type": "local",
      "capabilities": ["voice", "sms"],
      "project_id": "prj_EXEMPLE_A",
      "status": "active"
    }
  ],
  "next_cursor": "cur_EXEMPLE_002"
}

GET /numbers/search

Cherche des numéros dans le stock. La disponibilité réelle dépend du pays, du fournisseur retenu et du contrat.

  • country : pays au format ISO à deux lettres, par exemple FR.
  • type : type de numéro, par exemple local.
  • Chaque résultat porte e164, country, type, capabilities et documents_required, la liste des justificatifs à fournir avant activation.
Exemple fictif de réponse. La valeur de documents_required est illustrative.
{
  "data": [
    {
      "e164": "+33199001234",
      "country": "FR",
      "type": "local",
      "capabilities": ["voice", "sms"],
      "documents_required": ["proof_of_address"]
    }
  ]
}

POST /number-orders

Passe une commande de numéro. En-tête Idempotency-Key obligatoire. La commande reste en attente de validation des justificatifs et des conditions.

  • e164 : numéro à commander, issu d’une recherche (obligatoire).
  • project_id : projet de rattachement (obligatoire).
Exemple fictif de réponse. Simulation : aucun numéro réel n’est réservé.
{
  "id": "ord_EXEMPLE_001",
  "status": "pending_validation",
  "simulated": true
}

POST /calls

Lance un appel sortant entre deux numéros. En-tête Idempotency-Key obligatoire.

  • from : numéro appelant, en E.164 (obligatoire).
  • to : numéro appelé, en E.164 (obligatoire).
  • project_id : projet concerné (obligatoire).
  • flow_id : scénario d’appel à appliquer (facultatif).
Exemple fictif de réponse. Simulation : aucune communication réelle n’a été émise.
{
  "id": "call_EXEMPLE_001",
  "status": "ringing",
  "simulated": true
}

GET /calls

Liste le journal des appels, avec pagination par curseur. Les durées sont en secondes. La durée de conversation et la durée facturable sont deux champs distincts : elles peuvent différer selon le contrat.

  • limit et cursor : pagination (facultatifs).
  • Chaque appel porte id, direction, status, duration_seconds, billable_seconds et project_id.
Exemple fictif de réponse. Données de démonstration.
{
  "data": [
    {
      "id": "call_EXEMPLE_001",
      "direction": "outbound",
      "status": "completed",
      "duration_seconds": 42,
      "billable_seconds": 42,
      "project_id": "prj_EXEMPLE_A"
    }
  ],
  "next_cursor": null
}

POST /messages

Envoie ou programme un SMS. En-tête Idempotency-Key obligatoire. Un texte long est découpé en segments, chacun comptant pour la consommation.

  • from : expéditeur (obligatoire).
  • to : destinataire, en E.164 (obligatoire).
  • text : contenu du message (obligatoire).
  • nature : transactional ou marketing (obligatoire).
  • scheduled_at : date et heure d’envoi programmé (facultatif).
  • timezone : fuseau horaire de scheduled_at (facultatif, à fournir avec scheduled_at).
  • La réponse indique segments et encoding (GSM-7 ou UCS-2).
Exemple fictif de réponse. Simulation : aucun SMS réel n’a été émis.
{
  "id": "msg_EXEMPLE_001",
  "status": "queued",
  "segments": 1,
  "encoding": "GSM-7",
  "simulated": true
}

GET /usage

Renvoie les quantités consommées sur une période. La réponse porte des quantités et des unités, jamais de montants.

  • from et to : bornes de la période, au format AAAA-MM-JJ.
  • group_by : day, number, project, country ou service.
  • provisional vaut true quand des événements peuvent encore arriver en retard.
  • Un appel peut générer plusieurs lignes de consommation selon le contrat.
Exemple fictif de réponse. Valeurs inventées.
{
  "data": [
    { "key": "2026-10-01", "service": "voice", "direction": "outbound", "unit": "second", "quantity": 5400 },
    { "key": "2026-10-01", "service": "sms", "direction": "outbound", "unit": "segment", "quantity": 120 }
  ],
  "provisional": false
}

Statuts

ObjetStatutsRemarque
Appelringing, connected, completed, failedfailed n’indique pas la cause. Ne la déduisez pas.
SMSqueued, sent, delivered, undelivered, unknowndelivered ne veut pas dire lu. unknown peut rester définitif.
Commande de numéropending_validationLe numéro n’est utilisable qu’après activation (événement number.activated).

Webhooks

Vous pouvez recevoir des événements sur une adresse HTTPS de votre choix. Chaque livraison porte un en-tête Telqio-Signature de la forme t=<horodatage unix>,v1=<signature hexadécimale>.

La signature est un HMAC-SHA256 du texte « t, point, corps brut » avec le secret du point de terminaison. Rejetez toute livraison dont l’horodatage s’écarte de plus de 300 secondes, et dédupliquez sur l’identifiant d’événement id.

Événements : call.ringing, call.connected, call.completed, call.failed, message.sent, message.delivered, message.undelivered et number.activated. Les nouvelles tentatives de livraison suivent une politique bornée, visible dans la console. L’ordre d’arrivée n’est pas garanti.

Le guide « Vérifier un webhook signé » donne le code complet en Node.js.

Exemple fictif de livraison. La forme exacte de l’enveloppe peut évoluer.
POST /webhook HTTP/1.1
Telqio-Signature: t=1794096000,v1=<signature_hexadecimale>
Content-Type: application/json

{
  "id": "evt_EXEMPLE_001",
  "type": "call.completed",
  "created": 1794096000,
  "data": { "call_id": "call_EXEMPLE_001", "status": "completed" }
}

Ce que cette référence n’est pas

  • Ce n’est pas un engagement de service : aucune disponibilité, aucun délai ni aucune capacité n’est promis.
  • Ce n’est pas une API ouverte : aucune clé réelle n’existe et aucune communication n’est émise.
  • Les capacités réelles dépendront du pays, du fournisseur retenu et du contrat. Pour votre périmètre, demandez un devis.

Questions fréquentes

Puis-je utiliser cette API en production ?

Non. Il s’agit d’une version de démonstration. Aucune API de production n’est ouverte et le contrat d’interface peut encore changer.

Pourquoi les réponses contiennent-elles simulated: true ?

Parce qu’aucun fournisseur n’est configuré. Les appels, SMS et commandes de numéros sont simulés, et aucune communication réelle n’est émise.