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/v1CHARGEFLOW_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 biendispute.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 viafetchet le convertit enBlobprêt à être soumis à l'API Chargeflow.sendEvidence(params)envoie unFormDataavec la catégorie choisie. Les catégoriesadditional_evidenceetadditional_notesnécessitent un champcontentsupplémentaire.
API
new ChargeflowService(request: NextRequest)| Méthode | Description |
|---|---|
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.