/
BulkGate developer documentation
/
OTP API
/
OTP examples
OTP examples
Examples of using the OTP API . A code is sent through send, checked through verify and, when needed, sent again through resend — all three work with the id returned by the first request.
Smallest possible request
Only the recipient number and request_quota_identification are mandatory — the identification of the requester the per-minute quota is bound to. We recommend their IP address. Without channel the code goes out over SMS.
POST /api/1.0/otp/send HTTP/1.1
Host : portal.bulkgate.com
Content-Type : application/json
{
"application_id" : 451,
"application_token" : "NKN02TWE6NfBkfl-your-secret-token-Wf05GaqLIWLW4aBj" ,
"number" : "447820125799" ,
"request_quota_identification" : "127.0.0.1"
}
Custom code format
code_type picks the characters (int, string, combined), code_length the length (4–100). language selects the message language out of 100 supported ISO codes.
POST /api/1.0/otp/send HTTP/1.1
Host : portal.bulkgate.com
Content-Type : application/json
{
"application_id" : 451,
"application_token" : "NKN02TWE6NfBkfl-your-secret-token-Wf05GaqLIWLW4aBj" ,
"number" : "447820125799" ,
"request_quota_identification" : "127.0.0.1" ,
"code_type" : "combined" ,
"code_length" : 8,
"language" : "en"
}
Autofilling the code on the web (WebOTP)
developer.mozilla.org/WebOTP_API
domain in the SMS object appends a line that lets the browser offer the code by itself. The domain must match the site where the code is entered.
POST /api/1.0/otp/send HTTP/1.1
Host : portal.bulkgate.com
Content-Type : application/json
{
"application_id" : 451,
"application_token" : "NKN02TWE6NfBkfl-your-secret-token-Wf05GaqLIWLW4aBj" ,
"number" : "447820125799" ,
"request_quota_identification" : "127.0.0.1" ,
"channel" : {
"sms" : {
"sender_id" : "gText" ,
"sender_id_value" : "BulkGate" ,
"domain" : "https://example.com"
}
}
}
Channel cascade
The order of the keys is the order of the cascade. Here Viber is tried first, after 60 seconds without delivery RCS, and SMS last. An expiration below 60 is ignored.
POST /api/1.0/otp/send HTTP/1.1
Host : portal.bulkgate.com
Content-Type : application/json
{
"application_id" : 451,
"application_token" : "NKN02TWE6NfBkfl-your-secret-token-Wf05GaqLIWLW4aBj" ,
"number" : "447820125799" ,
"request_quota_identification" : "127.0.0.1" ,
"channel" : {
"viber" : {
"sender" : "BulkGate" ,
"expiration" : 60
} ,
"rcs" : {
"sender" : "BulkGate" ,
"expiration" : 60
} ,
"sms" : {
"sender_id" : "gText" ,
"sender_id_value" : "BulkGate"
}
}
}
Code read out loud
Text2Voice reads the code. repeat says it again during the call so the recipient can write it down.
POST /api/1.0/otp/send HTTP/1.1
Host : portal.bulkgate.com
Content-Type : application/json
{
"application_id" : 451,
"application_token" : "NKN02TWE6NfBkfl-your-secret-token-Wf05GaqLIWLW4aBj" ,
"number" : "447820125799" ,
"request_quota_identification" : "127.0.0.1" ,
"code_type" : "int" ,
"code_length" : 4,
"channel" : {
"text2voice" : {
"sender" : "447820125799" ,
"language" : "en" ,
"prefer_gender" : "female" ,
"repeat" : 2
}
}
}
Limits against abuse
trials_available_* caps how many times one code can be resent and verified, daily_limit the number of requests per 24 hours. daily_limit_country additionally allows only the listed countries — any other one fails with country_is_disabled.
POST /api/1.0/otp/send HTTP/1.1
Host : portal.bulkgate.com
Content-Type : application/json
{
"application_id" : 451,
"application_token" : "NKN02TWE6NfBkfl-your-secret-token-Wf05GaqLIWLW4aBj" ,
"number" : "447820125799" ,
"request_quota_identification" : "127.0.0.1" ,
"request_quota_number" : 3,
"trials_available_resend" : 2,
"trials_available_verification" : 5,
"daily_limit" : 100,
"daily_limit_country" : {
"gb" : 100,
"ie" : 50
} ,
"expiration" : 600
}
Verifying the code
id is the value from the send response. The response returns verified; false means an invalid code, not a failed request.
POST /api/1.0/otp/verify HTTP/1.1
Host : portal.bulkgate.com
Content-Type : application/json
{
"application_id" : 451,
"application_token" : "NKN02TWE6NfBkfl-your-secret-token-Wf05GaqLIWLW4aBj" ,
"id" : "otp-65cca8b4b6a6a2.24308291" ,
"code" : "123456"
}
Resending the code
Generates a new code for the same request and sends it over the same channel. Two resends must be 60 seconds apart.
POST /api/1.0/otp/resend HTTP/1.1
Host : portal.bulkgate.com
Content-Type : application/json
{
"application_id" : 451,
"application_token" : "NKN02TWE6NfBkfl-your-secret-token-Wf05GaqLIWLW4aBj" ,
"id" : "otp-65cca8b4b6a6a2.24308291"
}
Code examples
Below is the same send request in different programming languages:
The meaning of the individual parameters is described in the specification .
PHP
php.net
$context = stream_context_create (['http' => [
'method' => 'POST' ,
'header' => 'Content-Type: application/json' ,
'content' => json_encode ([
'application_id' => 451,
'application_token' => 'NKN02TWE6NfBkfl-your-secret-token-Wf05GaqLIWLW4aBj' ,
'number' => '447820125799' ,
'request_quota_identification' => '127.0.0.1' ,
'language' => 'en' ,
'code_length' => 6,
'channel' => [
'sms' => [
'sender_id' => 'gText' ,
'sender_id_value' => 'BulkGate' ,
],
],
], JSON_THROW_ON_ERROR ),
'timeout' => 30,
'ignore_errors' => true ,
]]);
$body = file_get_contents ('https://portal.bulkgate.com/api/1.0/otp/send' , false , $context );
if ($body === false )
{
throw new RuntimeException ('BulkGate API did not respond.' );
}
$response = json_decode ($body , true , flags : JSON_THROW_ON_ERROR );
if (isset ($response ['error' ]))
{
throw new RuntimeException ("BulkGate: {$response['error']} ({$response['type']})" );
}
print_r ($response ['data' ]);
PHP cURL
php.net/curl
$curl = curl_init ();
curl_setopt_array ($curl , [
CURLOPT_URL => 'https://portal.bulkgate.com/api/1.0/otp/send' ,
CURLOPT_POST => true ,
CURLOPT_RETURNTRANSFER => true ,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTPHEADER => ['Content-Type: application/json' ],
CURLOPT_POSTFIELDS => json_encode ([
'application_id' => 451,
'application_token' => 'NKN02TWE6NfBkfl-your-secret-token-Wf05GaqLIWLW4aBj' ,
'number' => '447820125799' ,
'request_quota_identification' => '127.0.0.1' ,
'language' => 'en' ,
'code_length' => 6,
'channel' => [
'sms' => [
'sender_id' => 'gText' ,
'sender_id_value' => 'BulkGate' ,
],
],
], JSON_THROW_ON_ERROR ),
]);
$body = curl_exec ($curl );
$error = curl_error ($curl );
curl_close ($curl );
if ($error !== '' )
{
throw new RuntimeException ("BulkGate API: $error" );
}
print_r (json_decode ($body , true , flags : JSON_THROW_ON_ERROR ));
PHP Guzzle
docs.guzzlephp.org
use GuzzleHttp\Client ;
use GuzzleHttp\Exception\GuzzleException ;
$client = new Client (['timeout' => 30, 'http_errors' => false]);
try
{
$result = $client ->post ('https://portal.bulkgate.com/api/1.0/otp/send' , ['json' => [
'application_id' => 451,
'application_token' => 'NKN02TWE6NfBkfl-your-secret-token-Wf05GaqLIWLW4aBj' ,
'number' => '447820125799' ,
'request_quota_identification' => '127.0.0.1' ,
'language' => 'en' ,
'code_length' => 6,
'channel' => [
'sms' => [
'sender_id' => 'gText' ,
'sender_id_value' => 'BulkGate' ,
],
],
]]);
}
catch (GuzzleException $e )
{
throw new RuntimeException ('BulkGate: ' . $e ->getMessage (), previous : $e );
}
print_r (json_decode ((string ) $result ->getBody (), true , flags : JSON_THROW_ON_ERROR ));
Go
go.dev
package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main () {
url := "https://portal.bulkgate.com/api/1.0/otp/send"
payload := strings.NewReader (`{"application_id": 451, "application_token": "NKN02TWE6NfBkfl-your-secret-token-Wf05GaqLIWLW4aBj", "number": "447820125799", "request_quota_identification": "127.0.0.1", "language": "en", "code_length": 6, "channel": {"sms": {"sender_id": "gText", "sender_id_value": "BulkGate"}}}` )
req, _ := http.NewRequest ("POST" , url, payload)
req.Header.Add ("Content-Type" , "application/json" )
res, err := http.DefaultClient.Do (req)
if err != nil {
panic (err)
}
defer res.Body.Close ()
body, _ := io.ReadAll (res.Body)
fmt.Println (res.StatusCode, string (body))
}
Python
python.org
import requests
response = requests.post('https://portal.bulkgate.com/api/1.0/otp/send' , json = {
'application_id' : 451 ,
'application_token' : 'NKN02TWE6NfBkfl-your-secret-token-Wf05GaqLIWLW4aBj' ,
'number' : '447820125799' ,
'request_quota_identification' : '127.0.0.1' ,
'language' : 'en' ,
'code_length' : 6 ,
'channel' : {
'sms' : {
'sender_id' : 'gText' ,
'sender_id_value' : 'BulkGate' ,
},
},
}, timeout = 30 )
data = response.json()
if 'error' in data:
raise RuntimeError(f"BulkGate: {data['error']} ({data['type']})" )
print (data['data' ]['id' ])
Node.js
nodejs.org
const response = await fetch ("https://portal.bulkgate.com/api/1.0/otp/send" , {
method : "POST" ,
headers : { "Content-Type" : "application/json" },
body : JSON .stringify ({
"application_id" : 451,
"application_token" : "NKN02TWE6NfBkfl-your-secret-token-Wf05GaqLIWLW4aBj" ,
"number" : "447820125799" ,
"request_quota_identification" : "127.0.0.1" ,
"language" : "en" ,
"code_length" : 6,
"channel" : {
"sms" : {
"sender_id" : "gText" ,
"sender_id_value" : "BulkGate"
}
}
}),
});
const result = await response.json ();
if (result.error ) {
throw new Error (`BulkGate : ${result.error } (${result.type })`);
}
console.log (result.data .id );
Java
java.net.http.HttpClient
import java.net.URI ;
import java.net.http.HttpClient ;
import java.net.http.HttpRequest ;
import java.net.http.HttpResponse ;
HttpClient client = HttpClient .newHttpClient ();
HttpRequest request = HttpRequest .newBuilder ()
.uri (URI .create ("https://portal.bulkgate.com/api/1.0/otp/send" ))
.header ("Content-Type" , "application/json" )
.POST (HttpRequest .BodyPublishers .ofString ("" "
{
"application_id" : 451 ,
"application_token" : "NKN02TWE6NfBkfl-your-secret-token-Wf05GaqLIWLW4aBj" ,
"number" : "447820125799" ,
"request_quota_identification" : "127.0.0.1" ,
"language" : "en" ,
"code_length" : 6 ,
"channel" : {
"sms" : {
"sender_id" : "gText" ,
"sender_id_value" : "BulkGate"
}
}
}"" "))
.build ();
HttpResponse <String > response = client.send (request, HttpResponse .BodyHandlers .ofString ());
System .out.println (response.statusCode () + " " + response.body ());
Kotlin
kotlinlang.org
import java.net.URI
import java.net.http.HttpClient
import java.net.http.HttpRequest
import java.net.http.HttpResponse
val payload = """
{
"application_id": 451,
"application_token": "NKN02TWE6NfBkfl-your-secret-token-Wf05GaqLIWLW4aBj",
"number": "447820125799",
"request_quota_identification": "127.0.0.1",
"language": "en",
"code_length": 6,
"channel": {
"sms": {
"sender_id": "gText",
"sender_id_value": "BulkGate"
}
}
}
""" .trimIndent ()
val request = HttpRequest .newBuilder ()
.uri (URI .create ("https://portal.bulkgate.com/api/1.0/otp/send" ))
.header ("Content-Type" , "application/json" )
.POST(HttpRequest .BodyPublishers.ofString (payload))
.build ()
val response = HttpClient .newHttpClient ().send (request, HttpResponse .BodyHandlers.ofString ())
println("${response.statusCode()} ${response.body()}" )
C# .NET
learn.microsoft.com
using System .Net.Http;
using System .Text;
var payload = """
{
"application_id": 451,
"application_token": "NKN02TWE6NfBkfl-your-secret-token-Wf05GaqLIWLW4aBj",
"number": "447820125799",
"request_quota_identification": "127.0.0.1",
"language": "en",
"code_length": 6,
"channel": {
"sms": {
"sender_id": "gText",
"sender_id_value": "BulkGate"
}
}
}
""" ;
using var client = new HttpClient ();
var response = await client.PostAsync (
"https://portal.bulkgate.com/api/1.0/otp/send" ,
new StringContent (payload, Encoding .UTF8, "application/json" ));
Console .WriteLine ($"{(int) response.StatusCode} {await response.Content.ReadAsStringAsync()}" );
C++ libcurl
curl.se/libcurl
#include <curl/curl.h>
#include <iostream>
#include <string>
static size_t collect(char *data, size_t size, size_t nmemb, std::string *out)
{
out->append(data, size * nmemb);
return size * nmemb;
}
int main()
{
const std::string payload = R"json(
{
"application_id": 451,
"application_token": "NKN02TWE6NfBkfl-your-secret-token-Wf05GaqLIWLW4aBj",
"number": "447820125799",
"request_quota_identification": "127.0.0.1",
"language": "en",
"code_length": 6,
"channel": {
"sms": {
"sender_id": "gText",
"sender_id_value": "BulkGate"
}
}
}
)json" ;
CURL *curl = curl_easy_init();
if (curl == nullptr )
{
std::cerr << "curl_easy_init failed\n" ;
return 1 ;
}
curl_slist *headers = curl_slist_append(nullptr , "Content-Type: application/json" );
std::string body;
curl_easy_setopt(curl, CURLOPT_URL , "https://portal.bulkgate.com/api/1.0/otp/send" );
curl_easy_setopt(curl, CURLOPT_HTTPHEADER , headers);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS , payload.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION , collect);
curl_easy_setopt(curl, CURLOPT_WRITEDATA , &body);
const CURLcode result = curl_easy_perform(curl);
long status = 0 ;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE , &status);
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
if (result != CURLE_OK )
{
std::cerr << curl_easy_strerror(result) << "\n" ;
return 1 ;
}
std::cout << status << " " << body << "\n" ;
return 0 ;
}
Ruby
ruby-lang.org
require 'json'
require 'net/http'
uri = URI ('https://portal.bulkgate.com/api/1.0/otp/send' )
response = Net ::HTTP .post (uri, {
'application_id' => 451 ,
'application_token' => 'NKN02TWE6NfBkfl-your-secret-token-Wf05GaqLIWLW4aBj' ,
'number' => '447820125799' ,
'request_quota_identification' => '127.0.0.1' ,
'language' => 'en' ,
'code_length' => 6 ,
'channel' => {
'sms' => {
'sender_id' => 'gText' ,
'sender_id_value' => 'BulkGate'
}
}
}.to_json , 'Content-Type' => 'application/json' )
puts "#{response.code} #{response.body}"
Bash cURL
curl.se
curl --request POST \
--url https://portal.bulkgate.com/api/1 .0 /otp/send \
--header 'Content-Type: application/json' \
--data '{"application_id": 451, "application_token": "NKN02TWE6NfBkfl-your-secret-token-Wf05GaqLIWLW4aBj", "number": "447820125799", "request_quota_identification": "127.0.0.1", "language": "en", "code_length": 6, "channel": {"sms": {"sender_id": "gText", "sender_id_value": "BulkGate"}}}'
Was this page helpful?
thumb_up Yes
thumb_down No
Thank you for your feedback.