CodeSMS

API Documentation

REST API v1 and SMS-Activate compatible endpoints

Sign up free

Introduction

The API lets you buy virtual numbers with your account balance, read incoming SMS codes and cancel for a refund. All requests use HTTPS; responses are JSON.

There is no minimum balance requirement. If your balance covers the number price the purchase works; otherwise the API returns NO_BALANCE.
Base URL
https://codesms.org
Format
JSON (application/json) — form-encoded is accepted too
Currency
TRY (₺)
Successful response
{"success": true, "data": ...}
Error response
{"success": false, "error": {"code": "NO_BALANCE", "message": "..."}}

Authentication

Send your API key with every request. You can get the key on the API page in your panel.

curl "https://codesms.org/api/v1/balance" \
  -H "X-API-Key: YOUR_API_KEY"
$ch = curl_init('https://codesms.org/api/v1/balance');
curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ['X-API-Key: YOUR_API_KEY']]);
requests.get("https://codesms.org/api/v1/balance", headers={"X-API-Key": "YOUR_API_KEY"})
fetch("https://codesms.org/api/v1/balance", { headers: { "X-API-Key": "YOUR_API_KEY" } })

Alternatives: the Authorization: Bearer YOUR_API_KEY header or the ?api_key=YOUR_API_KEY query parameter (for testing only; the key may end up in logs).

  • The API does not work on accounts with an unverified e-mail (EMAIL_NOT_VERIFIED).
  • You can define an allowed IP list in the panel; if the list is set, requests are accepted only from those addresses.
  • If your key leaks, regenerate it in the panel right away; the old key becomes invalid instantly.

Quick start

Buy a number → wait for the code → finish. If no code arrives, cancel to get a refund.

<?php
$base = 'https://codesms.org';
$key  = 'YOUR_API_KEY';

function api($method, $path, $body = null) {
    global $base, $key;
    $ch = curl_init($base . $path);
    curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true, CURLOPT_CUSTOMREQUEST => $method,
        CURLOPT_HTTPHEADER => ['X-API-Key: ' . $key, 'Content-Type: application/json'],
        CURLOPT_POSTFIELDS => $body ? json_encode($body) : null]);
    return json_decode(curl_exec($ch), true);
}

$r = api('POST', '/api/v1/activations', ['service' => 'tg', 'country' => 'tr']);
if (!$r['success']) { exit('Hata: ' . $r['error']['code']); }
$id = $r['data']['id'];
echo "Numara: {$r['data']['phone']}\n";

for ($i = 0; $i < 120; $i++) {          // en fazla ~6 dk
    sleep(3);
    $s = api('GET', "/api/v1/activations/$id")['data'];
    if ($s['status'] === 'received') { echo "Kod: {$s['code']}\n"; api('POST', "/api/v1/activations/$id/finish"); exit; }
    if (in_array($s['status'], ['canceled', 'expired', 'failed'])) exit("Bitti: {$s['status']}\n");
}
api('POST', "/api/v1/activations/$id/cancel");   // kod gelmedi: iptal et, ücret iade
import time, requests

BASE = "https://codesms.org"
HEAD = {"X-API-Key": "YOUR_API_KEY"}

r = requests.post(f"{BASE}/api/v1/activations", headers=HEAD, json={"service": "tg", "country": "tr"}).json()
if not r["success"]:
    raise SystemExit(f"Hata: {r['error']['code']}")
act = r["data"]
print("Numara:", act["phone"])

for _ in range(120):                       # en fazla ~6 dk
    time.sleep(3)
    s = requests.get(f"{BASE}/api/v1/activations/{act['id']}", headers=HEAD).json()["data"]
    if s["status"] == "received":
        print("Kod:", s["code"])
        requests.post(f"{BASE}/api/v1/activations/{act['id']}/finish", headers=HEAD)
        break
    if s["status"] in ("canceled", "expired", "failed"):
        break
else:
    requests.post(f"{BASE}/api/v1/activations/{act['id']}/cancel", headers=HEAD)   # ücret iade
const BASE = "https://codesms.org";
const HEAD = { "X-API-Key": "YOUR_API_KEY", "Content-Type": "application/json" };
const api = (method, path, body) => fetch(BASE + path, { method, headers: HEAD, body: body && JSON.stringify(body) }).then(r => r.json());

const r = await api("POST", "/api/v1/activations", { service: "tg", country: "tr" });
if (!r.success) throw new Error(r.error.code);
const { id, phone } = r.data;
console.log("Numara:", phone);

for (let i = 0; i < 120; i++) {              // en fazla ~6 dk
  await new Promise(res => setTimeout(res, 3000));
  const s = (await api("GET", `/api/v1/activations/${id}`)).data;
  if (s.status === "received") { console.log("Kod:", s.code); await api("POST", `/api/v1/activations/${id}/finish`); process.exit(0); }
  if (["canceled", "expired", "failed"].includes(s.status)) process.exit(1);
}
await api("POST", `/api/v1/activations/${id}/cancel`);   // ücret iade

Activation lifecycle

