RelySMS
API · protocole handler_api.php

Des numéros pour recevoir des SMS — depuis votre logiciel

Si votre logiciel fonctionne déjà avec un service d'activation via handler_api.php, il fonctionne avec RelySMS : changez l'adresse du serveur et la clé. Mêmes actions, mêmes réponses, nos prix et nos remboursements.

https://relysms.pro/stubs/handler_api.php

Démarrage rapide

  1. Connectez-vous et ouvrez Solde → API → Créer une clé. La clé n'est affichée qu'une fois — conservez-la.
  2. Rechargez jusqu'à 20 $ ou plus : les achats par l'API ne passent qu'avec ce solde. Garder une clé avec un solde nul ne pose aucun problème.
  3. Indiquez dans votre logiciel le serveur https://relysms.pro/stubs/handler_api.php et votre clé à la place de celle du service précédent.
  4. Achetez un numéro (getNumber), puis interrogez le statut toutes les 5 à 10 secondes (getStatus) jusqu'à recevoir STATUS_OK avec le code.
  5. Terminez la commande (setStatus=6). Sans code, annulez après 2 minutes (setStatus=8) ou laissez la fenêtre se terminer : l'argent revient tout seul.

Règles et limites

  • Les achats par l'API exigent un solde d'au moins 20 $. En dessous, getNumber répond NO_BALANCE ; les autres méthodes fonctionnent.
  • Le numéro est à vous pendant 20 minutes. Sans code, la commande se ferme d'elle-même et l'argent revient sur votre solde.
  • Vous pouvez annuler 2 minutes après l'achat si aucun code n'est arrivé. L'argent revient aussitôt.
  • Dès le premier code, la commande est payée et non remboursable. Tant que la fenêtre est ouverte, d'autres codes peuvent encore arriver.
  • Jusqu'à 20 requêtes et 5 achats par seconde et par clé ; jusqu'à 50 commandes ouvertes à la fois.
  • Le prix est fixé à l'achat. maxPrice vous évite d'acheter au-dessus de votre limite.
  • Les conditions du service s'appliquent : spam, fraude et inscriptions en masse à ces fins sont interdits.

Méthodes

Chaque requête est un GET ou un POST vers une seule adresse, avec les paramètres dans l'URL ou dans un formulaire. La clé va dans api_key, l'action dans action.

getBalance

Le solde du compte en dollars.

Seulement api_key et action.

GET https://relysms.pro/stubs/handler_api.php?api_key=KEY&action=getBalance

Réponse

ACCESS_BALANCE:25.00

getNumber

Acheter un numéro pour un service dans un pays. Débité tout de suite ; remboursé si aucun code n'arrive. Réponse : ACCESS_NUMBER:numéro_de_commande:téléphone.

ParamètreObligatoireDescription
serviceouiCode du service (getServicesList), p. ex. tg.
countryouiCode du pays (getCountries).
maxPricenonPrix maximal en dollars. Au-delà : WRONG_MAX_PRICE avec le prix actuel, rien n'est débité.
GET https://relysms.pro/stubs/handler_api.php?api_key=KEY&action=getNumber&service=tg&country=187&maxPrice=0.80

Réponse

ACCESS_NUMBER:1042:15550001111

Erreurs possibles: BAD_SERVICE, BAD_COUNTRY, NO_NUMBERS, NO_BALANCE, WRONG_MAX_PRICE:0.59, LIMIT_ACTIVATIONS, RATE_LIMIT, BANNED

getNumberV2

Comme getNumber, avec une réponse JSON incluant le prix et les horaires de la fenêtre.

ParamètreObligatoireDescription
serviceouiCode du service.
countryouiCode du pays.
maxPricenonPrix maximal en dollars.
GET https://relysms.pro/stubs/handler_api.php?api_key=KEY&action=getNumberV2&service=tg&country=187&maxPrice=0.80

Réponse

{
  "activationId": 1042,
  "phoneNumber": "15550001111",
  "activationCost": 0.59,
  "countryCode": "187",
  "canGetAnotherSms": true,
  "activationTime": "2026-10-27T10:00:00.000Z",
  "activationEndTime": "2026-10-27T10:20:00.000Z"
}

