Docs publiquesPartner-readyCloud + Connector

Intégrez WhatsApp dans votre SaaS sans reconstruire toute la plomberie technique

L'API Partner SMSV permet aux éditeurs SaaS, CRM, ERP et marketplaces d'offrir un vrai module WhatsApp en marque blanche. Chaque client connecte son propre numéro, vous gardez l'expérience dans votre produit, et SMSV gère l'infrastructure d'envoi, les webhooks et l'isolation multi-tenant.

Pour tester rapidement, créez un compte partenaire puis suivez le quick start pour connecter un premier client.

Multi-tenant

Une Partner Key pour piloter plusieurs clients, avec séparation claire des organisations et des numéros.

Prêt pour les devs

SDKs JS, Python et PHP, exemples curl et parcours d'intégration bout en bout.

Cloud ou local

Mode Cloud si vous voulez aller vite, Connector si vous voulez davantage de contrôle d'hébergement.

Parcours produit clair: org -> sender -> messages
Chaque client garde son propre numéro WhatsApp
Chemin documenté jusqu'à la mise en prod

Architecture

Le Partner API repose sur deux couches simples pour garder une gouvernance multi-tenant propre :

Couche 1 — Partner Key

X-Partner-Key: pk_cloud_xxx

Gestion des senders (créer, QR, statut, supprimer) et envoi de messages via Partner Cloud.

Couche 2 — App API Key

X-API-Key: sp_live_xxx

Chaque app créée via Partner reçoit sa propre API key pour contacts, campagnes, templates, batch.

Votre SaaS Partner API SMSV Cloud WhatsApp Client final

Authentification

Partner Key (gestion multi-tenant)

Utilisée pour créer/gérer les senders WhatsApp de vos clients et envoyer des messages via le Partner Cloud.

curl -H "X-Partner-Key: pk_cloud_xxxxx" \
  https://smsv.tech/api/v1/partner/cloud/senders

Obtenez votre Partner Key dans Dashboard → Partenaire → Vue d'ensemble.

App API Key (par client)

Chaque app créée via Partner reçoit une API key sp_live_xxx. Utilisez-la pour les contacts, campagnes, templates et envois directs.

curl -H "X-API-Key: sp_live_xxxxx" \
  https://smsv.tech/api/v1/text \
  -d '{"to": "+22370000000", "text": "Bonjour !"}'

Quick Start

Voici le chemin minimal pour afficher le QR dans votre interface, connecter le numéro du client, puis commencer les envois depuis votre application.

1

Activer le mode Partner

Dashboard → Paramètres → Partenaire → Activer. Vous recevez votre pk_cloud_xxx.

2

Créer un sender pour votre client

POST /v1/partner/cloud/senders avec l'ID unique de votre client (externalOrgId).

3

Afficher le QR code

GET /v1/partner/cloud/senders/{orgId}/qr — affichez le QR dans votre UI pour que votre client scanne.

4

Attendre la connexion

Poll GET /v1/partner/cloud/senders/{orgId}/status toutes les 3s jusqu'à status = 'ready'.

5

Envoyer des messages

POST /v1/partner/cloud/messages/send — votre client envoie des messages WhatsApp depuis votre app.

Exemple complet — cURL
# 1. Créer un sender
curl -X POST "https://smsv.tech/api/v1/partner/cloud/senders" \
  -H "X-Partner-Key: pk_cloud_xxxxx" \
  -H "Content-Type: application/json" \
  -d '{"externalOrgId": "client-123", "displayName": "Boutique Awa"}'

# 2. Reconnecter pour démarrer la session
curl -X POST "https://smsv.tech/api/v1/partner/cloud/senders/client-123/reconnect" \
  -H "X-Partner-Key: pk_cloud_xxxxx"

# 3. Récupérer le QR code (attendre 2s après reconnect)
curl "https://smsv.tech/api/v1/partner/cloud/senders/client-123/qr" \
  -H "X-Partner-Key: pk_cloud_xxxxx"

# 4. Vérifier le statut (poll toutes les 3s)
curl "https://smsv.tech/api/v1/partner/cloud/senders/client-123/status" \
  -H "X-Partner-Key: pk_cloud_xxxxx"

# 5. Envoyer un message (quand status = ready)
curl -X POST "https://smsv.tech/api/v1/partner/cloud/messages/send" \
  -H "X-Partner-Key: pk_cloud_xxxxx" \
  -H "Content-Type: application/json" \
  -d '{"externalOrgId": "client-123", "to": "+22370000000", "text": "Bonjour !"}'

