Autenticación y permisos

El formato de la clave, los permisos por dominio, qué está abierto a claves y los errores que devuelven el portero y la entrada de la API.

La clave

Cada llamada lleva la clave completa en la cabecera Authorization, tal como se mostró al crearla, incluido el <id>| del principio:

Authorization: Bearer <id>|fc_live_...
  • Una clave, una cuenta. La clave accede solo a los datos de la cuenta que la creó. No hay claves para varias cuentas. (D9)
  • Sin OAuth. No hay intercambio de tokens ni refresco: la clave se manda tal cual en cada llamada. (D8)
  • No vence. Guardala como una contraseña, fuera del código y de los repositorios. Si se filtra, revocala desde la pantalla Desarrolladores: según el contrato, deja de funcionar en todos los dominios desde la llamada siguiente. (C1)
  • Lleva un |. En un archivo .env, escribila entre comillas: FC_API_KEY='<id>|fc_live_…'. Sin comillas, si cargás el archivo con source, la shell toma el | como una tubería y la variable queda vacía.
  • Revocarla corta también los webhooks atados a ella. Una suscripción queda atada a la clave que la creó o a la última clave que le cambió la URL. Cuando esa clave se revoca, deja de recibir eventos en el acto y pasa a status: disabled con disabled_reason: "key_revoked"; no se puede volver a habilitar, así que hay que crear una nueva. Las suscripciones creadas desde el panel que ninguna clave redirigió son de la cuenta y no cambian. Ningún campo de la suscripción dice a qué clave está atada: llevá vos el registro de qué clave usó cada integración. (enmienda C3 del 04-10, E18, E19, E40)
  • Tope diario de llamadas: 10.000 por día por clave en accounts y en communities, cada área por su lado. Al superarlo, 429 daily_cap_exceeded. Si el tope se puede levantar a pedido es algo que el contrato anterior decía (D16, C6) y que el de la URL única no repite: pendiente de confirmar. (D16, C6; URL única, Q6; Q20 del 14-10)
  • conversations no tiene tope diario. Lo que se limita son los envíos a WhatsApp, por el número que manda y no por la clave: ver Ritmo por número. (Q20 del 14-10)
  • Cada llamada queda registrada (clave, ruta, método, código de respuesta, hora y duración) para entender cómo se usa el piloto. No se guarda el contenido. (C2, D12)

Todas las claves son fc_live_: no hay claves de prueba ni sandbox. Lo que hagas con una clave actúa sobre datos y números reales. (C1, D17)

Permisos

Cada ruta pide un permiso y los permisos se eligen al crear la clave. Son de la forma dominio:grado: leer, escribir y, solo donde el dominio produce salida a WhatsApp, enviar u operar. (D10)

PermisoQué habilitaEstado en v0Rutas en las instantáneas
conversations:readLeer contactos, conversaciones, mensajes, etiquetas, flujos, plantillas, tableros…Abierto (etapa 1).75
conversations:writeEscribir sin enviar a WhatsApp: contactos, etiquetas, campos, tableros, notas, tickets, carpetas.Abierto (etapa 1). La superficie amplificada sigue cerrada (route_not_available).69
conversations:sendEnviar mensajes 1:1 por WhatsApp.Abierto, con las reglas de WhatsApp: ritmo por número, ventana de 24 horas y antibloqueo.8
communities:readConsultar campañas, grupos, participantes, envíos y estadísticas.Abierto.48
communities:writeEscritura sin egress a WhatsApp.En v0 solo administra las suscripciones propias de communities, que no llegan por la URL base: las suscripciones se administran con webhooks:write.5
communities:sendEnvíos a grupos que la cuenta ya administra.Denegado a claves en v0.0
communities:operateAcciones sobre la sesión de WhatsApp (sincronizar, importar, renovar link, reintentar).Denegado a claves en v0.0
accounts:readLeer la cuenta, sus números (devices), alertas y dominios propios.Según la especificación de accounts.31
accounts:writeModificar de forma reversible.Según la especificación de accounts.25
accounts:operateLas operaciones irreversibles de accounts (reset, limpieza, purga de cola y borrados).Según la especificación de accounts; no figura en D10.5
webhooks:readLeer las suscripciones de webhooks y sus entregas.Abierto. Además, la clave necesita el permiso de lectura del área de cada evento de la suscripción.3
webhooks:writeCrear, modificar, probar y borrar suscripciones de webhooks. Incluye webhooks:read.Abierto. Para elegir un evento, la clave necesita además el permiso de lectura de su área (conversations:read, communities:read o accounts:read).4
whalink:readLeer links de wha-link.wha-link no forma parte de este portal todavía.—
whalink:writeEscribir en wha-link.wha-link no forma parte de este portal todavía.—