statusMeaningPossible actions
waitingNumber issued, waiting for SMS.Poll, cancel (if can_cancel=true).
receivedSMS arrived; in the code field.Use the code, finish; request another SMS if can_retry=true.
completedCompleted (code used).—
canceledCanceled, refunded.—
expiredTime expired, no SMS; refunded.—
failedCould not get a number; refunded.—

The availability of cancel, another SMS and finish depends on the provider: check the can_cancel, can_retry and can_finish fields in the response. If cancel_in > 0 you must wait that many seconds before canceling.

Get balance

GET/api/v1/balance

Returns the current balance of your account.

Request
curl "https://codesms.org/api/v1/balance" \
  -H "X-API-Key: YOUR_API_KEY"
$ch = curl_init('https://codesms.org/api/v1/balance');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ['X-API-Key: YOUR_API_KEY'],
]);
$response = json_decode(curl_exec($ch), true);
print_r($response);
import requests

response = requests.get(
    "https://codesms.org/api/v1/balance",
    headers={"X-API-Key": "YOUR_API_KEY"}
)
print(response.json())
const response = await fetch("https://codesms.org/api/v1/balance", {
  method: "GET",
  headers: {
    "X-API-Key": "YOUR_API_KEY"
  }
});
console.log(await response.json());
package main

import (
    "fmt"
    "io"
    "net/http"
)

func main() {
    req, _ := http.NewRequest("GET", "https://codesms.org/api/v1/balance", nil)
    req.Header.Set("X-API-Key", "YOUR_API_KEY")
    resp, err := http.DefaultClient.Do(req)
    if err != nil { panic(err) }
    defer resp.Body.Close()
    body, _ := io.ReadAll(resp.Body)
    fmt.Println(string(body))
}
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", "YOUR_API_KEY");
var response = await client.GetAsync("https://codesms.org/api/v1/balance");
Console.WriteLine(await response.Content.ReadAsStringAsync());
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://codesms.org/api/v1/balance"))
    .header("X-API-Key", "YOUR_API_KEY")
    .GET()
    .build();
HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
require 'net/http'
require 'json'

uri = URI("https://codesms.org/api/v1/balance")
req = Net::HTTP::Get.new(uri)
req['X-API-Key'] = 'YOUR_API_KEY'
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') { |http| http.request(req) }
puts res.body
Response 200
{
    "success": true,
    "data": {
        "balance": 125.5,
        "currency": "TRY"
    }
}

List services

GET/api/v1/services

Services that have numbers in stock, with the lowest price (your tier discount applied) and total stock.

Request
curl "https://codesms.org/api/v1/services" \
  -H "X-API-Key: YOUR_API_KEY"
$ch = curl_init('https://codesms.org/api/v1/services');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ['X-API-Key: YOUR_API_KEY'],
]);
$response = json_decode(curl_exec($ch), true);
print_r($response);
import requests

response = requests.get(
    "https://codesms.org/api/v1/services",
    headers={"X-API-Key": "YOUR_API_KEY"}
)
print(response.json())
const response = await fetch("https://codesms.org/api/v1/services", {
  method: "GET",
  headers: {
    "X-API-Key": "YOUR_API_KEY"
  }
});
console.log(await response.json());
package main

import (
    "fmt"
    "io"
    "net/http"
)

func main() {
    req, _ := http.NewRequest("GET", "https://codesms.org/api/v1/services", nil)
    req.Header.Set("X-API-Key", "YOUR_API_KEY")
    resp, err := http.DefaultClient.Do(req)
    if err != nil { panic(err) }
    defer resp.Body.Close()
    body, _ := io.ReadAll(resp.Body)
    fmt.Println(string(body))
}
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", "YOUR_API_KEY");
var response = await client.GetAsync("https://codesms.org/api/v1/services");
Console.WriteLine(await response.Content.ReadAsStringAsync());
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://codesms.org/api/v1/services"))
    .header("X-API-Key", "YOUR_API_KEY")
    .GET()
    .build();
HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
require 'net/http'
require 'json'

uri = URI("https://codesms.org/api/v1/services")
req = Net::HTTP::Get.new(uri)
req['X-API-Key'] = 'YOUR_API_KEY'
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') { |http| http.request(req) }
puts res.body
Response 200
{
    "success": true,
    "data": [
        {
            "code": "tg",
            "slug": "telegram",
            "name": "Telegram",
            "min_price": 2.1,
            "stock": 18540
        }
    ]
}

List countries

GET/api/v1/countries

Countries that have numbers in stock. "id" is the SMS-Activate compatible numeric country code.

Request
curl "https://codesms.org/api/v1/countries" \
  -H "X-API-Key: YOUR_API_KEY"
$ch = curl_init('https://codesms.org/api/v1/countries');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ['X-API-Key: YOUR_API_KEY'],
]);
$response = json_decode(curl_exec($ch), true);
print_r($response);
import requests

response = requests.get(
    "https://codesms.org/api/v1/countries",
    headers={"X-API-Key": "YOUR_API_KEY"}
)
print(response.json())
const response = await fetch("https://codesms.org/api/v1/countries", {
  method: "GET",
  headers: {
    "X-API-Key": "YOUR_API_KEY"
  }
});
console.log(await response.json());
package main

import (
    "fmt"
    "io"
    "net/http"
)