Objectif recommandé pour votre première intégration

Ouvrez un compte partenaire, connectez un premier sender de test, affichez le QR dans votre UI, puis validez un envoi de message de bout en bout avant de passer en production.

Partner Cloud API

Base URL : https://smsv.tech/api/v1/partner/cloud

Auth : X-Partner-Key: pk_cloud_xxx

Gestion des Senders

Un "sender" est une session WhatsApp liée à un de vos clients. Chaque client est identifié par son externalOrgId (un ID unique dans votre système).

GET/v1/partner/cloud/senders
X-Partner-Key

Lister tous les senders. Filtrer par ownerExternalOrgId en query param.

Response

{
  "success": true,
  "data": [
    {
      "externalOrgId": "client-123",
      "status": "ready",
      "phoneNumber": "+22370000000",
      "displayName": "Boutique Awa",
      "connectedAt": "2026-03-10T12:00:00Z"
    }
  ]
}
POST/v1/partner/cloud/senders
X-Partner-Key

Créer un sender WhatsApp pour un client.

Request Body

{
  "externalOrgId": "client-123",
  "displayName": "Boutique Awa"
}

Response

{
  "success": true,
  "data": {
    "externalOrgId": "client-123",
    "senderId": "sender_abc123",
    "status": "INITIALIZING"
  }
}
GET/v1/partner/cloud/senders/{orgId}
X-Partner-Key

Récupérer les détails d'un sender par son externalOrgId.

Response

{
  "success": true,
  "data": {
    "externalOrgId": "client-123",
    "status": "ready",
    "phoneNumber": "+22370000000",
    "connectedAt": "2026-03-10T12:00:00Z"
  }
}
GET/v1/partner/cloud/senders/{orgId}/qr
X-Partner-Key

Récupérer le QR code WhatsApp à afficher dans votre UI.

Response

{
  "success": true,
  "data": {
    "status": "qr_ready",
    "qrCode": "data:image/png;base64,iVBOR...",
    "expiresIn": 60
  }
}
GET/v1/partner/cloud/senders/{orgId}/status
X-Partner-Key

Vérifier le statut de connexion. Poll toutes les 3s jusqu'à 'ready' ou 'connected'.

Response

{
  "success": true,
  "data": {
    "externalOrgId": "client-123",
    "status": "ready",
    "phoneNumber": "+22370000000",
    "connectedAt": "2026-03-10T12:00:00Z"
  }
}
POST/v1/partner/cloud/senders/{orgId}/reconnect
X-Partner-Key

Reconnecter un sender déconnecté. Nécessaire avant de récupérer un nouveau QR.

Response

{ "success": true }
DELETE/v1/partner/cloud/senders/{orgId}
X-Partner-Key

Supprimer un sender et déconnecter la session WhatsApp.

Response

{ "success": true }

Référence des statuts

not_initializedPas de session activeAppeler /reconnect
initializingSession en cours de démarrageAttendre + poll
qr_readyQR code disponibleAfficher QR + poll /status
connectingQR scanné, connexion en coursAttendre + poll
readyConnecté et prêt à envoyerEnvoyer des messages
connectedAlias de readyEnvoyer des messages
disconnectedSession perdueAppeler /reconnect

Messagerie (Partner Cloud)

POST/v1/partner/cloud/messages/send
X-Partner-Key

Envoyer un message texte via le sender d'un client.

Request Body

{
  "externalOrgId": "client-123",
  "to": "+22370000000",
  "text": "Bonjour depuis votre app !"
}

Response

{
  "success": true,
  "messageId": "msg_abc123",
  "status": "queued"
}
POST/v1/partner/cloud/messages/send-document
X-Partner-Key

Envoyer un document (PDF, Excel, etc.).

Request Body

{
  "externalOrgId": "client-123",
  "to": "+22370000000",
  "documentUrl": "https://example.com/facture.pdf",
  "filename": "Facture-001.pdf",
  "caption": "Votre facture"
}

Response

{
  "success": true,
  "messageId": "msg_def456",
  "status": "queued"
}
POST/v1/partner/cloud/messages/send-image
X-Partner-Key

Envoyer une image avec légende optionnelle.

Request Body

{
  "externalOrgId": "client-123",
  "to": "+22370000000",
  "imageUrl": "https://example.com/photo.jpg",
  "caption": "Photo du produit"
}

Response

