L'API AIMERICA
Lisez les appels et les textos, lancez des appels, envoyez des textos et gardez vos contacts à jour depuis vos propres logiciels. Des webhooks signés préviennent vos systèmes dès que quelque chose se passe. Du HTTPS et du JSON, tout simplement.
Authentification
Chaque requête porte une clé API dans l'en-tête Authorization. Un propriétaire ou un administrateur crée les clés dans l'application sous Réglages → Développeur → Clés API. La clé est affichée une seule fois, à sa création; ensuite, seuls ses premiers caractères sont listés, et elle peut être révoquée à tout moment.
curl https://a1merica.ai/voip/api/calls/?limit=5 \
-H "Authorization: Bearer aim_live_3f9c1e2d0a7b4c5d6e8f90123456789a"
Chaque clé porte des permissions, choisies à sa création :
| Permission | Ce qu'elle ouvre |
|---|---|
calls:read | Lister les appels, lire un appel |
calls:write | Lancer un appel, répondre, raccrocher |
messages:read | Lister les conversations et les messages |
messages:write | Envoyer un texto ou un message avec image |
numbers:read | Lister vos numéros de téléphone (acheter ou libérer un numéro ne se fait jamais par clé) |
contacts:read | Lister les contacts, retrouver la personne derrière un numéro |
contacts:write | Ajouter, modifier et supprimer des contacts |
L'adresse de base est https://a1merica.ai/voip/api. Les heures sont en ISO 8601, en UTC. Les numéros sont au format E.164 (+15145550100).
Limite de débit
Soixante requêtes par minute par clé, comptées sur une minute glissante. Au-delà, la réponse est 429 Too Many Requests avec un en-tête Retry-After: 60. Les lectures que vous répéteriez en boucle gagnent à être remplacées par un webhook.
Appels
GET /calls/
Les appels les plus récents en premier. Filtres : direction (inbound | outbound), status, user_id, search (un numéro, ou une partie), since et until (heures ISO), limit (1 à 200, 50 par défaut), offset.
GET /voip/api/calls/?direction=inbound&since=2026-09-24T00:00:00Z&limit=2
[
{
"id": "6b1f0d2a-7e0c-4f1a-9c3a-1d2e3f4a5b6c",
"direction": "inbound",
"status": "completed",
"from_number": "+15145550100",
"to_number": "+16135550101",
"started_at": "2026-09-24T14:02:11+00:00",
"ended_at": "2026-09-24T14:05:40+00:00",
"duration_seconds": 209,
"recording_url": "/api/calls/6b1f0d2a-.../recording",
"transcript": null,
"ai_summary": null,
"caller_name": "Marie Tremblay",
"follow_up": null,
"record_call": true,
"transcribe_call": false,
"created_at": "2026-09-24T14:02:09+00:00",
"user_id": "9d8c7b6a-...",
"user_name": "Alex Roy",
"phone_number": "+16135550101",
"ai_agent_id": null,
"ai_agent_name": null,
"ai_outcome": null
}
]
status vaut completed, missed, voicemail, failed, canceled, ou un état en cours (ringing, in-progress). GET /calls/{id} renvoie un appel, dans la même forme.
POST /calls/initiate
Lance un appel depuis l'une de vos lignes. Le destinataire sonne aussitôt, et les règles d'enregistrement de la ligne s'appliquent.
POST /voip/api/calls/initiate
{ "to_number": "+15145550100", "from_number_id": "c4e1…", "record_call": true }
201
{ "call_id": "6b1f…", "room_name": "empire-out-…", "livekit_url": "wss://…", "livekit_token": "…" }
from_number_id est l'id d'un de vos numéros. to_number est un numéro de téléphone ou le poste d'un collègue. La réponse nomme la salle média de l'appel et un jeton pour que l'appareil de l'appelant s'y joigne — c'est ce que fait l'application AIMERICA quand elle passe un appel. Un logiciel qui ne fait qu'appeler ce point d'accès ne met personne du côté de l'appelant : la personne qui répond entend le silence. Utilisez-le depuis quelque chose qui rejoint la salle, ou pour tester le routage. Pour terminer un appel : POST /calls/{id}/hangup.
Textos
GET /sms/conversations
Une ligne par numéro avec lequel vous avez échangé des textos, du plus récent au plus ancien (limit 1 à 200).
[
{
"remote_number": "+15145550100",
"local_number": "+16135550101",
"last_message": "À 15 h, c'est bon",
"last_message_at": "2026-09-24T15:10:03+00:00",
"message_count": 12,
"unread_count": 1,
"user_id": "9d8c…",
"user_name": "Alex Roy"
}
]
GET /sms/conversations/{number}
Les messages échangés avec ce numéro, du plus ancien au plus récent (limit 1 à 500, offset).
[
{
"id": "0a9b…",
"direction": "inbound",
"from_number": "+15145550100",
"to_number": "+16135550101",
"body": "À 15 h, c'est bon",
"media_urls": [],
"status": "received",
"created_at": "2026-09-24T15:10:03+00:00"
}
]
POST /sms/send
POST /voip/api/sms/send
{ "from_number_id": "c4e1…", "to_number": "+15145550100", "body": "Votre rendez-vous est confirmé pour 15 h.", "media_urls": null }
201
{ "id": "1c2d…", "direction": "outbound", "from_number": "+16135550101", "to_number": "+15145550100",
"body": "Votre rendez-vous est confirmé pour 15 h.", "media_urls": [], "status": "sent", "created_at": "…" }
Un numéro qui a répondu STOP (ou ARRÊT) est refusé avec 403. La ligne doit avoir les textos activés.
Numéros
GET /phone-numbers/
[
{
"id": "c4e1…",
"number": "+16135550101",
"label": "Réception",
"status": "active",
"provider": "telnyx",
"trunk_group": null,
"sms_enabled": true,
"e911_configured": true,
"cnam_display": "AIMERICA",
"voicemail_enabled": true,
"routing_json": { "ring_seconds": 24 },
"monthly_cost_cents": 500,
"assigned_to_user_id": "9d8c…",
"assigned_to_name": "Alex Roy",
"assigned_to_group_id": null,
"assigned_to_group_name": null,
"ai_agent_id": null,
"ai_agent_name": null,
"ivr_flow_id": null,
"ivr_flow_name": null,
"created_at": "2026-08-01T12:00:00+00:00",
"number_type": "local",
"hd_voice": true,
"hd_voice_supported": true
}
]
Contacts
GET /contacts/
Tous les contacts de l'entreprise. GET /contacts/lookup?phone=+15145550100 retrouve la personne derrière un numéro.
POST /contacts/
POST /voip/api/contacts/
{ "first_name": "Marie", "last_name": "Tremblay", "company": "Tremblay inc.",
"phone_number": "+15145550100", "email": "marie@example.com", "notes": null, "tags": ["client"] }
201
{ "id": "7f6e…", "first_name": "Marie", "last_name": "Tremblay", "company": "Tremblay inc.",
"phone_number": "+15145550100", "email": "marie@example.com", "notes": null,
"is_team_member": false, "linked_user_id": null, "tags": ["client"], "book": "organisation",
"created_at": "2026-09-24T15:20:00+00:00" }
PUT /contacts/{id} modifie n'importe lequel de ces champs; DELETE /contacts/{id} supprime le contact (204).
Webhooks
Un propriétaire ou un administrateur ajoute une adresse sous Réglages → Développeur → Webhooks, choisit les événements et reçoit un secret de signature (affiché une seule fois). Dès lors, AIMERICA envoie (POST) un corps JSON à cette adresse pour chaque événement. L'adresse doit être publique et en https://.
| Événement | Quand |
|---|---|
call.started | Un appel commence : un appelant de l'extérieur fait sonner une ligne, ou quelqu'un passe un appel |
call.answered | Quelqu'un décroche |
call.ended | L'appel est terminé — avec sa durée, sa direction, les numéros, l'état final et s'il existe un enregistrement |
call.missed | Un appel entrant auquel personne n'a répondu (envoyé aussi s'il est allé à la boîte vocale) |
sms.received | Un texto est arrivé sur l'une de vos lignes |
sms.sent | Un texto est parti de l'une de vos lignes (par une personne, une réponse automatique, une programmation ou l'API) |
voicemail.new | Un message vocal a été enregistré |
fax.received | Une télécopie est arrivée |
Le corps
POST https://example.com/aimerica
Content-Type: application/json
X-AIMERICA-Event: call.ended
X-AIMERICA-Delivery: 3e2d1c0b-…
X-AIMERICA-Signature: t=1758724800,v1=5f1a…c9
{
"id": "3e2d1c0b-…",
"event": "call.ended",
"created_at": "2026-09-24T16:00:00+00:00",
"org_id": "a1b2…",
"data": {
"id": "6b1f…",
"direction": "inbound",
"status": "completed",
"from_number": "+15145550100",
"to_number": "+16135550101",
"started_at": "2026-09-24T15:55:02+00:00",
"answered_at": "2026-09-24T15:55:09+00:00",
"ended_at": "2026-09-24T15:59:58+00:00",
"duration_seconds": 289,
"recording": true,
"user_id": "9d8c…",
"phone_number_id": "c4e1…"
}
}
data pour sms.received / sms.sent contient id, direction, from_number, to_number, body, media_urls, status, phone_number_id et received_at ou sent_at; pour voicemail.new : id, call_id, from_number, to_number, duration_seconds, transcription, recording_url, phone_number_id, received_at; pour fax.received : id, from_number, to_number, page_count, status, phone_number_id, received_at.
Vérifier la signature
Prenez t dans l'en-tête, joignez-le au corps brut avec un point, et calculez un HMAC-SHA256 avec votre secret. Comparez avec v1 en temps constant, et refusez un horodatage de plus de cinq minutes.
# Python
import hmac, hashlib, time
def verify(secret: str, header: str, body: bytes) -> bool:
parts = dict(p.split("=", 1) for p in header.split(","))
t, v1 = parts["t"], parts["v1"]
if abs(time.time() - int(t)) > 300:
return False
mac = hmac.new(secret.encode(), f"{t}.".encode() + body, hashlib.sha256).hexdigest()
return hmac.compare_digest(mac, v1)
// Node.js
const crypto = require("crypto");
function verify(secret, header, rawBody) {
const p = Object.fromEntries(header.split(",").map(s => s.split("=")));
if (Math.abs(Date.now() / 1000 - Number(p.t)) > 300) return false;
const mac = crypto.createHmac("sha256", secret).update(`${p.t}.`).update(rawBody).digest("hex");
return crypto.timingSafeEqual(Buffer.from(mac), Buffer.from(p.v1));
}
Réponse, nouvelles tentatives, ordre
- Répondez
2xxen moins de dix secondes. Toute autre réponse, ou l'absence de réponse, compte comme un échec. - Après un échec, nous réessayons après 1 minute, 5 minutes, 30 minutes et 2 heures, puis nous abandonnons cette livraison et comptons un échec sur l'adresse. Vingt-cinq échecs de suite mettent l'adresse en pause; réactivez-la dans les Réglages une fois votre serveur rétabli.
- Chaque livraison a un
idunique; servez-vous-en pour ignorer un doublon. Les événements d'un appel partent dans l'ordre où ils se sont produits, mais une nouvelle tentative peut arriver dans le désordre — fiez-vous àdata.statuset aux horodatages plutôt qu'à l'ordre d'arrivée. - Le bouton Envoyer un test dans les Réglages envoie un événement
pingavec la même signature : vous pouvez vérifier votre récepteur avant tout trafic réel.
Utiliser AIMERICA avec Zapier
Il n'y a pas encore d'application AIMERICA dans le répertoire Zapier; les deux pièces ci-dessus sont tout ce dont Zapier a besoin.
- Déclencheurs (quelque chose se passe dans AIMERICA → un Zap démarre). Dans Zapier, commencez un Zap avec Webhooks by Zapier → Catch Hook. Copiez l'adresse que Zapier vous donne, ajoutez-la sous Réglages → Développeur → Webhooks, cochez les événements (un appel manqué, un nouveau message vocal, un texto reçu…), puis appuyez sur Envoyer un test. Zapier affichera le
ping; les champs de chaque événement suivant se trouvent sousdata. - Actions (un Zap fait quelque chose dans AIMERICA). Ajoutez une étape Webhooks by Zapier → Custom Request. Méthode
POST, URLhttps://a1merica.ai/voip/api/sms/send(ou tout autre point d'accès ci-dessus), un en-têteAuthorization: Bearer aim_live_…,Content-Type: application/json, et le corps JSON de cette page rempli avec les champs de votre Zap. - Pensez aux permissions de la clé : un Zap qui ne fait qu'envoyer des textos mérite une clé avec
messages:writeseulement.
La même recette fonctionne avec Make, n8n, Power Automate et tout outil capable de recevoir un webhook et d'envoyer une requête HTTPS.
Erreurs
| Code | Signification |
|---|---|
400 | Quelque chose cloche dans la requête; detail dit quoi |
401 | La clé est absente, erronée ou révoquée |
402 | Le compte de l'entreprise demande une action avant celle-ci (p. ex. une carte au dossier) |
403 | La clé n'a pas la permission requise, ou ce point d'accès n'est jamais offert par clé |
404 | Introuvable, ou invisible pour la personne que la clé représente |
429 | Plus de soixante requêtes dans la minute — attendez le délai de Retry-After |
Chaque corps d'erreur est {"detail": "une phrase que vous pouvez afficher"}.
Slack, Google Workspace et Microsoft 365 se configurent dans l'application sous Intégrations, sans code. Une question sur l'API? Écrivez-nous.