func main() {
    req, _ := http.NewRequest("GET", "https://codesms.org/api/v1/countries", nil)
    req.Header.Set("X-API-Key", "YOUR_API_KEY")
    resp, err := http.DefaultClient.Do(req)
    if err != nil { panic(err) }
    defer resp.Body.Close()
    body, _ := io.ReadAll(resp.Body)
    fmt.Println(string(body))
}
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", "YOUR_API_KEY");
var response = await client.GetAsync("https://codesms.org/api/v1/countries");
Console.WriteLine(await response.Content.ReadAsStringAsync());
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://codesms.org/api/v1/countries"))
    .header("X-API-Key", "YOUR_API_KEY")
    .GET()
    .build();
HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
require 'net/http'
require 'json'

uri = URI("https://codesms.org/api/v1/countries")
req = Net::HTTP::Get.new(uri)
req['X-API-Key'] = 'YOUR_API_KEY'
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') { |http| http.request(req) }
puts res.body
Response 200
{
    "success": true,
    "data": [
        {
            "iso": "tr",
            "id": 62,
            "name": "Turkey",
            "name_tr": "Türkiye",
            "dial": "90"
        }
    ]
}

Price and stock

GET/api/v1/prices

Current price and stock per service/country. An unfiltered call returns the whole list (up to 20,000 rows).

ParameterTypeDescription
servicestringoptionalService code or slug (e.g. tg).
countrystringoptionalCountry ISO code (tr) or numeric ID (62).
Request
curl "https://codesms.org/api/v1/prices?service=tg&country=tr" \
  -H "X-API-Key: YOUR_API_KEY"
$ch = curl_init('https://codesms.org/api/v1/prices?service=tg&country=tr');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ['X-API-Key: YOUR_API_KEY'],
]);
$response = json_decode(curl_exec($ch), true);
print_r($response);
import requests

response = requests.get(
    "https://codesms.org/api/v1/prices?service=tg&country=tr",
    headers={"X-API-Key": "YOUR_API_KEY"}
)
print(response.json())
const response = await fetch("https://codesms.org/api/v1/prices?service=tg&country=tr", {
  method: "GET",
  headers: {
    "X-API-Key": "YOUR_API_KEY"
  }
});
console.log(await response.json());
package main

import (
    "fmt"
    "io"
    "net/http"
)

func main() {
    req, _ := http.NewRequest("GET", "https://codesms.org/api/v1/prices?service=tg&country=tr", nil)
    req.Header.Set("X-API-Key", "YOUR_API_KEY")
    resp, err := http.DefaultClient.Do(req)
    if err != nil { panic(err) }
    defer resp.Body.Close()
    body, _ := io.ReadAll(resp.Body)
    fmt.Println(string(body))
}
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", "YOUR_API_KEY");
var response = await client.GetAsync("https://codesms.org/api/v1/prices?service=tg&country=tr");
Console.WriteLine(await response.Content.ReadAsStringAsync());
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://codesms.org/api/v1/prices?service=tg&country=tr"))
    .header("X-API-Key", "YOUR_API_KEY")
    .GET()
    .build();
HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
require 'net/http'
require 'json'

uri = URI("https://codesms.org/api/v1/prices?service=tg&country=tr")
req = Net::HTTP::Get.new(uri)
req['X-API-Key'] = 'YOUR_API_KEY'
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') { |http| http.request(req) }
puts res.body
Response 200
{
    "success": true,
    "data": [
        {
            "service": "tg",
            "country": "tr",
            "price": 8.5,
            "currency": "TRY",
            "stock": 420
        }
    ]
}

Buy a number

POST/api/v1/activations

Opens a new activation (number), deducting from your balance. Returns NO_BALANCE if the balance is insufficient, NO_NUMBERS if there is no stock. If no SMS arrives or you cancel, the fee is refunded automatically. Recommended: send a unique Idempotency-Key header with every purchase; if you retry with the same key after a network error, no second number is bought and the first activation is returned (valid for 24 hours).

ParameterTypeDescription
servicestringrequiredService code or slug (e.g. tg).
countrystringrequiredCountry ISO code (tr) or numeric ID (62).
Request
curl -X POST "https://codesms.org/api/v1/activations" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"service":"tg","country":"tr"}'
$ch = curl_init('https://codesms.org/api/v1/activations');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ['X-API-Key: YOUR_API_KEY', 'Content-Type: application/json'],
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => json_encode(['service' => 'tg', 'country' => 'tr']),
]);
$response = json_decode(curl_exec($ch), true);
print_r($response);
import requests

response = requests.post(
    "https://codesms.org/api/v1/activations",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"service": "tg", "country": "tr"}
)
print(response.json())
const response = await fetch("https://codesms.org/api/v1/activations", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({"service":"tg","country":"tr"})
});
console.log(await response.json());
package main

import (
    "bytes"
    "fmt"
    "io"
    "net/http"
)

