API de acciones

Expone verbos, no filas. No lista clientes, no lee facturas, no publica tablas. Lo único que sabe hacer es ejercer una acción declarada como pública, con la autorización que su dueño encendió, y contarte con precisión qué pasó.

Autenticación

Una clave del workspace, no una sesión de persona: autentica una integración. Authorization: Bearer nk_…. La clave nace acotada a unos alcances y con caducidad; se ve una sola vez, al crearla.

Idempotencia

Manda Idempotency-Key con un valor único por encargo. Un reintento por timeout con la misma clave no vuelve a ejecutar: contesta duplicate con lo que pasó la primera vez. Sin esa cabecera, un reintento es un encargo nuevo. La protección dura 24 h.

Tres desenlaces, no dos

done — hecho. refused — no se hizo, y por qué. pending_approval (202) — queda esperando una firma y puede terminar horas después; te avisamos por webhook cuando se resuelva. Un contrato de dos desenlaces obliga a que el tercero se disfrace de otro.

miira.lead_create v1

POST /api/v1/actions/miira.lead_create

Alcance de la clave
miira.lead_create@1
Permiso del workspace
api.miira.lead_create — nace apagado

Hacen falta los dos: una clave con ese alcance, y que el dueño del workspace haya encendido ese permiso. Tener la clave no basta.

Lo que mandas

campotiporeglas
submissionIdstring (uuid)obligatorio
source"web_form" | "referral" | "api" | "import" | "event" | "other"obligatorio
namestringopcionalmáx. 256
emailstring (email)opcionalmáx. 320
phonestringopcionalmáx. 40
fieldsmap<string, unknown>opcional
consentobjectopcional

Lo que recibes

campotiporeglas
outcome"created" | "existing" | "ambiguous" | "rejected"obligatorio
clientIdstring | nullobligatorio
reason"honeypot" | "invalid_email" | "disposable_email" | "invalid_identity" | nullobligatorio

Ejemplo

curl -X POST https://niiko.org/api/v1/actions/miira.lead_create \
  -H "Authorization: Bearer nk_…" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "submissionId": "01890a5d-ac96-774b-bcce-b302099a8057",
  "source": "web_form"
}'

Motivos por los que puede no hacerse

Del vocabulario que esta acción declara. Un motivo fuera de esta lista es un fallo del servidor, no un estado del producto.

Los motivos, y qué hacer con cada uno

El código HTTP lo elige el remedio, no el parecido: quién tiene que hacer algo, y qué.

motivocódigoqué significa
invalid_input400El payload no valida contra el contrato. Es lo único de esta lista que puedes arreglar tú solo.
unauthorized401La clave no vale. No se distingue entre inexistente, revocada, vencida o sin el alcance: distinguirlo convertiría esta puerta en un oráculo para quien esté probando claves. El estado exacto de tu clave lo ves en tu panel.
grant_off403El workspace no ha encendido esta capacidad. No es una prohibición: es una perilla que le toca a su dueño.
origin_denied403Este origen no puede ejercer esta acción, y no hay perilla que lo cambie.
not_autonomous409Necesita una aprobación y este camino no puede esperarla.
stale409El mundo cambió entre que lo pediste y que se iba a hacer. Vuelve a leer antes de reintentar.
duplicate409Ya pasó. Trae la clave y cómo terminó la primera vez. No se devuelve el resultado original: solo se guarda QUE ocurrió.
in_flight409Otra petición con la misma clave está corriendo ahora. Trae Retry-After.
not_exposed404Esa acción no está abierta al exterior. Puede existir dentro del producto; lo que no existe es su puerta.
version_retired410Esa versión ya se retiró. Sale con Sunset y las fechas dentro: existió, ya no.
rate_limited429Cupo por clave. Trae Retry-After.
internal_error500Un fallo nuestro. Es lo único de esta lista que no es una decisión ni un estado.