TryVox

Check Verification Code

Verify an OTP code submitted by the user.

Endpoint

POST /v1/verify/check

Headers

HeaderRequiredDescription
AuthorizationyesBearer token: Bearer tvx_sk_live_...
X-Tenant-IDyesYour tenant ID: acc_...
Content-TypeyesMust be application/json

Request body

ParameterTypeRequiredDescription
verification_idstringyesThe verification ID returned from the start endpoint
codestringyesThe OTP code entered by the user (4-8 digits)

Response

Success (200 OK)

When the code is correct and verification succeeds:

{
  "data": {
    "verification_id": "ver_abc123",
    "status": "approved",
    "to": "+919876543210",
    "channel": "sms"
  }
}

Response fields

FieldTypeDescription
verification_idstringThe verification ID that was checked
statusstringVerification status: approved
tostringThe phone number or email that was verified
channelstringThe channel used for verification

Examples

Verify a code

curl -X POST https://api.tryvox.io/v1/verify/check \
  -H "Authorization: Bearer tvx_sk_live_..." \
  -H "X-Tenant-ID: acc_123" \
  -H "Content-Type: application/json" \
  -d '{
    "verification_id": "ver_abc123",
    "code": "123456"
  }'

Success response

{
  "data": {
    "verification_id": "ver_abc123",
    "status": "approved",
    "to": "+919876543210",
    "channel": "sms"
  }
}

Errors

VERIFICATION_FAILED (400)

The submitted code is incorrect.

{
  "error": {
    "code": "VERIFICATION_FAILED",
    "message": "Invalid verification code"
  }
}

Note: The verification remains active (status: pending) until max attempts are exceeded. The user can try again with a different code.

MAX_ATTEMPTS_EXCEEDED (429)

The user has submitted 5 incorrect codes.

{
  "error": {
    "code": "MAX_ATTEMPTS_EXCEEDED",
    "message": "Maximum verification attempts exceeded. Please request a new code."
  }
}

Note: After 5 failed attempts, the verification status changes to failed and cannot be used anymore. The user must request a new verification code.

NOT_FOUND (404)

The verification ID is invalid, expired, or already approved.

{
  "error": {
    "code": "NOT_FOUND",
    "message": "Verification not found or has expired"
  }
}

Possible causes:

  • Verification has expired (10 minutes passed since creation)
  • Verification was already successfully approved
  • Invalid verification ID
  • Verification has been marked as failed (max attempts exceeded)

VALIDATION_FAILED (400)

Invalid request format.

{
  "error": {
    "code": "VALIDATION_FAILED",
    "message": "Code must be 4-8 digits"
  }
}

Verification lifecycle

pending → approved (correct code)
       → failed (5 wrong attempts)
       → expired (10 minutes passed)

Status transitions

  1. pending: Initial state after calling /verify/start
  2. approved: User submitted correct code via /verify/check
  3. failed: User exceeded 5 attempts with incorrect codes
  4. expired: 10 minutes passed without successful verification

Important rules

  • Once a verification is approved, it cannot be checked again
  • Once a verification is failed (max attempts), it cannot be checked again
  • Expired verifications (10 min TTL) return NOT_FOUND
  • Each incorrect attempt increments the attempt counter
  • All 5 attempts can be used within the 10-minute window

Best practices

  1. Clear error messages: Show user-friendly errors for wrong codes
  2. Attempt counter: Display remaining attempts to the user (call /verify/status)
  3. Request new code: After max attempts or expiration, allow users to request a new code
  4. Input validation: Validate code format client-side before submitting
  5. Security: Never expose the actual verification code in your UI or logs
  6. Single verification: Once approved, don't allow re-verification of the same ID

Example flow

// 1. User enters code in your UI
const userCode = "123456";

// 2. Submit to check endpoint
const response = await fetch("https://api.tryvox.io/v1/verify/check", {
  method: "POST",
  headers: {
    "Authorization": "Bearer tvx_sk_live_...",
    "X-Tenant-ID": "acc_123",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    verification_id: "ver_abc123",
    code: userCode
  })
});

// 3. Handle response
if (response.ok) {
  const data = await response.json();
  if (data.data.status === "approved") {
    // Verification successful
    console.log("Phone verified:", data.data.to);
  }
} else {
  const error = await response.json();

  if (error.error.code === "VERIFICATION_FAILED") {
    // Wrong code - user can try again
    console.log("Incorrect code, please try again");
  } else if (error.error.code === "MAX_ATTEMPTS_EXCEEDED") {
    // Too many attempts - need new code
    console.log("Too many attempts. Requesting new code...");
  } else if (error.error.code === "NOT_FOUND") {
    // Expired or invalid
    console.log("Code expired. Requesting new code...");
  }
}

Security notes

  • Codes are compared using bcrypt timing-safe comparison
  • All verification attempts are logged for audit purposes
  • Brute force attacks are prevented by attempt limits and rate limiting
  • Verification IDs are cryptographically random and unpredictable

On this page