Integración

Eventos

Una sola puerta para que su sistema le avise a Kuida lo que pasó: un turno nuevo, una consulta atendida, un pedido de servicio. Mismo sobre para todos los tipos.

POST /v1/events hace lo mismo que los recursos (/v1/visits, /v1/appointments, …) con un formato común. Conviene cuando su sistema ya emite eventos, cuando hay que cargar mucho de una vez o cuando es más simple tener un único punto de salida hacia Kuida.

POST /v1/events
curl https://www.kuida.ar/api/v1/events \
  -H "Authorization: Bearer kd_test_…" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "id": "turno-123-atendido",
  "type": "visit.completed",
  "occurredAt": "2026-10-05T10:45:00-03:00",
  "source": {
    "system": "mi-sistema",
    "version": "3.2"
  },
  "data": {
    "patient": {
      "phone": "+54 9 342 555 0000",
      "fullName": "Paciente Demo",
      "dni": "11111111"
    },
    "visit": {
      "visitedAt": "2026-10-05T10:45:00-03:00",
      "externalId": "turno-123"
    }
  }
}'

El sobre

  • idstringobligatorio

    Su id del evento. Es la clave de idempotencia: reenviar el mismo id no repite nada.

  • schemaVersionnumber

    Versión del esquema del evento. Siempre 1 en v1.

    Default: 1

  • occurredAttimestamp

    Cuándo pasó. Default: ahora.

  • sourceobjeto

    Qué sistema lo emite, para el registro.

    › Ver 2 campos
    • systemstring
    • versionstring
  • typeenumobligatorio

    Tipo de evento. Define la forma de data.

    Valores:intake.requestedpatient.upsertedappointment.createdappointment.rescheduledappointment.cancelledvisit.completedtreatment.prescribedorder.issued

  • dataobjetoobligatorio

    Su forma depende de type: ver el catálogo de eventos.

El id lo asigna su sistema y es la clave de idempotencia del evento: reenviar el mismo id no repite nada. Use un valor derivado del hecho, como turno-123-atendido, para que un reenvío desde otra parte de su sistema también se reconozca.

Lotes

El cuerpo puede ser un evento, un array de hasta 100 o un objeto { events: [...] }. Cada evento se valida y procesa por separado: uno inválido no impide que se procesen los demás.

POST /v1/events
curl https://www.kuida.ar/api/v1/events \
  -H "Authorization: Bearer kd_test_…" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "events": [
    {
      "id": "paciente-HC-1234",
      "type": "patient.upserted",
      "data": {
        "phone": "+54 9 342 555 0000",
        "fullName": "Paciente Demo",
        "externalId": "HC-1234"
      }
    },
    {
      "id": "turno-123-creado",
      "type": "appointment.created",
      "data": {
        "externalId": "turno-123",
        "startAt": "2026-10-05T10:30:00-03:00",
        "patient": {
          "phone": "+54 9 342 555 0000"
        }
      }
    }
  ]
}'

La respuesta

Un resultado por evento, en el mismo orden en que se enviaron. El status HTTP es 200 si se aceptó al menos uno y 400 si todos fallaron por esquema.

Respuesta
{
  "object": "event_batch",
  "results": [
    {
      "id": "turno-123-atendido",
      "accepted": true,
      "status": "processed",
      "event": "evt_cm1a2b3c4d5e6f7g8h9i0j",
      "result": {
        "object": "visit",
        "id": "vis_cm1a2b3c4d5e6f7g8h9i0j"
      },
      "error": null
    }
  ]
}
  • objectstring
  • resultsarray de objetos
    › Ver 6 campos
    • idstring

      El id que envió.

    • acceptedboolean
    • statusenum

      Valores:processedduplicateunhandledinvalidfailed

    • eventstringpuede ser null

      Id del evento en Kuida (evt_…).

    • resultobjetopuede ser null
      › Ver 2 campos
      • objectstring
      • idstring
    • errorstringpuede ser null