func main() {
    req, _ := http.NewRequest("POST", "https://codesms.org/api/v1/activations", bytes.NewBufferString(`{"service":"tg","country":"tr"}`))
    req.Header.Set("Content-Type", "application/json")
    req.Header.Set("X-API-Key", "YOUR_API_KEY")
    resp, err := http.DefaultClient.Do(req)
    if err != nil { panic(err) }
    defer resp.Body.Close()
    body, _ := io.ReadAll(resp.Body)
    fmt.Println(string(body))
}
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", "YOUR_API_KEY");
var response = await client.PostAsync("https://codesms.org/api/v1/activations", new StringContent("{\"service\":\"tg\",\"country\":\"tr\"}", System.Text.Encoding.UTF8, "application/json"));
Console.WriteLine(await response.Content.ReadAsStringAsync());
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://codesms.org/api/v1/activations"))
    .header("X-API-Key", "YOUR_API_KEY")
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString("{\"service\":\"tg\",\"country\":\"tr\"}"))
    .build();
HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
require 'net/http'
require 'json'

uri = URI("https://codesms.org/api/v1/activations")
req = Net::HTTP::Post.new(uri)
req['X-API-Key'] = 'YOUR_API_KEY'
req['Content-Type'] = 'application/json'
req.body = '{"service":"tg","country":"tr"}'
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') { |http| http.request(req) }
puts res.body
Response 201
{
    "success": true,
    "data": {
        "id": 1234,
        "status": "waiting",
        "phone": "+905551234567",
        "code": null,
        "text": null,
        "service": {
            "code": "tg",
            "name": "Telegram"
        },
        "country": {
            "iso": "tr",
            "name": "Turkey",
            "dial": "90"
        },
        "price": 8.5,
        "currency": "TRY",
        "created_at": "2026-01-15T10:00:00+03:00",
        "expires_at": "2026-01-15T10:20:00+03:00",
        "retry_count": 0,
        "can_cancel": true,
        "can_retry": false,
        "can_finish": false,
        "cancel_in": 0
    }
}

Activation status / SMS code

GET/api/v1/activations/1234

Returns the activation status and the SMS code if it arrived. Poll every 3–5 seconds until the code arrives (not needed if you use webhooks).

ParameterTypeDescription
idintegerrequiredActivation ID (path parameter).
Request
curl "https://codesms.org/api/v1/activations/1234" \
  -H "X-API-Key: YOUR_API_KEY"
$ch = curl_init('https://codesms.org/api/v1/activations/1234');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ['X-API-Key: YOUR_API_KEY'],
]);
$response = json_decode(curl_exec($ch), true);
print_r($response);
import requests

response = requests.get(
    "https://codesms.org/api/v1/activations/1234",
    headers={"X-API-Key": "YOUR_API_KEY"}
)
print(response.json())
const response = await fetch("https://codesms.org/api/v1/activations/1234", {
  method: "GET",
  headers: {
    "X-API-Key": "YOUR_API_KEY"
  }
});
console.log(await response.json());
package main

import (
    "fmt"
    "io"
    "net/http"
)

func main() {
    req, _ := http.NewRequest("GET", "https://codesms.org/api/v1/activations/1234", nil)
    req.Header.Set("X-API-Key", "YOUR_API_KEY")
    resp, err := http.DefaultClient.Do(req)
    if err != nil { panic(err) }
    defer resp.Body.Close()
    body, _ := io.ReadAll(resp.Body)
    fmt.Println(string(body))
}
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", "YOUR_API_KEY");
var response = await client.GetAsync("https://codesms.org/api/v1/activations/1234");
Console.WriteLine(await response.Content.ReadAsStringAsync());
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://codesms.org/api/v1/activations/1234"))
    .header("X-API-Key", "YOUR_API_KEY")
    .GET()
    .build();
HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
require 'net/http'
require 'json'

uri = URI("https://codesms.org/api/v1/activations/1234")
req = Net::HTTP::Get.new(uri)
req['X-API-Key'] = 'YOUR_API_KEY'
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') { |http| http.request(req) }
puts res.body
Response 200
{
    "success": true,
    "data": {
        "status": "received",
        "code": "482913",
        "text": "Your Telegram code: 482913",
        "can_cancel": false,
        "can_retry": true,
        "can_finish": true,
        "id": 1234,
        "phone": "+905551234567",
        "service": {
            "code": "tg",
            "name": "Telegram"
        },
        "country": {
            "iso": "tr",
            "name": "Turkey",
            "dial": "90"
        },
        "price": 8.5,
        "currency": "TRY",
        "created_at": "2026-01-15T10:00:00+03:00",
        "expires_at": "2026-01-15T10:20:00+03:00",
        "retry_count": 0,
        "cancel_in": 0
    }
}

List activations

GET/api/v1/activations

Your latest activations (newest first).

ParameterTypeDescription
statusstringoptionalwaiting, received, completed, canceled, expired, failed
limitintegeroptional1–100 (default 30).
Request
curl "https://codesms.org/api/v1/activations?status=waiting&limit=20" \
  -H "X-API-Key: YOUR_API_KEY"
$ch = curl_init('https://codesms.org/api/v1/activations?status=waiting&limit=20');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ['X-API-Key: YOUR_API_KEY'],
]);
$response = json_decode(curl_exec($ch), true);
print_r($response);
import requests

response = requests.get(
    "https://codesms.org/api/v1/activations?status=waiting&limit=20",
    headers={"X-API-Key": "YOUR_API_KEY"}
)
print(response.json())
const response = await fetch("https://codesms.org/api/v1/activations?status=waiting&limit=20", {
  method: "GET",
  headers: {
    "X-API-Key": "YOUR_API_KEY"
  }
});
console.log(await response.json());
package main