Erreurs possibles: BAD_SERVICE, BAD_COUNTRY, NO_NUMBERS, NO_BALANCE, WRONG_MAX_PRICE:0.59, LIMIT_ACTIVATIONS, RATE_LIMIT

getStatus

Statut de la commande : en attente du code, code reçu (avec le code) ou annulée.

ParamètreObligatoireDescription
idouiNuméro de commande renvoyé par getNumber.
GET https://relysms.pro/stubs/handler_api.php?api_key=KEY&action=getStatus&id=1042

Réponse

STATUS_OK:48213

Erreurs possibles: NO_ACTIVATION

setStatus

Agir sur une commande : prêt, autre code, terminer, annuler (voir Statuts).

ParamètreObligatoireDescription
idouiNuméro de commande.
statusoui1, 3, 6 ou 8.
GET https://relysms.pro/stubs/handler_api.php?api_key=KEY&action=setStatus&id=1042&status=6

Réponse

ACCESS_ACTIVATION

Erreurs possibles: NO_ACTIVATION, BAD_STATUS, EARLY_CANCEL_DENIED, ERROR_SQL

getActiveActivations

Toutes les commandes ouvertes de la clé : numéro, statut, codes et textes reçus.

Seulement api_key et action.

GET https://relysms.pro/stubs/handler_api.php?api_key=KEY&action=getActiveActivations

Réponse

{
  "status": "success",
  "activeActivations": [
    {
      "activationId": 1042,
      "serviceCode": "tg",
      "phoneNumber": "15550001111",
      "activationCost": 0.59,
      "activationStatus": "2",
      "smsCode": ["48213"],
      "smsText": ["Telegram code: 48213"],
      "activationTime": "2026-10-27T10:00:00.000Z",
      "countryCode": "187"
    }
  ]
}

getPrices

Nos prix en dollars et le nombre approximatif de numéros. Sans paramètres : tout ce qui est en vente.

ParamètreObligatoireDescription
servicenonSeulement ce service.
countrynonSeulement ce pays.
GET https://relysms.pro/stubs/handler_api.php?api_key=KEY&action=getPrices&service=tg&country=187

Réponse

{ "187": { "tg": { "cost": 0.59, "count": 1000 } } }

Erreurs possibles: BAD_SERVICE, BAD_COUNTRY

getCountries

Liste des pays avec les codes du protocole et les noms en russe et en anglais.

Seulement api_key et action.

GET https://relysms.pro/stubs/handler_api.php?api_key=KEY&action=getCountries

Réponse

{ "187": { "id": 187, "rus": "США", "eng": "United States", "visible": 1 } }

getServicesList

Liste des services avec les codes du protocole.

Seulement api_key et action.

GET https://relysms.pro/stubs/handler_api.php?api_key=KEY&action=getServicesList

Réponse

{ "status": "success", "services": [{ "code": "tg", "name": "Telegram" }] }

Statuts

Valeurs de status dans setStatus :

  • status=1 → ACCESS_READY — Le numéro est saisi dans le service, en attente du code. Ne change rien ; conservé pour la compatibilité.
  • status=3 → ACCESS_RETRY_GET — Demander un autre code sur le même numéro — après le premier code, tant que la commande est ouverte. Gratuit. En attendant, getStatus répond STATUS_WAIT_RETRY.
  • status=6 → ACCESS_ACTIVATION — Terminer la commande après le code. Aucun nouveau SMS n'arrivera sur le numéro.
  • status=8 → ACCESS_CANCEL — Annuler une commande sans code (pas avant 2 minutes). L'argent revient sur votre solde.

Réponses de getStatus :

  • STATUS_WAIT_CODE — Pas encore de code — redemandez dans 5 à 10 secondes.
  • STATUS_OK:48213 — Le code est arrivé ; après les deux-points figure le code (ou le texte du SMS s'il n'en contient pas).
  • STATUS_WAIT_RETRY:48213 — Un autre code a été demandé et n'est pas encore arrivé ; après les deux-points figure le code précédent.
  • STATUS_CANCEL — Annulée ou close sans code ; l'argent est déjà revenu sur le solde.

