Publicá tu app en el App Store de DrApp y conectala con la API en 6 pasos.
Desde Nueva App, creá una aplicación indicando nombre, descripción y los permisos (scopes) que necesitás.
Vas a recibir un client_id y un client_secret. Guardá el secret porque no se muestra de nuevo.
Completá los campos del marketplace (ícono, tagline, categoría, screenshots) para que tu app se vea profesional en el App Store.
La app queda en estado pendiente hasta que el equipo de DrApp la revise y apruebe.
Mientras esperás la aprobación, podés generar una sandbox key desde el detalle de tu app. Las claves sandbox (drapp_sandbox_*) apuntan a un equipo de prueba con datos ficticios, sin rate limit.
curl https://api.drapp.com.ar/public/v1/me \ -H "Authorization: Bearer drapp_sandbox_TU_KEY"
Cuando tu app sea aprobada, activá la opción "Publicar en App Store" desde la página de edición de tu app. Te llegará un email de confirmación.
Tu app aparecerá en el App Store de DrApp donde los profesionales y centros médicos pueden descubrirla e instalarla.
Si preferís no publicarla, podés compartir el link de instalación directamente:
https://appstore.drapp.com.ar/app/<tu-app-slug>
El administrador del equipo inicia sesión, elige su equipo y confirma los permisos. Se genera una API key de producción (drapp_live_*).
Si registraste una URL post-instalación, DrApp redirige al usuario automáticamente a esa URL con la key ya disponible en tu backend (ver Tip “Token Exchange” abajo). Si no configuraste esa URL, la key se muestra una sola vez en pantalla para que el usuario la copie.
Identidad profesional: si tu app solicita clinical:write o prescriptions:write, estos permisos solo se otorgan cuando quien instala es un profesional del equipo. Si instala un administrador o secretario, la app funciona pero sin esos permisos. Esto es así porque crear registros clínicos y emitir recetas son actos médicos que requieren la identidad del profesional que los firma.
Con la API key, podés hacer requests a cualquier endpoint que esté dentro de los scopes otorgados:
curl https://api.drapp.com.ar/public/v1/me \ -H "Authorization: Bearer drapp_live_TU_KEY" # Listar turnos del equipo curl "https://api.drapp.com.ar/public/v1/teams/TEAM_ID/events?from=2026-03-01&to=2026-03-31" \ -H "Authorization: Bearer drapp_live_TU_KEY"
Los headers de respuesta incluyen info de rate limit:
X-RateLimit-Limit-Minute: 60 X-RateLimit-Remaining-Minute: 59 X-RateLimit-Limit-Day: 10000 X-RateLimit-Remaining-Day: 9999 X-Request-ID: 550e8400-e29b-41d4-a716-446655440000
Registrá un webhook para recibir notificaciones en tiempo real. Eventos disponibles:
event.createdevent.updatedevent.cancelledconsumer.createdconsumer.updatedreminder.sentrecord.createdrecord.updatedprescription.createdmessage.sentcurl -X POST https://api.drapp.com.ar/public/v1/teams/TEAM_ID/webhooks \
-H "Authorization: Bearer drapp_live_TU_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://tu-app.com/webhooks/drapp",
"events": ["event.created", "record.created", "prescription.created"]
}'La respuesta incluye un signing_secret para verificar la firma HMAC-SHA256 en el header X-Drapp-Signature. Si una entrega falla, se reintenta automáticamente con backoff: 1 min → 5 min → 30 min → 2 h → 24 h. Después de 10 fallos consecutivos, el webhook se desactiva automáticamente.
Token Exchange — instalación sin copy-paste
Si registrás una URL post-instalación en tu app, DrApp agrega automáticamente los siguientes parámetros al redirigir al usuario:
https://tuapp.com/setup ?install_token=<64-hex-chars> &client_id=<tu-client-id> &team_id=teams/<slug>
Tu backend canjea ese token por la API key llamando a POST /public/install/exchangecon client_secret incluido. La API key llega directo a tu servidor — el usuario nunca tuvo que copiar nada.
# Ejemplo de exchange desde tu backend
curl -X POST https://api.drapp.com.ar/public/install/exchange \
-H "Content-Type: application/json" \
-d '{
"install_token": "<token-de-la-url>",
"client_id": "<tu-client-id>",
"client_secret": "<tu-client-secret>"
}'
# Respuesta:
# {
# "api_key": "drapp_live_...",
# "installation_id": "uuid",
# "team_id": "teams/mi-clinica",
# "granted_scopes": ["scheduling:read", "patients:read"]
# }El token expira a los 30 minutos y es de uso único. Si no podés llamar a exchange a tiempo, el usuario puede copiar la key manualmente desde la pantalla de instalación.
Identidad profesional y auto-fill de resource.id
Cuando una API key está vinculada a un profesional, los endpoints de escritura clínica (POST /records, POST /prescriptions) completan automáticamente el campo resource.id con la identidad del profesional. No necesitás enviarlo en el body.
Si enviás un resource.id diferente al profesional vinculado, la API responde 403 resource_mismatch. Esto previene que una app actúe a nombre de otro profesional.
# resource.id se completa automáticamente
curl -X POST https://api.drapp.com.ar/public/v1/teams/TEAM_ID/records \
-H "Authorization: Bearer drapp_live_TU_KEY" \
-H "Content-Type: application/json" \
-d '{ "type": "diagnosis", "consumer": { "id": "consumers/PATIENT_ID" } }'
# Error: 403 resource_required (si la key no es de un profesional)
# Error: 403 resource_mismatch (si resource.id no coincide con el profesional)Validación de request body
Todos los endpoints de escritura validan el body automáticamente. Si hay un error, recibís un detalle por campo:
{
"error": "validation_error",
"message": "Validation failed: firstName is required",
"details": [
{ "field": "firstName", "message": "firstName is required" }
]
}Idempotencia — evitá operaciones duplicadas
En requests POST/PATCH/PUT, enviá el header Idempotency-Key con un valor único. Si el request se repite dentro de las 24 horas, la API devuelve la respuesta original sin ejecutar la operación nuevamente.
curl -X POST https://api.drapp.com.ar/public/v1/teams/TEAM_ID/events \
-H "Authorization: Bearer drapp_live_TU_KEY" \
-H "Idempotency-Key: crear-turno-12345" \
-H "Content-Type: application/json" \
-d '{ ... }'Selección de campos
Usá ?fields= para recibir solo los campos que necesitás y reducir el tamaño de la respuesta:
# Solo traer id, nombre y emails de pacientes curl "https://api.drapp.com.ar/public/v1/teams/TEAM_ID/consumers?q=garcia&fields=id,firstName,lastName,emails" \ -H "Authorization: Bearer drapp_live_TU_KEY"
Expand / Embed
Por defecto, los objetos anidados en turnos (consumer, resource) vienen reducidos a { "id": "..." }. Para obtener los objetos completos, usá ?expand=consumer,resource:
curl "https://api.drapp.com.ar/public/v1/teams/TEAM_ID/events?from=2026-03-01&to=2026-03-31&expand=consumer,resource" \ -H "Authorization: Bearer drapp_live_TU_KEY"
Filtros incrementales — sincronización eficiente
Para sincronizar cambios sin releer todo, usá ?updated_after= o ?created_after= en el endpoint de turnos:
# Solo turnos modificados desde la última sincronización curl "https://api.drapp.com.ar/public/v1/teams/TEAM_ID/events?from=2026-03-01&to=2026-03-31&updated_after=2026-03-09T15:00:00Z" \ -H "Authorization: Bearer drapp_live_TU_KEY"
Paginación por cursor
Los endpoints que devuelven listas soportan paginación con cursor. Usá el valor de next_cursor de la respuesta para obtener la siguiente página:
# Primera página
{ "data": [...], "pagination": { "has_more": true, "next_cursor": "eyJpZ..." } }
# Siguiente página
curl "https://api.drapp.com.ar/public/v1/teams/TEAM_ID/consumers?q=garcia&cursor=eyJpZ..." \
-H "Authorization: Bearer drapp_live_TU_KEY"Rotación de API keys — zero downtime
Para rotar una API key sin downtime, usá el endpoint de rotación. La key vieja sigue activa durante un período de gracia (default 24h):
curl -X POST https://api.drapp.com.ar/public/install/installations/INSTALL_ID/rotate \
-H "Authorization: Bearer TU_JWT" \
-H "Content-Type: application/json" \
-d '{ "grace_hours": 24 }'
# Respuesta:
# { "api_key": "drapp_live_NUEVA_KEY", "old_key_expires_at": "2026-03-10T15:00:00Z" }Audit log — transparencia para los equipos
Los equipos pueden ver qué hizo cada app con sus datos:
curl "https://api.drapp.com.ar/public/v1/teams/TEAM_ID/audit-log?action=create&resource=events" \ -H "Authorization: Bearer drapp_live_TU_KEY"
Filtros disponibles: action, resource, app_id, from, to.
Errores estandarizados
Todas las respuestas de error siguen el mismo formato con un request_id para debugging:
{
"error": "not_found",
"message": "El recurso solicitado no existe",
"status": 404,
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}