📄 Générer des factures PDF — Pdf SDK

BotStrike intègre un objet global Pdf pour créer des documents PDF (factures, reçus, devis, contrats, certificats…) puis les envoyer via Telegram ou par email. Aucune installation requise.

⏳ Bientôt disponible. La création de PDF et de factures n'est pas encore ouverte — elle arrive prochainement. Voir la page de tarification.
📌 Règle d'or — Images via URL HTTPS uniquement. Pour ajouter un logo, une image ou un tampon, fournissez simplement l'URL publique de l'image. BotStrike télécharge automatiquement le fichier, détecte son format (PNG, JPG, WEBP, GIF) et le convertit si besoin. Vous n'avez jamais à gérer de fichiers locaux.

1 — API Pdf

Python

MéthodeDescription
Pdf.create({title, author, format, orientation})Crée un nouveau document. format: 'A4' (défaut) ou 'Letter'. orientation: 'P' (portrait) ou 'L' (paysage).
Pdf.h1(pdf, text)Titre principal (18pt gras)
Pdf.h2(pdf, text)Sous-titre (14pt gras)
Pdf.text(pdf, text, {size, bold})Paragraphe (11pt par défaut)
Pdf.row(pdf, [c1,c2,c3], {bold, widths, h, align, border})Ligne de tableau
Pdf.line(pdf)Trait séparateur
Pdf.br(pdf, n)Saut de ligne (n lignes)
Pdf.image(pdf, url, x, y, w, h)Insère une image (URL HTTPS, format auto)
Pdf.save(pdf, 'nom.pdf')Sauvegarde et retourne le chemin

JavaScript

Style chaînable : const pdf = Pdf.create() puis pdf.h1(...).text(...).row(...). image() et save() sont asynchrones — utilisez await.

2 — Exemple minimal (Hello PDF)

Python
JavaScript
pdf = Pdf.create({'title': 'Hello'})
Pdf.h1(pdf, 'Bonjour')
Pdf.text(pdf, 'Ceci est mon premier PDF généré par le bot.')
path = Pdf.save(pdf, 'hello.pdf')

bot.sendDocument(path, 'Voici votre PDF')
const pdf = Pdf.create({title: 'Hello'});
pdf.h1('Bonjour');
pdf.text('Ceci est mon premier PDF généré par le bot.');
const path = await pdf.save('hello.pdf');

await bot.sendDocument(path, 'Voici votre PDF');

3 — Exemple complet : facture avec logo

Le logo est fourni via une simple URL HTTPS — BotStrike télécharge l'image et l'insère. Aucune gestion de fichier local.

Python
JavaScript
# 1) URL du logo (configurée une fois via /setlogo, stockée dans Props)
logo_url = Props.get('logo_url')  # ex: https://i.imgur.com/abc123.png

# 2) Données client + articles
client = {
    'nom': 'Jean Dupont',
    'adresse': '12 rue des Lilas, 75011 Paris',
    'email': 'jean.dupont@example.com',
}
articles = [
    {'desc': 'Abonnement Premium 1 mois', 'qty': 1, 'prix': 29.99},
    {'desc': 'Pack 1000 messages',         'qty': 2, 'prix': 9.50},
    {'desc': 'Support prioritaire',        'qty': 1, 'prix': 15.00},
]

numero     = f"FAC-{int(time.time())}"
date_str   = datetime.datetime.now().strftime('%d/%m/%Y')
sous_total = sum(a['qty'] * a['prix'] for a in articles)
tva        = round(sous_total * 0.20, 2)
total      = round(sous_total + tva, 2)

# 3) Construction du PDF
pdf = Pdf.create({'title': numero, 'author': 'Mon Entreprise SARL'})

# Logo (URL HTTPS — BotStrike télécharge automatiquement)
if logo_url:
    Pdf.image(pdf, logo_url, x=80, y=10, w=50)
    Pdf.br(pdf, 3)

Pdf.h1(pdf, 'FACTURE')
Pdf.text(pdf, f'N° {numero}')
Pdf.text(pdf, f'Date : {date_str}')
Pdf.line(pdf)

Pdf.h2(pdf, 'Émetteur')
Pdf.text(pdf, 'Mon Entreprise SARL')
Pdf.text(pdf, '1 avenue de la République, 75001 Paris')
Pdf.text(pdf, 'SIRET 123 456 789 00010')
Pdf.line(pdf)

Pdf.h2(pdf, 'Client')
Pdf.text(pdf, client['nom'])
Pdf.text(pdf, client['adresse'])
Pdf.text(pdf, client['email'])
Pdf.line(pdf)

Pdf.h2(pdf, 'Détail')
Pdf.row(pdf, ['Description', 'Qté', 'Prix HT', 'Total'],
        {'bold': True, 'widths': [100, 20, 35, 35]})

