Incluse dans tous les plans — sans supplément

Votre logiciel facture. Fatora s’occupe du reste.

Votre SaaS, votre CRM ou votre application métier n’a pas de module de facturation marocaine ? Un bouton chez vous, un appel HTTP chez nous : Fatora émet la facture ou le devis dans la numérotation du commerçant, avec son cachet, son logo et toutes les mentions de l’article 145 CGI — PDF à l’appui, remis par WhatsApp, par email ou par QR code.

  • Factures et devis conformes DGI : ICE, IF, TVA ventilée, montant en toutes lettres, séquence continue
  • Remise au choix : WhatsApp, email, ou QR code à imprimer — le client scanne et télécharge
  • Modification en langage libre : écrivez le changement, l’IA l’applique
  • Logo, cachet et informations société pilotables par API

Obtenir sa clé API

  1. 1Le commerçant ouvre sa conversation WhatsApp Fatora-Bot
  2. 2Il écrit simplement « api »
  3. 3Le bot répond avec sa clé personnelle (fk_…) — à coller dans votre application

La clé est propre à chaque commerçant et incluse dans son abonnement, dès l’essai gratuit. « api reset » la régénère à tout moment (l’ancienne est révoquée). Les factures émises par l’API consomment le quota du plan ; les devis sont gratuits et illimités.

Démarrage en 5 minutes

Une seule requête suffit pour émettre un document. Le prix est hors taxe par défaut ; passez « priceIsTtc »: true si vos montants sont TTC — Fatora reconstitue la base.

Requête
curl -X POST https://bot.swiviq.com/v1/documents \
  -H "Authorization: Bearer fk_votre_cle" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "invoice",
    "client": { "name": "ATLAS DIGITAL SARL", "ice": "001122334455667", "type": "company" },
    "items": [
      { "description": "Abonnement CRM — pack annuel", "quantity": 1, "unitPrice": 4800 },
      { "description": "Formation équipe (2 jours)", "quantity": 2, "unitPrice": 1500 }
    ],
    "sendToEmail": "client@exemple.ma"
  }'
Réponse — 201
{
  "number": "FAT-2026-0042",
  "type": "invoice",
  "status": "issued",
  "issueDate": "2026-08-15",
  "client": { "name": "ATLAS DIGITAL SARL", "ice": "001122334455667", "type": "company" },
  "items": [
    { "description": "Abonnement CRM — pack annuel", "quantity": 1, "unitPrice": 4800, "vatRate": 20 },
    { "description": "Formation équipe (2 jours)", "quantity": 2, "unitPrice": 1500, "vatRate": 20 }
  ],
  "totals": { "ht": 7800, "vat": 1560, "ttc": 9360, "currency": "MAD" },
  "pdfUrl": "https://bot.swiviq.com/f/a1b2c3d4e5",
  "qrcodeUrl": "https://bot.swiviq.com/qr/a1b2c3d4e5.png",
  "whatsapp": { "owner": "sent", "client": "skipped" },
  "email": { "client": "sent" }
}
★ Unique à Fatora

La modification en langage libre

Aucun schéma de patch à apprendre. Votre utilisateur tape sa correction dans un champ texte, vous nous la transmettez telle quelle — le même moteur d’IA qui comprend les commerçants en darija sur WhatsApp la décode et l’applique.

Requête
curl -X POST https://bot.swiviq.com/v1/documents/FAT-2026-0042/modify \
  -H "Authorization: Bearer fk_votre_cle" \
  -H "Content-Type: application/json" \
  -d '{
    "instruction": "le client est en fait STE ATLAS DIGITAL MAROC SARL,
                    et remplace la formation par 3 jours à 1200 dh le jour"
  }'
Réponse — 200
{
  "number": "FAT-2026-0042",
  "client": { "name": "STE ATLAS DIGITAL MAROC SARL", "ice": "001122334455667", "type": "company" },
  "items": [
    { "description": "Abonnement CRM — pack annuel", "quantity": 1, "unitPrice": 4800, "vatRate": 20 },
    { "description": "Formation équipe", "quantity": 3, "unitPrice": 1200, "vatRate": 20 }
  ],
  "totals": { "ht": 8400, "vat": 1680, "ttc": 10080, "currency": "MAD" },
  "pdfUrl": "https://bot.swiviq.com/f/a1b2c3d4e5",
  "applied": "le client est en fait STE ATLAS DIGITAL MAROC SARL, et remplace…"
}

Le document garde son numéro (aucun trou dans la séquence), le PDF est régénéré, les totaux recalculés. Si l’instruction est incompréhensible, l’API répond 422 avec une explication — jamais de modification hasardeuse.

Remise au client : WhatsApp, email ou QR code

