Guides pour les développeurs IA
La surface API de Bird est conçue pour les agents : une opération par outil, du JSON en entrée et en sortie, et des résultats vérifiables par la machine. Un agent fiable nécessite tout de même les bons patterns autour. Ces cinq patterns couvrent les modes de défaillance qui cassent les intégrations d'agents : traiter l'acceptation comme une livraison, réessayer sans contexte, et parser de la prose au lieu de la structure. Chaque pattern fonctionne de la même manière, que votre agent pilote le serveur MCP ou le bird CLI. Les exemples ci-dessous concernent l'e-mail, car c'est là que l'outillage autour d'un envoi est le plus complet, et les patterns s'appliquent à SMS et WhatsApp sans modification : le même 202 à l'envoi, la même séquence d'événements accepté-puis-terminal, la même enveloppe d'erreur. La seule exception est le Pattern 3, dont les adresses magiques sont un sandbox e-mail.
Pattern 1 : Boucler une opération à la fois
Les outils de Bird sont volontairement granulaires : envoyer un message, récupérer un message, lister les domaines, ou créer un endpoint webhook. Chaque outil retourne du JSON structuré dont les champs peuvent être vérifiés par l'étape suivante. Construisez la boucle de sorte que la condition de sortie de chaque étape provienne de la sortie de l'étape précédente :
Exemple de code
loop:
result = run_tool(next_operation) # one operation per call
if result.ok: advance using result.data # for example, the em_… ID or verified domain
else: branch on the failure category # see Pattern 4Avec le CLI, la catégorie d'erreur est le code de sortie, donc le branchement ne nécessite aucun parsing de message. Consultez le tableau complet dans CLI :
Exemple de code
bird email get "$id" --format json > msg.json
case $? in
0) jq .status msg.json ;; # advance
3) echo "wrong ID: fix the value instead of retrying" ;;
4) bird auth login ;; # recover, then re-run
esacLa granularité est le point essentiel : un agent qui peut vérifier l'état entre les étapes récupère de n'importe quelle défaillance individuelle ; un agent pilotant une méga-opération unique ne peut que tout recommencer.
Pattern 2 : Un envoi retourne 202 ; le résultat arrive plus tard
Faites un POST d'envoi et vous obtenez 202 Accepted avec un identifiant de message. Accepted signifie que Bird a pris en charge le message et que la livraison est en attente. Le résultat final arrive sous forme d'événements webhook : email.delivered quand le serveur du destinataire l'accepte, email.bounced quand la livraison échoue définitivement, email.complained, et ainsi de suite.
Un agent qui déclare le succès au 202 manque silencieusement chaque rebond. Structurez la tâche comme envoi-puis-attente :
Exemple de code
send → 202 + em_… ID # record the ID; delivery is still pending
await webhook event where data.email_id == em_… id:
email.delivered → done
email.bounced → report failure with bounce_type / bounce_descriptionCorrélez sur email_id. Les payloads webhook renvoient vos tags et métadonnées aux côtés des champs d'identité, donc votre propre contexte revient sans recherche supplémentaire. Les livraisons sont au-moins-une-fois et non ordonnées ; dédupliquez sur l'en-tête webhook-id et triez par le timestamp du payload. Si votre agent n'a pas de récepteur webhook, interrogez le message avec GET (ou bird email get) jusqu'à ce que son statut se résolve. L'interrogation est plus lente, mais la relecture reste la source de vérité.
Pattern 3 : Utilisez le sandbox comme harnais de test
Pendant le développement de la boucle, utilisez les adresses magiques du sandbox mail sur messagebird.dev au lieu de vraies boîtes de réception. L'adresse détermine le résultat (delivered@ livre toujours, bounce@ produit toujours un hard-bounce, et complaint@ génère toujours une plainte). Tout le reste utilise le pipeline de production : le même 202, la même séquence d'événements et les mêmes livraisons webhook signées, sans aucun indicateur marquant le message comme un test.
Exemple de code
for address in [delivered@, bounce@, suppressed@] @messagebird.dev:
send to address+run42@… # +label correlates the test case
assert the expected terminal event arrives (delivered / bounced / rejected)Le sandbox fournit des résultats déterministes, zéro risque de réputation, aucune écriture dans les listes de suppression, et des adresses réutilisables à chaque exécution. Un agent qui passe la matrice du sandbox a exercé l'intégralité du chemin Pattern 2 (envoi, attente et branchement) avant de toucher une vraie boîte de réception.
Pattern 4 : Récupérer grâce à l'enveloppe d'erreur standard
Chaque erreur de l'API Bird a la même structure, donc un seul chemin de récupération d'erreur fonctionne pour tous les endpoints :
Exemple de code
{
"error": {
"type": "validation_error",
"code": "E04006",
"name": "DomainNotVerified",
"message": "The from address uses a domain that is not verified in this workspace.",
"doc_url": "https://bird.com/docs/api/errors/E04006",
"request_id": "req_01krdgeqcxet5s7t44vh8rt9mg"
}
}Chaque champ a un rôle dans la boucle. Branchez sur type/code (stable et lisible par la machine), affichez message à l'humain, et récupérez doc_url quand l'agent a besoin de la page pour cette erreur exacte. L'URL résout vers du Markdown que l'agent peut lire. Loguez request_id pour qu'un humain puisse le transmettre au support Bird. Puis séparez les erreurs réessayables des erreurs de requête :
Exemple de code
4xx (except 429) → a request bug: fix the input, never retry as-is
429 → back off, then retry (Pattern 5)
5xx / timeout → retry with the same Idempotency-Key (Pattern 5)Le catalogue complet des codes se trouve sur la page des erreurs. Avec le CLI, l'enveloppe arrive sur stderr et le code de sortie la pré-classifie (voir Pattern 1 et le tableau complet dans CLI). Un agent piloté par shell peut donc brancher avant de parser quoi que ce soit.
Pattern 5 : Réessayer en toute sécurité avec Idempotency-Key et Retry-After
Les réessais peuvent dupliquer le travail quand un envoi expire et que l'agent réessaie. Le support d'idempotence de Bird rend les réessais sûrs. Générez un Idempotency-Key par opération logique et réutilisez-le à chaque tentative :
Exemple de code
key = uuid() # once per logical send
attempt with Idempotency-Key: key
on 5xx / timeout: backoff, retry with SAME key
on 2xx with Idempotency-Replay: true → the first attempt had succeeded; do not treat as a new sendL'en-tête de réponse Idempotency-Replay: true indique une relecture de la réponse originale, afin que votre agent puisse loguer « récupéré » au lieu de « envoyé deux fois ». Les SDK Bird injectent automatiquement une clé sur chaque requête mutante, donc les agents basés sur les SDK bénéficient de cela gratuitement ; avec le CLI, passez --idempotency-key sur les mutations susceptibles d'être réessayées.
Un 429 signifie que l'agent doit ralentir. La réponse contient un en-tête Retry-After ; utilisez-le comme backoff minimum plutôt que d'inventer un calendrier séparé :
Exemple de code
on 429: sleep max(Retry-After, backoff(attempt)); retry with the same keyNe réessayez pas les autres réponses 4xx sans modification. L'idempotence les met en cache et les rejoue parce que la même requête produit la même erreur. Corrigez la requête (Pattern 4) et utilisez une nouvelle clé ; réutiliser une clé avec un corps différent retourne 409 IdempotencyKeyReuse.
Étapes suivantes
- Serveur MCP : la surface d'outils que ces patterns pilotent, hébergée sur mcp.bird.com ou exécutée localement avec le CLI
- CLI pour les agents : les mêmes opérations pour les agents capables d'utiliser un shell
- Webhooks & événements : sémantiques de livraison, signatures et le catalogue d'événements derrière le Pattern 2
- Idempotence : sémantiques de relecture et modes de défaillance derrière le Pattern 5
- Erreurs : l'enveloppe et le catalogue complet des codes d'erreur
- Sandbox mail : la matrice d'adresses magiques derrière le Pattern 3