Check Verification Code
Verify an OTP code submitted by the user.
Endpoint
POST /v1/verify/checkHeaders
| Header | Required | Description |
|---|---|---|
| Authorization | yes | Bearer token: Bearer tvx_sk_live_... |
| X-Tenant-ID | yes | Your tenant ID: acc_... |
| Content-Type | yes | Must be application/json |
Request body
| Parameter | Type | Required | Description |
|---|---|---|---|
| verification_id | string | yes | The verification ID returned from the start endpoint |
| code | string | yes | The 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
| Field | Type | Description |
|---|---|---|
| verification_id | string | The verification ID that was checked |
| status | string | Verification status: approved |
| to | string | The phone number or email that was verified |
| channel | string | The 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
- pending: Initial state after calling
/verify/start - approved: User submitted correct code via
/verify/check - failed: User exceeded 5 attempts with incorrect codes
- 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
- Clear error messages: Show user-friendly errors for wrong codes
- Attempt counter: Display remaining attempts to the user (call
/verify/status) - Request new code: After max attempts or expiration, allow users to request a new code
- Input validation: Validate code format client-side before submitting
- Security: Never expose the actual verification code in your UI or logs
- 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