Reddot UI Library

Docs
Chargeflow Service

Chargeflow Service

Service utilitaire pour valider les webhooks Chargeflow et téléverser des preuves.

Chargeflow gère automatiquement la contestation des paiements (chargebacks). Ce service encapsule les opérations critiques autour des webhooks Chargeflow dans un contexte Next.js : vérification cryptographique, parsing des payloads et dépôt de preuves.

Installation

$npx shadcn@latest add https://reddot.dottools.xyz/r/chargeflow.json

Structure du fichier

L'installation ajoute un fichier unique lib/services/chargeflow.ts exportant la classe ChargeflowService ainsi que les types associés au payload du webhook.

Variables d'environnement

Ajoutez ces variables à votre .env.local :

CHARGEFLOW_API_SECRET_KEY=sk_live_xxx
CHARGEFLOW_API_ACCESS_KEY=ak_live_xxx
CHARGEFLOW_API_BASE_URL=https://api.chargeflow.io/v1
  • CHARGEFLOW_API_SECRET_KEY : clé secrète utilisée pour recalculer la signature HMAC du webhook.
  • CHARGEFLOW_API_ACCESS_KEY : clé d'accès publique utilisée lors de l'envoi des preuves.
  • CHARGEFLOW_API_BASE_URL : (optionnel) URL racine de l'API Chargeflow. Laissez la valeur par défaut fournie par Chargeflow si disponible dans votre environnement.

Utilisation

Handler de webhook

import { NextRequest, NextResponse } from "next/server";
import { ChargeflowService } from "@/lib/services/chargeflow";
 
export async function POST(request: NextRequest) {
  const chargeflow = new ChargeflowService(request);
 
  try {
    const payload = await chargeflow.processWebhook();
 
    // Traiter le différend reçu (ex: persister les informations en base)
    await persistDispute(payload);
 
    return NextResponse.json({ received: true });
  } catch (error) {
    return NextResponse.json(
      { error: (error as Error).message },
      { status: 400 }
    );
  }
}
  • processWebhook() lit le corps de la requête, vérifie la signature HMAC (x-chargeflow-hmac-sha256) et garantit que l'événement est bien dispute.created.
  • Le payload validé est stocké en interne (this.webhookPayload) pour permettre l'envoi de pièces justificatives ultérieures.

Envoi de preuves

import { ChargeflowService } from "@/lib/services/chargeflow";
 
async function uploadEvidence(request: NextRequest, fileUrl: string) {
  const chargeflow = new ChargeflowService(request);
  const payload = await chargeflow.processWebhook();
 
  const { blob, error } = await chargeflow.getFileBlob(fileUrl);
  if (error || !blob) {
    throw new Error("Impossible de récupérer le fichier");
  }
 
  const response = await chargeflow.sendEvidence({
    category: "customer_communication",
    fileBlob: blob,
    fileName: `${payload.data.transaction.id}.pdf`,
  });
 
  if ("error" in response) {
    throw new Error(response.message ?? response.error);
  }
 
  return response;
}
  • getFileBlob(url) récupère un fichier distant via fetch et le convertit en Blob prêt à être soumis à l'API Chargeflow.
  • sendEvidence(params) envoie un FormData avec la catégorie choisie. Les catégories additional_evidence et additional_notes nécessitent un champ content supplémentaire.

API

new ChargeflowService(request: NextRequest)
MéthodeDescription
processWebhook()Valide la signature HMAC, parse le corps JSON et prépare le payload pour les opérations suivantes. Lance les erreurs invalid_signature, no_signature ou invalid_type en cas d'incohérence.
getFileBlob(fileUrl)Télécharge un fichier depuis une URL signée et retourne { blob } ou { error } selon le résultat.
sendEvidence(params)Dépose une preuve auprès de Chargeflow pour le différend courant. Nécessite que processWebhook() ait été appelé au préalable. Retourne { requestId, evidenceId } ou un objet d'erreur.

Types utiles

export interface ChargeflowWebhookPayload {
  webhookId: string;
  creationDate: string;
  type: "dispute.created" | "dispute.updated" | "dispute.won" | "dispute.lost";
  data: {
    chargeflowDisputeId: string;
    dispute: {
      processorId: string;
      processor: "stripe" | "paypal" | string;
      amount: {
        value: number;
        currency: string;
      };
      status:
        | "needs_response"
        | "under_review"
        | "warning_needs_response"
        | "warning_under_review"
        | "won"
        | "lost";
      reason:
        | "fraudulent"
        | "not_as_described"
        | "unrecognized"
        | "duplicate"
        | "subscription_canceled"
        | "product_unacceptable"
        | string;
      responseDueDate: string;
    };
    transaction: {
      id: string;
      creationDate: string;
      source: "stripe" | "paypal" | string;
      orderId?: string;
      customerEmail: string;
    };
  };
}

Ces types facilitent l'autocomplétion dans vos handlers et assurent l'accès typé aux propriétés clés du différend.