Konko FHIR API
FHIR API
api.medplum.konko.aiFHIR R4
API reference · FHIR R4Referencia de la API · FHIR R4

Konko FHIR API

Read the patients, practitioners, services, locations and appointments that Konko manages for your organization, and receive a webhook whenever one of them changes. The API implements the HL7 FHIR R4 standard, so standard FHIR tools and libraries work with it.

Lee los pacientes, profesionales, servicios, sedes y citas que Konko administra para tu organización, y recibe un webhook cada vez que alguno cambia. La API implementa el estándar HL7 FHIR R4, por lo que las herramientas y bibliotecas FHIR estándar funcionan con ella.

Base URLURL basehttps://api.medplum.konko.ai/fhir/R4
StandardEstándarHL7 FHIR R4 (4.0.1)
AuthenticationAutenticaciónOAuth 2.0 client credentials
FormatFormatoapplication/fhir+json

What your API client can reach

A qué puede acceder tu cliente de API

ResourceRecursoWhat it holdsQué contieneAccessAcceso
PatientPeople who have booked or attended an appointment.Personas que han agendado o asistido a una cita.ReadLectura
PractitionerDoctors and other professionals.Médicos y otros profesionales.ReadLectura
PractitionerRoleA practitioner at one location, with their services. Appointments point here.Un profesional en una sede, con sus servicios. Las citas apuntan aquí.ReadLectura
LocationSites where patients are seen, with opening hours.Sedes donde se atiende a los pacientes, con horario de atención.ReadLectura
HealthcareServiceServices patients can book, with prices and instructions.Servicios que los pacientes pueden agendar, con precios e instrucciones.ReadLectura
SlotBusy time on a practitioner's calendar: appointments, blocks and holidays.Tiempo ocupado en el calendario de un profesional: citas, bloqueos y feriados.ReadLectura
AppointmentBooked visits from your EHR, calendars and Konko's assistant.Visitas agendadas desde tu EHR, tus calendarios y el asistente de Konko.ReadLectura
SubscriptionYour webhooks.Tus webhooks.Read and writeLectura y escritura
AuditEventDelivery attempts of your webhooks.Intentos de entrega de tus webhooks.ReadLectura
Get startedPrimeros pasos

Quickstart

Inicio rápido

Konko creates an API client for your organization and sends you its client ID and secret through a secure channel. With those, three requests get you from nothing to live updates.

Konko crea un cliente de API para tu organización y te envía su ID de cliente y su secreto por un canal seguro. Con ellos, tres solicitudes te llevan de cero a recibir actualizaciones en vivo.

  1. Get an access token

    Obtener un token de acceso

    Exchange your client ID and secret for a token at POST /oauth2/token. It's valid for an hour. See Authentication.

    Intercambia tu ID de cliente y tu secreto por un token en POST /oauth2/token. Es válido por una hora. Consulta Autenticación.

  2. Read a day of appointments

    Leer las citas de un día

    Search appointments by date and include each patient in the same response. Dates carry the clinic's UTC offset. See Appointment.

    Busca citas por fecha e incluye cada paciente en la misma respuesta. Las fechas incluyen el desfase UTC de la clínica. Consulta Appointment.

  3. Subscribe to changes

    Suscribirse a los cambios

    Create a subscription with your HTTPS endpoint and a signing secret. From now on, every appointment change is sent to you. See Webhooks.

    Crea una suscripción con tu endpoint HTTPS y un secreto de firma. A partir de ese momento, se te envía cada cambio en una cita. Consulta Webhooks.

POST/oauth2/token
curl "https://api.medplum.konko.ai/oauth2/token" \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  --data-urlencode "grant_type=client_credentials"
GET/fhir/R4/Appointment
curl -G "https://api.medplum.konko.ai/fhir/R4/Appointment" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  --data-urlencode "date=ge2026-10-13T00:00:00-06:00" \
  --data-urlencode "date=lt2026-10-14T00:00:00-06:00" \
  --data-urlencode "status=booked" \
  --data-urlencode "_include=Appointment:patient" \
  --data-urlencode "_sort=date"
POST/fhir/R4/Subscription
curl -X POST "https://api.medplum.konko.ai/fhir/R4/Subscription" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/fhir+json" \
  -d '{
  "resourceType": "Subscription",
  "status": "active",
  "reason": "Appointment changes for our CRM",
  "criteria": "Appointment",
  "channel": {
    "type": "rest-hook",
    "endpoint": "https://integraciones.clinicahorizonte.example/konko/webhooks",
    "payload": "application/fhir+json"
  },
  "extension": [
    {
      "url": "https://www.medplum.com/fhir/StructureDefinition/subscription-secret",
      "valueString": "whsec_7b1d4e9a2c6f8b3e5a0d9c7f1e4b6a28"
    }
  ]
}'
Get startedPrimeros pasos

Authentication

Autenticación

The API uses the OAuth 2.0 client credentials flow. Konko gives your organization an API client with a client ID and a client secret. Exchange them for an access token and send the token with every request.

La API usa el flujo de credenciales de cliente de OAuth 2.0. Konko le da a tu organización un cliente de API con un ID de cliente y un secreto de cliente. Intercámbialos por un token de acceso y envía el token con cada solicitud.

Request an access token

Solicitar un token de acceso

POST/oauth2/token

Exchanges your client credentials for an access token. Send the body form-encoded (application/x-www-form-urlencoded); JSON bodies are rejected.

Intercambia tus credenciales de cliente por un token de acceso. Envía el cuerpo codificado como formulario (application/x-www-form-urlencoded); los cuerpos JSON se rechazan.

Body parameters
Parámetros del cuerpo
  • grant_typestringRequiredObligatorio

    Always client_credentials.

    Siempre client_credentials.

  • client_idstring

    Your client ID. Required unless you send the credentials as HTTP Basic (Authorization: Basic base64(client_id:client_secret)), which is what the cURL example does.

    Tu ID de cliente. Obligatorio a menos que envíes las credenciales como HTTP Basic (Authorization: Basic base64(client_id:client_secret)), que es lo que hace el ejemplo de cURL.

  • client_secretstring

    Your client secret. Required unless you send it as HTTP Basic.

    Tu secreto de cliente. Obligatorio a menos que lo envíes como HTTP Basic.

Response
Respuesta
  • access_tokenstring

    A signed JWT. Send it as Authorization: Bearer <access_token>.

    Un JWT firmado. Envíalo como Authorization: Bearer <access_token>.

  • token_typestring

    Always Bearer.

    Siempre Bearer.

  • expires_ininteger

    Seconds until the token expires. Normally 3600 (one hour).

    Segundos hasta que expire el token. Normalmente 3600 (una hora).

  • scopestring

    Always openid.

    Siempre openid.

  • projectReference

    Your organization's project. Every request made with this token is limited to it.

    El proyecto de tu organización. Toda solicitud hecha con este token se limita a él.

  • profileReference

    Your API client, as ClientApplication/<client_id>.

    Tu cliente de API, como ClientApplication/<client_id>.

  • id_tokenstring

    An OpenID Connect ID token. You don't need it for API calls.

    Un token de ID de OpenID Connect. No lo necesitas para las llamadas a la API.

There is no refresh token. When a token expires, request a new one the same way.

No hay refresh token. Cuando un token expira, solicita uno nuevo de la misma forma.

POST/oauth2/token
curl "https://api.medplum.konko.ai/oauth2/token" \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  --data-urlencode "grant_type=client_credentials"
200 OK  Response
200 OK  Respuesta
{
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "openid",
  "id_token": "eyJhbGciOiJFUzI1NiIsImtpZCI6IjRmM2E…",
  "access_token": "eyJhbGciOiJFUzI1NiIsImtpZCI6IjRmM2E4YjE2In0.eyJjbGllbnRfaWQiOiI3YzFlOWI1Mi…",
  "project": {
    "reference": "Project/0f5c3d2a-7b1e-4c8f-9a6d-2e4b8c1f7a90"
  },
  "profile": {
    "reference": "ClientApplication/7c1e9b52-3a4d-4f8e-b6c2-91d0a5e3f7b4"
  }
}

Send the token

Enviar el token

Pass the token in the Authorization header of every API request.

Pasa el token en el encabezado Authorization de cada solicitud a la API.

Call the API from your servers. It doesn't accept cross-origin requests from web browsers, which also keeps your credentials out of front-end code.

Llama a la API desde tus servidores. No acepta solicitudes cross-origin desde navegadores web, lo que además mantiene tus credenciales fuera del código front-end.

Reuse tokens until they expire

Reutilizar los tokens hasta que expiren

  • A token is valid for expires_in seconds, one hour by default. Keep it in memory and share it across threads or workers.
  • Un token es válido durante expires_in segundos, una hora de forma predeterminada. Guárdalo en memoria y compártelo entre hilos o workers.
  • Request a new token about a minute before the old one expires, or when a request returns 401 Unauthorized. Then retry that request once.
  • Solicita un token nuevo más o menos un minuto antes de que expire el anterior, o cuando una solicitud devuelva 401 Unauthorized. Luego reintenta esa solicitud una vez.
  • Don't request a token per API call. Token requests have their own, much lower rate limit.
  • No solicites un token por cada llamada a la API. Las solicitudes de token tienen su propio límite de frecuencia, mucho más bajo.
NoteNota

The API also accepts your client ID and secret as HTTP Basic credentials on each request. Use that only for quick manual tests: it sends your secret with every call instead of a short-lived token.

La API también acepta tu ID de cliente y tu secreto como credenciales HTTP Basic en cada solicitud. Úsalo solo para pruebas manuales rápidas: envía tu secreto en cada llamada en lugar de un token de corta duración.

GET/fhir/R4/Practitioner
curl -G "https://api.medplum.konko.ai/fhir/R4/Practitioner" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  --data-urlencode "active=true"
Token helper
Ayudante de token
import time
import requests

TOKEN_URL = "https://api.medplum.konko.ai/oauth2/token"


class KonkoToken:
    """Caches one access token and renews it shortly before it expires."""

    def __init__(self, client_id: str, client_secret: str):
        self._auth = (client_id, client_secret)
        self._token: str | None = None
        self._expires_at = 0.0

    def get(self) -> str:
        if self._token is None or time.time() > self._expires_at - 60:
            resp = requests.post(
                TOKEN_URL,
                data={"grant_type": "client_credentials"},
                auth=self._auth,  # HTTP Basic: client_id / client_secret
                timeout=30,
            )
            resp.raise_for_status()
            body = resp.json()
            self._token = body["access_token"]
            self._expires_at = time.time() + body["expires_in"]
        return self._token

    def invalidate(self) -> None:
        self._token = None  # call after a 401, then retry once

Keep credentials safe

Proteger las credenciales

  • Store the client secret in a secrets manager and use it only from your servers. Never put it in a browser, mobile app or public repository.
  • Guarda el secreto de cliente en un gestor de secretos y úsalo solo desde tus servidores. Nunca lo pongas en un navegador, una app móvil o un repositorio público.
  • If a secret leaks, tell us right away. We can disable the client and revoke its active tokens.
  • Si un secreto se filtra, avísanos de inmediato. Podemos deshabilitar el cliente y revocar sus tokens activos.
Token errors
Errores de token
StatusEstadoerrorerror_descriptionWhat to checkQué revisar
400invalid_requestMissing grant_typeSend grant_type=client_credentials.Envía grant_type=client_credentials.
400invalid_requestUnsupported grant_typeOnly client_credentials is available to API clients.Solo client_credentials está disponible para los clientes de API.
400invalid_requestMissing client_id / Missing client_secretSend both, in the body or as HTTP Basic.Envía ambos, en el cuerpo o como HTTP Basic.
400invalid_requestInvalid clientThe client ID is wrong, or the client has been disabled.El ID de cliente es incorrecto, o el cliente fue deshabilitado.
400invalid_requestInvalid secretThe secret is wrong.El secreto es incorrecto.
400(plain text)(texto plano)Unsupported content typeUse application/x-www-form-urlencoded.Usa application/x-www-form-urlencoded.
429OperationOutcomeToo Many RequestsMore than 160 token requests in a minute. Cache your token.Más de 160 solicitudes de token en un minuto. Guarda tu token en caché.
Get startedPrimeros pasos

Access and permissions

Acceso y permisos

Your API client can read the resources below and manage its own webhooks.

Tu cliente de API puede leer los siguientes recursos y administrar sus propios webhooks.

ResourceRecursoAllowedPermitido
Patient, Practitioner, PractitionerRole, Location, HealthcareService, Slot, AppointmentRead, search, version historyLectura, búsqueda, historial de versiones
SubscriptionCreate, read, update, delete and search your own webhooksCrear, leer, actualizar, eliminar y buscar tus propios webhooks
AuditEventRead and search webhook delivery attemptsLeer y buscar los intentos de entrega de webhooks
Get startedPrimeros pasos

Rate limits

Límites de frecuencia

Two limits protect the API: a request rate per IP address, and a quota of FHIR interaction points per API client. Both reset every minute.

Dos límites protegen la API: una tasa de solicitudes por dirección IP y una cuota de puntos de interacción FHIR por cliente de API. Ambos se reinician cada minuto.