for a in articles:
    Pdf.row(pdf, [
        a['desc'],
        str(a['qty']),
        f"{a['prix']:.2f} EUR",
        f"{a['qty'] * a['prix']:.2f} EUR",
    ], {'widths': [100, 20, 35, 35]})

Pdf.br(pdf)
Pdf.row(pdf, ['', 'Sous-total HT', f'{sous_total:.2f} EUR'],
        {'widths': [120, 35, 35], 'bold': True})
Pdf.row(pdf, ['', 'TVA 20 %', f'{tva:.2f} EUR'],
        {'widths': [120, 35, 35]})
Pdf.row(pdf, ['', 'TOTAL TTC', f'{total:.2f} EUR'],
        {'widths': [120, 35, 35], 'bold': True})

Pdf.br(pdf, 2)
Pdf.text(pdf, 'Merci pour votre confiance — Paiement à 30 jours.')

# 4) Sauvegarde + envoi
path = Pdf.save(pdf, f'{numero}.pdf')
bot.sendDocument(path, f'Votre facture {numero}')
// 1) URL du logo (Props)
const logoUrl = await Props.get('logo_url');

// 2) Données
const client = {
    nom: 'Jean Dupont',
    adresse: '12 rue des Lilas, 75011 Paris',
    email: 'jean.dupont@example.com',
};
const articles = [
    {desc: 'Abonnement Premium 1 mois', qty: 1, prix: 29.99},
    {desc: 'Pack 1000 messages',         qty: 2, prix: 9.50},
    {desc: 'Support prioritaire',        qty: 1, prix: 15.00},
];

const numero    = 'FAC-' + Date.now();
const dateStr   = new Date().toLocaleDateString('fr-FR');
const sousTotal = articles.reduce((s, a) => s + a.qty * a.prix, 0);
const tva       = Math.round(sousTotal * 0.20 * 100) / 100;
const total     = Math.round((sousTotal + tva) * 100) / 100;

// 3) Construction du PDF
const pdf = Pdf.create({title: numero, author: 'Mon Entreprise SARL'});

if (logoUrl) {
    await pdf.image(logoUrl, 50, 40, 90);
    pdf.br(3);
}

pdf.h1('FACTURE')
   .text('N° ' + numero)
   .text('Date : ' + dateStr)
   .line()
   .h2('Émetteur')
   .text('Mon Entreprise SARL')
   .text('1 avenue de la République, 75001 Paris')
   .text('SIRET 123 456 789 00010')
   .line()
   .h2('Client')
   .text(client.nom)
   .text(client.adresse)
   .text(client.email)
   .line()
   .h2('Détail')
   .row(['Description', 'Qté', 'Prix HT', 'Total'], {bold: true});

for (const a of articles) {
    pdf.row([
        a.desc,
        String(a.qty),
        a.prix.toFixed(2) + ' EUR',
        (a.qty * a.prix).toFixed(2) + ' EUR',
    ]);
}

pdf.br()
   .row(['', '', 'Sous-total HT', sousTotal.toFixed(2) + ' EUR'], {bold: true})
   .row(['', '', 'TVA 20 %',       tva.toFixed(2) + ' EUR'])
   .row(['', '', 'TOTAL TTC',      total.toFixed(2) + ' EUR'], {bold: true})
   .br(2)
   .text('Merci pour votre confiance — Paiement à 30 jours.');

const path = await pdf.save(numero + '.pdf');
await bot.sendDocument(path, 'Votre facture ' + numero);

4 — Apposer un tampon ou une signature SUR le PDF

Pour ajouter un cachet d'entreprise ou une signature directement sur la facture, utilisez Pdf.image() avec des coordonnées x/y et une taille adaptée. Le tampon est superposé à l'endroit voulu dans le PDF.

Python
JavaScript
# URL d'un tampon (PNG transparent recommandé)
tampon_url    = Props.get('tampon_url')     # ex: https://i.imgur.com/stamp.png
signature_url = Props.get('signature_url')  # ex: https://i.imgur.com/sig.png

pdf = Pdf.create()
Pdf.h1(pdf, 'FACTURE FAC-2026-042')
Pdf.text(pdf, 'Total : 59,99 EUR TTC')
# ... contenu de la facture ...
Pdf.br(pdf, 4)
Pdf.text(pdf, 'Signature et cachet :')
Pdf.br(pdf, 3)

# Le tampon est apposé DANS le PDF, à droite (en mm depuis bord gauche)
Pdf.image(pdf, tampon_url,    x=130, y=None, w=40)   # 40mm de large
Pdf.image(pdf, signature_url, x=80,  y=None, w=50)   # signature Ă  gauche du tampon

