Documentation API

v1.0.0

Accès programmatique aux numéros virtuels, commandes et solde du compte.

Authentification

Toutes les requêtes API nécessitent un Bearer token. Générez-en un depuis les Paramètres du compte dans le tableau de bord, puis incluez-le dans chaque requête :

Authorization: Bearer YOUR_API_TOKEN

Les requêtes sans token valide reçoivent une réponse 401 UNAUTHORIZED.

URL de base

Tous les chemins d'endpoints ci-dessous sont relatifs à :

https://api.smscode.gg/v1

Format de réponse

Chaque réponse renvoie du JSON avec une enveloppe cohérente. Toutes les réponses incluent un en-tête x-request-id pour le débogage.

Succès
{
  "success": true,
  "data": { ... }
}
Erreur
{
  "success": false,
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable message"
  }
}
GET /catalog/countries

Renvoie la liste de tous les pays disponibles.

Paramètres

Aucun

Exemple de requête

curl -s https://api.smscode.gg/v1/catalog/countries \
  -H "Authorization: Bearer YOUR_API_TOKEN"
const res = await fetch("https://api.smscode.gg/v1/catalog/countries", {
  headers: { Authorization: "Bearer YOUR_API_TOKEN" },
});
const data = await res.json();
import requests

res = requests.get("https://api.smscode.gg/v1/catalog/countries",
    headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()

Exemple de réponse

200 OK
{
  "success": true,
  "data": [
    {
      "id": 6,
      "code": "ID",
      "name": "Indonesia",
      "dial_code": "+62",
      "emoji": "🇮🇩",
      "active": true
    }
  ]
}
GET /catalog/services

Renvoie la liste des services (plateformes) disponibles. Filtrage optionnel par pays.

Paramètres de requête

NomTypeRequisDescription
country_idintegerNonFiltrer les services disponibles pour ce pays

Exemple de requête

curl -s "https://api.smscode.gg/v1/catalog/services?country_id=6" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
const res = await fetch("https://api.smscode.gg/v1/catalog/services?country_id=6", {
  headers: { Authorization: "Bearer YOUR_API_TOKEN" },
});
const data = await res.json();
import requests

res = requests.get("https://api.smscode.gg/v1/catalog/services",
    params={"country_id": 6},
    headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()

Exemple de réponse

200 OK
{
  "success": true,
  "data": [
    {
      "id": 3,
      "code": "wa",
      "name": "WhatsApp",
      "active": true
    }
  ]
}
GET /catalog/products

Renvoie une liste paginée des produits disponibles. Filtrage par pays et/ou plateforme.

Paramètres de requête

NomTypeRequisDescription
country_idintegerNonFiltrer par identifiant de pays
platform_idintegerNonFiltrer par identifiant de plateforme/service
sortstringNonOrdre de tri : price_asc (défaut), price_desc, available_asc, available_desc, name_asc, name_desc
limitintegerNonRésultats par page (1-10 000, défaut 1 000)
pageintegerNonNuméro de page (min. 1, défaut 1)

Exemple de requête

curl -s "https://api.smscode.gg/v1/catalog/products?country_id=6&platform_id=3&limit=10&page=1" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
const params = new URLSearchParams({
  country_id: "6", platform_id: "3", limit: "10", page: "1",
});
const res = await fetch(`https://api.smscode.gg/v1/catalog/products?${params}`, {
  headers: { Authorization: "Bearer YOUR_API_TOKEN" },
});
const data = await res.json();
import requests

res = requests.get("https://api.smscode.gg/v1/catalog/products",
    params={"country_id": 6, "platform_id": 3, "limit": 10, "page": 1},
    headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()

Exemple de réponse

200 OK
{
  "success": true,
  "data": [
    {
      "id": 142,
      "name": "WhatsApp Indonesia",
      "country_id": 6,
      "platform_id": 3,
      "available": 42,
      "price": 15000,
      "active": true
    }
  ],
  "meta": { "page": 1, "limit": 10, "count": 1 }
}
GET /catalog/exchange-rate

Renvoie le taux de change actuel pour une paire de devises. Utile pour la conversion des prix.

Paramètres de requête

NomTypeRequisDescription
pairstringNonPaire de devises (défaut : USD/IDR)

Exemple de requête

curl -s "https://api.smscode.gg/v1/catalog/exchange-rate?pair=USD/IDR" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
const res = await fetch("https://api.smscode.gg/v1/catalog/exchange-rate?pair=USD/IDR", {
  headers: { Authorization: "Bearer YOUR_API_TOKEN" },
});
const data = await res.json();
import requests

res = requests.get("https://api.smscode.gg/v1/catalog/exchange-rate",
    params={"pair": "USD/IDR"},
    headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()

Exemple de réponse

200 OK
{
  "success": true,
  "data": {
    "pair": "USD/IDR",
    "base_currency": "USD",
    "quote_currency": "IDR",
    "rate": 16250
  }
}
GET /balance

Renvoie le solde du compte de l'utilisateur authentifié en IDR.

Paramètres

Aucun

Exemple de requête

curl -s https://api.smscode.gg/v1/balance \
  -H "Authorization: Bearer YOUR_API_TOKEN"
const res = await fetch("https://api.smscode.gg/v1/balance", {
  headers: { Authorization: "Bearer YOUR_API_TOKEN" },
});
const data = await res.json();
import requests

res = requests.get("https://api.smscode.gg/v1/balance",
    headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()

Exemple de réponse

200 OK
{
  "success": true,
  "data": {
    "currency": "IDR",
    "balance": 500000
  }
}
GET /orders

Renvoie la liste des commandes de l'utilisateur authentifié, triées par date décroissante. Filtrage par statut et pagination via offset.

Paramètres de requête

NomTypeRequisDescription
limitintegerNonNombre max. de résultats (1-100, défaut 20)
offsetintegerNonNombre de résultats à ignorer (défaut 0)
statusstringNonFiltrer par statut : ACTIVE, OTP_RECEIVED, COMPLETED, CANCELED, EXPIRED (insensible à la casse)

Exemple de requête

curl -s "https://api.smscode.gg/v1/orders?limit=5&status=ACTIVE" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
const params = new URLSearchParams({
  limit: "5", status: "ACTIVE", offset: "0",
});
const res = await fetch(`https://api.smscode.gg/v1/orders?${params}`, {
  headers: { Authorization: "Bearer YOUR_API_TOKEN" },
});
const data = await res.json();
import requests

res = requests.get("https://api.smscode.gg/v1/orders",
    params={"limit": 5, "status": "ACTIVE", "offset": 0},
    headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()

Exemple de réponse

200 OK
{
  "success": true,
  "data": [
    {
      "id": 1001,
      "status": "ACTIVE",
      "created_at": "2026-02-25T10:00:00Z",
      "product_id": 142,
      "phone_number": "+6281234567890",
      "amount": 15000,
      "otp_code": null,
      "otp_received_at": null,
      "expires_at": "2026-02-25T10:20:00Z",
      "canceled_at": null,
      "failed_reason": null
    }
  ]
}
GET /orders/{id}

Renvoie une commande par son identifiant. Ne renvoie que les commandes de l'utilisateur authentifié.

Paramètres de chemin

NomTypeRequisDescription
idintegerOuiIdentifiant de commande (paramètre de chemin)

Exemple de requête

curl -s https://api.smscode.gg/v1/orders/1001 \
  -H "Authorization: Bearer YOUR_API_TOKEN"
const res = await fetch("https://api.smscode.gg/v1/orders/1001", {
  headers: { Authorization: "Bearer YOUR_API_TOKEN" },
});
const data = await res.json();
import requests

res = requests.get("https://api.smscode.gg/v1/orders/1001",
    headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()

Exemple de réponse

200 OK
{
  "success": true,
  "data": {
    "id": 1001,
    "status": "OTP_RECEIVED",
    "created_at": "2026-02-25T10:00:00Z",
    "product_id": 142,
    "phone_number": "+6281234567890",
    "amount": 15000,
    "otp_code": "123456",
    "otp_received_at": "2026-02-25T10:05:00Z",
    "expires_at": "2026-02-25T10:20:00Z",
    "canceled_at": null,
    "failed_reason": null
  }
}
GET /orders/active

Liste toutes les commandes actuellement actives (ACTIVE + OTP_RECEIVED). Utilisez cet endpoint pour surveiller les mises à jour de statut OTP.

Paramètres

Aucun

Exemple de requête

curl -s https://api.smscode.gg/v1/orders/active \
  -H "Authorization: Bearer YOUR_API_TOKEN"
const res = await fetch("https://api.smscode.gg/v1/orders/active", {
  headers: { Authorization: "Bearer YOUR_API_TOKEN" },
});
const data = await res.json();
import requests

res = requests.get("https://api.smscode.gg/v1/orders/active",
    headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()

Exemple de réponse

200 OK
{
  "success": true,
  "data": [
    {
      "id": 1001,
      "status": "OTP_RECEIVED",
      "otp_code": "123456",
      "otp_message": "Your verification code is 123456",
      "otp_received_at": "2026-02-25T10:05:00Z",
      "expires_at": "2026-02-25T10:20:00Z",
      "failed_reason": null
    },
    {
      "id": 1002,
      "status": "ACTIVE",
      "otp_code": null,
      "otp_message": null,
      "otp_received_at": null,
      "expires_at": "2026-02-25T10:50:00Z",
      "failed_reason": null
    }
  ]
}
POST /orders/create

Crée une nouvelle commande de numéro virtuel. Débite le solde automatiquement. Prend en charge un en-tête Idempotency-Key optionnel pour éviter les commandes en double lors des nouvelles tentatives réseau.

Corps de la requête

NomTypeRequisDescription
product_idintegerOuiIdentifiant du produit à commander
quantityintegerNonQuantité (1-100, défaut 1)

Passez un en-tête Idempotency-Key (toute chaîne unique) pour réessayer les requêtes en toute sécurité sans créer de doublons.

Exemple de requête

curl -s -X POST https://api.smscode.gg/v1/orders/create \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: unique-request-id-123" \
  -d '{"product_id":142,"quantity":1}'
const res = await fetch("https://api.smscode.gg/v1/orders/create", {
  method: "POST",
  headers: {
    Authorization: "Bearer YOUR_API_TOKEN",
    "Content-Type": "application/json",
    "Idempotency-Key": "unique-request-id-123",
  },
  body: JSON.stringify({ product_id: 142, quantity: 1 }),
});
const data = await res.json();
import requests

res = requests.post("https://api.smscode.gg/v1/orders/create",
    json={"product_id": 142, "quantity": 1},
    headers={
        "Authorization": "Bearer YOUR_API_TOKEN",
        "Idempotency-Key": "unique-request-id-123",
    })
data = res.json()

Exemple de réponse

200 OK
{
  "success": true,
  "data": {
    "orders": [
      {
        "id": 1002,
        "status": "ACTIVE",
        "phone_number": "+6281234567891",
        "otp_code": null,
        "otp_received_at": null,
        "expires_at": "2026-02-25T10:50:00Z",
        "failed_reason": null
      }
    ],
    "failed_count": 0
  }
}
POST /orders/cancel

Annule une commande active. Le coût de la location est remboursé sur le solde de votre compte.

Corps de la requête

NomTypeRequisDescription
idintegerOuiIdentifiant de la commande à annuler

Exemple de requête

curl -s -X POST https://api.smscode.gg/v1/orders/cancel \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"id":1001}'
const res = await fetch("https://api.smscode.gg/v1/orders/cancel", {
  method: "POST",
  headers: {
    Authorization: "Bearer YOUR_API_TOKEN",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ id: 1001 }),
});
const data = await res.json();
import requests

res = requests.post("https://api.smscode.gg/v1/orders/cancel",
    json={"id": 1001},
    headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()

Exemple de réponse

200 OK
{
  "success": true,
  "data": {
    "order_id": 1001,
    "status": "CANCELED",
    "refund_amount": 15000,
    "new_balance": 515000
  }
}
POST /orders/finish

Marque une commande comme terminée après réception de l'OTP. Cela libère le numéro immédiatement au lieu d'attendre l'expiration.

Corps de la requête

NomTypeRequisDescription
idintegerOuiIdentifiant de la commande à finaliser

Exemple de requête

curl -s -X POST https://api.smscode.gg/v1/orders/finish \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"id":1001}'
const res = await fetch("https://api.smscode.gg/v1/orders/finish", {
  method: "POST",
  headers: {
    Authorization: "Bearer YOUR_API_TOKEN",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ id: 1001 }),
});
const data = await res.json();
import requests

res = requests.post("https://api.smscode.gg/v1/orders/finish",
    json={"id": 1001},
    headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()

Exemple de réponse

200 OK
{
  "success": true,
  "data": {
    "order_id": 1001,
    "status": "COMPLETED"
  }
}
POST /orders/resend

Demande à la plateforme de renvoyer le SMS au numéro loué. Toutes les plateformes ne prennent pas en charge le renvoi — vérifiez le champ resent dans la réponse.

Corps de la requête

NomTypeRequisDescription
idintegerOuiIdentifiant de la commande pour le renvoi SMS

Exemple de requête

curl -s -X POST https://api.smscode.gg/v1/orders/resend \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"id":1001}'
const res = await fetch("https://api.smscode.gg/v1/orders/resend", {
  method: "POST",
  headers: {
    Authorization: "Bearer YOUR_API_TOKEN",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ id: 1001 }),
});
const data = await res.json();
import requests

res = requests.post("https://api.smscode.gg/v1/orders/resend",
    json={"id": 1001},
    headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()

Exemple de réponse

200 OK
{
  "success": true,
  "data": {
    "order_id": 1001,
    "status": "ACTIVE",
    "resent": true
  }
}
GET /webhook

Renvoie votre configuration actuelle de notifications webhook.

Paramètres

Aucun

Exemple de requête

curl -s https://api.smscode.gg/v1/webhook \
  -H "Authorization: Bearer YOUR_API_TOKEN"
const res = await fetch("https://api.smscode.gg/v1/webhook", {
  headers: { Authorization: "Bearer YOUR_API_TOKEN" },
});
const data = await res.json();
import requests

res = requests.get("https://api.smscode.gg/v1/webhook",
    headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()

Exemple de réponse

200 OK
{
  "success": true,
  "data": {
    "webhook_url": "https://example.com/webhook",
    "webhook_secret": "a1b2c3d4e5f6..."
  }
}
PATCH /webhook

Met à jour votre URL webhook et/ou votre secret. Un secret est généré automatiquement lorsque vous définissez une URL pour la première fois. Envoyez une chaîne vide pour effacer. L'URL doit utiliser HTTPS.

Corps de la requête

NomTypeRequisDescription
webhook_urlstringNonURL HTTPS pour recevoir les événements webhook (chaîne vide pour effacer)
webhook_secretstringNonSecret partagé pour la signature HMAC-SHA256 (généré automatiquement s'il est omis lors de la première configuration)

Au moins un champ est requis.

Exemple de requête

curl -s -X PATCH https://api.smscode.gg/v1/webhook \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"webhook_url":"https://example.com/webhook"}'
const res = await fetch("https://api.smscode.gg/v1/webhook", {
  method: "PATCH",
  headers: {
    Authorization: "Bearer YOUR_API_TOKEN",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ webhook_url: "https://example.com/webhook" }),
});
const data = await res.json();
import requests

res = requests.patch("https://api.smscode.gg/v1/webhook",
    json={"webhook_url": "https://example.com/webhook"},
    headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()

Exemple de réponse

200 OK
{
  "success": true,
  "data": {
    "webhook_url": "https://example.com/webhook",
    "webhook_secret": "a1b2c3d4e5f6..."
  }
}
POST /webhook/test

Envoie un événement test à votre URL webhook configurée. Renvoie le code de statut HTTP de votre serveur. Utile pour vérifier que votre endpoint fonctionne avant la mise en production.

Paramètres

Aucun

Exemple de requête

curl -s -X POST https://api.smscode.gg/v1/webhook/test \
  -H "Authorization: Bearer YOUR_API_TOKEN"
const res = await fetch("https://api.smscode.gg/v1/webhook/test", {
  method: "POST",
  headers: { Authorization: "Bearer YOUR_API_TOKEN" },
});
const data = await res.json();
import requests

res = requests.post("https://api.smscode.gg/v1/webhook/test",
    headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()

Exemple de réponse

200 OK
{
  "success": true,
  "data": {
    "status_code": 200
  }
}

Notifications webhook

Configurez une URL webhook pour recevoir des notifications push en temps réel pour les événements de commande au lieu du polling. C'est l'approche recommandée pour les scripts de bot.

Événements

ÉvénementDéclencheur
order.otp_receivedCode OTP livré au numéro loué
order.completedCommande marquée comme terminée (manuellement ou par expiration)
order.expiredCommande expirée sans OTP (solde remboursé)
order.canceledCommande annulée par l'utilisateur (solde remboursé)

Payload

Corps de la requête POST webhook
{
  "event": "order.otp_received",
  "timestamp": "2026-02-25T12:00:00Z",
  "data": {
    "order_id": 1001,
    "phone_number": "+628123456789",
    "otp_code": "1234",
    "otp_message": "Your verification code is 1234",
    "product_id": 42,
    "country": "Indonesia",
    "platform": "WhatsApp"
  }
}

Vérification de la signature

Chaque requête webhook inclut un en-tête X-Webhook-Signature avec une signature HMAC-SHA256 du corps de la requête, utilisant votre webhook_secret comme clé :

X-Webhook-Signature: sha256={HMAC-SHA256(body, webhook_secret)}

Vérifiez cette signature côté serveur pour vous assurer que la requête est authentique. La livraison est de type « fire-and-forget » avec un délai d'expiration de 3 secondes et sans nouvelle tentative.

Limites de débit

Les requêtes API sont soumises à des limites de débit par groupe d'endpoints. Le dépassement de la limite renvoie un code 429 Too Many Requests avec un en-tête Retry-After indiquant le nombre de secondes à attendre.

Groupe d'endpointsLimiteFenêtre
Catalogue (pays, services, produits, taux de change)1 200 requêtes60 secondes
Solde600 requêtes60 secondes
Lecture de commandes (liste, détail, actives)1 200 requêtes60 secondes
Création de commande1 200 requêtes60 secondes
Annulation de commande600 requêtes60 secondes
Actions sur les commandes (finaliser, renvoyer)600 requêtes60 secondes
Configuration webhook (lecture, mise à jour, test)120 requêtes60 secondes

Codes d'erreur

Les réponses d'erreur incluent l'un de ces codes dans error.code :

CodeHTTPDescription
UNAUTHORIZED401Token API manquant ou invalide
FORBIDDEN403Accès refusé
NOT_FOUND404Ressource introuvable (commande, taux de change, etc.)
CONFLICT409Requête en double ou conflit de ressource
INSUFFICIENT_BALANCE409Solde insuffisant pour créer la commande
VALIDATION_ERROR422Les paramètres de la requête n'ont pas passé la validation
RATE_LIMIT_EXCEEDED429Trop de requêtes (vérifiez l'en-tête Retry-After)
INTERNAL_ERROR500Erreur interne du serveur
PROVIDER_ERROR422Le fournisseur SMS en amont a rejeté la requête
CANCEL_TOO_EARLY409Commande trop récente pour être annulée — patientez 2 minutes
SERVICE_UNAVAILABLE503Service temporairement indisponible (maintenance)