{
  "success": true,
  "messageId": "msg_ghi789",
  "status": "queued"
}
POST/v1/partner/cloud/agent/chat
X-Partner-Key

Agent IA conversationnel avec catalogue produit.

Request Body

{
  "externalOrgId": "client-123",
  "customerPhone": "+22370000000",
  "message": "Je cherche un produit",
  "products": [
    { "id": "p1", "name": "T-shirt", "price": 5000 }
  ]
}

Response

{
  "success": true,
  "response": "Nous avons un T-shirt à 5 000 FCFA.",
  "actions": ["product_search"]
}

App API (par client)

Chaque app créée via le Partner API reçoit sa propre X-API-Key (sp_live_xxx). Utilisez-la pour accéder aux endpoints ci-dessous, scoped à cette app.

Base URL : https://smsv.tech/api

Auth : X-API-Key: sp_live_xxx

GET/v1/me
X-API-Key

Informations sur l'app : plan, limites, senders actifs.

Response

{
  "id": "app_xxx",
  "name": "Boutique Awa",
  "plan": "STARTER",
  "limits": {
    "messagesPerMonth": 2000,
    "accounts": 2
  },
  "senders": [
    { "id": "s1", "phoneNumber": "+22370000000", "status": "ready" }
  ]
}

Messagerie (App API)

Endpoints d'envoi direct, utilisables avec la clé API de chaque app.

POST/v1/text
X-API-Key

Envoyer un message texte.

Request Body

{
  "to": "+22370000000",
  "text": "Bonjour !",
  "senderId": "optional-sender-id"
}

Response

{
  "success": true,
  "messageId": "msg_xxx",
  "status": "queued"
}
POST/v1/image
X-API-Key

Envoyer une image.

Request Body

{
  "to": "+22370000000",
  "imageUrl": "https://example.com/photo.jpg",
  "caption": "Photo"
}

Response

{ "success": true, "messageId": "msg_xxx" }
POST/v1/document
X-API-Key

Envoyer un document.

Request Body

{
  "to": "+22370000000",
  "documentUrl": "https://example.com/file.pdf",
  "filename": "file.pdf"
}

Response

{ "success": true, "messageId": "msg_xxx" }
POST/v1/template
X-API-Key

Envoyer un message template (Meta Cloud API).

Request Body

{
  "to": "+22370000000",
  "templateSlug": "order_confirmation",
  "variables": { "name": "Awa", "order": "#1234" },
  "language": "fr"
}

Response

{ "success": true, "messageId": "msg_xxx" }
POST/v1/audio
X-API-Key

Envoyer un fichier audio.

Request Body

{
  "to": "+22370000000",
  "audioUrl": "https://example.com/audio.mp3"
}

Response

{ "success": true, "messageId": "msg_xxx" }
POST/v1/video
X-API-Key

Envoyer une vidéo.

Request Body

{
  "to": "+22370000000",
  "videoUrl": "https://example.com/video.mp4",
  "caption": "Vidéo promo"
}

Response

{ "success": true, "messageId": "msg_xxx" }
POST/v1/location
X-API-Key

Envoyer une localisation GPS.

Request Body

{
  "to": "+22370000000",
  "latitude": 12.6392,
  "longitude": -8.0029,
  "name": "Bamako, Mali"
}

Response

{ "success": true, "messageId": "msg_xxx" }

Contacts

GET/v1/contacts
X-API-Key

Lister les contacts. Supporte pagination (?page=1&limit=50) et recherche (?search=awa).

Response

{
  "contacts": [
    { "id": "c1", "phone": "+22370000000", "name": "Awa", "tags": ["vip"] }
  ],
  "total": 150,
  "page": 1,
  "limit": 50
}
POST/v1/contacts
X-API-Key

Créer un contact.

Request Body

{
  "phone": "+22370000000",
  "name": "Awa Diallo",
  "email": "awa@example.com",
  "tags": ["client", "vip"]
}

Response

{
  "id": "c_xxx",
  "phone": "+22370000000",
  "name": "Awa Diallo"
}
GET/v1/contacts/{id}
X-API-Key

Récupérer un contact par ID.

Response

{
  "id": "c_xxx",
  "phone": "+22370000000",
  "name": "Awa Diallo",
  "tags": ["client", "vip"],
  "createdAt": "2026-01-15T10:00:00Z"
}
PUT/v1/contacts/{id}
X-API-Key

Mettre à jour un contact.

Request Body

{
  "name": "Awa Diallo-Traoré",
  "tags": ["client", "vip", "premium"]
}

