Server-side APIEndpointsOTP

Verify an OTP

Check the code and open the OTP gate for the next 30 minutes.

POST /v1/otp/verify

Verifies the code from /v1/otp/send and opens the OTP gate for the patient named in x-end-user-id. Every gated route then accepts requests for that patient for 30 minutes.

It returns the verification result and nothing else. If you also want the patient's records in the same call, use verify-phone-verification-otp.

Body

FieldTypeRequiredDescription
otpCodestringYesThe code the patient received.
phoneNumberstringYes*The same number you sent to.
countryCodestringNoDefaults to +91. Must match what you sent to.
channelstringNowhatsapp (default) or email.
emailstringYes**Instead of phoneNumber on the email channel.

Try it

POST/v1/otp/verify

Body

Request
POST /v1/otp/verify
{
  "countryCode": "+91",
  "phoneNumber": "9811100001"
}
to https://api.medos.one
Use 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/otp/verify" \
  -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",
  "verified": true,
  "channel": "whatsapp",
  "sessionId": "svc:billing-sync",
  "expiresInMinutes": 30
}
FieldMeaning
verifiedtrue on success. A failure is a 400, not a 200 with false.
sessionIdThe identity the gate was opened for. For an API key it is dapi: followed by hashes of your key and your x-end-user-id — never the raw values — which is why the next request must carry the same x-end-user-id.
expiresInMinutesAlways 30. The clock starts now.

The gate follows x-end-user-id

One API key serves every patient you have, so the gate cannot be keyed to the key alone — it is keyed to the key and x-end-user-id together. Keep the value stable across the verify and the booking that follows, and use a distinct value per patient. Two patients sharing one would share a gate, and one would act on the other's verification.

Common failures

StatusCause
400otpCode missing — { "success": false, "message": "OTP code is required", "verified": false }.
400Invalid or expired code. Send a new one; codes are not reusable.
400Verifying a different destination than you sent to.

Next

On this page