path = Pdf.save(pdf, 'facture_signee.pdf')
bot.sendDocument(path)
const tamponUrl    = await Props.get('tampon_url');
const signatureUrl = await Props.get('signature_url');

const pdf = Pdf.create();
pdf.h1('FACTURE FAC-2026-042')
   .text('Total : 59,99 EUR TTC');
// ... contenu de la facture ...
pdf.br(4).text('Signature et cachet :').br(3);

// Tampon apposé DANS le PDF (coordonnées en points : 50pt = ~17mm)
await pdf.image(tamponUrl,    380, undefined, 110);
await pdf.image(signatureUrl, 240, undefined, 140);

const path = await pdf.save('facture_signee.pdf');
await bot.sendDocument(path);
📌 Astuce coordonnées : En Python (fpdf2), les unités sont en millimètres (A4 = 210×297 mm). En JavaScript (pdfkit), c'est en points (A4 = 595×842 pt). Passez y=None / undefined pour utiliser la position courante du curseur.

5 — Envoyer la facture par email avec pièce jointe

Combinez Pdf + Mail pour envoyer automatiquement la facture par email après paiement.

Python
JavaScript
# 1) Génération du PDF
pdf = Pdf.create()
Pdf.h1(pdf, 'FACTURE FAC-2026-042')
Pdf.text(pdf, 'Total : 59,99 EUR TTC')
pdf_path = Pdf.save(pdf, 'FAC-2026-042.pdf')

# 2) Envoi par email
Mail.send({
    'host': 'smtp.gmail.com',
    'port': 587,
    'user': 'facturation@mon-entreprise.com',
    'password': Props.get('smtp_password'),  # mot de passe d'application Gmail
    'from_name': 'Mon Entreprise',
    'to': 'jean.dupont@example.com',
    'subject': 'Votre facture FAC-2026-042',
    'html': '<p>Bonjour,</p><p>Votre facture est en pièce jointe.</p>',
    'attachments': [
        {'path': pdf_path, 'name': 'facture.pdf'}
    ]
})

bot.sendMessage('✅ Facture envoyée par email !')
// 1) Génération du PDF
const pdf = Pdf.create();
pdf.h1('FACTURE FAC-2026-042').text('Total : 59,99 EUR TTC');
const pdfPath = await pdf.save('FAC-2026-042.pdf');

// 2) Envoi par email
await Mail.send({
    host: 'smtp.gmail.com',
    port: 587,
    user: 'facturation@mon-entreprise.com',
    password: await Props.get('smtp_password'),
    from_name: 'Mon Entreprise',
    to: 'jean.dupont@example.com',
    subject: 'Votre facture FAC-2026-042',
    html: '<p>Bonjour,</p><p>Votre facture est en pièce jointe.</p>',
    attachments: [
        {path: pdfPath, name: 'facture.pdf'}
    ]
});

await bot.sendMessage('✅ Facture envoyée par email !');

7 — Où héberger les images ?

Pour obtenir une URL HTTPS publique pour votre logo / tampon / signature, choisissez l'un de ces hébergeurs gratuits :

⚠️ Important : L'URL doit pointer directement vers le fichier image (terminer par .png, .jpg etc.), pas vers une page de galerie. Testez en l'ouvrant dans un onglet privé : vous devez voir l'image seule.

8 — Et pour Word (.docx) ?

📌 Recommandation : Pour la facturation, le format PDF est la norme légale en France et dans l'UE — il est universel et non modifiable. Si vous avez vraiment besoin d'un .docx, vous pouvez :
html = """<html><body>
<h1>FACTURE FAC-001</h1>
<p>Client : Jean Dupont</p>
<table border="1">
  <tr><th>Article</th><th>Prix</th></tr>
  <tr><td>Premium</td><td>29,99 EUR</td></tr>
</table></body></html>"""

# Le sandbox interdit d'écrire un fichier sur le disque.
# Envoyez le HTML à un service de conversion, puis transmettez le fichier renvoyé.
res = HTTP.post("https://api.votre-convertisseur.com/html-vers-docx",
                body={"html": html}, token=Props.get("CONVERT_KEY"))
bot.sendDocument(res["url"], "Votre facture")

9 — Bonnes pratiques

10 — Erreurs fréquentes

ErreurCauseSolution
Image non visibleURL pointe vers une page HTML, pas l'imageUtilisez l'URL directe (clic droit → "Copier l'adresse de l'image")
Tampon avec rectangle blancPNG sans canal alphaRefaire le PNG sur remove.bg ou photopea.com
Tampon trop grand/petitParamètre w inadaptéTampon classique : 30-50 mm (Python) ou 80-130 pt (JS)
Caractères é à è cassésPolice par défaut limitéeUtiliser texte sans accents OU passer une police TTF unicode
PDF vide en JSOubli de awaitToujours await pdf.save(...)