La API de Cannis: tu organización y tu cuenta
Dos cosas se hacen por la API. Una organización que usa Cannis OS recibe las solicitudes de ingreso que la gente completa en su propio sitio web, sin mandar a nadie a otra página: dos consultas abiertas —provincias y localidades— y el alta de la solicitud, con un token de la organización. Y una persona maneja su cuenta de Cannis desde una app: se registra, ingresa, ve sus datos y sus organizaciones, y entra a Cannis Pro.
01 Antes de empezar
Cada solicitud que llega por la API entra a Cannis OS, en «Solicitudes de afiliación» de tu organización, marcada como llegada por su sitio, y la organización recibe un aviso por correo. Desde ahí se aprueba o se rechaza como cualquier otra.
- El acceso se pide. Cannis lo configura para tu organización y te entrega el token junto con los nombres definitivos de los campos.
- El alta se manda desde el servidor de tu sitio. El formulario que ve la persona le habla a tu servidor, y tu servidor a Cannis: el token nunca viaja al navegador.
- El reCAPTCHA se resuelve en el formulario. La persona lo resuelve en tu sitio y tu servidor manda el resultado junto con la solicitud.
02 Base y formato
Todo cuelga del prefijo /api y responde JSON. Es una API sin estado: no usa cookies ni
sesión. Mandá siempre el encabezado Accept: application/json: sin él, algunos errores
—como el de demasiados pedidos— pueden llegar como una página web en lugar de JSON.
Las respuestas de la API de tu organización no tienen todas la misma forma: las dos consultas
devuelven un arreglo y el alta, un objeto con su status. Cada sección muestra la suya.
La API de tu cuenta vive bajo /api/v1 y responde siempre el mismo sobre:
ok, mensaje, datos y errores.
https://ns2.cannis.org/api
Las dos consultas abiertas aceptan hasta 60 pedidos por minuto desde una misma IP. Si las usás para llenar un selector, guardá la respuesta en tu sitio: las provincias y las localidades casi no cambian.
03 Autenticación
Provincias y localidades son abiertas. El alta no: va con un token que se emite
por organización y viaja en el encabezado Authorization. El token
identifica a la organización, así que no hace falta —ni se puede— mandar cuál es: la solicitud
queda asociada a la del token.
Authorization: Bearer <tu-token> Accept: application/json
- Un token puede tener fecha de vencimiento o no tenerla.
- Un token revocado deja de funcionar al instante.
- Queda registrado cada uso del token.
- El token es secreto: va en el servidor de tu sitio, nunca en el código que corre en el navegador. Quien lo tenga puede cargar solicitudes a nombre de tu organización; si se filtró, pedí que lo revoquen.
04 Provincias
Devuelve las provincias argentinas con el identificador que después espera el alta de solicitud. Sin parámetros. La respuesta es un arreglo.
[
{ "id_provincia": 1, "nombre": "Buenos Aires" },
{ "id_provincia": 2, "nombre": "Catamarca" }
]
curl -H "Accept: application/json" https://ns2.cannis.org/api/provincias
05 Localidades
Las localidades de una provincia: el clásico segundo selector. La respuesta es un arreglo.
id_provincia que devolvió la consulta de provincias. Tiene que
existir.
[
{ "id": 1042, "nombre": "Rosario" },
{ "id": 1043, "nombre": "Venado Tuerto" }
]
Si falta id_provincia o no existe, los errores vienen por campo:
{
"message": "Parámetros inválidos",
"errors": {
"id_provincia": [ "El campo id provincia es obligatorio." ]
}
}
curl -H "Accept: application/json" "https://ns2.cannis.org/api/localidades?id_provincia=21"
Guardate el id: es lo que después va en el campo
localidad del alta de solicitud, igual que el
id_provincia va en provincia.
06 Solicitud de ingreso
Es el alta del formulario de ingreso que una organización publica en su propio sitio: la persona completa sus datos ahí, tu servidor los manda y la solicitud entra a Cannis OS, en «Solicitudes de afiliación» de tu organización.
Se envía como multipart/form-data, porque admite archivos, y desde tu
servidor. Está protegido con reCAPTCHA: la persona lo resuelve en el formulario y tu
servidor manda el resultado.
Los nombres de campo de esta página describen qué datos pide el alta, no cómo se llaman exactamente en el cuerpo del pedido. Los nombres definitivos te los pasamos junto con el token, cuando configuramos el acceso de tu organización.
AAAA-MM-DD.
id_provincia de la consulta de provincias.
id de la consulta de localidades.
curl -X POST https://ns2.cannis.org/api/post/solicitud_paciente \ -H "Authorization: Bearer <tu-token>" \ -H "Accept: application/json" \ -F "nombre=Lucía" \ -F "apellido=Fernández" \ -F "documento=30111222" \ -F "fecha_nacimiento=1983-04-12" \ -F "[email protected]" \ -F "celular=3415551234" \ -F "provincia=21" \ -F "localidad=1042" \ -F "calle=San Martín" \ -F "numero=1234" \ -F "reprocann=1" \ -F "consentimiento=1" \ -F "captcha=<resultado-del-recaptcha>" \ -F "[email protected]"
{
"status": "success",
"message": "Tu solicitud ha sido enviada exitosamente."
}
07 Errores
Los errores del alta traen "status": "error". Los de validación vienen en
messages, ya redactados en español y con el nombre legible del campo: se pueden
mostrar tal cual al lado del formulario.
{
"status": "error",
"messages": [
"Email: Ya existe un registro con ese Email en esta ONG.",
"Documento: El Documento debe contener entre 8 y 9 números."
]
}
Si el reCAPTCHA no verifica, el 422 trae errors —un objeto con el campo y sus
mensajes— en lugar de messages:
{
"status": "error",
"errors": {
"captcha": [ "Error en la verificación de reCAPTCHA." ]
}
}
Sin token, o con uno que no sirve, la respuesta es un objeto con status y
message:
{
"status": "error",
"message": "Token API no proporcionado."
}
Authorization o no empieza con Bearer.
Accept: application/json llega como
{"message": "Too Many Attempts."}, con el encabezado
Retry-After: los segundos que hay que esperar.
¿Tu organización quiere recibir solicitudes desde su sitio? Pedí el acceso por WhatsApp: Cannis lo configura para tu organización. Si todavía no está en Cannis, sumala primero.
08 La API de tu cuenta
Es la API que usa la app de Cannis, y está abierta a cualquier cuenta: registrarse, ingresar, ver y cambiar los datos propios, saber qué organizaciones opera la persona y entrar a Cannis Pro. Una cuenta sola, la misma del sitio y de todos los productos. Los nombres de los campos son los reales.
https://ns2.cannis.org/api/v1
Toda respuesta trae el mismo sobre. ok dice si salió; mensaje es un texto en
español que se puede mostrar; datos es lo pedido y errores, en un 422, los
mensajes por campo.
{ "ok": true, "mensaje": "Listo.", "datos": { "…": "…" }, "errores": null }
{ "ok": false, "mensaje": "Qué pasó, en claro", "datos": null, "errores": { "campo": [ "mensaje" ] } }
Para usar esta API hace falta una clave de aplicación: identifica a la app, no a
la persona, y Cannis la entrega a pedido. Va en el encabezado X-Cannis-App de cada
pedido, incluidos el registro y el ingreso; sin ella la respuesta es 401. Una clave se
puede revocar en el acto, y cada llamada queda registrada de nuestro lado.
El registro y el ingreso devuelven un token que identifica a la persona y al dispositivo.
Viaja en cada pedido como Authorization: Bearer. Vence a los 90 días sin uso y cada uso lo
renueva; cambiar la contraseña cierra todas las otras sesiones. Un token por dispositivo:
dispositivo es el nombre que la app le pone («iPhone de Ana»).
X-Cannis-App: <clave-de-aplicación> Authorization: Bearer <token-de-usuario> Accept: application/json
Crea la cuenta y devuelve el primer token. Hasta cinco intentos por minuto desde una misma IP.
password_confirmation.AAAA-MM-DD, anterior a hoy.{
"ok": true, "mensaje": "Cuenta creada.",
"datos": {
"token": "12|Qx9…",
"vence": "2027-01-29T14:05:00-03:00",
"usuario": { "…": "los mismos datos de GET /api/v1/usuario" }
},
"errores": null
}
La cuenta queda creada en Cannis y, en el acto, en Cannis Pro con el mismo número de cuenta.
Un email que ya existe responde 422 con errores.email.
Email y contraseña, y devuelve un token con la misma forma que el registro. Credenciales incorrectas: 422 con errores.email.
curl -X POST https://ns2.cannis.org/api/v1/ingresar \
-H "X-Cannis-App: <clave-de-aplicación>" \
-H "Accept: application/json" -H "Content-Type: application/json" \
-d '{"email":"[email protected]","password":"…","dispositivo":"iPhone de Ana"}'
Los datos completos de la cuenta: el perfil, las organizaciones que la persona opera con el rol que tendría en Cannis Pro y si esa organización tiene plan, las ONG de las que es socia (sin ningún dato de salud) y a qué productos puede entrar hoy.
{
"ok": true, "mensaje": "Listo.",
"datos": { "usuario": {
"id": 5120, "nombre": "Ana", "apellido": "Pérez", "apodo": "ana.perez",
"email": "[email protected]", "email_verificado": true,
"nacimiento": "1990-05-12", "celular": "5491155551234",
"rol": { "codigo": "ONG", "etiqueta": "ONG" }, "avatar_url": null,
"organizaciones": [
{ "origen": "ONG", "id": 12, "nombre": "Asociación Civil Raíces", "rol": "AD",
"cannis_pro": { "habilitada": true, "plan": "gratis", "estado": "AC" } }
],
"afiliaciones": [ { "ong_id": 30, "nombre": "Cultivo Sur", "estado": "AC", "desde": "2024-11-02" } ],
"productos": { "cannis_os": true, "cannis_pro": true }
} },
"errores": null
}
Cambia cualquier subconjunto de nombre, apellido,
nacimiento y celular (null borra el celular). Devuelve
el usuario completo. Con /api/v1/usuario/contrasena se cambia la contraseña:
actual, nueva y nueva_confirmation; si la actual no es,
422 con errores.actual.
Sólo la lista de organizaciones del usuario completo: donde la persona es del equipo, con su rol y lo que tienen de Cannis Pro. Es la lista de la que se elige para pedir un acceso.
errores, en español.Retry-After.
Lo que hoy no hace la API: recuperar la contraseña ni verificar el email. Las dos cosas se hacen
desde el sitio, con la misma cuenta. El contrato formal de la v1, en OpenAPI, está en el
repositorio de Cannis (docs/api/openapi.yaml).
09 Entrar a Cannis Pro
Cannis Pro es el módulo de cultivo de Cannis. Usa la misma cuenta: una persona que se registra en Cannis existe en Cannis Pro en el acto, con el mismo número de cuenta, y al revés. Lo que decide si una organización puede operar ahí es Cannis: le da un plan y, desde ese momento, su equipo entra sin otra contraseña. Desde la app se entra con un acceso de un solo uso.
Pide un acceso a Cannis Pro para una de las organizaciones que la persona opera. Devuelve una URL que la app abre en el navegador: Cannis Pro la canjea y entra con esa organización activa. El acceso dura dos minutos y sirve una sola vez.
ONG u ORGEl origen de la organización, tal como vino en el usuario.id de esa organización.{
"ok": true, "mensaje": "Listo.",
"datos": { "url": "https://app.cannis.pro/acceso-cannis?token=…", "vence_en": 120 },
"errores": null
}
Entre los dos sistemas no viaja ninguna contraseña en claro, y cada llamada va firmada. Un email que ya tiene cuenta en Cannis no se puede volver a registrar en Cannis Pro: esa persona entra con su contraseña de Cannis. Esa parte de la API es sólo entre Cannis y Cannis Pro y no se publica.