# CySmS Reseller API

Documentation publique (aucun compte requis pour la lire).
HTML: https://cysms.net/api-docs
Index LLM: https://cysms.net/llms.txt

CySmS fournit des numéros virtuels pour la réception de SMS OTP. Un achat API suit **le même parcours** qu’un achat dans l’application : contrôles CySmS (maintenance, solde) puis débit du **prix de vente CySmS**, pas le coût fournisseur.

Ne jamais exposer la clé API (`cs_live_...`) dans une app mobile ou une page web. Appeler l’API depuis un backend.

## Base URL

- REST JSON: `https://cysms.net/api/reseller`
- Stubs (protocole SMS-Activate): `https://cysms.net/stubs/handler_api.php`

En local: `http://localhost:3000/api/reseller`

## Authentification

Chaque requête doit inclure la clé.

1. Header (recommandé): `X-Api-Key: cs_live_xxxxxxxx`
2. Bearer: `Authorization: Bearer cs_live_xxxxxxxx`
3. Query: `?api_key=cs_live_xxxxxxxx` (compatibilité Stubs; déconseillé en REST car les URL peuvent être journalisées)

## Provider (gamme) & Smart Failover

CySmS dispose d'un système de bascule automatique intelligent garantissant une continuité de service maximale :
- `auto` (recommandé) — Tente le Service V2 en priorité, puis le Service V1 en secours si la première gamme ne peut pas servir la demande.
- `v2` — Tente le Service V2 en priorité, puis peut basculer sur le Service V1.
- `v1` — Tente le Service V1 en priorité, puis peut basculer sur le Service V2.

`provider` exprime une priorité de routage, pas une garantie de gamme. La réponse de `buyNumber` précise la gamme utilisée dans `serviceType` et `providerName`.

Noms de services : vous pouvez utiliser indifféremment le code du catalogue (ex: `wa`, `tg`, `go`) ou le nom complet (ex: `whatsapp`, `telegram`, `google`). Les codes du catalogue sont uniques; utilisez la colonne Code sur `/api-docs`.

Le catalogue sans pays ne donne pas de prix ni de stock. Avec `country`, choisissez `provider=v1` ou `provider=v2` pour interroger la gamme voulue. Sans gamme précisée, ou avec `provider=auto`, le catalogue affiche les tarifs V2; l'achat peut ensuite basculer vers V1 et avoir un tarif différent. Dans la réponse pays, `count` est le nombre de services listés, `availableCount` le nombre avec stock, et chaque ligne indique `available`, `price` et `count`. Si `pricing` vaut `temporarily_unavailable`, la gamme n'a pas répondu : ne traitez pas l'absence de stock comme une indisponibilité certaine. Ces données sont indicatives : le prix réel débité est calculé au moment de `buyNumber` et renvoyé dans `price`, `sellingPrice` et `chargedAmount`.

## Endpoints REST

Toujours lire `success` dans le JSON, pas seulement le code HTTP. Pour axios: `validateStatus: () => true`.

### getBalance

`GET /api/reseller?action=getBalance`

Réponse: `{ "success": true, "credits": 12.50 }`

### getServices

`GET /api/reseller?action=getServices&country=77&provider=v2`

Tarifs dynamiques en direct et stocks disponibles selon pays et gamme.

Pour une requête avec pays, `count` désigne le nombre de lignes du catalogue retournées et `availableCount` le nombre de services avec stock. `supportsV1` et `supportsV2` indiquent les fournisseurs vers lesquels CySmS peut router; ils ne garantissent pas de stock. Le catalogue peut contenir des lignes avec `available: false`, `price: null` et `count: 0`. Vérifiez aussi `pricing`: `temporarily_unavailable` signifie que la lecture du fournisseur a échoué.

### getCountries

`GET /api/reseller?action=getCountries`

La liste et son nombre de pays sont renvoyés par l'API et peuvent évoluer. Exemple: `77` = France, `27` = Côte d’Ivoire, `12` = États-Unis, `10` = Vietnam.

### buyNumber

`POST /api/reseller?action=buyNumber`

Body JSON:

```json
{ "service": "wa", "country": "77", "provider": "auto" }
```

