API revendeur et sous-comptes

Gérez vos propres clients depuis votre plateforme : créez un sous-compte par client, donnez-lui des SMS depuis votre solde, créez ses clés d’envoi et suivez sa consommation au prix que vous lui facturez.

Deux types de clés

  • Votre clé revendeur, avec les droits sub_accounts:read et sub_accounts:write, gère vos sous-comptes. Elle n’envoie pas de SMS pour eux.
  • Chaque sous-compte a ses propres clés API. Elles envoient avec le solde et les Sender IDs de ce sous-compte, exactement comme une clé ordinaire, via POST /v1/sms/send.
  • Une clé de sous-compte ne peut jamais gérer d’autres sous-comptes, et une clé fuitée n’expose qu’un seul de vos clients.
  • Les droits sub_accounts ne sont jamais attribués par défaut : créez une clé revendeur dédiée depuis Paramètres, profil « Revendeur : gestion des sous-comptes ».

Endpoints

MéthodeCheminDroitRôle
GET/v1/sub-accountssub_accounts:readSous-comptes, soldes, consommation et montant au prix de revente sur une période (30 jours par défaut, 400 au plus).
POST/v1/sub-accountssub_accounts:writeCréer un sous-compte ; la référence rend l’appel idempotent.
PATCH/v1/sub-accounts/{id}sub_accounts:writeSuspendre, réactiver, changer le prix de revente ou l’alerte de solde (un seul changement par appel).
POST/v1/sub-accounts/{id}/transferssub_accounts:writeDonner (allocation) ou reprendre (reclaim) des SMS ; Idempotency-Key obligatoire.
GET/v1/sub-accounts/{id}/statementsub_accounts:readRelevé jour par jour (fuseau Africa/Kinshasa).
GET/v1/sub-accounts/{id}/api-keyssub_accounts:readClés actives du sous-compte (masquées).
POST/v1/sub-accounts/{id}/api-keyssub_accounts:writeCréer une clé d’envoi pour le sous-compte ; le secret est affiché une fois.
DELETE/v1/sub-accounts/{id}/api-keys/{apiKeyId}sub_accounts:writeRévoquer une clé du sous-compte.
GET/v1/sub-accounts/{id}/messagessub_accounts:readSMS du sous-compte avec leur statut de livraison (DLR), filtres période, statut et numéro.
GET/v1/sub-accounts/{id}/webhookssub_accounts:readWebhooks DLR configurés pour le sous-compte.
POST/v1/sub-accounts/{id}/webhookssub_accounts:writeRecevoir les événements de livraison du sous-compte ; secret de signature affiché une fois.
DELETE/v1/sub-accounts/{id}/webhooks/{webhookEndpointId}sub_accounts:writeDésactiver un webhook du sous-compte.
GET/v1/sub-accounts/{id}/sender-idssub_accounts:readSender IDs du sous-compte.
POST/v1/sub-accounts/{id}/sender-idssub_accounts:writeDemander un Sender ID pour le client final ; vérifié par Coussema.

Créer un sous-compte

Appelez cet endpoint depuis votre serveur, jamais depuis un navigateur. Le prix de revente sert à vos relevés ; il ne change pas ce que vous payez à Coussema.

javascript
const resellerKey = process.env.COUSSEMA_RESELLER_API_KEY ?? '';
const response = await fetch('https://api.coussema.com/v1/sub-accounts', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${resellerKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    name: 'Client A',
    reference: 'client-a', // votre identifiant, qui sert aussi de clé d'idempotence
    resale_price_usd: 0.035,
  }),
});

const { outcome, sub_account_id } = await response.json();
// outcome = 'created' (201) ou 'existing' (200) si la référence existe déjà

Donner ou reprendre des SMS

Un transfert déplace des SMS entre votre solde et celui d’un sous-compte, sans création ni perte. Vous ne pouvez reprendre que des SMS que vous lui avez donnés et qu’il n’a pas utilisés.

Réutilisez la même Idempotency-Key si la réponse ne vous parvient pas : le transfert ne sera jamais appliqué deux fois.

javascript
const response = await fetch(`https://api.coussema.com/v1/sub-accounts/${subAccountId}/transfers`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${resellerKey}`,
    'Content-Type': 'application/json',
    'Idempotency-Key': `allocation-${invoiceId}`, // obligatoire, stable entre deux essais
  },
  body: JSON.stringify({ kind: 'allocation', units: 10000 }),
});

const transfer = await response.json();
// 201 : transfert appliqué ; 200 : rejeu du même transfert, rien n’est appliqué deux fois
console.log(transfer.reseller_remaining_units, transfer.sub_account_remaining_units);

Créer la clé d’envoi d’un client

Le sous-compte envoie uniquement avec ses propres Sender IDs approuvés et ne peut pas envoyer si son solde est vide.

javascript
const response = await fetch(`https://api.coussema.com/v1/sub-accounts/${subAccountId}/api-keys`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${resellerKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ name: 'Production', scopes: ['account:read', 'sender_ids:read', 'sms:send'] }),
});