LimitLímiteCounted perSe cuenta porAllowance per minutePermitido por minuto
Token requests (/oauth2/*)Solicitudes de token (/oauth2/*)Client IP addressDirección IP del cliente160 requests160 solicitudes
All other requestsTodas las demás solicitudesClient IP addressDirección IP del cliente60,000 requests60,000 solicitudes
FHIR interaction quotaCuota de interacciones FHIRAPI clientCliente de API50,000 points50,000 puntos

How interactions are counted

Cómo se cuentan las interacciones

Each interaction spends points from your client's per-minute quota. Batch requests spend points for every entry they contain.

Cada interacción gasta puntos de la cuota por minuto de tu cliente. Las solicitudes por lotes gastan puntos por cada entrada que contienen.

InteractionInteracciónPointsPuntos
Read or version read (GET /Patient/{id})Lectura o lectura de versión (GET /Patient/{id})1
Each resource returned by _includeCada recurso devuelto por _include1
Search, including one page of results (GET /Appointment?…)Búsqueda, incluida una página de resultados (GET /Appointment?…)20
History (GET /Patient/{id}/_history)Historial (GET /Patient/{id}/_history)10
Create, update, patch or deleteCrear, actualizar, patch o eliminar100

Reading your remaining quota

Leer tu cuota restante

Every response carries RateLimit headers, one per limit that applies. r is what remains in the current window and t is the number of seconds until the window resets. Some HTTP clients join the two headers into one value separated by a comma.

Cada respuesta lleva encabezados RateLimit, uno por cada límite que aplica. r es lo que queda en la ventana actual y t es el número de segundos hasta que la ventana se reinicia. Algunos clientes HTTP unen los dos encabezados en un solo valor separado por coma.

When you hit a limit

Cuando alcanzas un límite

The API responds 429 Too Many Requests with an OperationOutcome. There is no Retry-After header: wait for the t seconds reported in RateLimit, then resume. If the header is missing, back off exponentially with jitter, starting at one second.

La API responde 429 Too Many Requests con un OperationOutcome. No hay encabezado Retry-After: espera los t segundos indicados en RateLimit y luego continúa. Si falta el encabezado, aplica retroceso exponencial con jitter, empezando en un segundo.

Stay well inside the limits

Mantenerse muy por debajo de los límites

  • Use webhooks instead of polling for changes.
  • Usa webhooks en lugar de hacer polling para detectar cambios.
  • Cache directory data (practitioners, services and locations). It changes rarely, and a webhook tells you when it does.
  • Guarda en caché los datos de directorio (profesionales, servicios y sedes). Cambian rara vez, y un webhook te avisa cuando lo hacen.
  • Fetch related resources with _include in the same search rather than reading them one by one.
  • Obtén los recursos relacionados con _include en la misma búsqueda en lugar de leerlos uno por uno.
  • Request larger pages, for example _count=200, when you read many resources.
  • Solicita páginas más grandes, por ejemplo _count=200, cuando leas muchos recursos.

Other limits

Otros límites

LimitLímiteValueValorWhat to do insteadQué hacer en su lugar
Request bodyCuerpo de la solicitud1 MBSplit large batches.Divide los lotes grandes.
Results per page (_count)Resultados por página (_count)20 by default, up to 1,00020 de forma predeterminada, hasta 1,000Follow next links.Sigue los enlaces next.
Offset pagination (_offset)Paginación por offset (_offset)Up to 10,000Hasta 10,000Sort by _lastUpdated to get cursor links with no cap. See Pagination.Ordena por _lastUpdated para obtener enlaces de cursor sin tope. Consulta Paginación.
Request durationDuración de la solicitud30 seconds30 segundosNarrow the search with filters or a smaller _count.Acota la búsqueda con filtros o con un _count más pequeño.
URL and headersURL y encabezadosAbout 16 KBUnos 16 KBSend long searches as POST …/_search.Envía las búsquedas largas como POST …/_search.
Rate limit headers
Encabezados de límite de frecuencia
HTTP/1.1 200 OK
Content-Type: application/fhir+json; charset=utf-8
RateLimit: "requests";r=59987;t=41
RateLimit: "fhirInteractions";r=49740;t=41
429 Too Many Requests  Response
429 Too Many Requests  Respuesta
{
  "resourceType": "OperationOutcome",
  "id": "too-many-requests",
  "issue": [
    {
      "severity": "error",
      "code": "throttled",
      "details": {
        "text": "Too Many Requests"
      },
      "diagnostics": "{\"_remainingPoints\":0,\"_msBeforeNext\":37210,\"_consumedPoints\":50020,\"_isFirstInDuration\":false,\"limit\":50000}"
    }
  ]
}
Get startedPrimeros pasos

Errors

Errores

Failed requests return an HTTP status code and a FHIR OperationOutcome that explains what went wrong. The token endpoint is the exception: it answers with OAuth-style error and error_description fields.

Las solicitudes fallidas devuelven un código de estado HTTP y un OperationOutcome FHIR que explica qué salió mal. El endpoint de token es la excepción: responde con campos error y error_description al estilo OAuth.

StatusEstadoMeaningSignificado
200 OKThe request succeeded.La solicitud se completó correctamente.
201 CreatedA subscription was created. The Location header holds its URL.Se creó una suscripción. El encabezado Location contiene su URL.
400 Bad RequestThe request is malformed: unknown search parameter, invalid value, bad JSON or missing required fields. details.text says which.La solicitud está mal formada: parámetro de búsqueda desconocido, valor inválido, JSON incorrecto o campos obligatorios faltantes. details.text indica cuál.
401 UnauthorizedThe token is missing, invalid or expired. Get a new token and retry once.El token falta, es inválido o expiró. Obtén un token nuevo y reintenta una vez.
403 ForbiddenYour client isn't allowed to do this. See Access and permissions.Tu cliente no tiene permiso para hacer esto. Consulta Acceso y permisos.
404 Not FoundNo resource with this id exists in your project.No existe ningún recurso con este id en tu proyecto.
410 GoneThe resource existed but has been deleted.El recurso existía, pero fue eliminado.
412 Precondition FailedAn If-Match version check failed on an update.Falló una verificación de versión con If-Match en una actualización.
422 Unprocessable EntityThe request is well formed but breaks a business rule.La solicitud está bien formada, pero incumple una regla de negocio.
429 Too Many RequestsA rate limit was exceeded. See Rate limits.Se excedió un límite de frecuencia. Consulta Límites de frecuencia.
500, 502, 503, 504A problem on Konko's side. Retry with exponential backoff.Un problema del lado de Konko. Reintenta con retroceso exponencial.

Reading an OperationOutcome

Leer un OperationOutcome

  • issue[].code is a machine-readable category such as invalid, login, forbidden, not-found, deleted or throttled.
  • issue[].code es una categoría legible por máquina, como invalid, login, forbidden, not-found, deleted o throttled.
  • issue[].details.text is a human-readable explanation. Log it, but don't match on its wording, which can change.
  • issue[].details.text es una explicación legible para humanos. Regístrala en tus logs, pero no hagas coincidencias sobre su redacción, que puede cambiar.
  • The tracing extension carries a requestId and traceId. Include them when you report a problem to Konko.
  • La extensión tracing contiene un requestId y un traceId. Inclúyelos cuando reportes un problema a Konko.

Correlating requests

Correlacionar solicitudes

Send your own UUID in an X-Trace-Id header, or a W3C traceparent header, and Konko uses it as the trace ID for that request. It then appears in the tracing extension of any error response, and Konko can find the request by it.

Envía tu propio UUID en un encabezado X-Trace-Id, o un encabezado traceparent de W3C, y Konko lo usa como ID de traza para esa solicitud. Luego aparece en la extensión tracing de cualquier respuesta de error, y Konko puede encontrar la solicitud con él.

When to retry

Cuándo reintentar

  • Retry 429 and 5xx responses with exponential backoff and jitter.
  • Reintenta las respuestas 429 y 5xx con retroceso exponencial y jitter.
  • Retry a 401 once, after requesting a new token.
  • Reintenta un 401 una sola vez, después de solicitar un nuevo token.
  • Don't retry other 4xx responses unchanged. Fix the request first.
  • No reintentes otras respuestas 4xx sin cambios. Corrige primero la solicitud.
404 Not Found  Response
404 Not Found  Respuesta
{
  "resourceType": "OperationOutcome",
  "id": "not-found",
  "issue": [
    {
      "severity": "error",
      "code": "not-found",
      "details": {
        "text": "Not found"
      }
    }
  ],
  "extension": [
    {
      "url": "https://medplum.com/fhir/StructureDefinition/tracing",
      "extension": [
        {
          "url": "requestId",
          "valueId": "7d2f9b41-6c3e-4a8d-b1f5-0e9a2c7d4b63"
        },
        {
          "url": "traceId",
          "valueId": "c3a8e1f6-9b2d-4e7a-8c5f-1d0b6e9a3f27"
        }
      ]
    }
  ]
}
400 Bad Request  Response
400 Bad Request  Respuesta
{
  "resourceType": "OperationOutcome",
  "issue": [
    {
      "severity": "error",
      "code": "invalid",
      "details": {
        "text": "Unknown search parameter: doctor"
      }
    }
  ]
}
401 Unauthorized  Response
401 Unauthorized  Respuesta
{
  "resourceType": "OperationOutcome",
  "id": "unauthorized",
  "issue": [
    {
      "severity": "error",
      "code": "login",
      "details": {
        "text": "Unauthorized"
      }
    }
  ]
}
Working with FHIRTrabajar con FHIR

How the resources fit together

Cómo se relacionan los recursos

Resources refer to each other with references such as {"reference": "PractitionerRole/f7c3…"}. The PractitionerRole sits in the middle: a practitioner working at one location.

Los recursos se refieren entre sí con referencias como {"reference": "PractitionerRole/f7c3…"}. El PractitionerRole está en el centro: un profesional que trabaja en una sede.

Patientthe personla personaPractitionerthe doctorel médicoAppointmenta booked visituna visita agendadaPractitionerRoledoctor at a locationmédico en una sedeLocationa siteuna sedeSlotbusy timetiempo ocupadoHealthcareServicewhat can be bookedlo que se puede agendarparticipant.actorparticipant.actorslotpractitionerlocationhealthcareServicelocation
Arrows point from the resource that holds a reference to the resource it references, labelled with the field. Appointments reach the doctor, the location and the services only through the PractitionerRole.Las flechas van del recurso que contiene una referencia al recurso que referencia, etiquetadas con el campo. Las citas llegan al médico, la sede y los servicios solo a través del PractitionerRole.
To getPara obtenerFollowSigueIn one requestEn una sola solicitud
Patient of an appointmentEl paciente de una citaparticipant.actor where the reference starts with Patient/participant.actor donde la referencia empieza con Patient/_include=Appointment:patient
Doctor of an appointmentEl médico de una citaparticipant.actor (PractitionerRole), then PractitionerRole.practitionerparticipant.actor (PractitionerRole), luego PractitionerRole.practitioner_include=Appointment:actor&_include:iterate=PractitionerRole:practitioner
Location of an appointmentLa sede de una citaThe PractitionerRole's locationEl location del PractitionerRole_include=Appointment:actor&_include:iterate=PractitionerRole:location
Busy slot of an appointmentEl slot ocupado de una citaslot_include=Appointment:slot
Services a doctor offers at a siteLos servicios que un médico ofrece en una sedePractitionerRole.healthcareService_include=PractitionerRole:service
Working with FHIRTrabajar con FHIR

Searching

Búsqueda

Every resource type can be searched with GET /fhir/R4/{ResourceType}?parameter=value. Each resource's reference lists the parameters it supports.

Todo tipo de recurso se puede buscar con GET /fhir/R4/{ResourceType}?parameter=value. La referencia de cada recurso lista los parámetros que admite.

Combining parameters

Combinar parámetros

  • Different parameters must all match: status=booked&patient=Patient/{id}.
  • Los parámetros distintos deben coincidir todos: status=booked&patient=Patient/{id}.
  • Commas mean any of: status=booked,pending.
  • Las comas significan cualquiera de: status=booked,pending.
  • Repeat a parameter to require both conditions, which is how you write a range: date=ge2026-10-13&date=lt2026-10-20.
  • Repite un parámetro para exigir ambas condiciones, que es como se escribe un rango: date=ge2026-10-13&date=lt2026-10-20.
  • :missing=true finds resources without the field; :not excludes a value.
  • :missing=true encuentra recursos sin el campo; :not excluye un valor.

Parameter types

Tipos de parámetro

TypeTipoHow it matchesCómo coincideExampleEjemplo
tokenAn exact code or ID. system|value pins the system, value alone matches any system, system| matches any value in that system. :text searches the display text instead.Un código o ID exacto. system|value fija el sistema, value por sí solo coincide con cualquier sistema, system| coincide con cualquier valor de ese sistema. :text busca en cambio en el texto de visualización.status=booked
stringCase-insensitive, from the start of the value. :contains matches anywhere, :exact must match exactly. Accents count: jimenez doesn't match “Jiménez”.Sin distinguir mayúsculas, desde el inicio del valor. :contains coincide en cualquier posición, :exact debe coincidir exactamente. Los acentos cuentan: jimenez no coincide con “Jiménez”.name:contains=gineco
name and addressname y addressEvery word you send must start a word of the name or address, in any order. name=ana mora finds “Ana Lucía Mora Vargas”.Cada palabra que envías debe ser el inicio de una palabra del nombre o la dirección, en cualquier orden. name=ana mora encuentra “Ana Lucía Mora Vargas”.name=ana mora
referenceType/id of the referenced resource.Type/id del recurso referenciado.patient=Patient/3c9f6a1e…
dateAn ISO 8601 date or date-time, with an optional prefix. A date without a time covers the whole day. Always include the UTC offset in date-times.Una fecha o fecha-hora ISO 8601, con un prefijo opcional. Una fecha sin hora cubre todo el día. Incluye siempre el desfase UTC en las fechas-hora.date=ge2026-10-13T00:00:00-06:00

Date prefixes

Prefijos de fecha

PrefixPrefijoMeaningSignificado
eq (default)eq (predeterminado)Equal, or within the day or period you give.Igual, o dentro del día o periodo que indicas.
neNot equal.Distinto.
gt, geAfter, or on or after.Después, o en la fecha o después.
lt, leBefore, or on or before.Antes, o en la fecha o antes.
sa, ebStarts after, ends before.Empieza después, termina antes.
apApproximately.Aproximadamente.

Chained search

Búsqueda encadenada

Filter on a field of a referenced resource by chaining parameters with a dot. Name the target type when a reference can point to several: actor:PractitionerRole.practitioner=Practitioner/{id} finds a doctor's appointments at every location. Chains can be up to three links long, and _has filters in the opposite direction.

Filtra por un campo de un recurso referenciado encadenando parámetros con un punto. Indica el tipo de destino cuando una referencia puede apuntar a varios: actor:PractitionerRole.practitioner=Practitioner/{id} encuentra las citas de un médico en todas las sedes. Las cadenas pueden tener hasta tres eslabones, y _has filtra en la dirección opuesta.

Long queries

Consultas largas

URLs and headers are limited to about 16 KB. For long filters, such as many IDs, send the same parameters form-encoded to POST /fhir/R4/{ResourceType}/_search. The result is identical.

Las URL y los encabezados están limitados a unos 16 KB. Para filtros largos, como muchos IDs, envía los mismos parámetros codificados como formulario a POST /fhir/R4/{ResourceType}/_search. El resultado es idéntico.

An unknown parameter fails with 400 Bad Request and the message Unknown search parameter: …. Parameters are never silently ignored.

Un parámetro desconocido falla con 400 Bad Request y el mensaje Unknown search parameter: …. Los parámetros nunca se ignoran en silencio.

GET/fhir/R4/Appointment
curl -G "https://api.medplum.konko.ai/fhir/R4/Appointment" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  --data-urlencode "actor:PractitionerRole.practitioner=Practitioner/d1b5e8c3-4f7a-4d2e-9b6c-8a0f3e5d1c72" \
  --data-urlencode "date=ge2026-10-13T00:00:00-06:00" \
  --data-urlencode "date=lt2026-10-20T00:00:00-06:00" \
  --data-urlencode "status=booked,pending" \
  --data-urlencode "_sort=date"
POST/fhir/R4/Patient/_search
curl -X POST "https://api.medplum.konko.ai/fhir/R4/Patient/_search" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  --data-urlencode "_id=3c9f6a1e-8d4b-4f2a-b5e7-0d9c2f8a6b13,8f2d5b9a-1e6c-4d3f-a7b8-5c0e9d2f4a61" \
  --data-urlencode "_elements=name,telecom,birthDate"
Common parameters
Parámetros comunes
  • _idtoken

    One or more resource IDs, comma-separated.

    Uno o más IDs de recurso, separados por comas.

  • _lastUpdateddate

    When the resource last changed.

    Cuándo cambió el recurso por última vez.

    Example: _lastUpdated=gt2026-10-01T00:00:00Z
    Ejemplo: _lastUpdated=gt2026-10-01T00:00:00Z
  • _countinteger

    Results per page, 1 to 1,000. Default 20.

    Resultados por página, de 1 a 1,000. Predeterminado: 20.

  • _sortstring

    Comma-separated sort keys; a leading - sorts descending.

    Claves de ordenamiento separadas por comas; un - inicial ordena de forma descendente.

    Example: _sort=-date
    Ejemplo: _sort=-date
  • _elementsstring

    Return only these top-level fields, plus id and the required ones.

    Devuelve solo estos campos de nivel superior, más id y los obligatorios.

    Example: _elements=status,start,end,participant
    Ejemplo: _elements=status,start,end,participant
  • _summarycode

    count returns only the number of matches. true returns summary fields only.

    count devuelve solo el número de coincidencias. true devuelve solo los campos de resumen.

  • _totalcode

    accurate or estimate adds total to the Bundle. Without it there is no total, which keeps searches fast.

    accurate o estimate agrega total al Bundle. Sin él no hay total, lo que mantiene las búsquedas rápidas.

  • _include, _revincludestring

    Return referenced or referencing resources in the same Bundle. See Related resources.

    Devuelve los recursos referenciados o los que referencian en el mismo Bundle. Consulta Recursos relacionados.

Working with FHIRTrabajar con FHIR

Pagination

Paginación

Searches return a searchset Bundle holding one page of results. Follow its next link until there isn't one.

Las búsquedas devuelven un Bundle searchset con una página de resultados. Sigue su enlace next hasta que ya no haya uno.

  • Each result is an entry with the resource, its fullUrl, and search.mode: match for results, include for resources added by _include or _revinclude.
  • Cada resultado es un entry con el recurso, su fullUrl y search.mode: match para los resultados, include para los recursos agregados por _include o _revinclude.
  • Pages hold 20 results by default. Ask for up to 1,000 with _count.
  • Las páginas contienen 20 resultados de forma predeterminada. Pide hasta 1,000 con _count.
  • link lists self, first and, when more results exist, next. Request the next URL exactly as given, with your token. Don't build page URLs yourself.
  • link lista self, first y, cuando hay más resultados, next. Solicita la URL de next exactamente como se entrega, con tu token. No construyas las URL de página por tu cuenta.
  • By default pages are numbered with _offset, which stops at 10,000 results with 400 Search offset exceeds maximum.
  • De forma predeterminada las páginas se numeran con _offset, que se detiene en 10,000 resultados con 400 Search offset exceeds maximum.
  • To read further, sort by _lastUpdated ascending and nothing else, with _count of at least 20. The next links then use a _cursor and have no limit. This is the right way to export a whole resource type.
  • Para leer más allá, ordena por _lastUpdated ascendente y nada más, con un _count de al menos 20. Los enlaces next usan entonces un _cursor y no tienen límite. Esta es la forma correcta de exportar un tipo de recurso completo.
  • Bundles carry no total unless you ask for _total=accurate. For a count alone, use _summary=count.
  • Los Bundle no incluyen total a menos que pidas _total=accurate. Para obtener solo el conteo, usa _summary=count.
NoteNota

A next link repeats your whole query. If the query is long, the link can exceed the URL limit and fail with 431. Send its query string as a form body to POST …/_search instead.

Un enlace next repite toda tu consulta. Si la consulta es larga, el enlace puede exceder el límite de la URL y fallar con 431. En su lugar, envía su cadena de consulta como cuerpo de formulario a POST …/_search.

Read every page
Leer todas las páginas
import requests

def fetch_all(url: str, params: dict, token: str):
    """Yields every matching resource, following the server's next links."""
    headers = {"Authorization": f"Bearer {token}"}
    resp = requests.get(url, params=params, headers=headers, timeout=30)
    while True:
        resp.raise_for_status()
        bundle = resp.json()
        for entry in bundle.get("entry", []):
            if entry.get("search", {}).get("mode", "match") == "match":
                yield entry["resource"]
        next_url = next((l["url"] for l in bundle.get("link", []) if l["relation"] == "next"), None)
        if not next_url:
            return
        resp = requests.get(next_url, headers=headers, timeout=30)


for appt in fetch_all(
    "https://api.medplum.konko.ai/fhir/R4/Appointment",
    {"_lastUpdated": "gt2026-10-01T00:00:00Z", "_sort": "_lastUpdated", "_count": 200},
    access_token,
):
    upsert(appt)
Cursor links
Enlaces de cursor
{
  "resourceType": "Bundle",
  "type": "searchset",
  "entry": [],
  "link": [
    {
      "relation": "self",
      "url": "https://api.medplum.konko.ai/fhir/R4/Appointment?_count=200&_lastUpdated=gt2026-10-01T00%3A00%3A00Z&_sort=_lastUpdated"
    },
    {
      "relation": "first",
      "url": "https://api.medplum.konko.ai/fhir/R4/Appointment?_count=200&_lastUpdated=gt2026-10-01T00%3A00%3A00Z&_sort=_lastUpdated"
    },
    {
      "relation": "next",
      "url": "https://api.medplum.konko.ai/fhir/R4/Appointment?_count=200&_cursor=2-1759763347382-&_lastUpdated=gt2026-10-01T00%3A00%3A00Z&_sort=_lastUpdated"
    }
  ]
}
Working with FHIRTrabajar con FHIR

Related resources

Recursos relacionados

Fetch the resources a result points to, or the ones that point to it, in the same request.

Obtén los recursos a los que apunta un resultado, o los que apuntan a él, en la misma solicitud.

  • _include=Appointment:patient adds the patient referenced by each appointment. The value is SourceType:search-parameter.
  • _include=Appointment:patient agrega el paciente referenciado por cada cita. El valor es SourceType:search-parameter.
  • _include:iterate follows references from resources that were themselves included: _include=Appointment:actor&_include:iterate=PractitionerRole:practitioner returns appointments, their PractitionerRoles and those roles' practitioners.
  • _include:iterate sigue las referencias de recursos que a su vez fueron incluidos: _include=Appointment:actor&_include:iterate=PractitionerRole:practitioner devuelve las citas, sus PractitionerRole y los profesionales de esos roles.
  • _revinclude works the other way round and adds resources that reference the results: GET /Practitioner?_revinclude=PractitionerRole:practitioner returns practitioners with all their roles.
  • _revinclude funciona en sentido inverso y agrega los recursos que referencian a los resultados: GET /Practitioner?_revinclude=PractitionerRole:practitioner devuelve los profesionales con todos sus roles.
  • Included resources come after the matches on the same page, with search.mode set to include.
  • Los recursos incluidos vienen después de las coincidencias en la misma página, con search.mode en include.
  • Each included resource costs 1 point of your quota, far less than reading it separately.
  • Cada recurso incluido cuesta 1 punto de tu cuota, mucho menos que leerlo por separado.
GET/fhir/R4/PractitionerRole
curl -G "https://api.medplum.konko.ai/fhir/R4/PractitionerRole" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  --data-urlencode "location=Location/e4a9c1d7-2b6f-4a3e-9c8d-5f1b7e0a2c64" \
  --data-urlencode "_include=PractitionerRole:practitioner" \
  --data-urlencode "_include=PractitionerRole:service"
Working with FHIRTrabajar con FHIR

Common tasks

Tareas comunes

Requests for the questions integrations ask most often. Paths are relative to /fhir/R4; URL-encode values when you send them.

Solicitudes para las preguntas que las integraciones hacen con más frecuencia. Las rutas son relativas a /fhir/R4; codifica los valores para URL cuando los envíes.

TaskTareaRequestSolicitud
A patient's upcoming appointmentsLas próximas citas de un pacienteGET /Appointment?patient=Patient/3c9f6a1e…&date=ge2026-10-05T00:00:00-06:00&status=booked&_sort=date
Today's agenda at one locationLa agenda de hoy en una sedeGET /Appointment?actor:PractitionerRole.location=Location/e4a9c1d7…&date=ge2026-10-13T00:00:00-06:00&date=lt2026-10-14T00:00:00-06:00&_include=Appointment:patient&_sort=date
A doctor's week across all locationsLa semana de un médico en todas las sedesGET /Appointment?actor:PractitionerRole.practitioner=Practitioner/d1b5e8c3…&date=ge2026-10-12&date=lt2026-10-19
Doctors at a location, with their servicesLos médicos de una sede, con sus serviciosGET /PractitionerRole?location=Location/e4a9c1d7…&active=true&_include=PractitionerRole:practitioner&_include=PractitionerRole:service
Time blocked by the clinic this weekTiempo bloqueado por la clínica esta semanaGET /Slot?status=busy-unavailable&start=ge2026-10-12T00:00:00-06:00&start=lt2026-10-19T00:00:00-06:00
Find a patient by EHR file numberBuscar un paciente por número de expediente del EHRGET /Patient?identifier=https://konko.ai/huli/1/patient-file|10
Find a patient by phoneBuscar un paciente por teléfonoGET /Patient?phone=87654321,+50687654321
Cancellations since yesterdayCancelaciones desde ayerGET /Appointment?status=cancelled&_lastUpdated=gt2026-10-12T00:00:00-06:00
Bookable servicesServicios agendablesGET /HealthcareService?active=true&_elements=name,type,location,extension
Count this month's no-showsContar las inasistencias de este mesGET /Appointment?status=noshow&date=ge2026-10-01&date=lt2026-11-01&_summary=count
Working with FHIRTrabajar con FHIR

Version history

Historial de versiones

Every change creates a new version. You can list a resource's versions or read an old one, for any resource type your client can read.

Cada cambio crea una nueva versión. Puedes listar las versiones de un recurso o leer una anterior, para cualquier tipo de recurso que tu cliente pueda leer.

List a resource's versions

Listar las versiones de un recurso

GET/fhir/R4/{type}/{id}/_history

Returns every stored version of one resource, newest first, as a history Bundle. Each entry is one version; a version where the resource was deleted has no resource and an outcome that says Deleted on ….

Devuelve todas las versiones almacenadas de un recurso, de la más reciente a la más antigua, como un Bundle history. Cada entrada es una versión; una versión en la que el recurso fue eliminado no tiene resource y tiene un outcome que dice Deleted on ….

Parameters
Parámetros
  • ididRequiredObligatorio

    The resource id (path).

    El id del recurso (ruta).

  • _countinteger

    Versions per page, up to 1,000. Default 100.

    Versiones por página, hasta 1,000. Predeterminado: 100.

  • _offsetinteger

    Number of versions to skip. History Bundles have no next link; page with _offset and stop when total is reached.

    Número de versiones a omitir. Los Bundle de historial no tienen enlace next; pagina con _offset y detente cuando alcances total.

History is available per resource only. There is no history across a whole type; search with _lastUpdated instead.

El historial solo está disponible por recurso. No hay historial para un tipo completo; en su lugar, busca con _lastUpdated.

GET/fhir/R4/Appointment/{id}/_history
curl "https://api.medplum.konko.ai/fhir/R4/Appointment/{appointment_id}/_history" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
200 OK  Response
200 OK  Respuesta
{
  "resourceType": "Bundle",
  "type": "history",
  "entry": [
    {
      "fullUrl": "https://api.medplum.konko.ai/fhir/R4/Appointment/6b1f8e3d-2a9c-4b5e-8f7d-3e0a6c1b9d84",
      "request": {
        "method": "GET",
        "url": "Appointment/6b1f8e3d-2a9c-4b5e-8f7d-3e0a6c1b9d84/_history/0d6b3f9e-4a1c-4e7b-8f2d-9c5a1e7b3d60"
      },
      "response": {
        "status": "200",
        "outcome": {
          "resourceType": "OperationOutcome",
          "id": "ok",
          "issue": [
            {
              "severity": "information",
              "code": "informational",
              "details": {
                "text": "All OK"
              }
            }
          ]
        }
      },
      "resource": {
        "resourceType": "Appointment",
        "id": "6b1f8e3d-2a9c-4b5e-8f7d-3e0a6c1b9d84",
        "meta": {
          "versionId": "0d6b3f9e-4a1c-4e7b-8f2d-9c5a1e7b3d60",
          "lastUpdated": "2026-10-09T16:20:02.841Z"
        },
        "identifier": [
          {
            "system": "https://konko.ai/huli/appointment",
            "value": "100"
          }
        ],
        "status": "cancelled",
        "description": "Consulta de Ginecología — Ana Lucía Mora Vargas",
        "start": "2026-10-13T08:30:00-06:00",
        "end": "2026-10-13T09:00:00-06:00",
        "slot": [
          {
            "reference": "Slot/5e8b1d4f-7a2c-4e9d-8b3f-1c6a0e9d7b26"
          }
        ],
        "participant": [
          {
            "actor": {
              "reference": "PractitionerRole/f7c3a9e5-1b8d-4e6f-a2c4-9d7b0e3f5a18"
            },
            "status": "tentative"
          },
          {
            "actor": {
              "reference": "Patient/3c9f6a1e-8d4b-4f2a-b5e7-0d9c2f8a6b13"
            },
            "status": "accepted"
          }
        ]
      }
    },
    {
      "fullUrl": "https://api.medplum.konko.ai/fhir/R4/Appointment/6b1f8e3d-2a9c-4b5e-8f7d-3e0a6c1b9d84",
      "request": {
        "method": "GET",
        "url": "Appointment/6b1f8e3d-2a9c-4b5e-8f7d-3e0a6c1b9d84/_history/a8f1c4e7-2b9d-4e6a-9c3f-5d0b8e2a7c14"
      },
      "response": {
        "status": "200",
        "outcome": {
          "resourceType": "OperationOutcome",
          "id": "ok",
          "issue": [
            {
              "severity": "information",
              "code": "informational",
              "details": {
                "text": "All OK"
              }
            }
          ]
        }
      },
      "resource": {
        "resourceType": "Appointment",
        "id": "6b1f8e3d-2a9c-4b5e-8f7d-3e0a6c1b9d84",
        "meta": {
          "versionId": "a8f1c4e7-2b9d-4e6a-9c3f-5d0b8e2a7c14",
          "lastUpdated": "2026-10-05T15:21:47.382Z"
        },
        "identifier": [
          {
            "system": "https://konko.ai/huli/appointment",
            "value": "100"
          }
        ],
        "status": "booked",
        "description": "Consulta de Ginecología — Ana Lucía Mora Vargas",
        "start": "2026-10-13T08:30:00-06:00",
        "end": "2026-10-13T09:00:00-06:00",
        "slot": [
          {
            "reference": "Slot/5e8b1d4f-7a2c-4e9d-8b3f-1c6a0e9d7b26"
          }
        ],
        "participant": [
          {
            "actor": {
              "reference": "PractitionerRole/f7c3a9e5-1b8d-4e6f-a2c4-9d7b0e3f5a18"
            },
            "status": "tentative"
          },
          {
            "actor": {
              "reference": "Patient/3c9f6a1e-8d4b-4f2a-b5e7-0d9c2f8a6b13"
            },
            "status": "accepted"
          }
        ]
      }
    }
  ],
  "total": 2
}

Read one version

Leer una versión

GET/fhir/R4/{type}/{id}/_history/{vid}

Returns one specific version of a resource, by the versionId found in meta or in a history entry.

Devuelve una versión específica de un recurso, por el versionId que se encuentra en meta o en una entrada del historial.

Path parameters
Parámetros de ruta
  • ididRequiredObligatorio

    The resource id.

    El id del recurso.

  • vididRequiredObligatorio

    The versionId.

    El versionId.

GET/fhir/R4/Appointment/{id}/_history/{vid}
curl "https://api.medplum.konko.ai/fhir/R4/Appointment/{appointment_id}/_history/{version_id}" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
Working with FHIRTrabajar con FHIR

Batch requests

Solicitudes por lotes

Combine several reads and searches in one round trip.

Combina varias lecturas y búsquedas en un solo viaje de ida y vuelta.

Send a batch

Enviar un lote

POST/fhir/R4

Sends several reads and searches in one HTTP request. Post a Bundle of type batch whose entries each have a request with method: GET and a URL relative to /fhir/R4.

Envía varias lecturas y búsquedas en una sola solicitud HTTP. Haz un POST con un Bundle de tipo batch cuyas entradas tengan cada una un request con method: GET y una URL relativa a /fhir/R4.

The response is a batch-response Bundle with one entry per request, in the same order. Each entry has its own response.status, so one failed entry doesn't fail the others.

La respuesta es un Bundle batch-response con una entrada por solicitud, en el mismo orden. Cada entrada tiene su propio response.status, así que una entrada fallida no hace fallar a las demás.

  • Every entry counts against your quota as if you had sent it separately.
  • Cada entrada cuenta contra tu cuota como si la hubieras enviado por separado.
  • The request body is limited to 1 MB.
  • El cuerpo de la solicitud está limitado a 1 MB.
  • Entries are processed independently, not in the order you list them.
  • Las entradas se procesan de forma independiente, no en el orden en que las listas.
POST/fhir/R4
curl -X POST "https://api.medplum.konko.ai/fhir/R4" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/fhir+json" \
  -d '{
  "resourceType": "Bundle",
  "type": "batch",
  "entry": [
    {
      "request": {
        "method": "GET",
        "url": "Patient/3c9f6a1e-8d4b-4f2a-b5e7-0d9c2f8a6b13"
      }
    },
    {
      "request": {
        "method": "GET",
        "url": "PractitionerRole/f7c3a9e5-1b8d-4e6f-a2c4-9d7b0e3f5a18"
      }
    },
    {
      "request": {
        "method": "GET",
        "url": "Appointment?patient=Patient/3c9f6a1e-8d4b-4f2a-b5e7-0d9c2f8a6b13&date=ge2026-10-01&_count=10"
      }
    }
  ]
}'
200 OK  Response
200 OK  Respuesta
{
  "resourceType": "Bundle",
  "type": "batch-response",
  "entry": [
    {
      "response": {
        "outcome": {
          "resourceType": "OperationOutcome",
          "id": "ok",
          "issue": [
            {
              "severity": "information",
              "code": "informational",
              "details": {
                "text": "All OK"
              }
            }
          ]
        },
        "status": "200",
        "location": "Patient/3c9f6a1e-8d4b-4f2a-b5e7-0d9c2f8a6b13"
      },
      "resource": {
        "resourceType": "Patient",
        "id": "3c9f6a1e-8d4b-4f2a-b5e7-0d9c2f8a6b13",
        "meta": {
          "versionId": "6e3b9f1d-8a5c-4d2e-b7f4-1c6a9e3d8b50",
          "lastUpdated": "2026-10-05T15:21:40.964Z"
        },
        "identifier": [
          {
            "system": "https://konko.ai/huli/1/patient-file",
            "value": "10"
          }
        ],
        "active": true,
        "name": [
          {
            "use": "official",
            "family": "Mora Vargas",
            "given": [
              "Ana Lucía"
            ]
          }
        ],
        "telecom": [
          {
            "system": "phone",
            "value": "87654321"
          },
          {
            "system": "email",
            "value": "ana.mora@correo.example"
          }
        ],
        "gender": "female",
        "birthDate": "1990-04-17",
        "address": [
          {
            "text": "Santa Ana, San José"
          }
        ]
      }
    },
    {
      "response": {
        "outcome": {
          "resourceType": "OperationOutcome",
          "id": "ok",
          "issue": [
            {
              "severity": "information",
              "code": "informational",
              "details": {
                "text": "All OK"
              }
            }
          ]
        },
        "status": "200",
        "location": "PractitionerRole/f7c3a9e5-1b8d-4e6f-a2c4-9d7b0e3f5a18"
      },
      "resource": {
        "resourceType": "PractitionerRole",
        "id": "f7c3a9e5-1b8d-4e6f-a2c4-9d7b0e3f5a18",
        "meta": {
          "versionId": "2c7e0a4d-9f3b-4d6a-b1e8-5f2c9a7d0e43",
          "lastUpdated": "2026-09-14T17:02:17.056Z"
        },
        "language": "es",
        "extension": [
          {
            "url": "http://hl7.org/fhir/StructureDefinition/timezone",
            "valueCode": "America/Costa_Rica"
          }
        ],
        "identifier": [
          {
            "system": "https://konko.ai/practitioner-role",
            "value": "DOC001:LOC001"
          }
        ],
        "active": true,
        "practitioner": {
          "reference": "Practitioner/d1b5e8c3-4f7a-4d2e-9b6c-8a0f3e5d1c72"
        },
        "organization": {
          "reference": "Organization/b2d7e4a1-5c3f-4e9b-8a1d-6f2c0e7b9d35"
        },
        "specialty": [
          {
            "text": "Ginecología"
          }
        ],
        "location": [
          {
            "reference": "Location/e4a9c1d7-2b6f-4a3e-9c8d-5f1b7e0a2c64"
          }
        ],
        "healthcareService": [
          {
            "reference": "HealthcareService/a3f6b8d2-9e1c-4b7a-8d5f-2c0e6a9b1d47"
          }
        ]
      }
    },
    {
      "response": {
        "outcome": {
          "resourceType": "OperationOutcome",
          "id": "ok",
          "issue": [
            {
              "severity": "information",
              "code": "informational",
              "details": {
                "text": "All OK"
              }
            }
          ]
        },
        "status": "200"
      },
      "resource": {
        "resourceType": "Bundle",
        "type": "searchset",
        "entry": [
          {
            "fullUrl": "https://api.medplum.konko.ai/fhir/R4/Appointment/6b1f8e3d-2a9c-4b5e-8f7d-3e0a6c1b9d84",
            "resource": {
              "resourceType": "Appointment",
              "id": "6b1f8e3d-2a9c-4b5e-8f7d-3e0a6c1b9d84",
              "meta": {
                "versionId": "a8f1c4e7-2b9d-4e6a-9c3f-5d0b8e2a7c14",
                "lastUpdated": "2026-10-05T15:21:47.382Z"
              },
              "identifier": [
                {
                  "system": "https://konko.ai/huli/appointment",
                  "value": "100"
                }
              ],
              "status": "booked",
              "description": "Consulta de Ginecología — Ana Lucía Mora Vargas",
              "start": "2026-10-13T08:30:00-06:00",
              "end": "2026-10-13T09:00:00-06:00",
              "slot": [
                {
                  "reference": "Slot/5e8b1d4f-7a2c-4e9d-8b3f-1c6a0e9d7b26"
                }
              ],
              "comment": "full_name: Ana Lucía Mora Vargas\nphone_number: +50687654321\nservice: Consulta de Ginecología\nlocation: Sede Escazú",
              "participant": [
                {
                  "actor": {
                    "reference": "PractitionerRole/f7c3a9e5-1b8d-4e6f-a2c4-9d7b0e3f5a18"
                  },
                  "status": "tentative"
                },
                {
                  "actor": {
                    "reference": "Patient/3c9f6a1e-8d4b-4f2a-b5e7-0d9c2f8a6b13"
                  },
                  "status": "accepted"
                }
              ]
            },
            "search": {
              "mode": "match"
            }
          }
        ],
        "link": [
          {
            "relation": "self",
            "url": "https://api.medplum.konko.ai/fhir/R4/Appointment?_count=10&date=ge2026-10-01&patient=Patient%2F3c9f6a1e-8d4b-4f2a-b5e7-0d9c2f8a6b13"
          },
          {
            "relation": "first",
            "url": "https://api.medplum.konko.ai/fhir/R4/Appointment?_count=10&date=ge2026-10-01&patient=Patient%2F3c9f6a1e-8d4b-4f2a-b5e7-0d9c2f8a6b13"
          }
        ]
      }
    }
  ]
}
Working with FHIRTrabajar con FHIR

Conventions

Convenciones

The API follows HL7 FHIR R4 (4.0.1). These are the details that matter most when you parse its responses.

La API sigue HL7 FHIR R4 (4.0.1). Estos son los detalles que más importan al analizar sus respuestas.

TopicTemaConventionConvención
FormatFormatoJSON only, as application/fhir+json. Add _pretty=true for indented output while exploring. Responses are gzip-compressed when you send Accept-Encoding: gzip.Solo JSON, como application/fhir+json. Agrega _pretty=true para obtener una salida indentada mientras exploras. Las respuestas se comprimen con gzip cuando envías Accept-Encoding: gzip.
IDsEvery resource has a UUID id that never changes. Refer to resources as Type/id.Cada recurso tiene un id UUID que nunca cambia. Haz referencia a los recursos como Type/id.
TimesHorasstart, end and other instants carry the clinic's UTC offset, for example 2026-10-13T08:30:00-06:00. meta.lastUpdated is in UTC. Always parse the offset.start, end y otros instantes llevan el desfase UTC de la clínica, por ejemplo 2026-10-13T08:30:00-06:00. meta.lastUpdated está en UTC. Analiza siempre el desfase.
VersionsVersionesmeta.versionId changes on every update. Read responses carry it as ETag: W/"<versionId>". Conditional reads (If-None-Match) aren't supported.meta.versionId cambia en cada actualización. Las respuestas de lectura lo llevan como ETag: W/"<versionId>". Las lecturas condicionales (If-None-Match) no se admiten.
LanguageIdiomaNames, descriptions and instructions are in the clinic's language, usually Spanish. Clinic configuration resources carry language: es.Los nombres, descripciones e instrucciones están en el idioma de la clínica, normalmente español. Los recursos de configuración de la clínica llevan language: es.
ExtensionsExtensionesKonko adds extensions documented on each resource. Ignore extensions you don't recognize, as the FHIR standard requires.Konko agrega extensiones documentadas en cada recurso. Ignora las extensiones que no reconozcas, como exige el estándar FHIR.
Several sourcesVarias fuentesData comes from your EHR, connected calendars, your clinic configuration in Konko and bookings made by Konko's assistant. The same doctor or site can exist more than once; compare identifiers.Los datos provienen de tu EHR, los calendarios conectados, la configuración de tu clínica en Konko y las reservas hechas por el asistente de Konko. El mismo médico o sede puede existir más de una vez; compara los identificadores.
Populated fieldsCampos pobladosAttributes marked Populated are the ones Konko fills. Other standard FHIR fields are valid but usually empty.Los atributos marcados como Poblado son los que Konko llena. Otros campos estándar de FHIR son válidos pero normalmente están vacíos.
PatientsPacientes

Patient

A person who has booked or attended an appointment at your clinic.

Una persona que ha agendado o asistido a una cita en tu clínica.

  • Patients come from three places: your EHR (imported with their patient-file number), calendar invitations (identified by the attendee's email), and bookings made through Konko's assistant (name, phone and birth date as the patient gave them).
  • Los pacientes provienen de tres lugares: tu EHR (importados con su número de expediente), las invitaciones de calendario (identificados por el correo del invitado) y las reservas hechas a través del asistente de Konko (nombre, teléfono y fecha de nacimiento tal como los dio el paciente).
  • The same person can exist more than once, for example once from the EHR and once from a calendar invitation. Compare identifiers, phone numbers and birth dates before merging records on your side.
  • La misma persona puede existir más de una vez, por ejemplo una vez desde el EHR y otra desde una invitación de calendario. Compara identificadores, números de teléfono y fechas de nacimiento antes de fusionar registros de tu lado.
  • Phone numbers are stored as the source provided them. EHR imports often hold local digits (87654321); the assistant stores international format (+50687654321).
  • Los números de teléfono se guardan tal como los proporcionó la fuente. Las importaciones del EHR suelen tener dígitos locales (87654321); el asistente guarda el formato internacional (+50687654321).
AttributesPopulated = filled by Konko
AtributosPoblado = lo llena Konko
  • idid1..1

    Konko's ID for this resource, a UUID. It never changes.

    El ID de Konko para este recurso, un UUID. Nunca cambia.

  • metaMeta1..1

    Version information, maintained by the server.

    Información de versión, mantenida por el servidor.

    2 child attributes2 atributos secundarios
    • versionIdid1..1

      Changes on every update. Use it to detect changes and to ignore duplicate webhook deliveries.

      Cambia en cada actualización. Úsalo para detectar cambios y para ignorar entregas de webhook duplicadas.

    • lastUpdatedinstant1..1

      When this version was saved, in UTC. Search on it with _lastUpdated.

      Cuándo se guardó esta versión, en UTC. Busca por este campo con _lastUpdated.

  • identifierIdentifier0..*PopulatedPoblado

    IDs from the systems this record came from. Match on system and value:

    IDs de los sistemas de los que proviene este registro. Haz coincidir por system y value:

    https://konko.ai/huli/{organizationId}/patient-file: patient-file number in the Huli EHR.

    https://konko.ai/huli/{organizationId}/patient-file: número de expediente en el EHR de Huli.

    https://konko.ai/fhir/identifier/google-calendar-patient: email of a calendar-event attendee.

    https://konko.ai/fhir/identifier/google-calendar-patient: correo de un invitado del evento de calendario.

    Patients created by Konko's assistant have no identifier.

    Los pacientes creados por el asistente de Konko no tienen identificador.

  • activeboolean0..1PopulatedPoblado

    true for records imported from an EHR.

    true para registros importados de un EHR.

  • nameHumanName0..*PopulatedPoblado

    The patient's names.

    Los nombres del paciente.

    5 child attributes5 atributos secundarios
    • usecode0..1

      official for names from an EHR, nickname for a preferred name.

      official para nombres de un EHR, nickname para un nombre preferido.

    • textstring0..1

      The full name as one string. Names collected by Konko's assistant have only text.

      El nombre completo como una sola cadena. Los nombres recopilados por el asistente de Konko solo tienen text.

    • familystring0..1

      Family name, usually both surnames (Mora Vargas).

      Apellido, normalmente ambos apellidos (Mora Vargas).

    • givenstring0..*

      Given names.

      Nombres de pila.

    • prefixstring0..*

      Titles such as Dra or Dr.

      Títulos como Dra o Dr.

  • telecomContactPoint0..*PopulatedPoblado

    Phone numbers and emails.

    Números de teléfono y correos electrónicos.

    3 child attributes3 atributos secundarios
    • systemcode0..1

      phone, email or url.

      phone, email o url.

    • valuestring0..1

      The number, address or URL, as stored by the source.

      El número, la dirección o la URL, tal como los guardó la fuente.

    • usecode0..1

      mobile on numbers collected by Konko's assistant.

      mobile en los números recopilados por el asistente de Konko.

  • gendercode0..1PopulatedPoblado

    male, female, other or unknown.

    male, female, other o unknown.

  • birthDatedate0..1PopulatedPoblado

    YYYY-MM-DD.

  • addressAddress0..*PopulatedPoblado

    Usually free text in text.

    Normalmente texto libre en text.

  • Other FHIR fieldsOtros campos FHIR

    communication, contact, generalPractitioner, managingOrganization, maritalStatus, deceased[x], photo and link are part of the standard resource. Konko doesn't fill them today, so treat them as optional.

    communication, contact, generalPractitioner, managingOrganization, maritalStatus, deceased[x], photo y link forman parte del recurso estándar. Konko no los llena hoy, así que trátalos como opcionales.

The Patient object
El objeto Patient
{
  "resourceType": "Patient",
  "id": "3c9f6a1e-8d4b-4f2a-b5e7-0d9c2f8a6b13",
  "meta": {
    "versionId": "6e3b9f1d-8a5c-4d2e-b7f4-1c6a9e3d8b50",
    "lastUpdated": "2026-10-05T15:21:40.964Z"
  },
  "identifier": [
    {
      "system": "https://konko.ai/huli/1/patient-file",
      "value": "10"
    }
  ],
  "active": true,
  "name": [
    {
      "use": "official",
      "family": "Mora Vargas",
      "given": [
        "Ana Lucía"
      ]
    }
  ],
  "telecom": [
    {
      "system": "phone",
      "value": "87654321"
    },
    {
      "system": "email",
      "value": "ana.mora@correo.example"
    }
  ],
  "gender": "female",
  "birthDate": "1990-04-17",
  "address": [
    {
      "text": "Santa Ana, San José"
    }
  ]
}

Retrieve a patient

Obtener un paciente

GET/fhir/R4/Patient/{id}

Returns a patient by its id. The response carries ETag: W/"<versionId>" and Last-Modified headers.

Devuelve un paciente por su id. La respuesta lleva los encabezados ETag: W/"<versionId>" y Last-Modified.

Returns 404 Not Found if no Patient with that id exists in your project, and 410 Gone if it was deleted.

Devuelve 404 Not Found si no existe ningún Patient con ese id en tu proyecto, y 410 Gone si fue eliminado.

Path parameters
Parámetros de ruta
  • ididRequiredObligatorio

    The Patient id.

    El id del Patient.

GET/fhir/R4/Patient/{id}
curl "https://api.medplum.konko.ai/fhir/R4/Patient/{patient_id}" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
200 OK  Response
200 OK  Respuesta
{
  "resourceType": "Patient",
  "id": "3c9f6a1e-8d4b-4f2a-b5e7-0d9c2f8a6b13",
  "meta": {
    "versionId": "6e3b9f1d-8a5c-4d2e-b7f4-1c6a9e3d8b50",
    "lastUpdated": "2026-10-05T15:21:40.964Z"
  },
  "identifier": [
    {
      "system": "https://konko.ai/huli/1/patient-file",
      "value": "10"
    }
  ],
  "active": true,
  "name": [
    {
      "use": "official",
      "family": "Mora Vargas",
      "given": [
        "Ana Lucía"
      ]
    }
  ],
  "telecom": [
    {
      "system": "phone",
      "value": "87654321"
    },
    {
      "system": "email",
      "value": "ana.mora@correo.example"
    }
  ],
  "gender": "female",
  "birthDate": "1990-04-17",
  "address": [
    {
      "text": "Santa Ana, San José"
    }
  ]
}
ProvidersProfesionales

Practitioner

A doctor or other professional who sees patients at your clinic.

Un médico u otro profesional que atiende pacientes en tu clínica.

  • A practitioner holds the person's details. Where they work and what they offer hang off their PractitionerRole.
  • Un profesional contiene los datos de la persona. Dónde trabaja y qué ofrece se definen en su PractitionerRole.
  • The same doctor can appear as more than one Practitioner when the data comes from several sources: your EHR, the clinic configuration in Konko, and staff user accounts. Konko's assistant only schedules for practitioners that carry the https://konko.ai/fhir/knowledge-base-id identifier.
  • El mismo médico puede aparecer como más de un Practitioner cuando los datos provienen de varias fuentes: tu EHR, la configuración de la clínica en Konko y las cuentas de usuario del personal. El asistente de Konko solo agenda para los profesionales que llevan el identificador https://konko.ai/fhir/knowledge-base-id.
AttributesPopulated = filled by Konko
AtributosPoblado = lo llena Konko
  • idid1..1

    Konko's ID for this resource, a UUID. It never changes.

    El ID de Konko para este recurso, un UUID. Nunca cambia.

  • metaMeta1..1

    Version information, maintained by the server.

    Información de versión, mantenida por el servidor.

    2 child attributes2 atributos secundarios
    • versionIdid1..1

      Changes on every update. Use it to detect changes and to ignore duplicate webhook deliveries.

      Cambia en cada actualización. Úsalo para detectar cambios y para ignorar entregas de webhook duplicadas.

    • lastUpdatedinstant1..1

      When this version was saved, in UTC. Search on it with _lastUpdated.

      Cuándo se guardó esta versión, en UTC. Busca por este campo con _lastUpdated.

  • identifierIdentifier0..*PopulatedPoblado

    IDs from the systems this record came from. Match on system and value:

    IDs de los sistemas de los que proviene este registro. Haz coincidir por system y value:

    https://konko.ai/huli/doctor and https://konko.ai/huli/user: doctor and user IDs in the Huli EHR.

    https://konko.ai/huli/doctor y https://konko.ai/huli/user: IDs de médico y de usuario en el EHR de Huli.

    https://konko.ai/practitioner: the practitioner's code in the clinic configuration, such as DOC001.

    https://konko.ai/practitioner: el código del profesional en la configuración de la clínica, como DOC001.

    https://konko.ai/fhir/knowledge-base-id: the same DOC### code, on the practitioners Konko's assistant books for.

    https://konko.ai/fhir/knowledge-base-id: el mismo código DOC###, en los profesionales para los que agenda el asistente de Konko.

  • activeboolean0..1PopulatedPoblado

    Whether the practitioner is in use.

    Si el profesional está en uso.

  • nameHumanName0..*PopulatedPoblado

    The practitioner's name, including titles in prefix or text.

    El nombre del profesional, incluidos los títulos en prefix o text.

    5 child attributes5 atributos secundarios
    • usecode0..1

      official for names from an EHR, nickname for a preferred name.

      official para nombres de un EHR, nickname para un nombre preferido.

    • textstring0..1

      The full name as one string. Names collected by Konko's assistant have only text.

      El nombre completo como una sola cadena. Los nombres recopilados por el asistente de Konko solo tienen text.

    • familystring0..1

      Family name, usually both surnames (Mora Vargas).

      Apellido, normalmente ambos apellidos (Mora Vargas).

    • givenstring0..*

      Given names.

      Nombres de pila.

    • prefixstring0..*

      Titles such as Dra or Dr.

      Títulos como Dra o Dr.

  • telecomContactPoint0..*PopulatedPoblado

    Contact details that apply to all of the practitioner's roles.

    Datos de contacto que aplican a todos los roles del profesional.

    3 child attributes3 atributos secundarios
    • systemcode0..1

      phone, email or url.

      phone, email o url.

    • valuestring0..1

      The number, address or URL, as stored by the source.

      El número, la dirección o la URL, tal como los guardó la fuente.

    • usecode0..1

      mobile on numbers collected by Konko's assistant.

      mobile en los números recopilados por el asistente de Konko.

  • gendercode0..1PopulatedPoblado

    male, female, other or unknown.

    male, female, other o unknown.

  • qualificationBackboneElement0..*PopulatedPoblado

    Licences and specialties from the EHR.

    Licencias y especialidades del EHR.

    2 child attributes2 atributos secundarios
    • identifierIdentifier0..*

      https://konko.ai/huli/professional-license for a licence number, https://konko.ai/huli/specialty for a specialty ID.

      https://konko.ai/huli/professional-license para un número de licencia, https://konko.ai/huli/specialty para un ID de especialidad.

    • codeCodeableConcept1..1

      The qualification as text only, for example Ginecología y Obstetricia.

      La cualificación solo como texto, por ejemplo Ginecología y Obstetricia.

  • extensionExtension0..*PopulatedPoblado

    Konko extensions. Ignore any you don't recognize; some are for Konko's internal use.

    Extensiones de Konko. Ignora las que no reconozcas; algunas son de uso interno de Konko.

    1 child attribute1 atributo secundario
    • biographyvalueString0..1

      url: https://konko.ai/practitioner/biography

      A short biography written for patients.

      Una biografía corta escrita para los pacientes.

  • languagecode0..1PopulatedPoblado

    es on resources that come from the clinic's configuration in Konko.

    es en los recursos que provienen de la configuración de la clínica en Konko.

  • Other FHIR fieldsOtros campos FHIR

    address, birthDate, photo and communication are part of the standard resource. Konko doesn't fill them today, so treat them as optional.

    address, birthDate, photo y communication forman parte del recurso estándar. Konko no los llena hoy, así que trátalos como opcionales.

The Practitioner object
El objeto Practitioner
{
  "resourceType": "Practitioner",
  "id": "d1b5e8c3-4f7a-4d2e-9b6c-8a0f3e5d1c72",
  "meta": {
    "versionId": "9e2b5d8f-4c1a-4b7e-8d3f-2a6c0e9b5d17",
    "lastUpdated": "2026-09-20T13:44:08.771Z"
  },
  "identifier": [
    {
      "system": "https://konko.ai/huli/doctor",
      "value": "1000"
    },
    {
      "system": "https://konko.ai/huli/user",
      "value": "10000"
    },
    {
      "system": "https://konko.ai/fhir/knowledge-base-id",
      "value": "DOC001"
    }
  ],
  "active": true,
  "name": [
    {
      "use": "official",
      "text": "Dra. Carolina Jiménez Soto",
      "family": "Jiménez Soto",
      "given": [
        "Carolina"
      ]
    }
  ],
  "telecom": [
    {
      "system": "phone",
      "value": "88112233"
    },
    {
      "system": "email",
      "value": "dra.jimenez@clinicahorizonte.example"
    }
  ],
  "gender": "female",
  "qualification": [
    {
      "identifier": [
        {
          "system": "https://konko.ai/huli/professional-license",
          "value": "MED-12345"
        }
      ],
      "code": {
        "text": "Colegio de Médicos y Cirujanos"
      }
    },
    {
      "identifier": [
        {
          "system": "https://konko.ai/huli/specialty",
          "value": "41"
        }
      ],
      "code": {
        "text": "Ginecología y Obstetricia"
      }
    }
  ]
}

Retrieve a practitioner

Obtener un profesional

GET/fhir/R4/Practitioner/{id}

Returns a practitioner by its id. The response carries ETag: W/"<versionId>" and Last-Modified headers.

Devuelve un profesional por su id. La respuesta lleva los encabezados ETag: W/"<versionId>" y Last-Modified.

Returns 404 Not Found if no Practitioner with that id exists in your project, and 410 Gone if it was deleted.

Devuelve 404 Not Found si no existe ningún Practitioner con ese id en tu proyecto, y 410 Gone si fue eliminado.

Path parameters
Parámetros de ruta
  • ididRequiredObligatorio

    The Practitioner id.

    El id del Practitioner.

GET/fhir/R4/Practitioner/{id}
curl "https://api.medplum.konko.ai/fhir/R4/Practitioner/{practitioner_id}" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
200 OK  Response
200 OK  Respuesta
{
  "resourceType": "Practitioner",
  "id": "d1b5e8c3-4f7a-4d2e-9b6c-8a0f3e5d1c72",
  "meta": {
    "versionId": "9e2b5d8f-4c1a-4b7e-8d3f-2a6c0e9b5d17",
    "lastUpdated": "2026-09-20T13:44:08.771Z"
  },
  "identifier": [
    {
      "system": "https://konko.ai/huli/doctor",
      "value": "1000"
    },
    {
      "system": "https://konko.ai/huli/user",
      "value": "10000"
    },
    {
      "system": "https://konko.ai/fhir/knowledge-base-id",
      "value": "DOC001"
    }
  ],
  "active": true,
  "name": [
    {
      "use": "official",
      "text": "Dra. Carolina Jiménez Soto",
      "family": "Jiménez Soto",
      "given": [
        "Carolina"
      ]
    }
  ],
  "telecom": [
    {
      "system": "phone",
      "value": "88112233"
    },
    {
      "system": "email",
      "value": "dra.jimenez@clinicahorizonte.example"
    }
  ],
  "gender": "female",
  "qualification": [
    {
      "identifier": [
        {
          "system": "https://konko.ai/huli/professional-license",
          "value": "MED-12345"
        }
      ],
      "code": {
        "text": "Colegio de Médicos y Cirujanos"
      }
    },
    {
      "identifier": [
        {
          "system": "https://konko.ai/huli/specialty",
          "value": "41"
        }
      ],
      "code": {
        "text": "Ginecología y Obstetricia"
      }
    }
  ]
}
ProvidersProfesionales

PractitionerRole

A practitioner working at a location. It links the doctor to the place and the services they offer, and it's what appointments point to.

Un profesional que trabaja en una sede. Vincula al médico con el lugar y los servicios que ofrece, y es a lo que apuntan las citas.

  • Clinic configuration creates one role for every practitioner at every location where they work. Roles synced from an EHR or a calendar may lack organization or location.
  • La configuración de la clínica crea un rol por cada profesional en cada sede donde trabaja. Los roles sincronizados desde un EHR o un calendario pueden carecer de organization o location.
  • To find everything about one doctor, start from their roles: GET /PractitionerRole?practitioner=Practitioner/{id}.
  • Para encontrar todo sobre un médico, parte de sus roles: GET /PractitionerRole?practitioner=Practitioner/{id}.
AttributesPopulated = filled by Konko
AtributosPoblado = lo llena Konko
  • idid1..1

    Konko's ID for this resource, a UUID. It never changes.

    El ID de Konko para este recurso, un UUID. Nunca cambia.

  • metaMeta1..1

    Version information, maintained by the server.

    Información de versión, mantenida por el servidor.

    2 child attributes2 atributos secundarios
    • versionIdid1..1

      Changes on every update. Use it to detect changes and to ignore duplicate webhook deliveries.

      Cambia en cada actualización. Úsalo para detectar cambios y para ignorar entregas de webhook duplicadas.

    • lastUpdatedinstant1..1

      When this version was saved, in UTC. Search on it with _lastUpdated.

      Cuándo se guardó esta versión, en UTC. Busca por este campo con _lastUpdated.

  • identifierIdentifier0..*PopulatedPoblado

    IDs from the systems this record came from. Match on system and value:

    IDs de los sistemas de los que proviene este registro. Haz coincidir por system y value:

    https://konko.ai/practitioner-role: practitioner code and location code, such as DOC001:LOC001.

    https://konko.ai/practitioner-role: código del profesional y código de la sede, como DOC001:LOC001.

    https://konko.ai/huli/practitioner-role: Huli doctor ID and clinic ID, as {doctorId}:{clinicId}.

    https://konko.ai/huli/practitioner-role: ID del médico y de la clínica en Huli, como {doctorId}:{clinicId}.

    https://konko.ai/fhir/identifier/google-calendar-practitioner-role: email of the connected Google Calendar.

    https://konko.ai/fhir/identifier/google-calendar-practitioner-role: correo del Google Calendar conectado.

  • activeboolean0..1PopulatedPoblado

    Whether the role is in use.

    Si el rol está en uso.

  • practitionerReference(Practitioner)0..1PopulatedPoblado

    The practitioner.

    El profesional.

  • organizationReference(Organization)0..1PopulatedPoblado

    The organization the practitioner works for in this role. Organizations aren't part of this API.

    La organización para la que trabaja el profesional en este rol. Las organizaciones no forman parte de esta API.

  • locationReference(Location)0..*PopulatedPoblado

    Where the practitioner works in this role. Normally one location.

    Dónde trabaja el profesional en este rol. Normalmente una sede.

  • healthcareServiceReference(HealthcareService)0..*PopulatedPoblado

    Services this practitioner is specifically assigned to. A service that any practitioner can provide isn't listed, so an empty list doesn't mean the practitioner offers nothing.

    Servicios asignados específicamente a este profesional. Un servicio que cualquier profesional puede ofrecer no aparece aquí, así que una lista vacía no significa que el profesional no ofrezca nada.

  • specialtyCodeableConcept0..*PopulatedPoblado

    Specialty as text only, for example {"text": "Ginecología"}.

    Especialidad solo como texto, por ejemplo {"text": "Ginecología"}.

  • telecomContactPoint0..*PopulatedPoblado

    Contact details for this role.

    Datos de contacto de este rol.

    3 child attributes3 atributos secundarios
    • systemcode0..1

      phone, email or url.

      phone, email o url.

    • valuestring0..1

      The number, address or URL, as stored by the source.

      El número, la dirección o la URL, tal como los guarda la fuente.

    • usecode0..1

      mobile on numbers collected by Konko's assistant.

      mobile en los números recopilados por el asistente de Konko.

  • extensionExtension0..*PopulatedPoblado

    Konko extensions.

    Extensiones de Konko.

    1 child attribute1 atributo secundario
    • timezonevalueCode0..1

      url: http://hl7.org/fhir/StructureDefinition/timezone

      IANA time zone, for example America/Costa_Rica.

      Zona horaria IANA, por ejemplo America/Costa_Rica.

  • languagecode0..1PopulatedPoblado

    es on resources that come from the clinic's configuration in Konko.

    es en los recursos que provienen de la configuración de la clínica en Konko.

  • Other FHIR fieldsOtros campos FHIR

    period, code, availableTime, notAvailable and availabilityExceptions are part of the standard resource. Konko doesn't fill them today, so treat them as optional.

    period, code, availableTime, notAvailable y availabilityExceptions forman parte del recurso estándar. Konko no los llena hoy, así que trátalos como opcionales.

The PractitionerRole object
El objeto PractitionerRole
{
  "resourceType": "PractitionerRole",
  "id": "f7c3a9e5-1b8d-4e6f-a2c4-9d7b0e3f5a18",
  "meta": {
    "versionId": "2c7e0a4d-9f3b-4d6a-b1e8-5f2c9a7d0e43",
    "lastUpdated": "2026-09-14T17:02:17.056Z"
  },
  "language": "es",
  "extension": [
    {
      "url": "http://hl7.org/fhir/StructureDefinition/timezone",
      "valueCode": "America/Costa_Rica"
    }
  ],
  "identifier": [
    {
      "system": "https://konko.ai/practitioner-role",
      "value": "DOC001:LOC001"
    }
  ],
  "active": true,
  "practitioner": {
    "reference": "Practitioner/d1b5e8c3-4f7a-4d2e-9b6c-8a0f3e5d1c72"
  },
  "organization": {
    "reference": "Organization/b2d7e4a1-5c3f-4e9b-8a1d-6f2c0e7b9d35"
  },
  "specialty": [
    {
      "text": "Ginecología"
    }
  ],
  "location": [
    {
      "reference": "Location/e4a9c1d7-2b6f-4a3e-9c8d-5f1b7e0a2c64"
    }
  ],
  "healthcareService": [
    {
      "reference": "HealthcareService/a3f6b8d2-9e1c-4b7a-8d5f-2c0e6a9b1d47"
    }
  ]
}

Retrieve a practitioner role

Obtener un rol de profesional

GET/fhir/R4/PractitionerRole/{id}

Returns a practitioner role by its id. The response carries ETag: W/"<versionId>" and Last-Modified headers.

Devuelve un rol de profesional por su id. La respuesta incluye los encabezados ETag: W/"<versionId>" y Last-Modified.

Returns 404 Not Found if no PractitionerRole with that id exists in your project, and 410 Gone if it was deleted.

Devuelve 404 Not Found si no existe ningún PractitionerRole con ese id en tu proyecto, y 410 Gone si fue eliminado.

Path parameters
Parámetros de ruta
  • ididRequiredObligatorio

    The PractitionerRole id.

    El id del PractitionerRole.

GET/fhir/R4/PractitionerRole/{id}
curl "https://api.medplum.konko.ai/fhir/R4/PractitionerRole/{practitionerrole_id}" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
200 OK  Response
200 OK  Respuesta
{
  "resourceType": "PractitionerRole",
  "id": "f7c3a9e5-1b8d-4e6f-a2c4-9d7b0e3f5a18",
  "meta": {
    "versionId": "2c7e0a4d-9f3b-4d6a-b1e8-5f2c9a7d0e43",
    "lastUpdated": "2026-09-14T17:02:17.056Z"
  },
  "language": "es",
  "extension": [
    {
      "url": "http://hl7.org/fhir/StructureDefinition/timezone",
      "valueCode": "America/Costa_Rica"
    }
  ],
  "identifier": [
    {
      "system": "https://konko.ai/practitioner-role",
      "value": "DOC001:LOC001"
    }
  ],
  "active": true,
  "practitioner": {
    "reference": "Practitioner/d1b5e8c3-4f7a-4d2e-9b6c-8a0f3e5d1c72"
  },
  "organization": {
    "reference": "Organization/b2d7e4a1-5c3f-4e9b-8a1d-6f2c0e7b9d35"
  },
  "specialty": [
    {
      "text": "Ginecología"
    }
  ],
  "location": [
    {
      "reference": "Location/e4a9c1d7-2b6f-4a3e-9c8d-5f1b7e0a2c64"
    }
  ],
  "healthcareService": [
    {
      "reference": "HealthcareService/a3f6b8d2-9e1c-4b7a-8d5f-2c0e6a9b1d47"
    }
  ]
}
ProvidersProfesionales

Location

A site where patients are seen: a clinic, an office, or a virtual location for remote consultations.

Una sede donde se atiende a los pacientes: una clínica, un consultorio o una sede virtual para consultas remotas.

  • Opening hours are in hoursOfOperation, with a human-readable version in the operating-hours-narrative extension. All times are local to the location's time zone.
  • El horario de atención está en hoursOfOperation, con una versión legible para personas en la extensión operating-hours-narrative. Todas las horas son locales a la zona horaria de la sede.
AttributesPopulated = filled by Konko
AtributosPoblado = lo llena Konko
  • idid1..1

    Konko's ID for this resource, a UUID. It never changes.

    El ID de Konko para este recurso, un UUID. Nunca cambia.

  • metaMeta1..1

    Version information, maintained by the server.

    Información de versión, mantenida por el servidor.

    2 child attributes2 atributos secundarios
    • versionIdid1..1

      Changes on every update. Use it to detect changes and to ignore duplicate webhook deliveries.

      Cambia en cada actualización. Úsalo para detectar cambios y para ignorar entregas de webhook duplicadas.

    • lastUpdatedinstant1..1

      When this version was saved, in UTC. Search on it with _lastUpdated.

      Cuándo se guardó esta versión, en UTC. Búscala con _lastUpdated.

  • identifierIdentifier0..*PopulatedPoblado

    IDs from the systems this record came from. Match on system and value:

    IDs de los sistemas de donde proviene este registro. Compara por system y value:

    https://konko.ai/location: the location's code in the clinic configuration, such as LOC001.

    https://konko.ai/location: el código de la sede en la configuración de la clínica, como LOC001.

    https://konko.ai/huli/clinic: clinic ID in the Huli EHR.

    https://konko.ai/huli/clinic: ID de la clínica en el EHR de Huli.

    https://konko.ai/fhir/knowledge-base-id: the LOC### code on locations Konko's assistant books for.

    https://konko.ai/fhir/knowledge-base-id: el código LOC### en las sedes para las que agenda el asistente de Konko.

  • statuscode0..1PopulatedPoblado

    active, suspended or inactive. Set on locations synced from an EHR.

    active, suspended o inactive. Se establece en las sedes sincronizadas desde un EHR.

  • namestring0..1PopulatedPoblado

    The name patients know the site by.

    El nombre con el que los pacientes conocen la sede.

  • descriptionstring0..1PopulatedPoblado

    Directions and other details for patients.

    Indicaciones para llegar y otros detalles para los pacientes.

  • typeCodeableConcept0..*PopulatedPoblado

    On locations synced from an EHR: PHYSICAL or VIRTUAL in the system https://konko.ai/huli/clinic-type.

    En las sedes sincronizadas desde un EHR: PHYSICAL o VIRTUAL en el sistema https://konko.ai/huli/clinic-type.

  • telecomContactPoint0..*PopulatedPoblado

    Phone and email for this site.

    Teléfono y correo de esta sede.

    3 child attributes3 atributos secundarios
    • systemcode0..1

      phone, email or url.

      phone, email o url.

    • valuestring0..1

      The number, address or URL, as stored by the source.

      El número, la dirección o la URL, tal como los guarda la fuente.

    • usecode0..1

      mobile on numbers collected by Konko's assistant.

      mobile en los números recopilados por el asistente de Konko.

  • addressAddress0..1PopulatedPoblado

    One address. Always has text; locations from an EHR also have city, state and country.

    Una dirección. Siempre tiene text; las sedes que vienen de un EHR también tienen city, state y country.

  • positionBackboneElement0..1PopulatedPoblado

    latitude and longitude, when the EHR provides them.

    latitude y longitude, cuando el EHR los proporciona.

  • managingOrganizationReference(Organization)0..1PopulatedPoblado

    The organization that runs the site, either as {"reference": "Organization/{id}"} or as an identifier only. Organizations aren't part of this API.

    La organización que opera la sede, ya sea como {"reference": "Organization/{id}"} o solo como identificador. Las organizaciones no forman parte de esta API.

  • hoursOfOperationBackboneElement0..*PopulatedPoblado

    Regular opening hours.

    Horario de atención habitual.

    3 child attributes3 atributos secundarios
    • daysOfWeekcode0..*

      mon to sun.

      De mon a sun.

    • openingTimetime0..1

      Local time, HH:MM:SS.

      Hora local, HH:MM:SS.

    • closingTimetime0..1

      Local time, HH:MM:SS.

      Hora local, HH:MM:SS.

  • extensionExtension0..*PopulatedPoblado

    Konko extensions.

    Extensiones de Konko.

    3 child attributes3 atributos secundarios
    • timezonevalueCode0..1

      url: http://hl7.org/fhir/StructureDefinition/timezone

      IANA time zone, for example America/Costa_Rica.

      Zona horaria IANA, por ejemplo America/Costa_Rica.

    • operating-hours-narrativevalueString0..1

      url: https://konko.ai/location/operating-hours-narrative

      Opening hours as a sentence for patients.

      El horario de atención como una oración para los pacientes.

    • location-urlvalueString0..1

      url: https://konko.ai/location/location-url

      A map link.

      Un enlace a un mapa.

  • languagecode0..1PopulatedPoblado

    es on resources that come from the clinic's configuration in Konko.

    es en los recursos que provienen de la configuración de la clínica en Konko.

  • Other FHIR fieldsOtros campos FHIR

    mode, alias, operationalStatus, physicalType, partOf and availabilityExceptions are part of the standard resource. Konko doesn't fill them today, so treat them as optional.

    mode, alias, operationalStatus, physicalType, partOf y availabilityExceptions forman parte del recurso estándar. Konko no los llena hoy, así que trátalos como opcionales.

The Location object
El objeto Location
{
  "resourceType": "Location",
  "id": "e4a9c1d7-2b6f-4a3e-9c8d-5f1b7e0a2c64",
  "meta": {
    "versionId": "8d1f4b6e-2a7c-4e3d-9b5f-6c0e8a2d4f71",
    "lastUpdated": "2026-09-14T17:02:12.918Z"
  },
  "language": "es",
  "extension": [
    {
      "url": "http://hl7.org/fhir/StructureDefinition/timezone",
      "valueCode": "America/Costa_Rica"
    },
    {
      "url": "https://konko.ai/location/operating-hours-narrative",
      "valueString": "Lunes a viernes de 8:00 a 17:00; sábados de 8:00 a 12:00"
    },
    {
      "url": "https://konko.ai/location/location-url",
      "valueString": "https://maps.example.com/?q=clinica-horizonte-escazu"
    }
  ],
  "identifier": [
    {
      "system": "https://konko.ai/location",
      "value": "LOC001"
    }
  ],
  "name": "Sede Escazú",
  "description": "Torre B, piso 3. Parqueo gratuito en el sótano.",
  "telecom": [
    {
      "system": "phone",
      "value": "+506 2288 0000"
    }
  ],
  "address": {
    "text": "Plaza Médica Horizonte, Escazú, San José"
  },
  "managingOrganization": {
    "identifier": {
      "system": "https://konko.ai/clinic-details",
      "value": "clinica_horizonte"
    }
  },
  "hoursOfOperation": [
    {
      "daysOfWeek": [
        "mon",
        "tue",
        "wed",
        "thu",
        "fri"
      ],
      "openingTime": "08:00:00",
      "closingTime": "17:00:00"
    },
    {
      "daysOfWeek": [
        "sat"
      ],
      "openingTime": "08:00:00",
      "closingTime": "12:00:00"
    }
  ]
}

Retrieve a location

Obtener una sede

GET/fhir/R4/Location/{id}

Returns a location by its id. The response carries ETag: W/"<versionId>" and Last-Modified headers.

Devuelve una sede por su id. La respuesta incluye los encabezados ETag: W/"<versionId>" y Last-Modified.

Returns 404 Not Found if no Location with that id exists in your project, and 410 Gone if it was deleted.

Devuelve 404 Not Found si no existe ninguna Location con ese id en tu proyecto, y 410 Gone si fue eliminada.

Path parameters
Parámetros de ruta
  • ididRequiredObligatorio

    The Location id.

    El id de la Location.

GET/fhir/R4/Location/{id}
curl "https://api.medplum.konko.ai/fhir/R4/Location/{location_id}" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
200 OK  Response
200 OK  Respuesta
{
  "resourceType": "Location",
  "id": "e4a9c1d7-2b6f-4a3e-9c8d-5f1b7e0a2c64",
  "meta": {
    "versionId": "8d1f4b6e-2a7c-4e3d-9b5f-6c0e8a2d4f71",
    "lastUpdated": "2026-09-14T17:02:12.918Z"
  },
  "language": "es",
  "extension": [
    {
      "url": "http://hl7.org/fhir/StructureDefinition/timezone",
      "valueCode": "America/Costa_Rica"
    },
    {
      "url": "https://konko.ai/location/operating-hours-narrative",
      "valueString": "Lunes a viernes de 8:00 a 17:00; sábados de 8:00 a 12:00"
    },
    {
      "url": "https://konko.ai/location/location-url",
      "valueString": "https://maps.example.com/?q=clinica-horizonte-escazu"
    }
  ],
  "identifier": [
    {
      "system": "https://konko.ai/location",
      "value": "LOC001"
    }
  ],
  "name": "Sede Escazú",
  "description": "Torre B, piso 3. Parqueo gratuito en el sótano.",
  "telecom": [
    {
      "system": "phone",
      "value": "+506 2288 0000"
    }
  ],
  "address": {
    "text": "Plaza Médica Horizonte, Escazú, San José"
  },
  "managingOrganization": {
    "identifier": {
      "system": "https://konko.ai/clinic-details",
      "value": "clinica_horizonte"
    }
  },
  "hoursOfOperation": [
    {
      "daysOfWeek": [
        "mon",
        "tue",
        "wed",
        "thu",
        "fri"
      ],
      "openingTime": "08:00:00",
      "closingTime": "17:00:00"
    },
    {
      "daysOfWeek": [
        "sat"
      ],
      "openingTime": "08:00:00",
      "closingTime": "12:00:00"
    }
  ]
}
ProvidersProfesionales

HealthcareService

A service patients can book, such as a first consultation or a procedure, with its price range, preparation instructions and where it's offered.

Un servicio que los pacientes pueden agendar, como una primera consulta o un procedimiento, con su rango de precios, instrucciones de preparación y dónde se ofrece.

  • Services come from your clinic's configuration in Konko. The appointment type in type (for example office-visit) is the code that links a service to its booked slots.
  • Los servicios provienen de la configuración de tu clínica en Konko. El tipo de cita en type (por ejemplo office-visit) es el código que vincula un servicio con sus slots agendados.
  • Prices are display text for patients (₡35 000), not amounts to calculate with. The currency is in its own extension.
  • Los precios son texto para mostrar a los pacientes (₡35 000), no montos para hacer cálculos. La moneda está en su propia extensión.
AttributesPopulated = filled by Konko
AtributosPoblado = lo llena Konko
  • idid1..1

    Konko's ID for this resource, a UUID. It never changes.

    El ID de Konko para este recurso, un UUID. Nunca cambia.

  • metaMeta1..1

    Version information, maintained by the server.

    Información de versión, mantenida por el servidor.

    2 child attributes2 atributos secundarios
    • versionIdid1..1

      Changes on every update. Use it to detect changes and to ignore duplicate webhook deliveries.

      Cambia en cada actualización. Úsalo para detectar cambios y para ignorar entregas de webhook duplicadas.

    • lastUpdatedinstant1..1

      When this version was saved, in UTC. Search on it with _lastUpdated.

      Cuándo se guardó esta versión, en UTC. Búscala con _lastUpdated.

  • identifierIdentifier0..*PopulatedPoblado

    IDs from the systems this record came from. Match on system and value:

    IDs de los sistemas de donde proviene este registro. Compara por system y value:

    https://konko.ai/healthcare-service: the service's code in the clinic configuration, such as SVC003.

    https://konko.ai/healthcare-service: el código del servicio en la configuración de la clínica, como SVC003.

  • activeboolean0..1PopulatedPoblado

    Whether patients can book the service.

    Si los pacientes pueden agendar el servicio.

  • namestring0..1PopulatedPoblado

    The name shown to patients.

    El nombre que se muestra a los pacientes.

  • providedByReference(Organization)0..1PopulatedPoblado

    The organization offering the service. Organizations aren't part of this API.

    La organización que ofrece el servicio. Las organizaciones no forman parte de esta API.

  • categoryCodeableConcept0..*PopulatedPoblado

    A grouping as text only, for example Consultas.

    Una agrupación solo como texto, por ejemplo Consultas.

  • typeCodeableConcept0..*PopulatedPoblado

    The appointment type, as a code without a system, such as office-visit. The same code appears on booked slots, in Slot.serviceType.

    El tipo de cita, como un código sin system, por ejemplo office-visit. El mismo código aparece en los slots agendados, en Slot.serviceType.

  • specialtyCodeableConcept0..*PopulatedPoblado

    Sub-category, coded in https://konko.ai/service-sub-category/CodeSystem/{clinic}.

    Subcategoría, codificada en https://konko.ai/service-sub-category/CodeSystem/{clinic}.

  • locationReference(Location)0..*PopulatedPoblado

    Where the service is offered.

    Dónde se ofrece el servicio.

  • commentstring0..1PopulatedPoblado

    A short description.

    Una descripción breve.

  • extraDetailsmarkdown0..1PopulatedPoblado

    Longer details for patients.

    Detalles más extensos para los pacientes.

  • appointmentRequiredboolean0..1PopulatedPoblado

    Whether the service needs an appointment.

    Si el servicio requiere cita.

  • extensionExtension0..*PopulatedPoblado

    Konko extensions. The URLs all start with https://konko.ai/healthcare-service/.

    Extensiones de Konko. Todas las URL empiezan con https://konko.ai/healthcare-service/.

    9 child attributes9 atributos secundarios
    • price-minimum-narrative, price-maximum-narrativevalueString0..1

      Lowest and highest price, as display text.

      Precio mínimo y máximo, como texto para mostrar.

    • currencyvalueString0..1

      ISO 4217 currency code, such as CRC.

      Código de moneda ISO 4217, como CRC.

    • service-prerequisitesvalueString0..1

      What the patient must do beforehand.

      Lo que el paciente debe hacer antes.

    • consent-instructions, additional-instructionsvalueString0..1

      Consent and other instructions for patients.

      Consentimiento y otras instrucciones para los pacientes.

    • results-lead-timevalueString0..1

      How long results usually take, as text.

      Cuánto suelen tardar los resultados, como texto.

    • appointment-type-codevalueString0..1

      The appointment type code, the same as in type.

      El código del tipo de cita, el mismo que en type.

    • auto-scheduling-allowedvalueBoolean0..1

      Whether Konko's assistant can book the service without staff.

      Si el asistente de Konko puede agendar el servicio sin intervención del personal.

    • all-locationsvalueBoolean0..1

      Whether the service is offered at every location.

      Si el servicio se ofrece en todas las sedes.

    • SchedulingParametersExtension0..1

      url: https://medplum.com/fhir/StructureDefinition/SchedulingParameters

      The service's appointment length in duration.

      La duración de la cita del servicio en duration.

  • languagecode0..1PopulatedPoblado

    es on resources that come from the clinic's configuration in Konko.

    es en los recursos que provienen de la configuración de la clínica en Konko.

The HealthcareService object
El objeto HealthcareService
{
  "resourceType": "HealthcareService",
  "id": "a3f6b8d2-9e1c-4b7a-8d5f-2c0e6a9b1d47",
  "meta": {
    "versionId": "3a6c9e1f-7b2d-4f8a-a5c3-1e9d7b0f2a64",
    "lastUpdated": "2026-09-14T17:02:15.402Z"
  },
  "language": "es",
  "extension": [
    {
      "url": "https://konko.ai/healthcare-service/price-minimum-narrative",
      "valueString": "₡35 000"
    },
    {
      "url": "https://konko.ai/healthcare-service/price-maximum-narrative",
      "valueString": "₡45 000"
    },
    {
      "url": "https://konko.ai/healthcare-service/currency",
      "valueString": "CRC"
    },
    {
      "url": "https://konko.ai/healthcare-service/service-prerequisites",
      "valueString": "No requiere ayuno."
    },
    {
      "url": "https://konko.ai/healthcare-service/additional-instructions",
      "valueString": "Traer exámenes previos."
    },
    {
      "url": "https://konko.ai/healthcare-service/appointment-type-code",
      "valueString": "office-visit"
    },
    {
      "url": "https://konko.ai/healthcare-service/auto-scheduling-allowed",
      "valueBoolean": true
    },
    {
      "url": "https://konko.ai/healthcare-service/all-locations",
      "valueBoolean": false
    },
    {
      "url": "https://medplum.com/fhir/StructureDefinition/SchedulingParameters",
      "extension": [
        {
          "url": "duration",
          "valueDuration": {
            "value": 30,
            "unit": "min"
          }
        },
        {
          "url": "alignmentInterval",
          "valueDuration": {
            "value": 30,
            "unit": "min"
          }
        }
      ]
    }
  ],
  "identifier": [
    {
      "system": "https://konko.ai/healthcare-service",
      "value": "SVC003"
    }
  ],
  "active": true,
  "providedBy": {
    "reference": "Organization/b2d7e4a1-5c3f-4e9b-8a1d-6f2c0e7b9d35"
  },
  "category": [
    {
      "text": "Consultas"
    }
  ],
  "type": [
    {
      "coding": [
        {
          "code": "office-visit",
          "display": "Consulta"
        }
      ]
    }
  ],
  "specialty": [
    {
      "coding": [
        {
          "system": "https://konko.ai/service-sub-category/CodeSystem/clinica_horizonte",
          "code": "ginecologia-y-obstetricia",
          "display": "Ginecología y Obstetricia"
        }
      ]
    }
  ],
  "location": [
    {
      "reference": "Location/e4a9c1d7-2b6f-4a3e-9c8d-5f1b7e0a2c64"
    }
  ],
  "name": "Consulta de Ginecología",
  "comment": "Valoración ginecológica general.",
  "extraDetails": "Incluye revisión de exámenes previos.",
  "appointmentRequired": true
}

Retrieve a service

Obtener un servicio

GET/fhir/R4/HealthcareService/{id}

Returns a service by its id. The response carries ETag: W/"<versionId>" and Last-Modified headers.

Devuelve un servicio por su id. La respuesta incluye los encabezados ETag: W/"<versionId>" y Last-Modified.

Returns 404 Not Found if no HealthcareService with that id exists in your project, and 410 Gone if it was deleted.

Devuelve 404 Not Found si no existe ningún HealthcareService con ese id en tu proyecto, y 410 Gone si fue eliminado.

Path parameters
Parámetros de ruta
  • ididRequiredObligatorio

    The HealthcareService id.

    El id del HealthcareService.

GET/fhir/R4/HealthcareService/{id}
curl "https://api.medplum.konko.ai/fhir/R4/HealthcareService/{healthcareservice_id}" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
200 OK  Response
200 OK  Respuesta
{
  "resourceType": "HealthcareService",
  "id": "a3f6b8d2-9e1c-4b7a-8d5f-2c0e6a9b1d47",
  "meta": {
    "versionId": "3a6c9e1f-7b2d-4f8a-a5c3-1e9d7b0f2a64",
    "lastUpdated": "2026-09-14T17:02:15.402Z"
  },
  "language": "es",
  "extension": [
    {
      "url": "https://konko.ai/healthcare-service/price-minimum-narrative",
      "valueString": "₡35 000"
    },
    {
      "url": "https://konko.ai/healthcare-service/price-maximum-narrative",
      "valueString": "₡45 000"
    },
    {
      "url": "https://konko.ai/healthcare-service/currency",
      "valueString": "CRC"
    },
    {
      "url": "https://konko.ai/healthcare-service/service-prerequisites",
      "valueString": "No requiere ayuno."
    },
    {
      "url": "https://konko.ai/healthcare-service/additional-instructions",
      "valueString": "Traer exámenes previos."
    },
    {
      "url": "https://konko.ai/healthcare-service/appointment-type-code",
      "valueString": "office-visit"
    },
    {
      "url": "https://konko.ai/healthcare-service/auto-scheduling-allowed",
      "valueBoolean": true
    },
    {
      "url": "https://konko.ai/healthcare-service/all-locations",
      "valueBoolean": false
    },
    {
      "url": "https://medplum.com/fhir/StructureDefinition/SchedulingParameters",
      "extension": [
        {
          "url": "duration",
          "valueDuration": {
            "value": 30,
            "unit": "min"
          }
        },
        {
          "url": "alignmentInterval",
          "valueDuration": {
            "value": 30,
            "unit": "min"
          }
        }
      ]
    }
  ],
  "identifier": [
    {
      "system": "https://konko.ai/healthcare-service",
      "value": "SVC003"
    }
  ],
  "active": true,
  "providedBy": {
    "reference": "Organization/b2d7e4a1-5c3f-4e9b-8a1d-6f2c0e7b9d35"
  },
  "category": [
    {
      "text": "Consultas"
    }
  ],
  "type": [
    {
      "coding": [
        {
          "code": "office-visit",
          "display": "Consulta"
        }
      ]
    }
  ],
  "specialty": [
    {
      "coding": [
        {
          "system": "https://konko.ai/service-sub-category/CodeSystem/clinica_horizonte",
          "code": "ginecologia-y-obstetricia",
          "display": "Ginecología y Obstetricia"
        }
      ]
    }
  ],
  "location": [
    {
      "reference": "Location/e4a9c1d7-2b6f-4a3e-9c8d-5f1b7e0a2c64"
    }
  ],
  "name": "Consulta de Ginecología",
  "comment": "Valoración ginecológica general.",
  "extraDetails": "Incluye revisión de exámenes previos.",
  "appointmentRequired": true
}
SchedulingAgenda

Slot

A block of busy time on a practitioner's calendar: a booked appointment, time the clinic has blocked, or a holiday.

Un bloque de tiempo ocupado en el calendario de un profesional: una cita agendada, tiempo que la clínica ha bloqueado o un feriado.

  • Konko stores only busy time; there are no free slots.
  • Konko solo guarda tiempo ocupado; no hay slots free.
  • Slot IDs are not stable. When an appointment is cancelled its slot is deleted, and when it's rescheduled the slot is deleted and a new one created. Use the Appointment as your record of a booking.
  • Los IDs de los slots no son estables. Cuando se cancela una cita, su slot se elimina, y cuando se reprograma, el slot se elimina y se crea uno nuevo. Usa el Appointment como tu registro de una reserva.
AttributesPopulated = filled by Konko
AtributosPoblado = lo llena Konko
  • idid1..1

    Konko's ID for this resource, a UUID. It never changes.

    El ID de Konko para este recurso, un UUID. Nunca cambia.

  • metaMeta1..1

    Version information, maintained by the server.

    Información de versión, mantenida por el servidor.

    2 child attributes2 atributos secundarios
    • versionIdid1..1

      Changes on every update. Use it to detect changes and to ignore duplicate webhook deliveries.

      Cambia en cada actualización. Úsalo para detectar cambios y para ignorar entregas de webhook duplicadas.

    • lastUpdatedinstant1..1

      When this version was saved, in UTC. Search on it with _lastUpdated.

      Cuándo se guardó esta versión, en UTC. Busca por este campo con _lastUpdated.

  • identifierIdentifier0..*PopulatedPoblado

    IDs from the systems this record came from. Match on system and value:

    IDs de los sistemas de los que proviene este registro. Compara por system y value:

    https://konko.ai/huli/slot: event ID in the Huli EHR.

    https://konko.ai/huli/slot: ID del evento en el EHR de Huli.

    https://konko.ai/fhir/identifier/google-calendar-event: Google Calendar event ID.

    https://konko.ai/fhir/identifier/google-calendar-event: ID del evento de Google Calendar.

    https://konko.ai/holidays: YYYY-MM-DD:{scheduleId} on holidays from the clinic configuration.

    https://konko.ai/holidays: YYYY-MM-DD:{scheduleId} en los feriados de la configuración de la clínica.

  • scheduleReference(Schedule)1..1RequiredObligatorioPopulatedPoblado

    The practitioner's calendar this time belongs to. Schedules aren't part of this API; use the reference to group one calendar's slots.

    El calendario del profesional al que pertenece este tiempo. Los recursos Schedule no forman parte de esta API; usa la referencia para agrupar los slots de un calendario.

  • statuscode1..1RequiredObligatorioPopulatedPoblado

    busy for an appointment. busy-unavailable for time blocked by the clinic, holidays and calendar events without patients.

    busy para una cita. busy-unavailable para tiempo bloqueado por la clínica, feriados y eventos de calendario sin pacientes.

  • startinstant1..1RequiredObligatorioPopulatedPoblado

    Start time, with the clinic's UTC offset.

    Hora de inicio, con el desfase UTC de la clínica.

  • endinstant1..1RequiredObligatorioPopulatedPoblado

    End time, with the clinic's UTC offset.

    Hora de fin, con el desfase UTC de la clínica.

  • serviceTypeCodeableConcept0..*PopulatedPoblado

    Appointment type, on slots booked by Konko's assistant.

    Tipo de cita, en slots agendados por el asistente de Konko.

  • commentstring0..1PopulatedPoblado

    Title of the calendar event, for time blocked in Google Calendar.

    Título del evento de calendario, para tiempo bloqueado en Google Calendar.

  • extensionExtension0..*PopulatedPoblado

    Konko extensions.

    Extensiones de Konko.

    1 child attribute1 atributo secundario
    • holiday namenombre del feriadovalueString0..1

      url: https://konko.ai/holidays/name

      Name of the holiday, such as Navidad.

      Nombre del feriado, por ejemplo Navidad.

  • Other FHIR fieldsOtros campos FHIR

    serviceCategory, specialty, appointmentType and overbooked are part of the standard resource. Konko doesn't fill them today, so treat them as optional.

    serviceCategory, specialty, appointmentType y overbooked forman parte del recurso estándar. Konko no los llena hoy, así que trátalos como opcionales.

The Slot object
El objeto Slot
{
  "resourceType": "Slot",
  "id": "5e8b1d4f-7a2c-4e9d-8b3f-1c6a0e9d7b26",
  "meta": {
    "versionId": "4b9d2f7a-6e1c-4c8b-9a3d-7e0f5b2c9a16",
    "lastUpdated": "2026-10-05T15:21:44.210Z"
  },
  "schedule": {
    "reference": "Schedule/9a4e2c7b-5d1f-4b8a-9e3c-6f0d2a8b4e51"
  },
  "status": "busy",
  "start": "2026-10-13T08:30:00-06:00",
  "end": "2026-10-13T09:00:00-06:00",
  "serviceType": [
    {
      "coding": [
        {
          "code": "office-visit"
        }
      ]
    }
  ]
}

Retrieve a slot

Obtener un slot

GET/fhir/R4/Slot/{id}

Returns a slot by its id. The response carries ETag: W/"<versionId>" and Last-Modified headers.

Devuelve un slot por su id. La respuesta incluye los encabezados ETag: W/"<versionId>" y Last-Modified.

Returns 404 Not Found if no Slot with that id exists in your project, and 410 Gone if it was deleted.

Devuelve 404 Not Found si no existe ningún Slot con ese id en tu proyecto, y 410 Gone si fue eliminado.

Path parameters
Parámetros de ruta
  • ididRequiredObligatorio

    The Slot id.

    El id del Slot.

GET/fhir/R4/Slot/{id}
curl "https://api.medplum.konko.ai/fhir/R4/Slot/{slot_id}" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
200 OK  Response
200 OK  Respuesta
{
  "resourceType": "Slot",
  "id": "5e8b1d4f-7a2c-4e9d-8b3f-1c6a0e9d7b26",
  "meta": {
    "versionId": "4b9d2f7a-6e1c-4c8b-9a3d-7e0f5b2c9a16",
    "lastUpdated": "2026-10-05T15:21:44.210Z"
  },
  "schedule": {
    "reference": "Schedule/9a4e2c7b-5d1f-4b8a-9e3c-6f0d2a8b4e51"
  },
  "status": "busy",
  "start": "2026-10-13T08:30:00-06:00",
  "end": "2026-10-13T09:00:00-06:00",
  "serviceType": [
    {
      "coding": [
        {
          "code": "office-visit"
        }
      ]
    }
  ]
}
SchedulingAgenda

Appointment

A booked visit: who it's for, with which practitioner, and when. Appointments come from your EHR, from connected calendars and from bookings made through Konko's assistant.

Una visita agendada: para quién es, con qué profesional y cuándo. Las citas provienen de tu EHR, de los calendarios conectados y de las reservas hechas a través del asistente de Konko.

  • Participants are the patient and the practitioner's PractitionerRole, never the Practitioner itself. Follow the role to reach the practitioner and the location; to filter by practitioner, see the chained search below.
  • Los participantes son el paciente y el PractitionerRole del profesional, nunca el Practitioner en sí. Sigue el rol para llegar al profesional y a la sede; para filtrar por profesional, consulta la búsqueda encadenada más abajo.
  • Cancelled appointments stay in place with status: cancelled, and their slot is deleted. A rescheduled appointment is normally updated in place with a new start and end.
  • Las citas canceladas se mantienen con status: cancelled, y su slot se elimina. Una cita reagendada normalmente se actualiza en el mismo recurso con un nuevo start y end.
  • The service booked is recorded on the slot (serviceType) and in description, not in Appointment.serviceType.
  • El servicio agendado se registra en el slot (serviceType) y en description, no en Appointment.serviceType.
AttributesPopulated = filled by Konko
AtributosPoblado = lo llena Konko
  • idid1..1

    Konko's ID for this resource, a UUID. It never changes.

    El ID de Konko para este recurso, un UUID. Nunca cambia.

  • metaMeta1..1

    Version information, maintained by the server.

    Información de versión, mantenida por el servidor.

    2 child attributes2 atributos secundarios
    • versionIdid1..1

      Changes on every update. Use it to detect changes and to ignore duplicate webhook deliveries.

      Cambia en cada actualización. Úsalo para detectar cambios y para ignorar entregas de webhook duplicadas.

    • lastUpdatedinstant1..1

      When this version was saved, in UTC. Search on it with _lastUpdated.

      Cuándo se guardó esta versión, en UTC. Busca por este campo con _lastUpdated.

  • identifierIdentifier0..*PopulatedPoblado

    IDs from the systems this record came from. Match on system and value:

    IDs de los sistemas de los que proviene este registro. Compara por system y value:

    https://konko.ai/huli/appointment: appointment ID in the Huli EHR.

    https://konko.ai/huli/appointment: ID de la cita en el EHR de Huli.

    https://konko.ai/fhir/identifier/google-calendar-event: Google Calendar event ID.

    https://konko.ai/fhir/identifier/google-calendar-event: ID del evento de Google Calendar.

    Bookings made by Konko's assistant have no identifier until they're pushed to your EHR.

    Las reservas hechas por el asistente de Konko no tienen identificador hasta que se envían a tu EHR.

  • statuscode1..1RequiredObligatorioPopulatedPoblado

    booked, pending (a tentative calendar event), fulfilled, cancelled or noshow.

    booked, pending (un evento de calendario tentativo), fulfilled, cancelled o noshow.

  • startinstant0..1PopulatedPoblado

    Start time, with the clinic's UTC offset.

    Hora de inicio, con el desfase UTC de la clínica.

  • endinstant0..1PopulatedPoblado

    End time, with the clinic's UTC offset.

    Hora de fin, con el desfase UTC de la clínica.

  • participantBackboneElement1..*RequiredObligatorioPopulatedPoblado

    Who takes part. Time blocks from a calendar can have no patient.

    Quiénes participan. Los bloqueos de un calendario pueden no tener paciente.

    2 child attributes2 atributos secundarios
    • actorReference(Patient | PractitionerRole)0..1

      The patient, or the practitioner's role.

      El paciente, o el rol del profesional.

    • statuscode1..1

      accepted, declined, tentative or needs-action.

      accepted, declined, tentative o needs-action.

  • slotReference(Slot)0..*PopulatedPoblado

    The busy slot the appointment occupies. When an appointment is cancelled, its slot is deleted.

    El slot ocupado por la cita. Cuando se cancela una cita, su slot se elimina.

  • descriptionstring0..1PopulatedPoblado

    Subject line, usually the service and the patient's name.

    Asunto, normalmente el servicio y el nombre del paciente.

  • commentstring0..1PopulatedPoblado

    Free-text notes. On bookings made by Konko's assistant, the answers the patient gave while booking, one per line. Treat it as personal data.

    Notas de texto libre. En reservas hechas por el asistente de Konko, las respuestas que dio el paciente al agendar, una por línea. Trátalo como datos personales.

  • Other FHIR fieldsOtros campos FHIR

    serviceType, appointmentType, specialty, reasonCode, cancelationReason, minutesDuration and patientInstruction are part of the standard resource. Konko doesn't fill them today, so treat them as optional.

    serviceType, appointmentType, specialty, reasonCode, cancelationReason, minutesDuration y patientInstruction forman parte del recurso estándar. Konko no los llena hoy, así que trátalos como opcionales.

The Appointment object
El objeto Appointment
{
  "resourceType": "Appointment",
  "id": "6b1f8e3d-2a9c-4b5e-8f7d-3e0a6c1b9d84",
  "meta": {
    "versionId": "a8f1c4e7-2b9d-4e6a-9c3f-5d0b8e2a7c14",
    "lastUpdated": "2026-10-05T15:21:47.382Z"
  },
  "identifier": [
    {
      "system": "https://konko.ai/huli/appointment",
      "value": "100"
    }
  ],
  "status": "booked",
  "description": "Consulta de Ginecología — Ana Lucía Mora Vargas",
  "start": "2026-10-13T08:30:00-06:00",
  "end": "2026-10-13T09:00:00-06:00",
  "slot": [
    {
      "reference": "Slot/5e8b1d4f-7a2c-4e9d-8b3f-1c6a0e9d7b26"
    }
  ],
  "comment": "full_name: Ana Lucía Mora Vargas\nphone_number: +50687654321\nservice: Consulta de Ginecología\nlocation: Sede Escazú",
  "participant": [
    {
      "actor": {
        "reference": "PractitionerRole/f7c3a9e5-1b8d-4e6f-a2c4-9d7b0e3f5a18"
      },
      "status": "tentative"
    },
    {
      "actor": {
        "reference": "Patient/3c9f6a1e-8d4b-4f2a-b5e7-0d9c2f8a6b13"
      },
      "status": "accepted"
    }
  ]
}

Retrieve an appointment

Obtener una cita

GET/fhir/R4/Appointment/{id}

Returns an appointment by its id. The response carries ETag: W/"<versionId>" and Last-Modified headers.

Devuelve una cita por su id. La respuesta incluye los encabezados ETag: W/"<versionId>" y Last-Modified.

Returns 404 Not Found if no Appointment with that id exists in your project, and 410 Gone if it was deleted.

Devuelve 404 Not Found si no existe ningún Appointment con ese id en tu proyecto, y 410 Gone si fue eliminado.

Path parameters
Parámetros de ruta
  • ididRequiredObligatorio

    The Appointment id.

    El id del Appointment.

GET/fhir/R4/Appointment/{id}
curl "https://api.medplum.konko.ai/fhir/R4/Appointment/{appointment_id}" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
200 OK  Response
200 OK  Respuesta
{
  "resourceType": "Appointment",
  "id": "6b1f8e3d-2a9c-4b5e-8f7d-3e0a6c1b9d84",
  "meta": {
    "versionId": "a8f1c4e7-2b9d-4e6a-9c3f-5d0b8e2a7c14",
    "lastUpdated": "2026-10-05T15:21:47.382Z"
  },
  "identifier": [
    {
      "system": "https://konko.ai/huli/appointment",
      "value": "100"
    }
  ],
  "status": "booked",
  "description": "Consulta de Ginecología — Ana Lucía Mora Vargas",
  "start": "2026-10-13T08:30:00-06:00",
  "end": "2026-10-13T09:00:00-06:00",
  "slot": [
    {
      "reference": "Slot/5e8b1d4f-7a2c-4e9d-8b3f-1c6a0e9d7b26"
    }
  ],
  "comment": "full_name: Ana Lucía Mora Vargas\nphone_number: +50687654321\nservice: Consulta de Ginecología\nlocation: Sede Escazú",
  "participant": [
    {
      "actor": {
        "reference": "PractitionerRole/f7c3a9e5-1b8d-4e6f-a2c4-9d7b0e3f5a18"
      },
      "status": "tentative"
    },
    {
      "actor": {
        "reference": "Patient/3c9f6a1e-8d4b-4f2a-b5e7-0d9c2f8a6b13"
      },
      "status": "accepted"
    }
  ]
}
Webhooks

How webhooks work

Cómo funcionan los webhooks

Instead of polling, tell Konko which changes you care about and where to send them. When a matching resource is created, updated or deleted in your project, Konko sends it to your endpoint in an HTTPS POST.

En lugar de hacer polling, dile a Konko qué cambios te interesan y adónde enviarlos. Cuando un recurso que coincide se crea, actualiza o elimina en tu proyecto, Konko lo envía a tu endpoint en un POST HTTPS.

A webhook is a FHIR R4 Subscription resource that you create and manage through the API. It holds three things: the changes you want (criteria), the URL to deliver them to (channel.endpoint), and delivery options such as a signing secret.

Un webhook es un recurso Subscription de FHIR R4 que creas y administras a través de la API. Contiene tres cosas: los cambios que quieres (criteria), la URL a la que entregarlos (channel.endpoint) y opciones de entrega como un secreto de firma.

Change in your projectCambio en tu proyecto create · update · deletecrear · editar · borrar Match subscriptionsCruce con suscripciones status=active, criteria Delivery queueCola de entrega one job per matchuna por suscripción Your endpointTu endpoint HTTPS POST, 120 s timeoutHTTPS POST, 120 s máx. DoneListo no retrysin reintento signedfirmada 2xx/3xx other status, timeout or errorotro estado,tiempo de espera o error retry after 1 s, 2 s, 4 s, 8 s …reintento tras 1 s, 2 s, 4 s, 8 s …
Every attempt is logged. A failed attempt goes back to the queue and is retried with exponential backoff until it succeeds or the retry limit is reached.Cada intento se registra. Un intento fallido vuelve a la cola y se reintenta con retroceso exponencial hasta que tiene éxito o se alcanza el límite de reintentos.

What to expect

Qué esperar

  • Triggers. Creating, updating or deleting a matching resource triggers a delivery. An update that changes nothing creates no new version and sends nothing.
  • Disparadores. Crear, actualizar o eliminar un recurso que coincide dispara una entrega. Una actualización que no cambia nada no crea una nueva versión y no envía nada.
  • New appointments can arrive as updates. Appointments booked through Konko's assistant are delivered with X-Medplum-Interaction: update, not create. Treat an appointment id you haven't seen before as new, whatever the interaction says.
  • Las citas nuevas pueden llegar como actualizaciones. Las citas agendadas a través del asistente de Konko se entregan con X-Medplum-Interaction: update, no create. Trata un id de cita que no hayas visto antes como nuevo, sin importar lo que diga la interacción.
  • Payload. Creates and updates carry the full resource as it is after the change. Deletes carry an empty JSON object and name the deleted resource in a header. See Receiving deliveries.
  • Carga útil. Las creaciones y actualizaciones llevan el recurso completo tal como queda después del cambio. Las eliminaciones llevan un objeto JSON vacío e indican el recurso eliminado en un encabezado. Consulta Recibir entregas.
  • At least once. You can receive the same change more than once. Use the resource's meta.versionId to ignore versions you have already processed.
  • Al menos una vez. Puedes recibir el mismo cambio más de una vez. Usa el meta.versionId del recurso para ignorar versiones que ya procesaste.
  • No ordering guarantee. Deliveries can arrive out of order. Compare meta.lastUpdated before overwriting newer data with older data.
  • Sin garantía de orden. Las entregas pueden llegar desordenadas. Compara meta.lastUpdated antes de sobrescribir datos más recientes con datos más antiguos.
  • Latest state wins on retries. If a resource changes again before a failed delivery is retried, the stale retry is dropped and you receive the newer version instead.
  • En los reintentos gana el estado más reciente. Si un recurso vuelve a cambiar antes de que se reintente una entrega fallida, el reintento obsoleto se descarta y recibes la versión más nueva en su lugar.
  • Fast responses. Reply with 2xx as soon as you have stored the event, then process it in the background. Deliveries time out after 120 seconds.
  • Respuestas rápidas. Responde con 2xx en cuanto hayas guardado el evento y luego procésalo en segundo plano. Las entregas agotan el tiempo de espera a los 120 segundos.
ImportantImportante

Deliveries are not a substitute for a periodic catch-up. If your endpoint is down for longer than the retry window, events are dropped. After an outage, search with _lastUpdated=gt{time of your last delivery} to pick up the changes you missed.

Las entregas no sustituyen una puesta al día periódica. Si tu endpoint está caído más tiempo que la ventana de reintentos, los eventos se descartan. Después de una caída, busca con _lastUpdated=gt{time of your last delivery} para recuperar los cambios que te perdiste.

Webhooks

The Subscription object

El objeto Subscription

A standard FHIR R4 Subscription with the rest-hook channel, plus optional delivery settings carried as extensions.

Un Subscription estándar de FHIR R4 con el canal rest-hook, más ajustes de entrega opcionales incluidos como extensiones.

Attributes
Atributos
  • idid0..1Read-onlySolo lectura

    Assigned by the server when you create the subscription.

    Lo asigna el servidor cuando creas la suscripción.

  • statuscode1..1RequiredObligatorio

    active to receive deliveries. Set it to off to pause a subscription without deleting it.

    active para recibir entregas. Ponlo en off para pausar una suscripción sin eliminarla.

    Konko never changes this value for you. A subscription whose endpoint keeps failing stays active.

    Konko nunca cambia este valor por ti. Una suscripción cuyo endpoint sigue fallando permanece active.

    Example: active
    Ejemplo: active
  • reasonstring1..1RequiredObligatorio

    What the subscription is for, so you and Konko can tell subscriptions apart when debugging deliveries.

    Para qué sirve la suscripción, de modo que tú y Konko puedan distinguir las suscripciones al depurar entregas.

  • criteriastring1..1RequiredObligatorio

    One resource type, optionally followed by search filters. See Choosing what to receive.

    Un tipo de recurso, opcionalmente seguido de filtros de búsqueda. Consulta Elegir qué recibir.

    Example: Appointment?status=booked,cancelled
    Ejemplo: Appointment?status=booked,cancelled
  • channelBackboneElement1..1RequiredObligatorio

    Where and how deliveries are sent.

    Dónde y cómo se envían las entregas.

    4 child attributes4 atributos secundarios
    • typecode1..1RequiredObligatorio

      Always rest-hook.

      Siempre rest-hook.

    • endpointurl0..1RequiredObligatorio

      The HTTPS URL that receives deliveries. A subscription without an endpoint is accepted but never delivers.

      La URL HTTPS que recibe las entregas. Una suscripción sin endpoint se acepta, pero nunca entrega nada.

    • payloadcode0..1

      Set to application/fhir+json. Deliveries always carry the full resource, whatever this field says.

      Establécelo en application/fhir+json. Las entregas siempre llevan el recurso completo, diga lo que diga este campo.

    • headerstring0..*

      Extra HTTP headers to send with every delivery, each written as Name: value, for example an API key your endpoint expects.

      Encabezados HTTP adicionales para enviar con cada entrega, cada uno escrito como Name: value, por ejemplo una clave de API que tu endpoint espera.

      The value can't contain a colon (:). Anything after a second colon is dropped.

      El valor no puede contener dos puntos (:). Todo lo que siga a un segundo signo de dos puntos se descarta.

      Example: Authorization: Bearer 3f9c1a7e5b2d4c8f
      Ejemplo: Authorization: Bearer 3f9c1a7e5b2d4c8f
  • extensionExtension0..*

    Delivery options. Each option is one entry with a url and a value.

    Opciones de entrega. Cada opción es una entrada con una url y un valor.

    5 child attributes5 atributos secundarios
    • subscription-secretvalueString0..1

      url: https://www.medplum.com/fhir/StructureDefinition/subscription-secret

      Signing secret. When set, every delivery carries an X-Signature header. See Verifying signatures. Use at least 32 random characters.

      Secreto de firma. Cuando está configurado, cada entrega lleva un encabezado X-Signature. Consulta Verificar firmas. Usa al menos 32 caracteres aleatorios.

    • subscription-supported-interactionvalueCode0..1

      url: https://medplum.com/fhir/StructureDefinition/subscription-supported-interaction

      Deliver only one kind of change: create, update or delete. Without it you receive all three. To receive two of the three, create two subscriptions.

      Entrega solo un tipo de cambio: create, update o delete. Sin ella recibes los tres. Para recibir dos de los tres, crea dos suscripciones.

    • fhir-path-criteria-expressionvalueString0..1

      url: https://medplum.com/fhir/StructureDefinition/fhir-path-criteria-expression

      A FHIRPath expression that must evaluate to true for the change to be delivered. %previous is the version before the change and %current the version after it. For a newly created resource, %previous is empty.

      Una expresión FHIRPath que debe evaluarse como true para que el cambio se entregue. %previous es la versión anterior al cambio y %current la versión posterior. Para un recurso recién creado, %previous está vacío.

      Example: %previous.status != 'cancelled' and %current.status = 'cancelled'
      Ejemplo: %previous.status != 'cancelled' and %current.status = 'cancelled'
    • subscription-max-attemptsvalueInteger0..1

      url: https://medplum.com/fhir/StructureDefinition/subscription-max-attempts

      How many times to retry a failed delivery, from 1 to 18. The default is 4. See Retries.

      Cuántas veces reintentar una entrega fallida, de 1 a 18. El valor predeterminado es 4. Consulta Reintentos.

    • subscription-success-codesvalueString0..1

      url: https://medplum.com/fhir/StructureDefinition/subscription-success-codes

      HTTP status codes that count as delivered, as a comma-separated list of codes and ranges. The default is 200-399.

      Códigos de estado HTTP que cuentan como entregados, como una lista de códigos y rangos separados por comas. El valor predeterminado es 200-399.

      Example: 200-299,409
      Ejemplo: 200-299,409
  • metaMeta0..1Read-onlySolo lectura

    versionId and lastUpdated, maintained by the server.

    versionId y lastUpdated, mantenidos por el servidor.

The Subscription object
El objeto Subscription
{
  "resourceType": "Subscription",
  "id": "2e7a4c9f-6b3d-4a1e-9c5b-8d0f7e2a4c39",
  "meta": {
    "versionId": "a1c4e7b2-9d3f-4e6a-8b5c-2f0d7e9a1b36",
    "lastUpdated": "2026-10-01T15:04:11.482Z"
  },
  "status": "active",
  "reason": "Sync appointment changes into our CRM",
  "criteria": "Appointment",
  "channel": {
    "type": "rest-hook",
    "endpoint": "https://integraciones.clinicahorizonte.example/konko/webhooks",
    "payload": "application/fhir+json",
    "header": [
      "Authorization: Bearer 3f9c1a7e5b2d4c8f"
    ]
  },
  "extension": [
    {
      "url": "https://www.medplum.com/fhir/StructureDefinition/subscription-secret",
      "valueString": "whsec_7b1d4e9a2c6f8b3e5a0d9c7f1e4b6a28"
    },
    {
      "url": "https://medplum.com/fhir/StructureDefinition/subscription-max-attempts",
      "valueInteger": 12
    }
  ]
}
Webhooks

Choosing what to receive

Elegir qué recibir

criteria names one resource type and, optionally, search filters that the changed resource must match. Two extensions narrow it further.

criteria indica un tipo de recurso y, opcionalmente, filtros de búsqueda que el recurso modificado debe cumplir. Dos extensiones lo acotan aún más.

You wantQuierescriteriaAlso setConfigura también
Every appointment changeCada cambio de citaAppointment—
Booked and cancelled appointmentsCitas agendadas y canceladasAppointment?status=booked,cancelled—
Appointments of one practitioner at one locationCitas de un profesional en una sedeAppointment?actor=PractitionerRole/{id}—
The moment an appointment is cancelledEl momento en que se cancela una citaAppointmentFHIRPath %previous.status != 'cancelled' and %current.status = 'cancelled'
Time blocked by the clinicTiempo bloqueado por la clínicaSlot?status=busy-unavailable—
Changes to patient recordsCambios en los registros de pacientesPatientinteraction updateinteracción update
Directory changes (one subscription each)Cambios en el directorio (una suscripción por cada uno)Practitioner, PractitionerRole, HealthcareService, Location—

Filter rules

Reglas de filtrado

  • Use one resource type per subscription, from the types your client can read (see Access and permissions).
  • Usa un tipo de recurso por suscripción, de entre los tipos que tu cliente puede leer (consulta Acceso y permisos).
  • Filters are checked against the changed resource itself, using the same search parameters as the search endpoints. Token, string, reference, URI and date parameters work. Number and quantity parameters, chained parameters (such as patient.name), _include and _has don't.
  • Los filtros se evalúan contra el propio recurso modificado, con los mismos parámetros de búsqueda que los endpoints de búsqueda. Funcionan los parámetros token, string, reference, URI y date. No funcionan los parámetros number y quantity, los parámetros encadenados (como patient.name), _include ni _has.
  • Separate alternatives with commas (status=booked,cancelled). Repeat a parameter to require both conditions (date=ge2026-10-01&date=lt2026-11-01).
  • Separa las alternativas con comas (status=booked,cancelled). Repite un parámetro para exigir ambas condiciones (date=ge2026-10-01&date=lt2026-11-01).
  • Date filters accept the usual prefixes (ge, gt, le, lt, eq, ne). :missing and :not work as in searches.
  • Los filtros de fecha aceptan los prefijos habituales (ge, gt, le, lt, eq, ne). :missing y :not funcionan igual que en las búsquedas.
  • String filters match case-insensitively anywhere in the value, so name=ana also matches “Juliana”.
  • Los filtros de tipo string coinciden sin distinguir mayúsculas de minúsculas en cualquier parte del valor, así que name=ana también coincide con “Juliana”.
  • Konko doesn't validate criteria when you create the subscription. A typo simply never matches. Run the same query as a search first (GET /fhir/R4/Appointment?status=booked) to check that it returns what you expect.
  • Konko no valida criteria cuando creas la suscripción. Un error de tipeo simplemente nunca coincide. Ejecuta primero la misma consulta como búsqueda (GET /fhir/R4/Appointment?status=booked) para comprobar que devuelve lo que esperas.
NoteNota

A filter such as Appointment?status=cancelled fires on every later edit of a cancelled appointment too. When you only want the moment something changes, use the FHIRPath extension with %previous and %current.

Un filtro como Appointment?status=cancelled también se dispara con cada edición posterior de una cita cancelada. Cuando solo quieres el momento en que algo cambia, usa la extensión FHIRPath con %previous y %current.

Webhooks

Manage subscriptions

Administrar suscripciones

Create, list, change and delete your webhooks. These are the only write operations your API client can perform.

Crea, lista, modifica y elimina tus webhooks. Son las únicas operaciones de escritura que tu cliente de API puede realizar.

Create a subscription

Crear una suscripción

POST/fhir/R4/Subscription

Creates a webhook. Deliveries start with the next matching change; existing resources are not sent retroactively.

Crea un webhook. Las entregas comienzan con el siguiente cambio que coincida; los recursos existentes no se envían retroactivamente.

Send a Subscription object without id. Konko assigns the id and returns the stored subscription with 201 Created and a Location header.

Envía un objeto Subscription sin id. Konko asigna el id y devuelve la suscripción almacenada con 201 Created y un encabezado Location.

SecuritySeguridad

Keep the signing secret out of source control. Anyone who can read the Subscription through the API can see its secret and headers, so treat your API credentials as equally sensitive.

Mantén el secreto de firma fuera del control de versiones. Cualquiera que pueda leer la Subscription a través de la API puede ver su secreto y sus encabezados, así que trata tus credenciales de API como igual de sensibles.

POST/fhir/R4/Subscription
curl -X POST "https://api.medplum.konko.ai/fhir/R4/Subscription" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/fhir+json" \
  -d '{
  "resourceType": "Subscription",
  "status": "active",
  "reason": "Sync appointment changes into our CRM",
  "criteria": "Appointment",
  "channel": {
    "type": "rest-hook",
    "endpoint": "https://integraciones.clinicahorizonte.example/konko/webhooks",
    "payload": "application/fhir+json",
    "header": [
      "Authorization: Bearer 3f9c1a7e5b2d4c8f"
    ]
  },
  "extension": [
    {
      "url": "https://www.medplum.com/fhir/StructureDefinition/subscription-secret",
      "valueString": "whsec_7b1d4e9a2c6f8b3e5a0d9c7f1e4b6a28"
    },
    {
      "url": "https://medplum.com/fhir/StructureDefinition/subscription-max-attempts",
      "valueInteger": 12
    }
  ]
}'
201 Created  Response
201 Created  Respuesta
{
  "resourceType": "Subscription",
  "id": "2e7a4c9f-6b3d-4a1e-9c5b-8d0f7e2a4c39",
  "meta": {
    "versionId": "a1c4e7b2-9d3f-4e6a-8b5c-2f0d7e9a1b36",
    "lastUpdated": "2026-10-01T15:04:11.482Z"
  },
  "status": "active",
  "reason": "Sync appointment changes into our CRM",
  "criteria": "Appointment",
  "channel": {
    "type": "rest-hook",
    "endpoint": "https://integraciones.clinicahorizonte.example/konko/webhooks",
    "payload": "application/fhir+json",
    "header": [
      "Authorization: Bearer 3f9c1a7e5b2d4c8f"
    ]
  },
  "extension": [
    {
      "url": "https://www.medplum.com/fhir/StructureDefinition/subscription-secret",
      "valueString": "whsec_7b1d4e9a2c6f8b3e5a0d9c7f1e4b6a28"
    },
    {
      "url": "https://medplum.com/fhir/StructureDefinition/subscription-max-attempts",
      "valueInteger": 12
    }
  ]
}

List subscriptions

Listar suscripciones

GET/fhir/R4/Subscription

Returns the subscriptions in your project as a searchset Bundle.

Devuelve las suscripciones de tu proyecto como un Bundle searchset.

Query parameters
Parámetros de consulta
  • statustoken

    requested, active, error or off.

    requested, active, error u off.

    Example: active
    Ejemplo: active
  • typetoken

    Channel type. Always rest-hook for webhooks.

    Tipo de canal. Siempre rest-hook para webhooks.

  • urluri

    Exact endpoint URL.

    URL exacta del endpoint.

    Example: https://integraciones.clinicahorizonte.example/konko/webhooks
    Ejemplo: https://integraciones.clinicahorizonte.example/konko/webhooks
  • criteriastring

    Text contained in criteria.

    Texto contenido en criteria.

    Example: Appointment
    Ejemplo: Appointment
  • _countinteger

    Page size, 1–1000. Default 20.

    Tamaño de página, 1–1000. Predeterminado: 20.

GET/fhir/R4/Subscription
curl -G "https://api.medplum.konko.ai/fhir/R4/Subscription" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  --data-urlencode "status=active"
200 OK  Response
200 OK  Respuesta
{
  "resourceType": "Bundle",
  "type": "searchset",
  "entry": [
    {
      "fullUrl": "https://api.medplum.konko.ai/fhir/R4/Subscription/2e7a4c9f-6b3d-4a1e-9c5b-8d0f7e2a4c39",
      "resource": {
        "resourceType": "Subscription",
        "id": "2e7a4c9f-6b3d-4a1e-9c5b-8d0f7e2a4c39",
        "meta": {
          "versionId": "a1c4e7b2-9d3f-4e6a-8b5c-2f0d7e9a1b36",
          "lastUpdated": "2026-10-01T15:04:11.482Z"
        },
        "status": "active",
        "reason": "Sync appointment changes into our CRM",
        "criteria": "Appointment",
        "channel": {
          "type": "rest-hook",
          "endpoint": "https://integraciones.clinicahorizonte.example/konko/webhooks",
          "payload": "application/fhir+json",
          "header": [
            "Authorization: Bearer 3f9c1a7e5b2d4c8f"
          ]
        },
        "extension": [
          {
            "url": "https://www.medplum.com/fhir/StructureDefinition/subscription-secret",
            "valueString": "whsec_7b1d4e9a2c6f8b3e5a0d9c7f1e4b6a28"
          },
          {
            "url": "https://medplum.com/fhir/StructureDefinition/subscription-max-attempts",
            "valueInteger": 12
          }
        ]
      },
      "search": {
        "mode": "match"
      }
    }
  ],
  "link": [
    {
      "relation": "self",
      "url": "https://api.medplum.konko.ai/fhir/R4/Subscription?status=active"
    }
  ]
}

Retrieve a subscription

Obtener una suscripción

GET/fhir/R4/Subscription/{id}

Returns one subscription by id.

Devuelve una suscripción por id.

Path parameters
Parámetros de ruta
  • ididRequiredObligatorio

    The subscription id.

    El id de la suscripción.

GET/fhir/R4/Subscription/{id}
curl "https://api.medplum.konko.ai/fhir/R4/Subscription/{subscription_id}" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
200 OK  Response
200 OK  Respuesta
{
  "resourceType": "Subscription",
  "id": "2e7a4c9f-6b3d-4a1e-9c5b-8d0f7e2a4c39",
  "meta": {
    "versionId": "a1c4e7b2-9d3f-4e6a-8b5c-2f0d7e9a1b36",
    "lastUpdated": "2026-10-01T15:04:11.482Z"
  },
  "status": "active",
  "reason": "Sync appointment changes into our CRM",
  "criteria": "Appointment",
  "channel": {
    "type": "rest-hook",
    "endpoint": "https://integraciones.clinicahorizonte.example/konko/webhooks",
    "payload": "application/fhir+json",
    "header": [
      "Authorization: Bearer 3f9c1a7e5b2d4c8f"
    ]
  },
  "extension": [
    {
      "url": "https://www.medplum.com/fhir/StructureDefinition/subscription-secret",
      "valueString": "whsec_7b1d4e9a2c6f8b3e5a0d9c7f1e4b6a28"
    },
    {
      "url": "https://medplum.com/fhir/StructureDefinition/subscription-max-attempts",
      "valueInteger": 12
    }
  ]
}

Update a subscription

Actualizar una suscripción

PUT/fhir/R4/Subscription/{id}

Replaces a subscription. Send the complete resource, including its id. Anything you leave out is removed.

Reemplaza una suscripción. Envía el recurso completo, incluido su id. Todo lo que omitas se elimina.

Use it to pause deliveries (status: off), change the endpoint or change the signing secret. To change a secret without dropping deliveries, accept both the old and the new signature on your side for a few minutes while the update takes effect.

Úsalo para pausar las entregas (status: off), cambiar el endpoint o cambiar el secreto de firma. Para cambiar un secreto sin perder entregas, acepta de tu lado tanto la firma antigua como la nueva durante unos minutos mientras la actualización surte efecto.

Path parameters
Parámetros de ruta
  • ididRequiredObligatorio

    The subscription id. Must match the id in the body.

    El id de la suscripción. Debe coincidir con el id del cuerpo.

PUT/fhir/R4/Subscription/{id}
curl -X PUT "https://api.medplum.konko.ai/fhir/R4/Subscription/{subscription_id}" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/fhir+json" \
  -d '{
  "resourceType": "Subscription",
  "id": "2e7a4c9f-6b3d-4a1e-9c5b-8d0f7e2a4c39",
  "status": "off",
  "reason": "Sync appointment changes into our CRM",
  "criteria": "Appointment",
  "channel": {
    "type": "rest-hook",
    "endpoint": "https://integraciones.clinicahorizonte.example/konko/webhooks",
    "payload": "application/fhir+json",
    "header": [
      "Authorization: Bearer 3f9c1a7e5b2d4c8f"
    ]
  },
  "extension": [
    {
      "url": "https://www.medplum.com/fhir/StructureDefinition/subscription-secret",
      "valueString": "whsec_7b1d4e9a2c6f8b3e5a0d9c7f1e4b6a28"
    },
    {
      "url": "https://medplum.com/fhir/StructureDefinition/subscription-max-attempts",
      "valueInteger": 12
    }
  ]
}'
200 OK  Response
200 OK  Respuesta
{
  "resourceType": "Subscription",
  "id": "2e7a4c9f-6b3d-4a1e-9c5b-8d0f7e2a4c39",
  "status": "off",
  "reason": "Sync appointment changes into our CRM",
  "criteria": "Appointment",
  "channel": {
    "type": "rest-hook",
    "endpoint": "https://integraciones.clinicahorizonte.example/konko/webhooks",
    "payload": "application/fhir+json",
    "header": [
      "Authorization: Bearer 3f9c1a7e5b2d4c8f"
    ]
  },
  "extension": [
    {
      "url": "https://www.medplum.com/fhir/StructureDefinition/subscription-secret",
      "valueString": "whsec_7b1d4e9a2c6f8b3e5a0d9c7f1e4b6a28"
    },
    {
      "url": "https://medplum.com/fhir/StructureDefinition/subscription-max-attempts",
      "valueInteger": 12
    }
  ],
  "meta": {
    "versionId": "c7e1b9d4-2a6f-4c8e-9b3d-5f0a7e2c4b18",
    "lastUpdated": "2026-10-03T09:12:40.905Z"
  }
}

Delete a subscription

Eliminar una suscripción

DELETE/fhir/R4/Subscription/{id}

Deletes a subscription. Deliveries that are already queued for it are cancelled before their next attempt.

Elimina una suscripción. Las entregas que ya están en cola para ella se cancelan antes de su siguiente intento.

Path parameters
Parámetros de ruta
  • ididRequiredObligatorio

    The subscription id.

    El id de la suscripción.

DELETE/fhir/R4/Subscription/{id}
curl -X DELETE "https://api.medplum.konko.ai/fhir/R4/Subscription/{subscription_id}" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
200 OK  Response
200 OK  Respuesta
{
  "resourceType": "OperationOutcome",
  "id": "ok",
  "issue": [
    {
      "severity": "information",
      "code": "informational",
      "details": {
        "text": "All OK"
      }
    }
  ]
}
Webhooks

Receiving deliveries

Recibir entregas

Each delivery is one HTTPS POST to your endpoint, carrying one changed resource.

Cada entrega es un POST HTTPS a tu endpoint, con un recurso modificado.

Request headers
Encabezados de la solicitud
HeaderEncabezadoMeaningSignificado
Content-TypeAlways application/fhir+json.Siempre application/fhir+json.
X-Medplum-SubscriptionThe id of the subscription that matched.El id de la suscripción que coincidió.
X-Medplum-Interactioncreate, update or delete.create, update o delete.
X-Medplum-Deleted-ResourceDeletes only. The deleted resource as Type/id, for example Appointment/6b1f….Solo en eliminaciones. El recurso eliminado como Type/id, por ejemplo Appointment/6b1f….
X-SignaturePresent when the subscription has a signing secret. Hex-encoded HMAC-SHA256 of the raw body.Presente cuando la suscripción tiene un secreto de firma. HMAC-SHA256 del cuerpo sin formato, codificado en hexadecimal.
x-trace-id, traceparentPresent when the change carried a trace ID. Quote it when you report a problem to Konko.Presente cuando el cambio llevaba un ID de traza. Cítalo cuando reportes un problema a Konko.
Your headersTus encabezadosEvery channel.header entry, as configured.Cada entrada de channel.header, tal como se configuró.

The body is the resource exactly as a read would return it at that version, so you can store it directly or pass it to the same code that handles API responses.

El cuerpo es el recurso exactamente como lo devolvería una lectura en esa versión, así que puedes almacenarlo directamente o pasarlo al mismo código que maneja las respuestas de la API.

For a delete the body is {}. Take the resource type and id from X-Medplum-Deleted-Resource.

En una eliminación el cuerpo es {}. Toma el tipo de recurso y el id de X-Medplum-Deleted-Resource.

Bodies are sent as compact JSON without whitespace. The examples on this page are formatted for reading; their signatures are computed over the compact form.

Los cuerpos se envían como JSON compacto, sin espacios en blanco. Los ejemplos de esta página están formateados para facilitar la lectura; sus firmas se calculan sobre la forma compacta.

Deliveries don't include related resources. If you need the patient of an appointment, read it or use _include on a search.

Las entregas no incluyen recursos relacionados. Si necesitas el paciente de una cita, léelo o usa _include en una búsqueda.

POSTUpdate delivery
POSTEntrega de actualización
POST /konko/webhooks HTTP/1.1
Host: integraciones.clinicahorizonte.example
Content-Type: application/fhir+json
X-Medplum-Subscription: 2e7a4c9f-6b3d-4a1e-9c5b-8d0f7e2a4c39
X-Medplum-Interaction: update
X-Signature: bbc14666f59330c5ceaca8b582042dd28bdc05460504b692313b0002444d079c
Authorization: Bearer 3f9c1a7e5b2d4c8f

{
  "resourceType": "Appointment",
  "id": "6b1f8e3d-2a9c-4b5e-8f7d-3e0a6c1b9d84",
  "meta": {
    "versionId": "0d6b3f9e-4a1c-4e7b-8f2d-9c5a1e7b3d60",
    "lastUpdated": "2026-10-09T16:20:02.841Z"
  },
  "identifier": [
    {
      "system": "https://konko.ai/huli/appointment",
      "value": "100"
    }
  ],
  "status": "cancelled",
  "description": "Consulta de Ginecología — Ana Lucía Mora Vargas",
  "start": "2026-10-13T08:30:00-06:00",
  "end": "2026-10-13T09:00:00-06:00",
  "slot": [
    {
      "reference": "Slot/5e8b1d4f-7a2c-4e9d-8b3f-1c6a0e9d7b26"
    }
  ],
  "comment": "full_name: Ana Lucía Mora Vargas\nphone_number: +50687654321\nservice: Consulta de Ginecología\nlocation: Sede Escazú",
  "participant": [
    {
      "actor": {
        "reference": "PractitionerRole/f7c3a9e5-1b8d-4e6f-a2c4-9d7b0e3f5a18"
      },
      "status": "tentative"
    },
    {
      "actor": {
        "reference": "Patient/3c9f6a1e-8d4b-4f2a-b5e7-0d9c2f8a6b13"
      },
      "status": "accepted"
    }
  ]
}
POSTDelete delivery
POSTEntrega de eliminación
POST /konko/webhooks HTTP/1.1
Host: integraciones.clinicahorizonte.example
Content-Type: application/fhir+json
X-Medplum-Subscription: 2e7a4c9f-6b3d-4a1e-9c5b-8d0f7e2a4c39
X-Medplum-Interaction: delete
X-Medplum-Deleted-Resource: Appointment/6b1f8e3d-2a9c-4b5e-8f7d-3e0a6c1b9d84
X-Signature: e77eb15d139ff89a6849bd1f20f78a3583aaa46ead148ba2779d94eb75371470
Authorization: Bearer 3f9c1a7e5b2d4c8f

{}
Webhooks

Verifying signatures

Verificar firmas

Set a signing secret on each subscription and reject any delivery whose signature doesn't match.

Configura un secreto de firma en cada suscripción y rechaza cualquier entrega cuya firma no coincida.

  • Konko computes an HMAC-SHA256 of the request body with your secret and sends the hex digest in X-Signature.
  • Konko calcula un HMAC-SHA256 del cuerpo de la solicitud con tu secreto y envía el digest hexadecimal en X-Signature.
  • Compute the same digest over the raw body bytes before parsing the JSON. Re-serialized JSON won't match.
  • Calcula el mismo digest sobre los bytes sin procesar del cuerpo antes de analizar el JSON. Un JSON reserializado no coincidirá.
  • Compare with a constant-time function such as hmac.compare_digest or crypto.timingSafeEqual.
  • Compara con una función de tiempo constante como hmac.compare_digest o crypto.timingSafeEqual.
  • Delete deliveries are signed too. Their body is {}.
  • Las entregas de eliminación también se firman. Su cuerpo es {}.
  • The signature proves the body came from Konko and wasn't modified. It doesn't include a timestamp, so rely on meta.versionId to drop replays and duplicates.
  • La firma demuestra que el cuerpo vino de Konko y no fue modificado. No incluye una marca de tiempo, así que apóyate en meta.versionId para descartar repeticiones y duplicados.
NoteNota

Serve your endpoint over HTTPS only. Custom channel.header values, such as an API key, give you a second check that the request came from Konko.

Sirve tu endpoint solo por HTTPS. Los valores personalizados de channel.header, como una clave de API, te dan una segunda comprobación de que la solicitud vino de Konko.

Verify X-Signature
Verificar X-Signature
import hashlib
import hmac

WEBHOOK_SECRET = "whsec_7b1d4e9a2c6f8b3e5a0d9c7f1e4b6a28"


def is_valid_signature(raw_body: bytes, signature: str | None) -> bool:
    """raw_body must be the exact bytes received, before any JSON parsing."""
    if not signature:
        return False
    expected = hmac.new(WEBHOOK_SECRET.encode(), raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, signature)


# FastAPI example
from fastapi import FastAPI, HTTPException, Request

app = FastAPI()


@app.post("/konko/webhooks")
async def konko_webhook(request: Request):
    raw = await request.body()
    if not is_valid_signature(raw, request.headers.get("X-Signature")):
        raise HTTPException(status_code=401)
    enqueue_for_processing(
        interaction=request.headers["X-Medplum-Interaction"],
        deleted=request.headers.get("X-Medplum-Deleted-Resource"),
        body=raw,
    )
    return {"received": True}
Webhooks

Retries

Reintentos

A delivery succeeds when your endpoint answers with a status from 200 to 399. Anything else is retried with exponential backoff.

Una entrega tiene éxito cuando tu endpoint responde con un estado de 200 a 399. Cualquier otra cosa se reintenta con retroceso exponencial.

  • Failures are any other status code, no response within 120 seconds, or a connection or TLS error. Redirects are followed.
  • Son fallos cualquier otro código de estado, la falta de respuesta en 120 segundos, o un error de conexión o de TLS. Las redirecciones se siguen.
  • Retries wait 1 second, then 2, 4, 8 and so on, doubling each time.
  • Los reintentos esperan 1 segundo, luego 2, 4, 8 y así sucesivamente, duplicando cada vez.
  • The default is 4 retries. Raise it with the subscription-max-attempts extension (up to 18) if your endpoint can be unavailable for longer. To change which status codes count as success, use subscription-success-codes.
  • El valor predeterminado es 4 reintentos. Auméntalo con la extensión subscription-max-attempts (hasta 18) si tu endpoint puede estar no disponible por más tiempo. Para cambiar qué códigos de estado cuentan como éxito, usa subscription-success-codes.
  • After the last retry the delivery is dropped. The subscription stays active and keeps receiving new changes.
  • Después del último reintento, la entrega se descarta. La suscripción permanece active y sigue recibiendo nuevos cambios.
  • While a delivery is waiting to be retried, the resource may change again. The stale retry is then skipped and the newer version is delivered.
  • Mientras una entrega espera a reintentarse, el recurso puede cambiar de nuevo. En ese caso el reintento obsoleto se omite y se entrega la versión más reciente.
subscription-max-attemptsTotal attemptsIntentos totalesLast attempt, after the first failureÚltimo intento, después del primer fallo
4 (default)4 (predeterminado)5about 15 secondsalrededor de 15 segundos
89about 4 minutesalrededor de 4 minutos
1213about 1 hour 8 minutesalrededor de 1 hora 8 minutos
1516about 9 hoursalrededor de 9 horas
18 (maximum)18 (máximo)19about 73 hoursalrededor de 73 horas

Times are approximate and exclude the time your endpoint takes to respond.

Los tiempos son aproximados y excluyen el tiempo que tarda tu endpoint en responder.

Webhooks

Delivery log

Registro de entregas

Check what Konko sent to your endpoint and why a delivery failed.

Revisa qué envió Konko a tu endpoint y por qué falló una entrega.

List delivery attempts

Listar intentos de entrega

GET/fhir/R4/AuditEvent

Every delivery attempt is recorded as an AuditEvent of type transmit. Search them by subscription to see what was sent, when, and what your endpoint answered.

Cada intento de entrega se registra como un AuditEvent de tipo transmit. Búscalos por suscripción para ver qué se envió, cuándo y qué respondió tu endpoint.

Query parameters
Parámetros de consulta
  • entityreferenceRequiredObligatorio

    Subscription/{id} for one webhook, or the changed resource (Appointment/{id}) to see every delivery about it.

    Subscription/{id} para un webhook, o el recurso modificado (Appointment/{id}) para ver todas las entregas relacionadas con él.

    Example: Subscription/2e7a4c9f-6b3d-4a1e-9c5b-8d0f7e2a4c39
    Ejemplo: Subscription/2e7a4c9f-6b3d-4a1e-9c5b-8d0f7e2a4c39
  • outcometoken

    0 for successful attempts, 4 for failed ones.

    0 para los intentos exitosos, 4 para los fallidos.

  • datedate

    When the attempt was recorded. Supports ge, le and the other date prefixes.

    Cuándo se registró el intento. Admite ge, le y los demás prefijos de fecha.

    Example: ge2026-10-02
    Ejemplo: ge2026-10-02
  • _sortstring

    -date for newest first.

    -date para los más recientes primero.

What each attempt records
Qué registra cada intento
  • outcomecode

    0 delivered, 4 failed.

    0 entregado, 4 fallido.

  • outcomeDescstring

    The attempt number (starting at 0) and your endpoint's status code, or the network error.

    El número de intento (empezando en 0) y el código de estado de tu endpoint, o el error de red.

    Example: Attempt 0 received status 503
    Ejemplo: Attempt 0 received status 503
  • periodPeriod

    start is when the change happened, end is when the attempt finished.

    start es cuándo ocurrió el cambio, end es cuándo terminó el intento.

  • entityBackboneElement[]

    The changed resource (role 4, or 1 for a Patient) and the subscription (role 9).

    El recurso modificado (role 4, o 1 para un Patient) y la suscripción (role 9).

GET/fhir/R4/AuditEvent
curl -G "https://api.medplum.konko.ai/fhir/R4/AuditEvent" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  --data-urlencode "entity=Subscription/{subscription_id}" \
  --data-urlencode "_sort=-date" \
  --data-urlencode "_count=20"
200 OK  Response
200 OK  Respuesta
{
  "resourceType": "Bundle",
  "type": "searchset",
  "entry": [
    {
      "fullUrl": "https://api.medplum.konko.ai/fhir/R4/AuditEvent/4d8c2f6a-9e5b-4c1d-a3f7-6b0e8d4c2a95",
      "resource": {
        "resourceType": "AuditEvent",
        "id": "4d8c2f6a-9e5b-4c1d-a3f7-6b0e8d4c2a95",
        "meta": {
          "versionId": "e2b7d4a9-6c1f-4e3b-a8d5-0f9c2e7b4a61",
          "lastUpdated": "2026-10-02T16:20:03.117Z"
        },
        "period": {
          "start": "2026-10-02T16:20:02.841Z",
          "end": "2026-10-02T16:20:03.109Z"
        },
        "recorded": "2026-10-02T16:20:03.109Z",
        "type": {
          "code": "transmit"
        },
        "agent": [
          {
            "type": {
              "text": "Subscription"
            },
            "requestor": false
          }
        ],
        "source": {
          "observer": {
            "reference": "Subscription/2e7a4c9f-6b3d-4a1e-9c5b-8d0f7e2a4c39"
          }
        },
        "entity": [
          {
            "what": {
              "reference": "Appointment/6b1f8e3d-2a9c-4b5e-8f7d-3e0a6c1b9d84"
            },
            "role": {
              "code": "4",
              "display": "Domain"
            }
          },
          {
            "what": {
              "reference": "Subscription/2e7a4c9f-6b3d-4a1e-9c5b-8d0f7e2a4c39"
            },
            "role": {
              "code": "9",
              "display": "Subscriber"
            }
          }
        ],
        "outcome": "4",
        "outcomeDesc": "Attempt 0 received status 503"
      },
      "search": {
        "mode": "match"
      }
    }
  ],
  "link": [
    {
      "relation": "self",
      "url": "https://api.medplum.konko.ai/fhir/R4/AuditEvent?entity=Subscription/2e7a4c9f-6b3d-4a1e-9c5b-8d0f7e2a4c39&_sort=-date&_count=20"
    },
    {
      "relation": "first",
      "url": "https://api.medplum.konko.ai/fhir/R4/AuditEvent?entity=Subscription/2e7a4c9f-6b3d-4a1e-9c5b-8d0f7e2a4c39&_sort=-date&_count=20&_offset=0"
    },
    {
      "relation": "next",
      "url": "https://api.medplum.konko.ai/fhir/R4/AuditEvent?entity=Subscription/2e7a4c9f-6b3d-4a1e-9c5b-8d0f7e2a4c39&_sort=-date&_count=20&_offset=20"
    }
  ]
}