Erreurs

Les erreurs sont des chaînes de texte, comme le veut l'usage de ce protocole. Toutes, sauf RATE_LIMIT, arrivent avec le statut 200.

NO_KEYapi_key manquant.
BAD_KEYClé erronée ou désactivée, ou compte bloqué.
BAD_ACTIONAction inconnue.
BAD_SERVICECe code de service n'existe pas.
BAD_COUNTRYCe code de pays n'existe pas.
NO_NUMBERSPas de numéro pour cette paire pour l'instant ; rien n'est débité.
NO_BALANCEMoins de 20 $ de solde (seuil de l'API) ou moins que le prix.
WRONG_MAX_PRICELe prix dépasse maxPrice ; le prix actuel suit les deux-points.
LIMIT_ACTIVATIONSTrop de commandes ouvertes — terminez-en ou annulez-en.
RATE_LIMITTrop fréquent ; HTTP 429. Réessayez dans une seconde.
BANNEDLe compte est bloqué — contactez le support.
NO_ACTIVATIONAucune commande avec ce numéro pour cette clé.
BAD_STATUSCette action n'est pas disponible pour la commande en ce moment (p. ex. terminer sans code).
EARLY_CANCEL_DENIEDL'annulation n'est possible que 2 minutes après l'achat.
ERROR_SQLErreur temporaire de notre côté — répétez la requête dans une minute.

Codes des services et pays

Les codes sont ceux, standard, du protocole : tg — Telegram, wa — WhatsApp, etc. ; le pays 187 — les États-Unis. getServicesList et getCountries renvoient les listes complètes — prenez les codes là, pas dans d'anciens tableaux : services et pays évoluent avec le stock.

API REST v1

Les mêmes numéros et les mêmes règles que handler_api.php, en JSON : services par nom (telegram), pays par code ISO (US), statuts HTTP et codes d'erreur sur lesquels un programme peut s'appuyer. Utilisez-la pour du code neuf ; gardez handler_api.php pour les logiciels qui le parlent déjà.

https://relysms.pro/api/v1

Clé

Envoyez la clé dans un en-tête : Authorization: Bearer <clé> (ou X-Api-Key: <clé>). Jamais dans l'URL — les URL finissent dans les logs. Les limites, le seuil de 20 $ et le catalogue sont ceux de handler_api.php.

Réessayer sans acheter deux fois

Ajoutez l'en-tête Idempotency-Key avec une valeur à vous (un UUID, jusqu'à 255 caractères) sur POST /orders et /orders/batch. Si la connexion coupe et que vous renvoyez la requête avec la même clé, vous recevez la première réponse (avec l'en-tête Idempotent-Replayed: true) et rien n'est acheté deux fois. La même clé avec un autre corps est refusée ; une répétition arrivée pendant que la première tourne encore reçoit idempotency_in_progress. Les réponses réussies sont gardées 24 heures ; un achat échoué n'a rien débité et peut être relancé avec la même clé.

Plusieurs numéros d'un coup

POST /orders/batch achète jusqu'à 20 numéros pour un service et un pays en une requête — c'est ainsi qu'on achète plus de 5 par seconde. Les achats se font un par un ; le premier qui échoue arrête le lot, et la réponse contient ce qui a été acheté et la raison dans stoppedBy. Si rien n'a été acheté, la réponse est cette erreur.

Pages

GET /orders renvoie d'abord les plus récentes. Quand next n'est pas null, passez-le dans before pour obtenir la page suivante.

Webhooks

Plutôt que d'interroger GET /orders/{id}, définissez une adresse HTTPS avec PUT /webhook : nous y envoyons un POST quand il arrive quelque chose à une commande passée par l'API. Le corps contient la commande telle qu'elle est au moment de l'envoi. Répondez par n'importe quel 2xx sous 10 secondes ; une commande peut produire plusieurs événements, et le même événement peut arriver deux fois après une nouvelle tentative : appuyez-vous sur l'id de livraison.

  • order.code_received — Un code est arrivé (chaque nouveau code le renvoie).
  • order.finished — La commande est terminée — par vous, ou à la fin de son temps après un code.
  • order.cancelled — Annulée sans code ; l'argent est revenu sur le solde.
  • order.expired — Temps écoulé sans code ; l'argent est revenu sur le solde.
  • ping — Un test depuis POST /webhook/test ; order vaut null.
POST /relysms-hook HTTP/1.1
Content-Type: application/json
X-RelySMS-Event: order.code_received
X-RelySMS-Delivery: cm…
X-RelySMS-Signature: t=1793095272,v1=5f2b…

{
  "id": "cm…",
  "event": "order.code_received",
  "createdAt": "2026-10-27T10:01:12.000Z",
  "order": { "id": 1042, "status": "received", "codes": [{ "code": "48213", … }], … }
}

Chaque requête porte X-RelySMS-Signature: t=<heure unix>,v1=<signature>. La signature est le HMAC-SHA256 de la chaîne « t.corps » (le corps brut, octet pour octet) avec le secret du webhook, en hexadécimal. Vérifiez-la, ainsi que t date de moins de 5 minutes, avant de faire confiance au corps.

Python

import hashlib, hmac, time

def verify(secret: str, body: bytes, header: str, tolerance=300) -> bool:
    parts = dict(p.split("=", 1) for p in header.split(","))
    t, sig = parts.get("t", ""), parts.get("v1", "")
    if not t.isdigit() or abs(time.time() - int(t)) > tolerance:
        return False
    expected = hmac.new(secret.encode(), f"{t}.".encode() + body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, sig)

Node.js

import { createHmac, timingSafeEqual } from "node:crypto";

export function verify(secret, rawBody, header, tolerance = 300) {
  const parts = Object.fromEntries(header.split(",").map((p) => p.split("=", 2)));
  const t = Number(parts.t);
  if (!Number.isInteger(t) || Math.abs(Date.now() / 1000 - t) > tolerance) return false;
  const expected = createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
  return expected.length === parts.v1?.length && timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}

Si votre serveur ne répond pas 2xx, nous réessayons après 10 secondes, 1 minute, 5 minutes, 30 minutes, 2 heures et 6 heures — 7 tentatives en tout — puis abandonnons. GET /webhook/deliveries montre ce qui est parti et ce qui a échoué.

Points d'accès

GET /balance

Le solde en dollars, et s'il suffit pour acheter par l'API.

curl -H "Authorization: Bearer $KEY" https://relysms.pro/api/v1/balance

Réponse

{ "balance": 25, "currency": "USD", "canBuy": true, "apiMinimum": 20 }

GET /services

Tous les services en vente : notre id, le nom et le code handler_api.php.

ParamètreObligatoireDescription
lang querynonLangue des noms : en (par défaut), ru, uk, zh, es, pt, id, vi, tr, ar, fr.
curl -H "Authorization: Bearer $KEY" "https://relysms.pro/api/v1/services?lang=en"

Réponse

{ "services": [{ "id": "telegram", "name": "Telegram", "protocolCode": "tg" }] }

GET /countries

Tous les pays en vente : code ISO, nom et code handler_api.php.

ParamètreObligatoireDescription
lang querynonLangue des noms : en (par défaut), ru, uk, zh, es, pt, id, vi, tr, ar, fr.
curl -H "Authorization: Bearer $KEY" "https://relysms.pro/api/v1/countries?lang=en"

Réponse

{ "countries": [{ "id": "US", "name": "United States", "protocolCode": 187 }] }

GET /prices

Nos prix en dollars et le nombre approximatif de numéros. Sans paramètres : tout ce qui est en vente.

ParamètreObligatoireDescription
service querynonId du service tiré de /services, p. ex. telegram.
country querynonCode ISO du pays tiré de /countries, p. ex. US.
curl -H "Authorization: Bearer $KEY" "https://relysms.pro/api/v1/prices?service=telegram"

Réponse

{ "prices": [{ "service": "telegram", "country": "US", "price": 0.59, "stock": 1000 }] }

Erreurs possibles: unknown_service, unknown_country

POST /orders

Acheter un numéro. Débité tout de suite ; remboursé si aucun code n'arrive.

ParamètreObligatoireDescription
service bodyouiId du service tiré de /services, p. ex. telegram.
country bodyouiCode ISO du pays tiré de /countries, p. ex. US.
maxPrice bodynonPrix maximal en dollars, un nombre. Au-delà : price_above_max avec le prix actuel, rien n'est débité.
curl -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -H "Idempotency-Key: 7c1f0e2a-run-1" \
  -d '{"service":"telegram","country":"US","maxPrice":0.8}' \
  https://relysms.pro/api/v1/orders

Réponse

{
  "order": {
    "id": 1042,
    "service": "telegram",
    "country": "US",
    "phone": "15550001111",
    "price": 0.59,
    "status": "waiting",
    "refunded": false,
    "codes": [],
    "awaitingAnotherCode": false,
    "createdAt": "2026-10-27T10:00:00.000Z",
    "expiresAt": "2026-10-27T10:20:00.000Z",
    "cancelableAt": "2026-10-27T10:02:00.000Z"
  }
}

Erreurs possibles: bad_request, unknown_service, unknown_country, no_numbers, insufficient_balance, below_api_minimum, price_above_max, too_many_open_orders, buying_too_fast, idempotency_key_reused, idempotency_in_progress

POST /orders/batch

Acheter jusqu'à 20 numéros pour un service et un pays en une requête.

ParamètreObligatoireDescription
service bodyouiId du service tiré de /services, p. ex. telegram.
country bodyouiCode ISO du pays tiré de /countries, p. ex. US.
quantity bodyouiCombien de numéros, de 1 à 20.
maxPrice bodynonPrix maximal en dollars, un nombre. Au-delà : price_above_max avec le prix actuel, rien n'est débité.
curl -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -H "Idempotency-Key: 7c1f0e2a-batch-1" \
  -d '{"service":"telegram","country":"US","quantity":5}' \
  https://relysms.pro/api/v1/orders/batch

Réponse

{
  "orders": [{ "id": 1043, "phone": "15550001112", … }, { "id": 1044, … }],
  "requested": 5,
  "placed": 2,
  "stoppedBy": { "code": "no_numbers", "message": "…" }
}

Erreurs possibles: bad_request, unknown_service, unknown_country, no_numbers, insufficient_balance, below_api_minimum, price_above_max, too_many_open_orders, buying_too_fast, idempotency_key_reused, idempotency_in_progress

GET /orders

Vos commandes, les plus récentes d'abord : les ouvertes par défaut, ou toutes.

ParamètreObligatoireDescription
status querynonopen (par défaut) — en attente ou avec code ; all — toutes les commandes.
limit querynonCommandes par page, de 1 à 100 (50 par défaut).
before querynonLa valeur next de la page précédente.
curl -H "Authorization: Bearer $KEY" "https://relysms.pro/api/v1/orders?status=all&limit=50"

Réponse

{ "orders": [{ "id": 1042, … }], "next": "1001" }

Erreurs possibles: bad_request

GET /orders/{id}

Une commande avec ses codes. Interrogez-la toutes les 5 à 10 secondes tant que le statut est waiting.

ParamètreObligatoireDescription
id pathouiL'id de la commande renvoyé à l'achat.
curl -H "Authorization: Bearer $KEY" https://relysms.pro/api/v1/orders/1042

Réponse

{
  "order": {
    "id": 1042,
    "status": "received",
    "codes": [{ "code": "48213", "text": "Telegram code: 48213", "receivedAt": "2026-10-27T10:01:12.000Z" }],
    …
  }
}

Erreurs possibles: not_found

POST /orders/{id}/finish

Terminer une commande qui a un code. Le numéro ne recevra plus de SMS. Recommencer est sans effet.

ParamètreObligatoireDescription
id pathouiL'id de la commande renvoyé à l'achat.
curl -X POST -H "Authorization: Bearer $KEY" https://relysms.pro/api/v1/orders/1042/finish

Réponse

{ "order": { "id": 1042, "status": "finished", … } }

Erreurs possibles: not_found, invalid_state

POST /orders/{id}/another-code

Un autre code sur le même numéro — après le premier code, tant que la commande est ouverte. Gratuit. En attendant, la commande a awaitingAnotherCode = true.

ParamètreObligatoireDescription
id pathouiL'id de la commande renvoyé à l'achat.
curl -X POST -H "Authorization: Bearer $KEY" https://relysms.pro/api/v1/orders/1042/another-code

Réponse

{ "order": { "id": 1042, "status": "received", "awaitingAnotherCode": true, … } }

Erreurs possibles: not_found, invalid_state, try_later

POST /orders/{id}/cancel

Annuler une commande sans code, 2 minutes après l'achat. L'argent revient aussitôt.

ParamètreObligatoireDescription
id pathouiL'id de la commande renvoyé à l'achat.
curl -X POST -H "Authorization: Bearer $KEY" https://relysms.pro/api/v1/orders/1042/cancel

Réponse

{ "order": { "id": 1042, "status": "cancelled", "refunded": true, … } }

Erreurs possibles: not_found, invalid_state, too_early_to_cancel

GET /webhook

L'adresse du webhook et son secret de signature, ou null.

curl -H "Authorization: Bearer $KEY" https://relysms.pro/api/v1/webhook

Réponse

{ "webhook": { "url": "https://example.com/relysms-hook", "secret": "whsec_…", "createdAt": "2026-10-27T10:00:00.000Z" } }

PUT /webhook

Définir ou changer l'adresse. Le secret est créé une fois et conservé ; rotateSecret en crée un nouveau.

ParamètreObligatoireDescription
url bodyouiAdresse HTTPS de votre serveur. Les adresses privées et locales sont refusées.
rotateSecret bodynontrue — créer un nouveau secret de signature.
curl -X PUT -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{"url":"https://example.com/relysms-hook"}' \
  https://relysms.pro/api/v1/webhook

Réponse

{ "webhook": { "url": "https://example.com/relysms-hook", "secret": "whsec_…", "createdAt": "2026-10-27T10:00:00.000Z" } }

Erreurs possibles: bad_request, invalid_webhook_url

DELETE /webhook

Supprimer le webhook. Les événements pas encore envoyés sont abandonnés.

curl -X DELETE -H "Authorization: Bearer $KEY" https://relysms.pro/api/v1/webhook

Réponse

{ "webhook": null }

POST /webhook/test

Envoyer un événement ping pour vérifier l'adresse et la signature.

curl -X POST -H "Authorization: Bearer $KEY" https://relysms.pro/api/v1/webhook/test

Réponse

{ "delivery": { "id": "cm…" } }

Erreurs possibles: not_found

GET /webhook/deliveries

Les 20 dernières livraisons : événement, statut, tentatives, dernière réponse de votre serveur.

curl -H "Authorization: Bearer $KEY" https://relysms.pro/api/v1/webhook/deliveries

Réponse

{
  "deliveries": [{
    "id": "cm…", "event": "order.code_received", "orderId": 1042,
    "status": "pending", "attempts": 2, "lastHttpStatus": 502, "lastError": "HTTP 502",
    "createdAt": "2026-10-27T10:01:12.000Z", "deliveredAt": null, "nextAttemptAt": "2026-10-27T10:02:22.000Z"
  }]
}

Statuts de commande

Le champ status d'une commande :

  • waiting — Le numéro est à vous et aucun code n'est encore arrivé.
  • received — Un code est arrivé ; il est dans codes. D'autres peuvent arriver tant que la commande est ouverte.
  • finished — Vous avez terminé la commande (ou son temps s'est écoulé après un code).
  • cancelled — Annulée sans code ; refunded vaut true et l'argent est sur le solde.
  • expired — Le temps s'est écoulé sans code ; l'argent est revenu sur le solde.

Erreurs

Une erreur, c'est un statut HTTP et un JSON avec code pour le programme et message pour les humains. Certaines portent des champs en plus (price, cancelableAt, apiMinimum).

{ "error": { "code": "price_above_max", "message": "The price is above maxPrice.", "price": 0.59 } }
missing_key401Aucune clé dans Authorization ni dans X-Api-Key.
invalid_key401La clé est fausse, a été remplacée, ou le compte est bloqué.
bad_request400Le corps ou un paramètre est incorrect ; message précise lequel.
unknown_service400Cet id de service n'existe pas.
unknown_country400Ce code de pays n'existe pas.
idempotency_key_invalid400Idempotency-Key est vide ou dépasse 255 caractères.
invalid_webhook_url400L'adresse du webhook n'est pas en HTTPS, n'est pas une URL ou pointe vers un serveur privé ou local.
insufficient_balance402Le solde est inférieur au prix.
below_api_minimum402Moins de 20 $ de solde — l'API n'achète qu'à partir de 20 $.
account_blocked403Le compte est bloqué — contactez le support.
not_found404Aucune commande avec cet id pour cette clé.
no_numbers409Pas de numéro pour cette paire pour l'instant ; rien n'est débité.
price_above_max409Le prix dépasse maxPrice ; price contient le prix actuel.
too_many_open_orders409Trop de commandes ouvertes — terminez-en ou annulez-en.
invalid_state409Impossible dans ce statut (p. ex. terminer sans code).
too_early_to_cancel409L'annulation est possible à partir de cancelableAt, 2 minutes après l'achat.
idempotency_in_progress409Une requête avec cet Idempotency-Key est encore en cours ; réessayez dans un instant.
idempotency_key_reused422Cet Idempotency-Key a déjà servi pour une autre requête.
rate_limited429Plus de 20 requêtes par seconde ; Retry-After indique quand réessayer.
buying_too_fast429Plus de 5 achats par seconde ; utilisez /orders/batch.
try_later503Échec temporaire — réessayez dans une minute.

Exemples REST

Acheter un numéro, attendre le code, terminer la commande.

Python

import time, uuid, requests

BASE = "https://relysms.pro/api/v1"
S = requests.Session()
S.headers["Authorization"] = "Bearer rs_your_key"

r = S.post(f"{BASE}/orders",
           json={"service": "telegram", "country": "US", "maxPrice": 0.8},
           headers={"Idempotency-Key": str(uuid.uuid4())}, timeout=30)
if r.status_code != 201:
    raise SystemExit(r.json()["error"])   # no_numbers, below_api_minimum, …
order = r.json()["order"]
print("number:", order["phone"])

while order["status"] == "waiting":       # up to 20 minutes
    time.sleep(10)
    order = S.get(f"{BASE}/orders/{order['id']}", timeout=30).json()["order"]

if order["status"] == "received":
    print("code:", order["codes"][-1]["code"])
    S.post(f"{BASE}/orders/{order['id']}/finish", timeout=30)
# "expired" or "cancelled": the money is back on the balance

Node.js

const BASE = "https://relysms.pro/api/v1";
const headers = { Authorization: "Bearer rs_your_key", "Content-Type": "application/json" };

const res = await fetch(`${BASE}/orders`, {
  method: "POST",
  headers: { ...headers, "Idempotency-Key": crypto.randomUUID() },
  body: JSON.stringify({ service: "telegram", country: "US", maxPrice: 0.8 }),
});
if (res.status !== 201) throw new Error((await res.json()).error.code);
let { order } = await res.json();
console.log("number:", order.phone);

while (order.status === "waiting") {
  await new Promise((r) => setTimeout(r, 10_000));
  ({ order } = await (await fetch(`${BASE}/orders/${order.id}`, { headers })).json());
}
if (order.status === "received") {
  console.log("code:", order.codes.at(-1).code);
  await fetch(`${BASE}/orders/${order.id}/finish`, { method: "POST", headers });
}

Exemples

Le cycle complet : acheter un numéro, attendre le code, terminer la commande.

curl

KEY=rs_your_key
BASE=https://relysms.pro/stubs/handler_api.php

curl "$BASE?api_key=$KEY&action=getBalance"
curl "$BASE?api_key=$KEY&action=getNumber&service=tg&country=187&maxPrice=0.80"
# → ACCESS_NUMBER:1042:15550001111
curl "$BASE?api_key=$KEY&action=getStatus&id=1042"
# → STATUS_WAIT_CODE … then STATUS_OK:48213
curl "$BASE?api_key=$KEY&action=setStatus&id=1042&status=6"

Python

import time, requests

BASE = "https://relysms.pro/stubs/handler_api.php"
KEY = "rs_your_key"

def call(action, **params):
    r = requests.get(BASE, params={"api_key": KEY, "action": action, **params}, timeout=30)
    r.raise_for_status()
    return r.text

answer = call("getNumber", service="tg", country="187", maxPrice="0.80")
if not answer.startswith("ACCESS_NUMBER"):
    raise SystemExit(answer)          # NO_NUMBERS, NO_BALANCE, …
_, order_id, phone = answer.split(":")
print("number:", phone)

for _ in range(120):                  # up to 20 minutes, every 10 s
    status = call("getStatus", id=order_id)
    if status.startswith("STATUS_OK:"):
        print("code:", status.split(":", 1)[1])
        call("setStatus", id=order_id, status=6)
        break
    if status == "STATUS_CANCEL":
        break                         # refunded automatically
    time.sleep(10)

Node.js

const BASE = "https://relysms.pro/stubs/handler_api.php";
const KEY = "rs_your_key";

async function call(action, params = {}) {
  const url = new URL(BASE);
  url.search = new URLSearchParams({ api_key: KEY, action, ...params });
  const res = await fetch(url);
  return res.text();
}

const answer = await call("getNumber", { service: "tg", country: "187", maxPrice: "0.80" });
if (!answer.startsWith("ACCESS_NUMBER")) throw new Error(answer);
const [, id, phone] = answer.split(":");
console.log("number:", phone);

for (let i = 0; i < 120; i++) {
  const status = await call("getStatus", { id });
  if (status.startsWith("STATUS_OK:")) {
    console.log("code:", status.slice("STATUS_OK:".length));
    await call("setStatus", { id, status: "6" });
    break;
  }
  if (status === "STATUS_CANCEL") break; // refunded automatically
  await new Promise((r) => setTimeout(r, 10_000));
}

Questions

Mon logiciel utilisait un autre service d'activation. Que dois-je changer ?

L'adresse du serveur en https://relysms.pro/stubs/handler_api.php et la clé par celle de votre compte. Les codes des services et des pays restent les mêmes.

Pourquoi NO_BALANCE alors que j'ai du solde ?

Les achats par l'API exigent un solde de 20 $ ou plus. Le compte et la Mini App n'ont pas ce seuil.

Et l'argent, si le code n'arrive pas ?

Il revient tout seul sur votre solde à la fin de la fenêtre, ou aussitôt si vous annulez après 2 minutes.

Puis-je recevoir un second code sur le même numéro ?

Oui, tant que la fenêtre est ouverte : setStatus=3, puis à nouveau getStatus.

Y a-t-il un mode test ?

Non : tous les achats sont réels. Commencez par une paire bon marché et testez votre flux sur un numéro.

Ma clé a fuité. Que faire ?

Compte → Solde → API → En émettre une nouvelle. L'ancienne cesse de fonctionner aussitôt.

Pour les assistants IA

La documentation complète en un seul texte pour ChatGPT, Claude et d'autres modèles se trouve sur /fr/developers.md, et une carte courte sur /llms.txt. Donnez le lien au modèle et demandez-lui de connecter RelySMS à votre code.

Lis https://relysms.pro/fr/developers.md et connecte RelySMS à mon script.

developers.md · llms.txt