Response

{ "id": "c_xxx", "name": "Awa Diallo-Traoré" }
DELETE/v1/contacts/{id}
X-API-Key

Supprimer un contact.

Response

{ "success": true }
POST/v1/contacts/import
X-API-Key

Importer des contacts en masse (CSV ou JSON).

Request Body

{
  "contacts": [
    { "phone": "+22370000001", "name": "Contact 1" },
    { "phone": "+22370000002", "name": "Contact 2" }
  ]
}

Response

{
  "imported": 2,
  "duplicates": 0,
  "errors": 0
}

Campagnes

GET/v1/campaigns
X-API-Key

Lister les campagnes. Filtrer par statut (?status=DRAFT).

Response

{
  "campaigns": [
    {
      "id": "camp_xxx",
      "name": "Promo Ramadan",
      "status": "COMPLETED",
      "audienceCount": 500,
      "sentCount": 498
    }
  ],
  "total": 12
}
POST/v1/campaigns
X-API-Key

Créer une campagne.

Request Body

{
  "name": "Promo Ramadan",
  "messageContent": "Profitez de -20% !",
  "segmentTags": ["client"],
  "scheduledAt": "2026-03-15T08:00:00Z"
}

Response

{
  "id": "camp_xxx",
  "name": "Promo Ramadan",
  "status": "DRAFT"
}
POST/v1/campaigns/{id}/send
X-API-Key

Lancer l'envoi d'une campagne.

Response

{ "success": true, "status": "RUNNING" }
POST/v1/campaigns/{id}/pause
X-API-Key

Mettre en pause une campagne en cours.

Response

{ "success": true, "status": "PAUSED" }
POST/v1/campaigns/{id}/resume
X-API-Key

Reprendre une campagne en pause.

Response

{ "success": true, "status": "RUNNING" }
GET/v1/campaigns/{id}/stats
X-API-Key

Statistiques d'une campagne.

Response

{
  "audienceCount": 500,
  "sentCount": 498,
  "deliveredCount": 490,
  "readCount": 320,
  "failedCount": 2
}

Templates

GET/api/templates
X-API-Key

Lister les templates de l'app.

Response

[
  {
    "id": "t_xxx",
    "slug": "order_confirmation",
    "name": "Confirmation de commande",
    "content": "Bonjour {{name}}, commande {{order}} confirmée.",
    "variables": ["name", "order"]
  }
]
POST/api/templates
X-API-Key

Créer un template.

Request Body

{
  "name": "Confirmation de commande",
  "slug": "order_confirmation",
  "content": "Bonjour {{name}}, votre commande {{order}} est confirmée.",
  "variables": ["name", "order"]
}

Response

{
  "id": "t_xxx",
  "slug": "order_confirmation"
}
POST/api/messages/template
X-API-Key

Envoyer un message basé sur un template.

Request Body

{
  "to": "+22370000000",
  "templateSlug": "order_confirmation",
  "variables": { "name": "Awa", "order": "#1234" }
}

Response

{ "success": true, "messageId": "msg_xxx" }

Envoi en masse (Batch)

POST/v1/batch
X-API-Key

Envoyer jusqu'à 1000 messages en un seul appel.

Request Body

{
  "messages": [
    { "to": "+22370000001", "text": "Bonjour 1" },
    { "to": "+22370000002", "text": "Bonjour 2" }
  ]
}

Response

{
  "batchId": "batch_xxx",
  "total": 2,
  "queued": 2
}
GET/v1/batch/{batchId}
X-API-Key

Vérifier le statut d'un batch.

Response

{
  "batchId": "batch_xxx",
  "total": 2,
  "sent": 2,
  "failed": 0,
  "status": "completed"
}

Média

POST/v1/media/upload
X-API-Key

Uploader un fichier (image, document, audio, vidéo). Retourne une URL utilisable dans les endpoints d'envoi.

Request Body

Content-Type: multipart/form-data
file: <binary>

Response

{
  "url": "https://smsv.tech/uploads/xxx.pdf",
  "mimeType": "application/pdf",
  "size": 125000
}

Webhooks

Recevez des notifications en temps réel sur les événements de messagerie et de connexion.

Événements disponibles

message.sentMessage envoyé
message.deliveredMessage délivré
message.readMessage lu
message.failedÉchec d'envoi
message.receivedNouveau message entrant
sender.connectedWhatsApp connecté
sender.disconnectedWhatsApp déconnecté