La última columna cuenta las operaciones de cada permiso en las instantáneas de hoy; en la referencia cada operación muestra el suyo.

Los nombres pueden cambiar

Los permisos de v0 usan los nombres de D10 y se van a unificar con los roles de workspaces (Q20). El contrato llama whalink al dominio de links; la pantalla de claves puede mostrarlo como wha-link.

Qué permisos tiene tu clave

En v0, una clave no puede consultar quién es ni qué permisos tiene. Es una limitación conocida:

  • GET /api/v1/me (accounts) pide accounts:read. Con una clave sin ese permiso responde 403 permission_denied, y con el permiso, según su especificación, devuelve los datos de la cuenta, no los permisos de la clave.
  • Las rutas de claves (/api/v1/me/api-keys) responden 403 route_not_available a cualquier clave.

Qué hacer: guardá junto a la clave la lista de permisos que elegiste al crearla. Si una llamada responde 403 permission_denied, message dice cuál falta, por ejemplo: «Esta API key no tiene el permiso accounts:read.»

Qué está abierto a claves

La API se abre por radio de daño, no por dominio ni por ruta. (D21)

SuperficieQué incluyeDaño posible por llamadaEstado
ALectura y escritura sin envío a WhatsApp: contactos, etiquetas, campos, tableros, notas, tickets, listas, carpetasDatos basura en la cuentaAbierta (etapa 1)
BEnvío 1:1Un mensajeAbierta, con el permiso conversations:send y las reglas de WhatsApp (ventana de 24 horas, frenos contra spam y ritmo por número) (Q19)
CEnvío amplificado: masivos, arrancar flujos, disparadores, etiqueta que dispara un flujoN mensajes, sin tope en el pedidoFuera del piloto

El envío 1:1 pide conversations:send, un permiso aparte de conversations:write: elegilo al crear la clave solo si tu integración manda mensajes.

Ninguna clave habilita la superficie amplificada, donde una llamada produce N mensajes. En conversations son estas diez rutas, y responden 403 route_not_available con cualquier permiso: (C1)

  • broadcasts/{id}/execute y sus dos reintentos
  • contacts/{contact}/start-flow
  • flows/triggers/{uuid}/listen
  • contacts/add-tags y contacts/remove-tags
  • contacts/tags/bulk-operation
  • contacts-sync
  • contacts/import/analyze

write no habilita envío, ni siquiera por adentro: agregarle una etiqueta a un contacto puede disparar un flujo que manda mensajes, y por eso esas rutas quedan afuera.

En communities, en v0, una clave lee: Escribir solo administra las suscripciones propias de communities, que no llegan por la URL base (las suscripciones se administran con webhooks:write), y Enviar y Operar no habilitan ninguna operación. La especificación de Communities (instantánea 6f32f0b4 (árbol con cambios sin commitear)) ya no dice que las claves estén pendientes. Confirmalo con una llamada real antes de depender de eso. (enmienda C1 del 04-10)