import (
    "fmt"
    "io"
    "net/http"
)

func main() {
    req, _ := http.NewRequest("GET", "https://codesms.org/api/v1/activations?status=waiting&limit=20", nil)
    req.Header.Set("X-API-Key", "YOUR_API_KEY")
    resp, err := http.DefaultClient.Do(req)
    if err != nil { panic(err) }
    defer resp.Body.Close()
    body, _ := io.ReadAll(resp.Body)
    fmt.Println(string(body))
}
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", "YOUR_API_KEY");
var response = await client.GetAsync("https://codesms.org/api/v1/activations?status=waiting&limit=20");
Console.WriteLine(await response.Content.ReadAsStringAsync());
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://codesms.org/api/v1/activations?status=waiting&limit=20"))
    .header("X-API-Key", "YOUR_API_KEY")
    .GET()
    .build();
HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
require 'net/http'
require 'json'

uri = URI("https://codesms.org/api/v1/activations?status=waiting&limit=20")
req = Net::HTTP::Get.new(uri)
req['X-API-Key'] = 'YOUR_API_KEY'
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') { |http| http.request(req) }
puts res.body
Response 200
{
    "success": true,
    "data": [
        {
            "id": 1234,
            "status": "waiting",
            "phone": "+905551234567",
            "code": null,
            "text": null,
            "service": {
                "code": "tg",
                "name": "Telegram"
            },
            "country": {
                "iso": "tr",
                "name": "Turkey",
                "dial": "90"
            },
            "price": 8.5,
            "currency": "TRY",
            "created_at": "2026-01-15T10:00:00+03:00",
            "expires_at": "2026-01-15T10:20:00+03:00",
            "retry_count": 0,
            "can_cancel": true,
            "can_retry": false,
            "can_finish": false,
            "cancel_in": 0
        }
    ]
}

Cancel and get a refund

POST/api/v1/activations/1234/cancel

If no code arrived, cancels the activation and refunds the fee to your balance. Some providers do not allow cancellation in the first seconds (CANCEL_TOO_EARLY is returned while cancel_in > 0). If the provider does not support it, can_cancel=false.

ParameterTypeDescription
idintegerrequiredActivation ID (path parameter).
Request
curl -X POST "https://codesms.org/api/v1/activations/1234/cancel" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
$ch = curl_init('https://codesms.org/api/v1/activations/1234/cancel');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ['X-API-Key: YOUR_API_KEY', 'Content-Type: application/json'],
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => json_encode([]),
]);
$response = json_decode(curl_exec($ch), true);
print_r($response);
import requests

response = requests.post(
    "https://codesms.org/api/v1/activations/1234/cancel",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={}
)
print(response.json())
const response = await fetch("https://codesms.org/api/v1/activations/1234/cancel", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({})
});
console.log(await response.json());
package main

import (
    "bytes"
    "fmt"
    "io"
    "net/http"
)

func main() {
    req, _ := http.NewRequest("POST", "https://codesms.org/api/v1/activations/1234/cancel", bytes.NewBufferString(`{}`))
    req.Header.Set("Content-Type", "application/json")
    req.Header.Set("X-API-Key", "YOUR_API_KEY")
    resp, err := http.DefaultClient.Do(req)
    if err != nil { panic(err) }
    defer resp.Body.Close()
    body, _ := io.ReadAll(resp.Body)
    fmt.Println(string(body))
}
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", "YOUR_API_KEY");
var response = await client.PostAsync("https://codesms.org/api/v1/activations/1234/cancel", new StringContent("{}", System.Text.Encoding.UTF8, "application/json"));
Console.WriteLine(await response.Content.ReadAsStringAsync());
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://codesms.org/api/v1/activations/1234/cancel"))
    .header("X-API-Key", "YOUR_API_KEY")
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString("{}"))
    .build();
HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
require 'net/http'
require 'json'

uri = URI("https://codesms.org/api/v1/activations/1234/cancel")
req = Net::HTTP::Post.new(uri)
req['X-API-Key'] = 'YOUR_API_KEY'
req['Content-Type'] = 'application/json'
req.body = '{}'
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') { |http| http.request(req) }
puts res.body
Response 200
{
    "success": true,
    "data": {
        "status": "canceled",
        "can_cancel": false,
        "id": 1234,
        "phone": "+905551234567",
        "code": null,
        "text": null,
        "service": {
            "code": "tg",
            "name": "Telegram"
        },
        "country": {
            "iso": "tr",
            "name": "Turkey",
            "dial": "90"
        },
        "price": 8.5,
        "currency": "TRY",
        "created_at": "2026-01-15T10:00:00+03:00",
        "expires_at": "2026-01-15T10:20:00+03:00",
        "retry_count": 0,
        "can_retry": false,
        "can_finish": false,
        "cancel_in": 0
    }
}

Request another SMS

POST/api/v1/activations/1234/retry

Requests a new SMS to the same number after a code arrived (only when can_retry=true). The activation goes back to "waiting".