Émettre ne suffit pas — il faut que le client final reçoive son document. Trois canaux, cumulables, réutilisables à volonté : une facture perdue se renvoie en un appel.

WhatsApp

« sendToPhone » à la création, ou POST /send avec channel « whatsapp » : le PDF part dans la conversation du client, au nom du commerçant.

Email

« sendToEmail » à la création, ou channel « email » : le client reçoit un message soigné avec la facture en pièce jointe — le même gabarit que le bot.

QR code

Chaque document expose « qrcodeUrl » : un PNG à afficher en caisse, imprimer sur un ticket ou intégrer dans votre interface. Le client scanne, la facture se télécharge.

Requête
curl -X POST https://bot.swiviq.com/v1/documents/FAT-2026-0042/send \
  -H "Authorization: Bearer fk_votre_cle" \
  -H "Content-Type: application/json" \
  -d '{ "channel": "email", "to": "client@exemple.ma" }'
Réponse — 200
{ "ok": true, "number": "FAT-2026-0042",
  "channel": "email", "to": "client@exemple.ma", "status": "sent" }

Référence des endpoints

✓ Chaque exemple ci-dessous a été rejoué tel quel contre l’API de production le 15/08/2026 — les réponses affichées sont les vraies.

POST/v1/documents

Émettre une facture ou un devis

« type »: « invoice » (défaut) ou « quote ». Options : « priceIsTtc », « vatRate » par ligne ou global, « sendToPhone » et « sendToEmail » pour la remise immédiate au client final, « notify »: false pour ne pas prévenir le commerçant. Réponse 201 avec numéro, totaux, lien PDF et QR code.

Voir l’exemple testé
Requête
curl -X POST https://bot.swiviq.com/v1/documents \
  -H "Authorization: Bearer fk_votre_cle" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "invoice",
    "client": { "name": "ATLAS DIGITAL SARL", "ice": "001122334455667", "type": "company" },
    "items": [
      { "description": "Abonnement CRM — pack annuel", "quantity": 1, "unitPrice": 4800 },
      { "description": "Formation équipe (2 jours)", "quantity": 2, "unitPrice": 1500 }
    ],
    "sendToEmail": "client@exemple.ma"
  }'
Réponse
{
  "number": "FAT-2026-0042",
  "type": "invoice",
  "status": "issued",
  "issueDate": "2026-08-15",
  "client": { "name": "ATLAS DIGITAL SARL", "ice": "001122334455667", "type": "company" },
  "items": [
    { "description": "Abonnement CRM — pack annuel", "quantity": 1, "unitPrice": 4800, "vatRate": 20 },
    { "description": "Formation équipe (2 jours)", "quantity": 2, "unitPrice": 1500, "vatRate": 20 }
  ],
  "totals": { "ht": 7800, "vat": 1560, "ttc": 9360, "currency": "MAD" },
  "pdfUrl": "https://bot.swiviq.com/f/a1b2c3d4e5",
  "qrcodeUrl": "https://bot.swiviq.com/qr/a1b2c3d4e5.png",
  "whatsapp": { "owner": "sent", "client": "skipped" },
  "email": { "client": "sent" }
}
POST/v1/documents/{number}/modify

Modifier en langage libre

Le corps ne contient qu’une « instruction » en texte libre (français, darija ou anglais). Même numéro, PDF régénéré, champ « applied » qui confirme l’instruction comprise.

Voir l’exemple testé
Requête
curl -X POST https://bot.swiviq.com/v1/documents/FAT-2026-0042/modify \
  -H "Authorization: Bearer fk_votre_cle" \
  -H "Content-Type: application/json" \
  -d '{
    "instruction": "le client est en fait STE ATLAS DIGITAL MAROC SARL,
                    et remplace la formation par 3 jours à 1200 dh le jour"
  }'
Réponse
{
  "number": "FAT-2026-0042",
  "client": { "name": "STE ATLAS DIGITAL MAROC SARL", "ice": "001122334455667", "type": "company" },
  "items": [
    { "description": "Abonnement CRM — pack annuel", "quantity": 1, "unitPrice": 4800, "vatRate": 20 },
    { "description": "Formation équipe", "quantity": 3, "unitPrice": 1200, "vatRate": 20 }
  ],
  "totals": { "ht": 8400, "vat": 1680, "ttc": 10080, "currency": "MAD" },
  "pdfUrl": "https://bot.swiviq.com/f/a1b2c3d4e5",
  "applied": "le client est en fait STE ATLAS DIGITAL MAROC SARL, et remplace…"
}
POST/v1/documents/{number}/send

Remettre ou renvoyer un document

{ « channel »: « whatsapp » | « email », « to »: numéro ou adresse }. Le PDF est régénéré s’il a disparu — réutilisable autant de fois que nécessaire.