Webhooks: webhooks:read y webhooks:write administran las suscripciones de /api/v1/webhooks y no se implican con los de accounts. Para elegir un evento, la clave necesita además el permiso de lectura de su área; ver Webhooks.

Errores

Cuando el portero o la entrada de la API rechazan una llamada, el cuerpo trae error (un código estable) y message (para personas):

{
  "error": "permission_denied",
  "message": "Esta API key no tiene el permiso `conversations:send`."
}
CódigoerrorQué pasóQué hacer
401unauthenticatedFalta la clave, no existe o fue revocada. Según el contrato de la URL única es igual en las tres áreas. De las instantáneas de hoy, solo la de communities lo documenta, con la cabecera WWW-Authenticate: Bearer; las de conversations y accounts declaran para el 401 un cuerpo con solo message. Pendiente de confirmar en conversations y accounts.Revisá la cabecera Authorization y que la clave siga activa.
403permission_deniedLa clave no tiene el permiso que pide la ruta: «Esta API key no tiene el permiso …».Creá una clave con ese permiso.
403route_not_availableLa ruta no está disponible para claves en el piloto: superficie amplificada (por ejemplo contacts/add-tags) o una ruta que no figura en la referencia.No hay permiso que pedir: ninguna clave la habilita.
403— (solo message)Lo rechazó la autorización propia del dominio, no el portero.Leé message.
404route_not_foundLa ruta no existe en la API pública: se contesta sin llegar a ninguna área.Revisá la ruta y que empiece con /api/v1/.
422—Error de validación: message y errors, con la lista de problemas por campo.Corregí los campos indicados.
429daily_cap_exceededSe superó el tope diario de llamadas de accounts o de communities (10.000 por día por clave en cada una). conversations no tiene tope diario. Trae Retry-After con los segundos que faltan para que se reinicie.Esperá lo que indica Retry-After.
429rate_limitedUn envío superó el ritmo del número por el que sale: 60 mensajes por segundo en un número oficial, 15 en coexistencia y sin límite por QR; además, 10 por minuto al mismo contacto en lo que sale por la Cloud API. Se cuenta por número, no por clave. No lo devuelve el portero sino las reglas de WhatsApp. Trae Retry-After.Esperá lo que indica Retry-After y reintentá.
429—Límite por minuto de una ruta concreta.Bajá el ritmo y reintentá.
500edge_misconfiguredLa entrada de la API no está configurada para llegar al área de la ruta y no reenvía la llamada. Es un problema de nuestro lado.Reportalo citando el X-Request-Id.
502origin_unreachableLa entrada de la API no pudo comunicarse con el área que atiende la ruta.Reintentá con espera, cada vez más larga. Si sigue, reportalo citando el X-Request-Id.
503gate_unavailableEl portero no pudo evaluar la llamada y, por seguridad, no la deja pasar. Trae Retry-After.Reintentá en unos segundos. (C6 P7)

503 gate_unavailable y 403 permission_denied son distintos a propósito: el primero es «no pude evaluar, reintentá»; el segundo, «evalué y no».

500 edge_misconfigured y 502 origin_unreachable los responde la entrada de la API, antes de llegar al área, con el mismo message: «La API no está disponible en este momento.». No traen Retry-After. Ante un 502 no hay garantía de que el área no haya recibido la llamada: si era una escritura, comprobá que no se aplicó antes de repetirla.

  • Cada respuesta trae X-Request-Id, en éxito y en error, incluidos todos los de esta tabla. Es un UUID distinto para cada pedido. Al reportar un problema, citalo junto con la hora aproximada de la llamada: con ese id soporte encuentra la llamada. No se puede consultar por el id desde la API. Ver El id del pedido. (1019)

  • Decidí por el código HTTP y por error, no por message. message es para personas: su texto y su idioma cambian según el dominio.

  • Esperá un 403 en cualquier ruta. Las especificaciones de los dominios no lo documentan en todas, y donde lo documentan el esquema trae solo message, sin error (conocido en v0).

En esta página