Les paramètres `service`, `country` et `provider` peuvent aussi être passés en query string.

Succès HTTP 200:

```json
{
  "success": true,
  "orderId": "CY-123456",
  "phone": "+336...",
  "service": "wa",
  "country": "77",
  "countryCode": "77",
  "countryName": "France",
  "countryPrefix": "+33",
  "countryIso": "FR",
  "countryFlag": "🇫🇷",
  "price": 1.20,
  "sellingPrice": 1.20,
  "chargedAmount": 1.20,
  "provider": "Service V2 (CySmS Premium)",
  "providerName": "Service V2",
  "serviceType": "v2",
  "status": "PENDING",
  "expiresAt": 1756801200000,
  "createdAt": 1756800000000
}
```

Conservez et réutilisez `orderId` exactement tel que renvoyé, préfixe `CY-` compris. Les champs `price`, `sellingPrice` et `chargedAmount` sont le prix de vente CySmS débité. La marge active du fournisseur, définie dans le panneau admin, est appliquée côté serveur; l'appelant ne peut pas imposer son prix. Le coût fournisseur n'est pas exposé.

Échecs métier:

| HTTP | error | Signification |
|------|-------|----------------|
| 200 | NO_NUMBERS | Aucun fournisseur n'a pu servir la demande (stock ou indisponibilité) |
| 400 | MISSING_SERVICE / MISSING_COUNTRY | Paramètre manquant |
| 400 | BAD_SERVICE / WRONG_COUNTRY / BAD_PROVIDER | Service, pays ou stratégie fournisseur invalide |
| 400 | MISSING_ORDER_ID / BAD_ACTION | Identifiant de commande manquant ou action inconnue |
| 401 | BAD_KEY | Clé absente ou invalide |
| 403 | ACCOUNT_BLOCKED / API_BLOCKED | Compte ou accès API suspendu |
| 409 | NO_BALANCE | Solde insuffisant |
| 503 | MAINTENANCE | Gamme temporairement indisponible |
| 503/504 | PROVIDER_UNAVAILABLE | Statut temporairement indisponible; conserver la commande et réessayer `getStatus` |
| 404 | ORDER_NOT_FOUND | Commande inconnue pour cette clé API |
| 4xx/5xx | CANCEL_FAILED | Annulation refusée ou erreur fournisseur; aucun remboursement n'est confirmé |
| 503/504 | CANCEL_PENDING | Réponse d'annulation incertaine; appelez getStatus avant de réessayer |
| 409 | CANCEL_TOO_EARLY | Attendez deux minutes après l'achat avant d'annuler |
| 500 | INTERNAL_ERROR | Erreur interne; ne présumez pas le résultat d'une mutation et vérifiez son état avant de réessayer |

### getStatus

`GET /api/reseller?action=getStatus&orderId=CY-123456`

Selon la gamme, `status` peut être `PENDING`, `RECEIVED`, `CANCELED`, `TIMEOUT`, `FINISHED` ou `BANNED`. CySmS normalise toute expiration confirmée en `CANCELED`. Traitez les statuts terminaux séparément de `PENDING` et `RECEIVED`.

Les champs `sms` et `code` contiennent le message et l'OTP extrait. Si `code` est présent, traitez-le avant le statut : certaines activations V1 peuvent déjà être `FINISHED` tout en conservant le code reçu.

### cancelOrder

`POST /api/reseller?action=cancelOrder`

Body: `{ "orderId": "CY-123456" }`

Rembourse le prix CySmS débité si le fournisseur confirme l'annulation. Une annulation peut être refusée si le SMS est déjà reçu ou si le fournisseur impose un délai minimum. La réponse JSON contient `refunded`, le montant recrédité.

## Webhooks

Jusqu’à 3 URL HTTPS. HMAC SHA-256 dans `X-CySms-Signature`.

Chaque événement d'activation est déclenché une seule fois par commande et par type. `webhook.test` est envoyé à chaque appel de test. Les deux tentatives éventuelles d'une même livraison réutilisent `X-CySms-Delivery`.