Voir l’exemple testé
Requête
curl -X POST https://bot.swiviq.com/v1/documents/FAT-2026-0042/send \
  -H "Authorization: Bearer fk_votre_cle" \
  -H "Content-Type: application/json" \
  -d '{ "channel": "email", "to": "client@exemple.ma" }'
Réponse
{ "ok": true, "number": "FAT-2026-0042",
  "channel": "email", "to": "client@exemple.ma", "status": "sent" }
GET/qr/{token}.png

QR code de téléchargement (public)

Le PNG du QR pointant vers le PDF. Sans authentification : le jeton est le secret. À intégrer directement dans une balise <img> ou à imprimer sur un ticket de caisse.

Voir l’exemple testé
Requête
<!-- directement dans votre page -->
<img src="https://bot.swiviq.com/qr/a1b2c3d4e5.png" width="180" alt="QR facture">

# ou en téléchargement
curl -o facture-qr.png https://bot.swiviq.com/qr/a1b2c3d4e5.png
Réponse
HTTP 200 — image/png, 600 × 600 px
Cache-Control: public, max-age=86400, immutable
GET/v1/documents

Lister les documents

Les derniers documents émis, du plus récent au plus ancien. « limit » jusqu’à 50, « type » pour filtrer factures (« invoice ») ou devis (« quote »).

Voir l’exemple testé
Requête
curl -H "Authorization: Bearer fk_votre_cle" \
  "https://bot.swiviq.com/v1/documents?limit=5&type=invoice"
Réponse
[
  {
    "number": "FAT-2026-0042",
    "type": "invoice",
    "status": "issued",
    "issueDate": "2026-08-15",
    "client": { "name": "STE ATLAS DIGITAL MAROC SARL", "ice": "001122334455667" },
    "totals": { "ht": 8400, "vat": 1680, "ttc": 10080, "currency": "MAD" },
    "pdfUrl": "https://bot.swiviq.com/f/a1b2c3d4e5",
    "qrcodeUrl": "https://bot.swiviq.com/qr/a1b2c3d4e5.png"
  },
  { "number": "FAT-2026-0041", "...": "..." }
]
GET/v1/documents/{number}

Lire un document

Lignes, totaux, lien PDF, QR code — pratique pour afficher l’état dans votre interface ou vérifier une modification.

Voir l’exemple testé
Requête
curl -H "Authorization: Bearer fk_votre_cle" \
  https://bot.swiviq.com/v1/documents/FAT-2026-0042
Réponse
{
  "number": "FAT-2026-0042",
  "type": "invoice",
  "status": "issued",
  "issueDate": "2026-08-15",
  "client": { "name": "STE ATLAS DIGITAL MAROC SARL", "ice": "001122334455667", "type": "company" },
  "items": [
    { "description": "Abonnement CRM — pack annuel", "quantity": 1, "unitPrice": 4800, "vatRate": 20 },
    { "description": "Formation équipe", "quantity": 3, "unitPrice": 1200, "vatRate": 20 }
  ],
  "totals": { "ht": 8400, "vat": 1680, "ttc": 10080, "currency": "MAD" },
  "pdfUrl": "https://bot.swiviq.com/f/a1b2c3d4e5",
  "qrcodeUrl": "https://bot.swiviq.com/qr/a1b2c3d4e5.png"
}
GET/v1/account

Compte et quota

Profil société, plan actif, quota consommé/restant. C’est aussi le moyen le plus simple de tester qu’une clé est valide.

Voir l’exemple testé
Requête
curl -H "Authorization: Bearer fk_votre_cle" \
  https://bot.swiviq.com/v1/account
Réponse
{
  "company": {
    "name": "ATLAS SERVICES SARL", "ice": "002233445566778",
    "address": "Agdal, Rabat", "defaultVatRate": 20,
    "taxRegime": "normal", "hasLogo": true, "hasStamp": true
  },
  "plan": { "key": "p100", "label": "100 factures / mois", "priceMAD": 90 },
  "quota": { "used": 12, "limit": 100, "remaining": 88, "ok": true }
}
PUT/v1/company

Mettre à jour la société

Champs acceptés : companyName, ice, if, taxePro, rc, address, email, defaultVatRate, paymentTerms. Seuls les champs envoyés sont modifiés.

Voir l’exemple testé
Requête
curl -X PUT https://bot.swiviq.com/v1/company \
  -H "Authorization: Bearer fk_votre_cle" \
  -H "Content-Type: application/json" \
  -d '{
    "address": "12 rue Oued Fès, Agdal, Rabat",
    "paymentTerms": "Virement à 30 jours"
  }'