ParameterTypeDescription
idintegerrequiredActivation ID (path parameter).
Request
curl -X POST "https://codesms.org/api/v1/activations/1234/retry" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
$ch = curl_init('https://codesms.org/api/v1/activations/1234/retry');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ['X-API-Key: YOUR_API_KEY', 'Content-Type: application/json'],
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => json_encode([]),
]);
$response = json_decode(curl_exec($ch), true);
print_r($response);
import requests

response = requests.post(
    "https://codesms.org/api/v1/activations/1234/retry",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={}
)
print(response.json())
const response = await fetch("https://codesms.org/api/v1/activations/1234/retry", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({})
});
console.log(await response.json());
package main

import (
    "bytes"
    "fmt"
    "io"
    "net/http"
)

func main() {
    req, _ := http.NewRequest("POST", "https://codesms.org/api/v1/activations/1234/retry", bytes.NewBufferString(`{}`))
    req.Header.Set("Content-Type", "application/json")
    req.Header.Set("X-API-Key", "YOUR_API_KEY")
    resp, err := http.DefaultClient.Do(req)
    if err != nil { panic(err) }
    defer resp.Body.Close()
    body, _ := io.ReadAll(resp.Body)
    fmt.Println(string(body))
}
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", "YOUR_API_KEY");
var response = await client.PostAsync("https://codesms.org/api/v1/activations/1234/retry", new StringContent("{}", System.Text.Encoding.UTF8, "application/json"));
Console.WriteLine(await response.Content.ReadAsStringAsync());
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://codesms.org/api/v1/activations/1234/retry"))
    .header("X-API-Key", "YOUR_API_KEY")
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString("{}"))
    .build();
HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
require 'net/http'
require 'json'

uri = URI("https://codesms.org/api/v1/activations/1234/retry")
req = Net::HTTP::Post.new(uri)
req['X-API-Key'] = 'YOUR_API_KEY'
req['Content-Type'] = 'application/json'
req.body = '{}'
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') { |http| http.request(req) }
puts res.body
Response 200
{
    "success": true,
    "data": {
        "retry_count": 1,
        "id": 1234,
        "status": "waiting",
        "phone": "+905551234567",
        "code": null,
        "text": null,
        "service": {
            "code": "tg",
            "name": "Telegram"
        },
        "country": {
            "iso": "tr",
            "name": "Turkey",
            "dial": "90"
        },
        "price": 8.5,
        "currency": "TRY",
        "created_at": "2026-01-15T10:00:00+03:00",
        "expires_at": "2026-01-15T10:20:00+03:00",
        "can_cancel": true,
        "can_retry": false,
        "can_finish": false,
        "cancel_in": 0
    }
}

Finish

POST/api/v1/activations/1234/finish

Reports that you used the code successfully and closes the activation. Activations not finished within 15 minutes are finished automatically.

ParameterTypeDescription
idintegerrequiredActivation ID (path parameter).
Request
curl -X POST "https://codesms.org/api/v1/activations/1234/finish" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
$ch = curl_init('https://codesms.org/api/v1/activations/1234/finish');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ['X-API-Key: YOUR_API_KEY', 'Content-Type: application/json'],
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => json_encode([]),
]);
$response = json_decode(curl_exec($ch), true);
print_r($response);
import requests

response = requests.post(
    "https://codesms.org/api/v1/activations/1234/finish",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={}
)
print(response.json())
const response = await fetch("https://codesms.org/api/v1/activations/1234/finish", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({})
});
console.log(await response.json());
package main

import (
    "bytes"
    "fmt"
    "io"
    "net/http"
)

func main() {
    req, _ := http.NewRequest("POST", "https://codesms.org/api/v1/activations/1234/finish", bytes.NewBufferString(`{}`))
    req.Header.Set("Content-Type", "application/json")
    req.Header.Set("X-API-Key", "YOUR_API_KEY")
    resp, err := http.DefaultClient.Do(req)
    if err != nil { panic(err) }
    defer resp.Body.Close()
    body, _ := io.ReadAll(resp.Body)
    fmt.Println(string(body))
}
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", "YOUR_API_KEY");
var response = await client.PostAsync("https://codesms.org/api/v1/activations/1234/finish", new StringContent("{}", System.Text.Encoding.UTF8, "application/json"));
Console.WriteLine(await response.Content.ReadAsStringAsync());
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://codesms.org/api/v1/activations/1234/finish"))
    .header("X-API-Key", "YOUR_API_KEY")
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString("{}"))
    .build();
HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
require 'net/http'
require 'json'

uri = URI("https://codesms.org/api/v1/activations/1234/finish")
req = Net::HTTP::Post.new(uri)
req['X-API-Key'] = 'YOUR_API_KEY'
req['Content-Type'] = 'application/json'
req.body = '{}'
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') { |http| http.request(req) }
puts res.body
Response 200
{
    "success": true,
    "data": {
        "status": "completed",
        "code": "482913",
        "text": "Your Telegram code: 482913",
        "can_cancel": false,
        "can_retry": true,
        "can_finish": true,
        "id": 1234,
        "phone": "+905551234567",
        "service": {
            "code": "tg",
            "name": "Telegram"
        },
        "country": {
            "iso": "tr",
            "name": "Turkey",
            "dial": "90"
        },
        "price": 8.5,
        "currency": "TRY",
        "created_at": "2026-01-15T10:00:00+03:00",
        "expires_at": "2026-01-15T10:20:00+03:00",
        "retry_count": 0,
        "cancel_in": 0
    }
}