Événements: `activation.created`, `activation.sms_received`, `activation.canceled`, `activation.expired`, `webhook.test`.

Actions: `getWebhook`, `setWebhook`, `testWebhook`, `deleteWebhook`.

- `POST ?action=setWebhook` avec `{ "urls": ["https://votre-site.example/webhook"] }` enregistre jusqu'à 3 URL et renvoie le secret `whsec_...`.
- `GET ?action=getWebhook` renvoie les URL et le secret actuels.
- `POST ?action=testWebhook` teste les URL enregistrées; le champ optionnel `url` permet d'en tester une seule.
- `POST ?action=deleteWebhook` supprime toutes les URL enregistrées sans révoquer le secret.

CySmS considère uniquement HTTP 200 comme un accusé de réception. Le délai est de 3 secondes par tentative; en cas d'échec réseau, de timeout ou de réponse non-200, une seconde et dernière tentative est effectuée après 1 seconde. Vérifiez `X-CySms-Signature` sur le corps JSON brut, avant son parsing.

## Stubs SMS-Activate

`GET /stubs/handler_api.php?api_key=...&action=getBalance`
Réponse texte: `ACCESS_BALANCE:12.50`

Achat: `action=getNumber&service=wa&country=77`
Réponse: `ACCESS_NUMBER:CY-123456:phone`

Statut: `action=getStatus&id=CY-123456`
Annulation: `action=setStatus&id=CY-123456&status=8`

`ACCESS_CANCEL` confirme une annulation et un remboursement effectués. En cas de refus, l'API renvoie `EARLY_CANCEL_DENIED` si le fournisseur impose un délai, ou `ERROR_SQL` pour une autre erreur; ne créditez pas le compte client dans votre système sur ces réponses.

## Cycle recommandé

1. `buyNumber`
2. Polling `getStatus` toutes les 3–5 s (max 15–20 min) **ou** webhook `activation.sms_received`
3. Si timeout: `cancelOrder`

Après `cancelOrder`, confirmez toujours `success === true` et lisez `refunded`. En format Stubs, seul `ACCESS_CANCEL` confirme l’annulation et le remboursement.

## Services courants

| code | service |
|------|---------|
| wa | WhatsApp |
| tg | Telegram |
| go | Google / Gmail |
| ig | Instagram |
| th | Threads |
| tk | TikTok |
| fb | Facebook |
| tw | Twitter / X |
| ot | Autre |

### Codes d'API uniques et services corrigés

Les codes du catalogue sont maintenant uniques. Pour ces services, utilisez le code indiqué afin d'éviter toute ambiguïté :

| Code API | Service |
|----------|---------|
| sc | Snapchat |
| soundcloud | SoundCloud |
| gh | Grab |
| github | GitHub |
| ma | Mail.ru |
| mercari | Mercari |
| nt | Nintendo |
| neteller | Neteller |
| ok | Odnoklassniki |
| okcupid | OkCupid |
| sk | Skype |
| skrill | Skrill |
| st | Stripe |
| steam | Steam |
| ub | Uber / UberEats |
| ubisoft | Ubisoft Connect |
| wb | Weibo |
| wildberries | Wildberries |
| bl | Bigo Live |
| bolt | Bolt |
| al | Alibaba / 1688 |
| aliexpress | AliExpress |

La liste complète et filtrable est sur /api-docs. Un tarif ou stock disponible reste lié au pays et au fournisseur; consultez getServices avant l'achat. Les anciens codes courts gardent leur correspondance historique côté service principal; mettez à jour les intégrations qui utilisaient le code d'une autre ligne de ces paires.

## Prompt pour assistant IA

Intègre l’API CySmS (numéros virtuels OTP). Base: `https://cysms.net/api/reseller`. Auth: `X-Api-Key`. Achat: POST `buyNumber` avec `{service, country, provider}`. Identique à l’app: débit du prix de vente CySmS. Succès: `success: true` + `orderId` + `phone`. Échec stock: HTTP 200 `NO_NUMBERS`. Solde: HTTP 409 `NO_BALANCE`. Poll `getStatus` ou webhook. Timeout → `cancelOrder`. Spec complète: https://cysms.net/docs/api.md
