AMI — documentación interactiva
AMI — interactive documentation
AMI es un protocolo abierto que permite a un agente AI obtener su propia identidad móvil — un número real con SMS y voz — de forma autónoma, programable y auditable.
AMI is an open protocol that lets an AI agent obtain its own mobile identity — a real number with SMS and voice — autonomously, programmatically, and auditably.
TL;DR
Tu agente llama tres tools MCP (o tres POST REST) y obtiene un número de teléfono real en menos de un segundo. Después puede enviar SMS y hacer llamadas usando un agent_token scoped a ese número. La voz se bridgea a tu propio motor Realtime — AMI es la pipa, tu agente es el cerebro.
Your agent calls three MCP tools (or three REST POSTs) and gets a real phone number in under a second. From there it can send SMS and place calls using an agent_token scoped to that number. Voice gets SIP-bridged to your own real-time engine — AMI is the pipe, your agent is the brain.
Mapa del documento
Document map
- Quick startQuick start — de cero a un SMS enviado en 5 líneas from zero to a sent SMS in 5 lines
- ConceptosConcepts — MobileIdentity, agent_token, bridge-by-API MobileIdentity, agent_token, bridge-by-API
- AutenticaciónAuthentication — los dos niveles + master admin the two levels + admin master
- Contracting · SMS · Voice · Webhooks · Limits · Admin · Errors · SDKs
Otros recursos
Other resources
- /spec — spec técnica completafull technical spec
- /openapi.json — OpenAPI 3.1
- /diagram — animación del ciclo de vidalifecycle animation
- /llms.txt — índice para LLMsindex for LLMs
- /partners — para operadores telcofor telco operators
Quick start
Obtén un número de teléfono real y envía tu primer SMS con cinco líneas de código. Los SDKs oficiales hacen todo el flujo de contratación en una sola llamada.
Get a real phone number and send your first SMS in five lines of code. The official SDKs handle the entire contracting flow in a single call.
1. Instala el SDK
1. Install the SDK
pip install ami-protocol
npm install @ami-protocol/sdk
# no install needed
2. Provisiona un número + envía un SMS
2. Provision a number + send an SMS
from ami import AmiClient
client = AmiClient(api_key="amik_live_...",
base_url="https://api.protocolami.com")
creds = client.provision_number(country="ES", customer={
"legal_name": "Acme S.L.", "tax_id": "B12345678",
"billing_email": "billing@acme.test",
"address": "Madrid, Spain",
"representative_name": "Ada Lovelace",
})
agent = client.as_agent(creds.agent_token)
agent.send_sms(to="+34600...", body="Hello from my agent")
print(f"Number: {creds.phone_number}")
print(f"Token (save it!): {creds.agent_token[:20]}...")import { AmiClient } from "@ami-protocol/sdk";
const client = new AmiClient({
apiKey: process.env.AMI_API_KEY!,
baseUrl: "https://api.protocolami.com",
});
const creds = await client.provisionNumber({
country: "ES",
customer: {
legalName: "Acme S.L.", taxId: "B12345678",
billingEmail: "billing@acme.test",
address: "Madrid, Spain",
representativeName: "Ada Lovelace",
},
});
const agent = client.asAgent(creds.agentToken);
await agent.sendSms({ to: "+34600...", body: "Hello from my agent" });# 1) request + offer
curl -X POST https://api.protocolami.com/v1/sim-requests \
-H "Authorization: Bearer $AMI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"country":"ES"}'
# 2-5) accept offer / customer-data / contract / mock-sign
# 6) activate → returns agent_token ONCE
curl -X POST https://api.protocolami.com/v1/mobile-identities/activate \
-H "Authorization: Bearer $AMI_API_KEY" \
-d '{"contract_id":"contract_..."}'
# 7) send SMS using the agent_token
curl -X POST https://api.protocolami.com/v1/agent/sms/send \
-H "Authorization: Bearer $AGENT_TOKEN" \
-d '{"to":"+34600...","body":"Hello"}'3. Pruébalo ahora
3. Try it now
El endpoint POST /v1/demo/quick es público (sin auth)
y ejecuta el flujo entero contra el backend mock. Útil para ver
el shape de las respuestas sin necesidad de API key.
The POST /v1/demo/quick endpoint is public (no auth)
and runs the full flow against the mock backend. Useful to see
the shape of responses without an API key.
Conceptos clave
Key concepts
MobileIdentity (MID)
Una MobileIdentity es la unidad central del protocolo:
un número de teléfono activo con un conjunto de capacidades
(sms, voice) asignado a un agente concreto bajo un contrato
firmado con un customer. Su id tiene formato mid_<hex>.
A MobileIdentity is the protocol's central unit: an
active phone number with a set of capabilities (sms, voice)
assigned to a specific agent under a signed contract. Its id
has format mid_<hex>.
agent_token vs API key
Hay dos niveles de auth: la API key del customer cubre la contratación y administración (provisión, límites, webhooks, rotación); el agent_token está scoped a una MID concreta y cubre la operación diaria (enviar SMS, hacer llamadas). Si el agent_token se filtra, el blast radius es esa MID y nada más.
There are two auth levels: the customer's API key covers contracting and admin (provisioning, limits, webhooks, rotation); the agent_token is scoped to one specific MID and covers daily operation (sending SMS, placing calls). If the agent_token leaks, the blast radius is that one MID and nothing else.
Bridge-by-API · voz
Bridge-by-API · voice
AMI es el operador / SIP provider, no ejecuta
voz Realtime. Cuando tu agente origina una llamada, AMI marca
al PSTN y bridgea la llamada por SIP al
callback_sip_uri que tu agente proporciona
(típicamente el endpoint SIP de tu motor de voz en tiempo real).
El audio en sí pasa por la pipa de AMI; el "cerebro" del agente
vive en tu endpoint.
AMI is the operator / SIP provider, it does not
run real-time voice. When your agent places a call, AMI dials
the PSTN and SIP-bridges the call to the
callback_sip_uri your agent provides (typically
your real-time voice engine's SIP endpoint). Audio flows
through AMI's pipe; the agent "brain" lives at your endpoint.
Ver la animación →See the animation →
Multi-tenancy
Multi-tenancy
Cada empresa cliente es un customer_account con su
propia API key. Cada recurso (sim_request, contract, MID,
customer legal) lleva account_id, y AMI filtra
cualquier acceso para que un customer NO pueda ver ni mutar
recursos de otro. Los endpoints /v1/admin/*
(gestión de customers) requieren un master key separado.
Each client company is a customer_account with its
own API key. Every resource (sim_request, contract, MID, legal
customer) carries account_id, and AMI filters all
access so one customer cannot see or mutate another's resources.
/v1/admin/* endpoints (customer management) require
a separate master key.
Todo real menos el partner telco
All real except the telco partner
Contratos, firma, estados, audit, webhooks, rate-limits — todo
el plano funcional es real y persiste en SQLite. La única pieza
"mockeable" es el adaptador hacia el SMSC (Kannel) y el PBX
(Asterisk): por defecto en modo mock, y conmutable
a live via AMI_TELCO_MODE cuando el
partner telco aporte credenciales SMPP y trunk SIP.
Contracts, signing, state machine, audit log, webhooks,
rate-limits — the entire functional plane is real and persists
to SQLite. The only "mockable" piece is the adapter towards the
SMSC (Kannel) and the PBX (Asterisk): mock by default,
switchable to live via AMI_TELCO_MODE
once the telco partner supplies SMPP credentials and a SIP trunk.
Autenticación
Authentication
| Nivel | Level | Header | Formato | Format | Cubre | Covers |
|---|---|---|---|---|---|---|
| 1 — customer | Authorization: Bearer ... |
amik_live_<48hex> | Contratación + admin del MID | Contracting + MID admin | ||
| 2 — agent | Authorization: Bearer ... |
amiagt_live_<64hex> | SMS y voz scoped a UN MID | SMS and voice scoped to ONE MID | ||
| admin | Authorization: Bearer ... |
AMI_ADMIN_KEY (env) | CRUD de customer-accounts | CRUD of customer-accounts | ||
| telco | X-Telco-Key |
AMI_TELCO_INBOUND_KEY (env) | Webhooks del partner (/v1/_telco/*) | Partner webhooks (/v1/_telco/*) |
Cómo se obtiene cada uno
How to get each one
- API key del customer — creada por el admin concreated by the admin with
POST /v1/admin/customers. Devuelta una sola vez en plano.Returned in plaintext once. - agent_token — devuelto al activar la MID conreturned when activating the MID with
POST /v1/mobile-identities/activate. Una sola vez.One time only. - Admin master key — se setea en la variable de entornoset in the environment variable
AMI_ADMIN_KEY. Nunca se devuelve por la API.Never returned by the API. - Telco inbound key — envenv
AMI_TELCO_INBOUND_KEY, compartida con Kannel/Asterisk en la VPS del partner.shared with Kannel/Asterisk on the partner VPS.
Rotación
Rotation
Si sospechas de filtración de un agent_token, hard-rota con:
If you suspect an agent_token leak, hard-rotate with:
curl -X POST https://api.protocolami.com/v1/mobile-identities/$MID/rotate-token \ -H "Authorization: Bearer $AMI_API_KEY"
client.rotate_agent_token(mid)
await client.rotateAgentToken(mid);
El token anterior queda invalidado al instante. La respuesta trae el nuevo agent_token en plano (única vez).
The previous token is invalidated instantly. The response returns the new agent_token in plaintext (one time only).
Flujo de contratación
Contracting flow
Seis pasos: request → offer → customer-data → contract → sign → activate. Cada paso devuelve el estado de la SIMRequest que actúa como máquina de estados (ver §17.6 del spec).
Six steps: request → offer → customer-data → contract → sign → activate. Each step returns the SIMRequest state which acts as the state machine (see §17.6 of the spec).
1. SIMRequest + Offer
curl -X POST https://api.protocolami.com/v1/sim-requests \
-H "Authorization: Bearer $AMI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"country":"ES","sim_type":"eSIM","capabilities":["sms","voice"]}'sim = client.request_number(country="ES",
capabilities=["sms","voice"],
agent_name="agent01")
offer_id = sim.id # OfferAccepted.idconst { simRequest, offer } = await client.requestNumber({
country: "ES", capabilities: ["sms","voice"], agentName: "agent01",
});2. Accept offer
curl -X POST https://api.protocolami.com/v1/offers/$OFFER_ID/accept \ -H "Authorization: Bearer $AMI_API_KEY"
client.accept_offer(offer.id)
await client.acceptOffer(offer.id);
3. Customer data
curl -X POST https://api.protocolami.com/v1/sim-requests/$SIM_ID/customer-data \
-H "Authorization: Bearer $AMI_API_KEY" \
-d '{"customer":{"legal_name":"Acme S.L.","tax_id":"B12345678","billing_email":"billing@acme.test","address":"Madrid, Spain","representative_name":"Ada Lovelace"}}'customer = client.submit_customer_data(
sim_request_id=sim.sim_request_id,
legal_name="Acme S.L.", tax_id="B12345678",
billing_email="billing@acme.test",
address="Madrid, Spain",
representative_name="Ada Lovelace",
)4. Contract → 5. Sign → 6. Activate
POST /v1/contracts crea el contrato y devuelve un
signature_url con el signing_token de
128 bits. El firmante humano abre esa URL y hace clic; si
automatizas el flujo, POST /v1/contracts/{id}/mock-sign
es el atajo programático. Después, POST /v1/mobile-identities/activate
devuelve la MID activa con el agent_token en plano.
POST /v1/contracts creates the contract and returns
a signature_url with the 128-bit signing_token.
A human signer opens that URL and clicks; if you automate the
flow, POST /v1/contracts/{id}/mock-sign is the
programmatic shortcut. Then POST /v1/mobile-identities/activate
returns the active MID with the agent_token in plaintext.
contract = client.create_contract(offer_id=offer.id, customer_id=customer.id) client.mock_sign(contract.id) # o abrir contract.signature_url en navegador identity = client.activate_identity(contract.id) # identity.agent_token disponible AQUÍ — una sola vez print(identity.phone_number, identity.agent_token)
Atajo todo-en-uno
One-shot helper
Los SDKs exponen provision_number() que hace los 6
pasos en una sola llamada y devuelve {mid, phone, agent_token}.
The SDKs expose provision_number() which runs all
6 steps in a single call and returns {mid, phone, agent_token}.
SMS
SMS
Enviar SMS saliente
Send outbound SMS
Auth: agent_token. El SMS sale en estado queued;
el DLR del SMSC (o el simulador mock en dev) lo lleva a
sent y luego delivered.
Auth: agent_token. SMS goes out in queued;
the SMSC's DLR (or the mock simulator in dev) takes it through
sent and then delivered.
agent.send_sms(to="+34611000000", body="Hello")
await agent.sendSms({ to: "+34611000000", body: "Hello" });curl -X POST https://api.protocolami.com/v1/agent/sms/send \
-H "Authorization: Bearer $AGENT_TOKEN" \
-d '{"to":"+34611000000","body":"Hello"}'ami.send_sms(to="+34611000000", body="Hello")
Listar SMS
List SMS
msgs = agent.list_sms(limit=20, direction="outbound")
for m in msgs:
print(m.id, m.status, m.body)curl "https://api.protocolami.com/v1/agent/sms?limit=20&direction=outbound" \ -H "Authorization: Bearer $AGENT_TOKEN"
SMS entrante
Inbound SMS
Llega al backend vía el webhook del SMSC en
POST /v1/_telco/sms/inbound. Se asocia automáticamente
al MID correspondiente al número receptor. El agente lo ve en
list_sms(direction="inbound") o (mejor) recibe
un webhook saliente sms.inbound en su URL registrada.
Arrives at the backend via the SMSC webhook at
POST /v1/_telco/sms/inbound. Auto-associates to the
MID matching the destination number. The agent sees it in
list_sms(direction="inbound") or (better) receives
an outbound sms.inbound webhook at its registered URL.
Estados
Statuses
| queued | aceptado, esperando salir | accepted, awaiting send |
| sent | cursado al SMSC, en camino | sent to SMSC, in flight |
| delivered | DLR final positivo | final positive DLR |
| failed | DLR de fallo — retry automático hasta 3 veces | failure DLR — auto-retried up to 3 times |
| received | MO entrante | inbound MO |
Voz · bridge-by-API
Voice · bridge-by-API
Recordatorio: AMI NO ejecuta voz Realtime.
AMI es la pipa SIP/RTP. El cerebro de la conversación vive en tu
callback_sip_uri.
Reminder: AMI does NOT run real-time voice.
AMI is the SIP/RTP pipe. The conversation brain lives at your
callback_sip_uri.
Originar una llamada saliente
Place an outbound call
call = agent.place_call(
to="+34600999888",
callback_sip_uri="sip:proj@sip.api.example;transport=tls",
)
print(call.id, call.status) # initiatedconst call = await agent.placeCall({
to: "+34600999888",
callbackSipUri: "sip:proj@sip.api.example;transport=tls",
});curl -X POST https://api.protocolami.com/v1/agent/calls/place \
-H "Authorization: Bearer $AGENT_TOKEN" \
-d '{"to":"+34600999888","callback_sip_uri":"sip:proj@sip.api.example;transport=tls"}'Colgar una llamada
Hang up a call
agent.hangup_call(call.id)
await agent.hangupCall(call.id);
curl -X POST https://api.protocolami.com/v1/agent/calls/$CALL_ID/hangup \ -H "Authorization: Bearer $AGENT_TOKEN"
Llamadas entrantes
Inbound calls
Configura un inbound_sip_uri por MID. Cuando entra
una llamada al número, el PBX consulta a AMI a dónde reenviarla
y la bridgea por SIP a tu URI configurada. Sin URI configurado,
la llamada se rechaza limpiamente con 486 Busy Here.
Configure an inbound_sip_uri per MID. When a call
comes in to the number, the PBX asks AMI where to forward and
bridges it via SIP to your configured URI. Without a configured
URI, the call is cleanly rejected with 486 Busy Here.
client.set_inbound_sip_uri(mid,
"sip:agent@your-pbx.example;transport=tls")curl -X POST https://api.protocolami.com/v1/mobile-identities/$MID/inbound-config \
-H "Authorization: Bearer $AMI_API_KEY" \
-d '{"inbound_sip_uri":"sip:agent@your-pbx.example;transport=tls"}'Lifecycle de una llamada
Call lifecycle
| initiated → ringing → in_progress → completed | camino feliz | happy path |
| failed | error técnico (retry automático si pre-answer) | technical error (auto-retry if pre-answer) |
| no_answer | timeout sin contestar (retry auto) | timeout no answer (auto-retry) |
| busy | línea ocupada (NO se reintenta) | line busy (NOT retried) |
| cancelled | hangup explícito antes de answer | explicit hangup before answer |
Webhooks
AMI te hace POST a una URL tuya cuando ocurre un evento del
MID. Firmamos con HMAC-SHA256 sobre timestamp.body
para que puedas verificar autenticidad y rechazar replays.
AMI POSTs to a URL of yours when an event happens for a MID.
We sign with HMAC-SHA256 over timestamp.body so you
can verify authenticity and reject replays.
Registrar un webhook
Register a webhook
wh = client.create_webhook(mid,
url="https://your-app.example/ami/hook",
events=["sms.inbound","call.completed"])
# wh.secret está aquí UNA SOLA VEZ — guárdalo
print(wh.secret)curl -X POST https://api.protocolami.com/v1/mobile-identities/$MID/webhooks \
-H "Authorization: Bearer $AMI_API_KEY" \
-d '{"url":"https://your-app.example/ami/hook","events":["sms.inbound","call.completed"]}'Eventos disponibles
Available events
| sms.inbound | MO recibido en el MID | MO received at the MID |
| sms.delivered | DLR positivo de MT enviado | positive DLR for sent MT |
| sms.failed | DLR de fallo | failure DLR |
| call.inbound | llamada entrante (antes de answer) | inbound call (before answer) |
| call.completed | llamada terminada con duración | call ended with duration |
| call.failed | llamada caída (failed/no_answer/busy/cancelled) | call dropped (failed/no_answer/busy/cancelled) |
| * | wildcard — todos | wildcard — all |
Verificar la firma en tu handler
Verify the signature in your handler
from ami.webhooks import verify_signature
def my_handler(request):
body = request.body
sig = request.headers["X-Ami-Signature"]
ts = request.headers["X-Ami-Timestamp"]
if not verify_signature(secret="whsec_...",
body=body,
signature_header=sig,
timestamp_header=ts):
return 401
payload = json.loads(body)
# payload = {"event": "sms.inbound", "mid": "mid_...", "data": {...}, "delivered_at": "..."}
...import { verifySignature } from "@ami-protocol/sdk/webhooks";
export async function handler(req) {
const body = await readRawBody(req);
const sig = req.headers["x-ami-signature"];
const ts = req.headers["x-ami-timestamp"];
const ok = verifySignature({
secret: process.env.AMI_WEBHOOK_SECRET,
body, signatureHeader: sig, timestampHeader: ts,
});
if (!ok) return new Response(null, { status: 401 });
const payload = JSON.parse(body);
...
}# pseudocode — equivalente en cualquier lenguaje
ts = headers["X-Ami-Timestamp"]
sig_header = headers["X-Ami-Signature"] # "sha256=<hex>"
if abs(now() - int(ts)) > 300: reject("stale")
expected = "sha256=" + hmac_sha256(secret, ts + "." + raw_body).hex()
if not constant_time_eq(expected, sig_header): reject("bad sig")Política de reintentos
Retry policy
AMI reintenta hasta 4 veces con backoff [0.5s, 2s, 8s].
Tras 10 fallos consecutivos el webhook se auto-deshabilita
(status disabled). Defensa contra SSRF: validamos
la URL antes de cada delivery (no solo al registrar) y rechazamos
redirects 3xx automáticos.
AMI retries up to 4 times with backoff [0.5s, 2s, 8s].
After 10 consecutive failures the webhook auto-disables
(status disabled). SSRF defense: we validate the
URL before each delivery (not only at register time) and reject
automatic 3xx redirects.
Rate limits y spending
Rate limits and spending
Cada MID tiene topes configurables: SMS/hora, SMS/día, llamadas/hora, llamadas/día, budget mensual en EUR, y allowlist de prefijos de país. El backend hace enforcement antes de cursar al telco — si bloquea, devuelve 429 con la razón concreta.
Every MID has configurable caps: SMS/hour, SMS/day, calls/hour, calls/day, monthly EUR budget, and country-prefix allowlist. Backend enforces before cursing to telco — if blocked, returns 429 with the specific reason.
Defaults al activar
Defaults at activation
- sms_per_hour: 60 · sms_per_day: 500
- calls_per_hour: 20 · calls_per_day: 200
- monthly_budget_eur: 100.00
- allowed_country_prefixes:
["+34"](España)(Spain)
Cambiar los límites
Change the limits
client.update_limits(mid,
sms_per_day=1000,
monthly_budget_eur=50,
allowed_country_prefixes=["+34","+33","+1"])curl -X POST https://api.protocolami.com/v1/mobile-identities/$MID/limits \
-H "Authorization: Bearer $AMI_API_KEY" \
-d '{"sms_per_day":1000,"monthly_budget_eur":50}'Ver uso en tiempo real
Real-time usage
u = agent.usage()
print(f"SMS today: {u.sms_count_today} / {u.sms_per_day}")
print(f"Spend: €{u.spend_this_month_eur} / €{u.monthly_budget_eur}")curl https://api.protocolami.com/v1/agent/usage \ -H "Authorization: Bearer $AGENT_TOKEN"
Razones de bloqueo (429)
Block reasons (429)
country_not_allowedsms_hourly_limit_exceeded·sms_daily_limit_exceededcalls_hourly_limit_exceeded·calls_daily_limit_exceededmonthly_budget_exceeded
Admin · multi-tenancy
Los endpoints /v1/admin/* gestionan customers (cuentas
con su propia API key). Auth: master key
AMI_ADMIN_KEY (env), separada de la API key del customer.
/v1/admin/* endpoints manage customers (accounts
with their own API key). Auth: master key
AMI_ADMIN_KEY (env), separate from any customer's API key.
Crear un customer-account
Create a customer-account
curl -X POST https://api.protocolami.com/v1/admin/customers \
-H "Authorization: Bearer $AMI_ADMIN_KEY" \
-d '{"name":"Acme Robotics","billing_email":"billing@acme.test"}'
# devuelve api_key UNA SOLA VEZListar / rotar / suspender
List / rotate / suspend
# listar
curl https://api.protocolami.com/v1/admin/customers \
-H "Authorization: Bearer $AMI_ADMIN_KEY"
# rotar API key (hard rotate)
curl -X POST https://api.protocolami.com/v1/admin/customers/$ID/rotate-key \
-H "Authorization: Bearer $AMI_ADMIN_KEY"
# suspender / reactivar
curl -X POST https://api.protocolami.com/v1/admin/customers/$ID/suspend \
-H "Authorization: Bearer $AMI_ADMIN_KEY" \
-d '{"reason":"non_payment"}'
curl -X POST https://api.protocolami.com/v1/admin/customers/$ID/activate \
-H "Authorization: Bearer $AMI_ADMIN_KEY"Aislamiento entre customers
Isolation between customers
Cada recurso (sim_request, contract, MID, customer legal) lleva
account_id desde su creación. El backend filtra todo
acceso por este campo — un customer A no puede ver, mutar ni
operar ningún recurso de B. El intento devuelve 404 (no 403)
para no leakear la existencia del id.
Every resource (sim_request, contract, MID, legal customer)
carries account_id from creation. The backend
filters all access by this field — customer A cannot see,
mutate or operate any resource of B. The attempt returns 404
(not 403) to avoid leaking the id's existence.
Códigos de error
Error codes
| HTTP | error | Significado | Meaning |
|---|---|---|---|
| 400 | invalid_* | campo malformado | malformed field |
| 400 | missing_fields | faltan campos requeridos | missing required fields |
| 401 | unauthorized | API key inválida o faltante | invalid or missing API key |
| 401 | invalid_agent_token | agent_token inválido | invalid agent_token |
| 401 | unauthorized_admin | admin master key inválida | invalid admin master key |
| 404 | *_not_found | recurso no existe o pertenece a otro account | resource not found or owned by another account |
| 409 | invalid_state / *_not_active | transición no permitida o recurso suspended | transition not allowed or suspended resource |
| 409 | webhook_limit_reached | 10 webhooks por MID max | 10 webhooks per MID max |
| 429 | sms_hourly_limit_exceeded | SMS/hora superado | SMS/hour exceeded |
| 429 | monthly_budget_exceeded | presupuesto mensual agotado | monthly budget depleted |
| 429 | country_not_allowed | prefijo de país no en la allowlist | country prefix not in allowlist |
| 503 | telco_inbound_disabled | AMI_TELCO_INBOUND_KEY no configurada | AMI_TELCO_INBOUND_KEY not set |
Reintentos
Retries
Los SDKs reintentan GET en 5xx con backoff exponencial. POST NO se reintenta automáticamente — duplicar un SMS o un contrato sobre un blip es peor que devolver el error.
The SDKs retry GETs on 5xx with exponential backoff. POSTs are NOT auto-retried — duplicating an SMS or a contract on a blip is worse than surfacing the error.
SDKs
| SDK | Package | Repo | Status |
|---|---|---|---|
| Python ≥ 3.9 | ami-protocol | sdk/python | 0.1.0 |
| TypeScript / Node ≥ 18 | @ami-protocol/sdk | sdk/typescript | 0.1.0 |
| MCP server | ami_mcp.py | ami_mcp.py | 23 tools |
Conectar tu cliente MCP
Connect your MCP client
Apunta tu cliente MCP (streamable-http) a:
Point your MCP client (streamable-http) to:
https://mcp.protocolami.com/mcp/
REST direct
Para clientes no-MCP, la API REST tiene 47 endpoints documentados en /openapi.json (OpenAPI 3.1) y /spec (markdown/HTML con ejemplos).
For non-MCP clients, the REST API has 47 endpoints documented at /openapi.json (OpenAPI 3.1) and /spec (markdown/HTML with examples).