Aller au contenu principal

Formulaires HTML

Une des façons d'ajouter le paiement en crypto à un site, une boutique en ligne ou un bot. Le client clique sur un bouton et la page de paiement avec la facture s'ouvre.

Le formulaire s'envoie uniquement en POST vers https://dash.bitsby.app/invoices/form et contient deux champs :

ChampContenu
database64url du JSON avec les champs de la facture
signatureHMAC-SHA256 de la chaîne data, 64 caractères hexadécimaux

Un projet peut avoir au plus 50 factures impayées créées de cette façon à un instant donné.

Exemple de formulaire

<form method="post" action="https://dash.bitsby.app/invoices/form" target="_blank">
<input type="hidden" name="data" value="eyJwcm9qZWN0SWQiOiJhMWIyYzNkNC01ZTZm...">
<input type="hidden" name="signature" value="f77d6da1be35bd2900e0bfed9f202b04...">
<button type="submit">Pay</button>
</form>

Le serveur de la boutique remplit les deux valeurs au rendu de la page. Le secret n'apparaît jamais dans le balisage.

L'attribut target="_blank" est facultatif : avec lui, le panier reste ouvert dans l'onglet d'origine.

Construction du conteneur

  1. Construisez un objet JSON avec les champs de la facture.
  2. Encodez-le en base64url. C'est la chaîne data.
  3. Calculez signature = HMAC-SHA256(data, formSecret).

La chaîne data est signée dans son ensemble, donc l'ordre des clés JSON, l'indentation et le style d'échappement Unicode n'ont pas d'importance. Le destinataire accepte aussi le base64 standard, avec ou sans padding.

Ne reconstruisez pas data après la signature : si un seul octet change, la signature doit être recalculée.

Le calcul de la signature, avec des exemples prêts à l'emploi en quatre langages, est couvert dans Signature du formulaire HTML.

Clés à l'intérieur de data

CléObligatoireContenu
projectIdouiID du projet depuis les réglages dans le tableau de bord, uuid
amountFiatouiMontant de 1 à 100 000, au plus deux décimales. Sous forme de chaîne "10.50" ou de nombre 10.5
currencyFiatouiDevise fiat : USD, EUR ou RUB
timeToPayouiDélai de paiement en heures : 0.5, 1, 3, 6, 12. Sous forme de chaîne ou de nombre
descriptionnonDescription pour le client, jusqu'à 1 000 caractères
serviceDatanonIdentifiant de la commande côté boutique, jusqu'à 1 000 caractères. Non affiché au client mais visible dans le code source du formulaire — n'y mettez rien de sensible
outputnonerrors — afficher les détails des erreurs de validation

Une clé facultative peut être omise du JSON — c'est équivalent à une chaîne vide. Les clés peuvent aller dans n'importe quel ordre ; le destinataire ignore les clés inconnues.

Les valeurs sont des chaînes ou des nombres JSON. Les booléens, les tableaux et les objets imbriqués ne comptent pas comme valeurs de champ et arrivent comme une chaîne vide.

Exemple du contenu de data :

{
"projectId": "a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"amountFiat": 10.5,
"currencyFiat": "USD",
"timeToPay": 1,
"description": "Order #7, delivery",
"serviceData": "order-7"
}

Ici, le montant et le délai de paiement sont passés comme des nombres ; les chaînes sont acceptées aussi. La clé facultative output n'est pas définie du tout.

Format du montant

Uniquement des chiffres et un point décimal, au plus deux décimales : 10, 10.00, 1000.50. Les espaces autour sont supprimés.

Tout autre format est rejeté — séparateurs de milliers, virgule à la place du point, notation exponentielle, signe devant le nombre, symbole de devise. Il n'y a pas d'arrondi : une troisième décimale n'est pas tronquée, elle provoque un rejet.

Secret du formulaire

Le secret se trouve dans les réglages du projet dans le tableau de bord, dans le champ Secret du formulaire (Form secret). Le serveur l'émet à la création du projet. Vous ne pouvez pas définir votre propre valeur ; le secret peut seulement être réémis — par exemple, s'il est compromis.

Le secret doit rester sur le serveur de la boutique. S'il se retrouve dans le HTML de la vitrine, la signature perd tout son sens.

Le secret du formulaire et le secret du webhook sont des clés différentes ; ne les confondez pas.

Identifiant de commande

Remplissez toujours serviceData : mettez-y votre propre identifiant de commande. La valeur revient dans la notification de paiement — la boutique s'en sert pour retrouver la commande.

Un serviceData rempli protège des doublons. Renvoyer le formulaire ou double-cliquer sur le bouton ne crée pas de seconde facture : le client est envoyé vers la facture impayée existante. La correspondance se fait sur les champs de la commande — projet, montant, devise, description et serviceData — pas sur les octets de data.

La valeur doit être unique par commande. Avec la même valeur, un second client arrive sur la facture impayée du premier.

Un serviceData vide supprime cette protection : il n'y a rien pour reconnaître une répétition, et chaque envoi crée une nouvelle facture. Les doublons épuisent la limite de 50 factures impayées, et quand l'une est payée, la boutique n'a rien pour relier le paiement à une commande.

Erreurs et mode débogage

Le formulaire passe deux contrôles : d'abord la signature et le conteneur, puis les valeurs des champs.

SituationCe que le service affiche
La signature ne correspond pas, le conteneur est illisible, le projet appartient à quelqu'un d'autre ou n'existe pasUne erreur générique, sans raison indiquée
La signature correspond, mais un champ est mal rempliUne erreur générique. Avec "output":"errors" — les erreurs détaillées
Les deux contrôles sont passésLa page de paiement avec la facture

Le premier contrôle ne révèle jamais la raison, quels que soient les réglages.

La paire "output":"errors" dans le JSON active les détails pour le second contrôle : le service nomme le champ, liste les valeurs autorisées et signale quand le plafond de 50 factures impayées est atteint. La clé vit à l'intérieur du conteneur signé et ne peut donc pas être injectée de l'extérieur.

Pendant la mise au point du formulaire, mettez "output":"errors" dans le JSON ; une fois le formulaire réglé, retirez la clé et reconstruisez le conteneur.

Si la signature elle-même ne correspond pas, comparez vos data et signature avec le jeu de référence dans Signature du formulaire HTML.

Et ensuite

Une facture créée par le formulaire est traitée de la même façon qu'une facture venue de l'API ou du tableau de bord :