Verify and fetch records
Check the code, open the OTP gate, and get the patient's records back in the same call.
POST /v1/patients/verify-phone-verification-otpVerifies the code sent by send-phone-verification-otp and does two things at once: it opens the OTP gate for the next 30 minutes, and it returns everything the clinic already holds for that phone — the patient records on it, their active session packs, and the packs available to buy.
That second half is why this pair exists alongside
/v1/otp/*: one call gets you both
consent and the data you need to book.
Body
| Field | Type | Required | Description |
|---|---|---|---|
otpCode | string | Yes | The code the patient received. |
phoneNumber | string | Yes* | The same number you sent to. |
countryCode | string | No | Defaults to +91. Must match what you sent to. |
channel | string | No | whatsapp (default) or email. |
email | string | Yes* | *Instead of phoneNumber on the email channel. |
Try it
/v1/patients/verify-phone-verification-otpBody
POST /v1/patients/verify-phone-verification-otp{
"countryCode": "+91",
"phoneNumber": "9811100001"
}https://api.medos.oneUse a dedicated test key, and put your browser's address on its allowlist
A Developer API key authenticates on its own, so it only works from the addresses registered against it — and this page calls from your browser, not your servers. Unless your own public address is on the list you get a 403 naming it, which is the allowlist doing its job. Your browser may also reach us over IPv6 even when your server does not, so the address in the error is often not the one you expected. The key here is kept in memory only and never written to storage, but create a test key for it and deactivate that key when you are done.
Request
curl -sX POST "https://api.medos.one/v1/patients/verify-phone-verification-otp" \
-H "x-api-key: $MEDOS_API_KEY" \
-H "x-end-user-id: $PATIENT_ID" \
-H "Content-Type: application/json" \
-d '{ "countryCode": "+91", "phoneNumber": "9876543210", "otpCode": "418206" }'Response
{
"success": true,
"message": "Phone number verified successfully",
"channel": "whatsapp",
"data": {
"associatedPatients": [
{
"id": 774,
"mrnNumber": "MRN-0774",
"firstName": "Asha",
"lastName": "Nair",
"countryCode": "+91",
"phoneNumber": "9876543210",
"dob": "1991-04-02",
"gender": "FEMALE",
"patientFormValues": {}
}
],
"activeSessionPackResponses": [
{
"id": 4411,
"packageConfigId": 12,
"sessionPackName": "Physio — 10 sessions",
"totalSessions": 10,
"sessionsUsed": 3,
"sessionsRemaining": 7,
"durationMins": 30,
"purchasedOn": "2026-07-14",
"expiresOn": "2026-10-12",
"allowedDoctorIds": [4, 7],
"allowFamilyBooking": true
}
],
"allSessionPackResponses": []
}
}| Field | Meaning |
|---|---|
associatedPatients[] | Every patient record on that phone. One number often covers a household — a parent booking for a child shares it — so this is a list, and picking the right member is your job. |
activeSessionPackResponses[] | Packs the patient can spend now. id is the patientPackageId a USE_ACTIVE_PACKAGE booking takes. |
allSessionPackResponses[] | The clinic's purchasable catalog, same shape as the catalog route. |
An empty associatedPatients is a successful verification of a phone the clinic
has never seen. Book with a patientPayload and the record is created.
The gate is now open for 30 minutes
Every OTP-gated route will accept requests carrying the same
x-end-user-id for the next 30 minutes. A different value is a different
patient, and starts unverified.
Common failures
| Status | Cause |
|---|---|
400 | otpCode missing. |
400 | Invalid or expired code — { "success": false, "message": "Invalid or expired OTP" }. Send a new one. |
400 | Verifying a different destination than you sent to. The code is bound to the exact countryCode + phoneNumber pair. |