Medical Core Docs
POST/appointments
Troubleshooting

Bug 510 — Cannot read properties of null (reading 'admitionStatus')

Por qué `POST /appointments` falla con 510 y cómo enviar el payload correcto.

El endpoint `POST /api/v1/appointments` delegate a MedicalCore RD en `/api/cita/insert`. MedicalCore es extremadamente estricto con la estructura del payload: cualquier campo extra en `paciente`, un `area._id` mal mapeado o un `start/end` con timezone mal calculado devuelve 510 Not Extended. Esta guía resume las 4 causas más frecuentes del 510 (en orden de aparición) y la estructura EXACTA del payload validado.
Headers obligatorios: `Content-Type: application/json`, `x-api-key: <MEDEX_API_KEY>`, `enterpriseid: 150575`, `ownerid: 150575`.
Mapeo crítico: `cita.area._id` debe ser el área de CONSULTA (660, 1816, 622), NO la specialty (1704, 1690, 1723). El wrapper `/areas` expone especialidades; las áreas de consulta son un subconjunto interno.
Timezone: `cita.start` en formato `-04:00` (AST) y `cita.end` en formato `Z` (UTC). `start = utc - 4h`, `end = start + 20min` en UTC.
Saneamiento de `paciente`: el `raw` de `/patients/search` tiene ~40 campos. Sólo enviar los 11 básicos.
Operations: leer de `paciente.raw.properties` — NO hardcodear todos a `false`, MedicalCore los usa para resolver el estado de admisión.
Campos PROHIBIDOS en `paciente` (causan el 510): `medicoCabecera`, `patientMaster`, `centroMedicos`, `agent`, `companions`, `properties`, `admitionStatus`, `patientContactDetailId`, `datosDeSistemaIntegrado`, `branch`, `direccion`, `padronUrl`, `pais`, `paisPasaporte`, `maritalStatus`, `titular`, `numeroAfiliado`, `isValidIdentification`, `emailValidation`, `forms`, `question_sets`, `cuestionario`, `viaDeContacto`, `contactIndicator`, `token`, `createdBy`, `createdDate`, `updatedBy`, `updatedDate`, `ownerId`, `baseApiPathv2`, `baseApiPathPatientBraceletv2`, `isMedic`, `fullName`.
Flujo recomendado
Orden en que deberías llamar a los endpoints.
  1. 1
    1. Síntoma: Cannot read properties of null (reading 'admitionStatus')paciente.raw con ~40 campos + area mal mapeado. Fix: limpiar paciente a 11 campos y traducir area.
  2. 2
    2. Síntoma: Cannot read properties of undefined (reading '_id') → falta cita.area._id. Fix: incluir el objeto area con su _id.
  3. 3
    3. Síntoma: Invalid appointment structure. Must contain cita object with doctorId and pacienteId. → falta cita.pacienteId a nivel raíz. Fix: incluir pacienteId tanto en cita como en cita.citaPaciente.
  4. 4
    4. Síntoma: la fecha fin debe ser mayor a la fecha de inicio → cálculo mal del timezone (sumaba 4h en vez de restar). Fix: restar 4h para formato -04:00.
Mapeo de campos
De dónde sale cada valor que tienes que enviar.
CampoOrigen
cita.area._idMapeo specialty → consulta (660, 1816, 622)
cita.startSlot UTC → restar 4h → `-04:00`
cita.end`start + 20min` en `Z` (UTC)
cita.citaPaciente.pacienteSaneado a 11 campos desde `raw`
cita.operations`paciente.raw.properties`

Cuerpo de la petición

Payload COMPLETO validado contra MedicalCore RD. Estructura probada y funcional.

Ejemplos

Ejemplo 1
Payload validado (Opción B)

Estructura completa que NO devuelve 510. Copia y adapta los IDs a tu caso.