Webhook

If you set a webhook URL in the panel, we send a signed POST request to it when the SMS code arrives; no need to poll constantly. On non-2xx responses it is retried after 1 min, 5 min, 15 min, 1 h and 6 h.

Headers
X-SMSOnay-Event
activation.code
X-SMSOnay-Timestamp
Unix seconds
X-SMSOnay-Signature
sha256=HMAC_SHA256(secret, timestamp + "." + body)
Body
{
    "event": "activation.code",
    "activation": {
        "id": 1234,
        "status": "received",
        "phone": "+905551234567",
        "code": "482913",
        "service": {
            "code": "tg"
        },
        "...": "..."
    },
    "timestamp": 1768460000
}
Signature verification
# HMAC-SHA256(secret, timestamp + "." + rawBody) -> "sha256=" + hex
# Header'lar: X-SMSOnay-Timestamp, X-SMSOnay-Signature
$ts   = $_SERVER['HTTP_X_SMSONAY_TIMESTAMP'];
$sig  = $_SERVER['HTTP_X_SMSONAY_SIGNATURE'];
$body = file_get_contents('php://input');
$calc = 'sha256=' . hash_hmac('sha256', $ts . '.' . $body, 'whsec_YOUR_SECRET');
if (!hash_equals($calc, $sig) || abs(time() - (int)$ts) > 300) { http_response_code(401); exit; }
$event = json_decode($body, true);
import hmac, hashlib, time

def verify(ts, signature, body: bytes, secret: str) -> bool:
    calc = 'sha256=' + hmac.new(secret.encode(), ts.encode() + b'.' + body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(calc, signature) and abs(time.time() - int(ts)) < 300
const crypto = require('crypto');

function verify(ts, signature, rawBody, secret) {
  const calc = 'sha256=' + crypto.createHmac('sha256', secret).update(ts + '.' + rawBody).digest('hex');
  return crypto.timingSafeEqual(Buffer.from(calc), Buffer.from(signature)) && Math.abs(Date.now() / 1000 - Number(ts)) < 300;
}
func verify(ts, signature string, body []byte, secret string) bool {
    mac := hmac.New(sha256.New, []byte(secret))
    mac.Write([]byte(ts + "."))
    mac.Write(body)
    calc := "sha256=" + hex.EncodeToString(mac.Sum(nil))
    return hmac.Equal([]byte(calc), []byte(signature))
}
static bool Verify(string ts, string signature, string body, string secret)
{
    using var h = new HMACSHA256(Encoding.UTF8.GetBytes(secret));
    var calc = "sha256=" + Convert.ToHexString(h.ComputeHash(Encoding.UTF8.GetBytes(ts + "." + body))).ToLower();
    return CryptographicOperations.FixedTimeEquals(Encoding.UTF8.GetBytes(calc), Encoding.UTF8.GetBytes(signature));
}
static boolean verify(String ts, String signature, String body, String secret) throws Exception {
    Mac mac = Mac.getInstance("HmacSHA256");
    mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
    String calc = "sha256=" + HexFormat.of().formatHex(mac.doFinal((ts + "." + body).getBytes(StandardCharsets.UTF_8)));
    return MessageDigest.isEqual(calc.getBytes(), signature.getBytes());
}
require 'openssl'

def verify(ts, signature, body, secret)
  calc = 'sha256=' + OpenSSL::HMAC.hexdigest('SHA256', secret, "#{ts}.#{body}")
  Rack::Utils.secure_compare(calc, signature)
end

You can get your signing secret on the API page in the panel. Verify the timestamp (±5 min) and the signature; de-duplicate repeated deliveries for the same activation by id.

SMS-Activate compatible API

If your existing registration/automation software supports the SMS-Activate (handler_api) protocol, you can connect to us just by changing the server address and API key.

GEThttps://codesms.org/stubs/handler_api.php?api_key=YOUR_API_KEY&action=...
  • service: service code (tg, wa, ig, go, fb …) — the code from GET /api/v1/services.
  • country: SMS-Activate country ID (e.g. 62 = Turkey, 0 = Russia, 187 = USA) — the id from GET /api/v1/countries.
  • Prices are in Turkish lira; maxPrice is interpreted in TRY too.
actionParametersExample response
getBalance—ACCESS_BALANCE:125.50
getNumberservice, country (ID), [maxPrice]ACCESS_NUMBER:1234:905551234567
getNumberV2service, country (ID), [maxPrice]{"activationId":"1234","phoneNumber":"905551234567","activationCost":8.5,"countryCode":"62","canGetAnotherSms":true,...}
getStatusidSTATUS_WAIT_CODE | STATUS_OK:482913 | STATUS_WAIT_RETRY:482913 | STATUS_CANCEL
getStatusV2id{"verificationType":0,"sms":{"dateTime":"...","code":"482913","text":"..."},"call":null}
setStatusid, status (3=tekrar SMS, 6=tamamla, 8=iptal)ACCESS_RETRY_GET | ACCESS_ACTIVATION | ACCESS_CANCEL | EARLY_CANCEL_DENIED
getPrices[service], [country]{"62":{"tg":{"cost":8.5,"count":420}}}
getNumbersStatuscountry{"tg_0":420,"wa_0":310}
getCountries—{"62":{"id":62,"eng":"Turkey",...}}
getServicesList—{"status":"success","services":[{"code":"tg","name":"Telegram"}]}
getActiveActivations—{"status":"success","activeActivations":[...]}
Example
curl "https://codesms.org/stubs/handler_api.php?api_key=YOUR_API_KEY&action=getNumber&service=tg&country=62" \
  -H "X-API-Key: unused"
$ch = curl_init('https://codesms.org/stubs/handler_api.php?api_key=YOUR_API_KEY&action=getNumber&service=tg&country=62');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ['X-API-Key: unused'],
]);
$response = json_decode(curl_exec($ch), true);
print_r($response);
import requests