const { apiKey } = await response.json();
// apiKey.plainTextKey n’est affichée qu’une fois : stockez-la côté serveur pour ce client.

Suivre la livraison (DLR)

Créez un webhook par sous-compte avec votre clé revendeur, en pointant tous vos sous-comptes vers la même URL : chaque événement contient organization_id, qui est l’identifiant du sous-compte, et client_reference si vous l’avez fourni à l’envoi. Les événements sont signés comme tout webhook Coussema (voir le guide Webhooks).

Pour un rapprochement ou une reprise, GET /v1/sub-accounts/{id}/messages liste les SMS avec leur statut de livraison, sans identifiant fournisseur ni erreur brute.

bash
curl -X POST "https://api.coussema.com/v1/sub-accounts/$SUB_ACCOUNT_ID/webhooks" \
  -H "Authorization: Bearer $COUSSEMA_RESELLER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://votre-plateforme.example/webhooks/coussema","subscribed_events":["message.sent","message.delivered","message.failed"]}'

Être notifié des transferts

Abonnez un webhook de votre propre compte revendeur à l’événement sub_account.transfer.created avec POST /v1/webhooks. La clé utilisée doit avoir les droits webhooks:write et sub_accounts:read.

Chaque transfert enregistré envoie un seul événement, même si vous rejouez la même Idempotency-Key. Il contient l’identifiant du transfert, le sous-compte, le sens (allocation ou reclaim), le nombre de SMS et les soldes du revendeur et du sous-compte juste après le transfert.

bash
curl -X POST "https://api.coussema.com/v1/webhooks" \
  -H "Authorization: Bearer $COUSSEMA_RESELLER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://votre-plateforme.example/webhooks/coussema","subscribed_events":["sub_account.transfer.created"]}'

Alertes de solde

Fixez un seuil en SMS pour chaque sous-compte avec PATCH /v1/sub-accounts/{id} et le champ low_balance_threshold_units (null pour désactiver). Le seuil apparaît dans la liste des sous-comptes.

Quand le solde passe sous le seuil, vous recevez un seul email et l’événement sub_account.balance.low (abonnez-y votre webhook revendeur avec une clé ayant sub_accounts:read). L’alerte se réarme quand le solde repasse au-dessus du seuil, par exemple après un transfert.

Chaque compte peut aussi régler sa propre alerte depuis la page Quota SMS et recevoir l’événement balance.low.

bash
curl -X PATCH "https://api.coussema.com/v1/sub-accounts/$SUB_ACCOUNT_ID" \
  -H "Authorization: Bearer $COUSSEMA_RESELLER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"low_balance_threshold_units":1000}'

Sender IDs des clients

  • Chaque sous-compte envoie uniquement avec ses propres Sender IDs approuvés ; ceux du revendeur ne sont pas partagés.
  • Demandez le Sender ID au nom du client final (sa marque, son activité, un exemple de SMS) avec POST /v1/sub-accounts/{id}/sender-ids ou depuis l’espace revendeur.
  • Coussema vérifie chaque demande avant approbation. Le sous-compte doit disposer d’un solde payé : transférez-lui des SMS avant la demande.

Relevé d’un sous-compte

Chaque SMS est valorisé au prix de revente en vigueur au moment de sa facturation. Les SMS consommés avant que vous fixiez un prix apparaissent en unpriced_units.

bash
curl "https://api.coussema.com/v1/sub-accounts/$SUB_ACCOUNT_ID/statement?from=2026-10-01T00:00:00%2B01:00&to=2026-11-01T00:00:00%2B01:00" \
  -H "Authorization: Bearer $COUSSEMA_RESELLER_API_KEY"

Erreurs propres aux revendeurs

HTTPCodeSignification
403reseller_requiredLa clé n’appartient pas à un compte revendeur.
403reseller_manager_requiredLa clé n’a pas le droit sub_accounts:write.
403reseller_not_activeVotre compte revendeur est suspendu.
404sub_account_not_foundCe sous-compte n’existe pas ou ne vous appartient pas.
409insufficient_reseller_balanceVotre solde ne couvre pas ce transfert.
409insufficient_sub_account_balanceLe sous-compte n’a pas assez de SMS que vous lui avez donnés et qu’il n’a pas utilisés.
409sub_account_status_lockedSuspension décidée par Coussema : contactez le support.
409sub_account_limit_reachedNombre maximal de sous-comptes atteint.
409idempotency_key_conflictCette Idempotency-Key a déjà servi pour un autre transfert.