payload-validado-(opción-b).json·json
{
  "cita": {
    "citaId": null,
    "doctorId": 153625,
    "pacienteId": 4958123,
    "pacienteCedula": "223-0073480-7",
    "attentionType": "h",
    "type": "p",
    "recurrente": false,
    "doctor": {
      "_id": 153625,
      "nombre": "Pedro",
      "apellido": "Rodriguez Gonzalez",
      "fullName": "Pedro Rodriguez Gonzalez",
      "universalId": "",
      "especialidad": " Medicina Interna"
    },
    "area": {
      "_id": 660,
      "description": "Consulta de Medicina Interna",
      "type": {
        "_id": 1,
        "description": "Doctores"
      }
    },
    "subArea": {
      "_id": 153625,
      "fullName": "Pedro Rodriguez Gonzalez"
    },
    "start": "2026-08-05T11:40:00-04:00",
    "end": "2026-08-05T16:00:00.000Z",
    "status": "Pendiente por confirmar",
    "citaPaciente": {
      "place": {
        "_id": 150575,
        "name": "Médico Express RD"
      },
      "service": {
        "_id": 2221,
        "description": "CONSULTA DE SEGUNDA OPINIÓN LOCAL",
        "duration": {
          "_id": 1,
          "label": "240 Minutos",
          "value": "m",
          "time": 240
        },
        "baseApiPath": "api/especialidad"
      },
      "pacienteId": 4958123,
      "paciente": {
        "_id": 4958123,
        "nombre": "DANIEL GIOVANNI",
        "apellido": "SANTILLAN PEREZ",
        "sexo": "M",
        "email": "SANTILLANDSP@GMAIL.COM",
        "fechaNacimiento": "1989-05-26T08:00:00.000Z",
        "newPatient": false,
        "numeroDeRecord": "2024-3831",
        "numeroIdentificacion": "223-0073480-7",
        "telefono": [
          {
            "tipo": "Móvil",
            "numero": "829-605-8450"
          }
        ],
        "afiliaciones": []
      },
      "comment": null,
      "internment": false,
      "coverages": [
        {
          "_id": 75229,
          "codCobertura": "00423315A",
          "description": "CONSULTA DE SEGUNDA OPINIÓN LOCAL",
          "duration": {
            "_id": 1,
            "label": "20 Minutos",
            "value": "m",
            "time": 20
          },
          "tipo": "Otros",
          "subTipo": " ",
          "dispositivo": false,
          "usePaymentLink": false,
          "servicioAseguradora": {
            "code": "1",
            "description": "Ambulatorio"
          }
        }
      ]
    },
    "branch": {
      "_id": 392,
      "description": "San Isidro"
    },
    "servicioAseguradora": {
      "code": "1",
      "description": "Ambulatorio"
    },
    "doneSaved": false,
    "operations": {
      "priority": false,
      "fallRisk": false,
      "wheelChair": false,
      "vip": false,
      "companion": false,
      "overWeight": false,
      "pregnant": true,
      "needSupport": false,
      "disabled": false,
      "special": false
    },
    "ubicacion": null,
    "pagadorReferidor": null,
    "pagador": {},
    "referallDoctors": [],
    "ordenMedica": {
      "numero": null,
      "doctor": {
        "_id": 0,
        "fullName": null,
        "especialidad": null
      }
    }
  }
}

cURL

