La verificación se divide más o menos por la mitad. Las herramientas para desarrolladores y el SaaS suelen enviar un código por email. Todo lo que toca dinero, identidad o una cuenta atada a un teléfono envía un SMS. Un agente que solo puede hacer una de las dos se traba en la mitad de internet.
La respuesta habitual son dos proveedores: una API de email y una API de SMS. Eso son dos modelos de autenticación, dos formatos de respuesta, dos estrategias de sondeo, dos modos de falla y un montón de pegamento cuyo único trabajo es hacer que se vean iguales para el agente. El pegamento es el problema: es la parte que nadie quiere mantener y que todos tienen que escribir.
La misma forma, ambos canales
apumail pasa los dos por una sola capa. El flujo de email:
# provision an inbox — no auth
INBOX=$(curl -sS -X POST https://api.apumail.com/api/v1/inboxes)
ADDR=$(echo "$INBOX" | jq -r .address)
TOK=$(echo "$INBOX" | jq -r .token)
# block until it lands, read the extracted code
curl -sS -H "Authorization: Bearer $TOK" \
"https://api.apumail.com/api/v1/inbox/$ADDR/wait?timeout=120" \
| jq -r '.messages[0].otp'
Y el flujo de SMS:
# buy a real dedicated number, on demand
PHONE=$(curl -sS -X POST https://api.apumail.com/api/v1/phones \
-H "Authorization: Bearer $TOK" \
-d '{"country_code":"US"}')
# same wait, same extract, different channel
Crear, esperar, extraer. Los mismos verbos, la misma autenticación, el mismo JSON. En MCP
la simetría es literal: wait_for_mail / extract_latest_otp junto a
wait_for_sms / extract_latest_sms_otp. Un agente que aprendió
uno aprendió el otro.
Números bajo demanda
Lo que hace incómodo el SMS para agentes en otros lugares es la adquisición. La mayoría
de los flujos asumen un humano: elegir un número de un pool, esperar disponibilidad, escribirle
a soporte para una región nueva. Un solo POST /api/v1/phones con un
country_code compra un número dedicado real en el acto: sin pool que esperar, sin
humano a quien escribirle. Es el número del agente mientras esté pagado, no uno compartido en
el que caen los códigos de otro.
Ese también es el trade-off honesto: es un plan pago. Un número cuesta desde $20/año en EE. UU./Canadá, con precio por país ($16 en $PROWL), y enviar cuesta $0.07/SMS desde crédito prepago. Las bandejas de email son gratis; los números de teléfono cuestan dinero porque los operadores cobran. Si solo necesitas códigos por email, nunca tocas esto y nunca pagas.
Enviar, no solo recibir
Ambos canales son bidireccionales, y eso importa más de lo que parece. La verificación no
siempre es un código: a veces es responder para confirmar, y a veces el flujo que estás
automatizando sigue por el mismo canal después del código. Un agente que solo puede
recibir tiene que pasarle el control a un humano en la primera respuesta. send_mail y
send_sms lo mantienen en el ciclo, con el from fijado a la
dirección o número del propio agente para que un token filtrado no sirva para suplantar a nadie.
En qué quedas
Un solo proveedor para un problema que suele ser doble no es una virtud en sí misma: es una virtud cuando las dos mitades realmente comparten forma, y aquí la comparten. Empieza con el flujo de email, que es gratis y requiere un solo POST. Agrega un número cuando un flujo lo exija.