response = requests.get(
    "https://codesms.org/stubs/handler_api.php?api_key=YOUR_API_KEY&action=getNumber&service=tg&country=62",
    headers={"X-API-Key": "unused"}
)
print(response.json())
const response = await fetch("https://codesms.org/stubs/handler_api.php?api_key=YOUR_API_KEY&action=getNumber&service=tg&country=62", {
  method: "GET",
  headers: {
    "X-API-Key": "unused"
  }
});
console.log(await response.json());

Error responses are plain text: BAD_KEY, BAD_ACTION, BAD_SERVICE, NO_NUMBERS, NO_BALANCE, NO_ACTIVATION, EARLY_CANCEL_DENIED, WRONG_MAX_PRICE:price, ACCOUNT_INACTIVE…

Signed requests (optional)

If Panel → API → "Signed request required" is turned on, the following headers must be added to every REST request; even if your key is stolen, requests can't be made without the signing secret, and the same request can't be replayed. The SMS-Activate compatible endpoint doesn't support signing, so it can't be used while this option is on.

  • X-Timestamp: Unix time (seconds); may differ from the server time by at most 5 minutes.
  • X-Nonce: A new random value for each request, 16–64 characters (A-Z a-z 0-9 _ -).
  • X-Signature: hex(HMAC-SHA256(imza_sırrı, X-Timestamp + "\n" + X-Nonce + "\n" + METHOD + "\n" + yol?sorgu + "\n" + hex(SHA256(gövde))))
$ts = (string)time(); $nonce = bin2hex(random_bytes(16)); $body = json_encode(['service' => 'tg', 'country' => 'tr']);
$sig = hash_hmac('sha256', "$ts\n$nonce\nPOST\n/api/v1/activations\n" . hash('sha256', $body), $signSecret);
// Başlıklar: X-API-Key, X-Timestamp: $ts, X-Nonce: $nonce, X-Signature: $sig, Content-Type: application/json

Error codes

codeHTTPDescription
BAD_KEY401API key is missing or invalid.
API_DISABLED403API access is disabled on your account.
EMAIL_NOT_VERIFIED403Your e-mail address is not verified.
IP_NOT_ALLOWED403The request IP address is not in the allow list.
ACCOUNT_BANNED403The account is suspended.
RATE_LIMIT429The per-minute request limit was exceeded.
BAD_SERVICE400The service code is invalid or missing.
BAD_COUNTRY400The country code is invalid or missing.
NO_BALANCE402Insufficient balance. (There is no minimum balance requirement; this error is returned when your balance is lower than the price.)
NO_NUMBERS409No numbers for this service/country right now (no charge / refunded).
TOO_MANY_ACTIVE429The allowed number of concurrent active activations was exceeded.
NOT_FOUND404Activation not found.
BAD_STATUS409This action is not possible in the current activation state.
CANCEL_TOO_EARLY409The provider does not allow cancellation at this stage; retry after cancel_in seconds.
ALREADY_RECEIVED409Cannot be canceled because the code has arrived.
UNSUPPORTED409The provider does not support this action (e.g. another SMS).
PROVIDER_ERROR502The provider had a temporary error; try again.
PLAN_REQUIRED403API erişimi için etkin bir API paketi gerekiyor (Panel → API).
BAD_SIGNATURE401İmzalı istek zorunlu ve imza eksik/geçersiz ya da zaman damgası 5 dakikadan eski.
BAD_IDEMPOTENCY_KEY400The Idempotency-Key header must be 8–64 characters (letters, digits, _ - : .).
IDEMPOTENCY_IN_PROGRESS409An earlier request with the same Idempotency-Key is still being processed; retry in a few seconds.
REPLAYED_REQUEST401Aynı X-Nonce ikinci kez kullanıldı (tekrar oynatma koruması).
SERVER_ERROR500Unexpected server error.

Limits and recommendations

  • Rate limit: 120 requests per minute (per account).
  • Poll status every 3–5 seconds; using webhooks is more efficient.
  • Activations that get no SMS are canceled and refunded automatically when time runs out; you can also cancel early.
  • The number of simultaneously open activations is limited (TOO_MANY_ACTIVE).
  • On a network timeout, resend the purchase request with the same Idempotency-Key header; no second number is bought. If you do not use the header, check your recent activations with GET /api/v1/activations first.