Líneas de la clínica
La lista corta de lo que buscan los pacientes (Implantes, Estética, Endodoncia…): cada especialidad del equipo y cada anuncio pertenecen a una sola Línea, y cada lead lleva una.
Descarga la proyección completa de la API pública: openapi.json.
Definir prestaciones y precios explica este recurso en prosa, con ejemplos ejecutables.
| Método | Ruta | Qué hace |
|---|---|---|
GET | /clinic/lineas | List the clinic's Líneas, with the mapping and the unmapped |
POST | /clinic/lineas | Add a Línea |
PATCH | /clinic/lineas/{id} | Rename or archive a Línea |
POST | /clinic/lineas/{id}/keywords | Add a keyword for leads without an ad |
POST | /clinic/lineas/{id}/merge | Merge a Línea into another |
POST | /clinic/lineas/{id}/rules | Map ads to a Línea by a name fragment |
DELETE | /clinic/lineas/keywords/{id} | Remove a keyword |
DELETE | /clinic/lineas/rules/{id} | Remove a name fragment rule |
PUT | /clinic/lineas/specialties/{id} | Place a roster specialty in a Línea |
GET /clinic/lineas
List the clinic's Líneas, with the mapping and the unmapped
A Línea is one entry in the clinic's own short list of what patients come for (Implantes, Estética, Endodoncia, TTM…), usually fewer than its specialties. The list is seeded from the roster's specialties on first read and is editable. Every roster specialty and every ad maps into exactly one Línea: specialties and rules (name fragments an ad's campaign, ad set or ad name must contain) say how; keywords are the words a lead without an ad says when it wants the Línea (seeded for dental clinics, editable); unmapped_specialties and the ads with linea_id: null are the ones the owner still has to place. Each lead carries exactly one Línea (linea on the lead). Requires clinic:read.
Connected apps: every patient and contact in the response is a Seudónimo de paciente — initials plus a stable number, "M.F. · #1001" — unless the clinic allowed patient names, with RUT, phone and email masked in free text and meta.patient_privacy saying so. Clinical alerts (flags) are withheld in both modes, and a non-JSON body (an export, a file) is refused with 403 CONNECTED_APP_SENSITIVE_DATA.
curl https://api.vitrinadev.com/api/v1/clinic/lineas \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"lineas": [
{
"id": "5b1f0c1e-0000-4000-8000-000000000001",
"nombre": "Implantes",
"is_default": false,
"archived": false,
"leads": 41,
"open_leads": 33,
"rules": [
{
"id": "5b1f0c1e-0000-4000-8000-000000000003",
"match": "implant",
"source": "seed"
}
],
"keywords": [
{
"id": "5b1f0c1e-0000-4000-8000-000000000005",
"keyword": "implant",
"source": "seed"
}
],
"specialties": [
{
"id": "5b1f0c1e-0000-4000-8000-000000000002",
"nombre": "Implantología"
}
]
}
],
"unmapped_specialties": [
{
"id": "5b1f0c1e-0000-4000-8000-000000000004",
"nombre": "Prostodoncia"
}
],
"ads": [
{
"external_id": "120250735360390233",
"campaign_name": "Campaña de mensajes IMPLANTES",
"ad_set_name": "INTERESES",
"ad_name": "Implantes 2",
"linea_id": "5b1f0c1e-0000-4000-8000-000000000001",
"via": "rule",
"matched": "implant",
"conversations": 119,
"leads": 38
}
]
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /clinic/lineas
Add a Línea
Find-or-create by name (accent- and case-insensitive). Requires clinic_admin:write.
Connected apps: every patient and contact in the response is a Seudónimo de paciente — initials plus a stable number, "M.F. · #1001" — unless the clinic allowed patient names, with RUT, phone and email masked in free text and meta.patient_privacy saying so. Clinical alerts (flags) are withheld in both modes, and a non-JSON body (an export, a file) is refused with 403 CONNECTED_APP_SENSITIVE_DATA.
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
nombre | string | sí | mín. 1, máx. 80 |
curl -X POST https://api.vitrinadev.com/api/v1/clinic/lineas \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"nombre": "Implantes"
}'Ejemplo de respuesta (201)
{
"data": {
"id": "5b1f0c1e-0000-4000-8000-000000000001",
"tenant_id": "5b1f0c1e-0000-4000-8000-0000000000aa",
"nombre": "Implantes",
"is_default": false,
"archived_at": null,
"created_at": "2026-10-09T12:00:00.000Z",
"updated_at": "2026-10-09T12:00:00.000Z"
}
}Responde: 201 · 400 · 401 · 403 · 404 · 409 · 429
PATCH /clinic/lineas/{id}
Rename or archive a Línea
An archived Línea leaves the pickers but keeps the leads that carry it. The default Línea («General») cannot be archived. Requires clinic_admin:write.
Connected apps: every patient and contact in the response is a Seudónimo de paciente — initials plus a stable number, "M.F. · #1001" — unless the clinic allowed patient names, with RUT, phone and email masked in free text and meta.patient_privacy saying so. Clinical alerts (flags) are withheld in both modes, and a non-JSON body (an export, a file) is refused with 403 CONNECTED_APP_SENSITIVE_DATA.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
nombre | string | — | mín. 1, máx. 80 |
archived | boolean | — |
curl -X PATCH https://api.vitrinadev.com/api/v1/clinic/lineas/<id> \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"nombre": "Implantología"
}'Ejemplo de respuesta (200)
{
"data": {
"id": "5b1f0c1e-0000-4000-8000-000000000001",
"tenant_id": "5b1f0c1e-0000-4000-8000-0000000000aa",
"nombre": "Implantes",
"is_default": false,
"archived_at": null,
"created_at": "2026-10-09T12:00:00.000Z",
"updated_at": "2026-10-09T12:00:00.000Z"
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /clinic/lineas/{id}/keywords
Add a keyword for leads without an ad
A lead that did not come from an ad gets its Línea from its own words before it falls back to General: the lead's title, the booked cita's tratamiento, the score reason, the conversation summary and the notes are matched (accent- and case-insensitive, from the start of a word) against each Línea's keywords. The first of those fields that names a Línea decides; within it the Línea with the most keywords wins. An ad's Línea and a person's choice are never replaced. No model call. A keyword already pointing at another Línea answers 409. Requires clinic_admin:write.
Connected apps: every patient and contact in the response is a Seudónimo de paciente — initials plus a stable number, "M.F. · #1001" — unless the clinic allowed patient names, with RUT, phone and email masked in free text and meta.patient_privacy saying so. Clinical alerts (flags) are withheld in both modes, and a non-JSON body (an export, a file) is refused with 403 CONNECTED_APP_SENSITIVE_DATA.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
keyword | string | sí | mín. 2, máx. 80 |
curl -X POST https://api.vitrinadev.com/api/v1/clinic/lineas/<id>/keywords \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"keyword": "botox"
}'Ejemplo de respuesta (201)
{
"data": {
"id": "5b1f0c1e-0000-4000-8000-000000000005",
"tenant_id": "5b1f0c1e-0000-4000-8000-0000000000aa",
"linea_id": "5b1f0c1e-0000-4000-8000-000000000001",
"keyword": "botox",
"source": "owner",
"created_at": "2026-10-10T12:00:00.000Z"
}
}Responde: 201 · 400 · 401 · 403 · 404 · 409 · 429
POST /clinic/lineas/{id}/merge
Merge a Línea into another
Moves every lead, specialty and rule of this Línea to into_id, then removes it. Irreversible. Requires clinic_admin:write.
Connected apps: every patient and contact in the response is a Seudónimo de paciente — initials plus a stable number, "M.F. · #1001" — unless the clinic allowed patient names, with RUT, phone and email masked in free text and meta.patient_privacy saying so. Clinical alerts (flags) are withheld in both modes, and a non-JSON body (an export, a file) is refused with 403 CONNECTED_APP_SENSITIVE_DATA.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
into_id | uuid | sí |
curl -X POST https://api.vitrinadev.com/api/v1/clinic/lineas/<id>/merge \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"into_id": "5b1f0c1e-0000-4000-8000-000000000001"
}'Ejemplo de respuesta (200)
{
"data": {
"into": {
"id": "5b1f0c1e-0000-4000-8000-000000000001",
"tenant_id": "5b1f0c1e-0000-4000-8000-0000000000aa",
"nombre": "Implantes",
"is_default": false,
"archived_at": null,
"created_at": "2026-10-09T12:00:00.000Z",
"updated_at": "2026-10-09T12:00:00.000Z"
},
"moved": {
"leads": 4,
"specialties": 1,
"rules": 2
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /clinic/lineas/{id}/rules
Map ads to a Línea by a name fragment
An ad whose campaign, ad set or ad name contains the fragment belongs to this Línea; the longest fragment wins. A fragment already pointing at another Línea answers 409. Requires clinic_admin:write.
Connected apps: every patient and contact in the response is a Seudónimo de paciente — initials plus a stable number, "M.F. · #1001" — unless the clinic allowed patient names, with RUT, phone and email masked in free text and meta.patient_privacy saying so. Clinical alerts (flags) are withheld in both modes, and a non-JSON body (an export, a file) is refused with 403 CONNECTED_APP_SENSITIVE_DATA.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
match | string | sí | mín. 2, máx. 80 |
curl -X POST https://api.vitrinadev.com/api/v1/clinic/lineas/<id>/rules \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"match": "GABRIELA RIQUELME"
}'Ejemplo de respuesta (201)
{
"data": {
"id": "5b1f0c1e-0000-4000-8000-000000000003",
"tenant_id": "5b1f0c1e-0000-4000-8000-0000000000aa",
"linea_id": "5b1f0c1e-0000-4000-8000-000000000001",
"match": "GABRIELA RIQUELME",
"source": "owner",
"created_at": "2026-10-09T12:00:00.000Z"
}
}Responde: 201 · 400 · 401 · 403 · 404 · 409 · 429
DELETE /clinic/lineas/keywords/{id}
Remove a keyword
Requires clinic_admin:write.
Connected apps: every patient and contact in the response is a Seudónimo de paciente — initials plus a stable number, "M.F. · #1001" — unless the clinic allowed patient names, with RUT, phone and email masked in free text and meta.patient_privacy saying so. Clinical alerts (flags) are withheld in both modes, and a non-JSON body (an export, a file) is refused with 403 CONNECTED_APP_SENSITIVE_DATA.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X DELETE https://api.vitrinadev.com/api/v1/clinic/lineas/keywords/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Responde: 204 · 400 · 401 · 403 · 404 · 409 · 429
DELETE /clinic/lineas/rules/{id}
Remove a name fragment rule
Requires clinic_admin:write.
Connected apps: every patient and contact in the response is a Seudónimo de paciente — initials plus a stable number, "M.F. · #1001" — unless the clinic allowed patient names, with RUT, phone and email masked in free text and meta.patient_privacy saying so. Clinical alerts (flags) are withheld in both modes, and a non-JSON body (an export, a file) is refused with 403 CONNECTED_APP_SENSITIVE_DATA.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X DELETE https://api.vitrinadev.com/api/v1/clinic/lineas/rules/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Responde: 204 · 400 · 401 · 403 · 404 · 409 · 429
PUT /clinic/lineas/specialties/{id}
Place a roster specialty in a Línea
id is a clinic_specialty id. linea_id: null takes it out of its Línea. Requires clinic_admin:write.
Connected apps: every patient and contact in the response is a Seudónimo de paciente — initials plus a stable number, "M.F. · #1001" — unless the clinic allowed patient names, with RUT, phone and email masked in free text and meta.patient_privacy saying so. Clinical alerts (flags) are withheld in both modes, and a non-JSON body (an export, a file) is refused with 403 CONNECTED_APP_SENSITIVE_DATA.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
linea_id | string | null | sí |
curl -X PUT https://api.vitrinadev.com/api/v1/clinic/lineas/specialties/<id> \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"linea_id": "5b1f0c1e-0000-4000-8000-000000000001"
}'Ejemplo de respuesta (200)
{
"data": {
"id": "5b1f0c1e-0000-4000-8000-000000000002",
"linea_id": "5b1f0c1e-0000-4000-8000-000000000001"
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429