Saltar al contenido
API pública

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.
Cómo viaja una solicitud
1 La persona completa el formulario de tu sitio y el reCAPTCHA
2 Tu servidor la manda a Cannis con el token
3 Cannis valida los datos y el reCAPTCHA
4 La solicitud entra a Cannis OS y llega el aviso por correo

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.

BaseHTTPS
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.

EncabezadoBearer
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

GET /api/provincias Sin token

Devuelve las provincias argentinas con el identificador que después espera el alta de solicitud. Sin parámetros. La respuesta es un arreglo.

Respuesta · 200
JSONArreglo
[
  { "id_provincia": 1, "nombre": "Buenos Aires" },
  { "id_provincia": 2, "nombre": "Catamarca" }
]
Ejemplo
curlbash
curl -H "Accept: application/json" https://ns2.cannis.org/api/provincias

05 Localidades

GET /api/localidades Sin token

Las localidades de una provincia: el clásico segundo selector. La respuesta es un arreglo.

Parámetros de consulta
id_provincia* entero El id_provincia que devolvió la consulta de provincias. Tiene que existir.
Respuesta · 200
JSONArreglo
[
  { "id": 1042, "nombre": "Rosario" },
  { "id": 1043, "nombre": "Venado Tuerto" }
]
Respuesta · 422

Si falta id_provincia o no existe, los errores vienen por campo:

JSON422
{
  "message": "Parámetros inválidos",
  "errors": {
    "id_provincia": [ "El campo id provincia es obligatorio." ]
  }
}
Ejemplo
curlbash
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.

POST /api/post/solicitud_paciente Con token

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.

Identidad y contacto
nombre* texto · 100 Nombre de la persona.
apellido* texto · 100 Apellido.
documento* 8 a 9 dígitos Sólo números. Único por organización: si esa persona ya mandó una solicitud, la segunda se rechaza.
numero_tramite texto · 20 Número de trámite del DNI. Opcional.
fecha_nacimiento* fecha Formato AAAA-MM-DD.
email* email · 255 Único por organización.
celular* texto · 20 Único por organización.
profesion texto · 100 Opcional.
Domicilio
provincia* entero El id_provincia de la consulta de provincias.
localidad* entero El id de la consulta de localidades.
calle* texto · 255 Calle.
numero* texto · 10 Altura.
REPROCANN y consentimiento
reprocann* booleano Si la persona ya tiene REPROCANN.
estado_reprocann texto · 5 El estado del trámite, si lo sabe.
consentimiento* tiene que valer 1 Sin consentimiento informado no hay solicitud. No es un formalismo: es el requisito legal.
captcha* texto El resultado del reCAPTCHA que la persona resolvió en tu formulario.
Archivos y texto libre
carnet_reprocann PDF · 5 MB El carnet de REPROCANN. Opcional.
declaracion_jurada PDF · 5 MB Declaración jurada. Opcional.
consentimiento_bilateral PDF · 5 MB Consentimiento firmado por las dos partes. Opcional.
descripcion texto Lo que la persona quiera contar de su caso.
informacion_adicional texto Campo libre para lo que tu formulario necesite guardar.
La forma del pedido
curlEjemplo ilustrativo
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]"
Respuesta · 200
JSONObjeto
{
  "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.

JSON422 · datos
{
  "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:

JSON422 · reCAPTCHA
{
  "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:

JSON401
{
  "status": "error",
  "message": "Token API no proporcionado."
}
401 Sin token Falta el encabezado Authorization o no empieza con Bearer.
403 Token inválido Está revocado, venció o no tiene una organización asociada.
422 Validación En el alta, faltan campos o están mal, hay un duplicado o el reCAPTCHA no verificó. En localidades, falta la provincia o no existe.
429 Demasiados pedidos Se pasó del límite por minuto de las consultas abiertas. Con 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.

BaseHTTPS · JSON
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.

JSONEl sobre
{ "ok": true,  "mensaje": "Listo.", "datos": { "…": "…" }, "errores": null }
{ "ok": false, "mensaje": "Qué pasó, en claro", "datos": null, "errores": { "campo": [ "mensaje" ] } }
La clave de aplicación

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 token de usuario

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»).

EncabezadoBearer
X-Cannis-App: <clave-de-aplicación>
Authorization: Bearer <token-de-usuario>
Accept: application/json
POST /api/v1/registro Sin token

Crea la cuenta y devuelve el primer token. Hasta cinco intentos por minuto desde una misma IP.

Cuerpo
nombre*texto · 100Nombre.
apellido*texto · 100Apellido.
email*emailNo puede existir ya en Cannis.
password*texto · 8 o másCon letras y números. Va con password_confirmation.
nacimiento*fechaAAAA-MM-DD, anterior a hoy.
celulartexto · 15Opcional.
acepta_terminos*booleanoTiene que ser verdadero: los términos y la política de privacidad.
dispositivotexto · 80El nombre del dispositivo, para la lista de sesiones.
Respuesta · 201
JSONObjeto
{
  "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.

POST /api/v1/ingresar Sin token

Email y contraseña, y devuelve un token con la misma forma que el registro. Credenciales incorrectas: 422 con errores.email.

curlbash
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"}'
GET /api/v1/usuario Con token

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.

Respuesta · 200
JSONObjeto
{
  "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
}
PUT /api/v1/usuario Con token

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.

GET /api/v1/usuario/organizaciones Con token

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.

Las sesiones
POST /api/v1/salir Con token Revoca el token con el que se pidió. Es el cierre de sesión de ese dispositivo.
GET /api/v1/sesiones Con token Las sesiones vivas de la cuenta: cada dispositivo, cuándo se usó por última vez y cuándo vence.
DELETE /api/v1/sesiones/{id} Con token Cierra otra sesión de la misma cuenta.
Errores de la v1
401Sin clave o sin tokenFalta la clave de aplicación o fue revocada; o falta el token, venció o se revocó. La app vuelve a la pantalla de ingreso.
422ValidaciónLos mensajes por campo vienen en errores, en español.
429Demasiados pedidosCinco por minuto en registro e ingreso, 120 en el resto, por IP; con 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.

POST /api/v1/usuario/cannis-pro/acceso Con token

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.

Cuerpo
origen*ONG u ORGEl origen de la organización, tal como vino en el usuario.
id*enteroEl id de esa organización.
Respuesta · 200
JSONObjeto
{
  "ok": true, "mensaje": "Listo.",
  "datos": { "url": "https://app.cannis.pro/acceso-cannis?token=…", "vence_en": 120 },
  "errores": null
}
403No la operaLa persona no es del equipo de esa organización.
409Sin planLa organización no tiene plan de Cannis Pro: lo pide a Cannis.
502 · 503Cannis Pro no respondióO la integración está apagada. Volver a intentar.
Cómo se conectan Cannis y Cannis Pro
1 Cada cuenta y cada organización de Cannis se copia a Cannis Pro, con el mismo número
2 Cannis le da el plan a la organización; sin plan, Pro la conoce pero no la deja operar
3 Su equipo entra desde Cannis OS o desde la app, sin otra contraseña
4 Quien se registra en Cannis Pro queda también en Cannis, con la misma cuenta

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.