Réponse
{
  "ok": true,
  "company": {
    "name": "ATLAS SERVICES SARL", "ice": "002233445566778",
    "address": "12 rue Oued Fès, Agdal, Rabat", "defaultVatRate": 20
  }
}
POST/v1/company/logo

Envoyer le logo

Corps : { « image »: « <base64 ou data-URI png/jpeg> » } (6 Mo max). Le logo est nettoyé et recadré automatiquement, puis apposé sur les prochains PDF.

Voir l’exemple testé
Requête
curl -X POST https://bot.swiviq.com/v1/company/logo \
  -H "Authorization: Bearer fk_votre_cle" \
  -H "Content-Type: application/json" \
  -d "{ \"image\": \"data:image/png;base64,$(base64 -w0 logo.png)\" }"
Réponse
{ "ok": true, "logo": "saved",
  "appliesTo": "toutes les prochaines factures" }
POST/v1/company/stamp

Envoyer le cachet

Même format que le logo. Le fond est supprimé par extraction d’encre (une photo du cachet sur papier suffit), puis le cachet est apposé sur chaque PDF.

Voir l’exemple testé
Requête
curl -X POST https://bot.swiviq.com/v1/company/stamp \
  -H "Authorization: Bearer fk_votre_cle" \
  -H "Content-Type: application/json" \
  -d "{ \"image\": \"data:image/png;base64,$(base64 -w0 cachet.jpg)\" }"
Réponse
{ "ok": true, "stamp": "saved",
  "appliesTo": "toutes les prochaines factures" }

Codes d’erreur

Toute erreur renvoie un JSON à deux champs constants : « error » (code machine stable, à tester dans votre code) et « message » (explication en clair, affichable telle quelle). Le 402 ajoute « used », « limit » et « reason » pour construire votre propre écran de quota.

400Requête invalideCodes : invalid_json (corps illisible), empty_body (corps vide — vérifiez qu’aucun retour à la ligne ne casse vos en-têtes), missing_client, missing_items, invalid_channel, invalid_phone, invalid_email, invalid_image. Le message dit exactement quel champ corriger.
401Clé absente ou invalidemissing_api_key : ajoutez l’en-tête Authorization: Bearer fk_… · invalid_api_key : clé inconnue ou révoquée par « api reset » — redemandez-la au commerçant.
402Quota du plan atteintquota_exceeded : la réponse contient used/limit/reason. Les devis ne comptent pas. Le commerçant passe au plan supérieur en deux messages WhatsApp.
403Compte suspenduaccount_suspended : le compte du commerçant est suspendu — contactez contact@swiviq.com.
404Document introuvablenot_found : aucun document à ce numéro pour CE compte — chaque clé ne voit que ses propres documents.
409Document annulécancelled : le document a été annulé (avoir émis) — il ne peut plus être modifié ni renvoyé. Émettez-en un nouveau.
413Corps trop volumineuxbody_too_large : 8 Mo maximum — compressez le logo ou le cachet avant l’envoi.
422Instruction incompriseinstruction_not_understood : l’IA n’a pas pu appliquer la modification sans risque — reformulez plus précisément. Rien n’a été modifié.
429Trop de requêtesrate_limited : 60 requêtes/minute par clé — espacez ou mettez en file d’attente, puis réessayez.
500Erreur interneinternal : réessayez ; si l’erreur persiste, écrivez à contact@swiviq.com avec le corps de la réponse.
Réponse
HTTP 402
{
  "error": "quota_exceeded",
  "reason": "trial",
  "used": 2,
  "limit": 2,
  "message": "Quota d'essai atteint (2 factures). Le commerçant peut passer
              au plan supérieur depuis son WhatsApp Fatora."
}

Questions d’intégration

Combien coûte l’API ?

Rien de plus que l’abonnement Fatora du commerçant, dès l’essai gratuit. Les factures API comptent dans le quota du plan comme celles dictées sur WhatsApp ; les devis sont gratuits et illimités.

Qui détient la clé : moi (l’éditeur) ou mon utilisateur ?

Chaque commerçant a sa propre clé, liée à son compte et à sa numérotation. Votre application stocke la clé que l’utilisateur colle — aucun compte central à gérer, chaque client paie son propre abonnement.

Les montants que j’envoie sont TTC — comment faire ?

Ajoutez « priceIsTtc »: true. Fatora reconstitue la base hors taxe en divisant par un plus le taux, ligne par ligne.

Le commerçant est auto-entrepreneur, sans TVA ?

Son régime fiscal est enregistré dans son compte et s’impose à l’API : quoi que votre application envoie, ses documents sortent sans TVA, avec la mention adaptée.

Que se passe-t-il quand le quota est atteint ?

L’API répond 402 avec used, limit et un message prêt à afficher. Le commerçant change de plan en deux messages WhatsApp.