curl --request GET \
--url https://api.otpbay.com/v1/verifications/{sid} \
--header 'Authorization: Bearer <token>'const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.otpbay.com/v1/verifications/{sid}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.otpbay.com/v1/verifications/{sid}"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.otpbay.com/v1/verifications/{sid}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.otpbay.com/v1/verifications/{sid}"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.otpbay.com/v1/verifications/{sid}")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.otpbay.com/v1/verifications/{sid}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_bodyusing RestSharp;
var options = new RestClientOptions("https://api.otpbay.com/v1/verifications/{sid}");
var client = new RestClient(options);
var request = new RestRequest("");
request.AddHeader("Authorization", "Bearer <token>");
var response = await client.GetAsync(request);
Console.WriteLine("{0}", response.Content);
{
"sid": "VE6650c3a1b2c3d4e5f6a7b8c9",
"status": "pending",
"to": "+14155552671",
"channel": "sms",
"fallback_reason": "timeout",
"attempts": [
{
"channel": "telegram",
"sid": "TG6650c3a1b2c3d4e5f6a7b8d0",
"status": "sent",
"cost": "0.00",
"date_created": "2026-09-26T10:15:02.114Z"
},
{
"channel": "sms",
"sid": "SM6650c3dfb2c3d4e5f6a7b8e1",
"status": "sent",
"cost": "0.05",
"date_created": "2026-09-26T10:16:02.402Z"
}
],
"checks_left": 5,
"fee": "0.02",
"cost": "0.07",
"date_created": "2026-09-26T10:15:01.873Z",
"expires_at": "2026-09-26T10:25:01.873Z",
"approved_at": null,
"metadata": {
"user_id": "usr_1042"
}
}{
"error": {
"code": "INVALID_MESSAGE_SID",
"message": "`sid` must match VExxxxxxxxxxxxxxxxxxxxxxxx (ObjectId hex)."
}
}{
"error": {
"code": "INVALID_API_KEY",
"message": "Invalid API key."
}
}{
"error": {
"code": "IP_NOT_ALLOWED",
"message": "This IP address is not allowed for this project."
}
}{
"error": {
"code": "VERIFICATION_NOT_FOUND",
"message": "Verification was not found for this account."
}
}Get a verification
Returns the verification with every send attempt. Reading a verification also moves it forward: it falls back to SMS when due and marks it expired once expires_at passes.
curl --request GET \
--url https://api.otpbay.com/v1/verifications/{sid} \
--header 'Authorization: Bearer <token>'const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.otpbay.com/v1/verifications/{sid}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.otpbay.com/v1/verifications/{sid}"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.otpbay.com/v1/verifications/{sid}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.otpbay.com/v1/verifications/{sid}"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.otpbay.com/v1/verifications/{sid}")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.otpbay.com/v1/verifications/{sid}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_bodyusing RestSharp;
var options = new RestClientOptions("https://api.otpbay.com/v1/verifications/{sid}");
var client = new RestClient(options);
var request = new RestRequest("");
request.AddHeader("Authorization", "Bearer <token>");
var response = await client.GetAsync(request);
Console.WriteLine("{0}", response.Content);
{
"sid": "VE6650c3a1b2c3d4e5f6a7b8c9",
"status": "pending",
"to": "+14155552671",
"channel": "sms",
"fallback_reason": "timeout",
"attempts": [
{
"channel": "telegram",
"sid": "TG6650c3a1b2c3d4e5f6a7b8d0",
"status": "sent",
"cost": "0.00",
"date_created": "2026-09-26T10:15:02.114Z"
},
{
"channel": "sms",
"sid": "SM6650c3dfb2c3d4e5f6a7b8e1",
"status": "sent",
"cost": "0.05",
"date_created": "2026-09-26T10:16:02.402Z"
}
],
"checks_left": 5,
"fee": "0.02",
"cost": "0.07",
"date_created": "2026-09-26T10:15:01.873Z",
"expires_at": "2026-09-26T10:25:01.873Z",
"approved_at": null,
"metadata": {
"user_id": "usr_1042"
}
}{
"error": {
"code": "INVALID_MESSAGE_SID",
"message": "`sid` must match VExxxxxxxxxxxxxxxxxxxxxxxx (ObjectId hex)."
}
}{
"error": {
"code": "INVALID_API_KEY",
"message": "Invalid API key."
}
}{
"error": {
"code": "IP_NOT_ALLOWED",
"message": "This IP address is not allowed for this project."
}
}{
"error": {
"code": "VERIFICATION_NOT_FOUND",
"message": "Verification was not found for this account."
}
}Authorizations
Your project API key, sent as Authorization: Bearer otp_live_.... Create keys on the API Keys page of the dashboard.
Path Parameters
The verification sid returned by Start a verification.
^VE[a-fA-F0-9]{24}$"VE6650c3a1b2c3d4e5f6a7b8c9"
Response
The verification.
Unique verification ID.
^VE[a-f0-9]{24}$"VE6650c3a1b2c3d4e5f6a7b8c9"
pending until the user enters the right code (approved), the code expires (expired), or the code can't be sent or too many wrong codes are entered (failed).
pending, approved, expired, failed Destination phone number in international format. OTPBay normalizes it to E.164, so +1 (415) 555-2671 becomes +14155552671.
"+14155552671"
Channel the code was last sent on.
telegram, sms Why the code was re-sent by SMS, or null if it wasn't.
telegram_failed, timeout, null Every send of the code, oldest first.
Hide child attributes
Hide child attributes
Channel this attempt was sent on.
telegram, sms sid of the underlying message: TG… for Telegram, SM… for SMS.
"TG6650c3a1b2c3d4e5f6a7b8d0"
Delivery status of the message. Telegram: sending, sent, delivered, read, expired, revoked, failed. SMS: queued, processing, sent, failed, enqueue_failed.
"sent"
Amount in US dollars as a decimal string.
^\d+\.\d{2}$"0.02"
Wrong codes the user can still enter before the verification fails.
5
Amount in US dollars as a decimal string.
^\d+\.\d{2}$"0.02"
Verify fee plus what the channel sends currently cost. Refunded sends count as 0.00.
^\d+\.\d{2}$"0.04"
When the code stops being accepted.
When the right code was entered.
Why the verification failed. Only present when status is failed.
"Too many wrong codes."