processed
SignificadoKuida lo procesó. result indica el objeto que produjo ({ object: "visit", id: "vis_…" }).
duplicate
SignificadoYa había llegado un evento con ese id. No se repite nada; result apunta al objeto original.
unhandled
SignificadoSe guardó, pero ese tipo todavía no tiene efecto en Kuida. Reenviarlo con el mismo id responde duplicate.
invalid
SignificadoNo cumple el esquema. error indica qué campo falló. No se guardó: se puede corregir y reenviar.
failed
SignificadoFalló el procesamiento. Reenviar con el mismo id lo vuelve a procesar.

Tipos de evento de la versión vigente y lo que hace Kuida con cada uno. Los que figuran como “recibido, todavía sin efecto” se aceptan y quedan registrados con status unhandled; se pueden enviar desde ya.

intake.requested
EstadoProcesado
Equivalenteintake_requests.create
patient.upserted
EstadoProcesado
Equivalentepatients.create
appointment.created
EstadoProcesado
Equivalenteappointments.create
visit.completed
EstadoProcesado
Equivalentevisits.create
treatment.prescribed
EstadoProcesado
Equivalentetreatments.create
order.issued
EstadoRecibido, todavía sin efecto
Equivalente—

intake.requestedProcesado

Alguien pide el servicio para un paciente. Abre una solicitud de ingreso; Kuida completa por WhatsApp los datos que falten.

intake.requested
{
  "id": "ejemplo-intake-requested",
  "type": "intake.requested",
  "data": {
    "patient": {
      "fullName": "Paciente Demo",
      "dni": "11111111"
    },
    "contacts": [
      {
        "name": "Familiar Demo",
        "relationship": "hija",
        "phone": "+54 9 342 555 0001"
      }
    ],
    "coverage": {
      "insurer": "OSDEMO",
      "memberId": "000123"
    },
    "requestedService": "Internación domiciliaria",
    "flags": {
      "hospitalized": true
    }
  }
}
› Campos de data
  • patientobjeto
    › Ver 6 campos
    • phonestringpuede ser null
    • dnistringpuede ser null
    • externalIdstringpuede ser null
    • fullNamestringpuede ser null
    • emailstringpuede ser null
    • dateOfBirthtimestamppuede ser null
  • contactsarray de objetos

    Default: []

    › Ver 4 campos
    • namestringpuede ser null
    • relationshipstringpuede ser null
    • phonestringpuede ser null
    • emailstringpuede ser null
  • coverageobjeto
    › Ver 3 campos
    • insurerstringpuede ser null
    • planstringpuede ser null
    • memberIdstringpuede ser null
  • addressstringpuede ser null
  • requestedServicestringpuede ser null
  • senderobjeto
    › Ver 3 campos
    • namestringpuede ser null
    • emailstringpuede ser null
    • organizationstringpuede ser null
  • attachmentsarray de objetos

    Default: []

    › Ver 4 campos
    • namestringobligatorio
    • mimeTypestringpuede ser null
    • kindenum

      Valores:PEDIDO_MEDICOHISTORIA_CLINICACOBERTURAOTRO

    • refstringpuede ser null
  • summarystringpuede ser null
  • flagsobjeto
    › Ver 1 campos
    • hospitalizedboolean
  • originobjeto
    › Ver 6 campos
    • channelenum

      Valores:EMAILFORMMANUALAPI

    • threadIdstringpuede ser null
    • messageIdstringpuede ser null
    • fromstringpuede ser null
    • subjectstringpuede ser null
    • receivedAttimestamppuede ser null

patient.upsertedProcesado

Alta o actualización de un paciente. Kuida lo busca por teléfono, DNI o id externo y, si no existe, lo crea.

patient.upserted
{
  "id": "ejemplo-patient-upserted",
  "type": "patient.upserted",
  "data": {
    "phone": "+54 9 342 555 0000",
    "fullName": "Paciente Demo",
    "dni": "11111111",
    "externalId": "HC-1234"
  }
}
› Campos de data
  • phonestringpuede ser null
  • dnistringpuede ser null
  • externalIdstringpuede ser null
  • fullNamestringpuede ser null
  • emailstringpuede ser null
  • dateOfBirthtimestamppuede ser null