request.sh·bash
curl -X POST "https://apimedex.dploy.lol/api/v1/appointments" \
  -H "Content-Type: application/json" \
  -H "x-api-key: $MEDEX_API_KEY" \
  -H "enterpriseid: 150575" \
  -H "ownerid: 150575" \
  -d '{
    "cita": {
      "citaId": null, "doctorId": 153625, "pacienteId": 4958123, "pacienteCedula": "223-0073480-7",
      "attentionType": "h", "type": "p", "recurrente": false,
      "doctor": { "_id": 153625, "nombre": "Pedro", "apellido": "Rodriguez Gonzalez", "fullName": "Pedro Rodriguez Gonzalez", "universalId": "", "especialidad": " Medicina Interna" },
      "area": { "_id": 660, "description": "Consulta de Medicina Interna", "type": { "_id": 1, "description": "Doctores" } },
      "subArea": { "_id": 153625, "fullName": "Pedro Rodriguez Gonzalez" },
      "start": "2026-08-05T11:40:00-04:00", "end": "2026-08-05T16:00:00.000Z", "status": "Pendiente por confirmar",
      "citaPaciente": {
        "place": { "_id": 150575, "name": "Médico Express RD" },
        "service": { "_id": 2221, "description": "CONSULTA DE SEGUNDA OPINIÓN LOCAL", "duration": { "_id": 1, "label": "240 Minutos", "value": "m", "time": 240 }, "baseApiPath": "api/especialidad" },
        "pacienteId": 4958123,
        "paciente": { "_id": 4958123, "nombre": "DANIEL GIOVANNI", "apellido": "SANTILLAN PEREZ", "sexo": "M", "email": "SANTILLANDSP@GMAIL.COM", "fechaNacimiento": "1989-05-26T08:00:00.000Z", "newPatient": false, "numeroDeRecord": "2024-3831", "numeroIdentificacion": "223-0073480-7", "telefono": [{"tipo": "Móvil", "numero": "829-605-8450"}], "afiliaciones": [] },
        "comment": null, "internment": false,
        "coverages": [{ "_id": 75229, "codCobertura": "00423315A", "description": "CONSULTA DE SEGUNDA OPINIÓN LOCAL", "duration": { "_id": 1, "label": "20 Minutos", "value": "m", "time": 20 }, "tipo": "Otros", "subTipo": " ", "dispositivo": false, "usePaymentLink": false, "servicioAseguradora": { "code": "1", "description": "Ambulatorio" } }]
      },
      "branch": { "_id": 392, "description": "San Isidro" },
      "servicioAseguradora": { "code": "1", "description": "Ambulatorio" },
      "doneSaved": false,
      "operations": { "priority": false, "fallRisk": false, "wheelChair": false, "vip": false, "companion": false, "overWeight": false, "pregnant": true, "needSupport": false, "disabled": false, "special": false },
      "ubicacion": null, "pagadorReferidor": null, "pagador": {}, "referallDoctors": [],
      "ordenMedica": { "numero": null, "doctor": { "_id": 0, "fullName": null, "especialidad": null } }
    }
  }'

Respuestas
4

StatusDescripción
200Cita creada. Devuelve `{ data: { citaId: "2026-XXXX", _id: 9XXXXXX, ... } }`.
400Estructura inválida. Verificar `citaId`, `pacienteId`, `doctorId`, `area._id`.
510MedicalCore no pudo procesar. Verificar: (a) `paciente` saneado, (b) `area._id` mapeado a consulta, (c) timezone correcto, (d) `pacienteId` a nivel raíz.
510Mensaje alternativo cuando se manda `start` y `end` con timezone mal calculado.
200
Cita creada. Devuelve `{ data: { citaId: "2026-XXXX", _id: 9XXXXXX, ... } }`.
response-200.json·json
{
  "data": {
    "citaId": "2026-XXXX",
    "_id": 9000000,
    "status": "Pendiente por confirmar"
  }
}
400
Estructura inválida. Verificar `citaId`, `pacienteId`, `doctorId`, `area._id`.
response-400.json·json
{
  "error": "Invalid appointment structure. Must contain cita object with doctorId and pacienteId."
}
510
MedicalCore no pudo procesar. Verificar: (a) `paciente` saneado, (b) `area._id` mapeado a consulta, (c) timezone correcto, (d) `pacienteId` a nivel raíz.
response-510.json·json
{
  "error": "Cannot read properties of null (reading 'admitionStatus')"
}
510
Mensaje alternativo cuando se manda `start` y `end` con timezone mal calculado.
response-510.json·json
{
  "error": "la fecha fin debe ser mayor a la fecha de inicio"
}