Format du payload

{
  "event": "message.delivered",
  "timestamp": "2026-03-13T14:30:00Z",
  "externalOrgId": "client-123",
  "data": {
    "messageId": "msg_abc123",
    "to": "+22370000000",
    "status": "delivered"
  }
}

Vérification de signature

Chaque webhook inclut un header X-Webhook-Signature (HMAC SHA-256).

Node.js
const crypto = require('crypto');

function verifyWebhook(payload, signature, secret) {
  const expected = 'sha256=' +
    crypto.createHmac('sha256', secret)
      .update(payload)
      .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

Configuration webhook (Partner)

Configurez votre URL webhook dans Dashboard → Partenaire → Paramètres, ou via l'API pour chaque app :

POST/apps/{appId}/webhooks
Bearer JWT

Créer un endpoint webhook pour une app.

Request Body

{
  "url": "https://yourapp.com/webhooks/smsv",
  "events": ["message.sent", "message.delivered", "message.received"],
  "isActive": true
}

Response

{
  "id": "wh_xxx",
  "url": "https://yourapp.com/webhooks/smsv",
  "secret": "whsec_xxxxx",
  "isActive": true
}

SDKs

Tous les SDKs sont open-source et disponibles sur GitHub.

JavaScript / TypeScript

Client complet (Standard + Partner).

# Cloner le repo puis installer localement
git clone https://github.com/dione24/smsv-sdk.git
cd smsv-sdk/js && npm install && npm run build
# Puis dans votre projet :
npm install ../smsv-sdk/js
Usage Partner
import { SmsvPartnerClient } from '@sahelpay/smsv';

const client = new SmsvPartnerClient({
  partnerKey: 'pk_cloud_xxxxx'
});

const sender = await client.createSender({
  externalOrgId: 'client-123',
  displayName: 'Boutique Awa'
});

const { qrCode } = await client.getQRCode('client-123');

await client.sendMessage({
  externalOrgId: 'client-123',
  to: '+22370000000',
  text: 'Bonjour !'
});

Python

Client Standard + Partner.

# Cloner le repo puis installer localement
git clone https://github.com/dione24/smsv-sdk.git
pip install ./smsv-sdk/python
Usage Partner
from smsv import SMSvPartnerClient

client = SMSvPartnerClient(
    partner_key="pk_cloud_xxxxx"
)

sender = client.create_sender(
    "client-123", "Boutique Awa"
)

qr = client.get_qr_code("client-123")

client.send_message(
    "client-123",
    "+22370000000",
    "Bonjour !"
)

PHP / Laravel

Client Standard + Partner.

# Cloner le repo, puis dans composer.json ajouter :
# "repositories": [{ "type": "path", "url": "./smsv-sdk/php-laravel" }]
git clone https://github.com/dione24/smsv-sdk.git
composer require sahelpay/smsv-laravel @dev
Usage Partner
use Sahelpay\Smsv\SmsvPartnerClient;

$client = new SmsvPartnerClient(
    'pk_cloud_xxxxx'
);

$sender = $client->createSender(
    'client-123', 'Boutique Awa'
);

$qr = $client->getQRCode('client-123');

$client->sendMessage(
    'client-123',
    '+22370000000',
    'Bonjour !'
);

Erreurs

Toutes les erreurs suivent le même format :

{
  "statusCode": 400,
  "message": "Description de l'erreur",
  "code": "VALIDATION_ERROR"
}
Code HTTPCodeDescription
400VALIDATION_ERRORParamètres invalides
401UNAUTHORIZEDClé API manquante ou invalide
403FORBIDDENAccès refusé (plan, quota, permissions)
404NOT_FOUNDRessource introuvable
409CONFLICTRessource déjà existante (ex: sender avec même orgId)
429RATE_LIMITEDTrop de requêtes. Voir header Retry-After
500INTERNAL_ERRORErreur serveur. Réessayer avec backoff exponentiel
Retry strategy : En cas de 429 ou 5xx, attendez le header Retry-After (en secondes), puis réessayez avec un backoff exponentiel (1s, 2s, 4s, max 60s). Les SDKs gèrent cela automatiquement.

Limites & Quotas

RessourceLimiteNotes
Requêtes API100/min par cléHeader X-RateLimit-Remaining
Messages/moisSelon planVoir /v1/me pour les limites actuelles
Batch send1000 messages/appelPOST /v1/batch
Upload média16 MB/fichierPOST /v1/media/upload
Senders/partnerSelon plan partnerVisible dans Dashboard → Partenaire
Contacts/import10 000/appelPOST /v1/contacts/import

Exemple complet : SaaS de facturation

Scénario : votre SaaS de facturation permet à chaque client de lier son WhatsApp pour envoyer automatiquement les factures PDF à ses propres clients.

1. Onboarding : le client lie son WhatsApp

backend/routes/whatsapp.ts
import { SmsvPartnerClient } from '@sahelpay/smsv';

const smsv = new SmsvPartnerClient({
  partnerKey: process.env.SMSV_PARTNER_KEY!
});

// Quand le client clique "Connecter WhatsApp"
app.post('/api/whatsapp/connect', async (req, res) => {
  const { tenantId } = req.auth;

  // Créer ou récupérer le sender
  let sender;
  try {
    sender = await smsv.getSender(tenantId);
  } catch {
    sender = await smsv.createSender({
      externalOrgId: tenantId,
      displayName: req.auth.companyName
    });
  }

  // Si déconnecté, reconnecter
  if (sender.status === 'disconnected' || sender.status === 'not_initialized') {
    await smsv.reconnectSender(tenantId);
  }

  // Récupérer le QR
  const qr = await smsv.getQRCode(tenantId);
  res.json({ qrCode: qr.qrCode, status: qr.status });
});

// Frontend poll ce endpoint
app.get('/api/whatsapp/status', async (req, res) => {
  const { tenantId } = req.auth;
  const status = await smsv.getStatus(tenantId);
  res.json(status);
});

2. Envoi automatique de facture

backend/services/invoice.ts
// Quand une facture est payée
async function onInvoicePaid(invoice: Invoice) {
  const tenant = await db.tenant.findUnique({
    where: { id: invoice.tenantId }
  });

  // Vérifier que le client a WhatsApp connecté
  const status = await smsv.getStatus(tenant.id);
  if (status.status !== 'ready' && status.status !== 'connected') {
    console.log('WhatsApp non connecté pour', tenant.id);
    return;
  }

  // Envoyer la facture PDF
  await smsv.sendDocument({
    externalOrgId: tenant.id,
    to: invoice.customerPhone,
    documentUrl: invoice.pdfUrl,
    filename: `Facture-${invoice.number}.pdf`,
    caption: `Facture ${invoice.number} — ${invoice.total} FCFA`
  });

  await db.invoice.update({
    where: { id: invoice.id },
    data: { whatsappSent: true }
  });
}

3. Recevoir les webhooks

backend/routes/webhooks.ts
app.post('/webhooks/smsv', async (req, res) => {
  const signature = req.headers['x-webhook-signature'] as string;
  const isValid = smsv.verifyWebhook(
    JSON.stringify(req.body),
    signature,
    process.env.SMSV_WEBHOOK_SECRET!
  );

  if (!isValid) {
    return res.status(401).send('Invalid signature');
  }

  const { event, externalOrgId, data } = req.body;

  switch (event) {
    case 'message.delivered':
      await db.invoice.updateMany({
        where: { tenantId: externalOrgId, messageId: data.messageId },
        data: { deliveryStatus: 'delivered' }
      });
      break;

    case 'message.failed':
      console.error('Message failed:', data);
      break;

    case 'sender.disconnected':
      await notifyTenant(externalOrgId, 'WhatsApp déconnecté');
      break;
  }

  res.json({ received: true });
});

Même exemple en Python

backend/smsv_service.py
from smsv import SMSvPartnerClient

smsv = SMSvPartnerClient(partner_key="pk_cloud_xxxxx")

# Onboarding
def connect_whatsapp(tenant_id: str, company_name: str):
    try:
        sender = smsv.get_sender(tenant_id)
    except Exception:
        sender = smsv.create_sender(tenant_id, company_name)

    if sender["status"] in ("disconnected", "not_initialized"):
        smsv.reconnect_sender(tenant_id)

    qr = smsv.get_qr_code(tenant_id)
    return {"qr_code": qr["qrCode"], "status": qr["status"]}

# Envoi de facture
def send_invoice(tenant_id: str, customer_phone: str, pdf_url: str, number: str):
    status = smsv.get_status(tenant_id)
    if status["status"] not in ("ready", "connected"):
        return False

    smsv.send_document(
        org_id=tenant_id,
        to=customer_phone,
        document_url=pdf_url,
        filename=f"Facture-{number}.pdf",
        caption=f"Facture {number}"
    )
    return True