appointment.createdProcesado

Un turno nuevo. Kuida agenda los recordatorios por WhatsApp que tiene configurados la organización. Sin externalId, el turno solo se puede cambiar por la API con su id de Kuida.

appointment.created
{
  "id": "ejemplo-appointment-created",
  "type": "appointment.created",
  "data": {
    "externalId": "turno-123",
    "startAt": "2026-10-05T10:30:00-03:00",
    "visitType": "Control",
    "patient": {
      "phone": "+54 9 342 555 0000",
      "fullName": "Paciente Demo"
    },
    "doctor": {
      "externalId": "MED-12",
      "fullName": "Dra. Demo"
    }
  }
}
› Campos de data
  • externalIdstringpuede ser null
  • bookingExternalIdstringpuede ser null
  • startAttimestampobligatorio
  • visitTypestringpuede ser null
  • patientobjetoobligatorio
    › Ver 6 campos
    • phonestringpuede ser null
    • dnistringpuede ser null
    • externalIdstringpuede ser null
    • fullNamestringpuede ser null
    • emailstringpuede ser null
    • dateOfBirthtimestamppuede ser null
  • doctorobjeto
    › Ver 3 campos
    • fullNamestringpuede ser null
    • specialtystringpuede ser null
    • externalIdstringpuede ser null

appointment.rescheduledProcesado

Cambio de horario de un turno, identificado por su externalId. Reprograma los recordatorios.

appointment.rescheduled
{
  "id": "ejemplo-appointment-rescheduled",
  "type": "appointment.rescheduled",
  "data": {
    "externalId": "turno-123",
    "startAt": "2026-10-06T11:00:00-03:00",
    "patient": {
      "phone": "+54 9 342 555 0000"
    },
    "reason": "Pedido del paciente"
  }
}
› Campos de data
  • externalIdstringobligatorio
  • bookingExternalIdstringpuede ser null
  • startAttimestampobligatorio
  • visitTypestringpuede ser null
  • patientobjetoobligatorio
    › Ver 6 campos
    • phonestringpuede ser null
    • dnistringpuede ser null
    • externalIdstringpuede ser null
    • fullNamestringpuede ser null
    • emailstringpuede ser null
    • dateOfBirthtimestamppuede ser null
  • doctorobjeto
    › Ver 3 campos
    • fullNamestringpuede ser null
    • specialtystringpuede ser null
    • externalIdstringpuede ser null
  • reasonstringpuede ser null

appointment.cancelledProcesado

Cancelación de un turno, identificado por su externalId. Da de baja los recordatorios pendientes.

appointment.cancelled
{
  "id": "ejemplo-appointment-cancelled",
  "type": "appointment.cancelled",
  "data": {
    "externalId": "turno-123",
    "startAt": "2026-10-05T10:30:00-03:00",
    "patient": {
      "phone": "+54 9 342 555 0000"
    },
    "reason": "El paciente avisó que no puede asistir"
  }
}
› Campos de data
  • externalIdstringobligatorio
  • bookingExternalIdstringpuede ser null
  • startAttimestampobligatorio
  • visitTypestringpuede ser null
  • patientobjetoobligatorio
    › Ver 6 campos
    • phonestringpuede ser null
    • dnistringpuede ser null
    • externalIdstringpuede ser null
    • fullNamestringpuede ser null
    • emailstringpuede ser null
    • dateOfBirthtimestamppuede ser null
  • doctorobjeto
    › Ver 3 campos
    • fullNamestringpuede ser null
    • specialtystringpuede ser null
    • externalIdstringpuede ser null
  • reasonstringpuede ser null

visit.completedProcesado

Una consulta atendida. Arranca el seguimiento posconsulta del paciente por WhatsApp.

visit.completed
{
  "id": "ejemplo-visit-completed",
  "type": "visit.completed",
  "data": {
    "patient": {
      "phone": "+54 9 342 555 0000",
      "fullName": "Paciente Demo",
      "dni": "11111111"
    },
    "doctor": {
      "externalId": "MED-12",
      "fullName": "Dra. Demo"
    },
    "visit": {
      "visitedAt": "2026-10-05T10:45:00-03:00",
      "type": "Control",
      "externalId": "turno-123"
    }
  }
}
› Campos de data
  • patientobjetoobligatorio
    › Ver 6 campos
    • phonestringpuede ser null
    • dnistringpuede ser null
    • externalIdstringpuede ser null
    • fullNamestringpuede ser null
    • emailstringpuede ser null
    • dateOfBirthtimestamppuede ser null
  • doctorobjeto
    › Ver 3 campos
    • fullNamestringpuede ser null
    • specialtystringpuede ser null
    • externalIdstringpuede ser null
  • visitobjetoobligatorio
    › Ver 7 campos
    • visitedAttimestampobligatorio
    • typestringpuede ser null
    • diagnosisstringpuede ser null
    • notesstringpuede ser null
    • recommendedFollowUpsarray de anypuede ser null
    • externalIdstringpuede ser null
    • bookingExternalIdstringpuede ser null
  • rawany

treatment.prescribedProcesado

Un tratamiento indicado al paciente. Queda registrado en su ficha; Kuida no envía recordatorios de toma de medicación.

treatment.prescribed
{
  "id": "ejemplo-treatment-prescribed",
  "type": "treatment.prescribed",
  "data": {
    "patient": {
      "phone": "+54 9 342 555 0000"
    },
    "name": "Enalapril 10 mg",
    "kind": "MEDICATION",
    "frequency": "cada 12 horas",
    "startAt": "2026-10-05T00:00:00-03:00"
  }
}
› Campos de data
  • patientobjetoobligatorio
    › Ver 6 campos
    • phonestringpuede ser null
    • dnistringpuede ser null
    • externalIdstringpuede ser null
    • fullNamestringpuede ser null
    • emailstringpuede ser null
    • dateOfBirthtimestamppuede ser null
  • namestringobligatorio
  • kindenum

    Valores:MEDICATIONTHERAPYDIETSTUDYLABWORKLIFESTYLE

  • dosagestringpuede ser null
  • instructionsstringpuede ser null
  • frequencystringpuede ser null
  • startAttimestamppuede ser null
  • endAttimestamppuede ser null
  • prescribedByobjeto
    › Ver 3 campos
    • fullNamestringpuede ser null
    • specialtystringpuede ser null
    • externalIdstringpuede ser null

order.issuedRecibido, todavía sin efecto

Una orden emitida para el paciente: laboratorio, imágenes, interconsulta u otra.

order.issued
{
  "id": "ejemplo-order-issued",
  "type": "order.issued",
  "data": {
    "patient": {
      "phone": "+54 9 342 555 0000"
    },
    "kind": "LAB",
    "description": "Hemograma completo",
    "issuedAt": "2026-10-05T10:45:00-03:00"
  }
}
› Campos de data
  • patientobjetoobligatorio
    › Ver 6 campos
    • phonestringpuede ser null
    • dnistringpuede ser null
    • externalIdstringpuede ser null
    • fullNamestringpuede ser null
    • emailstringpuede ser null
    • dateOfBirthtimestamppuede ser null
  • kindenumobligatorio

    Valores:LABIMAGINGCONSULTOTHER

  • descriptionstringobligatorio
  • issuedAttimestamppuede ser null
  • issuedByobjeto
    › Ver 3 campos
    • fullNamestringpuede ser null
    • specialtystringpuede ser null
    • externalIdstringpuede ser null

Depurar una integración

Todo lo que entra a Kuida para la organización queda en GET /v1/events, con su estado y el error si lo hubo. Para ver lo que falló:

GET /v1/events
curl -G https://www.kuida.ar/api/v1/events \
  -H "Authorization: Bearer kd_test_…" \
  -d status=failed \
  -d limit=10

Webhooks de eventos procesados

Cuando Kuida procesa un evento, avisa a los endpoints de webhook suscriptos a ese tipo. Ver Webhooks.