# Insights (https://docs.chargeflow.io/docs/merchants/insights) You want to know your chargeback position before your processor tells you. **Insights** is Chargeflow's monitoring product: a single view of payments and chargebacks across every processor you have connected, with proactive notifications when something moves in the wrong direction. ## When to use Insights [#when-to-use-insights] * You run more than one processor and have no single number for your dispute ratio. * You want warning that a ratio is approaching a scheme threshold while you can still act, not after a penalty. * You need dispute performance broken down by processor, reason code, or period for a board or a partner. * You want fraud patterns surfaced across your payment stack rather than per tool. ## What it gives you [#what-it-gives-you] | Capability | What it does | | ----------------------- | ------------------------------------------------------------------------------------ | | Holistic view | Payments and chargebacks from every connected processor in one dashboard | | Fraud intelligence | Patterns across your stack, not siloed per processor | | Customised insights | Cuts by processor, reason code, and period | | Real-time notifications | Told when a ratio moves, not at month end | | Proactive alerts | A warning when your chargeback ratio approaches a threshold, with the action to take | Insights reads from the same connections the rest of Chargeflow uses. Connect a processor once and it appears here. See [Integrations](https://docs.chargeflow.io/docs/reference/integrations). ## Why thresholds matter [#why-thresholds-matter] Card networks monitor dispute ratios, and crossing a threshold moves you into a monitoring program with fees, mandated remediation, and in the worst case loss of processing. The ratio is a lagging number, so the useful moment is while it is climbing. That is the moment Insights is built for: [Alerts](https://docs.chargeflow.io/docs/merchants/alerts) deflects the disputes and [Prevent](https://docs.chargeflow.io/docs/merchants/prevent) stops the risky orders, while Insights tells you which lever the numbers say to pull. Insights runs today in the Chargeflow dashboard. There is no public API for its metrics yet, so nothing on this page is callable. Dispute-level data is available now through the [Disputes API](https://docs.chargeflow.io/docs/api/2025-04-01/merchants/disputes) if you want to build your own reporting. ## Where Insights fits [#where-insights-fits] Prevent, Alerts, and Automation act on individual transactions and disputes. Insights acts on the portfolio: it is the layer that tells you whether the other three are working and where the next problem is forming. See the [product model](https://docs.chargeflow.io/docs/reference/start-here/product-model). ## Next step [#next-step] The usual response to a climbing ratio: deflect before the chargeback posts. # Interactive tutorials (https://docs.chargeflow.io/docs/merchants/interactive-tutorials) Interactive tutorials are not live yet. Until they are, the [Quickstart](https://docs.chargeflow.io/docs/merchants/quickstart) is the fastest path to a first working call. Interactive tutorials will let you run real API calls against seeded sandbox data from inside the page: authenticate, fetch a dispute, enrich it with order and customer data, and handle an alert, without leaving the docs. ## What they will cover [#what-they-will-cover] | Tutorial | What you will do | Closest guide today | | ------------------ | --------------------------------------------------- | ----------------------------------------------------------------------------------------- | | First call | Authenticate and read your first dispute | [Quickstart](https://docs.chargeflow.io/docs/merchants/quickstart) | | Automate a dispute | Ingest a dispute and let Automation submit evidence | [Automate a chargeback dispute](https://docs.chargeflow.io/docs/merchants/automation/automate-a-chargeback-dispute) | | Enrich evidence | Attach order, subscription, and communication data | [Enrich a dispute](https://docs.chargeflow.io/docs/merchants/automation/enrich-a-dispute) | | Handle an alert | Receive an alert and report its outcome | [Manage pre-chargeback alerts](https://docs.chargeflow.io/docs/merchants/alerts/manage-alerts) | Every tutorial will run against the [sandbox](https://docs.chargeflow.io/docs/merchants/sandbox), so nothing you do touches live disputes. ## Next step [#next-step] Make your first authenticated call: [Merchant quickstart](https://docs.chargeflow.io/docs/merchants/quickstart). # Merchants overview (https://docs.chargeflow.io/docs/merchants/overview) Chargeflow is an agentic dispute automation engine that recovers revenue from disputes on your behalf. Connect your PSPs and business tools in minutes; Chargeflow handles disputes from ingestion to submission. This section covers the merchant-facing products: **Automation** (most of these docs - everything below), **[Alerts](https://docs.chargeflow.io/docs/merchants/alerts)** (deflect complaints before they become chargebacks), and **[Prevent](https://docs.chargeflow.io/docs/merchants/prevent)** (stop risky orders before they ship; API coming soon). New to the vocabulary? Start with the [product model](https://docs.chargeflow.io/docs/reference/start-here/product-model). ## How it works [#how-it-works] 1. **Ingest**: Chargeflow automatically ingests 100% of your disputes from connected PSPs. 2. **First enrichment**: Chargeflow's Enrichment Engine pulls case-relevant signals to strengthen the evidence set. 3. **Second enrichment (optional)**: You add targeted signals via the Update Dispute API endpoint. 4. **Generation**: Chargeflow's AI agents compile a challenge strategy and compose a coherent response with a narrative. 5. **Submission**: Chargeflow submits the generated response back to your PSP. 6. **Monitor**: Chargeflow updates the dispute throughout its lifecycle so you can track progress programmatically. Start automation in minutes, then improve recovery by sending targeted enrichments to our API. ## How Chargeflow builds a response [#how-chargeflow-builds-a-response] Chargeflow orchestrates multiple agentic layers to assemble a dispute response from the data you and Chargeflow provide. You can improve outcomes by sending targeted enrichments to a single API endpoint, which is fast to implement and easy to maintain. * **Agentic automation**: Chooses what evidence to generate and how to present it based on available signals, historical data, network requirements, and domain intelligence. * **Simple integration**: One endpoint for enrichments; minimal payloads focused on what actually moves win rate. * **Data network effects**: Chargeflow augments your inputs with internal models (when available) to strengthen the case. Chargeflow partners with leading data-enrichment providers and uses internal models to enhance evidence and increase the likelihood of a win. ## Control and transparency [#control-and-transparency] You stay in control of automation strategy and evidence: * **Your data, end-to-end**: Fetch the complete, normalized dispute record, including Chargeflow-added enrichments, via a single retrieval endpoint for your own systems and BI. * **Override or provide**: Provide (or override) signals per dispute; Chargeflow adapts the response accordingly. * **Clear status**: Programmatic access to lifecycle status, evidence artifacts, and submission history. ## Privacy and security [#privacy-and-security] Chargeflow treats privacy and security as first-order features: data is minimized, segmented, and encrypted, partner enrichments are clearly labeled, and controls are continuously hardened. Chargeflow is SOC 2 Type II audited and GDPR-compliant - see [Security & compliance](https://docs.chargeflow.io/docs/reference/security) for certifications, encryption standards, and the Trust Center. ## Key guides [#key-guides] End-to-end automation flow The PATCH endpoint and enrichment mechanics Uploading files directly to a dispute Alerts API integration models and endpoints Logging customer conversations The evidence set for SaaS or e-commerce Configuring and verifying webhooks No-code automation via Zapier # Prevent (https://docs.chargeflow.io/docs/merchants/prevent) You want risky orders stopped before they ship - the only stage where stopping a dispute costs nothing. **Prevent** is Chargeflow's pre-fulfillment product: after checkout, every order is scored for dispute risk and given a clear recommendation - **approve**, **verify**, or **cancel** - so the orders most likely to become chargebacks never leave the warehouse. ## When to use Prevent [#when-to-use-prevent] * You want to stop friendly fraud - "item not received" or "not as described" abuse from real buyers - before fulfillment, not fight it after. * You want true fraud (stolen cards, false identities) and refund/return abuse flagged on the same signal. * You want to challenge suspicious buyers without cancelling their orders outright, so legitimate customers are not turned away. * You want fraud screening that never touches checkout - legitimate customers are never blocked at payment. ## How it works [#how-it-works] Prevent acts **after** payment and **before** fulfillment. The customer completes checkout normally; during the fulfillment window, Prevent scores the order using identity intelligence across device, IP, email, and payment behavior, backed by machine-learning models trained on the Chargeflow Network. Each order receives a risk score and one of three recommendations: * **Approve** - low risk; fulfill with confidence. * **Verify** - elevated risk; the buyer is challenged through a verification flow (a "yellow card") that confirms the order and the identity behind it. The challenge itself acts as a deterrent to abusive buyers, while legitimate buyers complete it and proceed. * **Cancel** - high risk; hold or cancel the order before it ships. Recommendations can be applied automatically against your rules, or reviewed manually in the Chargeflow dashboard. ## Set it up [#set-it-up] Prevent runs today through the [Chargeflow app for Shopify](https://apps.shopify.com/chargeflow) - a one-click install that screens every order regardless of which PSP processes the payment. Enable Prevent from the Chargeflow dashboard; no code is required. Shopify is the route in today, and support for other platforms is on the roadmap. If you are not on Shopify yet, the earliest stage you can act at is [Alerts](https://docs.chargeflow.io/docs/merchants/alerts). A public Prevent API (order scores, recommendations, and webhook events) is not yet available - nothing on this page is callable via the API today. When it ships, its reference and integration guides will live here. ## Where Prevent fits [#where-prevent-fits] Prevent acts at stage 2 of the [transaction lifecycle](https://docs.chargeflow.io/docs/reference/start-here/transaction-lifecycle) - the earliest, cheapest point to stop a dispute. Complaints that arise after fulfillment are deflected in the pre-chargeback window by [Alerts](https://docs.chargeflow.io/docs/merchants/alerts); chargebacks that are filed anyway are fought by [dispute automation](https://docs.chargeflow.io/docs/reference/concepts/dispute-automation). # Quickstart (https://docs.chargeflow.io/docs/merchants/quickstart) Get up and running with the Chargeflow API in five steps. By the end of this guide you will have authenticated, fetched disputes, enriched a dispute with evidence, and registered a webhook. ## Get your API key [#get-your-api-key] 1. Log in to the [Chargeflow App](https://app.chargeflow.io/auth/sign-in). 2. Navigate to **Settings → Developers**. 3. Click **Generate Keys**. 4. Copy your **API Access Key**. ## Validate your key [#validate-your-key] Confirm your key is active by hitting the key-validation health check: ```bash title="Terminal" curl -X GET https://api.chargeflow.io/public/2025-04-01/health-check/access-key \ -H "x-api-key: YOUR_API_KEY" ``` ```javascript title="Node.js" const res = await fetch('https://api.chargeflow.io/public/2025-04-01/health-check/access-key', { method: 'GET', headers: { 'x-api-key': process.env.CHARGEFLOW_API_KEY, }, }); const data = await res.json(); ``` ```python title="Python" import os, requests res = requests.get( "https://api.chargeflow.io/public/2025-04-01/health-check/access-key", headers={"x-api-key": os.environ["CHARGEFLOW_API_KEY"]}, ) data = res.json() ``` Expected response: ```json title="Response" "OK" ``` If you receive a `403 {"message":"Forbidden"}` response, your API key is invalid. Return to Settings → Developers, revoke the existing key, and generate a new one. ## List your disputes [#list-your-disputes] Fetch your first page of disputes: ```bash title="Terminal" curl -X GET "https://api.chargeflow.io/public/2025-04-01/disputes?limit=5" \ -H "x-api-key: YOUR_API_KEY" ``` ```javascript title="Node.js" const res = await fetch('https://api.chargeflow.io/public/2025-04-01/disputes?limit=5', { method: 'GET', headers: { 'x-api-key': process.env.CHARGEFLOW_API_KEY, }, }); const data = await res.json(); ``` ```python title="Python" import os, requests res = requests.get( "https://api.chargeflow.io/public/2025-04-01/disputes", headers={"x-api-key": os.environ["CHARGEFLOW_API_KEY"]}, params={"limit": 5}, ) data = res.json() ``` The response returns a paginated list of dispute objects. Use the `id` field from any dispute to continue with the next step. ## Enrich a dispute [#enrich-a-dispute] Send targeted transaction data to strengthen the evidence Chargeflow uses when composing a rebuttal: ```bash title="Terminal" curl -X PATCH https://api.chargeflow.io/public/2025-04-01/disputes/DISPUTE_ID \ -H "x-api-key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"transaction": {"type": "paid", "amount": 150, "currency": "USD"}}' ``` ```javascript title="Node.js" const res = await fetch('https://api.chargeflow.io/public/2025-04-01/disputes/DISPUTE_ID', { method: 'PATCH', headers: { 'x-api-key': process.env.CHARGEFLOW_API_KEY, 'Content-Type': 'application/json', }, body: JSON.stringify({ transaction: { type: 'paid', amount: 150, currency: 'USD' } }), }); const data = await res.json(); ``` ```python title="Python" import os, requests res = requests.patch( "https://api.chargeflow.io/public/2025-04-01/disputes/DISPUTE_ID", headers={"x-api-key": os.environ["CHARGEFLOW_API_KEY"]}, json={"transaction": {"type": "paid", "amount": 150, "currency": "USD"}}, ) data = res.json() ``` Replace `DISPUTE_ID` with the `id` value from your dispute list. Chargeflow's Enrichment Engine evaluates submitted artifacts and includes only those that strengthen the rebuttal - submit everything you have. ## Register a webhook [#register-a-webhook] Subscribe to the `dispute.created` event to receive real-time notifications whenever a new dispute is ingested: ```bash title="Terminal" curl -X POST https://api.chargeflow.io/public/2025-04-01/webhooks \ -H "x-api-key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"event": "dispute.created", "url": "https://your-server.com/webhook"}' ``` ```javascript title="Node.js" const res = await fetch('https://api.chargeflow.io/public/2025-04-01/webhooks', { method: 'POST', headers: { 'x-api-key': process.env.CHARGEFLOW_API_KEY, 'Content-Type': 'application/json', }, body: JSON.stringify({ event: 'dispute.created', url: 'https://your-server.com/webhook' }), }); const data = await res.json(); ``` ```python title="Python" import os, requests res = requests.post( "https://api.chargeflow.io/public/2025-04-01/webhooks", headers={"x-api-key": os.environ["CHARGEFLOW_API_KEY"]}, json={"event": "dispute.created", "url": "https://your-server.com/webhook"}, ) data = res.json() ``` Each registration subscribes one endpoint to one event; repeat per event, or pass `"event": "*"` to receive all events. Chargeflow will send an HTTP POST to your endpoint each time a matching event occurs. Respond with `200` to acknowledge delivery. ## Next steps [#next-steps] Learn how to handle and verify webhook events in your server. Enable HMAC signature validation for production-grade security. Understand dispute lifecycle, stages, and statuses. # Sandbox (https://docs.chargeflow.io/docs/merchants/sandbox) An isolated sandbox for merchant integrations is on the way. It will let you build and validate against seeded test disputes and alerts without touching production data, with seeded scenarios (won, lost, representment, alert prevented) and an in-page API explorer. Interactive, runnable tutorials will ship alongside it. Until the sandbox ships, build against the live API with care. ## Build safely before the sandbox [#build-safely-before-the-sandbox] 1. Generate API keys from the [Chargeflow App](https://app.chargeflow.io/settings#developers), see [API keys](https://docs.chargeflow.io/docs/reference/api-fundamentals/test-credentials). 2. Read disputes and alerts before you write, so you can confirm response shapes without side effects. 3. Make your first call with the [Quickstart](https://docs.chargeflow.io/docs/merchants/quickstart). 4. Work through the [Go-live checklist](https://docs.chargeflow.io/docs/reference/api-fundamentals/go-live-checklist) before you send production traffic. ## What you will be able to test [#what-you-will-be-able-to-test] * Authentication against `https://api.chargeflow.io` using the `x-api-key` header. * List and read disputes with [pagination](https://docs.chargeflow.io/docs/reference/api-fundamentals/pagination), and fetch a single dispute by ID. * Upload evidence, following [Upload evidence](https://docs.chargeflow.io/docs/merchants/automation/upload-evidence). * Pre-chargeback alerts, following [Manage alerts](https://docs.chargeflow.io/docs/merchants/alerts/manage-alerts). * Webhooks for `dispute.created` and alert events, following [Subscribe to events](https://docs.chargeflow.io/docs/merchants/automation/subscribe-to-events). ## Next steps [#next-steps] Generate your keys. End-to-end flows to follow. Explorer and linter, coming soon. # Merchant webhook events (https://docs.chargeflow.io/docs/merchants/webhook-events) Chargeflow emits webhook events so your system reacts to disputes and alerts in real time. Subscribe to the events your integration needs and Chargeflow delivers an HTTP POST to your endpoint whenever one fires. Formal payload schemas are generated from the spec and live in the [API reference](https://docs.chargeflow.io/docs/api/2025-04-01/merchants/webhooks-events); this page is the narrative catalog - when each event fires and what to do with it. ## Available events [#available-events] | Event | Fires when | What to do | | --------------------------------------------------------- | ------------------------------------------------- | ------------------------------------------------ | | [`dispute.created`](#dispute-created) | A new dispute is ingested and first-pass enriched | Trigger your enrichment flow | | [`alerts.created`](#alerts-created) | A new pre-chargeback alert arrives | Refund / mitigate (or trigger workflows) | | [`alerts.updated`](#alerts-updated) | An alert's outcome changes | Sync your records to the new outcome | | [`alerts.transaction.linked`](#alerts-transaction-linked) | An alert is matched to a PSP transaction | Get the transaction to refund (merchant-managed) | To register an endpoint and build a handler, see [Subscribe to webhook events](https://docs.chargeflow.io/docs/merchants/automation/subscribe-to-events). For signature verification and delivery/retry behavior, see [Webhooks](https://docs.chargeflow.io/docs/reference/concepts/webhooks). `dispute.created` arrives wrapped in an envelope (`{type, data, creationDate, webhookId}`) carrying the current dispute resource under `data`. The three alert events are delivered **flat, with no envelope** - their `type` field holds the alert type, not the event name. `dispute.created` is the only dispute event. Status changes, evidence submission, and the final outcome are **not** pushed: read them with `GET /public/2025-04-01/disputes/{disputeId}` on your own schedule, or from the dashboard. Wider dispute-event coverage is planned. ## `dispute.created` [#dispute-created] Fires after Chargeflow ingests a new dispute from a connected PSP and completes its first enrichment pass - so the payload already shows what Chargeflow matched, and you can focus on the gaps. **What to do:** inspect the linked objects (`transaction`, `order`, `subscription`, `customerCommunication`), gather any missing high-impact data from your systems, then `PATCH` the dispute using `data.id`. See [Enrich a dispute](https://docs.chargeflow.io/docs/merchants/automation/enrich-a-dispute) for the endpoint and merge behavior. Payload: [API reference](https://docs.chargeflow.io/docs/api/2025-04-01/merchants/webhooks-events/dispute.created). ## `alerts.created` [#alerts-created] Fires in real time when Chargeflow ingests a new pre-chargeback alert. Some fields (for example `transaction`) may populate later; for the full record call `GET /public/2025-04-01/alerts/{id}`. **What to do:** in the automated Chargeflow Alerts model no action is required - use it to trigger supplementary workflows (CRM tagging, fraud notifications). In the merchant-managed model, locate the transaction, refund it, and report the outcome. See [Manage pre-chargeback alerts](https://docs.chargeflow.io/docs/merchants/alerts/manage-alerts). Payload: [API reference](https://docs.chargeflow.io/docs/api/2025-04-01/merchants/webhooks-events/alerts.created). ## `alerts.updated` [#alerts-updated] Fires whenever Chargeflow updates an alert's `outcome`. | Outcome | Meaning | | --------------------- | -------------------------------------------- | | `prevented` | Refunded; chargeback prevented | | `not_found` | No matching transaction located | | `duplicate` | Duplicate of an existing alert | | `chargebacked` | Escalated to a chargeback despite mitigation | | `previously_refunded` | Already refunded before the alert arrived | | `pending` | Still being processed | | `error` | An error occurred while handling the alert | **What to do:** sync your records to the outcome. On `prevented`, record the win and close tickets; on `chargebacked`, watch for `dispute.created` to begin enrichment; on `not_found`, investigate manually; `duplicate` / `previously_refunded` need no action. Payload: [API reference](https://docs.chargeflow.io/docs/api/2025-04-01/merchants/webhooks-events/alerts.updated). ## `alerts.transaction.linked` [#alerts-transaction-linked] Fires when Chargeflow matches an alert to a PSP transaction using card metadata (amount, BIN, last 4, auth code, ARN). Not every alert produces this event - if no match is found automatically, it does not fire. **What to do:** informational in the automated model. In merchant-managed mode it supplies the `transactionId` to refund before you report the outcome - subscribe to both `alerts.created` and this event, since some alerts carry the transaction on creation and others only here. See [Manage pre-chargeback alerts](https://docs.chargeflow.io/docs/merchants/alerts/manage-alerts). Payload: [API reference](https://docs.chargeflow.io/docs/api/2025-04-01/merchants/webhooks-events/alerts.transaction.linked). ## Next step [#next-step] Register an endpoint, verify signatures, and build your handler. # Interactive tutorials (https://docs.chargeflow.io/docs/platforms/interactive-tutorials) Interactive tutorials are not live yet. Until they are, the [Quickstart](https://docs.chargeflow.io/docs/platforms/quickstart) is the fastest path to a first working call. Interactive tutorials will let you run real API calls against seeded sandbox data from inside the page: create an account, load a dispute, generate evidence, and receive the webhook that says it is ready, without leaving the docs. ## What they will cover [#what-they-will-cover] | Tutorial | What you will do | Closest guide today | | ------------------ | ------------------------------------------------- | ----------------------------------------------------------------------------- | | First call | Authenticate and create your first account | [Quickstart](https://docs.chargeflow.io/docs/platforms/quickstart) | | Onboard a merchant | Create an account and link a processor | [Onboard a merchant](https://docs.chargeflow.io/docs/platforms/eaas/onboard-a-merchant) | | Generate evidence | Load a dispute and generate evidence through EaaS | [Generate evidence in seconds](https://docs.chargeflow.io/docs/platforms/eaas/generate-evidence-in-10s) | | Receive events | Register a webhook and handle `evidence.ready` | [Platform webhook events](https://docs.chargeflow.io/docs/platforms/webhook-events) | Every tutorial will run against the [sandbox](https://docs.chargeflow.io/docs/platforms/sandbox), so nothing you do touches live disputes. ## Next step [#next-step] Make your first authenticated call: [Platform quickstart](https://docs.chargeflow.io/docs/platforms/quickstart). # Monitor integration health (https://docs.chargeflow.io/docs/platforms/monitor-integration-health) Use the health check endpoints to verify that the Chargeflow API is reachable and that your API key is valid. These are lightweight endpoints designed for integration monitoring and pre-flight checks. ## Check service availability [#check-service-availability] Verifies that the Chargeflow API is reachable and returning responses. ``` GET /public/2025-04-01/health-check ``` ### Example request [#example-request] ```bash title="Terminal" curl https://api.chargeflow.io/public/2025-04-01/health-check \ -H "x-api-key: YOUR_PLATFORM_API_KEY" ``` ### Example response [#example-response] ```json title="Response" "OK" ``` A `200 OK` response confirms the service is available. Any non-200 response indicates a service-level issue. Check the [Chargeflow status page](https://status.chargeflow.io) for incident updates. *** ## Validate your API key [#validate-your-api-key] Verifies that your `x-api-key` is valid and currently active. ``` GET /public/2025-04-01/health-check/access-key ``` ### Example request [#example-request-1] ```bash title="Terminal" curl https://api.chargeflow.io/public/2025-04-01/health-check/access-key \ -H "x-api-key: YOUR_PLATFORM_API_KEY" ``` ### Example response [#example-response-1] ```json title="Response" "OK" ``` A `200 OK` confirms the key is valid. A `403` response with `{"message": "Forbidden"}` indicates an invalid or revoked key (see [Error handling](https://docs.chargeflow.io/docs/reference/api-fundamentals/error-handling)). Regenerate your credentials in the Developer Hub. *** ## When to use these endpoints [#when-to-use-these-endpoints] **Add health checks to your integration monitoring.** Call both endpoints in your uptime checks to catch connectivity issues before they affect your merchants. Recommended use cases: * **Startup/initialization check:** call before making other API calls when your service starts or redeploys, to confirm the integration is healthy. * **Incident investigation:** if webhooks stop arriving or API calls fail unexpectedly, run these checks first to rule out connectivity and authentication issues before deeper debugging. * **Canary monitoring:** include in synthetic monitoring to get alerted on Chargeflow availability issues without waiting for a real dispute to fail. ## Next steps [#next-steps] Get notified when a merchant connection breaks. Resolve the errors these checks surface. Act on the merchant accounts behind a failed check. Check for ongoing Chargeflow incidents. # Platforms overview (https://docs.chargeflow.io/docs/platforms/overview) You are an ISV, platform, or PSP whose merchants get chargebacks, and you need to give them a dispute product without building a dispute team. Connect is that product, delivered as infrastructure you put your own name on. ## What Connect is [#what-connect-is] **Connect - "Chargeflow for Platforms"** - is the horizontal offering in the [Chargeflow product model](https://docs.chargeflow.io/docs/reference/start-here/product-model): the [Prevent](https://docs.chargeflow.io/docs/merchants/prevent), [Alerts](https://docs.chargeflow.io/docs/merchants/alerts) and [Automation](https://docs.chargeflow.io/docs/merchants/overview) stack, exposed so your platform can offer it to the merchants it already serves. It is a B2B2B product - three parties, one relationship: | Party | Role | | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **Chargeflow** | Runs the engine. The dispute expertise was built on the merchant side of the market first, across many payment service providers, before the first platform integration. | | **Your platform** | Delivers that expertise as a product under its own brand, with no dispute infrastructure to build. | | **The merchant** | Is protected inside the product they already use. Never has to become a chargeback expert, and never has to see Chargeflow. | Connect sells to platforms, not to their merchants. What you buy is the dispute lifecycle, at the level of control you choose. ## Core capabilities [#core-capabilities] | Capability | What it means for you | | ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Onboard and manage merchants** | Invite merchants to a co-branded portal or activate them instantly, then track each one's dispute activity and recovery performance. See [Merchants](./connect/merchants). | | **Automate dispute recovery** | Disputes flow in from connected processors; scoring, evidence, and submission are handled for you. See [How recovery works](https://docs.chargeflow.io/docs/reference/concepts/how-recovery-works). | | **Connect payment processors** | Link Stripe, PayPal, Adyen, Checkout.com, Braintree and more so disputes route automatically. See [Integrations](./connect/integrations). | | **Generate evidence via API** | Evidence-as-a-Service produces and returns dispute evidence programmatically, with no PSP connection required. See [Set up EaaS](./eaas/setup). | | **Embed widgets** *(beta)* | Drop pre-built, real-time dispute widgets into your own dashboard. See [Widgets](./connect/widgets). | | **Control access** | API keys, webhooks, team members, and role-based permissions. See [Developers](./connect/developers) and [Settings](./connect/settings). | Your merchants see your platform. The recovery engine runs underneath. ## When to use it [#when-to-use-it] * Your merchants concede disputes they could win, because compiling and uploading evidence takes longer than the dispute is worth to them. * Your support team fields chargeback questions your product has no answer for, and the first chargeback is the moment a merchant decides whether you are a partner or a payment rail. * You already run your own submission engine and want bank-ready evidence plus the outcome signal over an API, and nothing more. * You want to sell dispute protection as your own product, on your own pricing, without an underlying vendor visible to merchants. ## Which model fits you [#which-model-fits-you] Four delivery models, differing in who owns the brand and who takes the action. Every one runs the same engine. | You are | Start with | Why | | ----------------------------------------------------------- | ---------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | | An **ISV** with your own submission flow | [EaaS](#evidence-as-a-service-eaas) | You keep the workflow; you consume evidence and outcomes over the API. | | A **platform or PSP** adding disputes to your product | [EaaS](#evidence-as-a-service-eaas) or [Co-Branded](#co-branded) | API-first if you have engineers to spend, Co-Branded if you want the shortest path to launch. | | A **merchant of record (MoR)** | [Co-Branded](#co-branded) or [White-Label](#white-label-beta) | EaaS does not fit an MoR model; the branded surfaces do. | | A platform that wants **disputes as your own product line** | [White-Label](#white-label-beta) | Your product name, your UI, your pricing, on the Public API. | Model availability is set per platform by your Chargeflow account manager. Talk to them before you build - see [Support](https://docs.chargeflow.io/docs/reference/support). ### Evidence-as-a-Service (EaaS) [#evidence-as-a-service-eaas] **Available today.** A chargeback lands in your platform, the engine builds the case, the merchant approves it with one click - all inside your UI, with Chargeflow invisible. You supply the dispute data, Chargeflow returns a bank-ready PDF evidence package and the structured data behind it. ISVs are the sharpest fit: many already run their own submission engine and want only the evidence and the win signal over the API. EaaS is for ISVs, platforms and PSPs - not for merchants of record. The capabilities, the entitlement, and who it's for. Account setup, the call, the webhook, the PDF. ### Co-Branded [#co-branded] **Available today.** The Chargeflow interface with your logo, your colors, and your domain. Merchants see your brand; the engine runs underneath, configured by Chargeflow rather than built by you. This is the fastest brand-safe launch: no dispute UI to build, no submission flow to own. It fits ISVs and merchants of record that want to be live this month rather than next quarter. Setup is contract-dependent and arranged with your Chargeflow account team - there is no self-serve configuration. ### White-Label (beta) [#white-label-beta] Your own product name, your own UI, and your own pricing, with Chargeflow invisible end to end. Chargeflow connects to your merchants' PSPs and data sources, enriches disputes, builds evidence, and submits it - all under your brand. This is the model platforms ask for most, and it rides on the same Public API the rest of these docs describe. What Chargeflow runs for you, and how it compares to EaaS. Platform account, keys, webhooks, merchant integrations. ### Alerts-as-a-Service (AaaS) [#alerts-as-a-service-aaas] **Soon.** Chargeflow sends Ethoca alerts on the merchant's own statement descriptors; your platform issues the refund and stops the chargeback before it is ever filed. Same shape as EaaS - Chargeflow's intelligence, your action, your brand. Enrolling a merchant for Ethoca and RDR will take a single API call at onboarding. Until AaaS ships, alert-based deflection is available to merchants directly. See [Alerts](https://docs.chargeflow.io/docs/merchants/alerts). ## Choose your level of autonomy [#choose-your-level-of-autonomy] The on-ramp is not a smaller product. It is the same engine, run at the level of control you pick, per merchant segment: | Mode | Who decides | Use it when | | -------------- | -------------------------------------------------------------- | ------------------------------------------------------------------------------ | | **Auto-pilot** | Chargeflow generates and submits, no human in the loop | Volume is high and per-dispute review is not worth a person's time. | | **Co-pilot** | Chargeflow generates, your merchant approves before submission | Your merchants or your risk team require sign-off on what is sent to the bank. | Acquirers and regulated platforms usually start on co-pilot: an engine deciding everything unsupervised creates its own problems. Segment your merchant base and run both - the Public API exposes the same endpoints either way. ## What you'll need [#what-youll-need] 1. **A Chargeflow Connect account.** Your account manager invites your team. 2. **API keys.** Generate them in the Developer Hub in the Connect UI. 3. **A Chargeflow account per merchant.** See [Onboard a merchant](./eaas/onboard-a-merchant). ## Get started [#get-started] Whichever model you land on, the first thing to do is prove the engine works against a real dispute. The quickstart takes you from API key to a bank-ready evidence package. Authenticate, generate evidence, receive the webhook, fetch the PDF. Running Connect day to day, rather than integrating against it, is covered in [Run Connect](./connect): merchants, disputes, integrations, widgets, developers, and settings. The API path itself runs through [Evidence-as-a-Service](./eaas/introduction): [onboard a merchant](./eaas/onboard-a-merchant), [submit platform disputes](./eaas/submit-platform-disputes), then generate evidence. Alongside it, subscribe to the [webhook events](./webhook-events), watch the connection with [Monitor integration health](./monitor-integration-health), and find partner-facing tooling in [Partner Studio](./partner-studio). All Platforms API endpoints authenticate with your `x-api-key` header. See the [Authentication](https://docs.chargeflow.io/docs/reference/api-fundamentals/authentication) guide for how to generate keys and optionally enable HMAC signature verification. # Partner Studio (https://docs.chargeflow.io/docs/platforms/partner-studio) You are a platform or PSP with an active or proof-of-concept (POC) relationship with Chargeflow, and you want the partner-facing tooling to evaluate, sell, and operate Chargeflow alongside the core [Platforms API](https://docs.chargeflow.io/docs/platforms/overview). Partner Studio brings that tooling together in one gated workspace. It is built for the same audience as the rest of the Platforms documentation - B2B platforms and PSPs, not individual merchants. The Partner Studio tools below are on the way. Each is gated to approved partners and becomes available once your platform is approved and the relevant access is enabled on your account. In the meantime, the Platforms overview covers the products and workflows this tooling is built on. ## How a platform requests access [#how-a-platform-requests-access] Partner Studio access is granted per platform, not self-served: 1. Review the [Platforms overview](https://docs.chargeflow.io/docs/platforms/overview) to confirm Chargeflow fits your integration model. 2. Reach out through [Support](https://docs.chargeflow.io/docs/reference/support) or your Chargeflow account manager to request Partner Studio access for your platform. 3. Once your platform is approved, the gated tools become available to your team as they ship. ## What's coming to Partner Studio [#whats-coming-to-partner-studio] Each capability is gated to approved partners and not yet available. ### Demo generator [#demo-generator] **Soon.** Produce a sample evidence experience to show prospects and internal teams how Chargeflow turns dispute data into a bank-ready package. ### Enablement [#enablement] **Soon.** Battlecards plus an ROI and win-rate estimator to support partner sales conversations for a given merchant base. ### White-label config [#white-label-config] **Soon.** Configuration for presenting Chargeflow under your own brand. Options are contract-dependent and set up with your Chargeflow account team rather than self-served. ### Advanced EaaS [#advanced-eaas] **Soon.** Compliance options and evidence-language localization that extend the standard [Evidence-as-a-Service](https://docs.chargeflow.io/docs/platforms/eaas/introduction) integration, so packages suit the regions and languages your merchants operate in. ### Runbooks [#runbooks] **Soon.** Per-platform operational guides for running Chargeflow day to day, tailored to how your platform is integrated. ## Next steps [#next-steps] The core integration this tooling wraps - start here. # Quickstart (https://docs.chargeflow.io/docs/platforms/quickstart) Get a platform integration running in four steps. By the end you will have authenticated, generated an AI evidence package for a merchant's dispute, received the `evidence.ready` webhook, and fetched the bank-ready PDF. This is the **Evidence-as-a-Service (EaaS)** flow: your platform supplies dispute data, Chargeflow returns a polished PDF in about 30 seconds. Merchants never call it directly. New here? Start with the [Platforms overview](https://docs.chargeflow.io/docs/platforms/overview). ## Get your platform API key [#get-your-platform-api-key] 1. Log in to the [Chargeflow Connect dashboard](https://app.chargeflow.io/auth/sign-in). 2. Navigate to **Settings → Developers**. 3. Click **Generate Keys** and copy your **API Access Key**. EaaS must be enabled on your Connect account by your Chargeflow account manager. Without it, every EaaS call returns `403_eaas_not_enabled`. See [What is EaaS?](https://docs.chargeflow.io/docs/platforms/eaas/introduction). ## Generate evidence [#generate-evidence] `POST /public/2025-04-01/evidence` accepts an existing `dispute_id` or a full inline dispute object. The dispute must be in `needs_response` status. ```bash title="Terminal" curl -X POST https://api.chargeflow.io/public/2025-04-01/evidence \ -H "x-api-key: YOUR_PLATFORM_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "account_id": "66e6ea9ecd94925a9f8060d9", "dispute": { "dispute_id": "66e6ea9ecd94925a9f8060d9" } }' ``` ```javascript title="Node.js" const res = await fetch('https://api.chargeflow.io/public/2025-04-01/evidence', { method: 'POST', headers: { 'x-api-key': process.env.CHARGEFLOW_PLATFORM_API_KEY, 'Content-Type': 'application/json', }, body: JSON.stringify({ account_id: '66e6ea9ecd94925a9f8060d9', dispute: { dispute_id: '66e6ea9ecd94925a9f8060d9' }, }), }); const data = await res.json(); ``` ```python title="Python" import os, requests res = requests.post( "https://api.chargeflow.io/public/2025-04-01/evidence", headers={"x-api-key": os.environ["CHARGEFLOW_PLATFORM_API_KEY"]}, json={ "account_id": "66e6ea9ecd94925a9f8060d9", "dispute": {"dispute_id": "66e6ea9ecd94925a9f8060d9"}, }, ) data = res.json() ``` The API responds immediately with `in_progress`. Generation is asynchronous, so the PDF is not in this response, store the `id` as your permanent reference. ```json title="Response" { "id": "ev_abc123456789", "status": "in_progress", "file_url": null, "file_version": 1 } ``` ## Receive the evidence. ready webhook [#receive-the-evidence-ready-webhook] Do not poll in a tight loop. Subscribe to `evidence.ready` and `evidence.error` in the Connect Developer Hub, then let Chargeflow push the result when the PDF is ready. ```javascript title="Node.js" app.post('/webhook', express.json(), (req, res) => { const event = req.body; res.json({ received: true }); // acknowledge first if (event.event?.type === 'evidence.ready') { const { id, file_url } = event.evidence; saveEvidencePdf(id, file_url); // download and submit to your PSP } }); ``` ## Fetch the latest evidence link [#fetch-the-latest-evidence-link] The download link expires 7 days after it is issued. Read the evidence record by `id` any time for a fresh link: ```bash title="Terminal" curl -X GET https://api.chargeflow.io/public/2025-04-01/evidence/ev_abc123456789 \ -H "x-api-key: YOUR_PLATFORM_API_KEY" ``` ```javascript title="Node.js" const res = await fetch('https://api.chargeflow.io/public/2025-04-01/evidence/ev_abc123456789', { method: 'GET', headers: { 'x-api-key': process.env.CHARGEFLOW_PLATFORM_API_KEY, }, }); const data = await res.json(); ``` ```python title="Python" import os, requests res = requests.get( "https://api.chargeflow.io/public/2025-04-01/evidence/ev_abc123456789", headers={"x-api-key": os.environ["CHARGEFLOW_PLATFORM_API_KEY"]}, ) data = res.json() ``` ## Next steps [#next-steps] The full copy-paste-runnable flow, including regeneration. Connect account setup and webhook payload shapes. HMAC signatures and production-grade key handling. Create and manage merchant accounts via the API. # Sandbox (https://docs.chargeflow.io/docs/platforms/sandbox) An isolated sandbox for platform integrations is on the way. It will let you build and validate against seeded test accounts and disputes without touching production data, including a sample EaaS package and an in-page API explorer. Interactive, runnable tutorials will ship alongside it. Until the sandbox ships, build against the live API with care. ## Build safely before the sandbox [#build-safely-before-the-sandbox] 1. Generate API keys from the [Chargeflow App](https://app.chargeflow.io/settings#developers), see [API keys](https://docs.chargeflow.io/docs/reference/api-fundamentals/test-credentials). 2. Read [How Evidence as a Service works](https://docs.chargeflow.io/docs/platforms/eaas/how-it-works) before you build your generation flow. 3. Work through the [Go-live checklist](https://docs.chargeflow.io/docs/reference/api-fundamentals/go-live-checklist) before you send production traffic. ## What you will be able to test [#what-you-will-be-able-to-test] * Authentication against `https://api.chargeflow.io` using the `x-api-key` header. * Onboard accounts, following [Onboard a merchant](https://docs.chargeflow.io/docs/platforms/eaas/onboard-a-merchant). * Submit platform disputes, following [Submit platform disputes](https://docs.chargeflow.io/docs/platforms/eaas/submit-platform-disputes). * Generate evidence, following the [Generate evidence recipe](https://docs.chargeflow.io/docs/platforms/eaas/generate-evidence-in-10s). * Webhooks for `evidence.ready`, `evidence.error`, and `integration.access.error` events. ## Next steps [#next-steps] Generate your keys. The core platform product. The end-to-end flow. # Platform webhook events (https://docs.chargeflow.io/docs/platforms/webhook-events) Chargeflow pushes real-time notifications to your platform when key events occur. Formal payload schemas are generated from the spec and live in the [API reference](https://docs.chargeflow.io/docs/api/2025-04-01/platforms/webhooks-events); this page is the narrative catalog - when each event fires and what to do. For signature verification and delivery/retry behavior, see [Webhooks](https://docs.chargeflow.io/docs/reference/concepts/webhooks). ## Available events [#available-events] | Event | Fires when | What to do | | ----------------------------------------------------------------------------------- | ----------------------------------------- | ---------------------------------- | | [`evidence.ready`](#evidence-ready) | An evidence PDF is generated | Download and submit it to your PSP | | [`evidence.error`](#evidence-error) | Generation fails after all retries | Read the error code, fix, retry | | [`integration.access.error`](#integration-access-error) | Chargeflow loses access to a merchant PSP | Get the merchant to reconnect | | [`dispute.created`](https://docs.chargeflow.io/docs/api/2025-04-01/platforms/webhooks-events/dispute.created) | A dispute is ingested for a merchant | Schema in the API reference | ## `evidence.ready` [#evidence-ready] Fired when an EaaS evidence PDF has been generated and is available to download. `file_url` expires **7 days** after it is issued. Store the `evidence.id`, not the URL; call the evidence API with the id for a fresh link. **What to do:** (1) verify the `x-chargeflow-hmac-sha256` signature; (2) download the `file_url` and store the PDF; (3) submit it to your PSP before `due_by`; (4) optionally surface an "evidence ready" status to the merchant. Regeneration re-fires this event with an incremented `file_version` (same `evidence.id`). Payload: [API reference](https://docs.chargeflow.io/docs/api/2025-04-01/platforms/webhooks-events/evidence.ready). ## `evidence.error` [#evidence-error] Fired when generation fails after all automatic retries. Chargeflow will not retry further until you call the Generate Evidence API again. | Error code | Cause | Resolution | | ---------------------------- | ------------------------------- | ---------------------------------------------------------------------------- | | `422_dispute_invalid_state` | Dispute not in `needs_response` | If it moved to `under_review` / `won` / `lost`, generation no longer applies | | `409_generation_in_progress` | A generation is already running | Wait for `evidence.ready` / `evidence.error` | | `404_*_not_found` | Dispute not found | Verify `dispute_id` + `account_id` match | | `403_eaas_not_enabled` | Key not entitled to EaaS | Contact your account manager | | `504_generation_timeout` | Transient AI timeout | Retry the request | **What to do:** verify the signature, read `error_code`, fix the underlying issue, then retry `POST /public/2025-04-01/evidence`. Payload: [API reference](https://docs.chargeflow.io/docs/api/2025-04-01/platforms/webhooks-events/evidence.error). ## `integration.access.error` [#integration-access-error] Fired when Chargeflow cannot access a merchant's PSP or data source - usually expired, revoked, or changed credentials. Relevant primarily for [White-Label](https://docs.chargeflow.io/docs/platforms/chargeflow-embedded/overview) integrations. While the integration is broken, Chargeflow cannot ingest or enrich disputes for this merchant. Cases may be missed or processed with incomplete data until it is restored. **What to do:** (1) verify the signature; (2) identify the merchant via `integration.account_id` / `integration.ext_account_id`; (3) notify them that their `integration.provider` connection broke; (4) guide them to re-authorize. Common causes: rotated/revoked PSP keys, expired OAuth tokens (Shopify, WooCommerce), or a suspended PSP account. Payload: [API reference](https://docs.chargeflow.io/docs/api/2025-04-01/platforms/webhooks-events/integration.access.error). ## Next step [#next-step] The API call these events report on. # Changelog (https://docs.chargeflow.io/docs/reference/changelog) Chargeflow uses date-based API versioning. See [API Versioning](https://docs.chargeflow.io/docs/reference/concepts/api-versioning) for how to specify a version in your requests. ## 2025-04-01 [#2025-04-01] **Release Date:** April 1, 2025 New endpoints and payload modifications: * Added Alerts API (`GET /alerts`, `GET /alerts/{id}`, `POST /alerts/{id}/outcome`) * Added Customer Communication endpoint * Added Platform Accounts API (`POST`, `GET`, `PATCH /accounts`) * Added Evidence-as-a-Service (`POST /evidence`, `GET /evidence`, `GET /evidence/{id}`) * Added Platform Disputes (`POST /platform/disputes`) * Updated Disputes API payload structure ## 2024-03-18 [#2024-03-18] **Release Date:** March 18, 2024 Initial API release: * Disputes API (`GET /disputes`, `GET /disputes/{id}`, `PATCH /disputes/{id}`) * Evidence Upload (`POST /disputes/{id}/evidence`) * Webhooks API (`GET /webhooks`, `POST /webhooks`, `DELETE /webhooks/{id}`) * Health Check endpoints ## Next steps [#next-steps] How to pin a version and migrate when one is deprecated The full endpoint reference for the current version Make your first request against the current version # Error codes reference (https://docs.chargeflow.io/docs/reference/error-codes) A quick lookup of the codes the Chargeflow API returns. For how to **handle and retry** each status - which are retry-safe, how to back off, and how to diagnose a `403` - see [Error handling](https://docs.chargeflow.io/docs/reference/api-fundamentals/error-handling). ## HTTP status codes [#http-status-codes] | Status | Name | Meaning | | ------ | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | | `400` | Bad Request | Malformed syntax or incorrect parameters. | | `401` | Unauthorized | Missing or invalid API key (or bad HMAC signature, if enabled). | | `403` | Forbidden | Valid key without permission for the resource, or an invalid key. [Diagnose which →](https://docs.chargeflow.io/docs/reference/api-fundamentals/error-handling#http-error-codes) | | `404` | Not Found | The resource or URL does not exist. | | `429` | Too Many Requests | Rate limit exceeded. | | `500` | Internal Server Error | Unexpected server error. | | `502` | Bad Gateway | Upstream/gateway error. | For which of these are safe to retry and how, see [Error handling → retry safety](https://docs.chargeflow.io/docs/reference/api-fundamentals/error-handling#retry-safety-at-a-glance). ## EaaS-specific error codes [#eaas-specific-error-codes] | Error Code | Description | Resolution | | ---------------------------- | ----------------------------------------- | ------------------------------------------------ | | `422_dispute_invalid_state` | Dispute must have status `needs_response` | Check dispute status before generating evidence | | `409_generation_in_progress` | Evidence generation already in progress | Use `idempotency-key` header to avoid duplicates | | `404_*_not_found` | Resource not found | Verify the ID in your request | | `403_eaas_not_enabled` | API key not entitled to EaaS | Contact your account manager | | `504_generation_timeout` | Generation timed out | Retry the request | ## Next steps [#next-steps] How to handle and recover from each status code What to do when you hit a 429 Fix 401 and 403 responses What to include when you contact the team # FAQ (https://docs.chargeflow.io/docs/reference/faq) You are evaluating or integrating Chargeflow and need a quick answer - on the API, security, data handling, or how Chargeflow operates. Each answer here is short by design and links to the page where the topic is documented in full. ## Getting started [#getting-started] Any of them. The API is platform-independent: it reads and writes the disputes and alerts already ingested into your account, so all that matters is that at least one payment processor or store is connected. See [Integrations & Ecosystem](https://docs.chargeflow.io/docs/reference/integrations). Send it as the `x-api-key` header on requests to `https://api.chargeflow.io`. Validate it first against the key health check, then list your disputes: both calls are copy-paste ready in the [Quickstart](https://docs.chargeflow.io/docs/merchants/quickstart). Neither. Any active Chargeflow account can generate a key under **Settings → Developers**, with no plan requirement and no approval step. Read access to the Alerts and Disputes endpoints is the one exception: it is enabled per account, so if a valid key returns `403` on those, ask [Support](https://docs.chargeflow.io/docs/reference/support) to enable it. Yes, and the path we recommend is Zapier MCP rather than a hand-written API script: it connects Chargeflow to AI tools without any authentication or signing code of your own to maintain. Set the Chargeflow connection up once as described in [Zapier integration (no-code)](https://docs.chargeflow.io/docs/merchants/automation/zapier-no-code#connect-chargeflow-to-an-ai-assistant). A first-party Chargeflow MCP server is on the way, see [Tools](https://docs.chargeflow.io/docs/reference/tools#mcp-server). ## Authentication [#authentication] Chargeflow uses API key authentication. Include your API Access Key in the `x-api-key` header on every request. See [Authentication](https://docs.chargeflow.io/docs/reference/api-fundamentals/authentication). Generate your keys in the Chargeflow app under **Settings → Developers → Generate Keys**. Your API Secret Key is shown only once, so store it securely. See [Authentication](https://docs.chargeflow.io/docs/reference/api-fundamentals/authentication). It does both jobs. The Access Key authenticates every REST call you make, and generating it is also what unlocks webhook registration: the Secret Key that pairs with it is used to sign webhook deliveries so you can verify them. See [Authentication](https://docs.chargeflow.io/docs/reference/api-fundamentals/authentication) and [Webhooks](https://docs.chargeflow.io/docs/reference/concepts/webhooks). Neither: the key belongs wherever your own code or automation calls Chargeflow, for example your backend, a Zapier connection, or your CRM's outbound HTTP step. Never paste it into your payment processor's portal, and never expose it in client-side code. See [Authentication](https://docs.chargeflow.io/docs/reference/api-fundamentals/authentication). HMAC signature validation is an optional second layer of security that proves your requests are authentic and untampered. It is disabled by default on new keys. When enabled, you send a signature in the `x-chargeflow-hmac-sha256` header. See [Authentication](https://docs.chargeflow.io/docs/reference/api-fundamentals/authentication). ## Environments [#environments] A fully isolated sandbox environment is planned but not yet available - see [Sandbox](https://docs.chargeflow.io/docs/merchants/sandbox) for current status; until then API keys act on your live account (see [Test credentials](https://docs.chargeflow.io/docs/reference/api-fundamentals/test-credentials)). When you go to production, follow the [go-live checklist](https://docs.chargeflow.io/docs/reference/api-fundamentals/go-live-checklist). All requests go to `https://api.chargeflow.io`, with the API version in the path, for example `https://api.chargeflow.io/public/2025-04-01/disputes`. See [API Versioning](https://docs.chargeflow.io/docs/reference/concepts/api-versioning). Per-plan rate limits are not published yet - see [Rate limits](https://docs.chargeflow.io/docs/reference/api-fundamentals/rate-limits) for status. If you receive a `429`, back off and retry; the retry pattern is in [Error handling](https://docs.chargeflow.io/docs/reference/api-fundamentals/error-handling). Reads (GET) are always safe to retry. For writes, full idempotency semantics are not published yet - see [Idempotency](https://docs.chargeflow.io/docs/reference/api-fundamentals/idempotency) for status and [Error handling](https://docs.chargeflow.io/docs/reference/api-fundamentals/error-handling) for which status codes are retry-safe. ## Errors [#errors] It is almost certainly the request, not the account. A `403` (rather than a `401`) means the key was recognized but the request was rejected, and when even the health check returns it the usual cause is an HMAC signature or header that does not match the required `METHOD\nPATH\nBODY` format exactly. There is no "enable API access" switch for support to flip. See [Error handling](https://docs.chargeflow.io/docs/reference/api-fundamentals/error-handling) and the signing rules in [Authentication](https://docs.chargeflow.io/docs/reference/api-fundamentals/authentication). Because the header is not arriving. Nothing changed on the Chargeflow side: check that your client sends the header spelled exactly `x-api-key`, that it is set on the request that actually goes out (proxies and HTTP libraries sometimes drop unknown headers), and that it carries the Access Key rather than the Secret Key. See [Authentication](https://docs.chargeflow.io/docs/reference/api-fundamentals/authentication). Yes. Read access to the Alerts and Disputes endpoints is enabled per account and is not granted automatically just because webhooks are working. If the [health check](https://docs.chargeflow.io/docs/reference/api-fundamentals/error-handling#health-check-endpoint) returns `200` and those endpoints still return `403`, ask [Support](https://docs.chargeflow.io/docs/reference/support) to enable read access on your account. ## Webhooks [#webhooks] Register an HTTP endpoint in the Chargeflow app under **Settings → Developers → + Add Webhook**, then subscribe to the events you need. See [Webhooks](https://docs.chargeflow.io/docs/reference/concepts/webhooks). Your own. Chargeflow does not hand you a URL to call: you supply an HTTPS endpoint on your side that accepts `POST` requests and returns `2XX`, and Chargeflow delivers events to it. Register that URL under **Settings → Developers → + Add Webhook**. The handler code is in [Webhooks](https://docs.chargeflow.io/docs/reference/concepts/webhooks#configuring-webhooks). No. `dispute.created` is the only dispute event today, fired when a dispute is first detected. Status changes, evidence submission, and outcomes are not pushed: poll `GET /public/2025-04-01/disputes/{disputeId}` or check the dashboard. Wider dispute-event coverage is on the roadmap. See [Merchant webhook events](https://docs.chargeflow.io/docs/merchants/webhook-events). Each webhook POST includes an HMAC signature in the `X-Chargeflow-Hmac-Sha256` header. Recompute the signature from the request method, path, and body using your secret key and compare. See [Webhooks](https://docs.chargeflow.io/docs/reference/concepts/webhooks). Return a `2XX` status code (preferably `200`) quickly to acknowledge receipt. If Chargeflow receives any other response, it retries delivery until a `2XX` is returned or the retry limit is reached. See [Webhooks](https://docs.chargeflow.io/docs/reference/concepts/webhooks). ## Disputes [#disputes] Disputes are ingested from your connected payment processors and platforms. Each dispute carries a `source` that identifies its origin, such as `stripe`, `paypal`, or `shopify_payments`. See [Integrations & Ecosystem](https://docs.chargeflow.io/docs/reference/integrations) and the [Disputes API](https://docs.chargeflow.io/docs/api/2025-04-01/merchants/disputes). Subscribe to the `dispute.created` webhook event. See [Webhooks](https://docs.chargeflow.io/docs/reference/concepts/webhooks) and the [dispute.created event](https://docs.chargeflow.io/docs/merchants/webhook-events#dispute-created). Use the enrichment endpoints to attach order, transaction, and customer data. See [Enrich a dispute](https://docs.chargeflow.io/docs/merchants/automation/enrich-a-dispute) and [Upload evidence](https://docs.chargeflow.io/docs/merchants/automation/upload-evidence). Only if Chargeflow can already see it. The response is built from what your connected integrations return plus whatever you send through the enrichment endpoints, so a field you never share cannot appear in the evidence. Also note that arrays you send replace the stored array rather than appending to it, so omitting an existing item removes it. See [Enrich a dispute](https://docs.chargeflow.io/docs/merchants/automation/enrich-a-dispute#important-array-merge-behavior). Two places: the `PATCH` call returns the updated dispute object with your data merged in, and the same data appears on the dispute in the Chargeflow dashboard. If you need to re-read it later, call `GET /public/2025-04-01/disputes/{disputeId}`. See [Enrich a dispute](https://docs.chargeflow.io/docs/merchants/automation/enrich-a-dispute#response). ## Alerts [#alerts] A pre-chargeback alert is an early notification from a card network that a cardholder has disputed a transaction, giving you a short window to resolve it before it becomes a chargeback. See [Alerts model](https://docs.chargeflow.io/docs/reference/concepts/alerts-model). It depends on the integration model. In the Chargeflow Alerts model, Chargeflow handles matching and refunds automatically. In the merchant-managed model, you perform the action and report the outcome. See [Manage pre-chargeback alerts](https://docs.chargeflow.io/docs/merchants/alerts/manage-alerts). Yes, that is the merchant-managed model: Chargeflow delivers `alerts.created` (and `alerts.transaction.linked` once it matches a transaction), you issue the refund in your own processor, then report the result to `POST /public/2025-04-01/alerts/{id}/outcome`. Reporting the outcome is required, otherwise Chargeflow cannot close the alert with the issuer and the chargeback can still post. See [Manage pre-chargeback alerts](https://docs.chargeflow.io/docs/merchants/alerts/manage-alerts#merchant-managed-step-by-step-responsibilities). ## Prevent [#prevent] Not yet. Prevent runs only through the [Chargeflow app for Shopify](https://apps.shopify.com/chargeflow) today: there is no public API and no custom integration path for other platforms, and no committed timeline for one. See [Prevent](https://docs.chargeflow.io/docs/merchants/prevent). ## API versioning [#api-versioning] Chargeflow uses date-based versioning in the request path, for example `2025-04-01`. Always include an explicit version so future changes do not affect your integration. See [API Versioning](https://docs.chargeflow.io/docs/reference/concepts/api-versioning). Use the newest version in the [API Versioning](https://docs.chargeflow.io/docs/reference/concepts/api-versioning) version table for new integrations; that page also covers the deprecation policy. ## Security & compliance [#security--compliance] Yes, Chargeflow holds SOC 2 Type II certification. See [Security & compliance](https://docs.chargeflow.io/docs/reference/security) for the current certification list and roadmap. Generally not applicable - Chargeflow is not a cardholder-data environment and does not store full card numbers. The full rationale is in [Security & compliance](https://docs.chargeflow.io/docs/reference/security). All security and privacy documents are available through the [Chargeflow Trust Center](https://trust.chargeflow.io/), with gated reports granted on request. See [Security & compliance](https://docs.chargeflow.io/docs/reference/security). Incident history is published in [Security & compliance](https://docs.chargeflow.io/docs/reference/security) and kept current at the [Trust Center](https://trust.chargeflow.io/). ## Data & privacy [#data--privacy] The data needed to automate disputes - encrypted in transit and at rest, and never full card numbers. The specifics are in [Security & compliance](https://docs.chargeflow.io/docs/reference/security). Hosting, regions, and data-residency options are documented in [Security & compliance](https://docs.chargeflow.io/docs/reference/security). Chargeflow acts as a data processor on your behalf (you are the controller). Route data-subject requests through your account team or [support@chargeflow.io](mailto:support@chargeflow.io); the roles, transfer mechanisms, DPA, and privacy documentation are covered in [Security & compliance](https://docs.chargeflow.io/docs/reference/security) and the [Trust Center](https://trust.chargeflow.io/). No - see the AI governance section of [Security & compliance](https://docs.chargeflow.io/docs/reference/security). ## How Chargeflow operates [#how-chargeflow-operates] It can. As part of resolving disputes at the earliest, lowest-cost stage, Chargeflow may reach out to end customers directly to resolve a case. The governing terms are in the [Terms of Service](https://www.chargeflow.io/terms-of-service). Both. Chargeflow monitors ingestion and integration health on its side, and you can poll the [health check endpoint](https://docs.chargeflow.io/docs/reference/api-fundamentals/error-handling) to confirm connectivity from yours. Maintaining the integration access Chargeflow relies on is the merchant's responsibility (see the [Terms of Service](https://www.chargeflow.io/terms-of-service)); if access breaks, disputes tied to it cannot be handled until it is restored. Billing terms are set with your account team and depend on your plan. For specifics on fees, deposits, and charge timing, contact your account team or see the [Terms of Service](https://www.chargeflow.io/terms-of-service). ## Next steps [#next-steps] * Start with the [Quickstart](https://docs.chargeflow.io/docs/merchants/quickstart). * Review the [go-live checklist](https://docs.chargeflow.io/docs/reference/api-fundamentals/go-live-checklist) before production. * Still stuck? Contact [Support](https://docs.chargeflow.io/docs/reference/support). # Integrations (https://docs.chargeflow.io/docs/reference/integrations) You want to know whether Chargeflow works with the stack you already run. This page is the full catalog, grouped the way the connections actually work. You connect each tool once from the [Chargeflow App](https://app.chargeflow.io). After that, disputes arrive on their own, and every ingested dispute carries a `source` you can read through the [Disputes API](https://docs.chargeflow.io/docs/api/2025-04-01/merchants/disputes). ## What each category does [#what-each-category-does] Each category plays a different role in recovering a dispute: * **Payment processors** route disputes in. This is the connection that makes everything else work: without it, Chargeflow never sees the dispute. * **eCommerce platforms** and **subscription tools** enrich evidence. They supply the order, fulfilment, and billing history that proves the transaction was legitimate. * **Customer communication tools** supply the conversation history. This is what wins Item Not Received and Product Not As Described cases, because the thread shows what you told the customer and when. * **Alert networks** deflect disputes before they become chargebacks. Statuses read the same as the sidebar: Available is live today, New shipped recently, Coming soon is not connectable yet. ## Payment processors [#payment-processors] Connect at least one. Disputes flow in automatically from here. | Integration | Status | Connection guide | | ------------------------- | ------------------------ | ----------------------------- | | Shopify Payments | Available | [Shopify](#shopify) | | Stripe | Available | [Stripe](#stripe) | | PayPal | Available | [PayPal](#paypal) | | Braintree | Available | Connect in the Chargeflow App | | Adyen | Available | Connect in the Chargeflow App | | Checkout.com | Available | Connect in the Chargeflow App | | Airwallex | New | Connect in the Chargeflow App | | WooPayments | New | [WooCommerce](#woocommerce) | | Authorize.net | New | Connect in the Chargeflow App | | Klarna | Available | Connect in the Chargeflow App | | Affirm | Available | Connect in the Chargeflow App | | AfterPay | Available | Connect in the Chargeflow App | | Sezzle | Available | Connect in the Chargeflow App | | Square | Available | Connect in the Chargeflow App | | Nuvei | Available | Connect in the Chargeflow App | | NMI | Available | Connect in the Chargeflow App | | Commerce Control (Fiserv) | Available | Connect in the Chargeflow App | | Maverick | Available | Connect in the Chargeflow App | | Zenpayments | Available | Connect in the Chargeflow App | | PayArc | Available | Connect in the Chargeflow App | | Global Payments | Available | Connect in the Chargeflow App | | Deposyt | Available | Connect in the Chargeflow App | | Micamp | Available | Connect in the Chargeflow App | | Mamopay | Available | Connect in the Chargeflow App | | Chase Paymentech | Available | Connect in the Chargeflow App | | Finix Payments | Available | Connect in the Chargeflow App | Klarna, Affirm, AfterPay, and Sezzle are buy-now-pay-later providers. They are listed here because that is how the Chargeflow App groups them; in Chargeflow Connect they appear under Subscriptions and BNPL. ## eCommerce platforms [#ecommerce-platforms] Order and fulfilment data. These strengthen evidence, they do not route disputes in. | Integration | Status | Connection guide | | -------------- | -------------------------- | --------------------------------------------------- | | Chargeflow API | New | [API get started](https://docs.chargeflow.io/docs/api/2025-04-01/get-started) | | Shopify | Available | [Shopify](#shopify) | | WooCommerce | New | [WooCommerce](#woocommerce) | | Magento | Coming soon | | | BigCommerce | Coming soon | | | Wix | Coming soon | | | SquareSpace | Coming soon | | | Amazon | Coming soon | | | Ebay | Coming soon | | | Walmart | Coming soon | | | PrestaShop | Coming soon | | | Square | Coming soon | | | Volusion | Coming soon | | | Etsy | Coming soon | | | Salesforce | Coming soon | | **Square** the payment processor is available today and routes disputes in. **Square** the eCommerce platform, which supplies order data, is a separate integration and is not connectable yet. Connecting the processor does not give you the store data, and the reverse is also true. ## Subscriptions [#subscriptions] Billing history, plan changes, and cancellation records, for recurring-billing disputes. | Integration | Status | Connection guide | | ----------- | ------------------------ | ---------------------------------------------------------------------------------------- | | Recharge | Available | [Subscription enrichment](https://docs.chargeflow.io/docs/merchants/automation/enrich-a-dispute/by-business-model) | | Chargebee | Available | [Subscription enrichment](https://docs.chargeflow.io/docs/merchants/automation/enrich-a-dispute/by-business-model) | | Recurly | Available | [Subscription enrichment](https://docs.chargeflow.io/docs/merchants/automation/enrich-a-dispute/by-business-model) | ## Customer communication [#customer-communication] The conversation history. Connect one of these if you dispute Item Not Received or Product Not As Described cases, because the thread is often the strongest single piece of evidence. | Integration | Status | Connection guide | | ----------- | -------------------------- | -------------------------------------------------------------------------------------------------------- | | Gmail | New | [Customer communication enrichment](https://docs.chargeflow.io/docs/merchants/automation/enrich-a-dispute/customer-communications) | | Gorgias | Available | [Customer communication enrichment](https://docs.chargeflow.io/docs/merchants/automation/enrich-a-dispute/customer-communications) | | Zendesk | Available | [Customer communication enrichment](https://docs.chargeflow.io/docs/merchants/automation/enrich-a-dispute/customer-communications) | | Intercom | Coming soon | | | HelpScout | Coming soon | | ## Alert networks [#alert-networks] Received on your behalf, no connection to set up. They deflect a complaint before it becomes a chargeback. | Network | Status | What it does | | ----------------- | ------------------------ | --------------------------------------- | | Mastercard Ethoca | Available | [Mastercard Ethoca](#mastercard-ethoca) | | Visa Verifi RDR | Available | [Visa Verifi RDR](#visa-verifi-rdr) | ## No-code [#no-code] | Tool | Status | Connection guide | | ------ | ------------------------ | ----------------- | | Zapier | Available | [Zapier](#zapier) | ## Stripe [#stripe] Disputes originate with `source: stripe`. Each is matched to the underlying transaction and order, and Chargeflow fires the `dispute.created` webhook so you can react in real time. See [Webhooks](https://docs.chargeflow.io/docs/reference/concepts/webhooks). ## PayPal [#paypal] Buyer cases and chargebacks arrive with `source: paypal`, matched to the underlying transaction and order, and announced via the `dispute.created` webhook. ## Shopify [#shopify] Disputes arrive with `source: shopify` and pull in the order context already available in Shopify, which strengthens enrichment evidence. See [e-commerce enrichment](https://docs.chargeflow.io/docs/merchants/automation/enrich-a-dispute). ## WooCommerce [#woocommerce] WooCommerce settles through an underlying processor, so the `source` varies: WooCommerce-handled payments carry `wooCommerce`, WooPayments carry `wooPayments`, and some disputes instead carry the underlying processor (for example `stripe`). Confirm the exact `source` per dispute through the [Disputes API](https://docs.chargeflow.io/docs/api/2025-04-01/merchants/disputes). ## Mastercard Ethoca [#mastercard-ethoca] Ethoca surfaces a cardholder dispute as an alert before it becomes a chargeback, giving you a short window to act. Chargeflow matches each alert to a transaction, resolves it (most commonly by refunding) or hands it to you, and updates the network with the outcome to prevent the chargeback. Alerts arrive through the Alerts API and the `alerts.created`, `alerts.transaction.linked`, and `alerts.updated` webhooks. See the [alerts model](https://docs.chargeflow.io/docs/reference/concepts/alerts-model) to choose between automated and merchant-managed handling. ## Visa Verifi RDR [#visa-verifi-rdr] RDR resolves eligible Visa disputes automatically at the network level, based on rules you set, typically with a refund. Chargeflow ingests each case as a pre-chargeback alert, matches it to a transaction, and records the outcome so the resolution stays visible in your account. Same Alerts API and webhooks as Ethoca; see the [alerts model](https://docs.chargeflow.io/docs/reference/concepts/alerts-model). ## Zapier [#zapier] Zapier connects Chargeflow to thousands of apps with no code, using the **New Dispute** trigger and your `x-api-key`. Pre-built Zap templates let you enrich disputes, sync to a CRM or OMS, and trigger internal workflows. The complete step-by-step setup lives in the guide: The complete step-by-step setup with workflow examples. ## Do not see your tool? [#do-not-see-your-tool] If a processor is missing, you can still load disputes yourself through the [Chargeflow API](https://docs.chargeflow.io/docs/api/2025-04-01/get-started), which needs no processor connection. For anything else, [contact support](https://docs.chargeflow.io/docs/reference/support) and tell us what you run. ## Next step [#next-step] Now that a source is connected, run the end-to-end recipe. # Resources overview (https://docs.chargeflow.io/docs/reference/overview) Resources is the lookup layer. The merchant and platform sections walk you through a job; this section holds the facts those guides link to, documented once so there is a single canonical answer. Nothing here is sequential. Come in from a link, get the answer, go back. ## What lives here [#what-lives-here] | Section | Who it is for | Read it when | | ----------------------------------------------------------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | [Start here](https://docs.chargeflow.io/docs/reference/start-here/product-model) | Anyone new to Chargeflow | You need the map before the details: the [product model](https://docs.chargeflow.io/docs/reference/start-here/product-model), the [transaction lifecycle](https://docs.chargeflow.io/docs/reference/start-here/transaction-lifecycle), and [the language of disputes](https://docs.chargeflow.io/docs/reference/start-here/language-of-disputes) | | [Concepts](https://docs.chargeflow.io/docs/reference/concepts/chargeback-lifecycle) | Anyone new to disputes | You need the vocabulary: the chargeback lifecycle, reason codes, network timelines, how alerts and automation work | | [API fundamentals](https://docs.chargeflow.io/docs/reference/api-fundamentals/authentication) | Developers | You are writing code: authentication, API keys, pagination, errors, rate limits, idempotency, the go-live checklist | | [Integrations](https://docs.chargeflow.io/docs/reference/integrations) | Merchants and platforms | You want to know whether Chargeflow connects to a processor, store, subscription, or support tool you already run | | [Tools](https://docs.chargeflow.io/docs/reference/tools) | Developers and agents | You want the OpenAPI spec, the Postman collection, SDKs, or the MCP server | | [Error codes](https://docs.chargeflow.io/docs/reference/error-codes) | Developers | A call returned something you did not expect | | [Security and compliance](https://docs.chargeflow.io/docs/reference/security) | Security and procurement reviewers | You are assessing how Chargeflow handles data | | [FAQ](https://docs.chargeflow.io/docs/reference/faq) | Everyone | You have a short question and want a short answer | | [Status](https://docs.chargeflow.io/docs/reference/status) and [Support](https://docs.chargeflow.io/docs/reference/support) | Everyone | Something looks broken, or you need a human | | [Changelog](https://docs.chargeflow.io/docs/reference/changelog) | Developers | You want to know what shipped and when | ## If you are here for one thing [#if-you-are-here-for-one-thing] Most readers arrive on one of these three paths: * **Making your first API call.** Start with [Authentication](https://docs.chargeflow.io/docs/reference/api-fundamentals/authentication), then the [API get started](https://docs.chargeflow.io/docs/api/2025-04-01/get-started) page. * **Debugging a response.** Go straight to [Error codes](https://docs.chargeflow.io/docs/reference/error-codes). * **Checking whether we support your stack.** Go to [Integrations](https://docs.chargeflow.io/docs/reference/integrations). ## Next step [#next-step] Learn the chargeback lifecycle first; every other page in this section assumes it. Already fluent in disputes and just here to build? Go to [API fundamentals](https://docs.chargeflow.io/docs/reference/api-fundamentals/authentication). # Security & compliance (https://docs.chargeflow.io/docs/reference/security) Chargeflow follows enterprise-grade security and compliance practices for handling financial and customer data. This page summarizes our posture and links to the canonical source for every report and policy. The [Chargeflow Trust Center](https://trust.chargeflow.io/) is the single source of truth for our certifications, security policies, and data-privacy documentation, including the SOC 2 Type II report, penetration test report, and DPA. Access to gated reports is granted on request. ## Certifications & compliance [#certifications--compliance] | Standard | Status | | ------------------------- | ----------------------------------------------------------------------------------- | | SOC 2 Type II | Certified - current attestation at the [Trust Center](https://trust.chargeflow.io/) | | GDPR | Compliant | | ISO 27001 / 27017 / 27018 | Planned - current status at the [Trust Center](https://trust.chargeflow.io/) | | CCPA | Planned - current status at the [Trust Center](https://trust.chargeflow.io/) | | PCI DSS | Not held (see below) | **On PCI DSS:** Chargeflow does not store raw PAN (full card numbers) and does not operate as a cardholder-data environment, so a PCI attestation is generally not applicable. Chargeflow may ingest non-sensitive card-related dispute attributes exposed by your payment processor, such as BIN, last four, brand, expiration metadata, and AVS/CVV results, when needed to build evidence. All certificates and reports are available at [trust.chargeflow.io](https://trust.chargeflow.io/). ## Data handling & privacy [#data-handling--privacy] * **What we process:** the customer, transaction, dispute, and enrichment data needed to automate dispute management (names, contact details, order and transaction metadata, reason codes and deadlines, evidence files, and related signals). * **What we do not store:** raw PAN / full card numbers. * **Roles under GDPR:** Chargeflow acts as a data processor on your behalf; you remain the data controller. Data-subject requests are handled per the Data Processing Agreement, and transfers out of the EEA are covered by Standard Contractual Clauses. * **Encryption:** all data in transit is encrypted with TLS 1.2 or higher; all data at rest is encrypted with AES-256 or equivalent. * **Authentication:** all user accounts require MFA. See [Authentication](https://docs.chargeflow.io/docs/reference/api-fundamentals/authentication) for API key and HMAC options. * **Historical data:** Chargeflow ingests roughly the past 24 months of chargeback data from connected processors. Data Processing Agreements and the full privacy documentation are available at [trust.chargeflow.io](https://trust.chargeflow.io/). ## Hosting & availability [#hosting--availability] * **Infrastructure:** single-tenant on AWS, primary region `us-east-1`. Specific regional data-residency requirements can be reviewed and supported on request. * **Availability:** contractual uptime SLAs are set per agreement; live availability is published at [status.chargeflow.io](https://status.chargeflow.io/). * **Disaster recovery:** RPO of 6 hours, RTO of 24 hours. As a pure cloud platform, Chargeflow can redeploy to any available AWS region. * **Scalability:** serverless architecture with no practical limit on accounts, processors, merchants, or dispute volume. Live status is published at [status.chargeflow.io](https://status.chargeflow.io/). ## AI governance & data use [#ai-governance--data-use] * **No training on your data:** Chargeflow does not use PII or sensitive customer data to train or fine-tune AI models. AI workflows use retrieval-augmented generation with controlled prompts that reference case data at runtime, and process it only to generate outputs for the requesting customer. * **No automated decisions affecting consumers:** the platform provides analysis and workflow automation; final decisions remain with the merchant. * **Runtime guardrails:** every model in production is subject to input and output guardrails, including PII detection, content moderation, jailbreak and prompt-injection detection, hallucination detection, URL filtering, and organization-specific prompt policies. Deployed models are continuously monitored for quality, latency, error rates, and anomalous usage. ## Secure development [#secure-development] * Annual third-party penetration testing (report available at the Trust Center). * Security-integrated SDLC with strict environment separation and secrets managed through AWS SSM Parameter Store and Secrets Manager. * Pre-commit secret scanning and CI gating: automated tests, dependency scanning that blocks high/critical vulnerabilities, static analysis, and peer review before merge. * Daily vulnerability triage and prioritized remediation. ## Subprocessors [#subprocessors] The complete, up-to-date list of subprocessors is published at [trust.chargeflow.io/subprocessors](https://trust.chargeflow.io/subprocessors). If a DPA is in place between us, it also includes the subprocessor list as an annex. ## Incident history [#incident-history] Incident history is published and kept current at the [Trust Center](https://trust.chargeflow.io/) and [status.chargeflow.io](https://status.chargeflow.io/). ## Requesting documents or reporting an issue [#requesting-documents-or-reporting-an-issue] * **Security documents** (SOC 2 report, penetration test, DPA, subprocessor list): request access through the [Trust Center](https://trust.chargeflow.io/). * **Security questions or vulnerability reports:** contact [support@chargeflow.io](mailto:support@chargeflow.io) or your account team. ## Related [#related] Short answers to common security, data, and privacy questions API keys, HMAC signatures, and key management Certifications, reports, and policies Reach the Chargeflow team # Status (https://docs.chargeflow.io/docs/reference/status) Check the live status of the Chargeflow API and view incident history. ## Status page [#status-page] Monitor the Chargeflow API at [status.chargeflow.io](https://status.chargeflow.io). The status page shows current availability and any ongoing or past incidents. ## During an incident [#during-an-incident] If you are seeing errors that the status page does not explain, capture the `requestId` from the API response and contact support. The `requestId` lets the team locate your exact request in the logs. See [Error Handling](https://docs.chargeflow.io/docs/reference/api-fundamentals/error-handling). ## Next steps [#next-steps] * Reach the team through [Support](https://docs.chargeflow.io/docs/reference/support). * Review the [Error Codes Reference](https://docs.chargeflow.io/docs/reference/error-codes) to interpret a failing response. # Support (https://docs.chargeflow.io/docs/reference/support) When an API call fails and the [error reference](https://docs.chargeflow.io/docs/reference/error-codes) didn't resolve it, this page gets you unblocked fast: who to contact, the one field to include so they can trace your request, and where to check live API status first. ## Getting help [#getting-help] **Email:** [support@chargeflow.io](mailto:support@chargeflow.io) **Developer Portal:** [app.chargeflow.io](https://app.chargeflow.io) When contacting support, always include the `requestId` from the API response: this allows the team to look up your exact request in our logs. ## Before contacting support [#before-contacting-support] 1. Check the [Error Codes Reference](https://docs.chargeflow.io/docs/reference/error-codes) for your HTTP status code 2. Validate your API key using the [health check endpoint](https://docs.chargeflow.io/docs/merchants/quickstart) 3. Review the relevant guide for the endpoint you're calling 4. Check that you're using the correct API version (`2025-04-01`) ## API status [#api-status] Monitor Chargeflow API status at [status.chargeflow.io](https://status.chargeflow.io). ## Next steps [#next-steps] Look up the HTTP status you received before you reach out Learn how to retry and recover from each error Validate your API key and confirm connectivity Check common questions before contacting the team # Tools (https://docs.chargeflow.io/docs/reference/tools) I am looking for a Chargeflow tool, SDK, or utility. Everything below helps you build against the Chargeflow API: the specs and client tooling to generate code, the agent tools that let a coding assistant integrate for you, and the interactive and testing tools that are planned. All of it targets the API at `https://api.chargeflow.io`, authenticated with your API key in the `x-api-key` header. | Tool | What it is | Status | | ----------------------------------------- | ------------------------------------------------------------- | ----------------------------------- | | [OpenAPI specs](#openapi-specs) | Machine-readable specs for the Merchants and Platforms APIs | Available | | [SDKs](#sdks) | Official client libraries | Coming soon | | [Postman collection](#postman-collection) | Ready-made collection of every endpoint | Coming soon (import the spec today) | | [AI skill](#ai-skill) | Hosted `SKILL.md` that teaches a coding agent to integrate | Available | | [MCP server](#mcp-server) | Lets an agent call Chargeflow tools directly | Coming soon | | [API explorer](#api-explorer) | In-page runner for real sandbox calls | Coming soon | | [Integration linter](#integration-linter) | Validates auth, webhook, and idempotency setup before go-live | Coming soon | | [Seeded scenarios](#seeded-scenarios) | Ready-made sandbox test data for each dispute outcome | Coming soon | ## Specs & client libraries [#specs--client-libraries] ### OpenAPI specs [#openapi-specs] Chargeflow publishes OpenAPI specifications for both APIs. Use them to generate a typed client with an OpenAPI generator, import into Postman or other tools, or review request and response schemas without making live calls. All specs describe the API served at `https://api.chargeflow.io`; authenticate with your API key in the `x-api-key` header. Latest versioned specs (`2025-04-01`): * [Merchants API, 2025-04-01](https://docs.chargeflow.io/specs/openapi-merchants-2025-04-01.json) * [Platforms API, 2025-04-01](https://docs.chargeflow.io/specs/openapi-platforms-2025-04-01.json) Earlier version (`2024-03-18`), still available: * [Merchants API, 2024-03-18](https://docs.chargeflow.io/specs/openapi-merchants-2024-03-18.json) * [Platforms API, 2024-03-18](https://docs.chargeflow.io/specs/openapi-platforms-2024-03-18.json) ### SDKs [#sdks] Official Chargeflow client libraries. None have shipped yet - Node.js / TypeScript, Python, PHP, and Ruby are planned, and package names and install instructions will be listed here when each one ships. In the meantime the Chargeflow API is a standard REST API that works with any HTTP client, so you can integrate today: use the [quickstart](https://docs.chargeflow.io/docs/merchants/quickstart) for copy-paste curl examples, or generate a typed client yourself from the OpenAPI specs above. ### Postman collection [#postman-collection] An official Postman collection covering every Chargeflow endpoint is in progress; a download link will appear here when it ships. Until then, import an OpenAPI spec into Postman to get a request per endpoint: choose **Import**, paste the spec URL or upload the file, and Postman builds a collection from it. After importing, set your `x-api-key` header so requests are authenticated - see [Test credentials](https://docs.chargeflow.io/docs/reference/api-fundamentals/test-credentials) for sandbox keys. ## Agent tools [#agent-tools] ### AI skill [#ai-skill] A hosted, self-contained reference file that teaches a coding agent to integrate Chargeflow - authentication, listing and enriching disputes, uploading evidence, handling pre-chargeback alerts, and webhooks - routing each intent to the exact endpoint instead of guessing. It is hosted at [`/SKILL.md`](https://docs.chargeflow.io/SKILL.md): point your agent at that URL, or paste its contents into your assistant's context. You can also copy the ready-made prompt from the **Setup for agents** button on the [docs homepage](https://docs.chargeflow.io/). The skill covers the base URL, auth, and versioning (the `x-api-key` header and the credential health check to run first), merchant and platform intent-to-endpoint tables, webhooks, and the rules an agent must follow (never invent endpoints, honor `Retry-After` on 429s, keep the key server-side, treat the OpenAPI specs as source of truth). Every docs page is also fetchable as plain markdown - append `.md` to any URL - and the skill links to [`/llms.txt`](https://docs.chargeflow.io/llms.txt) as the full docs index. ### MCP server [#mcp-server] An MCP server is coming so a coding agent can call Chargeflow tools directly from Claude Code, Cursor, Codex, and VS Code. When it ships, this section becomes a per-client setup selector with the exact install command or JSON config for each client. Until then, the agent path that already works needs no MCP: give your agent the [AI skill](#ai-skill) at [`/SKILL.md`](https://docs.chargeflow.io/SKILL.md), point it at [`/llms.txt`](https://docs.chargeflow.io/llms.txt) as the docs index, and hand it the [OpenAPI specs](#openapi-specs) for exact request and response shapes. If what you want is an assistant that reads your live dispute data rather than one that writes integration code, you do not have to wait: expose Chargeflow to it through Zapier MCP, which reuses the Zapier connection and leaves no auth code for you to maintain. See [Connect Chargeflow to an AI assistant](https://docs.chargeflow.io/docs/merchants/automation/zapier-no-code#connect-chargeflow-to-an-ai-assistant). ## Interactive & testing tools [#interactive--testing-tools] These tools are planned; each entry lists what already works in the meantime. ### API explorer [#api-explorer] An in-page explorer that runs real calls against the sandbox, with your test keys injected automatically once you sign in. Until it ships, use the [quickstart](https://docs.chargeflow.io/docs/merchants/quickstart) to make your first call and [test credentials](https://docs.chargeflow.io/docs/reference/api-fundamentals/test-credentials) to authenticate. ### Integration linter [#integration-linter] A check that validates your authentication, webhook, and idempotency setup and flags anything that would fail in production. Until it ships, work through the [go-live checklist](https://docs.chargeflow.io/docs/reference/api-fundamentals/go-live-checklist) to confirm your integration is ready. ### Seeded scenarios [#seeded-scenarios] Ready-made sandbox test scenarios that let you exercise each dispute outcome without waiting for real events - planned coverage includes a dispute won, a dispute lost, a representment, an alert that prevents a chargeback, and an EaaS package. Until they ship, generate a [test key](https://docs.chargeflow.io/docs/reference/api-fundamentals/test-credentials) and call the sandbox directly to set up your own test data. ## Next step [#next-step] Make your first authenticated call against the API these tools target. # API Reference - v2024-03-18 (https://docs.chargeflow.io/docs/api/2024-03-18) This is the legacy version of the Chargeflow API. Use [v2025-04-01](https://docs.chargeflow.io/docs/api/2025-04-01/get-started) for new integrations, and follow the [migration guide](https://docs.chargeflow.io/docs/api/2025-04-01/migration) to upgrade. Switch versions anytime with the version selector at the top of the sidebar. # API overview (https://docs.chargeflow.io/docs/api/2025-04-01/get-started) You are a developer about to call the Chargeflow API for the first time. This page gets you a real response in one call, then points at the mechanics every other endpoint shares. ## What the API is for [#what-the-api-is-for] The Chargeflow API is how you run dispute recovery from your own code instead of the dashboard. You use it to read disputes as they arrive, enrich them with the order, transaction, subscription, and customer-communication data that wins cases, upload evidence, act on pre-chargeback alerts, and receive webhooks when any of it changes. Two surfaces, one API: | Surface | Who it is for | Where it starts | | ----------------- | ------------------------------------------------------------------------- | ----------------------------------------------------------- | | **Merchants API** | You recover your own disputes | [Health check](https://docs.chargeflow.io/docs/api/2025-04-01/merchants/health-check) | | **Platforms API** | You are a platform or PSP recovering disputes for the merchants you serve | [Accounts](https://docs.chargeflow.io/docs/api/2025-04-01/platforms/accounts) | ## Base URL and version [#base-url-and-version] ``` https://api.chargeflow.io/public/2025-04-01 ``` The version is part of the path, so a request never silently changes behaviour. | Version | Status | Reference | | ------------ | -------------------- | -------------------------------------------------------------------------------------------------- | | `2025-04-01` | Current | This section | | `2024-03-18` | Legacy, still served | [Legacy reference](https://docs.chargeflow.io/docs/api/2024-03-18) and the [migration guide](https://docs.chargeflow.io/docs/api/2025-04-01/migration) | ## Your first request [#your-first-request] Validate your key. It is the cheapest call in the API, it has no side effects, and it proves both authentication and connectivity in one shot. You need an API access key. Generate one in the Chargeflow App under **Settings → Developers → Generate Keys**. See [API keys](https://docs.chargeflow.io/docs/reference/api-fundamentals/test-credentials). ```bash title="Terminal" curl -X GET https://api.chargeflow.io/public/2025-04-01/health-check/access-key \ -H "x-api-key: YOUR_API_KEY" ``` ```javascript title="Node.js" const res = await fetch('https://api.chargeflow.io/public/2025-04-01/health-check/access-key', { method: 'GET', headers: { 'x-api-key': process.env.CHARGEFLOW_API_KEY, }, }); const data = await res.json(); ``` ```python title="Python" import os, requests res = requests.get( "https://api.chargeflow.io/public/2025-04-01/health-check/access-key", headers={"x-api-key": os.environ["CHARGEFLOW_API_KEY"]}, ) data = res.json() ``` Expected response: ```json title="Response" "OK" ``` A `403 {"message":"Forbidden"}` means the key is invalid or lacks permission. Call `GET /public/2025-04-01/health-check` to tell the two apart: a `200` there means the key is valid and the `403` was a permissions problem. See [Error handling](https://docs.chargeflow.io/docs/reference/api-fundamentals/error-handling). ## Authentication [#authentication] Every endpoint requires the `x-api-key` header. HMAC signature validation is off by default and can be enabled in **Settings → Developers**; once on, requests also carry an `x-chargeflow-hmac-sha256` signature over `METHOD\nPATH\nBODY`. Full setup, including the signing walkthrough: [Authentication](https://docs.chargeflow.io/docs/reference/api-fundamentals/authentication). ## Environments [#environments] There is one environment today. The keys you generate act on your live account, so read before you write and work through the [go-live checklist](https://docs.chargeflow.io/docs/reference/api-fundamentals/go-live-checklist) before you send production traffic. An isolated sandbox with separate test keys is coming: [Sandbox](https://docs.chargeflow.io/docs/merchants/sandbox). ## What every endpoint shares [#what-every-endpoint-shares] | Mechanic | The short version | Full page | | ----------- | ----------------------------------------------------------------------------------------- | ----------------------------------------------------------------- | | Pagination | `offset` (zero-based page index) and `limit` (default 25, max 100) on every list endpoint | [Pagination](https://docs.chargeflow.io/docs/reference/api-fundamentals/pagination) | | Errors | Standard HTTP status codes; every response carries a `requestId` to quote to support | [Error handling](https://docs.chargeflow.io/docs/reference/api-fundamentals/error-handling) | | Rate limits | A `429` means back off and honour `Retry-After`; published limits are coming | [Rate limits](https://docs.chargeflow.io/docs/reference/api-fundamentals/rate-limits) | | Idempotency | An `Idempotency-Key` header applies to evidence generation today, not yet API-wide | [Idempotency](https://docs.chargeflow.io/docs/reference/api-fundamentals/idempotency) | | Webhooks | Register an endpoint per event and reply `200` to acknowledge | [Webhooks](https://docs.chargeflow.io/docs/reference/concepts/webhooks) | ## Next step [#next-step] Run the first endpoint, then walk the merchant API in the order the sidebar lists it. Building for a platform instead? Start at [Accounts](https://docs.chargeflow.io/docs/api/2025-04-01/platforms/accounts). Upgrading from the previous version? Read the [migration guide](https://docs.chargeflow.io/docs/api/2025-04-01/migration). # Migrate from 2024-03-18 to 2025-04-01 (https://docs.chargeflow.io/docs/api/2025-04-01/migration) This guide describes every change between API version `2024-03-18` and `2025-04-01` for both the Merchants API and the Platforms API. The deltas below come from comparing the two OpenAPI specs directly, so each item reflects an actual difference in paths, request bodies, response schemas, enums, or required fields. Version `2025-04-01` introduces breaking changes. Read the sections that apply to your integration before you switch. Several endpoints from `2024-03-18` are not present in `2025-04-01`, and shared endpoints changed their request and response shapes. Plan to update your code, not just the version string in the URL. ## How to set the version [#how-to-set-the-version] Chargeflow uses date-based versioning in the request path. The version is the date segment after `/public/`. To move to `2025-04-01`, replace the date in every request path. Authentication did not change. Both versions use the `x-api-key` request header with the same production server, `https://api.chargeflow.io`. ```bash title="Terminal" curl https://api.chargeflow.io/public/2024-03-18/disputes \ -H "x-api-key: YOUR_API_KEY" ``` ```bash title="Terminal" curl https://api.chargeflow.io/public/2025-04-01/disputes \ -H "x-api-key: YOUR_API_KEY" ``` For background on how versions work, see [API versioning](https://docs.chargeflow.io/docs/reference/concepts/api-versioning). ## Merchants API changes [#merchants-api-changes] ### Endpoint changes [#endpoint-changes] | Method and path | 2024-03-18 | 2025-04-01 | Change | | ----------------------------------------- | ---------- | ---------- | ------------------------------------------------------ | | `GET /disputes` | Yes | Yes | Response shape changed, query parameters reduced | | `GET /disputes/{disputeId}` | No | Yes | New endpoint | | `PATCH /disputes/{disputeId}` | No | Yes | New endpoint (Enrich Dispute) | | `POST /disputes` | Yes | No | Removed | | `POST /disputes/{disputeId}/evidence` | Yes | Yes | Unchanged | | `POST /disputes/{disputeId}/subscription` | No | Yes | New endpoint | | `GET /alerts` | No | Yes | New endpoint | | `GET /alerts/{alertId}` | No | Yes | New endpoint | | `POST /alerts/{alertId}/outcome` | No | Yes | New endpoint | | `POST /customer-communication` | No | Yes | New endpoint | | `POST /data-subject/removal` | No | Yes | New endpoint | | `GET /webhooks` | Yes | Yes | Response shape changed | | `POST /webhooks` | Yes | Yes | Unchanged (`{event, url}`, one event per registration) | | `DELETE /webhooks/{id}` | Yes | Yes | Unchanged | | `GET /health-check` | Yes | Yes | Unchanged | | `GET /health-check/access-key` | Yes | Yes | Unchanged | ### Removed endpoints [#removed-endpoints] These endpoints exist in `2024-03-18` but are not in `2025-04-01`. If you call them, you need to stop or move to a replacement. | Removed endpoint | Notes | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `POST /disputes` | No direct equivalent in the Merchants API for `2025-04-01`. To enrich an existing dispute, use `PATCH /disputes/{disputeId}` and the per-resource `POST` endpoints instead. | ### `GET /disputes` response changed [#get-disputes-response-changed] The list response was restructured. The top-level fields and the per-item shape both changed. | 2024-03-18 | 2025-04-01 | | ------------------------- | -------------------------------------------------------------------------- | | `totalCount` (number) | moved under `pagination.totalCount` (integer) | | `hasMore` (boolean) | removed | | `data` (array of objects) | renamed to `disputes` (array) | | no pagination object | new `pagination` object with `totalCount`, `offset`, `limit`, `totalPages` | In `2024-03-18`, each item in `data` had a fixed shape with `chargeflowDisputeId`, a nested `dispute` object (with `processorId`, `processor`, `amount`, `status`, `reason`, `responseDueDate`), and a nested `transaction` object. In `2025-04-01`, the `disputes` array items use the flat snake\_case dispute shape (`id`, `source`, `source_id`, `account_id`, `created_at`, `reason`, `due_by`, `amount`, `currency`, `status`, `stage`, `closed_at`), with related resources referenced rather than embedded - do not rely on the old `data[].dispute` and `data[].transaction` structure. To read a single dispute with full detail, use the new `GET /disputes/{disputeId}` endpoint. The query parameters on `GET /disputes` were also reduced. | Query parameter | 2024-03-18 | 2025-04-01 | | ----------------- | ------------ | ------------- | | `offset` | Yes (number) | Yes (integer) | | `limit` | Yes (number) | Yes (integer) | | `dateCreatedFrom` | Yes | Removed | | `dateCreatedTo` | Yes | Removed | | `amountFrom` | Yes | Removed | | `amountTo` | Yes | Removed | | `statusNames` | Yes (enum) | Removed | | `reason` | Yes (enum) | Removed | | `processorNames` | Yes (enum) | Removed | If you relied on date, amount, status, reason, or processor filters in the query string, that filtering is no longer available on `GET /disputes` in `2025-04-01`. Plan to filter on your side after fetching, or fetch individual disputes by ID. ### `GET /webhooks` response changed [#get-webhooks-response-changed] The webhook list items are simpler in `2025-04-01`. | Field | 2024-03-18 | 2025-04-01 | | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- | | `success` | boolean | boolean | | `data[].id` | string | string | | `data[].event` | enum (`webhook.test`, `dispute.created`, `evidence.ready`, `evidence.error`, `alerts.created`, `alerts.updated`, `alerts.transaction.linked`, `*`) | plain string, no enum | | `data[].url` | string | string | | `data[].active` | boolean | removed | | `data[].version` | string | removed | ### Unchanged Merchants endpoints [#unchanged-merchants-endpoints] `POST /disputes/{disputeId}/evidence`, `DELETE /webhooks/{id}`, `GET /health-check`, and `GET /health-check/access-key` have the same request and response shapes in both versions. The evidence upload still accepts the same two `oneOf` variants and the same `evidenceUploadCategory` enums (`tracking_information`, `customer_communication`, `invoice` for the first variant, and `additional_evidence`, `additional_notes` for the second). ### New Merchants endpoints [#new-merchants-endpoints] `2025-04-01` adds several endpoints. The notable request and response details are below. `GET /disputes/{disputeId}` returns a single dispute with nested `transaction`, `subscription`, and `order` objects. Note that its `reason` enum is the smaller set `fraud`, `not_received`, `not_as_described`, `canceled_recurring_billing`, `duplicate_charge`, `credit_not_processed`, `other`, and `status` is one of `needs_response`, `under_review`, `won`, `lost`. It also includes a `stage` enum (`Chargeback`, `Inquiry`, `Pre_arbitration`, `Arbitration`) and a `source` enum listing supported processors. `POST /disputes/{disputeId}/subscription` creates subscription context for a dispute. Required fields: `source_id`, `created_at`, `start_date`, `frequency` (`day`, `week`, `month`, `year`), and `frequency_count`. `GET /alerts` and `GET /alerts/{alertId}` return alert records, including a nested `network_transaction` object and an optional `transaction`. `GET /alerts` wraps results in `alerts` plus the same `pagination` object used by `GET /disputes`. `POST /alerts/{alertId}/outcome` records an alert outcome. Required field: `outcome`, one of `refunded`, `previously_refunded`, `duplicate`, `decline`, `error`. It returns `202` with no body. `POST /customer-communication` submits communication tied to one or more disputes. Required fields: `source_id`, `disputes` (array of strings), and `messages`. Each message requires `sender`, `date`, and `body_plain_text`, and may set a `type` of `email`, `chat`, `transcript`, `form`, or `sms`. ## Platforms API changes [#platforms-api-changes] The Platforms API changed more than the Merchants API. Every `2024-03-18` Platforms endpoint was removed, and `2025-04-01` introduces a new set of endpoints with a new naming and data model. ### Endpoint changes [#endpoint-changes-1] | Method and path | 2024-03-18 | 2025-04-01 | Change | | ---------------------------- | ---------- | ---------- | ---------------------------------------- | | `GET /disputes` | Yes | No | Removed | | `POST /disputes` | Yes | No | Removed | | `POST /platform/disputes` | No | Yes | New endpoint (replaces dispute creation) | | `POST /accounts` | No | Yes | New endpoint | | `GET /accounts/{accountId}` | No | Yes | New endpoint | | `POST /evidence` | No | Yes | New endpoint | | `GET /evidence/{evidenceId}` | No | Yes | New endpoint | There are no Platforms endpoints common to both versions. The `2025-04-01` Platforms API is a new surface, so treat the migration as a rewrite of your Platforms integration rather than a field rename. ### Removed Platforms endpoints [#removed-platforms-endpoints] | Removed endpoint | 2025-04-01 direction | | ---------------- | -------------------------------------------------------------------------------------------------------------- | | `GET /disputes` | No list endpoint in `2025-04-01`. Fetch a single record instead, for example via `GET /evidence/{evidenceId}`. | | `POST /disputes` | Replaced by `POST /platform/disputes` with a new request body. | ### Dispute creation model changed [#dispute-creation-model-changed] The old `POST /disputes` and the new `POST /platform/disputes` both create a dispute, but the request bodies are different. The data model moved from a flat, processor-oriented payload to a nested model with `transaction`, `subscription`, and `order` objects, and the field names changed from camelCase to snake\_case. | Old field (`POST /disputes`) | New field (`POST /platform/disputes`) | | ---------------------------------------------------------- | ------------------------------------------------------------------------- | | `disputeId` (required) | not used as input; the response returns `id` | | `creationDate` (required) | `created_at` (required) | | `due_by` (required) | `due_by` (required) | | `disputeAmount` (required) | `amount` (required) | | `currency` (required) | `currency` (required) | | `processor` (required) | not present; use `source_id` (required) plus the response `source` enum | | `isChargeRefundable` (required) | removed | | `handleByChargeflow` (required) | removed | | `reason` (required, large enum) | `reason` (required, smaller enum) | | `status` (enum `needs_response`, `warning_needs_response`) | `status` (required, enum `needs_response`, `under_review`, `won`, `lost`) | | no `account_id` | `account_id` (required) | | `products`, `pastPayments` (flat arrays) | nested under `order` and `transaction` objects | New required fields on `POST /platform/disputes`: `source_id`, `account_id`, `created_at`, `reason`, `due_by`, `amount`, `currency`, `status`. The `reason` enum is smaller and uses different values. | Old `reason` values | New `reason` values | | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | | `general`, `fraudulent`, `duplicate`, `subscription_canceled`, `product_unacceptable`, `product_not_received`, `unrecognized`, `credit_not_processed`, `incorrect_account_details`, `insufficient_funds`, `bank_cannot_process`, `debit_not_authorized`, `goods_services_returned_or_refused`, `goods_services_cancelled`, `transaction_amount_differs`, `retrieved` | `fraud`, `not_received`, `not_as_described`, `canceled_recurring_billing`, `duplicate_charge`, `credit_not_processed`, `other` | Map your old reason values to the new set before you send them. There is no automatic conversion. The new request body also supports rich nested objects: * `transaction` with `payment_method` (including `brand`, `wallet`, and a `checks` object for 3-D Secure and AVS results) and `billing_address`. * `subscription` with `frequency`, `frequency_count`, `collection_method`, `pricing_model`, and `status`. * `order` with `customer`, `products` (each requiring `name`, `type`, `quantity`, `price`), `shipping_address`, and `fulfillments`. The response is a full dispute object with `id`, a `source` enum, `status` (`needs_response`, `under_review`, `won`, `lost`), `stage`, and the nested `transaction`, `subscription`, and `order` objects. ### New Platforms endpoints [#new-platforms-endpoints] `POST /accounts` creates a platform account. Required fields: `owner_name`, `business_name`, `business_url`, `email`. The `status` enum is `active` or `inactive`. The response returns the account with a generated `id`. `GET /accounts/{accountId}` returns a single account in the same shape as the create response. `POST /evidence` generates evidence. Required fields: `account_id` and `dispute`. The `dispute` field is an `anyOf`: either `{ "dispute_id": "..." }` to reference an existing dispute, or `{ "dispute_data": { ... } }` to pass the full dispute payload inline. The inline `dispute_data` uses the same nested `transaction`, `subscription`, and `order` model as `POST /platform/disputes`. The response returns an evidence record with `id`, `status` (`in_progress`, `completed`, `error`), `file_url`, and `file_version`. `GET /evidence/{evidenceId}` returns an evidence record. Its `dispute` field is an `anyOf` of a string ID or the full nested dispute object. ## Upgrade checklist [#upgrade-checklist] Update the version segment in every request path from `/public/2024-03-18/` to `/public/2025-04-01/`. Keep the `x-api-key` header as is. For Merchants `GET /disputes`, read results from `disputes` instead of `data`, and read counts from the new `pagination` object instead of `totalCount` and `hasMore`. Remove any reliance on the old `data[].dispute` and `data[].transaction` structure. Replace removed Merchants query filters (`dateCreatedFrom`, `dateCreatedTo`, `amountFrom`, `amountTo`, `statusNames`, `reason`, `processorNames`) with client-side filtering or per-dispute lookups via `GET /disputes/{disputeId}`. For Merchants `GET /webhooks`, stop reading `data[].active` and `data[].version`, and treat `data[].event` as a plain string rather than a fixed enum. Stop calling the removed Merchants endpoint `POST /disputes`. Adopt the new endpoints (`GET /disputes/{disputeId}`, `PATCH /disputes/{disputeId}`, which carries both `order` and `transaction` data, `POST /disputes/{disputeId}/subscription`, the `alerts` endpoints, and `POST /customer-communication`) where they fit your flow. For Platforms, rebuild your dispute creation against `POST /platform/disputes`. Rename camelCase fields to snake\_case, send the new required fields (`source_id`, `account_id`, `created_at`, `reason`, `due_by`, `amount`, `currency`, `status`), and map old `reason` values to the new seven-value enum. For Platforms, send order, transaction, and subscription data in the nested objects of the dispute body. Adopt the new Platforms endpoints you need: `POST /accounts` and `GET /accounts/{accountId}` for account management, and `POST /evidence` and `GET /evidence/{evidenceId}` for evidence generation. Confirm connectivity and credentials on the new version with `GET /health-check` and `GET /health-check/access-key`, which are unchanged. ## Next steps [#next-steps] * [API reference for 2025-04-01](https://docs.chargeflow.io/docs/api/2025-04-01/get-started) * [API versioning](https://docs.chargeflow.io/docs/reference/concepts/api-versioning) # Alerts (https://docs.chargeflow.io/docs/merchants/alerts) You want fewer chargebacks to ever reach your account. **Alerts** is Chargeflow's pre-chargeback product: when a cardholder complains to their issuer, an alert arrives through Verifi (RDR / CDRN) or Ethoca **before** the chargeback posts, leaving a short window to resolve the case - usually with a refund - so it never counts against you. ## When to use Alerts [#when-to-use-alerts] * You want to protect your dispute ratio, not just win disputes after they are filed. * You want eligible Visa disputes resolved automatically against your rules (RDR), with no manual action. * You want alert data and outcomes in your own systems via API and webhooks. * You want to run custom logic (subscription cancellation, customer tagging) when a complaint arrives. ## How it works [#how-it-works] Chargeflow receives alerts from the networks, matches each one to a merchant and transaction via the Chargeflow Network matching layer, resolves the case, and reports the outcome back to the issuer. Two integration models are supported - fully Chargeflow-managed (most common) or merchant-managed refunds. The model, the outcome flow, and how to choose are covered canonically in [Alerts model](https://docs.chargeflow.io/docs/reference/concepts/alerts-model). ## Work with the API [#work-with-the-api] The Alerts API lets you list alerts, fetch one by id, and post an outcome update (for merchant-managed handling). See the [Alerts API reference](https://docs.chargeflow.io/docs/api/2025-04-01/merchants/alerts). Real-time events: A new alert has arrived. The alert was matched to a transaction. The alert reached an outcome. ## Start integrating [#start-integrating] **Start here** - choose an integration model, wire the endpoints, and handle outcomes. Then run the [Deflect chargebacks with alerts](https://docs.chargeflow.io/docs/merchants/alerts/prevent-with-alerts) recipe end-to-end. Alerts reach you through the [Ethoca](https://docs.chargeflow.io/docs/reference/integrations#mastercard-ethoca) and [Verifi RDR](https://docs.chargeflow.io/docs/reference/integrations#visa-verifi-rdr) networks. ## Where Alerts fits [#where-alerts-fits] Alerts acts at stage 3 of the [transaction lifecycle](https://docs.chargeflow.io/docs/reference/start-here/transaction-lifecycle) - after the complaint, before the chargeback. Disputes that slip past the window are picked up by [dispute automation](https://docs.chargeflow.io/docs/reference/concepts/dispute-automation); risky orders are caught even earlier by [Prevent](https://docs.chargeflow.io/docs/merchants/prevent), before they ship. # Manage pre-chargeback alerts (https://docs.chargeflow.io/docs/merchants/alerts/manage-alerts) You want complaints resolved before they post as chargebacks, with the alert data flowing through your own systems. This guide covers the **Alerts API**: choosing an integration model, the endpoints, and the outcome vocabulary. For the product overview, start at the [Alerts landing page](https://docs.chargeflow.io/docs/merchants/alerts); the integration models are taught canonically in [Alerts model](https://docs.chargeflow.io/docs/reference/concepts/alerts-model). ## How alerts work [#how-alerts-work] Card networks issue a pre-chargeback alert when a cardholder questions a transaction, giving you a short window (typically 24-72 hours) to refund and stop the chargeback from posting. The end-to-end flow and the two integration models - **Chargeflow Alerts** (full automation) and **merchant-managed** (you issue the refund) - are covered in [Alerts model](https://docs.chargeflow.io/docs/reference/concepts/alerts-model). This guide is the API-level how-to: the endpoints, the webhooks, and the merchant-managed outcome flow. Want the alerts delivered to your systems without Chargeflow touching the money? That is merchant-managed handling: you receive every alert over the API and webhooks, issue the refund (or decline) in your own processor, and report the result back. The [steps below](#merchant-managed-step-by-step-responsibilities) are what your side owns. ## Available endpoints [#available-endpoints] | Endpoint | Method | Description | | ---------------------------------------- | ------------------------------------ | --------------------------------------------------------------------------------------------------------------- | | `/public/2025-04-01/alerts` | GET | Retrieve a paginated list of all alerts for your account. Supports filtering by date, type, status, and reason. | | `/public/2025-04-01/alerts/{id}` | GET | Retrieve full details of a specific alert by its ID, including status, outcome, and transaction details. | | `/public/2025-04-01/alerts/{id}/outcome` | POST | Update the outcome for a specific alert. Required when using Merchant-Managed Handling. | Read access to the Alerts endpoints is enabled per account, and working webhook delivery does not grant it. If a key that passes the [health check](https://docs.chargeflow.io/docs/reference/api-fundamentals/error-handling#health-check-endpoint) still gets `403` here, ask [Support](https://docs.chargeflow.io/docs/reference/support) to enable it. ## Available webhooks [#available-webhooks] | Webhook | Trigger | Description | | --------------------------- | -------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | | `alerts.created` | A new pre-chargeback alert is received | Sends an HTTP POST to your endpoint with the alert ID and metadata. Use this to initiate refunds or other mitigation actions. | | `alerts.transaction.linked` | Chargeflow matches an alert to a transaction | Sends an HTTP POST with the alert ID and matched transaction ID. Useful if you need transaction-level data for your automated processes. | | `alerts.updated` | The outcome of an alert is updated | Sends an HTTP POST with the updated outcome and timestamp. | ## Merchant-Managed: step-by-step responsibilities [#merchant-managed-step-by-step-responsibilities] If you are using the Merchant-Managed model, your system must complete the following steps for each alert: ### Receive the alert [#receive-the-alert] Listen for `alerts.created` on your webhook endpoint. The payload includes the alert ID and metadata. If you need the matched PSP transaction ID before taking action, also subscribe to `alerts.transaction.linked`. ### Locate and validate the transaction [#locate-and-validate-the-transaction] Using the alert metadata (amount, currency, card details, ARN), find the corresponding transaction in your payment processor or order management system. ### Issue the refund [#issue-the-refund] Process the refund in your payment processor. Keep a record of the refund confirmation. ### Report the outcome to Chargeflow [#report-the-outcome-to-chargeflow] Call `POST /public/2025-04-01/alerts/{id}/outcome` with the result. This step is critical: without it, Chargeflow cannot report back to the issuer and the chargeback may still be filed. ```bash title="Terminal" curl -X POST https://api.chargeflow.io/public/2025-04-01/alerts/ALERT_ID/outcome \ -H "x-api-key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"outcome": "refunded"}' ``` Failing to call the outcome endpoint in Merchant-Managed mode means Chargeflow cannot close the alert with the issuer. Always report outcomes, even if the transaction was already refunded (`previously_refunded`). ## Outcome vocabularies [#outcome-vocabularies] Alert outcomes use two distinct vocabularies. The value you **post** to the outcome endpoint is not the same set you **receive** on the `alerts.updated` webhook. **Outcome you POST** to `POST /alerts/{id}/outcome`: | Value | Meaning | | --------------------- | ------------------------------------------------------------------- | | `refunded` | You refunded the transaction to handle the alert. | | `previously_refunded` | The transaction had already been refunded before the alert arrived. | | `duplicate` | The alert duplicates one you have already handled. | | `decline` | You are declining to refund this alert. | | `error` | You could not process the alert due to an error. | **Outcome you RECEIVE** on the `alerts.updated` webhook: | Value | Meaning | | --------------------- | -------------------------------------------------------------- | | `duplicate` | The alert is a duplicate of an existing alert. | | `not_found` | No matching transaction could be located. | | `prevented` | The transaction was refunded and the chargeback was prevented. | | `pending` | The alert is still being processed. | | `chargebacked` | The alert escalated to a chargeback despite mitigation. | | `previously_refunded` | The transaction was already refunded before the alert arrived. | | `error` | An error occurred while handling the alert. | ## Next steps [#next-steps] How to register for alert webhooks. Payload reference. Payload reference. Payload reference. # Deflect chargebacks (https://docs.chargeflow.io/docs/merchants/alerts/prevent-with-alerts) Pre-chargeback alerts give you a chance to refund a transaction before it becomes a chargeback. (This recipe is about the [Alerts](https://docs.chargeflow.io/docs/merchants/alerts) product - stopping risky orders **before shipment** is [Prevent](https://docs.chargeflow.io/docs/merchants/prevent).) This recipe is a full, copy-paste-runnable flow for the merchant-managed model: subscribe to alert webhooks, receive an alert, refund the matching transaction in your processor, then report the outcome to Chargeflow so the alert is closed with the issuer. ## Before you start [#before-you-start] * Get your `API Access Key`. Every request sends it in the `x-api-key` header. See [Authentication](https://docs.chargeflow.io/docs/reference/api-fundamentals/authentication). * All requests go to `https://api.chargeflow.io` under the `/public/2025-04-01/` path. This recipe covers the merchant-managed model, where you refund and report outcomes yourself. With Chargeflow Alerts (the automated model), Chargeflow matches and refunds automatically, and you do not need to call the outcome endpoint. ## Steps [#steps] ### Subscribe to alert events [#subscribe-to-alert-events] Register a webhook endpoint for the alert lifecycle events. Each registration subscribes one endpoint to one event, so register once per event: ```bash title="Terminal" curl -X POST https://api.chargeflow.io/public/2025-04-01/webhooks \ -H "x-api-key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"event": "alerts.created", "url": "https://your-server.com/webhooks/alerts-created"}' curl -X POST https://api.chargeflow.io/public/2025-04-01/webhooks \ -H "x-api-key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"event": "alerts.updated", "url": "https://your-server.com/webhooks/alerts-updated"}' ``` ```javascript title="Node.js" // One registration per event for (const [event, path] of [ ['alerts.created', '/webhooks/alerts-created'], ['alerts.updated', '/webhooks/alerts-updated'], ]) { const res = await fetch('https://api.chargeflow.io/public/2025-04-01/webhooks', { method: 'POST', headers: { 'x-api-key': process.env.CHARGEFLOW_API_KEY, 'Content-Type': 'application/json', }, body: JSON.stringify({ event, url: `https://your-server.com${path}` }), }); console.log(await res.json()); } ``` ```python title="Python" import os, requests # One registration per event for event, path in [ ("alerts.created", "/webhooks/alerts-created"), ("alerts.updated", "/webhooks/alerts-updated"), ]: res = requests.post( "https://api.chargeflow.io/public/2025-04-01/webhooks", headers={"x-api-key": os.environ["CHARGEFLOW_API_KEY"]}, json={"event": event, "url": f"https://your-server.com{path}"}, ) print(res.json()) ``` See [Subscribe to Webhook Events](https://docs.chargeflow.io/docs/merchants/automation/subscribe-to-events) for the full list of events, and [Webhooks](https://docs.chargeflow.io/docs/reference/concepts/webhooks#verifying-a-webhook-signature) for signature verification. ### Receive the alerts.created webhook [#receive-the-alertscreated-webhook] When a card network raises a pre-chargeback alert, Chargeflow posts an `alerts.created` event to your endpoint. The payload carries the alert ID and the metadata you need to locate the transaction. ```json title="Webhook payload" { "id": "alert_123456789", "account_id": "account_987654321", "ext_account_id": "platform_acc_12345", "transaction": "txn_abcdef123456", "created_at": "2025-07-31T12:34:56Z", "status": "alerted", "status_date": "2025-07-31T13:00:00Z", "statement_descriptor": "My Merchant Store", "amount": 12500, "currency": "USD", "outcome": "pending", "type": "fraud_warning", "reason": "fraud", "network_transaction": { "id": "net_txn_78910", "created_at": "2025-07-31T12:30:00Z", "amount": 12500, "currency": "USD", "card_brand": "Visa", "bin": "411111", "last4": "1111", "auth_code": "AUTH1234", "arn": "ARN56789" } } ``` Acknowledge with a `2XX` quickly, then handle the alert asynchronously. ```javascript title="Node.js" app.post('/webhooks/alerts', express.json(), (req, res) => { const alert = req.body; res.json({ received: true }); // acknowledge first // The alerts.created payload is delivered flat (no envelope): the alert // fields are at the top level. Subscribe this endpoint to alerts.created, // so every delivery is a new alert. alert.type holds the alert type, // for example 'fraud_warning'. handleAlert(alert.id); }); ``` ### Fetch the full alert (optional) [#fetch-the-full-alert-optional] Some fields, such as the matched `transaction` reference, may be filled in after ingestion. For the current, complete alert record, read it by ID. ```bash title="Terminal" curl -X GET https://api.chargeflow.io/public/2025-04-01/alerts/alert_123456789 \ -H "x-api-key: YOUR_API_KEY" ``` ```javascript title="Node.js" async function handleAlert(alertId) { const res = await fetch(`https://api.chargeflow.io/public/2025-04-01/alerts/${alertId}`, { headers: { 'x-api-key': process.env.CHARGEFLOW_API_KEY }, }); const alert = await res.json(); // Use alert.network_transaction.last4, .arn, .amount to find the charge return alert; } ``` ```python title="Python" import os, requests res = requests.get( "https://api.chargeflow.io/public/2025-04-01/alerts/alert_123456789", headers={"x-api-key": os.environ["CHARGEFLOW_API_KEY"]}, ) alert = res.json() # Use alert["network_transaction"]["last4"], ["arn"], ["amount"] to find the charge ``` You can also list alerts with `GET /public/2025-04-01/alerts`, which supports `offset`, `limit`, `created_at_min`, `created_at_max`, `type`, `status`, `reason`, and `sort` query parameters. ### Refund the matching transaction [#refund-the-matching-transaction] Use the alert metadata to find the charge in your payment processor and refund it. Match on `network_transaction.last4`, `network_transaction.arn`, `amount`, and `currency`. This step happens in your own processor, not in the Chargeflow API. ```javascript title="Node.js" // Pseudocode against your processor's SDK const charge = await psp.findCharge({ last4: alert.network_transaction.last4, arn: alert.network_transaction.arn, amount: alert.amount, currency: alert.currency, }); await psp.refund(charge.id); ``` ### Report the outcome [#report-the-outcome] After processing the alert, report the outcome with `POST /public/2025-04-01/alerts/{alertId}/outcome`. This is what closes the alert with the issuer. The request body takes a single required `outcome` field. Valid `outcome` values are `refunded`, `previously_refunded`, `duplicate`, `decline`, and `error`. ```bash title="Terminal" curl -X POST https://api.chargeflow.io/public/2025-04-01/alerts/alert_123456789/outcome \ -H "x-api-key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"outcome": "refunded"}' ``` ```javascript title="Node.js" async function reportOutcome(alertId, outcome) { const res = await fetch(`https://api.chargeflow.io/public/2025-04-01/alerts/${alertId}/outcome`, { method: 'POST', headers: { 'x-api-key': process.env.CHARGEFLOW_API_KEY, 'Content-Type': 'application/json', }, body: JSON.stringify({ outcome }), }); // Returns 202 Accepted on success return res.status; } await reportOutcome('alert_123456789', 'refunded'); ``` ```python title="Python" import os, requests res = requests.post( "https://api.chargeflow.io/public/2025-04-01/alerts/alert_123456789/outcome", headers={"x-api-key": os.environ["CHARGEFLOW_API_KEY"]}, json={"outcome": "refunded"}, ) # Returns 202 Accepted on success status = res.status_code ``` A successful call returns `202 Accepted`. In the merchant-managed model, always call the outcome endpoint after handling an alert, even if you could not find the transaction. Without this step, Chargeflow cannot close the alert with the issuer and the chargeback may still be filed. ### React to `alerts.updated` [#react-to-alertsupdated] As the alert moves through its lifecycle, Chargeflow fires `alerts.updated`. Use it to keep your records in sync. For example, when `outcome` is `prevented`, record the successful prevention. ```json title="Webhook payload" { "id": "alert_123456789", "account_id": "account_987654321", "status": "prevented", "status_date": "2025-07-31T14:00:00Z", "amount": 12500, "currency": "USD", "outcome": "prevented", "type": "fraud_warning", "reason": "fraud" } ``` If `outcome` is `chargebacked`, the alert escalated to a chargeback despite mitigation. Watch for `dispute.created` if you want to begin enrichment. See [Automate a chargeback dispute](https://docs.chargeflow.io/docs/merchants/automation/automate-a-chargeback-dispute). ## Next steps [#next-steps] The full alert payload reference. Every outcome value and what it means. Register endpoints and verify signatures. What to do when an alert escalates to a chargeback. # Automate a chargeback dispute (https://docs.chargeflow.io/docs/merchants/automation/automate-a-chargeback-dispute) This recipe is a full, copy-paste-runnable flow for responding to a chargeback with Chargeflow, whatever processor it came from. You receive the `dispute.created` webhook, fetch the dispute, attach supporting evidence and notes, and Chargeflow builds and submits the representment on your behalf, ahead of the deadline. The flow is identical for every processor. Each dispute carries a `source` field (`stripe`, `paypal`, `shopify_payments`, `braintree`, and so on) telling you where it originated, but you call the same Chargeflow endpoints regardless. See [Integrations](https://docs.chargeflow.io/docs/reference/integrations) for how each processor connection ingests disputes. You never call a submit endpoint or talk to the processor's dispute API. Once a dispute is in `needs_response` and your evidence is attached, Chargeflow assembles the evidence package and files the representment for you. This recipe is about feeding Chargeflow the context, not about submitting. ## Before you start [#before-you-start] * Connect at least one payment processor to Chargeflow. After that, new disputes from that processor are ingested automatically. See [Integrations](https://docs.chargeflow.io/docs/reference/integrations). * Get your `API Access Key`. Every request sends it in the `x-api-key` header. See [Authentication](https://docs.chargeflow.io/docs/reference/api-fundamentals/authentication). * Register a webhook endpoint for `dispute.created`. See [Subscribe to Webhook Events](https://docs.chargeflow.io/docs/merchants/automation/subscribe-to-events). All requests go to `https://api.chargeflow.io` under the `/public/2025-04-01/` path. ## Steps [#steps] ### Register for the dispute.created event [#register-for-the-disputecreated-event] Register a webhook endpoint so Chargeflow notifies you when a new dispute is ingested, from any connected processor. ```bash title="Terminal" curl -X POST https://api.chargeflow.io/public/2025-04-01/webhooks \ -H "x-api-key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "url": "https://your-server.com/webhook", "event": "dispute.created" }' ``` ```javascript title="Node.js" const res = await fetch('https://api.chargeflow.io/public/2025-04-01/webhooks', { method: 'POST', headers: { 'x-api-key': process.env.CHARGEFLOW_API_KEY, 'Content-Type': 'application/json', }, body: JSON.stringify({ url: 'https://your-server.com/webhook', event: 'dispute.created', }), }); console.log(await res.json()); ``` ```python title="Python" import os, requests res = requests.post( "https://api.chargeflow.io/public/2025-04-01/webhooks", headers={"x-api-key": os.environ["CHARGEFLOW_API_KEY"]}, json={ "url": "https://your-server.com/webhook", "event": "dispute.created", }, ) print(res.json()) ``` ### Receive the dispute.created webhook [#receive-the-disputecreated-webhook] When a cardholder disputes a payment, Chargeflow ingests the dispute, runs its first enrichment pass, and posts a `dispute.created` event to your endpoint. The `dispute.created` event arrives wrapped in the delivery envelope: the dispute fields are inside `data`, and `data.id` is the Chargeflow dispute ID you use in the rest of this recipe. Example payload (the `source` here is `stripe`, but it could be any connected processor): ```json title="Webhook payload" { "type": "dispute.created", "webhookId": "123e4567-e89b-12d3-a456-426614174000", "creationDate": "2025-01-27T10:00:00Z", "data": { "id": "dis_12345", "source_id": "du_123456789", "account_id": "act_112233", "created_at": "2025-01-27T09:00:00Z", "reason": "fraud", "due_by": "2025-02-10T10:00:00Z", "source": "stripe", "amount": 150, "currency": "USD", "status": "needs_response", "stage": "Chargeback", "closed_at": null, "transaction": "tx_1234567890", "subscription": null, "order": "ord_1234567890", "customerCommunication": null } } ``` Your endpoint must return a `2XX` status promptly, then process the event asynchronously. Acknowledge first, work after. ```javascript title="Node.js" const express = require('express'); const app = express(); app.post('/webhook', express.json(), (req, res) => { const event = req.body; // Acknowledge receipt immediately so Chargeflow does not retry res.json({ received: true }); if (event.type === 'dispute.created') { // Same flow for every processor - branch on event.data.source only if you // need processor-specific handling on your side. handleDispute(event.data.id); } }); app.listen(8000, () => console.log('Webhook handler running on port 8000')); ``` Verify the `X-Chargeflow-Hmac-Sha256` signature on every webhook in production. See [Webhooks](https://docs.chargeflow.io/docs/reference/concepts/webhooks#verifying-a-webhook-signature) for the verification code. ### Fetch the dispute [#fetch-the-dispute] Use the Chargeflow dispute ID from `data.id` to read the full, current dispute record. Check the `status`, the `due_by` deadline, and which linked objects (`transaction`, `order`, `subscription`) Chargeflow has already matched. ```bash title="Terminal" curl -X GET https://api.chargeflow.io/public/2025-04-01/disputes/dis_12345 \ -H "x-api-key: YOUR_API_KEY" ``` ```javascript title="Node.js" async function handleDispute(disputeId) { const res = await fetch(`https://api.chargeflow.io/public/2025-04-01/disputes/${disputeId}`, { headers: { 'x-api-key': process.env.CHARGEFLOW_API_KEY }, }); const dispute = await res.json(); console.log(dispute.status, dispute.reason, dispute.due_by); return dispute; } ``` ```python title="Python" import os, requests res = requests.get( "https://api.chargeflow.io/public/2025-04-01/disputes/dis_12345", headers={"x-api-key": os.environ["CHARGEFLOW_API_KEY"]}, ) dispute = res.json() ``` Example response: ```json title="Response" { "id": "dis_12345", "source": "stripe", "source_id": "du_123456789", "account_id": "act_112233", "created_at": "2025-01-27T09:00:00Z", "reason": "fraud", "due_by": "2025-02-10T10:00:00Z", "amount": 150, "currency": "USD", "status": "needs_response", "stage": "Chargeback", "closed_at": null, "transaction": "tx_1234567890", "subscription": null, "order": "ord_1234567890" } ``` Respond only while `status` is `needs_response`. Once the response is filed with the issuer, the status moves to `under_review`. ### Add evidence [#add-evidence] Attach the files that refute the claim. This is a `multipart/form-data` request. The dispute ID is the path parameter, and each call uploads one file with an `evidenceUploadCategory`. For a fraud chargeback, proof of delivery and customer communication are the strongest artifacts. ```bash title="Terminal" curl -X POST https://api.chargeflow.io/public/2025-04-01/disputes/dis_12345/evidence \ -H "x-api-key: YOUR_API_KEY" \ -F "file=@/path/to/delivery-confirmation.pdf" \ -F "evidenceUploadCategory=tracking_information" ``` ```javascript title="Node.js" const fs = require('fs'); const { blob } = require('stream/consumers'); async function addEvidence(disputeId) { const form = new FormData(); form.append('evidenceUploadCategory', 'tracking_information'); form.append( 'file', await blob(fs.createReadStream('./delivery-confirmation.pdf')), 'delivery-confirmation.pdf', ); const res = await fetch( `https://api.chargeflow.io/public/2025-04-01/disputes/${disputeId}/evidence`, { method: 'POST', headers: { 'x-api-key': process.env.CHARGEFLOW_API_KEY }, body: form, }, ); return res.json(); // { requestId, evidenceId } } ``` ```python title="Python" import os, requests with open("/path/to/delivery-confirmation.pdf", "rb") as f: res = requests.post( "https://api.chargeflow.io/public/2025-04-01/disputes/dis_12345/evidence", headers={"x-api-key": os.environ["CHARGEFLOW_API_KEY"]}, files={"file": f}, data={"evidenceUploadCategory": "tracking_information"}, ) data = res.json() # { requestId, evidenceId } ``` A successful upload returns the evidence ID: ```json title="Response" { "requestId": "req_abc123def456", "evidenceId": "evd_789xyz" } ``` Supported categories are `tracking_information`, `customer_communication`, `invoice`, `additional_evidence`, and `additional_notes`. Files can be PNG, JPG, or PDF, up to 5 MB. See [Upload Evidence](https://docs.chargeflow.io/docs/merchants/automation/upload-evidence) for the full reference. ### Add notes [#add-notes] Notes are uploaded through the same endpoint using the `additional_notes` category. This category requires a `content` field with your free-form text, alongside the file. ```bash title="Terminal" curl -X POST https://api.chargeflow.io/public/2025-04-01/disputes/dis_12345/evidence \ -H "x-api-key: YOUR_API_KEY" \ -F "file=@/path/to/account-history.pdf" \ -F "evidenceUploadCategory=additional_notes" \ -F "content=Customer has 4 prior undisputed orders to the same address. IP and billing ZIP match the order on file." ``` ```javascript title="Node.js" async function addNotes(disputeId) { const form = new FormData(); form.append('evidenceUploadCategory', 'additional_notes'); form.append( 'content', 'Customer has 4 prior undisputed orders to the same address. IP and billing ZIP match the order on file.', ); form.append( 'file', await blob(fs.createReadStream('./account-history.pdf')), 'account-history.pdf', ); const res = await fetch( `https://api.chargeflow.io/public/2025-04-01/disputes/${disputeId}/evidence`, { method: 'POST', headers: { 'x-api-key': process.env.CHARGEFLOW_API_KEY }, body: form, }, ); return res.json(); } ``` ```python title="Python" import os, requests with open("/path/to/account-history.pdf", "rb") as f: res = requests.post( "https://api.chargeflow.io/public/2025-04-01/disputes/dis_12345/evidence", headers={"x-api-key": os.environ["CHARGEFLOW_API_KEY"]}, files={"file": f}, data={ "evidenceUploadCategory": "additional_notes", "content": "Customer has 4 prior undisputed orders to the same address. IP and billing ZIP match the order on file.", }, ) data = res.json() ``` Add evidence as early as possible after `dispute.created`. Chargeflow folds your uploads into the evidence package before submission, so the sooner they arrive, the more the AI can build around them. ### Let Chargeflow submit the response [#let-chargeflow-submit-the-response] You do not call a separate submit endpoint, and you never touch the processor's own dispute API. Once a dispute is in `needs_response` and your evidence is attached, Chargeflow assembles the evidence package and submits the representment to the issuer ahead of the `due_by` deadline. Track progress by reading the dispute again. The `status` moves from `needs_response` to `under_review` after submission, and to `won` or `lost` once the issuer decides. ```bash title="Terminal" curl -X GET https://api.chargeflow.io/public/2025-04-01/disputes/dis_12345 \ -H "x-api-key: YOUR_API_KEY" ``` ```javascript title="Node.js" const res = await fetch('https://api.chargeflow.io/public/2025-04-01/disputes/dis_12345', { method: 'GET', headers: { 'x-api-key': process.env.CHARGEFLOW_API_KEY, }, }); const data = await res.json(); ``` ```python title="Python" import os, requests res = requests.get( "https://api.chargeflow.io/public/2025-04-01/disputes/dis_12345", headers={"x-api-key": os.environ["CHARGEFLOW_API_KEY"]}, ) data = res.json() ``` ## Next steps [#next-steps] Every evidence category and file rule. Pull in disputes that predate your webhook setup. The full event payload reference. What each dispute status means. # Automate dispute management (https://docs.chargeflow.io/docs/merchants/automation/automate-dispute-management) You have connected your PSPs and want disputes fought automatically. Chargeflow runs the whole pipeline on its own - this guide shows the two places your integration actually does work, and how to wire them. The full ingest → enrich → generate → submit → monitor model is taught canonically in [Dispute Automation Engine](https://docs.chargeflow.io/docs/reference/concepts/dispute-automation). Your integration touches it in exactly two places, both optional but high-impact: | Pipeline stage | Who acts | | --------------------------------------------------- | -------------------------------------------------------------------- | | Ingest · first enrichment · generation · submission | Chargeflow, automatically | | **Second enrichment** | **You** - send targeted signals the engine can't retrieve on its own | | **Monitor** | **You** - read status, or subscribe to lifecycle webhooks | ## Connect your PSPs [#connect-your-psps] Connect your payment processors in Chargeflow Settings. From then on, every new dispute from those processors is ingested and enriched automatically - you do not poll any PSP API or import disputes by hand. ## Subscribe to `dispute.created` [#subscribe-to-disputecreated] Register a webhook endpoint so your enrichment flow triggers the moment a dispute is ingested. See [Subscribe to webhook events](./subscribe-to-events) for registration, and [dispute.created](../webhook-events#dispute-created) for the payload. ## Send a second enrichment (the high-impact step) [#send-a-second-enrichment-the-high-impact-step] This is where your integration adds the most win-rate. After `dispute.created`, inspect what Chargeflow already matched (transaction, order, subscription) and fill the gaps by calling the enrich endpoint with the data only you have - order details, subscription history, customer activity, communications. See [Enrich a dispute](./enrich-a-dispute) for the PATCH endpoint, upsert semantics, and array-merge behavior. Enrich as early as possible after `dispute.created`. Chargeflow folds your signals into the evidence package before submission - the sooner they arrive, the more the engine can build around them. ## Track the outcome [#track-the-outcome] Chargeflow generates, submits, and monitors the case for you - you never call a submit endpoint or touch the processor's dispute API. To follow progress, read the dispute (`status` moves `needs_response` → `under_review` → `won`/`lost`) or subscribe to lifecycle webhooks and feed your own dashboards. ## Next step [#next-step] Send the signals that move win rate - the PATCH endpoint and merge behavior. Building the whole thing end-to-end? Follow the [Automate a chargeback dispute](./automate-a-chargeback-dispute) recipe. # Backfill the last 90 days (https://docs.chargeflow.io/docs/merchants/automation/backfill-90-days) When you first connect to Chargeflow, your webhook only fires for disputes that arrive after setup. To catch up on disputes that predate it, page through the Disputes list endpoint and keep the ones created in the last 90 days. This recipe is a full, copy-paste-runnable backfill. ## Before you start [#before-you-start] * Get your `API Access Key`. Every request sends it in the `x-api-key` header. See [Authentication](https://docs.chargeflow.io/docs/reference/api-fundamentals/authentication). * All requests go to `https://api.chargeflow.io` under the `/public/2025-04-01/` path. ## How pagination works [#how-pagination-works] The Disputes list endpoint uses offset-based pagination. See [Pagination](https://docs.chargeflow.io/docs/reference/api-fundamentals/pagination) for the `offset` and `limit` parameters and the shared pattern. For this recipe, the key detail is that `offset` is a page index, not a row count (covered in the note below). The response wraps the results in `disputes` and a `pagination` object: ```json title="Response" { "disputes": [ { "id": "66e6ea9ecd94925a9f8060d9", "source": "stripe", "source_id": "du_123456789", "created_at": "2024-02-10T12:00:00Z", "reason": "fraud", "due_by": "2024-02-20T12:00:00Z", "amount": 100, "currency": "USD", "status": "needs_response", "stage": "Chargeback" } ], "pagination": { "totalCount": 5400, "offset": 0, "limit": 100, "totalPages": 54 } } ``` | Field | Description | | ----------------------- | ----------------------------------------- | | `pagination.totalCount` | Total number of disputes available. | | `pagination.offset` | The current page offset. | | `pagination.limit` | Number of disputes returned in this page. | | `pagination.totalPages` | Total number of pages available. | ## Steps [#steps] ### Fetch a single page [#fetch-a-single-page] Set `limit=100` to minimize the number of requests. Start at `offset=0`. ```bash title="Terminal" curl -X GET "https://api.chargeflow.io/public/2025-04-01/disputes?offset=0&limit=100" \ -H "x-api-key: YOUR_API_KEY" ``` ```javascript title="Node.js" async function fetchPage(offset, limit = 100) { const url = `https://api.chargeflow.io/public/2025-04-01/disputes?offset=${offset}&limit=${limit}`; const res = await fetch(url, { headers: { 'x-api-key': process.env.CHARGEFLOW_API_KEY }, }); return res.json(); } ``` ```python title="Python" import os, requests def fetch_page(offset, limit=100): res = requests.get( "https://api.chargeflow.io/public/2025-04-01/disputes", headers={"x-api-key": os.environ["CHARGEFLOW_API_KEY"]}, params={"offset": offset, "limit": limit}, ) return res.json() ``` ### Page until you reach 90 days [#page-until-you-reach-90-days] Disputes come back newest first, so walk pages in order and stop once you cross the 90-day cutoff. Filter each page by `created_at` and break out as soon as a dispute is older than the window. Use `pagination.totalPages` as a hard stop so you never loop past the end. ```javascript title="Node.js" async function backfillLast90Days() { const limit = 100; const cutoff = new Date(Date.now() - 90 * 24 * 60 * 60 * 1000); const recent = []; let offset = 0; let totalPages = 1; while (offset < totalPages) { const page = await fetchPage(offset, limit); totalPages = page.pagination.totalPages; let crossedCutoff = false; for (const dispute of page.disputes) { if (new Date(dispute.created_at) >= cutoff) { recent.push(dispute); } else { // Older than 90 days. Since results are newest first, we can stop. crossedCutoff = true; break; } } if (crossedCutoff) break; offset += 1; } return recent; } ``` `offset` is a page number, not a row count. Increment it by `1` per page, not by `limit`. ### Process each dispute [#process-each-dispute] With the 90-day list in hand, write each dispute to your own store and trigger whatever follow-up you need. For example, enrich any open dispute that is still in `needs_response`. ```javascript title="Node.js" const recent = await backfillLast90Days(); console.log(`Backfilled ${recent.length} disputes from the last 90 days`); for (const dispute of recent) { // Persist the dispute in your system await upsertDispute(dispute); // Optionally act on disputes that still need a response if (dispute.status === 'needs_response') { // See the "Automate a chargeback dispute" recipe for the response flow } } ``` ## Be a good API citizen [#be-a-good-api-citizen] * Use `limit=100` so a 90-day backfill takes the fewest possible requests. * Run the backfill once at setup. After that, rely on the `dispute.created` webhook for new disputes rather than polling. * If you need to re-run the backfill, space out the requests instead of firing all pages at once. ## Next steps [#next-steps] The shared offset and limit pattern. Respond to the disputes you just backfilled. Stop polling once the backfill is done. # Automation (https://docs.chargeflow.io/docs/merchants/automation) You have chargebacks being filed and want them fought - without building a disputes team. **Automation** is Chargeflow's representment product: once a dispute is filed, Chargeflow ingests it from your connected PSPs, assembles an evidence package, and submits the response on your behalf. Your integration's job is to make that evidence stronger by sending the data only you have. ## When to use Automation [#when-to-use-automation] * You want every filed dispute answered, automatically, without per-case manual work. * You have order, subscription, or customer-communication data that strengthens evidence. * You want dispute status and outcomes flowing into your own systems via API and webhooks. * You want to backfill and track historical disputes alongside new ones. ## How it works [#how-it-works] Chargeflow ingests disputes from your connected payment processors, enriches each case with the signals you provide, generates the evidence response, and submits it within the network deadline. Four parts: data ingestion, data enrichment, evidence creation, submission, with every outcome fed back into the next case. The whole pipeline in one diagram, from filing to outcome. The agent architecture that writes the case. Why the claim is written from scratch rather than templated. The API-level model is in [Dispute automation](https://docs.chargeflow.io/docs/reference/concepts/dispute-automation); the mechanics of a representment in [Representment and evidence](https://docs.chargeflow.io/docs/reference/concepts/representment-and-evidence). ## Work with the API [#work-with-the-api] List disputes, fetch one by id, and enrich cases with your data. See the [Disputes API reference](https://docs.chargeflow.io/docs/api/2025-04-01/merchants/disputes). Real-time events: A new dispute was ingested - the trigger for your enrichment flow. ## Start integrating [#start-integrating] The golden path is one guide - where your integration plugs into the pipeline: **Start here** - the two places your integration acts: send a second enrichment, then track the outcome. Then go deeper as you need it: [Enrich a dispute](https://docs.chargeflow.io/docs/merchants/automation/enrich-a-dispute) to move win rate, [Upload evidence](https://docs.chargeflow.io/docs/merchants/automation/upload-evidence) for files, run the [Automate a chargeback dispute](https://docs.chargeflow.io/docs/merchants/automation/automate-a-chargeback-dispute) recipe end-to-end, or [Backfill 90 days](https://docs.chargeflow.io/docs/merchants/automation/backfill-90-days) of history. ## Where Automation fits [#where-automation-fits] Automation acts at stage 4 of the [transaction lifecycle](https://docs.chargeflow.io/docs/reference/start-here/transaction-lifecycle) - after the chargeback is filed. Complaints caught earlier are deflected by [Alerts](https://docs.chargeflow.io/docs/merchants/alerts); risky orders are stopped before shipping by [Prevent](https://docs.chargeflow.io/docs/merchants/prevent). # Subscribe to webhook events (https://docs.chargeflow.io/docs/merchants/automation/subscribe-to-events) Webhooks let your application receive real-time notifications from Chargeflow without polling the API. When a subscribed event occurs, for example when a new dispute is ingested, Chargeflow sends an HTTP POST request to your configured endpoint with the event payload. ## Before you start [#before-you-start] 1. Navigate to your [Chargeflow Account Settings](https://app.chargeflow.io/settings). 2. Scroll to the **Developers** section. 3. Generate **API Access Keys**. The same key is used for API requests and to sign webhook payloads. Once your API key is available, you can register webhook endpoints either from the Chargeflow dashboard (click **+ Add Webhook**) or via the API. ## Register a webhook endpoint [#register-a-webhook-endpoint] ``` POST https://api.chargeflow.io/public/2025-04-01/webhooks ``` Each registration subscribes one endpoint to **one** event (`event` is a single string). Register once per event you need, or pass `*` to subscribe one endpoint to all events. ```bash title="Terminal" curl -X POST https://api.chargeflow.io/public/2025-04-01/webhooks \ -H "x-api-key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"event": "dispute.created", "url": "https://your-server.com/webhooks/dispute-created"}' ``` A successful registration returns `{"success": true, "id": "..."}`. See the [Create Webhook reference](https://docs.chargeflow.io/docs/api/2025-04-01/merchants/webhooks-management) for the full event enum. ### Available events [#available-events] | Event | Description | | --------------------------- | -------------------------------------------------------------- | | `dispute.created` | A new dispute has been ingested and initially enriched | | `alerts.created` | A new pre-chargeback alert has been received | | `alerts.updated` | The outcome of an alert has been updated | | `alerts.transaction.linked` | An alert has been matched to its corresponding PSP transaction | ## List your webhooks [#list-your-webhooks] ```bash title="Terminal" curl -X GET https://api.chargeflow.io/public/2025-04-01/webhooks \ -H "x-api-key: YOUR_API_KEY" ``` ## Delete a webhook [#delete-a-webhook] ```bash title="Terminal" curl -X DELETE https://api.chargeflow.io/public/2025-04-01/webhooks/WEBHOOK_ID \ -H "x-api-key: YOUR_API_KEY" ``` ## Create a handler [#create-a-handler] Your endpoint must: 1. Accept `POST` requests with a JSON body. 2. Return a `2XX` status code promptly, before any complex logic that could cause a timeout. Chargeflow retries delivery until a `2XX` response is received or the retry limit is reached. 3. Process the event asynchronously after acknowledging receipt. ### Example handler (Node.js / Express) [#example-handler-nodejs--express] `dispute.created` arrives wrapped in an envelope (`{type, data, creationDate, webhookId}`) where `type` is the event name. **Alert payloads are delivered flat, with no envelope** - their `type` field holds the **alert** type (for example `fraud_warning`), not the event name. Do not switch on `event.type` to route alert events; register a dedicated URL per event instead (one registration is one event anyway). Payload shapes: [webhook events overview](../webhook-events). ```javascript title="Node.js" const express = require('express'); const app = express(); app.use(express.json({ type: 'application/json' })); // One route per registered event - the URL tells you which event arrived. app.post('/webhooks/dispute-created', (request, response) => { response.json({ received: true }); // acknowledge first const dispute = request.body.data; // enveloped: {type, data, creationDate, webhookId} // Trigger your enrichment flow asynchronously: // enrichDispute(dispute.id); }); app.post('/webhooks/alerts-created', (request, response) => { response.json({ received: true }); const alert = request.body; // flat payload - no envelope // alert.id, alert.type (e.g. 'fraud_warning'), alert.status, alert.outcome // Initiate refund or mitigation workflow: // handleAlert(alert.id); }); app.listen(8000, () => console.log('Webhook handler running on port 8000')); ``` ## Signature verification and delivery [#signature-verification-and-delivery] For signature verification and delivery/retry behavior, see [Webhooks](https://docs.chargeflow.io/docs/reference/concepts/webhooks). ## Testing webhooks [#testing-webhooks] After saving your webhook registration, you can send a mock payload at any time to validate your integration: * Click the **Test** button next to your webhook endpoint in the Chargeflow dashboard, or * Access the actions menu for the registered endpoint and select **Send Test Payload**. Chargeflow will deliver a sample event payload to your endpoint. Check that your handler responds with `200 OK` and processes the payload correctly. ## Next steps [#next-steps] Full event payload reference. How dispute.created fits into the automation flow. How alert webhooks work in each integration model. Signature verification and delivery/retry behavior. # Upload evidence (https://docs.chargeflow.io/docs/merchants/automation/upload-evidence) The Upload Evidence API allows you to attach supporting documents directly to a dispute. Use it when you have screenshots, delivery confirmations, signed invoices, or other file-based artifacts that strengthen your chargeback response. ## When to upload evidence [#when-to-upload-evidence] * Screenshots of customer communications (support tickets, email threads, chat logs) * Proof of delivery or tracking confirmation documents * Signed invoices or order confirmations * Any additional documentation that corroborates your response narrative Upload evidence as early as possible after receiving a `dispute.created` event. Chargeflow incorporates uploaded files into the evidence package before submission, so the sooner they arrive, the more time the AI has to build around them. ## Endpoint [#endpoint] ``` POST https://api.chargeflow.io/public/2025-04-01/disputes/{disputeId}/evidence ``` This is a `multipart/form-data` request. Pass the Chargeflow dispute ID as the path parameter. ### Request fields [#request-fields] | Field | Type | Required | Description | | ------------------------ | ------ | ----------- | ------------------------------------------------------------------------------------- | | `file` | binary | Yes | The file to upload | | `evidenceUploadCategory` | string | Yes | Category of the evidence (see values below) | | `content` | string | Conditional | Required when `evidenceUploadCategory` is `additional_evidence` or `additional_notes` | **`evidenceUploadCategory` values:** | Value | Description | | ------------------------ | ---------------------------------------------------------------------------- | | `tracking_information` | Shipping tracking documents or delivery confirmations | | `customer_communication` | Screenshots or transcripts of customer conversations | | `invoice` | Invoices or order confirmations | | `additional_evidence` | Any other supporting evidence (requires `content` field) | | `additional_notes` | Free-form notes to accompany the dispute response (requires `content` field) | ### Supported file types [#supported-file-types] * Images: PNG, JPG * Documents: PDF * Maximum file size: 5 MB ## Example: upload a customer communication screenshot [#example-upload-a-customer-communication-screenshot] ```bash title="Terminal" curl -X POST https://api.chargeflow.io/public/2025-04-01/disputes/DISPUTE_ID/evidence \ -H "x-api-key: YOUR_API_KEY" \ -F "file=@/path/to/screenshot.png" \ -F "evidenceUploadCategory=customer_communication" ``` ## Example: upload tracking information with a note [#example-upload-tracking-information-with-a-note] ```bash title="Terminal" curl -X POST https://api.chargeflow.io/public/2025-04-01/disputes/DISPUTE_ID/evidence \ -H "x-api-key: YOUR_API_KEY" \ -F "file=@/path/to/delivery-confirmation.pdf" \ -F "evidenceUploadCategory=additional_evidence" \ -F "content=FedEx delivery confirmation showing package signed for at customer address on Jan 26." ``` ## Response [#response] A successful upload returns `200 OK` with the evidence ID: ```json title="Response" { "requestId": "req_abc123def456", "evidenceId": "evd_789xyz" } ``` ## Upload-specific errors [#upload-specific-errors] A file larger than 5 MB is rejected with a `400`. For the full list of HTTP status codes and the standard error response shape, see [Error handling](https://docs.chargeflow.io/docs/reference/api-fundamentals/error-handling). ## Next steps [#next-steps] Send structured data alongside file uploads. Log structured message records (not file uploads) via the dedicated endpoint. The structured evidence that pairs with your uploads, for SaaS or physical goods. # Zapier integration (no-code) (https://docs.chargeflow.io/docs/merchants/automation/zapier-no-code) Zapier lets you connect Chargeflow to thousands of apps and automate actions when a new dispute is created, no custom code required. ## What you can do with Zapier + Chargeflow [#what-you-can-do-with-zapier--chargeflow] 1. Enrich disputes with subscription, order, transaction, customer, or internal data sourced from other apps. 2. Update your CRM or order management systems automatically when a dispute is created. 3. Trigger internal workflows across your own tools (Slack notifications, task creation, etc.). 4. Review and route full dispute details in real time. 5. Build custom flows tailored to your business needs. Chargeflow includes pre-built Zap templates that you can reuse instead of creating everything from scratch. ## Step-by-step: create a Zap [#step-by-step-create-a-zap] ### Log in and create a new Zap [#log-in-and-create-a-new-zap] Log in to your [Zapier account](https://zapier.com) and create a new Zap from scratch. ### Select Chargeflow as the trigger app [#select-chargeflow-as-the-trigger-app] Click **Trigger** (the first step in the workflow) and search for **Chargeflow** in the apps search bar. ### Select the trigger event [#select-the-trigger-event] Open the **Trigger Event** dropdown and select **New Dispute**. ### Generate your Chargeflow API key [#generate-your-chargeflow-api-key] Open your Chargeflow account, navigate to **Settings**, and scroll to the **Developers** section. Click **Generate Keys** to create your API keys. **Keep your API keys secure.** Your API keys provide full access to your Chargeflow data. Store them safely and only share them with trusted parties. Do not commit API keys to source control or include them in client-side code. ### Connect your Chargeflow account in Zapier [#connect-your-chargeflow-account-in-zapier] Copy your **API Access Key** from Chargeflow Settings and return to Zapier. Paste the key into the **Account** field when prompted. ### Test the connection [#test-the-connection] Click **Continue** and run a test to confirm the connection was set up successfully. Zapier will attempt to retrieve a sample dispute from your Chargeflow account. ### Select a sample dispute and build your workflow [#select-a-sample-dispute-and-build-your-workflow] Select one of the available sample disputes. The dispute fields (ID, amount, currency, reason, status, etc.) become available as dynamic values you can map to actions in the rest of your Zap. Add one or more action steps, for example: * Create a row in Google Sheets with the dispute details. * Post a message to a Slack channel. * Create a task in your project management tool. * Look up the order in your e-commerce platform and send the data back to Chargeflow via a webhook action. ### Activate your Zap [#activate-your-zap] Once your workflow is configured and tested, turn on the Zap. From this point, every new dispute Chargeflow ingests will automatically trigger the Zap. ## Connect Chargeflow to an AI assistant [#connect-chargeflow-to-an-ai-assistant] If your goal is to query dispute data from an AI tool such as Claude or ChatGPT, use Zapier MCP rather than writing your own API client. Zapier exposes the Chargeflow connection you set up above to the assistant as tools, so there is no authentication, signing, or retry code of yours to maintain: those are exactly the pieces that produce header and HMAC errors in hand-rolled scripts. ### Connect Chargeflow in Zapier [#connect-chargeflow-in-zapier] Follow the steps above through **Connect your Chargeflow account in Zapier** so Zapier holds a working Access Key. ### Enable Zapier MCP for your AI client [#enable-zapier-mcp-for-your-ai-client] In Zapier, open **MCP**, create a server, add the Chargeflow actions you want the assistant to use, then paste the generated MCP endpoint into your AI client's MCP settings. ### Ask the assistant for your data [#ask-the-assistant-for-your-data] Prompt it with something concrete, for example "list disputes created this week". The assistant calls Chargeflow through Zapier and answers from the live response. A Chargeflow MCP server that a coding agent can call directly is planned - see [Tools](https://docs.chargeflow.io/docs/reference/tools#mcp-server) for what works today, including the hosted AI skill at [`/SKILL.md`](https://docs.chargeflow.io/SKILL.md). ## Pre-built Zap templates [#pre-built-zap-templates] Chargeflow provides pre-built Zap templates for common use cases, such as syncing disputes to a spreadsheet or notifying your team in Slack. Look for Chargeflow templates in the Zapier template gallery to get started faster. ## Next steps [#next-steps] For developers who prefer to build a custom webhook handler. Send enrichment data back to Chargeflow from any system. Understand the full automation flow. # Developers (https://docs.chargeflow.io/docs/platforms/connect/developers) Developers is where a Connect platform manages its credentials and its webhook endpoints. ## API keys [#api-keys] Generate **production** and **sandbox** keys. The access key goes in the `x-api-key` header on every request; the secret key is only needed if you enforce HMAC, and it is shown once at generation time. ```bash title="Terminal" curl -X GET https://api.chargeflow.io/public/2025-04-01/health-check/access-key \ -H "x-api-key: YOUR_PLATFORM_API_KEY" ``` ```json title="Response" "OK" ``` Full setup, including the signing string format for HMAC: [Authentication](https://docs.chargeflow.io/docs/reference/api-fundamentals/authentication) and [API keys](https://docs.chargeflow.io/docs/reference/api-fundamentals/test-credentials). ## HMAC [#hmac] HMAC signature validation is off by default. Turning it on means Chargeflow verifies a signature on every inbound request, which protects against both forgery and tampering. Enable it once your integration is stable, not during first build: a wrong signature and a wrong key look identical from the outside. ## Webhooks [#webhooks] Register an endpoint and choose which events it receives. Platform events: | Event | Fires when | | -------------------------- | -------------------------------------------------- | | `dispute.created` | A dispute is ingested for one of your merchants | | `evidence.ready` | A generated evidence package is available to fetch | | `evidence.error` | Generation failed for a dispute | | `integration.access.error` | A processor connection stopped working | Payloads and handling are documented in [Platform webhook events](https://docs.chargeflow.io/docs/platforms/webhook-events); registration endpoints are in the [Webhooks management API](https://docs.chargeflow.io/docs/api/2025-04-01/merchants/webhooks-management). Reply `200` to acknowledge. A non-`200` is treated as a delivery failure and retried. ## Next step [#next-step] Use the key you just generated: evidence in four steps. # Disputes (https://docs.chargeflow.io/docs/platforms/connect/disputes) Disputes is every dispute across all your merchants, and where each one stands right now. ## Statuses [#statuses] | Status | Meaning | | ------------------ | -------------------------------------------------------------- | | **Needs response** | The clock is running and evidence has not been submitted | | **Under review** | Submitted, waiting on the issuer | | **Won** | Decided in the merchant's favour | | **Lost** | Decided against the merchant | | **Appealable** | Lost, but a further stage is available | | **Insured** | Covered under the merchant's arrangement regardless of outcome | | **Prevented** | Deflected before it became a chargeback | The underlying state machine, including which transitions are possible, is documented in [Dispute state machine](https://docs.chargeflow.io/docs/reference/concepts/dispute-state-machine). ## What you can do [#what-you-can-do] * **Track volume over time**, with a processing versus won breakdown and total charges. * **Filter** by status, response deadline, reason, source (Stripe, Klarna, PayPal, Afterpay, Adyen, or the Chargeflow API), card, stage, and amount. * **See what is managed by Chargeflow** versus handled elsewhere, so a dispute never falls between you and the engine. * **Open the evidence PDF** submitted for a dispute, and view its version history where the evidence was revised. * **View as merchant** to see a dispute exactly as the merchant sees it, which is what you want open when they call support. ## Response deadlines [#response-deadlines] Deadlines come from the card network and the processor, not from Chargeflow, and they are the one thing that cannot be recovered once missed. Filter by response deadline when you want to know what is at risk this week. Network timelines are documented in [Network timelines](https://docs.chargeflow.io/docs/reference/concepts/network-timelines). ## Reading it over the API [#reading-it-over-the-api] Everything on this screen is available programmatically: | You want | Endpoint | | ---------------------------------- | ------------------------------------------------------------------- | | List disputes for a merchant | [Get disputes](https://docs.chargeflow.io/docs/api/2025-04-01/merchants/disputes) | | Load a dispute into Connect | [Create dispute](https://docs.chargeflow.io/docs/api/2025-04-01/platforms/merchants-disputes) | | Fetch a generated evidence package | [Get evidence by ID](https://docs.chargeflow.io/docs/api/2025-04-01/platforms/evidence) | | Be told when something changes | [Platform webhook events](https://docs.chargeflow.io/docs/platforms/webhook-events) | ## Next step [#next-step] Connect the processors that route these disputes in. # Run Connect (https://docs.chargeflow.io/docs/platforms/connect) You have a Connect account and you need to get merchants recovering. This section covers the Connect dashboard: what each area does and what you can do in it. In one line: connect merchants, route their disputes automatically, Chargeflow wins the money back. Connect runs as a dashboard that carries both your brand and Chargeflow's. Your merchants see your platform. The recovery engine runs underneath. ## Five steps to running [#five-steps-to-running] ## Set up your platform [#set-up-your-platform] Pick your platform name, brand colour, logo, and industry. A live preview shows how your brand pairs with Chargeflow in the co-branded header. Branding can change at any time from [Settings](https://docs.chargeflow.io/docs/platforms/connect/settings). ## Connect a payment processor [#connect-a-payment-processor] From [Integrations](https://docs.chargeflow.io/docs/platforms/connect/integrations), connect a PSP. The smart connection flow detects the merchants on that account and imports them, so you are not adding them by hand. ## Onboard your merchants [#onboard-your-merchants] Invite them to the co-branded portal, or activate them instantly. A Magic Link is copyable per merchant if you want to send the invite through your own channel. See [Merchants](https://docs.chargeflow.io/docs/platforms/connect/merchants). ## Let the engine work [#let-the-engine-work] Disputes flow in from connected processors and are scored, evidenced, and submitted automatically. Recovery performance builds up across [Merchants](https://docs.chargeflow.io/docs/platforms/connect/merchants) and [Disputes](https://docs.chargeflow.io/docs/platforms/connect/disputes). ## Optional: go API-first with EaaS [#optional-go-api-first-with-eaas] If you would rather load dispute data programmatically than connect a PSP, follow the eight-step [Evidence-as-a-Service setup](https://docs.chargeflow.io/docs/platforms/eaas/setup) instead of step 2. ## What Connect gives you [#what-connect-gives-you] | Capability | Where | | -------------------------------------------------------------- | ---------------------------------------------------------- | | Onboard and manage merchants, track their recovery performance | [Merchants](https://docs.chargeflow.io/docs/platforms/connect/merchants) | | Every dispute across every merchant, with status and deadlines | [Disputes](https://docs.chargeflow.io/docs/platforms/connect/disputes) | | Connect processors so disputes route in automatically | [Integrations](https://docs.chargeflow.io/docs/platforms/connect/integrations) | | Generate evidence over the API with no PSP connection | [Evidence-as-a-Service](https://docs.chargeflow.io/docs/platforms/eaas/introduction) | | Embed live dispute widgets in your own dashboard | [Widgets](https://docs.chargeflow.io/docs/platforms/connect/widgets) | | API keys, HMAC, webhooks | [Developers](https://docs.chargeflow.io/docs/platforms/connect/developers) | | Branding, team, roles and permissions | [Settings](https://docs.chargeflow.io/docs/platforms/connect/settings) | ## Next step [#next-step] Onboard the first merchant and watch the first dispute arrive. Building against the API rather than the dashboard? Start at the [Platforms quickstart](https://docs.chargeflow.io/docs/platforms/quickstart). # Integrations (https://docs.chargeflow.io/docs/platforms/connect/integrations) Connect third-party payment processors so disputes and chargebacks are fully automated. This is the connection that makes everything else work: without it, no dispute reaches the engine. ## What you can connect [#what-you-can-connect] Connect groups processors into three families: | Group | Examples | | -------------------------- | --------------------------------------------------------------------------------------------------- | | **Payment processors** | Stripe, Checkout.com, PayPal, Adyen, Stripe Connect, Braintree, Commerce Control (Fiserv), and more | | **Subscriptions and BNPL** | Klarna, Affirm, Afterpay, Sezzle, Recharge | | **eCommerce platforms** | Shopify Payments, WooCommerce, Wix | The merchant-facing Chargeflow App groups Klarna, Affirm, Afterpay, and Sezzle under payment processors, while Connect groups them under Subscriptions and BNPL. Same integrations, different shelf. The full merchant-side catalog with per-integration status is in [Integrations](https://docs.chargeflow.io/docs/reference/integrations). ## The smart PSP connection flow [#the-smart-psp-connection-flow] Connecting a processor account is not one merchant. The smart flow: 1. Detects the merchants present on the processor account. 2. Shows you what it found so you can review before importing. 3. Imports them automatically once you confirm. That review step is the point. Importing a processor account blind is how a merchant ends up in your pipeline that should not be there. ## Merchant attribution [#merchant-attribution] Map each processor account to the merchant it belongs to, so disputes route to the right merchant the moment they arrive rather than being reconciled later. Get this right at connection time: attribution errors are invisible until someone reads a report or a merchant sees a dispute that is not theirs. ## Keeping connections healthy [#keeping-connections-healthy] A processor connection can need attention - credentials rotated, access revoked, permissions changed. Reconnect from this screen when that happens. Watch for `integration.access.error`, which is the event that tells you a connection has stopped working before the merchant notices missing disputes. See [Monitor integration health](https://docs.chargeflow.io/docs/platforms/monitor-integration-health). ## Turning on Evidence-as-a-Service [#turning-on-evidence-as-a-service] EaaS is enabled from Integrations. It is the alternative to a PSP connection: your platform loads dispute data over the API and Chargeflow returns evidence, with no processor link required. See the [eight-step setup](https://docs.chargeflow.io/docs/platforms/eaas/setup). ## Next step [#next-step] The API-first path, eight steps, no PSP connection needed. # Merchants (https://docs.chargeflow.io/docs/platforms/connect/merchants) Merchants is your pipeline: every merchant you have invited or onboarded, and how their recovery is going. ## What you see [#what-you-see] Each merchant carries a status and a performance summary. | Status | Meaning | | ------------ | --------------------------------------------- | | **Active** | Onboarded, processor linked, disputes routing | | **Pending** | Invited, has not completed onboarding | | **Inactive** | Deactivated, no longer processing disputes | Performance per merchant covers disputes processing, disputes under review, disputes won, and recovery rate. ## Onboard a merchant [#onboard-a-merchant] Two paths, chosen per merchant: | Path | What happens | Use when | | ------------------------------- | --------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | | **Invite to co-branded portal** | The merchant receives an invite and completes onboarding themselves in a portal carrying your brand | The merchant should own the connection and see their own disputes | | **Instant activation** | You activate the merchant directly, no action needed from them | You already hold the processor relationship and the merchant should not have to do anything | You can copy a **Magic Link** for a merchant and send it through your own channel instead of the built-in invite, which is useful when onboarding runs through your existing account managers. Doing this over the API instead? See [Onboard a merchant](https://docs.chargeflow.io/docs/platforms/eaas/onboard-a-merchant) and the [Accounts API](https://docs.chargeflow.io/docs/api/2025-04-01/platforms/accounts). ## Manage the pipeline [#manage-the-pipeline] * **Search, filter, sort, export.** Filter by status and processor; export for reporting. * **Re-invite** merchants stuck in Pending. * **Link a PSP account** to a merchant that onboarded before its processor was connected. * **Open a merchant's dashboard** to see what they see. * **Deactivate and reactivate** without losing history. ## Attribution matters more than it looks [#attribution-matters-more-than-it-looks] A dispute arrives from a processor account, not from a merchant. Connect maps processor accounts to merchants so each dispute lands against the right one. If attribution is wrong, the dispute still gets fought but the reporting is wrong, and a merchant may see a dispute that is not theirs. Check mapping when you connect a processor, not after the first invoice. See [Integrations](https://docs.chargeflow.io/docs/platforms/connect/integrations). ## Next step [#next-step] Watch the disputes arrive and see where each one stands. # Settings (https://docs.chargeflow.io/docs/platforms/connect/settings) Settings covers three things: how your brand appears to merchants, who on your team has access, and what they can do. ## Branding [#branding] Set your platform name, identity, logo, and brand colour. These drive the co-branded header your merchants see, and a live preview shows how your brand pairs with Chargeflow before you save. Branding can be changed at any time; it is not fixed at onboarding. If you would rather Chargeflow not appear at all, that is a different delivery model, not a branding setting. See [White-Label](https://docs.chargeflow.io/docs/platforms/chargeflow-embedded/overview). ## Team [#team] Invite members, resend pending invites, change roles, and remove access. Removing access is immediate. ## Roles and permissions [#roles-and-permissions] Permissions are defined per role at four levels: | Level | What it allows | | ------------- | ---------------------------------------------------------------- | | **No access** | The area is not visible | | **View** | Read only | | **Add** | Create records in the area | | **Actions** | Act on records, including submissions and merchant state changes | Give support teams **View** on Disputes and nothing else: it covers every "where is my dispute" question without putting a submission button in front of someone who is not accountable for it. ## Next step [#next-step] With branding and access set, onboard the merchants. # Widgets (https://docs.chargeflow.io/docs/platforms/connect/widgets) Widgets put live dispute data inside your product, so a merchant sees their disputes where they already work instead of in a second tool. Widgets are in beta. Availability is set per platform by your Chargeflow account manager, and the catalog is still growing. See [Support](https://docs.chargeflow.io/docs/reference/support) to get access. ## What you get [#what-you-get] * **Widget catalog.** Pre-built components that display real-time dispute data: counts, statuses, deadlines, recovery performance. * **Dashboard builder.** Assemble your own view from those components rather than taking a fixed layout. Widgets read the same data as the [Disputes](https://docs.chargeflow.io/docs/platforms/connect/disputes) screen, scoped to the merchant viewing them. ## When to use a widget instead of the API [#when-to-use-a-widget-instead-of-the-api] | Use a widget | Use the API | | ------------------------------------------------------------ | -------------------------------------------------------------- | | You want dispute data visible in your product this sprint | You need the data inside your own components and design system | | The standard dispute views are close enough to what you need | You are building a workflow, not a display | | You would rather not maintain the rendering | You already have a dashboard framework | Both read the same engine, so starting with widgets and moving to the API later does not mean re-onboarding merchants. ## Next step [#next-step] API keys, HMAC, and the webhook endpoints the widget fires from. # Privacy & security (https://docs.chargeflow.io/docs/platforms/eaas/compliance) Chargeflow is designed to handle sensitive dispute data responsibly. This page describes the data handling practices that apply specifically to Evidence-as-a-Service. ## Short-lived download links [#short-lived-download-links] Evidence PDF download URLs expire **7 days** after they are issued. If you need to retrieve the PDF after the link has expired, call the evidence API to request a fresh download URL. Store the `evidence.id` (not the `file_url`) as your persistent reference to a generated evidence package. The `id` is permanent; the `file_url` is temporary. ## Data minimization [#data-minimization] You control what dispute data you send to the Generate Evidence API. The AI agent selects only the most impactful details to include in the evidence package; you do not need to curate the payload manually. Only data relevant to the specific dispute needs to be shared. Do not include unrelated merchant or customer data in the request body. ## Regional data residency [#regional-data-residency] Chargeflow supports regional storage options to meet data residency requirements. If your platform operates in a region with specific data localization requirements, contact your account manager to discuss available storage region configurations. ## Compliance certifications [#compliance-certifications] Chargeflow is SOC 2 Type II audited and GDPR-compliant. Certifications, reports, encryption standards, and data-handling policies live in [Security & compliance](https://docs.chargeflow.io/docs/reference/security) and the [Trust Center](https://trust.chargeflow.io/). ## Webhook notifications [#webhook-notifications] You are notified via webhook when PDFs are ready for download (`evidence.ready`) or when generation fails (`evidence.error`). This means your integration never needs to poll for status; Chargeflow pushes updates as soon as they are available. See [Webhook Events](../webhook-events) for payload details and how to verify webhook signatures. ## Next steps [#next-steps] Kick off evidence generation. Download the PDF when it is ready. The end-to-end EaaS flow. The EaaS overview. # Generate & regenerate evidence (https://docs.chargeflow.io/docs/platforms/eaas/generate-and-regenerate) Generating evidence is the core EaaS action: you hand Chargeflow a dispute - by `dispute_id` or inline - and it returns an AI-composed, versioned evidence package. This page covers the call, its error codes, and how to regenerate as new data arrives. ## Generate evidence [#generate-evidence] Use the Generate Evidence API to kick off AI-powered evidence creation for a dispute. ``` POST /public/2025-04-01/evidence ``` The endpoint accepts either an existing Chargeflow `dispute_id` **or** a full inline dispute object. You do not need to create the dispute separately first. ### Integration patterns [#integration-patterns] **Option A, reference an existing dispute:** ```bash title="Terminal" curl -X POST https://api.chargeflow.io/public/2025-04-01/evidence \ -H "x-api-key: YOUR_PLATFORM_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "account_id": "66e6ea9ecd94925a9f8060d9", "dispute": { "dispute_id": "66e6ea9ecd94925a9f8060d9" } }' ``` **Option B, submit dispute data inline:** ```bash title="Terminal" curl -X POST https://api.chargeflow.io/public/2025-04-01/evidence \ -H "x-api-key: YOUR_PLATFORM_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "account_id": "66e6ea9ecd94925a9f8060d9", "dispute": { "dispute_data": { "source_id": "du_123456789", "created_at": "2024-02-10T12:00:00Z", "reason": "fraud", "due_by": "2024-02-20T12:00:00Z", "amount": 150.00, "currency": "USD", "status": "needs_response", "transaction": { "source_id": "tx_1234567890", "created_at": "2024-02-08T10:00:00Z", "type": "paid", "amount": 150.00, "currency": "USD" } } } }' ``` ### Response [#response] The API responds immediately with an `in_progress` status. Evidence generation is asynchronous; the PDF is not included in the response. Listen for the `evidence.ready` or `evidence.error` webhooks to know when it completes. ```json title="Response" { "id": "ev_abc123456789", "account_id": "acct_9876543210", "ext_account_id": "ext_acct_54321", "dispute": "dp_1122334455", "created_at": "2025-07-29T14:35:00Z", "status": "in_progress", "file_url": null, "file_version": 1 } ``` Generation typically completes in \~30 seconds, with a maximum of \~3 minutes. ### Error codes [#error-codes] | Error Code | HTTP Status | Description | | ---------------------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------- | | `422_dispute_invalid_state` | 422 | Dispute must have status `needs_response` to generate evidence. | | `409_generation_in_progress` | 409 | Evidence generation is already in progress for this dispute. Do not retry - wait for the completion webhook (see warning below). | | `404_*_not_found` | 404 | The dispute was not found. Verify the `dispute_id` is correct and belongs to the given `account_id`. | | `403_eaas_not_enabled` | 403 | Your API key is not entitled to EaaS. Contact your account manager to enable it. | | `504_generation_timeout` | 504 | The generation operation timed out. Retry the request. | Do not retry on `409_generation_in_progress`. Wait for the `evidence.ready` or `evidence.error` webhook before taking further action. ## Regenerate evidence [#regenerate-evidence] Evidence can be regenerated at any time while the dispute remains in `needs_response` status. Each regeneration attempt increments `file_version`, giving you a full history of evidence revisions. ```bash title="Terminal" curl -X POST https://api.chargeflow.io/public/2025-04-01/evidence \ -H "x-api-key: YOUR_PLATFORM_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "account_id": "66e6ea9ecd94925a9f8060d9", "dispute": { "dispute_id": "66e6ea9ecd94925a9f8060d9" } }' ``` The response will show `file_version: 2` (or higher) once the new PDF is ready. **When to regenerate:** * New order data has become available (tracking, fulfillment, etc.) * The merchant has added communication logs or policy context * You received an `evidence.error` and have resolved the underlying issue More data equals stronger narratives. Missing pieces won't block generation; the AI agent prioritizes the most impactful evidence available. But richer context consistently produces more persuasive evidence packages. ## Report dispute outcomes [#report-dispute-outcomes] When disputes are resolved (won or lost), share the outcome with Chargeflow. This data helps the AI continuously refine dispute strategies and improve win rates across all merchants on your platform. Contact your account manager for the preferred method of submitting outcome data for your integration. ## Next steps [#next-steps] Download the PDF once generation completes. Diagnose and retry a failed generation. How download links and data residency work. Create the dispute you generate evidence for. # Generate evidence in seconds (https://docs.chargeflow.io/docs/platforms/eaas/generate-evidence-in-10s) Evidence-as-a-Service (EaaS) turns dispute data into a polished, bank-ready PDF evidence package in about 30 seconds (up to \~3 minutes). This recipe is a full, copy-paste-runnable flow: call the Generate Evidence API, wait for the `evidence.ready` webhook, then fetch the PDF link. EaaS is a platform-level integration. Platforms call it on behalf of their merchants. Merchants never call it directly. See [What is EaaS?](https://docs.chargeflow.io/docs/platforms/eaas/introduction). ## Before you start [#before-you-start] * EaaS must be enabled on your Connect account by your Chargeflow account manager. Without it, every EaaS call returns `403_eaas_not_enabled`. See [What is EaaS?](https://docs.chargeflow.io/docs/platforms/eaas/introduction). * Get your platform `API Access Key`. Every request sends it in the `x-api-key` header. See [Authentication](https://docs.chargeflow.io/docs/reference/api-fundamentals/authentication). * Subscribe to the `evidence.ready` and `evidence.error` webhooks in the Connect Developer Hub. See [How It Works](https://docs.chargeflow.io/docs/platforms/eaas/how-it-works). All requests go to `https://api.chargeflow.io` under the `/public/2025-04-01/` path. ## Steps [#steps] ### Call the Generate Evidence API [#call-the-generate-evidence-api] `POST /public/2025-04-01/evidence` accepts either an existing Chargeflow `dispute_id` or a full inline dispute object. You do not need to create the dispute separately first. Provide exactly one of the two. The dispute must be in `needs_response` status, otherwise the call returns `422_dispute_invalid_state`. **Option A: reference an existing dispute:** ```bash title="Terminal" curl -X POST https://api.chargeflow.io/public/2025-04-01/evidence \ -H "x-api-key: YOUR_PLATFORM_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "account_id": "66e6ea9ecd94925a9f8060d9", "dispute": { "dispute_id": "66e6ea9ecd94925a9f8060d9" } }' ``` ```javascript title="Node.js" const res = await fetch('https://api.chargeflow.io/public/2025-04-01/evidence', { method: 'POST', headers: { 'x-api-key': process.env.CHARGEFLOW_PLATFORM_API_KEY, 'Content-Type': 'application/json', }, body: JSON.stringify({ account_id: '66e6ea9ecd94925a9f8060d9', dispute: { dispute_id: '66e6ea9ecd94925a9f8060d9' }, }), }); const evidence = await res.json(); console.log(evidence.id, evidence.status); // ev_..., in_progress ``` ```python title="Python" import os, requests res = requests.post( "https://api.chargeflow.io/public/2025-04-01/evidence", headers={"x-api-key": os.environ["CHARGEFLOW_PLATFORM_API_KEY"]}, json={ "account_id": "66e6ea9ecd94925a9f8060d9", "dispute": {"dispute_id": "66e6ea9ecd94925a9f8060d9"}, }, ) data = res.json() ``` **Option B: submit the dispute data inline:** ```bash title="Terminal" curl -X POST https://api.chargeflow.io/public/2025-04-01/evidence \ -H "x-api-key: YOUR_PLATFORM_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "account_id": "66e6ea9ecd94925a9f8060d9", "dispute": { "dispute_data": { "source_id": "du_123456789", "created_at": "2024-02-10T12:00:00Z", "reason": "fraud", "due_by": "2024-02-20T12:00:00Z", "amount": 150.00, "currency": "USD", "status": "needs_response", "transaction": { "source_id": "tx_1234567890", "created_at": "2024-02-08T10:00:00Z", "type": "paid", "amount": 150.00, "currency": "USD" } } } }' ``` ```javascript title="Node.js" const res = await fetch('https://api.chargeflow.io/public/2025-04-01/evidence', { method: 'POST', headers: { 'x-api-key': process.env.CHARGEFLOW_PLATFORM_API_KEY, 'Content-Type': 'application/json', }, body: JSON.stringify({ account_id: '66e6ea9ecd94925a9f8060d9', dispute: { dispute_data: { source_id: 'du_123456789', created_at: '2024-02-10T12:00:00Z', reason: 'fraud', due_by: '2024-02-20T12:00:00Z', amount: 150.0, currency: 'USD', status: 'needs_response', transaction: { source_id: 'tx_1234567890', created_at: '2024-02-08T10:00:00Z', type: 'paid', amount: 150.0, currency: 'USD', }, }, }, }), }); const data = await res.json(); ``` ```python title="Python" import os, requests res = requests.post( "https://api.chargeflow.io/public/2025-04-01/evidence", headers={"x-api-key": os.environ["CHARGEFLOW_PLATFORM_API_KEY"]}, json={ "account_id": "66e6ea9ecd94925a9f8060d9", "dispute": { "dispute_data": { "source_id": "du_123456789", "created_at": "2024-02-10T12:00:00Z", "reason": "fraud", "due_by": "2024-02-20T12:00:00Z", "amount": 150.00, "currency": "USD", "status": "needs_response", "transaction": { "source_id": "tx_1234567890", "created_at": "2024-02-08T10:00:00Z", "type": "paid", "amount": 150.00, "currency": "USD", }, } }, }, ) data = res.json() ``` The API responds immediately with `in_progress`. Generation is asynchronous, so the PDF is not in this response. ```json title="Response" { "id": "ev_abc123456789", "account_id": "acct_9876543210", "ext_account_id": "ext_acct_54321", "dispute": "dp_1122334455", "created_at": "2025-07-29T14:35:00Z", "status": "in_progress", "file_url": null, "file_version": 1 } ``` Store the `id` as your persistent reference to this evidence package. The `id` is permanent; the `file_url` is temporary and expires 7 days after it is issued. See [Privacy & Security](https://docs.chargeflow.io/docs/platforms/eaas/compliance). ### Wait for the evidence.ready webhook [#wait-for-the-evidenceready-webhook] Do not poll in a tight loop. Chargeflow pushes the result to your webhook endpoint when the PDF is ready (`evidence.ready`) or if generation fails (`evidence.error`). Generation typically completes in about 30 seconds, with a maximum of around 3 minutes. `evidence.ready` payload: ```json title="Webhook payload" { "event": { "id": "evt_XXXXXXXXXXXXXXXX", "type": "evidence.ready", "created_at": "2025-07-29T12:34:56Z" }, "evidence": { "id": "ev_abc123456789", "account_id": "acct_9876543210", "ext_account_id": "ext_acct_54321", "dispute": "dp_1122334455", "created_at": "2025-07-29T14:35:00Z", "status": "completed", "file_url": "https://cdn.chargeflow.io/evidence/ev_abc123456789/v2/evidence.pdf", "file_version": 1 } } ``` Acknowledge with a `2XX` quickly, then download or store the PDF asynchronously. ```javascript title="Node.js" app.post('/webhook', express.json(), (req, res) => { const event = req.body; res.json({ received: true }); // acknowledge first if (event.event?.type === 'evidence.ready') { const { id, file_url } = event.evidence; // Download the PDF and submit it to your PSP saveEvidencePdf(id, file_url); } if (event.event?.type === 'evidence.error') { // event.error_code and event.error_message explain what failed console.error(event.error_code, event.error_message); } }); ``` The `evidence.error` payload includes `error_code` and `error_message`, for example `422_dispute_invalid_state` with `"Dispute status must be needs_response"`. See [How It Works](https://docs.chargeflow.io/docs/platforms/eaas/how-it-works) for both payload shapes. ### Fetch the latest evidence link [#fetch-the-latest-evidence-link] The download link expires 7 days after it is issued. If you need a fresh link later, read the evidence record by its `id` with `GET /public/2025-04-01/evidence/{evidenceId}`. ```bash title="Terminal" curl -X GET https://api.chargeflow.io/public/2025-04-01/evidence/ev_abc123456789 \ -H "x-api-key: YOUR_PLATFORM_API_KEY" ``` ```javascript title="Node.js" const res = await fetch('https://api.chargeflow.io/public/2025-04-01/evidence/ev_abc123456789', { headers: { 'x-api-key': process.env.CHARGEFLOW_PLATFORM_API_KEY }, }); const evidence = await res.json(); console.log(evidence.status, evidence.file_url, evidence.file_version); ``` ```python title="Python" import os, requests res = requests.get( "https://api.chargeflow.io/public/2025-04-01/evidence/ev_abc123456789", headers={"x-api-key": os.environ["CHARGEFLOW_PLATFORM_API_KEY"]}, ) data = res.json() ``` The response carries the current `status`, `file_url`, and `file_version`: ```json title="Response" { "id": "ev_abc123456789", "account_id": "acct_9876543210", "ext_account_id": "ext_acct_54321", "dispute": "dp_1122334455", "created_at": "2025-07-29T14:35:00Z", "status": "completed", "file_url": "https://cdn.chargeflow.io/evidence/ev_abc123456789/v2/evidence.pdf", "file_version": 1 } ``` ### Regenerate when new data arrives (optional) [#regenerate-when-new-data-arrives-optional] While the dispute is still in `needs_response`, you can regenerate the package to fold in new data such as tracking, fulfillment, or added communication logs. Call the same Generate Evidence endpoint again. Each regeneration increments `file_version`. ```bash title="Terminal" curl -X POST https://api.chargeflow.io/public/2025-04-01/evidence \ -H "x-api-key: YOUR_PLATFORM_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "account_id": "66e6ea9ecd94925a9f8060d9", "dispute": { "dispute_id": "66e6ea9ecd94925a9f8060d9" } }' ``` ```javascript title="Node.js" const res = await fetch('https://api.chargeflow.io/public/2025-04-01/evidence', { method: 'POST', headers: { 'x-api-key': process.env.CHARGEFLOW_PLATFORM_API_KEY, 'Content-Type': 'application/json', }, body: JSON.stringify({ account_id: '66e6ea9ecd94925a9f8060d9', dispute: { dispute_id: '66e6ea9ecd94925a9f8060d9' }, }), }); const data = await res.json(); ``` ```python title="Python" import os, requests res = requests.post( "https://api.chargeflow.io/public/2025-04-01/evidence", headers={"x-api-key": os.environ["CHARGEFLOW_PLATFORM_API_KEY"]}, json={ "account_id": "66e6ea9ecd94925a9f8060d9", "dispute": {"dispute_id": "66e6ea9ecd94925a9f8060d9"}, }, ) data = res.json() ``` If a call returns `409_generation_in_progress`, do not retry. Wait for the `evidence.ready` or `evidence.error` webhook before taking further action. ### Report the outcome [#report-the-outcome] When the dispute resolves (won or lost), share the outcome with Chargeflow so the AI keeps improving win rates across your merchants. There is no public endpoint for this yet. A public Report Outcome endpoint is not available yet. For now, contact your Chargeflow account manager for the preferred method of submitting outcome data for your integration. ## Next steps [#next-steps] The full API reference and error codes. Connect account setup and the evidence.ready / evidence.error payloads. Link expiry and data handling. # How it works (https://docs.chargeflow.io/docs/platforms/eaas/how-it-works) This page walks through the end-to-end setup for integrating Evidence-as-a-Service into your platform. ## Obtain a Chargeflow Connect account [#obtain-a-chargeflow-connect-account] Chargeflow invites your team to a dedicated Connect account. From there you can generate API keys, register webhooks, and make your first EaaS calls. A dedicated [sandbox](https://docs.chargeflow.io/docs/platforms/sandbox) is coming soon; until then, API keys act on your live account. Your account manager must enable EaaS on your Connect account before EaaS API calls will succeed. Without this entitlement, calls return `403_eaas_not_enabled`. ## Generate API keys and subscribe to webhooks [#generate-api-keys-and-subscribe-to-webhooks] After accepting your invitation, navigate to the **Developer Hub** inside the Connect UI and generate your API keys. Keys act on your live account - see [Test credentials](https://docs.chargeflow.io/docs/reference/api-fundamentals/test-credentials). Then subscribe to the two EaaS lifecycle webhooks: | Event | Trigger | Behavior | | ---------------- | ------------------------------------ | --------------------------------------------------------------------------------------------- | | `evidence.ready` | Evidence generation completed. | A versioned PDF is ready for review and submission to your PSP. | | `evidence.error` | An error occurred during generation. | Chargeflow retries automatically; on final failure, sends detailed error info in the payload. | Verify the signature on incoming webhook deliveries to confirm they originate from Chargeflow - see [Webhooks](https://docs.chargeflow.io/docs/reference/concepts/webhooks) for the verification flow. For the full payload shapes and field references, see [`evidence.ready`](../webhook-events#evidence-ready) and [`evidence.error`](../webhook-events#evidence-error). ## Create a merchant entity [#create-a-merchant-entity] For each merchant on your platform, create a corresponding Chargeflow account entity using the Accounts API. This tells Chargeflow who the merchant is so it can enrich their profile and tailor evidence strategies to their business. Required fields: `business_name`, `business_url`, `email`, `owner_name`. See [Onboard a Merchant](./onboard-a-merchant) for the full request example. ## Integration patterns [#integration-patterns] Once your merchants are set up, you can choose how to trigger evidence generation: ### Platform-managed automation [#platform-managed-automation] Disputes are detected by your platform (via PSP webhooks or polling). When a dispute arrives in `needs_response` state, your platform calls the Generate Evidence API automatically, with no merchant action required. This pattern provides the fastest response time and requires the least merchant involvement. ### Merchant self-serve [#merchant-self-serve] Your platform creates a dispute record in Chargeflow and surfaces an "Generate Evidence" action in your merchant portal. Merchants can review and enrich the dispute with additional context via the [Enrich a Dispute](https://docs.chargeflow.io/docs/merchants/automation/enrich-a-dispute) flow before triggering generation. The platform always calls the Generate Evidence API; merchants never call it directly. ## Next steps [#next-steps] API details, request/response examples, and error codes. How Chargeflow handles your data. # What is EaaS? (https://docs.chargeflow.io/docs/platforms/eaas/introduction) Evidence-as-a-Service (EaaS) transforms messy dispute data into a polished, bank-ready **PDF evidence package** in about **30 seconds** (up to \~3 minutes). Your platform provides the dispute details and supporting materials; Chargeflow's AI agent enriches, validates, and assembles a consistent evidence letter designed to refute the claim. Once ready, Chargeflow notifies you via webhook and provides a secure download link for the PDF. ## Who it's for [#who-its-for] **EaaS is designed for B2B platforms and PSPs, not individual merchants.** * **Platforms** integrate EaaS by exposing a "Generate Evidence" action in their merchant portal, or by triggering evidence generation automatically when disputes arrive. * **Merchants** do not integrate directly with EaaS. Merchants on your platform can manage disputes through Chargeflow by connecting their payment providers, but the EaaS API itself is a platform-level integration. ## Key capabilities [#key-capabilities] * **Works for all disputes:** any stage, any country, any language. * **Rich context support:** leverages dispute data, enrichments, and optional merchant context such as policies, checkout steps, and buyer verification details. * **Single versioned PDF:** outputs one document per dispute, ready for bank submission. * **Version control:** regenerate evidence as new data arrives; each regeneration increments `file_version`. * **Structured data access:** enriched dispute data is accessible via API alongside the PDF. ## Entitlement gating [#entitlement-gating] EaaS access is **enabled per platform by your Chargeflow account manager**. You cannot self-serve enable it. Without the EaaS entitlement, all EaaS API calls return a `403_eaas_not_enabled` error. Contact your account manager to get EaaS enabled on your Connect account before testing. Once enabled, you can generate API keys, subscribe to webhooks, and start testing immediately. ## Next steps [#next-steps] Step-by-step setup guide. API reference and integration patterns. Compliance and data handling. # Onboard a merchant (https://docs.chargeflow.io/docs/platforms/eaas/onboard-a-merchant) Before Chargeflow can generate evidence for a merchant, you need to create a Chargeflow account entity for them. This account serves as the anchor for all of that merchant's disputes, evidence, and integrations within your platform. ## Create a merchant account [#create-a-merchant-account] ``` POST /public/2025-04-01/accounts ``` ### Required fields [#required-fields] | Field | Type | Description | | --------------- | -------------- | -------------------------------------------------------------------------------------------------------- | | `owner_name` | string | The account owner's full name. Used in evidence narratives. | | `business_name` | string | The merchant's business name. Used in evidence narratives and enrichment. | | `business_url` | string (URI) | The public URL of the merchant's website. Chargeflow enriches this with metadata to strengthen evidence. | | `email` | string (email) | The merchant owner's email address for login and contact purposes. | ### Optional fields [#optional-fields] | Field | Type | Description | | ---------------- | ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `ext_account_id` | string | Your internal ID for this merchant. Store this to easily look up the Chargeflow account later without tracking two separate IDs. | | `status` | `active` \| `inactive` | Account status. Defaults to `active`. | | `enrichments` | object | Company-level context: industry, product types, payment models, policies, checkout flow, and buyer verification methods. More enrichment = stronger default evidence strategies. | ### Example request [#example-request] ```bash title="Terminal" curl -X POST https://api.chargeflow.io/public/2025-04-01/accounts \ -H "x-api-key: YOUR_PLATFORM_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "owner_name": "Jane Smith", "business_name": "Acme Store", "business_url": "https://acme.com", "email": "jane@acme.com", "ext_account_id": "your_internal_id_123" }' ``` ### Example response [#example-response] ```json title="Response" { "id": "66e6ea9ecd94925a9f8060d9", "ext_account_id": "your_internal_id_123", "created_at": "2025-01-15T09:00:00Z", "owner_name": "Jane Smith", "business_name": "Acme Store", "business_url": "https://acme.com", "email": "jane@acme.com", "status": "active", "enrichments": null } ``` Store the returned `id` (the Chargeflow `account_id`) in your database. You will need it to submit disputes, generate evidence, and make all subsequent API calls on behalf of this merchant. ## Enriching merchant profiles [#enriching-merchant-profiles] Providing the `enrichments` object at creation time (or updating it later) significantly improves Chargeflow's ability to tailor evidence strategies for the merchant's specific business model. ```bash title="Terminal" curl -X POST https://api.chargeflow.io/public/2025-04-01/accounts \ -H "x-api-key: YOUR_PLATFORM_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "owner_name": "Jane Smith", "business_name": "Acme Store", "business_url": "https://acme.com", "email": "jane@acme.com", "ext_account_id": "your_internal_id_123", "enrichments": { "industry": "retail", "product_types": ["physical_goods"], "payment_models": ["single_payment"], "company_description": "Acme Store sells outdoor equipment direct to consumers.", "support_email": "support@acme.com", "policies": { "refund_url": "https://acme.com/refund-policy", "shipping_url": "https://acme.com/shipping-policy", "return_url": "https://acme.com/returns" } } }' ``` ## Retrieve an account [#get-account-by-id] Fetch a single merchant account by its Chargeflow ID, to confirm what you stored or read back the current `enrichments`. ``` GET /public/2025-04-01/accounts/{accountId} ``` | Parameter | Description | | ----------- | ---------------------------------------------------------- | | `accountId` | The Chargeflow account ID (`id` from the create response). | ```bash title="Terminal" curl "https://api.chargeflow.io/public/2025-04-01/accounts/66e6ea9ecd94925a9f8060d9" \ -H "x-api-key: YOUR_PLATFORM_API_KEY" ``` The response is the same account object returned by the create call above. A `404` means the `accountId` does not exist under your platform key; a `403` means the key itself is invalid or revoked (see [Monitor integration health](https://docs.chargeflow.io/docs/platforms/monitor-integration-health)). ## Next step [#next-step] Create the dispute records this account will anchor. # Set up EaaS (https://docs.chargeflow.io/docs/platforms/eaas/setup) Evidence-as-a-Service generates dispute evidence over the API for platforms that want to load dispute data programmatically instead of connecting a PSP. This page is the setup, step for step, in the same order as the in-app guide in Connect. EaaS merchants do not need a processor connection. Your platform loads the dispute data; optionally connect merchant tools to enrich it. EaaS must be enabled on your Connect account by your Chargeflow account manager. Without it, every EaaS call returns `403_eaas_not_enabled`. See [What is EaaS?](https://docs.chargeflow.io/docs/platforms/eaas/introduction). ## API keys and webhooks [#api-keys-and-webhooks] Generate production and sandbox keys in **Settings → Developers**, and optionally enforce HMAC signature validation. Register a webhook endpoint for `evidence.ready` and `evidence.error` while you are there. See [Developers](https://docs.chargeflow.io/docs/platforms/connect/developers). ## Add merchants [#add-merchants] Add merchant accounts. No PSP connection is required for an EaaS merchant. ```bash title="Terminal" curl -X POST https://api.chargeflow.io/public/2025-04-01/accounts \ -H "x-api-key: YOUR_PLATFORM_API_KEY" \ -H "Content-Type: application/json" \ -d '{"name": "Merchant name", "email": "ops@merchant.example"}' ``` Keep the returned `account_id`: every dispute you load references it. See the [Accounts API](https://docs.chargeflow.io/docs/api/2025-04-01/platforms/accounts). ## Load dispute data [#load-dispute-data] Push disputes in over the API. This replaces the processor connection: whatever your platform knows about the dispute is what the engine works from. See [Create dispute](https://docs.chargeflow.io/docs/api/2025-04-01/platforms/merchants-disputes) and [Submit platform disputes](https://docs.chargeflow.io/docs/platforms/eaas/submit-platform-disputes). ## Auto-enrich with integrations [#auto-enrich-with-integrations] Optionally connect merchant tools such as Chargebee or Gorgias so evidence is enriched automatically with subscription history and customer conversations. This is the single highest-leverage optional step: the data it adds is what wins item-not-received and not-as-described cases. See [Integrations](https://docs.chargeflow.io/docs/platforms/connect/integrations). ## Generate evidence [#generate-evidence] The engine produces the evidence package for the dispute. ```bash title="Terminal" curl -X POST https://api.chargeflow.io/public/2025-04-01/evidence \ -H "x-api-key: YOUR_PLATFORM_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "account_id": "ACCOUNT_ID", "dispute": { "dispute_id": "DISPUTE_ID" } }' ``` Generation is asynchronous. Wait for `evidence.ready` rather than polling. See [Generate evidence in seconds](https://docs.chargeflow.io/docs/platforms/eaas/generate-evidence-in-10s). ## Retrieve the evidence [#retrieve-the-evidence] Pull the generated package, including the PDF, once the webhook says it is ready. See [Get evidence by ID](https://docs.chargeflow.io/docs/api/2025-04-01/platforms/evidence) and [Generate and regenerate](https://docs.chargeflow.io/docs/platforms/eaas/generate-and-regenerate). ## Submit and mark it submitted [#submit-and-mark-it-submitted] Submit to the issuing bank through your own process, then tell Chargeflow you have done so. That is what puts the dispute on the deadline tracking you see in [Disputes](https://docs.chargeflow.io/docs/platforms/connect/disputes). ## Report the outcome [#report-the-outcome] Report won or lost. This is not bookkeeping: outcome data trains the engine for the next dispute of that type, and it powers win-rate and money-recovered reporting for the merchant. ## Also available [#also-available] | Surface | What it gives you | | --------------------- | ---------------------------------------------------------------------------- | | **Evidence activity** | The full lifecycle of every evidence request as a table | | **System health** | API usage and webhook delivery, so a silent integration is visible | | **Evidence language** | A default language for the account, overridable per merchant and per request | ## Next step [#next-step] Run steps 1, 5, and 6 end to end against a real dispute. # Submit platform disputes (https://docs.chargeflow.io/docs/platforms/eaas/submit-platform-disputes) Use this endpoint to create dispute records in Chargeflow directly from your platform. This is useful when Chargeflow is not automatically ingesting disputes from a connected PSP, for example when your platform is the authoritative source of dispute data, or when you're operating in a bring-your-own-disputes model. ## Create a dispute [#create-a-dispute] ``` POST /public/2025-04-01/platform/disputes ``` ### Request fields [#request-fields] | Field | Type | Required | Description | | -------------- | ----------------- | -------- | ----------------------------------------------------------------------------------------------------------- | | `account_id` | string | Yes | The Chargeflow account ID of the merchant this dispute belongs to. | | `source_id` | string | Yes | Your PSP's dispute ID, the unique identifier from the processor where the dispute originated. | | `created_at` | ISO 8601 datetime | Yes | When the dispute was created at the processor. | | `reason` | enum | Yes | The dispute reason code. See below for valid values. | | `due_by` | ISO 8601 datetime | Yes | The evidence submission deadline. | | `amount` | number | Yes | Disputed amount in the transaction currency. Must be ≤ the transaction amount. | | `currency` | string | Yes | Three-letter ISO 4217 currency code in uppercase (e.g., `USD`). | | `status` | enum | Yes | Current dispute status. Must be `needs_response`, `under_review`, `won`, or `lost`. | | `stage` | enum | No | Dispute stage. One of: `Chargeback`, `Inquiry`, `Pre_arbitration`, `Arbitration`. Defaults to `Chargeback`. | | `transaction` | object | No | Transaction details. Recommended for stronger evidence. See below. | | `subscription` | object | No | Subscription details, if the disputed charge is subscription-related. | | `order` | object | No | Order details including products, customer, shipping address, and fulfillment tracking. | ### Dispute reason values [#dispute-reason-values] | Value | Description | | ---------------------------- | ------------------------------------------------------------------- | | `fraud` | Unauthorized transaction claim. | | `not_received` | Customer claims goods or services were not received. | | `not_as_described` | Customer claims goods or services differed from what was promised. | | `canceled_recurring_billing` | Customer claims a recurring charge continued after cancellation. | | `duplicate_charge` | Customer claims they were charged more than once for the same item. | | `credit_not_processed` | Customer claims a refund was not applied. | | `other` | Any reason not covered by the above. | ### Example request [#example-request] ```bash title="Terminal" curl -X POST https://api.chargeflow.io/public/2025-04-01/platform/disputes \ -H "x-api-key: YOUR_PLATFORM_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "account_id": "66e6ea9ecd94925a9f8060d9", "source_id": "du_123456789", "created_at": "2025-04-15T08:30:00Z", "reason": "fraud", "due_by": "2025-04-29T23:59:00Z", "amount": 249.99, "currency": "USD", "status": "needs_response", "stage": "Chargeback", "transaction": { "source_id": "tx_1234567890", "account_id": "66e6ea9ecd94925a9f8060d9", "created_at": "2025-04-10T14:22:00Z", "type": "paid", "amount": 249.99, "currency": "USD", "payment_method": { "type": "card", "brand": "visa", "last4": "4242", "country": "US" } } }' ``` ```javascript title="Node.js" const res = await fetch('https://api.chargeflow.io/public/2025-04-01/platform/disputes', { method: 'POST', headers: { 'x-api-key': process.env.CHARGEFLOW_PLATFORM_API_KEY, 'Content-Type': 'application/json', }, body: JSON.stringify({ account_id: '66e6ea9ecd94925a9f8060d9', source_id: 'du_123456789', created_at: '2025-04-15T08:30:00Z', reason: 'fraud', due_by: '2025-04-29T23:59:00Z', amount: 249.99, currency: 'USD', status: 'needs_response', stage: 'Chargeback', transaction: { source_id: 'tx_1234567890', account_id: '66e6ea9ecd94925a9f8060d9', created_at: '2025-04-10T14:22:00Z', type: 'paid', amount: 249.99, currency: 'USD', payment_method: { type: 'card', brand: 'visa', last4: '4242', country: 'US', }, }, }), }); const data = await res.json(); ``` ```python title="Python" import os, requests res = requests.post( "https://api.chargeflow.io/public/2025-04-01/platform/disputes", headers={"x-api-key": os.environ["CHARGEFLOW_PLATFORM_API_KEY"]}, json={ "account_id": "66e6ea9ecd94925a9f8060d9", "source_id": "du_123456789", "created_at": "2025-04-15T08:30:00Z", "reason": "fraud", "due_by": "2025-04-29T23:59:00Z", "amount": 249.99, "currency": "USD", "status": "needs_response", "stage": "Chargeback", "transaction": { "source_id": "tx_1234567890", "account_id": "66e6ea9ecd94925a9f8060d9", "created_at": "2025-04-10T14:22:00Z", "type": "paid", "amount": 249.99, "currency": "USD", "payment_method": { "type": "card", "brand": "visa", "last4": "4242", "country": "US", }, }, }, ) data = res.json() ``` Always include `transaction` data when available. Card verification results (3DS, AVS, CVC) are among the most impactful fields for fraud disputes. ## After creating the dispute [#after-creating-the-dispute] Once the dispute record exists in Chargeflow you can: * **Generate evidence** via the [EaaS Generate Evidence API](./generate-and-regenerate), referencing the returned dispute ID. * **Enrich the dispute** with additional order or communication context before generating evidence. ## Next steps [#next-steps] Turn the dispute into a bank-ready PDF. Confirm your platform key stays valid. # Integration guide (https://docs.chargeflow.io/docs/platforms/chargeflow-embedded/integration-guide) White-Label (previously "Chargeflow Embedded") is currently in **beta**. Capabilities and APIs may change. This guide walks you through the full setup process for integrating [White-Label](./overview) Connect into your platform. ## Platform setup [#platform-setup] Complete these three steps before building your merchant-facing integration. ### Platform account creation [#platform-account-creation] Chargeflow creates your platform account. Provide your platform email address to your Chargeflow account manager to get started. Once created, your team will receive an invitation to the Chargeflow Connect UI. ### Generate API keys [#generate-api-keys] Log in to your Chargeflow Connect account and navigate to the **Developer Hub** and generate your API credentials. Keys act on your live account - see [Test credentials](https://docs.chargeflow.io/docs/reference/api-fundamentals/test-credentials). Your API key is passed as the `x-api-key` header on all API requests. Optionally, enable HMAC Signature Validation for an additional layer of request authenticity. See the [Authentication guide](https://docs.chargeflow.io/docs/reference/api-fundamentals/authentication) for instructions. ### Register webhooks [#register-webhooks] Subscribe to the dispute lifecycle webhooks to receive real-time notifications: | Event | Description | | ----------------- | ------------------------------------------------------------------------ | | `dispute.created` | Fires when a new dispute is ingested and initial enrichment is complete. | You can subscribe to additional events as your integration matures. *** ## Building your integration [#building-your-integration] Once your platform account is configured, follow these steps to build the merchant-facing integration. ### Initialize integrations [#initialize-integrations] Use the Integrations API to connect each merchant's data sources to Chargeflow. Chargeflow uses these connections to automatically fetch and enrich dispute data. **Required:** PSP (payment service provider). Chargeflow cannot ingest disputes without a PSP connection. **Recommended:** eCommerce platform or other data enrichment sources (order management systems, CRM, shipping providers). Each additional source enriches the evidence package and improves win rates. ```bash title="Terminal" POST https://api.chargeflow.io/public/2025-04-01/integrations ``` The supported providers and their required credential fields are not yet in the published OpenAPI spec. Ask your Chargeflow representative for the current list. ### Handle new disputes [#handle-new-disputes] Listen for the `dispute.created` webhook. This event fires when Chargeflow has ingested a new dispute from the merchant's PSP and completed the initial enrichment pass. Deliveries arrive wrapped in the standard webhook envelope, with the dispute resource under `data`: ```json title="Response" { "webhookId": "wh_abc123", "creationDate": "2025-01-27T10:00:00Z", "type": "dispute.created", "data": { "...": "the dispute resource" } } ``` The full payload schema lives in the API reference: [`dispute.created`](https://docs.chargeflow.io/docs/api/2025-04-01/platforms/webhooks-events/dispute.created). Your webhook handler should record the dispute and trigger any downstream notifications to the merchant if required by your product. ### Enrich dispute data (recommended) [#enrich-dispute-data-recommended] Use the **Update Dispute API** to enrich disputes with additional order or communication data before Chargeflow finalizes the evidence package. The richer the context, the more compelling the evidence. ```bash title="Terminal" PATCH https://api.chargeflow.io/public/2025-04-01/disputes/{disputeId} ``` See the [Enrich Dispute API reference](https://docs.chargeflow.io/docs/api/2025-04-01/merchants/disputes) for the full list of enrichable fields. Even partial enrichment helps. If you have order data but not subscription data, send what you have. Missing pieces won't block evidence generation; the AI prioritizes whatever impactful data is available. ### Track dispute progress [#track-dispute-progress] Use the `dispute.created` webhook to stay informed as disputes are ingested for your merchants. Use these events to: * Surface dispute status in your merchant portal * Trigger notifications to merchants when Chargeflow takes action * Record outcomes for reporting and analytics *** ## Next steps [#next-steps] Create merchant accounts via API. Full event reference. Verify connectivity before going live. # What is White-Label? (https://docs.chargeflow.io/docs/platforms/chargeflow-embedded/overview) White-Label (previously documented as "Chargeflow Embedded", Connect Path B) is currently in **beta**. Capabilities and APIs may change; talk to your account manager about availability. White-Label is the [Connect](https://docs.chargeflow.io/docs/platforms/overview) delivery model where disputes become your own product line. Instead of building and maintaining dispute tooling, you delegate the process to Chargeflow, which connects directly to your merchants' PSPs and data sources, enriches disputes automatically, builds evidence packages, and submits them on the merchants' behalf. Everything carries your product name, your UI and your pricing. Merchants get a seamless experience without knowing Chargeflow powers it - and it runs on the same Public API documented across these docs. ## What Chargeflow does automatically [#what-chargeflow-does-automatically] Once a merchant's integrations are configured, Chargeflow: 1. **Fetches dispute data:** connects to the merchant's PSP and pulls dispute details as they arrive. 2. **Enriches with context:** augments disputes with transaction data, order information, subscription history, customer communication, and more. 3. **Analyzes for strategy:** determines the optimal evidence approach based on dispute reason, industry, and historical win patterns. 4. **Builds evidence packages:** produces a compelling, data-driven evidence PDF tailored to the specific dispute. 5. **Submits to the bank:** handles submission on behalf of the merchant within the response deadline. Steps 4 and 5 run on auto-pilot by default. If your merchants need to approve evidence before it reaches the bank, ask your account manager to configure co-pilot mode for that segment - see [Choose your level of autonomy](https://docs.chargeflow.io/docs/platforms/overview#choose-your-level-of-autonomy). ## Security [#security] White-Label requires your merchants to share PSP and data source credentials with Chargeflow. Credentials are encrypted in transit and at rest and covered by role-based access control with audit logging. Certifications, encryption standards, and data-handling policies are documented in [Security & compliance](https://docs.chargeflow.io/docs/reference/security). ## When to use White-Label vs EaaS [#when-to-use-white-label-vs-eaas] | | White-Label | Evidence-as-a-Service | | ----------------------- | ------------------------------------------------------- | ----------------------------------------------------------------- | | **Dispute ingestion** | Chargeflow pulls from PSP automatically | Platform provides dispute data via API | | **Evidence generation** | Fully automatic | Triggered by platform API call | | **Submission** | Chargeflow handles submission | Platform downloads PDF and submits | | **Integration effort** | Lower ongoing maintenance | More platform control | | **Best for** | Full-service offering with minimal engineering overhead | Platforms and ISVs that want control over the submission workflow | Choose White-Label if you want Chargeflow to handle the entire dispute process end to end, including connecting to merchant PSPs and data sources. Choose [Evidence-as-a-Service](../eaas/introduction) if your platform already handles dispute ingestion and submission, and you want to augment just the evidence drafting step with AI. If you want your brand on Chargeflow's own interface instead of building a UI, see [Co-Branded](https://docs.chargeflow.io/docs/platforms/overview#co-branded). ## Next steps [#next-steps] How to set up your platform and start onboarding merchants. # Authentication (https://docs.chargeflow.io/docs/reference/api-fundamentals/authentication) Chargeflow provides a REST API that enables you to programmatically view and update data in your Chargeflow account, and receive event notifications via [Webhooks](../concepts/webhooks). All endpoints require authentication unless explicitly stated otherwise. ## Overview [#overview] Chargeflow uses API key authentication. Every request must include your `x-api-key` header. Optionally, you can enable HMAC signature validation to add a second layer of security that guarantees both the integrity and authenticity of your requests. **Required credentials:** * `API Access Key`: included in the `x-api-key` header on every request. * `API Secret Key`: only needed if HMAC signature validation is enabled. Generate your keys in the Chargeflow App under **Settings → Developers → Generate Keys** - see [API keys](./test-credentials) for the full walkthrough and how to use them. Any active Chargeflow account can generate a key: there is no plan requirement and no approval step. ### Where the key belongs [#where-the-key-belongs] One key pair covers both directions of the integration. The Access Key authenticates the REST calls you make, and generating it is also what unlocks webhook registration, where the Secret Key is used to sign the deliveries Chargeflow sends you (see [Webhooks](../concepts/webhooks)). So the key is not "just for webhooks". Use it wherever your own code or automation calls Chargeflow: your backend, a [Zapier](https://docs.chargeflow.io/docs/merchants/automation/zapier-no-code) connection, or your CRM's outbound HTTP step. It is not entered in your payment processor's portal, and it must never appear in client-side code. A body of `{"message": "Missing API Key header x-api-key"}` means the header did not arrive: check the exact spelling and that no proxy strips it. A `403` on **every** endpoint, health check included, points at the request rather than the account (there is no "enable API access" toggle): the signing string below must match `METHOD\nPATH\nBODY` byte for byte. Full triage in [Error handling](./error-handling). ## HMAC signature validation (optional) [#hmac-signature-validation-optional] By default, HMAC signature verification is disabled on newly generated access keys. In this mode, the API key alone authenticates your requests, making it easy to integrate in your codebase or in tools like Zapier or Make. If you prefer an additional layer of security, ensuring data integrity (no tampering) and authenticity (requests come from you), you can enable **HMAC Signature Validation** in the Developers section of your Chargeflow settings. Once enabled, Chargeflow's servers will always verify the HMAC signature of your incoming requests. HMAC (Hash-based Message Authentication Code) is a mechanism that produces a cryptographic signature from your request data and a shared secret key. The server independently computes the same signature and rejects any request where the signatures don't match. This prevents both forgery and tampering. In addition to the `x-api-key` header, you include the generated signature in the `x-chargeflow-hmac-sha256` header. **Signing string format:** The string to sign is composed as: ``` METHOD\nPATH\nBODY ``` Where: * `METHOD` is the HTTP method in uppercase (e.g., `POST`) * `PATH` is the request path (e.g., `/public/2025-04-01/disputes/dispute-id/subscription`) * `BODY` is the raw request body string (empty string `""` for requests with no body) Along with the request body, you send headers containing your **API key** and the HMAC signature generated from your request data and secret key. The Chargeflow server receives the request and validates the **API key**. The server retrieves your **Secret Key** from its database and independently generates a verification signature using HMAC-SHA256. If both signatures match, the request is authenticated. ## Code examples [#code-examples] ```typescript title="Node.js" const crypto = require('crypto'); // Function to generate HMAC-SHA256 signature function generateHmacSignature(data, secretKey) { const hmac = crypto.createHmac('sha256', secretKey); hmac.update(data); return hmac.digest('hex'); } function calculateHmac(method, path, body, secretKey) { // Example request data const requestData = { method: method.toUpperCase(), path, body, }; // Compose string to sign from request data const dataToSign = `${requestData.method}\n${requestData.path}\n${requestData.body}`; // Generate HMAC signature const hmacSignature = generateHmacSignature(dataToSign, secretKey); return hmacSignature; } // Example request data const method = 'POST'; const path = '/public/2025-04-01/disputes/dispute-id/subscription'; // # Example request body. Work with the same string when sending to ensure that body is sent exactly as signed. const body = JSON.stringify({ param: 'value' }); // Calculate HMAC signature const secretKey = 'your-secret-key'; const hmacSignature = calculateHmac(method, path, body, secretKey); console.log('Generated HMAC-SHA256 Signature:', hmacSignature); // You can now use the generated signature as the 'x-chargeflow-hmac-sha256' header value ``` ```python title="Python" import hashlib import hmac import json # Function to generate HMAC-SHA256 signature def generate_hmac_signature(data, secret_key): signature = hmac.new( bytes(secret_key, 'utf-8'), msg = bytes(data, 'utf-8'), digestmod = hashlib.sha256).hexdigest() return signature def calculate_hmac(method, path, body, secret_key): # Example request data request_data = { 'method': method.upper(), 'path': path, 'body': body, } # Compose string to sign from request data data_to_sign = f"{request_data['method']}\n{request_data['path']}\n{request_data['body']}" # Generate HMAC signature hmac_signature = generate_hmac_signature(data_to_sign, secret_key) return hmac_signature # Example request data method = 'POST' path = '/public/2025-04-01/disputes/dispute-id/subscription' # Example request body. Work with the same string when sending to ensure that body is sent exactly as signed. body = json.dumps({'param': 'value'}) # Calculate HMAC signature secret_key = 'your-secret-key' hmac_signature = calculate_hmac(method, path, body, secret_key) print('Generated HMAC-SHA256 Signature:', hmac_signature) # You can now use the generated signature as the 'x-chargeflow-hmac-sha256' header value ``` When sending `multipart/form-data` requests with files (such as for the Evidence Upload API), the body used for signing is a sorted list of `key=value` pairs joined with `;`. Each value is an MD5 hash of the content: file values are first converted to Base64 before hashing. ```javascript title="Node.js" // Compatible with Node.JS 18+ const crypto = require('crypto'); const fs = require('fs'); const { blob } = require('stream/consumers'); // Function to generate HMAC-SHA256 signature function generateHmacSignature(data, secretKey) { const hmac = crypto.createHmac('sha256', secretKey); hmac.update(data); return hmac.digest('hex'); } // Function to create MD5 hash of a FormData part async function createPartHash(part) { const isFile = part instanceof File; const partString = isFile ? await fileToBase64(part) : part; return getMd5(partString); } function getMd5(contents) { return crypto.createHash('md5').update(contents).digest('hex'); } async function fileToBase64(file) { return Buffer.from(await file.arrayBuffer()).toString('base64'); } // Function to normalize FormData into a signing string async function formDataToSignString(formData) { const formDataEntries = Array.from(formData); const hashedParts = []; for (const [key, value] of formDataEntries) { const partHash = await createPartHash(value); hashedParts.push(`${key}=${partHash}`); } return hashedParts.sort().join(';'); } // Function to calculate HMAC signature async function calculateHmacForFormData(method, path, formData, secretKey) { const body = await formDataToSignString(formData); const requestData = { method: method.toUpperCase(), path, body, }; // Compose string to sign from request data const dataToSign = `${requestData.method}\n${requestData.path}\n${requestData.body}`; // Generate HMAC signature const hmacSignature = generateHmacSignature(dataToSign, secretKey); return hmacSignature; } async function signRequest() { // Example request data const method = 'POST'; const path = '/public/2025-04-01/disputes/dispute-id/evidence'; // Prepare FormData, same as when sending a multipart/form-data request const formData = new FormData(); formData.append('description', 'File description'); formData.append('file', await blob(fs.createReadStream('./foo/bar.jpg')), 'bar.jpg'); // Calculate HMAC signature const secretKey = 'your-secret-key'; const hmacSignature = await calculateHmacForFormData(method, path, formData, secretKey); console.log('Generated HMAC-SHA256 Signature:', hmacSignature); // You can now use the generated signature as the 'x-chargeflow-hmac-sha256' header value } signRequest(); ``` ## Next steps [#next-steps] Make your first authenticated request. Retry requests safely without creating duplicates. Resolve 401 and 403 responses. Verify the HMAC signature on incoming webhook events. # Error Handling (https://docs.chargeflow.io/docs/reference/api-fundamentals/error-handling) This page explains the HTTP error codes returned by the Chargeflow API, which of them are safe to retry, and how to retry correctly. ## Retry safety at a glance [#retry-safety-at-a-glance] | Status | Cause | Remedy | Retry-safe? | | ------ | ---------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | ----------------------- | | `400` | Malformed JSON, wrong types, missing fields | Fix the request body/params | No - fix first | | `401` | Missing/invalid `x-api-key`, bad HMAC signature | Fix credentials | No - fix first | | `403` | Malformed signature/headers, key lacks permission for the resource, or key invalid | Diagnose via health check (below) | No - fix first | | `404` | Wrong URL or ID, or resource deleted | Verify the URL and ID | No - fix first | | `429` | Rate limit exceeded | Back off and retry; honor `Retry-After` if present | **Yes** - after waiting | | `500` | Unexpected server error | Retry with backoff; contact support with `requestId` if persistent | **Yes** - with backoff | | `502` | Temporary gateway/upstream issue | Retry with backoff; check the [status page](https://status.chargeflow.io) | **Yes** - with backoff | GET requests are always safe to repeat. Before retrying a write (POST) request, check whether it succeeded; full idempotency semantics are not published yet - see [Idempotency](https://docs.chargeflow.io/docs/reference/api-fundamentals/idempotency) for status. ## Request IDs [#request-ids] Every API response includes a `requestId` field with a unique identifier for that request. Include this `requestId` when contacting Chargeflow support; it allows the team to locate and diagnose your request quickly. ## HTTP error codes [#http-error-codes] The server cannot process your request due to a client-side error. This is typically caused by malformed JSON, incorrect parameter types, or missing required fields. **What to do:** Review your request body and query parameters for syntax errors or missing data. Your request requires authentication but the credentials could not be validated. This occurs when the `x-api-key` header is missing, the key is invalid, or the HMAC signature (if enabled) is incorrect. A body of `{"message": "Missing API Key header x-api-key"}` means the header never arrived. Nothing has changed on your account: check that the header is spelled exactly `x-api-key`, that your HTTP client or proxy is not stripping it, and that it carries the API **Access** Key, not the Secret Key. **What to do:** Verify your API key and, if HMAC is enabled, ensure your signature is being computed correctly. See [Authentication](./authentication) for full details. The server understood your request but refuses to authorize it. This typically means either insufficient permissions for the requested resource, or an invalid API key. A `403` is not a sign that API access has to be switched on for your account: there is no such toggle. If **every** endpoint returns `403`, including the health check, treat it as a malformed request rather than an account problem. The usual cause is an HMAC signature or header that does not match the required format exactly, so re-check the `METHOD\nPATH\nBODY` signing string (raw body, byte for byte, path including the version prefix) against [Authentication](./authentication). If the response body is exactly: ```json title="Response" { "message": "Forbidden" } ``` your API key is either invalid or lacks permission for this resource. To tell which: Call the health check endpoint: `GET /public/2025-04-01/health-check`. A `200` response means the key itself is valid, so the `403` is a permissions issue: contact your account manager to confirm the key is entitled to this resource. A non-`200` response means the key is invalid. If the key is invalid, log in to the Chargeflow app, navigate to **Settings → Developers**, click **Revoke**, then **Generate Keys** to create a new key pair. Read access to the Alerts and Disputes endpoints is enabled per account and is not granted automatically when webhook delivery already works. If the health check returns `200` but `GET /alerts` or `GET /disputes` returns `403`, ask [Support](https://docs.chargeflow.io/docs/reference/support) to enable read access on your account. The server could not find the resource at the requested URL. This can be caused by a misspelled URL, a deleted resource, or an incorrect ID. **What to do:** Verify the URL is correct and that the resource exists in your account. You have exceeded the API rate limit by sending too many requests in a short period. **What to do:** Implement exponential backoff and retry logic. Reduce the frequency of requests where possible. If the response carries a `Retry-After` header, it indicates how many seconds to wait before retrying; otherwise use exponential backoff. See [Rate Limits](./rate-limits) for more information. The server encountered an unexpected error and could not fulfill your request. This may be caused by a programming error, configuration issue, resource exhaustion, or database problem on Chargeflow's side. **What to do:** Retry the request after a short delay. If the error persists, contact Chargeflow support with your `requestId`. A server acting as a gateway or proxy received an invalid response from an upstream server. This typically indicates a temporary infrastructure issue such as a network timeout or upstream service failure. **What to do:** Retry the request. If the error persists, check the [Chargeflow status page](https://status.chargeflow.io) or contact support. ## Retry with backoff [#retry-with-backoff] Paste-ready retry helpers for the retry-safe statuses (`429`, `500`, `502`). Both honor `Retry-After` when present and fall back to exponential backoff with jitter. ```typescript title="retry.ts" const RETRYABLE = new Set([429, 500, 502]); async function fetchWithRetry(url: string, init: RequestInit = {}, maxAttempts = 5) { for (let attempt = 1; ; attempt++) { const res = await fetch(url, init); if (!RETRYABLE.has(res.status) || attempt === maxAttempts) return res; const retryAfter = Number(res.headers.get('retry-after')); const backoff = 2 ** attempt * 500 + Math.random() * 500; // exponential + jitter const waitMs = retryAfter > 0 ? retryAfter * 1000 : backoff; await new Promise((r) => setTimeout(r, waitMs)); } } ``` ```python title="retry.py" import random, time, requests RETRYABLE = {429, 500, 502} def request_with_retry(method, url, max_attempts=5, **kwargs): for attempt in range(1, max_attempts + 1): res = requests.request(method, url, **kwargs) if res.status_code not in RETRYABLE or attempt == max_attempts: return res retry_after = res.headers.get("Retry-After") backoff = 2 ** attempt * 0.5 + random.random() * 0.5 # exponential + jitter time.sleep(float(retry_after) if retry_after else backoff) ``` ## Health check endpoint [#health-check-endpoint] Use the health check endpoint to verify connectivity and confirm your API key is valid at any time: ```bash title="Terminal" curl -X GET https://api.chargeflow.io/public/2025-04-01/health-check \ -H "x-api-key: YOUR_API_KEY" ``` A `200` response with `{"status": "ok"}` confirms your key is valid and the API is reachable. ## Next steps [#next-steps] A quick lookup table for every status code. Back off correctly when you hit a 429. Fix 401 and 403 responses. What to include when you contact the team. # Go-live checklist (https://docs.chargeflow.io/docs/reference/api-fundamentals/go-live-checklist) Run through this checklist before you point your integration at production traffic. Each item links to the page where the topic is documented in full. ## Checklist [#checklist] ### Store your API keys securely [#store-your-api-keys-securely] Keep your API Access Key and API Secret Key out of source control and client-side code. Load them from environment variables or a secrets manager, and rotate them if they are ever exposed. The secret key is shown only once when generated. See [Authentication](https://docs.chargeflow.io/docs/reference/api-fundamentals/authentication). ### Switch from test to live keys [#switch-from-test-to-live-keys] Generate your production keys in the Chargeflow app under **Settings → Developers** and make sure your production deployment uses those keys, not any keys used during development. Confirm you are calling the production base URL `https://api.chargeflow.io`. See [Authentication](https://docs.chargeflow.io/docs/reference/api-fundamentals/authentication). ### Handle PII responsibly [#handle-pii-responsibly] Dispute and customer data can include personally identifiable information. Limit who and what systems can read it, avoid logging full payloads, and retain only what you need. Send the exact request body you signed when using HMAC, so you do not reshape sensitive data in transit. See [Authentication](https://docs.chargeflow.io/docs/reference/api-fundamentals/authentication). ### Verify webhook signatures [#verify-webhook-signatures] In production, verify the HMAC signature on every incoming webhook before acting on it. Recompute the signature from the request method, path, and body using your secret key and compare it to the `X-Chargeflow-Hmac-Sha256` header. Reject requests that do not match. See [Webhooks](https://docs.chargeflow.io/docs/reference/concepts/webhooks). ### Use idempotency for retries [#use-idempotency-for-retries] When retrying requests that create or generate resources, send an idempotency key so a retry does not produce a duplicate. The `Idempotency-Key` header can be used on evidence generation requests. See [Idempotency](https://docs.chargeflow.io/docs/reference/api-fundamentals/idempotency). ### Handle errors [#handle-errors] Map the HTTP status codes the API returns to clear handling in your code, and log the `requestId` from each response so you can reference it with support. See [Error Handling](https://docs.chargeflow.io/docs/reference/api-fundamentals/error-handling) and the [Error Codes Reference](https://docs.chargeflow.io/docs/reference/error-codes). ### Respect rate limits [#respect-rate-limits] If you receive a `429 Too Many Requests` response, back off and retry. Honor the `Retry-After` header to know how long to wait. See [Rate Limits](https://docs.chargeflow.io/docs/reference/api-fundamentals/rate-limits). ### Pin your API version [#pin-your-api-version] Include an explicit API version in every request path, for example `2025-04-01`, so future changes to newer versions do not affect your integration. See [API Versioning](https://docs.chargeflow.io/docs/reference/concepts/api-versioning). ## Next steps [#next-steps] * Review the [FAQ](https://docs.chargeflow.io/docs/reference/faq) for quick answers. * Bookmark [Status](https://docs.chargeflow.io/docs/reference/status) to watch for incidents. * Keep [Support](https://docs.chargeflow.io/docs/reference/support) handy for production issues. # Idempotency (https://docs.chargeflow.io/docs/reference/api-fundamentals/idempotency) Idempotency key documentation is coming soon. The `Idempotency-Key` header can be used on evidence generation requests to safely retry without creating duplicates. Full documentation is in progress. ## Next steps [#next-steps] Where the idempotency key applies today. Retry safely after a failed request. Set up the credentials every request needs. # Pagination (https://docs.chargeflow.io/docs/reference/api-fundamentals/pagination) All list endpoints in the Chargeflow API use page-based pagination via the `offset` and `limit` query parameters. `offset` is a zero-based page index, not an item count: increment it by 1 to move to the next page. ## Parameters [#parameters] | Parameter | Type | Default | Min | Max | Description | | --------- | ------- | ------- | --- | ----- | ----------------------------------- | | `offset` | integer | `0` | `0` | - | Zero-based page index to retrieve. | | `limit` | integer | `25` | `1` | `100` | Number of items to return per page. | ## Example request [#example-request] ```bash title="Terminal" curl -X GET "https://api.chargeflow.io/public/2025-04-01/disputes?offset=0&limit=25" \ -H "x-api-key: YOUR_API_KEY" ``` ## Example response shape [#example-response-shape] ```json title="Response" { "disputes": [{ "id": "66e6ea9ecd94925a9f8060d9" }, { "id": "66e6ea9ecd94925a9f8060da" }], "pagination": { "totalCount": 342, "offset": 0, "limit": 25, "totalPages": 14 } } ``` | Field | Description | | ----------------------- | ----------------------------------------------- | | `disputes` | Array of result objects for the current page. | | `pagination.totalCount` | Total number of items matching the query. | | `pagination.offset` | The current zero-based page index. | | `pagination.limit` | The number of items requested per page. | | `pagination.totalPages` | Total number of pages available for this query. | ## Paginating through all results [#paginating-through-all-results] Increment `offset` by 1 per page and stop once you reach `pagination.totalPages`: ```javascript title="Node.js" async function fetchAllDisputes(apiKey) { const baseUrl = 'https://api.chargeflow.io/public/2025-04-01/disputes'; const limit = 100; let offset = 0; let allDisputes = []; while (true) { const response = await fetch(`${baseUrl}?offset=${offset}&limit=${limit}`, { headers: { 'x-api-key': apiKey }, }); const { disputes, pagination } = await response.json(); allDisputes = allDisputes.concat(disputes); // Stop once the next page would be past the last one if (offset + 1 >= pagination.totalPages) break; offset += 1; } return allDisputes; } ``` Set `limit=100` when fetching large datasets to minimize the number of requests needed to page through all results. ## Next steps [#next-steps] A full pagination recipe. Pace your requests when paging large datasets. Every list endpoint and its parameters. # Rate Limits (https://docs.chargeflow.io/docs/reference/api-fundamentals/rate-limits) Rate limit documentation is coming soon. In the meantime: * If you receive a `429 Too Many Requests` response, implement exponential backoff * The `Retry-After` header indicates how long to wait before retrying * Contact [support@chargeflow.io](mailto:support@chargeflow.io) for current rate limit details ## Next steps [#next-steps] How to back off and retry on a 429. The full list of HTTP status codes. Page through large result sets to reduce request volume. # API keys (https://docs.chargeflow.io/docs/reference/api-fundamentals/test-credentials) API keys authenticate every request to the Chargeflow API. You generate them in the Chargeflow App and send the access key in the `x-api-key` header. An isolated sandbox with separate test keys is coming. Until then, the keys you generate act on your live account, so build with care: read before you write, and work through the go-live checklist before sending production traffic. ## What you need [#what-you-need] Chargeflow uses API key authentication. Depending on your setup you may use one or both of these credentials: * **API Access Key**. Sent in the `x-api-key` header on every request. This is required. * **API Secret Key**. Only needed if you enable HMAC signature validation. It is shown once at generation time, so store it securely. ## Generate your keys [#generate-your-keys] Log in to the [Chargeflow App](https://app.chargeflow.io/auth/sign-in). Navigate to [Settings](https://app.chargeflow.io/settings#developers) and select **Developers** from the left side menu. Click **Generate Keys**. Copy your **API Access Key** and, if you plan to use HMAC, your **API Secret Key**. The secret key is only shown once. ## Use a key [#use-a-key] Send the access key in the `x-api-key` header: ```bash title="Terminal" curl https://api.chargeflow.io/public/2025-04-01/disputes \ -H "x-api-key: YOUR_API_KEY" ``` `YOUR_API_KEY` above is a placeholder. Use the real value you copied from the Developers section. Never commit a real key to source control. ## Key scopes and HMAC [#key-scopes-and-hmac] By default, HMAC signature verification is disabled on newly generated access keys. In this mode the access key alone authenticates your requests, which keeps integration simple in code and in tools like Zapier or Make. If you want an extra layer of security that guarantees request integrity and authenticity, you can enable **HMAC Signature Validation** in the Developers section. Once enabled, Chargeflow verifies the `x-chargeflow-hmac-sha256` signature on every incoming request, computed from your request data and your secret key. The signing details and code examples are in [Authentication](https://docs.chargeflow.io/docs/reference/api-fundamentals/authentication). ## Next steps [#next-steps] # Alerts model (https://docs.chargeflow.io/docs/reference/concepts/alerts-model) A **pre-chargeback alert** is an early warning that a cardholder has questioned or disputed a transaction, sent before the dispute becomes a formal chargeback. Alerts give merchants a short window to resolve the issue, usually by refunding the transaction, so the chargeback never posts. Preventing a chargeback this way avoids the chargeback fee, protects the merchant's dispute ratio, and keeps the account in good standing with the networks. Chargeflow receives alerts from the card networks and makes them available through API endpoints and webhook notifications in real time. You can retrieve alerts, check their status, and follow each one through to its outcome: prevented, escalated, or otherwise resolved. ## Where alerts come from [#where-alerts-come-from] Two alert networks supply most pre-chargeback alerts. | Network | Owned by | What it does | | ------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Ethoca | Mastercard | Distributes fraud and customer-dispute alerts from issuers across many card brands, giving merchants a chance to refund before a chargeback is filed. | | Verifi | Visa | Provides Cardholder Dispute Resolution Network (CDRN) alerts and Rapid Dispute Resolution (RDR). RDR can resolve eligible Visa disputes automatically against merchant-defined rules, so no chargeback is created. | Ethoca and Verifi cover different issuers and brands, so using both widens the share of disputes that can be caught early. ## How alerts prevent chargebacks [#how-alerts-prevent-chargebacks] When an issuer or the alert network detects a dispute or fraud report, it sends an alert instead of, or just ahead of, a chargeback. If the merchant refunds the transaction within the alert window, the cardholder's complaint is satisfied and the issuer does not proceed to a chargeback. The merchant trades the disputed amount (which would often be lost anyway) for the avoided chargeback fee and a cleaner dispute ratio. ## Outcome flow [#outcome-flow] ### Consumer makes a purchase [#consumer-makes-a-purchase] A normal transaction posts to the cardholder's account. ### Consumer raises an issue [#consumer-raises-an-issue] The consumer makes an inquiry or disputes the purchase with their card issuer. ### Chargeflow receives an alert [#chargeflow-receives-an-alert] Chargeflow gets a pre-chargeback alert from Ethoca or Verifi, an early notification about the case. ### Chargeflow matches the alert [#chargeflow-matches-the-alert] Chargeflow associates the alert to a merchant and matches it to the corresponding transaction or order. ### The case is resolved [#the-case-is-resolved] Chargeflow resolves the case, typically by refunding the transaction, and updates the alert outcome. ### The issuer is informed [#the-issuer-is-informed] The outcome is reported back to the issuer or alert network. The case is resolved without escalating to a chargeback. ## Integration models [#integration-models] The Alerts API supports two models, depending on how much control you want over the refund. ### Chargeflow Alerts (most common) [#chargeflow-alerts-most-common] Chargeflow automates the full handling of alerts, including transaction matching and refunds where applicable. Merchants and platforms act as passive consumers of the API. The API and webhooks serve as an informational layer that lets you: * Retrieve alerts and outcomes via the API. * Embed alert data into your own dashboards, reports, or customer portals. * Receive event notifications for alert creation and outcome updates, without performing manual actions. This option requires minimal development effort, since Chargeflow runs the mitigation flow end to end. You can still build automations on top of the webhooks, such as customer tagging or subscription cancellation. ### Merchant-managed handling [#merchant-managed-handling] Chargeflow provides the alerts, but the merchant or platform executes the refund. ### Receive the alert [#receive-the-alert] Subscribe to the `alerts.created` webhook. If you need transaction-level data, also subscribe to `alerts.transaction.linked`. ### Locate and validate [#locate-and-validate] Find and validate the corresponding transaction in your systems. ### Perform the mitigation [#perform-the-mitigation] Issue the refund (or other mitigation) in your payment processor or order management system. ### Update the outcome [#update-the-outcome] Update Chargeflow with the final outcome using the Alert Outcome Update endpoint, so Chargeflow can report back to the issuer correctly and the chargeback is prevented. This option gives you full control over refunds and business logic, but requires more implementation and monitoring to ensure outcomes are updated reliably. If your team does not need to control the refund flow, use Chargeflow Alerts. It needs the least code and Chargeflow handles everything. Choose merchant-managed handling only when you must apply custom business logic before issuing refunds. ## Next steps [#next-steps] Setting up and working with alerts. Subscribe to alert events. What happens when an alert is not resolved in time. Recovering disputes that do become chargebacks. # API Versioning (https://docs.chargeflow.io/docs/reference/concepts/api-versioning) Chargeflow uses date-based, path parameter versioning for its public API. This approach gives you a stable, predictable URL structure and ample time to migrate whenever breaking changes are introduced. ## Using API versions [#using-api-versions] Select the API version by including the version date in the request path: ``` https://api.chargeflow.io/public/{apiVersion}/... ``` Replace `{apiVersion}` with the version string from the [Available versions](#available-versions) table below. For example: ```bash title="Terminal" https://api.chargeflow.io/public/2025-04-01/disputes ``` > Always include an explicit version in your requests. This ensures your integration is unaffected by future changes to newer versions. ## Deprecation policy [#deprecation-policy] During significant updates, Chargeflow may mark specific API methods of a version as deprecated. When a method is marked as deprecated, it indicates that it will no longer be available in upcoming versions. Deprecation notices are communicated in advance, giving you time to migrate before the method is removed. ## Available versions [#available-versions] | Version | Release date | Notes | | ------------ | -------------- | --------------------------------------- | | `2024-03-18` | March 18, 2024 | Initial API release | | `2025-04-01` | April 1, 2025 | New endpoints and payload modifications | Use the version string exactly as shown (e.g., `2025-04-01`) in the URL path. Do not use shortened or alternate date formats. ## Next steps [#next-steps] What changed in each version. The full endpoint reference for the current version. Make your first versioned request. # CE 3.0 eligibility (https://docs.chargeflow.io/docs/reference/concepts/ce-3.0-eligibility) **Visa Compelling Evidence 3.0** (CE 3.0) is a Visa rule that lets merchants fight certain fraud disputes by proving a history of prior, undisputed transactions from the same cardholder. It applies to fraud disputes under Visa reason code 10.4 (card-absent fraud). When a merchant can show that the same customer made earlier purchases that were never disputed, Visa treats the current transaction as more likely legitimate, and the liability can shift back to the issuer. CE 3.0 is one of the most effective tools for recovering "friendly fraud" disputes, where the cardholder did in fact make the purchase. ## What CE 3.0 changed [#what-ce-30-changed] Earlier compelling-evidence rules required merchants to prove the specific disputed transaction was valid, which is hard when a cardholder simply denies a charge they actually made. CE 3.0 takes a different approach: it lets the merchant point to a pattern of prior good transactions tied to the same person. If two or more qualifying prior transactions match, Visa can dismiss the dispute before it becomes a chargeback. ## Eligibility criteria [#eligibility-criteria] To qualify under CE 3.0, a merchant must identify at least **two prior transactions** from the same cardholder that meet all of the following conditions. | Criterion | Requirement | | -------------------- | ----------------------------------------------------------------------------------------------- | | Age | The prior transactions occurred between 120 and 365 days before the disputed transaction date. | | Undisputed | The prior transactions were not themselves disputed, charged back, or refunded for fraud. | | Same cardholder | The prior transactions belong to the same Visa account as the disputed transaction. | | Matching data points | The prior transactions share identifying data points with the disputed transaction (see below). | ## Required prior-transaction data points [#required-prior-transaction-data-points] The prior transactions must share identifying data with the disputed one. At least **two** of the following must match across the prior and disputed transactions, and at least one must be a device or account identifier. * Customer account or login ID used at the merchant. * Device fingerprint or device ID. * IP address. * Shipping address. * Email address used for the order. * Phone number on file. The more data points that match, and the more closely they tie to the device or account rather than just the order, the stronger the case. CE 3.0 is most effective against friendly fraud, where the cardholder made the purchase but disputes it anyway. By proving the same person transacted before without complaint, the merchant undercuts the claim that the charge was unauthorized. ## How it helps fraud disputes [#how-it-helps-fraud-disputes] A fraud dispute filed under Visa 10.4 normally turns on whether the merchant can prove the cardholder authorized the charge. Without CE 3.0, that is difficult in a card-absent environment. With CE 3.0, the merchant shifts the question from "was this one transaction valid" to "does this customer have a clean history with us," which is far easier to evidence. When the prior transactions qualify, Visa can resolve the dispute in the merchant's favor and, in many cases, prevent it from escalating to a chargeback at all. Chargeflow checks each eligible fraud dispute against CE 3.0 criteria, locates qualifying prior transactions in your connected data, and assembles the matching data points into the response. See [Dispute automation engine](https://docs.chargeflow.io/docs/reference/concepts/dispute-automation). ## Next steps [#next-steps] How fraud disputes are categorized. The broader evidence process CE 3.0 fits into. The Visa response windows that apply. How Chargeflow applies CE 3.0 automatically. # Chargeback lifecycle (https://docs.chargeflow.io/docs/reference/concepts/chargeback-lifecycle) A chargeback is a forced reversal of a card payment. It starts when a cardholder questions a posted transaction and asks their issuing bank to return the money. The issuer routes the case through the card network to the merchant's acquirer, the merchant gets a chance to respond with evidence, and the issuer returns a decision. This page explains who is involved and walks through the lifecycle stage by stage. ## The payment ecosystem [#the-payment-ecosystem] Understanding who does what makes disputes easier to navigate. The table below summarizes the key parties and their core responsibilities. | Party | Description | Primary responsibilities | Examples | | ------------------------------ | ---------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------- | | Cardholder | The person who owns or uses the payment card. | Makes purchases, provides card details at checkout, and can file a dispute with their bank if they contest a charge. | Buyers, consumers, end customers | | Merchant | A business that sells goods or services and accepts card payments. | Takes orders, requests payment authorization, fulfills orders, issues refunds, and responds to disputes and chargebacks. | Online stores, physical retailers, SaaS vendors | | Issuing bank | The bank that issued the card to the cardholder. | Maintains the card account, approves or declines authorizations, posts charges to the cardholder's account, and manages disputes on behalf of the cardholder. | Bank of America, Barclays, local card-issuing banks | | Acquiring bank | The bank that processes card payments for the merchant. | Provides the merchant account, forwards transactions to the card network, and deposits settlement funds to the merchant (net of fees). | Worldpay, regional acquiring banks | | Card network | The network that routes messages between issuers and acquirers and sets the rules. | Connects the issuer and acquirer, defines rules and fees, and manages clearing, settlement, and dispute workflows. | Visa, Mastercard, American Express, Discover | | Payment service provider (PSP) | A provider that helps merchants accept and manage payments. | Supplies gateways, SDKs, risk tools, and reconciliation, and often connects the merchant to one or more acquirers or networks. | Stripe, Adyen, PayPal | ## The lifecycle, stage by stage [#the-lifecycle-stage-by-stage] After a transaction posts, the cardholder has a network-defined window to open a dispute - the exact window depends on the network and reason code (see [Network timelines](https://docs.chargeflow.io/docs/reference/concepts/network-timelines)). A dispute moves through the system in a clear sequence. ### Cardholder files a dispute [#cardholder-files-a-dispute] The cardholder contacts their issuing bank, often through the bank's app, to contest a charge. The bank records the reason and starts the dispute process. ### Issuer opens a case [#issuer-opens-a-case] The issuing bank creates a formal dispute with a network reason code and sends it through the card network to the merchant's acquirer. ### Chargeback posted to the acquirer [#chargeback-posted-to-the-acquirer] The issuer posts a provisional reversal and routes the case to the acquirer. The disputed amount is temporarily removed from the merchant's balance. ### Merchant notification [#merchant-notification] The acquirer or PSP notifies the merchant and provides the dispute data, including the reason code and any supporting details. The merchant can accept the dispute or prepare a rebuttal. Chargeflow ingests disputes from all connected PSPs and presents every case in one place. ### Representment (merchant rebuttal) [#representment-merchant-rebuttal] The merchant gathers evidence and builds a clear, factual narrative to challenge the dispute. Evidence may include receipts, delivery proof, authentication logs, and customer communications. Chargeflow consolidates and enriches the data and drafts a focused rebuttal. See [Representment and evidence](https://docs.chargeflow.io/docs/reference/concepts/representment-and-evidence). ### Submission [#submission] The merchant submits the evidence and rebuttal to the acquirer or PSP, which forwards it to the issuer for review. Chargeflow submits the rebuttal on the merchant's behalf within the network response window. ### Issuer decision [#issuer-decision] The issuer reviews the submission and issues a ruling: merchant-favored (funds returned) or cardholder-favored (the reversal stands). Chargeflow tracks the outcome and updates case status. ### Pre-arbitration and arbitration (optional) [#pre-arbitration-and-arbitration-optional] If a decision is contested or network rules require it, the case can escalate to pre-arbitration or arbitration. The card network then adjudicates the dispute. Arbitration is rare, slow, and can be costly. Exact timelines and steps vary by card network, reason code, and region - filing windows, merchant response windows, and review periods are all network-defined. The canonical per-network figures live in [Network timelines](https://docs.chargeflow.io/docs/reference/concepts/network-timelines). Chargeflow exposes these transitions through `dispute` events so you can act immediately and keep your systems in sync. See [Webhooks](https://docs.chargeflow.io/docs/reference/concepts/webhooks). ## Next steps [#next-steps] The stages and statuses and the transitions between them. How network reason codes map to Chargeflow categories. Response windows by network. How Chargeflow handles the lifecycle end to end. # Dispute Automation Engine (https://docs.chargeflow.io/docs/reference/concepts/dispute-automation) An agentic dispute automation engine that ingests your disputes, builds and submits responses, and tracks each case through its lifecycle. This page is the API-level view: the pipeline as an integrator meets it. For the architecture behind it, read [How recovery works](https://docs.chargeflow.io/docs/reference/concepts/how-recovery-works) and [How our AI works](https://docs.chargeflow.io/docs/reference/concepts/how-our-ai-works). ## How it works [#how-it-works] Get up and running in minutes: create your account, connect your PSPs and business tools, and you are ready to go. Here's the full pipeline: | Step | What happens | | ----------------------------------------------- | --------------------------------------------------------------------------------------------------- | | **1. Ingest** | Chargeflow automatically ingests 100% of your disputes from connected PSPs. | | **2. First Enrichment** | Chargeflow's Enrichment Engine pulls case-relevant signals to strengthen the evidence set. | | **3. Second Enrichment** *(optional)* | You add targeted signals via the Update Dispute API endpoint. | | **4. Generation** | Chargeflow's AI agents compile a challenge strategy and compose the response. | | **5. Submission** | Chargeflow submits the generated response back to your PSP. | | **6. Monitor** | Chargeflow updates the dispute throughout its lifecycle so you can track progress programmatically. | Start automation in minutes, then improve outcomes by sending targeted enrichments to the API. ## How the engine wins disputes [#how-the-engine-wins-disputes] Chargeflow orchestrates multiple agentic layers to assemble the dispute response from the data you and Chargeflow provide. You can improve outcomes by sending targeted enrichments to a single API endpoint. **Agentic automation** Chooses what evidence to generate and how to present it based on available signals, historical data, network requirements, and domain intelligence. **Simple integration** One endpoint for enrichments; minimal payloads focused on what actually moves win rate. **Data network effects** Chargeflow augments your inputs with internal models (when available) to strengthen the case. Chargeflow partners with leading data-enrichment providers and uses internal models to enhance evidence and increase the likelihood of a win. ## Control and transparency [#control-and-transparency] You stay in control of your automation strategy and evidence at every stage. * **Your data, end-to-end**: Fetch the complete, normalized dispute record, including Chargeflow-added enrichments, via a single retrieval endpoint for your own systems and BI. * **Override or provide**: Provide (or override) signals per dispute; the response is adapted accordingly. * **Clear status**: Programmatic access to lifecycle status, evidence artifacts, and submission history. ## Privacy and security [#privacy-and-security] Chargeflow treats privacy and security as first-order features - data is minimized, segmented, and partner enrichments are clearly labeled. The compliance posture (SOC 2 Type II, GDPR) and data-handling detail are covered canonically in [Security](https://docs.chargeflow.io/docs/reference/security). ## Next steps [#next-steps] The step-by-step guide to the automation flow. Send targeted signals that move win rate. Trigger your enrichment flow on `dispute.created`. Understand the stages a dispute moves through. # Dispute state machine (https://docs.chargeflow.io/docs/reference/concepts/dispute-state-machine) A dispute is best understood as a state machine. It has a **stage** (where the case sits in the network's escalation path) and a **status** (whether it is waiting on you, under review, or resolved). Chargeflow unifies stages and statuses across every connected PSP so you read one consistent model regardless of source. This page lists the states and the transitions allowed between them. ## Stages [#stages] The stage tracks how far a dispute has escalated within the card network's rules. Each stage calls for a different approach, and Chargeflow takes stage-appropriate action. | Stage | What happens | What Chargeflow does | Possible next stage | | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | | `inquiry` | Also called a retrieval or request for information (RFI). The issuer requests transaction documents instead of immediately issuing a chargeback. | Sends available transaction documents to the issuer to prevent escalation, lists any missing artifacts as a prioritized checklist, and notifies your team. | The issuer can escalate to `chargeback`. | | `chargeback` | The issuer posts a provisional reversal and notifies the acquirer or PSP. The disputed amount is provisionally removed from the merchant's balance. | Normalizes the dispute data, creates the case record, consolidates and enriches evidence, drafts a targeted rebuttal, and flags missing high-impact artifacts. | One party can escalate to `pre_arbitration` to reopen the case as a second chargeback. | | `pre_arbitration` | Also called a second chargeback. One party (merchant or buyer) challenges the issuer's decision and requests escalation under network rules. This may incur fees. | Rebuilds the case narrative for escalation, compiles supplemental evidence, and advises on likelihood versus cost. | `arbitration`, a final decision by the network. | | `arbitration` | Final adjudication by the card network. The network issues a binding decision and any applicable fees. Arbitration is rare and can be slow and costly. | Prepares network-specific documentation, submits materials, and logs the outcome and fees. | None. The decision is binding. | ### Stage transitions [#stage-transitions] ``` inquiry ──> chargeback ──> pre_arbitration ──> arbitration ``` A dispute can enter directly at `chargeback` when the issuer skips the inquiry step. Stages only move forward; a dispute never returns to an earlier stage. ## Statuses [#statuses] The status tells you what the dispute needs right now, independent of its stage. A dispute can be in `needs_response` at the `chargeback` stage, then move to `under_review` after submission, then settle as `won` or `lost`. | Status | Description | Possible actions | | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | | `needs_response` | The dispute requires a response from the merchant. Chargeflow prepares to submit a rebuttal unless you add targeted evidence first. | Add targeted evidence with the Update Dispute endpoint before Chargeflow submits the rebuttal on your behalf. | | `under_review` | The dispute has been submitted, or the response window has passed, and the issuer is evaluating the case. | None. Wait for the decision. | | `won` | The dispute was resolved in the merchant's favor. | None. Funds are returned. | | `lost` | The dispute was resolved in the buyer's favor. | Consider escalation to `pre_arbitration` only after a cost-benefit review. Contact Chargeflow for guidance before escalating. | ### Status transitions [#status-transitions] | From | To | Trigger | | ---------------- | ---------------- | -------------------------------------------------------------------------- | | `needs_response` | `under_review` | The rebuttal is submitted, or the response window closes. | | `under_review` | `won` | The issuer rules in the merchant's favor. | | `under_review` | `lost` | The issuer rules in the buyer's favor. | | `lost` | `needs_response` | The case is escalated to `pre_arbitration` and reopens for a new response. | Stage describes escalation within the network. Status describes who the case is waiting on. A single dispute carries both at once, and they advance on their own triggers. ## Next steps [#next-steps] The end-to-end flow and the parties involved. What to submit during `needs_response`. How disputes are categorized. Track status changes programmatically. # Evidence examples by reason code (https://docs.chargeflow.io/docs/reference/concepts/evidence-examples) What the engine actually does, on a real dispute, for a specific reason code. Each example below follows the same three questions: what the reason code requires, what Chargeflow collected, and what the agents found. Two reason codes are documented in full today. The structure is deliberately repeatable, so more are added without rewriting the page. ## Visa Compelling Evidence 3.0, fraud [#visa-compelling-evidence-30-fraud] CE 3.0 exists for one scenario: the cardholder claims fraud on a merchant they have in fact been buying from. Rather than argue about the disputed transaction alone, it lets you show a history the fraudster could not have. ### What the reason code requires [#what-the-reason-code-requires] * **Two prior undisputed transactions** with the same cardholder, in the **120 to 365 day** window before the disputed one. * Both prior transactions must have **no active fraud report or dispute**. * Both must **share at least two matching data elements** with the disputed transaction. IP address and device ID are the pair that carries most cases. * The **IP address and billing address** of the disputed transaction. Eligibility rules and windows are covered in [CE 3.0 eligibility](https://docs.chargeflow.io/docs/reference/concepts/ce-3.0-eligibility). ### What Chargeflow collected [#what-chargeflow-collected] | Evidence | What it establishes | | -------------------------------- | -------------------------------------------------------------------------------------------- | | Device and IP analysis | The disputed order came from the same device fingerprint and IP as prior legitimate orders | | Geolocation comparison | Delivery, billing, and IP locations sit within a few kilometres of each other | | AVS result | The address verification match on the disputed transaction | | Account history | Two prior transactions with dates, amounts, ARNs, payment method, device, and dispute status | | Cardholder identity verification | The link between the person who filed the dispute and the account that placed the orders | | Service delivery confirmation | For a digital or advertising purchase, the delivery receipt and impression or click record | ### What the agents found [#what-the-agents-found] The agent read the requirements attached to this specific reason code and searched for the evidence that would refute the claim, rather than attaching everything available. It then linked the purchase to the cardholder: IP and billing address in close proximity, plus an AVS match, on two qualifying prior transactions. That is the shape of a CE 3.0 case. Not "here is our shipping policy", but "this person has been shopping here for months, from this device, at this address, without complaint". ## Visa 13.1, item not received [#visa-131-item-not-received] The cardholder says the product never arrived. The case is won by proving delivery, or by proving use. ### What the reason code requires [#what-the-reason-code-requires-1] Proof that the goods or services were provided as described, and the terms the cardholder agreed to at purchase. ### What Chargeflow collected [#what-chargeflow-collected-1] | Evidence | What it establishes | | ----------------------------------- | ------------------------------------------------------------------------------ | | Shipping partner record | Product confirmed delivered and fulfilled in good condition | | Product usage from the activity log | The account associated with the order used the product after the delivery date | | Order details and checkout record | What was bought, when, and by which account | | Terms and conditions | The delivery and risk-of-loss clause the customer accepted at checkout | ### What the agents found [#what-the-agents-found-1] Delivery evidence alone is often contested. The stronger finding came from behaviour: the customer claimed they never received the item, while the activity log showed the product registered and in use after the delivery date. The agents paired that with the specific terms-of-service section on delivery and risk of loss that the customer accepted when completing the purchase. A tracking number says a parcel moved. A usage log says the person using the product is the person disputing it. ## What this means for the data you send [#what-this-means-for-the-data-you-send] Both examples turn on data that lives outside the payment processor: * **Device, IP, and account history** win fraud cases. See [E-commerce data](https://docs.chargeflow.io/docs/merchants/automation/enrich-a-dispute/by-business-model). * **Usage and activity logs** win item-not-received and not-as-described cases. See [Enrich a dispute](https://docs.chargeflow.io/docs/merchants/automation/enrich-a-dispute). * **Support conversations** frequently contain an admission that settles the case. See [Customer communication](https://docs.chargeflow.io/docs/merchants/automation/enrich-a-dispute/customer-communications). If a dispute of yours would rely on data Chargeflow has no connection to, connect it before the dispute arrives rather than after. See [Integrations](https://docs.chargeflow.io/docs/reference/integrations). ## Next step [#next-step] Send the data these cases are built from. More reason codes are documented as they are worked end to end. The full catalog of codes is in [Reason codes](https://docs.chargeflow.io/docs/reference/concepts/reason-codes). # Evidence generation (https://docs.chargeflow.io/docs/reference/concepts/evidence-generation) Chargeflow writes each dispute response from scratch. There is no template with blanks in it. That is the difference worth understanding before you evaluate any dispute vendor, because it decides what happens on the disputes that are not typical, and those are the ones you lose. ## How it is built [#how-it-is-built] | Stage | What happens | | --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | | **Structure first** | The evidence structure is chosen for the reason code and the scheme before any prose exists. | | **Specialised agents** | Agents trained per dispute type, per vertical, and per data-collection type each write the part of the claim they own. | | **Composition** | A final agent composes and refines the parts into one coherent claim rather than a stack of sections. | | **BIN-driven optimisation** | The issuer's BIN informs how the case is presented, because issuers do not all weigh evidence the same way. | | **QA by an AI agent** | Facts, card-scheme rules, and structure are checked before submission. See [How our AI works](https://docs.chargeflow.io/docs/reference/concepts/how-our-ai-works). | | **Feedback-driven** | Wins and losses are A/B fed back, so the approach for each reason code keeps moving. | Multi-language support means the claim can be produced in the language the issuer works in. ## Chargeflow versus template-based tools [#chargeflow-versus-template-based-tools] | | Chargeflow | Template-based providers | | ------------------------ | ------------------------------------------------------- | ---------------------------------------------------- | | How the claim is written | From scratch by multiple agents | Pre-written template, AI fills the blanks | | Adapts to the dispute | Yes, per reason code, vertical, and available data | Limited to what the template anticipated | | Quality control | AI QA agent checks facts, rules, and structure | Usually none beyond validation | | Scheme alignment | A dedicated component aligns to card scheme regulations | Static, updated when the vendor updates the template | | Improves over time | Every win and loss feeds back | Only when someone rewrites the template | The bottom line: each case is unique and the output mimics what a chargeback analyst would produce, rather than what a form letter produces. ## What this means for you [#what-this-means-for-you] **Send the data, not the argument.** Your job is context: the order, the conversation, the usage, the fulfilment record. Deciding which of it wins this particular dispute is the engine's job. Send everything you have; the enrichment engine evaluates what strengthens the case and leaves out what does not. See [Enrich a dispute](https://docs.chargeflow.io/docs/merchants/automation/enrich-a-dispute). **Unusual disputes are the point.** Any tool handles a clean "item not received" with a tracking number. Value shows up on the dispute where the tracking number is missing but the customer's account history, IP, and support thread together make the case. **You can still review.** Platforms can run co-pilot, where evidence is generated and a human approves before submission. See [Platforms overview](https://docs.chargeflow.io/docs/platforms/overview). ## Next step [#next-step] What the agents actually collected and argued on two real dispute types. Background reading: [Representment and evidence](https://docs.chargeflow.io/docs/reference/concepts/representment-and-evidence) for the mechanics of a representment, and [How recovery works](https://docs.chargeflow.io/docs/reference/concepts/how-recovery-works) for where generation sits in the pipeline. # How our AI works (https://docs.chargeflow.io/docs/reference/concepts/how-our-ai-works) Chargeflow's AI is built around a domain model, not an industry list. A travel dispute and a SaaS dispute look different on the surface and are the same underneath: a commercial promise, a financial transaction, and a record of what happened. Model that once and every vertical works. Model each vertical separately and you maintain forever. That choice is the whole architecture. It runs in two phases. ## Phase 1: the data foundation [#phase-1-the-data-foundation] Industry-agnostic on purpose, in three steps. **Ingest.** Structured and unstructured data together: order rows and tracking numbers, but also support threads, receipts, screenshots, and terms of service. **Understand.** Everything is interpreted against a domain schema, the model of what a transaction, a fulfilment, a customer, and a promise are. This is the part that transfers across industries, and it is the moat: the schema is what lets a new vertical work on day one instead of after a bespoke integration. **Contextualise.** The result is not a pile of fields but a commercial and financial story: what was sold, what was delivered, what the customer did afterwards, and what they were told along the way. ## Phase 2: dispute execution [#phase-2-dispute-execution] **Read the reason code and select a playbook.** Reason codes are not interchangeable. Visa 13.1 asks whether the item arrived; a CE 3.0 fraud claim asks whether the cardholder is the person who has been shopping with you all year. Different questions need different evidence, so the playbook is chosen before anything is written. See [Reason codes](https://docs.chargeflow.io/docs/reference/concepts/reason-codes). **Draft the narrative strategy.** The argument is decided before the paragraphs: which claim to refute, in what order, with which artefacts as the spine of the case. **Delegate to specialised agents.** An orchestrator assigns the work: a transactions agent for payment and account history, a behaviour agent for how the customer actually used the product, a delivery agent for fulfilment proof, plus specialised agents where the case needs them. Each writes the part it is trained for. **QA before submission.** A QA agent checks three things: are the facts supported by the collected data, does the case meet the card network's rules for this reason code, and is it structured the way the issuer expects. Anything failing goes back to the responsible agent for up to three rounds. If it still does not pass, a human on the Chargeflow team is alerted rather than a weak case being submitted. **Learn from the outcome.** The issuer's letter and the win/loss result feed back into playbook selection and drafting for the next dispute of that type. ## Why this beats a template [#why-this-beats-a-template] Templates encode last year's winning argument and apply it to this year's dispute. An agent that reads the reason code, the evidence available, and the customer's actual behaviour writes a case for the dispute in front of it. The side-by-side is in [Evidence generation](https://docs.chargeflow.io/docs/reference/concepts/evidence-generation), and worked examples are in [Evidence examples by reason code](https://docs.chargeflow.io/docs/reference/concepts/evidence-examples). ## Next step [#next-step] Two disputes end to end: what the code required, what was collected, what the agents found. # How recovery works (https://docs.chargeflow.io/docs/reference/concepts/how-recovery-works) The dispute process is simple. The way Chargeflow does it is not. A chargeback gives you a deadline and a form. Filling that form well means assembling evidence from systems that were never designed to talk to each other, phrasing it the way a specific card network expects for a specific reason code, and doing it before the clock runs out. This page is what happens in between, in the order it happens. ## The whole flow [#the-whole-flow] ## The four parts [#the-four-parts] Everything in the diagram is one of four jobs. ### 1. Data ingestion [#1-data-ingestion] Disputes arrive on their own. Once a payment processor is connected, Chargeflow ingests every dispute it raises, with no polling and nothing for you to forward. Collection of the surrounding data is automated the same way, through direct integrations with the tools you already run rather than a CSV you assemble. What gets collected: the order, the transaction, the customer record, the subscription history where there is one, the fulfilment and delivery record, and the customer conversation thread. See [Integrations](https://docs.chargeflow.io/docs/reference/integrations) for what connects, and [Subscribe to webhook events](https://docs.chargeflow.io/docs/merchants/automation/subscribe-to-events) to be told the moment a dispute lands. ### 2. Data enrichment [#2-data-enrichment] Raw records are not evidence. Enrichment turns them into a picture of the transaction: who the customer is, what they did, what they were sent, what they were told, and whether any of that contradicts the claim on the dispute. Chargeflow enriches and analyses thousands of data points per dispute, and you can add your own through the [enrichment endpoints](https://docs.chargeflow.io/docs/merchants/automation/enrich-a-dispute) when you hold context we cannot see. Thread analysis is the part merchants underestimate. A support conversation in which the customer acknowledges receiving the item is often stronger than every shipping document combined. ### 3. Evidence creation [#3-evidence-creation] The automation layer decides what to argue and writes it. It is not one model filling a template: a rules engine applies what the card network requires, an AI evidence agent drafts the case, dispute-reason and card-specific logic shape it for the exact reason code and scheme, and merchant-specific logic keeps it consistent with how your business actually operates. Experimentation runs variants so the approach keeps improving. The detail lives in [Evidence generation](https://docs.chargeflow.io/docs/reference/concepts/evidence-generation) and [How our AI works](https://docs.chargeflow.io/docs/reference/concepts/how-our-ai-works). ### 4. Submission [#4-submission] Chargeflow submits the response through the processor's own channel, within the network deadline, and tracks the case afterwards. Submission is often deliberately close to the deadline rather than immediate, because late-arriving evidence (a delivery scan, a support reply) can still strengthen the case right up to the cut-off. Submission is processor-agnostic: the same evidence package is delivered in whatever shape each processor expects. ## The feedback loop [#the-feedback-loop] The last arrow in the diagram is the one that matters most. Every outcome, won or lost, returns to the automation layer along with the issuer's response. That is what tunes the rules, the drafting, and the experimentation over time, per reason code, per processor, per vertical. A dispute you lose today makes the next one of its kind stronger. ## Where you fit in [#where-you-fit-in] You do not have to touch any of it. The useful places to intervene, in order of value: | You want to | Do this | | ---------------------------------- | -------------------------------------------------------------------------------- | | Add context Chargeflow cannot see | [Enrich a dispute](https://docs.chargeflow.io/docs/merchants/automation/enrich-a-dispute) | | React the moment a dispute arrives | [Subscribe to `dispute.created`](https://docs.chargeflow.io/docs/merchants/automation/subscribe-to-events) | | Attach your own documents | [Upload evidence](https://docs.chargeflow.io/docs/merchants/automation/upload-evidence) | | Track outcomes in your own systems | [Disputes API](https://docs.chargeflow.io/docs/api/2025-04-01/merchants/disputes) | ## Next step [#next-step] The agent architecture behind the automation layer, phase by phase. Prefer the API view of the same pipeline? See [Dispute Automation Engine](https://docs.chargeflow.io/docs/reference/concepts/dispute-automation). # Network timelines (https://docs.chargeflow.io/docs/reference/concepts/network-timelines) Every card network sets its own clock for disputes. Miss a response window and the case is lost by default, even when the evidence is strong. This page summarizes the typical windows for Visa, Mastercard, American Express, and Discover so you know how much time each stage allows. ## Response windows by network [#response-windows-by-network] The windows below are the common defaults. They are counted in calendar days from the dispute date unless noted. | Stage | Visa | Mastercard | American Express | Discover | | --------------------------------- | ------------------------------------------------------------------------------------- | -------------- | ---------------- | -------------- | | Cardholder filing window | Up to 120 days from the transaction or expected delivery (up to 540 for some reasons) | Up to 120 days | Up to 120 days | Up to 120 days | | Merchant response (representment) | 30 days | 45 days | 20 days | 30 days | | Issuer review | Several weeks | Several weeks | Several weeks | Several weeks | | Pre-arbitration response | 30 days | 45 days | 20 days | 30 days | | Arbitration filing | 10 days after pre-arbitration | 45 days | Varies | Varies | These are typical defaults. The exact window depends on the specific reason code, the region, and the cardholder's situation. Some Visa reasons, for example, extend the filing window well beyond 120 days. Always confirm the deadline shown on the individual dispute with your PSP or the network before you rely on it. ## Why the clock matters [#why-the-clock-matters] The merchant response window is the deadline that matters most for recovery. If you do not submit a rebuttal in time, the dispute resolves in the cardholder's favor automatically. Networks count the window from the dispute date, not the date you were notified, so any delay between the issuer posting the chargeback and your PSP surfacing it eats into your available time. Chargeflow ingests disputes as soon as they post and submits the rebuttal well inside the window, which removes the risk of a missed deadline. See [Dispute automation engine](https://docs.chargeflow.io/docs/reference/concepts/dispute-automation). ## Inquiries and retrieval requests [#inquiries-and-retrieval-requests] Before a full chargeback, some networks issue an inquiry or retrieval request asking for transaction documents. These often carry shorter windows, frequently in the range of 24 to 72 hours for the initial document request and a few weeks for a full response. Responding to an inquiry promptly can prevent it from escalating into a chargeback. See [Dispute state machine](https://docs.chargeflow.io/docs/reference/concepts/dispute-state-machine). ## Next steps [#next-steps] How a dispute moves through each timed stage. The stages and statuses tied to these windows. What to submit before the response window closes. How the reason affects the applicable window. # Reason codes (https://docs.chargeflow.io/docs/reference/concepts/reason-codes) Every dispute carries a **reason code** that explains why the cardholder is contesting the charge. Each network maintains its own list of codes, and the same underlying complaint can have a different code on Visa, Mastercard, Amex, and Discover. To make disputes consistent and actionable, Chargeflow maps each network reason code to a single set of **reason categories**. Chargeflow then combines the category with transaction signals and your evidence to build the most effective rebuttal. ## Chargeflow reason categories [#chargeflow-reason-categories] | Category | Description | | ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | | `fraud` | The cardholder says they did not authorize or participate in the transaction. | | `not_received` | The cardholder says they never received the goods or service. | | `not_as_described` | The cardholder says the goods or services are materially different from what was advertised or expected. | | `canceled_recurring_billing` | The cardholder says they canceled a subscription but were still charged. | | `duplicate_charge` | The cardholder says they were charged more than once for the same purchase. | | `credit_not_processed` | The cardholder says a promised refund or credit was not applied. | | `other` | Any reason that does not fit the categories above. Network reason codes vary and may include merchant-specific or region-specific cases. | ## How network reason codes map to categories [#how-network-reason-codes-map-to-categories] Networks group their codes into a few broad themes: fraud, authorization, processing errors, and consumer disputes. Chargeflow normalizes those into the categories above. The table below shows representative network codes and the Chargeflow category each maps to. Codes and their exact meanings are defined by each network and change over time, so treat these as illustrative rather than exhaustive. | Chargeflow category | Visa | Mastercard | American Express | Discover | | ---------------------------- | ---------------------------- | ---------------- | ------------------ | ---------------------- | | `fraud` | 10.1, 10.2, 10.3, 10.4, 10.5 | 4837, 4849, 4863 | F24, F29, F30, F31 | UA01, UA02, UA05, UA06 | | `not_received` | 13.1 | 4855 | C08 | RG, AA | | `not_as_described` | 13.3, 13.5 | 4853 | C31, C32 | RM, C18 | | `canceled_recurring_billing` | 13.2 | 4841 | C28 | AP | | `duplicate_charge` | 12.6.1 | 4834 | P08 | DP | | `credit_not_processed` | 13.6, 13.7 | 4860 | C02, C05 | RN2, AW | Networks revise their reason-code lists, and the same code can carry slightly different requirements by region. Always confirm the current definition with the network or your PSP. Chargeflow keeps the mapping current so you work from stable categories instead of tracking every code change. ## Why categories matter [#why-categories-matter] The category drives strategy. A `fraud` dispute is won with authentication and prior-transaction evidence, often through [Compelling Evidence 3.0](https://docs.chargeflow.io/docs/reference/concepts/ce-3.0-eligibility). A `not_received` dispute is won with delivery proof. A `canceled_recurring_billing` dispute is won with the subscription terms and the cancellation record. Chargeflow uses the category to decide which evidence to gather and how to present it. See [Representment and evidence](https://docs.chargeflow.io/docs/reference/concepts/representment-and-evidence). ## Interactive explorer [#interactive-explorer] An interactive reason-code explorer is coming. Search any network reason code to see its Chargeflow category, the evidence that wins it, and the applicable response window. ## Next steps [#next-steps] The evidence each category needs. Winning fraud disputes with prior-transaction data. How reasoned disputes move through stages and statuses. Response windows, which vary by reason code. # Representment and evidence (https://docs.chargeflow.io/docs/reference/concepts/representment-and-evidence) **Representment** is the merchant's formal response to a chargeback. When a cardholder disputes a charge and the issuer reverses it, the merchant can "re-present" the transaction to the issuer along with evidence that the charge was valid. The issuer reviews the evidence and either returns the funds to the merchant or lets the reversal stand. Representment is the merchant's main opportunity to recover disputed revenue. ## How representment works [#how-representment-works] ### A chargeback arrives [#a-chargeback-arrives] The issuer posts a provisional reversal and the acquirer or PSP notifies the merchant. The dispute enters the `needs_response` status. See [Dispute state machine](https://docs.chargeflow.io/docs/reference/concepts/dispute-state-machine). ### Evidence is gathered [#evidence-is-gathered] The merchant collects the records that prove the transaction was legitimate and that the cardholder's claim does not hold. The right evidence depends on the reason category. See [Reason codes](https://docs.chargeflow.io/docs/reference/concepts/reason-codes). ### A rebuttal is built [#a-rebuttal-is-built] The evidence is organized into a clear, factual narrative, often called a rebuttal letter, that ties each document directly to the dispute reason. A focused, well-structured rebuttal beats a large pile of unrelated files. ### The response is submitted [#the-response-is-submitted] The rebuttal and evidence are submitted to the acquirer or PSP within the network response window, which forwards them to the issuer. The dispute moves to `under_review`. See [Network timelines](https://docs.chargeflow.io/docs/reference/concepts/network-timelines). ### The issuer decides [#the-issuer-decides] The issuer weighs the evidence and rules `won` or `lost`. If network rules allow, a lost case may escalate to pre-arbitration. ## Evidence categories [#evidence-categories] Evidence falls into a handful of categories. The strongest rebuttals draw from several of them and match the evidence to the dispute reason. | Category | Examples | Strongest against | | ----------------------------- | ------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------- | | Transaction and authorization | Authorization records, AVS and CVV results, 3-D Secure authentication logs, device and IP data. | `fraud` | | Customer identity | Account login history, prior purchase history, matching billing and shipping details, customer profile data. | `fraud`, `canceled_recurring_billing` | | Fulfillment and delivery | Tracking numbers, carrier confirmation, signed delivery proof, digital download or access logs. | `not_received` | | Product and service | Product descriptions, photos, service records, usage logs, terms of service the customer accepted. | `not_as_described` | | Communications | Email and chat threads, support tickets, order confirmations, cancellation and refund records. | `credit_not_processed`, `canceled_recurring_billing` | | Refund and credit | Refund receipts, credit memos, proof a credit was already issued. | `credit_not_processed`, `duplicate_charge` | Submitting delivery proof against a `fraud` dispute does little. Submitting authentication logs and prior-transaction history against the same dispute can win it. Always lead with the evidence that directly answers the cardholder's claim. ## How Chargeflow handles representment [#how-chargeflow-handles-representment] Chargeflow automates the representment process. It ingests the dispute, enriches it with case-relevant signals, and selects the evidence that fits the reason category and historical outcomes. Its agents then compose a coherent rebuttal and submit it to your PSP within the response window. You can strengthen any case by adding targeted evidence. See [Dispute automation engine](https://docs.chargeflow.io/docs/reference/concepts/dispute-automation) for how enrichment works. For step-by-step instructions on adding your own evidence to a dispute, see the [Upload evidence guide](https://docs.chargeflow.io/docs/merchants/automation/upload-evidence). ## Next steps [#next-steps] Add targeted evidence to a dispute. How Chargeflow enriches and builds rebuttals. Match evidence to the dispute reason. The prior-transaction evidence that wins fraud disputes. # Webhooks (https://docs.chargeflow.io/docs/reference/concepts/webhooks) Configure and listen to webhook events produced by Chargeflow to automatically notify your system of changes and trigger reactions. ## Why webhooks [#why-webhooks] When integrating with Chargeflow, your application may need to receive real-time notifications for specific events, such as when a new dispute is created. Webhooks provide this capability by allowing you to register an HTTP endpoint that Chargeflow calls whenever a subscribed event occurs. By using webhooks, your application can respond immediately to new events without relying on periodic API polling. This improves efficiency, reduces unnecessary API calls, and ensures your system remains up to date in real time. ## Enabling webhooks [#enabling-webhooks] Chargeflow does not issue a URL for you to call. You provide an HTTPS endpoint on your own server that accepts `POST` requests and answers `2XX`, and Chargeflow delivers events to it. The handler that endpoint needs is in [Configuring webhooks](#configuring-webhooks); if you would rather not run a server at all, use the [Zapier integration](https://docs.chargeflow.io/docs/merchants/automation/zapier-no-code) instead. Navigate to your [Chargeflow Account Settings](https://app.chargeflow.io/settings). Scroll to the **Developers** section. Generate **API Access Keys** to obtain your API key and enable webhook configuration. Click **+ Add Webhook** to register your first webhook endpoint and subscribe to the events relevant to your application. After registration, Chargeflow sends webhook events as HTTP POST requests to your specified endpoint. A successful delivery is confirmed when your endpoint responds with a `2XX` status code (preferably `200`). If any other response is received, Chargeflow will retry delivery until a `2XX` response is returned or the retry limit is reached. Payload shapes differ by event. `dispute.created` (and the platform `integration.access.error`) arrive wrapped in an envelope - `{type, data, creationDate, webhookId}` - where `type` is the event name and `data` carries the resource. **The three alert events are delivered flat, with no envelope**: their `type` field holds the **alert** type (for example `fraud_warning`), not the event name. See the [event payload reference](https://docs.chargeflow.io/docs/merchants/webhook-events) before writing your handler. ## Event authentication [#event-authentication] Each webhook POST request from Chargeflow includes an HMAC signature in the `X-Chargeflow-Hmac-Sha256` header, derived from the body, path, and method of the request. You can use this signature to verify the authenticity and integrity of the request on your side, ensuring you only react to genuine Chargeflow calls and not unauthorized third-party requests to your public endpoint. We strongly recommend implementing HMAC signature verification in all production systems. The Secret Key used to sign (and verify) webhook requests is available on the [Chargeflow Settings](https://app.chargeflow.io/settings) page alongside other webhook configurations. Note: the API Secret Key is currently the same as the primary API Access Key secret. This page is the canonical home for **verifying inbound webhook deliveries** (below). Signing your own **outbound** requests to the Chargeflow API uses the same HMAC construction and is documented in [Authentication](https://docs.chargeflow.io/docs/reference/api-fundamentals/authentication). ### Verifying a webhook signature [#verifying-a-webhook-signature] ```javascript title="Node.js" const crypto = require('crypto'); function generateHmacSignature(data, secretKey) { const hmac = crypto.createHmac('sha256', secretKey); hmac.update(data); return hmac.digest('hex'); } function verifySignature(req) { const receivedSig = req.headers['x-chargeflow-hmac-sha256']; const method = req.method; const path = req.originalUrl; const body = JSON.stringify(req.body); const dataToSign = `${method}\n${path}\n${body}`; const secret = 'your_secret_key'; // Obtain from Chargeflow Settings const hash = generateHmacSignature(dataToSign, secret); return receivedSig === hash; } ``` ## Configuring webhooks [#configuring-webhooks] ### Register the endpoint [#register-the-endpoint] Register the webhook event in the Chargeflow dashboard (**Settings → Developers → + Add Webhook**). ### Create a handler [#create-a-handler] Create an HTTP endpoint in your server that: 1. Handles `POST` requests with a JSON payload consisting of an event object. 2. Returns a `2XX` status code quickly, before any complex processing that could cause a timeout. ```javascript title="Node.js" // This example uses Express to receive webhooks const express = require('express'); const app = express(); // Match the raw body to content type application/json // If you are using Express v4 - v4.16 you need to use body-parser, not express, to retrieve the request body app.post('/webhook', express.json({ type: 'application/json' }), (request, response) => { const event = request.body; // Optionally validate request signature against body from x-chargeflow-hmac-sha256 header // Handle the event. Only enveloped events (dispute.created) carry the // event name in `type` - alert payloads are flat and their `type` is the // alert type, so route alert events by registering a dedicated URL per event. if (event.type === 'dispute.created') { const disputeCreated = event.data; // Then define and call a method to handle the dispute created event data. // handleDisputeCreated(disputeCreated); } // Return a response to acknowledge receipt of the event response.json({ received: true }); }); app.listen(8000, () => console.log('Running on port 8000')); ``` ### Test your webhook [#test-your-webhook] Once your webhook is configured, you can trigger a test payload to validate your integration. After saving your webhook registration, click the **Test** button next to your endpoint, or access the actions menu for the registered endpoint at any time. ## Webhook event topics [#webhook-event-topics] | Webhook Event | Description | | --------------------------- | ------------------------------------------------------------------------ | | `dispute.created` | Occurs whenever a new dispute is created. | | `alerts.created` | Occurs whenever a new alert is created. | | `alerts.updated` | Occurs whenever an alert outcome is updated. | | `alerts.transaction.linked` | Occurs whenever an alert is linked to its corresponding PSP transaction. | `dispute.created` deliveries wrap the current (`2025-04-01`) dispute resource shape under `data`. See the [`dispute.created` reference](https://docs.chargeflow.io/docs/merchants/webhook-events#dispute-created) for the full payload. That table is the complete list. There is no dispute **update** event today: status changes, evidence submission, and final outcomes are not pushed, so poll `GET /public/2025-04-01/disputes/{disputeId}` (or watch the dashboard) for anything after creation. Broader dispute-event coverage is planned. ## Next steps [#next-steps] Register an endpoint and build a handler. The full payload reference for each event. The HMAC code used to verify webhook signatures. # The language of disputes (https://docs.chargeflow.io/docs/reference/start-here/language-of-disputes) You keep meeting terms like **representment**, **reason code**, and **RDR** and want one page that defines them all. This is that page. Each entry is one or two lines; where a concept deserves depth, the entry links to its canonical page. ## The core event [#the-core-event] * **Dispute** - the umbrella term for a cardholder contesting a charge, at any stage. The Chargeflow API models everything as a dispute with a status. * **Chargeback** - a dispute that has been formally filed: the issuer provisionally reverses the charge and the merchant must respond or forfeit. See [Chargeback lifecycle](https://docs.chargeflow.io/docs/reference/concepts/chargeback-lifecycle). * **Pre-chargeback alert** - an early warning (via Ethoca or Verifi) that a cardholder has complained, sent before the chargeback posts. See [Alerts model](https://docs.chargeflow.io/docs/reference/concepts/alerts-model). * **Reason code** - the network-assigned code stating **why** the cardholder disputes the charge (fraud, product not received, and so on). See [Reason codes](https://docs.chargeflow.io/docs/reference/concepts/reason-codes). ## The parties [#the-parties] * **Cardholder** - the customer who paid and is now disputing. * **Issuer (issuing bank)** - the cardholder's bank; it files the dispute and makes the final ruling. * **Acquirer (acquiring bank)** - the merchant's bank; it receives the chargeback and forwards the merchant's response. * **Card network** - Visa, Mastercard, and peers; they route the case and set the rules and timelines. * **PSP (payment service provider)** - Stripe, PayPal, and peers; the merchant-facing layer Chargeflow connects to. ## Fighting a dispute [#fighting-a-dispute] * **Representment** - the merchant's formal rebuttal: evidence plus a narrative, submitted through the acquirer to the issuer. See [Representment and evidence](https://docs.chargeflow.io/docs/reference/concepts/representment-and-evidence). * **Evidence** - the documents and signals backing the rebuttal: receipts, delivery proof, authentication logs, customer communications. * **Enrichment** - adding targeted signals (order data, communications, subscription history) to a dispute so the evidence is stronger. See [Enrich a dispute](https://docs.chargeflow.io/docs/merchants/automation/enrich-a-dispute). * **Compelling Evidence 3.0 (CE 3.0)** - a Visa program that lets qualifying prior transactions prove a disputed one was legitimate. See [CE 3.0 eligibility](https://docs.chargeflow.io/docs/reference/concepts/ce-3.0-eligibility). * **Arbitration / pre-arbitration** - the escalation path when a ruling is contested; the network itself adjudicates. Rare and slow. ## Preventing a dispute [#preventing-a-dispute] * **Deflection** - resolving a cardholder complaint (usually by refunding) inside the pre-chargeback window so no chargeback ever posts. * **Ethoca** - Mastercard's alert network, covering fraud and customer-dispute alerts across brands. See [Ethoca](https://docs.chargeflow.io/docs/reference/integrations#mastercard-ethoca). * **Verifi CDRN** - Visa's Cardholder Dispute Resolution Network: alerts routed to the merchant for action. * **Verifi RDR** - Rapid Dispute Resolution: eligible Visa disputes auto-resolve against merchant-defined rules, no manual action. See [Verifi RDR](https://docs.chargeflow.io/docs/reference/integrations#visa-verifi-rdr). * **Chargeflow Network** - Chargeflow's own matching layer that links alerts to transactions and automates the resolution flow. ## Fraud vocabulary [#fraud-vocabulary] * **Third-party fraud** - the card or identity was actually stolen; the cardholder is a victim. * **First-party ("friendly") fraud** - the cardholder made the purchase but disputes it anyway. * **Dispute ratio** - disputes as a share of transactions; networks monitor it and penalize merchants who exceed thresholds. ## Chargeflow vocabulary [#chargeflow-vocabulary] * **Prevent / Alerts / Automation / Connect** - the four products. See [Product model](https://docs.chargeflow.io/docs/reference/start-here/product-model). * **Dispute status** - where a dispute sits in Chargeflow's state machine. See [Dispute state machine](https://docs.chargeflow.io/docs/reference/concepts/dispute-state-machine). * **EaaS (Evidence-as-a-Service)** - the Connect model where your workflow stays yours and Chargeflow generates the evidence. See [What is EaaS?](https://docs.chargeflow.io/docs/platforms/eaas/introduction) * **Co-Branded** - the Connect model where Chargeflow's interface carries your logo, colors and domain. See [Co-Branded](https://docs.chargeflow.io/docs/platforms/overview#co-branded). * **White-Label** - the Connect model (BETA, previously "Chargeflow Embedded") where the dispute product carries your own name, UI and pricing. See [White-Label](https://docs.chargeflow.io/docs/platforms/chargeflow-embedded/overview). * **AaaS (Alerts-as-a-Service)** - **Soon.** The Connect model where Chargeflow sends the alerts and your platform issues the refund. See [Platforms overview](https://docs.chargeflow.io/docs/platforms/overview#alerts-as-a-service-aaas). # Product model (https://docs.chargeflow.io/docs/reference/start-here/product-model) You are deciding what to integrate. This page gives you the map: Chargeflow is not one product but a suite, each part acting at a different point in a transaction's life. Everything else in these docs assumes this vocabulary. ## The product suite [#the-product-suite] | Product | Tier | Acts when | In one line | | -------------- | ---- | -------------------------- | ------------------------------------------------------------------------------------------------------------------ | | **Prevent** | 1 | Before you ship | A pre-fulfillment risk score and a recommended action, so risky orders never become disputes. | | **Alerts** | 1 | Before the chargeback | Deflects filed complaints via Verifi RDR / CDRN and Ethoca alerts before they post as chargebacks. | | **Automation** | 1 | Once a chargeback is filed | Agentic representment: builds, enriches, and submits the evidence response on your behalf. | | **Insights** | 1 | Continuously | Performance monitoring across every connected processor, with proactive alerts before a ratio crosses a threshold. | | **Connect** | 2 | Horizontal | "Chargeflow for Platforms": deliver the whole stack to your merchants, under your own brand. | Read the first four as a timeline and the fifth as a delivery model: | Stage | Post-auth, pre-fulfilment | Pre-chargeback | Post-chargeback | Across all of it | | ----------- | ------------------------- | --------------------- | ------------------- | ---------------------- | | **Product** | Prevent | Alerts | Automation | Insights | | **Job** | Friendly-fraud prevention | Chargeback prevention | Chargeback recovery | Performance monitoring | Prevent is live today via the Chargeflow dashboard and the Shopify app. Its public API is not yet available - see [Prevent](https://docs.chargeflow.io/docs/merchants/prevent) for what you can do now. ## Why several products, not one [#why-several-products-not-one] Each product catches a dispute one stage earlier than the next, and earlier is always cheaper: a blocked risky order costs nothing, a deflected alert costs the refund, a fought chargeback costs time and a fee even when you win. The products compound - what Automation learns from fought disputes sharpens what Alerts deflects and what Prevent flags, and Insights is where you see whether that is working. You can adopt any one alone; they are better together. See [Transaction lifecycle](https://docs.chargeflow.io/docs/reference/start-here/transaction-lifecycle) for exactly where each product sits on the timeline. ## Connect: the horizontal layer [#connect-the-horizontal-layer] Connect is Chargeflow for ISVs, platforms and PSPs rather than for individual merchants - a B2B2B product, where you deliver the dispute stack to the merchants you already serve, under your brand. It ships in four delivery models, differing in who owns the brand and who takes the action: | Model | Status | In one line | | -------------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | | **EaaS** - Evidence-as-a-Service | Available | You keep the workflow; Chargeflow returns bank-ready evidence on demand. See [What is EaaS?](https://docs.chargeflow.io/docs/platforms/eaas/introduction) | | **Co-Branded** | Available | Chargeflow's interface with your logo, colors and domain - the fastest brand-safe launch. See [Co-Branded](https://docs.chargeflow.io/docs/platforms/overview#co-branded). | | **White-Label** | Beta | Your product name, UI and pricing, Chargeflow invisible end to end. See [White-Label](https://docs.chargeflow.io/docs/platforms/chargeflow-embedded/overview). | | **AaaS** - Alerts-as-a-Service | Soon | Chargeflow sends the alerts, your platform issues the refund. See [Platforms overview](https://docs.chargeflow.io/docs/platforms/overview#alerts-as-a-service-aaas). | Each model runs the same engine, and each can run on auto-pilot or co-pilot per merchant segment. See the [Platforms overview](https://docs.chargeflow.io/docs/platforms/overview) for which model fits your business. ## Where each product lives in these docs [#where-each-product-lives-in-these-docs] Pre-fulfillment risk scoring: approve, verify, or cancel. Pre-chargeback deflection: RDR, CDRN, Ethoca. Dispute automation - most of the merchant docs. Chargeback and payment monitoring across processors. The platforms pillar: EaaS, Co-Branded and White-Label. ## How recovery actually happens [#how-recovery-actually-happens] The model above says which product acts when. If what you need is the mechanism - what happens between a chargeback being filed and the money coming back - read [How recovery works](https://docs.chargeflow.io/docs/reference/concepts/how-recovery-works), then [How our AI works](https://docs.chargeflow.io/docs/reference/concepts/how-our-ai-works) for the agent architecture behind it. ## Next steps [#next-steps] The five stages and which product acts where. The vocabulary the rest of the docs uses. Authenticate and make your first call. # Transaction lifecycle (https://docs.chargeflow.io/docs/reference/start-here/transaction-lifecycle) You want to know where in a transaction's life Chargeflow can act for you. Every transaction that ends in a dispute passes through the same five stages, and each Chargeflow product owns exactly one window on that timeline. ## The five stages [#the-five-stages] | # | Stage | What happens | Who acts | | - | ------------------------- | -------------------------------------------------------------------------------------------------------------- | -------------- | | 1 | **Checkout & auth** | The cardholder pays; the issuer authorizes the charge. | Your PSP | | 2 | **Pre-fulfillment** | The order is placed but not yet shipped or delivered - the last moment a risky order can be stopped for free. | **Prevent** | | 3 | **Pre-chargeback window** | The cardholder complains to their issuer; there is a short window to resolve before a formal chargeback posts. | **Alerts** | | 4 | **Chargeback filed** | The issuer posts the chargeback; funds are provisionally reversed and the response clock starts. | **Automation** | | 5 | **Dispute outcome** | The issuer rules for the merchant or the cardholder; Chargeflow reports the result. | **Automation** | [Connect](https://docs.chargeflow.io/docs/platforms/overview) is horizontal: it embeds stages 4-5 into your own platform for your merchants. ## Reading the timeline [#reading-the-timeline] * **Earlier is cheaper.** A risky order caught at stage 2 costs nothing; an alert resolved at stage 3 costs a refund; a chargeback fought at stage 4 costs a fee and weeks of waiting, win or lose. * **The windows are short and network-defined.** The pre-chargeback alert window is short - act on alerts as they arrive (see [Alerts model](https://docs.chargeflow.io/docs/reference/concepts/alerts-model)); the representment window varies by network and reason code. The canonical figures live in [Network timelines](https://docs.chargeflow.io/docs/reference/concepts/network-timelines). * **Every transition emits an event.** Chargeflow surfaces stage transitions as webhooks (`dispute.created`, `alerts.created`, and so on) so your systems can react in real time. See [Webhooks](https://docs.chargeflow.io/docs/reference/concepts/webhooks). ## Going deeper [#going-deeper] The mechanics of stages 4-5 - the parties, the provisional reversal, representment, arbitration - are covered once, canonically, in the concepts section: The full stage-by-stage flow through issuer, network, and acquirer. Every dispute status and the transitions between them. How the pre-chargeback window works and the two integration models. The 3+1 products that act on this timeline. # Enrichment by business model (https://docs.chargeflow.io/docs/merchants/automation/enrich-a-dispute/by-business-model) The evidence that wins a dispute depends on what you sell. A SaaS charge has no tracking number, so the case rests on proving the customer signed up, used the service, and knew the billing terms. A physical-goods charge turns on what was ordered and where it was delivered. Everything below is sent to the same endpoint: ``` PATCH https://api.chargeflow.io/public/2025-04-01/disputes/{disputeId} ``` Use the Chargeflow dispute ID (`dispute.id`) from the `dispute.created` webhook as the path parameter. See [Enrich a dispute](https://docs.chargeflow.io/docs/merchants/automation/enrich-a-dispute) for upsert semantics and the array merge behavior that applies to `products[]` and `fulfillments[]`. ## Find your evidence set [#find-your-evidence-set] SaaS disputes present unique challenges. Unlike physical goods, there is no tracking number or delivery confirmation: the challenge is proving that the customer knowingly signed up, actively used the service, and authorized the recurring charge. These data points are the most effective evidence for `fraud`, `canceled_recurring_billing`, and `credit_not_processed`. Issuers adjudicating a SaaS dispute look for signals that: 1. The customer intentionally created an account and signed up for the service. 2. The customer actively used the service after sign-up. 3. The customer was aware of the recurring billing terms. 4. If a subscription was canceled, the cancellation was processed correctly. Without this data, your response relies solely on generic transaction metadata, which is rarely enough to win. **Subscription information** Send subscription data to show the charge is part of a legitimate, established billing relationship. **Key fields** (`subscription` object): | Field | Description | Example | | --------------------------- | ------------------------------------------------ | ---------------------- | | `source_id` | Your internal subscription ID | `sub_1234567890` | | `start_date` | When the subscription started | `2024-01-15T00:00:00Z` | | `frequency` | Billing interval: `day`, `week`, `month`, `year` | `month` | | `frequency_count` | Number of intervals per billing cycle | `1` | | `status` | Current status: `active`, `inactive`, `canceled` | `active` | | `plan_name` | The plan the customer is on | `Pro Plan` | | `pricing_model` | `fixed_price` or `usage_base` | `fixed_price` | | `trial_start` / `trial_end` | Trial period dates if applicable | - | | `cancellation_date` | When the cancellation was requested | - | | `cancellation_reason` | Why the subscription was canceled | `too_expensive` | A history of successful payments on the same subscription strongly demonstrates an ongoing, consented billing relationship: link past charges via [transaction enrichment](https://docs.chargeflow.io/docs/merchants/automation/enrich-a-dispute) with the `subscription_id` reference. **Customer activity logs** Activity logs are among the most powerful evidence for SaaS fraud and unauthorized transaction disputes. They prove the customer's device or session was actively used before and after the disputed charge. | Event | Explanation | Importance | | -------- | --------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | | Sign up | Sign-up timestamp, IP address, and device information | Proves the customer is familiar with the merchant and their service | | Login | Login timestamp and IP address; send multiple events when available | Proves the customer intentionally used the service | | Purchase | Purchase data for the service or product; send multiple events if available | Establishes that the customer knows the merchant, is familiar with the service quality, and authorized the transaction | Send multiple login events if available. A pattern of logins over time, including events close to the disputed charge date, is significantly more compelling than a single event. Activity logs are attached as a file with the [Upload evidence endpoint](https://docs.chargeflow.io/docs/merchants/automation/upload-evidence) using `evidenceUploadCategory: "additional_evidence"`. Export the events with a timestamp, IP address, and user agent per event, and describe what the export shows in the `content` field. E-commerce merchants selling physical goods face disputes most commonly around `not_received`, `not_as_described`, and `fraud`. Winning these requires proving what was ordered, that it shipped to the correct address, and that it was delivered. **Order data** Order data establishes what the customer purchased and at what price. It counters `not_as_described` claims and demonstrates that the customer had access to accurate product information. **Key fields** (`order.products[]`): | Field | API path | Description | | ------------------- | ------------------------ | -------------------------------------------------- | | Product name | `products[].name` | The name of the product | | Product description | `products[].description` | Detailed description matching what was advertised | | Product image URL | `products[].image_url` | URL to the product image shown at time of purchase | | Price | `products[].price` | Unit price at time of purchase | | Quantity | `products[].quantity` | Number of units ordered | | Product type | `products[].type` | `physical_good` or `digital_good` | Always include the product image URL when available. Issuers reviewing disputes are not familiar with your catalog: a clear product image alongside the description makes the evidence immediately compelling. **Fulfillment information** Fulfillment data is the core evidence for `not_received` disputes. A tracking number with a confirmed delivery scan is often sufficient to resolve these cases. **Key fields** (`order.fulfillments[]`): | Field | API path | Description | | --------------- | ------------------------------------ | ------------------------------------------- | | Tracking number | `fulfillments[].tracking_number` | Carrier tracking number | | Courier | `fulfillments[].courier` | Carrier name (e.g., `FedEx`, `UPS`, `USPS`) | | Shipped at | `fulfillments[].shipped_at` | ISO 8601 timestamp when the item shipped | | Shipping method | `fulfillments[].shipping_line_title` | Description of the shipping service | For high-value shipments, also upload a proof of delivery document using the [Upload evidence endpoint](https://docs.chargeflow.io/docs/merchants/automation/upload-evidence) with `evidenceUploadCategory: "tracking_information"`. **Subscription information (if applicable)** If you run a subscription or auto-ship model, include subscription data to demonstrate the customer consented to recurring charges: `frequency` / `frequency_count`, `status`, `start_date`, and the charge history linked via [transaction enrichment](https://docs.chargeflow.io/docs/merchants/automation/enrich-a-dispute). The SaaS block above lists the full field set; the same fields apply here. **Full e-commerce payload** ```json title="Request body" { "order": { "products": [ { "name": "Wireless Headphones", "id": "prod_12345", "type": "physical_good", "quantity": 1, "description": "Noise-canceling wireless headphones with Bluetooth 5.2 connectivity and 30-hour battery life.", "image_url": "https://example.com/images/products/headphones.jpg", "price": 150 } ], "fulfillments": [ { "product_id": "prod_12345", "shipped_at": "2025-01-26T18:00:00Z", "shipping_line_title": "FedEx 2-Day Express", "shipping_method_price": 0, "tracking_number": "1Z999AA10123456789", "courier": "FedEx" } ], "shipping_address": { "name": "John Doe", "line1": "123 Main Street", "line2": "Apt 4B", "city": "New York", "country": "US", "state": "NY", "zip_code": "10001" } } } ``` ## Customer communication [#customer-communication] Whatever you sell, a record of your interactions with the customer strengthens the response: conversations where you provided shipping updates, where the customer acknowledged the service, asked for a refund, or where you offered a resolution before the dispute was filed. * **Structured messages**: use the [Customer communication endpoint](https://docs.chargeflow.io/docs/merchants/automation/enrich-a-dispute/customer-communications) to send helpdesk conversations programmatically. * **File upload**: use the [Upload evidence endpoint](https://docs.chargeflow.io/docs/merchants/automation/upload-evidence) with `evidenceUploadCategory: "customer_communication"` to attach a screenshot. ## How to send this data [#how-to-send-this-data] | Data | Endpoint | | -------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Order, products, fulfillments, transaction context | [`PATCH /public/2025-04-01/disputes/{disputeId}`](https://docs.chargeflow.io/docs/merchants/automation/enrich-a-dispute) | | Subscription record | [`POST /public/2025-04-01/disputes/{disputeId}/subscription`](https://docs.chargeflow.io/docs/api/2025-04-01/merchants/disputes/public/2025-04-01/disputes/disputeid/subscription/post) (required: `source_id`, `created_at`, `start_date`, `frequency`, `frequency_count`) | | Activity logs | [`POST /public/2025-04-01/disputes/{disputeId}/evidence`](https://docs.chargeflow.io/docs/merchants/automation/upload-evidence) (file upload, `evidenceUploadCategory: "additional_evidence"`) | | Communication records | [`POST /public/2025-04-01/customer-communication`](https://docs.chargeflow.io/docs/merchants/automation/enrich-a-dispute/customer-communications) | ### Confirm it landed [#confirm-it-landed] Each call returns the updated dispute, and the record then appears on that dispute in the Chargeflow dashboard. To re-check later, read the dispute back with `GET /public/2025-04-01/disputes/{disputeId}`: that response is the authoritative view of what Chargeflow stored. ## Next steps [#next-steps] Full endpoint reference including array merge behavior. Structured helpdesk records. Proof of delivery and communication screenshots. Trigger enrichment flows automatically on dispute.created. # Industry Enrichment (https://docs.chargeflow.io/docs/merchants/automation/enrich-a-dispute/by-industry) Industry Enrichment via the `universal_order` field is an upcoming addition to the Enrich Dispute API. The endpoints and schemas described here are not yet in the API reference. This section documents the model ahead of release so you can plan your integration. To enrich disputes today, use the current Enrich a Dispute guide, which covers the live `order` and `transaction` payloads. `PATCH /public/2025-04-01/disputes/{disputeId}` You are a merchant enriching a dispute for your industry. Every dispute is a story: the cardholder tells theirs to the issuer, and your job is to give Chargeflow the data to tell yours. Send all your evidence in one `universal_order` block matched to your vertical, and Chargeflow builds reason-code-aware evidence automatically. No explicit type declaration is needed, just include the right block. Industry Enrichment via `universal_order` is the most up-to-date way to enrich disputes. It builds reason-code-aware narratives from a single payload tailored to your vertical. Find yours in [Choose your block](#choose-your-block). ## How enrichment works [#how-enrichment-works] 1. **Your API call** - send a `PATCH` with `universal_order` containing your order data and the relevant industry block. 2. **Field analysis** - Chargeflow reads the industry fields and identifies the commercial story. 3. **Evidence builder** - Chargeflow crafts a narrative from your data, optimized for the dispute's reason code. 4. **Submission** - the completed evidence package is submitted to the issuer on your behalf. ## Quick start [#quick-start] Enrich an accommodation dispute in under five minutes. Swap the `accommodation` block for your industry's block (see [Choose your block](#choose-your-block)), keeping `customer` and `order` as the anchors. ```bash title="Terminal" curl -X PATCH https://api.chargeflow.io/public/2025-04-01/disputes/dp_01HXYZ \ -H "x-api-key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "universal_order": { "customer": { "email": "sarah.chen@example.com", "name": "Sarah Chen" }, "order": { "external_id": "BK-20260315-8842", "currency": "USD", "amount": 847.50, "ordered_at": "2026-02-10T14:23:00Z", "status": "completed" }, "accommodation": { "property_name": "The Oceanview Hotel", "property_type": "hotel", "booked_check_in": "2026-03-15", "booked_check_out": "2026-03-18", "actual_check_in": "2026-03-15T16:02:00Z" } } }' ``` Once the request succeeds, Chargeflow detects the industry from the block, analyzes the fields against the reason code, builds a tailored narrative, and submits it to the issuer. Disputes are re-enrichable by design. Call the endpoint again with new evidence whenever you have it. Chargeflow uses upsert semantics: send only the fields you have and they are added or updated. These fields are mutually exclusive. A request with both returns a `400`. The `transaction` field can be sent alongside `universal_order` without issue. See [Error responses](#error-responses). ## Universal fields [#universal-fields] Every `universal_order` payload shares the same outer envelope. The industry block (`accommodation`, `flight`, `dining`, etc.) tells Chargeflow the commercial story; the envelope carries the cross-industry data. You never specify the type explicitly. Send whatever data you have. No required fields. Chargeflow builds the best narrative from whatever you provide. | Field | Type | How Chargeflow uses it | | -------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `customer` | object | Cardholder identity: `email`, `name`, `phone`, `customer_since`. Long tenure undermines "I never signed up"; a matching name ties the order to the card. | | `order` | object | The commercial story: `external_id`, `amount`, `currency`, `ordered_at`, `status`, `confirmation_code`, `ip_address`. | | `charges[]` | array | Itemized breakdown: `charge_type` (`tax`, `fee`, `tip`, `deposit`, `discount`, `credit`), `amount`, `description`. | | `policies[]` | array | Consent records: `policy_type`, `consented_at`, `policy_url`, `acceptance_method`. | | `activities[]` | array | Event log of `event_name` + `event_at` pairs (snake\_case names like `booking_confirmed`, `check_in`, `login`). A timestamped audit trail of customer engagement. | | `addresses[]` | array | Named by `kind`: `billing`, `shipping`, `property`, `venue`, `pickup`, `dropoff`, `provider`, `other`. Supports `latitude`/`longitude` for GPS precision. | | `refunds[]` | array | Refund records: `reason`, `amount`, `refunded_at`, `refund_method`. | The `order` object also supports confirmation fields that strengthen evidence: | Field | Type | Purpose | | ---------------------- | --------- | ---------------------------------------------------------------- | | `confirmation_code` | string | The booking or order reference the customer received. | | `confirmation_methods` | array | How confirmation was sent, e.g. `["email"]`, `["email", "sms"]`. | | `confirmation_sent_to` | string | The email or phone the confirmation was delivered to. | | `confirmation_sent_at` | timestamp | When the confirmation was dispatched. | ### Recommended data points [#recommended-data-points] A few data points help win most dispute reasons across every industry: 1. **Customer identity** - `name` and `email` show you hold accurate records of your customers. 2. **Addresses** - `ip_address`, shipping, and billing addresses prove delivery, verify billing/shipping match, and confirm the buyer's location. 3. **Order and product information** - descriptions, prices, discounts, refunds, and images show the customer had clear information about the purchase. ## Choose your block [#choose-your-block] Search your industry or pick a card. Each block opens with what it covers, the fields that win disputes, and a full payload you can copy. If your platform spans several domains, send the block that matches the specific transaction being disputed: an OTA uses Accommodation for hotel bookings and Flights for air tickets, from the same platform. **When to use:** a customer pays to occupy a physical space for a defined period. **Industries:** hotels & resorts, vacation rentals, hostels, serviced apartments, bed & breakfasts, campgrounds & glamping, timeshare resorts. **Highest-impact:** `actual_check_in` plus cancellation `policies[].consented_at` resolve the vast majority of accommodation disputes. If no cancellation request appears in `activities[]`, that absence is itself evidence. ```json title="Accommodation payload" { "universal_order": { "customer": { "name": "Sarah Chen", "email": "sarah.chen@example.com", "customer_since": "2023-06-01" }, "order": { "external_id": "BK-20260315-8842", "amount": 847.5, "currency": "USD", "ordered_at": "2026-02-10T14:23:00Z", "status": "completed", "confirmation_code": "OVH-8842", "confirmation_methods": ["email"], "confirmation_sent_to": "sarah.chen@example.com", "confirmation_sent_at": "2026-02-10T14:23:05Z" }, "accommodation": { "property_name": "The Oceanview Hotel", "property_type": "hotel", "room_type": "King Ocean View", "booked_check_in": "2026-03-15", "booked_check_out": "2026-03-18", "actual_check_in": "2026-03-15T16:02:00Z", "actual_check_out": "2026-03-18T10:41:00Z", "number_of_nights": 3, "guest_name": "Sarah Chen", "guests_count": 2, "rate_per_night": 265.0, "total_accommodation_cost": 795.0, "is_no_show": false }, "policies": [ { "policy_type": "cancellation", "consented_at": "2026-02-10T14:23:00Z", "policy_url": "https://oceanview.example.com/cancellation", "acceptance_method": "checkbox" } ], "activities": [ { "event_name": "booking_confirmed", "event_at": "2026-02-10T14:23:05Z" }, { "event_name": "check_in", "event_at": "2026-03-15T16:02:00Z" }, { "event_name": "check_out", "event_at": "2026-03-18T10:41:00Z" } ] } } ``` **Other values:** `property_type` also takes `vacation_rental`, `hostel`, `b_and_b`, and the other property kinds. Cancellation and refund terms live in `policies[]`. **When to use:** a customer pays for scheduled air transportation between two points. **Industries:** commercial airlines, charter flights, private aviation, helicopter tours, air ambulance, scenic flights. **Highest-impact:** `boarded_at`, `ticket_number`, and `actual_departure` are the core trio - a boarding timestamp with a ticket number and actual departure is nearly irrefutable. `actual_departure`/`actual_arrival` also defeat "flight was canceled" claims. ```json title="Flight payload" { "universal_order": { "customer": { "name": "Daniel Moore", "email": "d.moore@example.com" }, "order": { "external_id": "PNR-4KX9QT", "amount": 612.3, "currency": "USD", "ordered_at": "2026-01-22T09:12:00Z", "status": "completed", "confirmation_code": "4KX9QT", "confirmation_methods": ["email", "sms"] }, "flight": { "airline_name": "Northwind Air", "airline_code": "NWA", "flight_number": "NW412", "ticket_number": "0142398871234", "departure_airport": "KJFK", "arrival_airport": "KSFO", "booked_departure": "2026-02-14T07:40:00Z", "booked_arrival": "2026-02-14T14:05:00Z", "actual_departure": "2026-02-14T07:56:00Z", "actual_arrival": "2026-02-14T14:12:00Z", "passenger_name": "Daniel Moore", "cabin_class": "economy", "seat_number": "22A", "fare_amount": 612.3, "checked_bags_count": 1, "is_checked_in": true, "boarded_at": "2026-02-14T07:21:00Z", "is_no_show": false }, "activities": [ { "event_name": "online_check_in", "event_at": "2026-02-13T08:02:00Z" }, { "event_name": "boarding_pass_scanned", "event_at": "2026-02-14T07:21:00Z" } ] } } ``` **Other values:** `cabin_class` also takes `premium_economy`, `business`, `first`, `other`. `airline_code` is the 3-char ICAO code, the airports the 4-char one. **When to use:** a customer pays for food or beverages prepared and served, on-premise or delivered. **Industries:** restaurants, cloud kitchens, catering, food delivery platforms, meal kit subscriptions, wine & spirits clubs, bars & lounges. **Highest-impact:** `reservation_at`, `guest_name`, and a `tip` in `charges[]` - a customer-added gratuity strongly implies voluntary engagement and customers who tip then dispute rarely win. ```json title="Dining payload" { "universal_order": { "customer": { "name": "Maya Ortiz", "email": "maya.ortiz@example.com" }, "order": { "external_id": "RSV-77213", "amount": 214.8, "currency": "USD", "ordered_at": "2026-03-02T21:44:00Z", "status": "completed" }, "dining": { "venue_name": "Trattoria Nove", "venue_type": "restaurant", "reservation_at": "2026-03-02T19:30:00Z", "guests_count": 4, "guest_name": "Maya Ortiz", "meal_type": "dinner", "total_dining_cost": 178.0, "price_per_guest": 44.5, "is_no_show": false }, "charges": [ { "charge_type": "tip", "amount": 32.0, "description": "Table gratuity" }, { "charge_type": "tax", "amount": 4.8, "description": "Sales tax" } ], "activities": [ { "event_name": "reservation_confirmed", "event_at": "2026-02-27T10:15:00Z" }, { "event_name": "table_seated", "event_at": "2026-03-02T19:34:00Z" } ] } } ``` **Other values:** `venue_type` also takes `bar`, `cafe`, `catering`, `food_truck`, `other`. `meal_type` takes `breakfast`, `brunch`, `lunch`, `afternoon_tea`, `dinner`, `drinks`, `tasting_menu`, `other`. Gratuity goes in `charges[]` (`charge_type: tip`), delivery fees too (`charge_type: fee`). **When to use:** a customer pays for a physical product shipped to an address. **Industries:** online retail, marketplace sellers, subscription boxes, print-on-demand, wholesale & B2B, dropshipping. **Highest-impact:** `items[].tracking_number` is the most powerful field - Chargeflow automatically fetches carrier data, delivery status, and proof of delivery (no manual tracking events needed). A delivered status with a matching billing/shipping address is near-irrefutable for "item not received". ```json title="E-commerce payload" { "universal_order": { "customer": { "name": "Priya Raman", "email": "priya.raman@example.com", "customer_since": "2022-11-04" }, "order": { "external_id": "ORD-58412", "amount": 236.4, "currency": "USD", "ordered_at": "2026-04-02T17:08:00Z", "status": "completed", "ip_address": "203.0.113.42" }, "items": [ { "type": "physical_good", "name": "Trailhead Jacket", "sku": "TH-JKT-M-OLV", "quantity": 1, "unit_price": 189.0, "total_price": 189.0, "url": "https://shop.example.com/products/trailhead-jacket", "image_url": "https://cdn.example.com/trailhead-jacket.jpg", "tracking_number": "1Z999AA10123456784" } ], "addresses": [ { "kind": "shipping", "line1": "418 Maple Street", "city": "Austin", "postal_code": "78701", "country": "US" }, { "kind": "billing", "line1": "418 Maple Street", "city": "Austin", "postal_code": "78701", "country": "US" } ] } } ``` **Other values:** `items[].type` also takes `digital_good`, `food_delivery`, `grocery`, `other`. Send both `addresses[]` kinds and the `ip_address` so billing, shipping, and buyer location line up. **When to use:** a customer pays for a non-physical product delivered electronically. **Industries:** online courses, software licenses, digital art & NFTs, e-books & audiobooks, stock photos & media, in-app purchases, gaming credits, digital subscriptions. **Highest-impact:** `access_granted_at` and `download_url` prove delivery. Combined with `activities[]` showing use (content\_accessed, lessons completed, files downloaded), the line between "delivered" and "used" becomes your biggest weapon. ```json title="Digital goods payload" { "universal_order": { "customer": { "name": "Tomás Alvarez", "email": "tomas@example.com", "customer_since": "2025-09-19" }, "order": { "external_id": "LIC-2026-0417", "amount": 149.0, "currency": "USD", "ordered_at": "2026-04-17T12:31:00Z", "status": "completed", "ip_address": "198.51.100.77" }, "items": [ { "type": "digital_good", "name": "Advanced React Patterns (course)", "quantity": 1, "unit_price": 149.0, "total_price": 149.0, "url": "https://learn.example.com/courses/advanced-react", "download_url": "https://learn.example.com/dl/arp-workbook.pdf", "access_granted_at": "2026-04-17T12:31:22Z" } ], "activities": [ { "event_name": "content_accessed", "event_at": "2026-04-17T12:34:10Z" }, { "event_name": "lesson_completed", "event_at": "2026-04-18T09:02:00Z" }, { "event_name": "workbook_downloaded", "event_at": "2026-04-18T09:26:00Z" } ] } } ``` **Other values:** `items[].type` is `digital_good` here. Keep appending usage `activities[]` as they happen, and send `customer_since` and `ip_address`. **When to use:** a customer pays to temporarily use an asset they do not own. **Industries:** car rental, equipment rental, boat & RV rental, tool rental, camera & electronics, costume & formalwear, storage units. **Highest-impact:** `policies[].policy_url` + `consented_at` (a signed, timestamped agreement) is decisive. For damage disputes, pair `has_damage_report` with `actual_pickup` vs. `actual_return`; late returns justify overage fees. ```json title="Rental payload" { "universal_order": { "customer": { "name": "Elena Petrova", "email": "e.petrova@example.com" }, "order": { "external_id": "RNT-99114", "amount": 521.75, "currency": "USD", "ordered_at": "2026-05-01T15:00:00Z", "status": "completed", "confirmation_code": "CW-99114" }, "rental": { "rental_type": "car", "provider_name": "Citywide Rentals", "booked_pickup": "2026-05-08T09:00:00Z", "booked_return": "2026-05-13T09:00:00Z", "actual_pickup": "2026-05-08T09:22:00Z", "actual_return": "2026-05-13T13:47:00Z", "duration_days": 5, "renter_name": "Elena Petrova", "rental_class": "Midsize SUV", "rate_per_day": 89.0, "total_rental_cost": 445.0, "protection_and_coverages": ["damage_waiver", "liability_insurance"], "has_damage_report": false, "is_no_show": false }, "policies": [ { "policy_type": "rental_agreement", "consented_at": "2026-05-08T09:22:00Z", "policy_url": "https://citywide.example.com/agreements/99114.pdf", "acceptance_method": "signature" } ], "charges": [ { "charge_type": "fee", "amount": 76.75, "description": "Late return fee" } ], "addresses": [ { "kind": "pickup", "line1": "1200 Airport Blvd", "city": "Denver" }, { "kind": "dropoff", "line1": "1200 Airport Blvd", "city": "Denver" } ] } } ``` **Other values:** `rental_type` also takes `motorcycle`, `rv`, `boat`, `bicycle`, `scooter`, `equipment`, `storage`, `clothing`, `furniture`, `property`, `other`. The signed agreement goes in `policies[]` (`rental_agreement`). **When to use:** a customer pays to be moved point-to-point, or to have something delivered. **Industries:** rideshare, taxi services, airport shuttles, courier & same-day delivery, moving services, limousine services, medical transport. **Highest-impact:** GPS coordinates on the pickup/dropoff `addresses[]` are the strongest evidence - machine-recorded, verifiable, and nearly impossible to dispute. Pair with `actual_pickup` and `actual_dropoff`. ```json title="Transportation payload" { "universal_order": { "customer": { "name": "Jordan Blake", "email": "jordan.blake@example.com" }, "order": { "external_id": "TRIP-7712094", "amount": 44.25, "currency": "USD", "ordered_at": "2026-06-11T22:14:00Z", "status": "completed" }, "transportation": { "transport_type": "ride_share", "provider_name": "Metro Ride", "booked_pickup": "2026-06-11T22:10:00Z", "actual_pickup": "2026-06-11T22:14:38Z", "actual_dropoff": "2026-06-11T22:41:06Z", "passenger_name": "Jordan Blake", "passengers_count": 1, "driver_name": "A. Nadir", "service_class": "standard", "distance": 12.4, "duration_minutes": 27, "fare_amount": 38.75, "is_completed": true }, "charges": [ { "charge_type": "tip", "amount": 5.5, "description": "Rider tip in app" } ], "addresses": [ { "kind": "pickup", "line1": "77 Harbor Way", "city": "Seattle", "country": "US", "latitude": 47.6062, "longitude": -122.3321 }, { "kind": "dropoff", "line1": "3410 Pine Ridge Rd", "city": "Bellevue", "country": "US", "latitude": 47.6101, "longitude": -122.2015 } ] } } ``` **Other values:** `transport_type` also takes `taxi`, `train`, `bus`, `ferry`, `shuttle`, `limousine`, `other`. Put `latitude`/`longitude` on both `addresses[]`, rider tips in `charges[]`. **When to use:** a customer pays for human labor, expertise, or ongoing software access. **Industries:** SaaS platforms, consulting firms, accounting & legal, cleaning & home services, personal training, tutoring, salon & spa, repair services. **Highest-impact:** `activities[]` is the most powerful SaaS evidence - multiple logins and usage events after the charge date prove the customer used the service. Send as many as you can: logins, feature usage, API calls, settings changes, report exports. ```json title="Service payload" { "universal_order": { "customer": { "name": "Rachel Kim", "email": "rachel.kim@example.com", "customer_since": "2024-02-14" }, "order": { "external_id": "SUB-2026-06-441", "amount": 299.0, "currency": "USD", "ordered_at": "2026-06-01T00:05:00Z", "status": "completed", "ip_address": "192.0.2.155" }, "service": { "service_type": "professional", "provider_name": "Northlane Analytics", "delivery_method": "other", "client_name": "Rachel Kim", "booked_at": "2026-06-01T00:05:00Z", "service_cost": 299.0, "is_no_show": false }, "policies": [ { "policy_type": "terms_of_service", "consented_at": "2024-02-14T11:20:00Z", "policy_url": "https://northlane.example.com/terms", "acceptance_method": "checkbox" } ], "activities": [ { "event_name": "login", "event_at": "2026-06-01T08:12:00Z" }, { "event_name": "report_exported", "event_at": "2026-06-03T14:47:00Z" }, { "event_name": "api_key_created", "event_at": "2026-06-07T10:03:00Z" }, { "event_name": "login", "event_at": "2026-06-19T09:51:00Z" } ] } } ``` **Other values:** `service_type` also takes `medical`, `dental`, `wellness`, `salon`, `fitness`, `legal`, `education`, `repair`, `cleaning`, `pet_care`, `insurance`, `other`. `delivery_method` takes `in_person`, `video`, `phone`, `home_visit`, `other`. Add `duration_minutes` for booked sessions and `cancelled_at` if the customer cancelled. **When to use:** a customer pays for admission to a time-bound experience at a specific location. **Industries:** concert promoters, sports teams & leagues, conference organizers, theater & performing arts, theme parks, museums & exhibitions, festival organizers. **Highest-impact:** `scanned_at` (gate scan) and `seat_number` are the core pair - a gate-scan timestamp with a specific seat assignment is typically decisive. ```json title="Event payload" { "universal_order": { "customer": { "name": "Owen Fitzgerald", "email": "owen.f@example.com" }, "order": { "external_id": "TCK-2026-33119", "amount": 258.0, "currency": "USD", "ordered_at": "2026-01-30T16:41:00Z", "status": "completed", "confirmation_code": "AF26-33119", "confirmation_methods": ["email"] }, "event": { "event_name": "Aurora Fest 2026", "event_type": "concert", "venue_name": "Harbor Amphitheatre", "event_start": "2026-07-18T19:00:00Z", "event_end": "2026-07-18T23:30:00Z", "scanned_at": "2026-07-18T18:42:11Z", "is_attended": true, "ticket_type": "reserved_seating", "seat_section": "B", "seat_row": "12", "seat_number": "14", "ticket_number": "TIX-99213-B", "ticket_price": 129.0, "attendee_name": "Owen Fitzgerald" }, "addresses": [ { "kind": "venue", "line1": "2 Harbor Point", "city": "Portland", "country": "US" } ] } } ``` **Other values:** `event_type` also takes `sports`, `theater`, `conference`, `festival`, `comedy`, `exhibition`, `theme_park`, `tour`, `attraction`, `other`. Add `rescheduled_to` if the date moved, `cancelled_at` if it was called off, and `addresses[]` (`venue`). ## Sending data: upsert, arrays, and linking [#sending-data-upsert-arrays-and-linking] Call `PATCH /{api_version}/disputes/{disputeId}` with the Chargeflow dispute ID to add or update enrichment. The endpoint uses **upsert** semantics: send only the fields you have. * **Arrays are replace-in-full.** When you update an array field (for example `products` or `fulfillments`), the passed array is stored exactly as sent. To add an item, include the existing items **and** the new one; omitted items are removed. To append safely, read the current array (or use the `dispute.created` event), then `PATCH` with the full array. * **Inline vs. linked objects.** Send full payloads, or pass IDs of objects already stored in Chargeflow to avoid duplication, e.g. `{ "transaction": "b6acc3e8408d1d6e78797725", "order": "e4d0437fb81cb881cc6bc26a" }`. Chargeflow links them and reuses their data. * **Multiple disputes on one transaction.** Chargeflow reuses enrichment from earlier disputes on the same transaction when possible; pass existing object IDs to force explicit linking. ## Error responses [#error-responses] For the full error reference, see [Error handling](https://docs.chargeflow.io/docs/reference/api-fundamentals/error-handling). | Status | When it occurs | | ------ | ------------------------------------------------------------------------------------------------ | | `400` | Both `order` and `universal_order` are present in the same request. They are mutually exclusive. | | `422` | Dispute status is not `needs_response`. You cannot enrich a dispute already submitted or closed. | `order` and `universal_order` cannot coexist in one request. Migrating from the legacy `order` field to `universal_order` means removing `order` from your payload. The `transaction` field can be sent alongside `universal_order`. ## Next step [#next-step] Use the live enrichment method available today with the `order` and `transaction` payloads. # Customer communication (https://docs.chargeflow.io/docs/merchants/automation/enrich-a-dispute/customer-communications) Documenting your interactions with a customer before and during a dispute is one of the most effective ways to strengthen a chargeback response. Issuers want to see that the merchant communicated proactively, honored their SLA, and that the customer was aware of their purchase and its terms. ## Why it matters [#why-it-matters] * **SLA proof**: Showing that your support team responded within your stated SLA demonstrates good faith and operational maturity. * **Awareness**: A record of the customer asking questions about, or acknowledging, a purchase directly counters "I didn't authorize this" claims. * **Refund offers**: Documenting that you offered a refund or resolution before the dispute was filed can lead issuers to rule in your favor. Submit customer communication records early, ideally as soon as you receive the `dispute.created` event. The sooner Chargeflow has this data, the more effectively it can weave it into the dispute narrative. ## Endpoint [#endpoint] ``` POST https://api.chargeflow.io/public/2025-04-01/customer-communication ``` This endpoint accepts a JSON body (not multipart). It creates a structured customer communication record in Chargeflow that can be linked to one or more disputes. ## Request fields [#request-fields] | Field | Type | Required | Description | | ------------ | ---------------- | -------------- | ---------------------------------------------------------------- | | `source_id` | string | Yes | Your internal ticket or conversation ID | | `disputes` | array of strings | Yes | One or more Chargeflow dispute IDs to link this communication to | | `messages` | array of objects | Yes | The individual messages in the conversation | | `account_id` | string | Platforms only | The Chargeflow account ID (required for platform users) | ### Message object fields [#message-object-fields] | Field | Type | Required | Description | | ----------------- | ----------------- | -------- | -------------------------------------------------------------------------------- | | `sender` | string | Yes | Email address of the sender, or `"buyer"` / `"merchant"` | | `date` | string (ISO 8601) | Yes | When the message was sent | | `body_plain_text` | string | Yes | The message content in plain text | | `type` | string | No | Message channel: `email`, `chat`, `transcript`, `form`, `sms` (default: `email`) | | `subject` | string | No | Email subject line (max 100 characters) | ## Example: logging a support conversation [#example-logging-a-support-conversation] ```bash title="Terminal" curl -X POST https://api.chargeflow.io/public/2025-04-01/customer-communication \ -H "x-api-key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "source_id": "ticket_87659876b", "disputes": ["6684a99a2664656565656565"], "messages": [ { "type": "email", "sender": "buyer", "date": "2025-01-20T09:15:00Z", "subject": "Where is my order?", "body_plain_text": "Hi, I placed my order 5 days ago and it still has not arrived. Can you please provide an update?" }, { "type": "email", "sender": "merchant", "date": "2025-01-20T10:30:00Z", "subject": "Re: Where is my order?", "body_plain_text": "Hi John, thank you for reaching out. Your order shipped on Jan 16 via FedEx, tracking number 1Z999AA10123456789. Expected delivery is Jan 22. Please let us know if you need anything further." } ] }' ``` ## Linking to multiple disputes [#linking-to-multiple-disputes] If the same customer conversation is relevant to more than one dispute, include all relevant dispute IDs in the `disputes` array: ```json title="Request body" { "source_id": "ticket_87659876b", "disputes": [ "6684a99a2664656565656565", "66e6ea9ecd94925a558060d9" ], "messages": [...] } ``` ## Alternative: uploading a screenshot [#alternative-uploading-a-screenshot] If you prefer to submit a screenshot of the conversation instead of structured message records, use the [Upload Evidence endpoint](https://docs.chargeflow.io/docs/merchants/automation/upload-evidence) with `evidenceUploadCategory: "customer_communication"`. Use structured messages (this endpoint) when you can extract the conversation from your helpdesk system programmatically. Use the file upload when you only have a screenshot. ## Next steps [#next-steps] Link this communication record into the full dispute enrichment payload. Uploading file-based evidence including communication screenshots. Where communication records fit in the SaaS and e-commerce evidence sets. # Enrich a dispute (https://docs.chargeflow.io/docs/merchants/automation/enrich-a-dispute) Enrichment is the process of sending additional evidence and signals to Chargeflow to strengthen a dispute response. Disputes are often vague: they arrive without the full context of a transaction's history and associated entities. By enriching disputes with comprehensive data points, such as order details, user activity logs, customer communications, and fulfillment records, you provide a clearer and more compelling narrative for Chargeflow's AI agents to work with. ## Why enrichment matters [#why-enrichment-matters] * Reduces missing-evidence gaps that weaken the narrative. * Allows Chargeflow to build a tight, reason-code-specific response. * Improves automation quality, enabling more effective handling of future disputes. Share targeted, high-value artifacts that directly address the issuer's reason code. That is the fastest and easiest way to improve your chance of winning. If you do not see a guide tailored to your business, contact Chargeflow. A risk and fraud analyst will help you identify which artifacts will move the needle. ## General recommendations [#general-recommendations] Regardless of your business model, the following data points are useful for most dispute reasons: 1. **Customer identity**: Customer name and email add credibility by demonstrating that the business has accurate, comprehensive customer records. 2. **Addresses**: IP address, shipping address, and billing address prove delivery, verify that shipping and billing locations match, and confirm that the IP address aligns with the customer's location. 3. **Order and product information**: Product descriptions, prices, discounts, refund records, and images show that the customer had access to clear and accurate information about their purchase. ## The update dispute endpoint [#the-update-dispute-endpoint] Send all dispute-related evidence to Chargeflow with a single call: ``` PATCH https://api.chargeflow.io/public/2025-04-01/disputes/{disputeId} ``` Use the Chargeflow dispute ID (`dispute.id`), available in the `dispute.created` webhook payload, as the path parameter. ### Key ideas [#key-ideas] * **Upsert semantics**: Send only the fields you have. Chargeflow will add new fields or update existing ones. You do not need to resend unchanged data. * **One endpoint for the core payload**: Transaction and order data go through this endpoint. Subscription records are a separate call on the same dispute, listed under [Disputes](https://docs.chargeflow.io/docs/api/2025-04-01/merchants/disputes): [`POST /disputes/{disputeId}/subscription`](https://docs.chargeflow.io/docs/api/2025-04-01/merchants/disputes/public/2025-04-01/disputes/disputeid/subscription/post). Communications have their own [Customer Communication endpoint](https://docs.chargeflow.io/docs/api/2025-04-01/merchants/customer-communication). * **Override or provide**: If Chargeflow has already pulled a signal from a partner provider, you can override it by sending your own value. Chargeflow will adapt the response accordingly. * **Only shared data is used**: the dispute response is built from what your connected integrations expose plus what you send here. A field you hold back, or one your integration does not expose, cannot appear in the evidence, so send anything you want argued. ## Important: array merge behavior [#important-array-merge-behavior] When updating array fields (for example, `products` or `fulfillments`), the API treats the passed array as the **exact** array to be stored. * To **add** an item, include the existing items **and** the new item in the payload. * If you omit existing items, they will be removed. ### Example: appending a product [#example-appending-a-product] **Current stored value:** ```json title="Response" "order": { "products": [ { "name": "Shoes", "id": "123456789", "type": "physical_good", "quantity": 1, "description": "Nice shoes", "price": 150 } ] } ``` **To append a new product**, read the current array (or use the `dispute.created` event payload) and send the full array including the new item: ```json title="Request body" { "order": { "products": [ { "name": "Shoes", "id": "123456789", "type": "physical_good", "quantity": 1, "description": "Nice shoes", "price": 150 }, { "name": "Socks", "id": "987654321", "type": "physical_good", "quantity": 2, "description": "Comfort socks", "price": 20 } ] } } ``` If you omit the original `Shoes` item in the payload above, Chargeflow will replace the stored array with only `Socks`. The `Shoes` item would be removed. ## Example: inline data creation [#example-inline-data-creation] Use inline creation when the relevant object does not yet exist in Chargeflow, when the dispute is urgent and you need to add evidence in a single step, or when your systems cannot return a Chargeflow object ID. ```json title="Request body" { "transaction": { "payment_method": { "checks": { "three_d_secure_result": "passed", "avs_results": "Y", "address_line1_check": "passed", "address_zip_check": "passed", "cvc_check": "passed" }, "name": "John Doe", "type": "card", "last4": "4242", "expiry_month": "12", "expiry_year": "2027", "brand": "visa", "country": "US" }, "billing_address": { "name": "John Doe", "line1": "123 Main St", "line2": "Apt 4B", "city": "New York", "country": "US", "state": "NY", "zip_code": "10001", "phone": "1(123)4567890" }, "source_id": "trx_1234567890", "created_at": "2025-01-27T10:00:00Z", "type": "paid", "amount": 100, "currency": "USD" } } ``` Prefer linking existing Chargeflow objects when possible to avoid duplication and keep payloads small. Use inline creation when linking is not possible or would delay your response. ## Example: linking existing objects [#example-linking-existing-objects] If the transaction or order is already stored in Chargeflow, pass the object IDs instead of resending the full payload: ```json title="Request body" { "transaction": "b6acc3e8408d1d6e78797725", "order": "e4d0437fb81cb881cc6bc26a" } ``` Chargeflow will link those objects to the dispute and reuse their data for enrichment and generation. ## Multiple disputes on the same transaction [#multiple-disputes-on-the-same-transaction] A single transaction can generate more than one dispute. To avoid duplication, Chargeflow will attempt to reuse enrichment data from previous disputes involving the same transaction. If automatic reuse is not possible or you prefer explicit linking, pass existing Chargeflow object IDs in your PATCH payload. This keeps payloads small and ensures consistent data across related disputes. ## Response [#response] When your PATCH request succeeds, Chargeflow returns the updated dispute object. The returned dispute includes the enrichment data you just sent (or linked), so you can confirm the update immediately. **Example response:** ```json title="Response" HTTP/1.1 200 OK Content-Type: application/json { "id": "dis_12345", "source_id": "proc_67890", "account_id": "act_112233", "ext_account_id": "ext_act_445566", "created_at": "2025-01-27T10:00:00Z", "reason": "fraud", "due_by": "2025-02-10T10:00:00Z", "source": "stripe", "amount": 150, "currency": "USD", "status": "needs_response", "stage": "Chargeback", "closed_at": null, "evidence": {}, "transaction": { "id": "trx_654321", "source_id": "550e8400-e29b-41d4-a716-446655440000", "created_at": "2025-01-26T15:00:00Z", "type": "paid", "amount": 150, "currency": "USD", "payment_method": { "name": "John Doe", "type": "card", "last4": "4242", "expiry_month": "12", "expiry_year": "2027", "brand": "visa", "country": "US", "checks": { "three_d_secure_result": "passed", "avs_results": "Y", "address_line1_check": "passed", "address_zip_check": "passed", "cvc_check": "passed" } }, "billing_address": { "name": "John Doe", "line1": "123 Main Street", "line2": "Apt 4B", "city": "New York", "country": "US", "state": "NY", "zip_code": "10001", "phone": "1(123)4567890" } }, "order": { "id": "ord_98765", "source_id": "748e2a7c-4d21-11ee-8c99-0242ac120002", "account_id": "act_112233", "ext_account_id": "ext_act_445566", "created_at": "2025-01-26T14:30:00Z", "payment_status": "paid", "name": "#ORD-98765", "type": "pre_order", "amount": 150, "currency": "USD", "customer": { "name": "John Doe", "email": "john.doe@example.com", "customer_since": "2023-06-15T12:00:00Z", "order_count": 10, "phone_number": "1(123)4567890", "ip_address": "192.168.1.1", "verified_email": true }, "products": [ { "name": "Wireless Headphones", "id": "prod_12345", "type": "physical_good", "quantity": 1, "description": "Noise-canceling wireless headphones with Bluetooth connectivity.", "image_url": "https://example.com/images/products/12345.jpg", "price": 150 } ], "shipping_address": { "name": "John Doe", "line1": "123 Main Street", "line2": "Apt 4B", "city": "New York", "country": "US", "state": "NY", "zip_code": "10001", "phone": "1(123)4567890" }, "fulfillments": [ { "product_id": "prod_12345", "shipped_at": "2025-01-26T18:00:00Z", "shipping_line_title": "FedEx Air Express Shipping", "shipping_method_price": 0, "tracking_number": "1Z999AA10123456789", "courier": "FedEx" } ] }, "activity_logs": null, "customerCommunication": "ccm_01j92p1x8a6y7t4gz8d9w3n5qk", "booking": null } ``` ## Next steps [#next-steps] 1. Map your internal data schema to Chargeflow fields. Decide which objects you will link by ID versus send inline. 2. Subscribe to `dispute.created` so your enrichment flows trigger automatically when a new dispute is ingested. 3. Pick what you want to add to the dispute: SaaS: sign-up, usage, and billing terms. E-commerce: products, fulfillment, and delivery proof. Support conversations, refund offers, and SLA proof. One universal\_order payload tailored to your vertical. # Disputes (https://docs.chargeflow.io/docs/api/2024-03-18/platforms/disputes) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Disputes (https://docs.chargeflow.io/docs/api/2024-03-18/merchants/disputes) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Health Check (https://docs.chargeflow.io/docs/api/2024-03-18/merchants/health-check) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Alerts Created Event (https://docs.chargeflow.io/docs/api/2024-03-18/merchants/webhooks-events/alerts.created) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Alert Transaction Linked Event (https://docs.chargeflow.io/docs/api/2024-03-18/merchants/webhooks-events/alerts.transaction.linked) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Alerts Outcome Updated Event (https://docs.chargeflow.io/docs/api/2024-03-18/merchants/webhooks-events/alerts.updated) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Dispute Created Event (https://docs.chargeflow.io/docs/api/2024-03-18/merchants/webhooks-events/dispute.created) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Webhooks Events (https://docs.chargeflow.io/docs/api/2024-03-18/merchants/webhooks-events) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Webhooks Management (https://docs.chargeflow.io/docs/api/2024-03-18/merchants/webhooks-management) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Dispute Created Event (https://docs.chargeflow.io/docs/api/2024-03-18/platforms/webhooks-events/dispute.created) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Evidence Error Event (https://docs.chargeflow.io/docs/api/2024-03-18/platforms/webhooks-events/evidence.error) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Evidence Ready Event (https://docs.chargeflow.io/docs/api/2024-03-18/platforms/webhooks-events/evidence.ready) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Webhooks Events (https://docs.chargeflow.io/docs/api/2024-03-18/platforms/webhooks-events) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Integration Access Error Event (https://docs.chargeflow.io/docs/api/2024-03-18/platforms/webhooks-events/integration.access.error) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Data Subject (https://docs.chargeflow.io/docs/api/2025-04-01/merchants/data-subject) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Disputes (https://docs.chargeflow.io/docs/api/2025-04-01/merchants/disputes) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Health Check (https://docs.chargeflow.io/docs/api/2025-04-01/merchants/health-check) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Alerts Created Event (https://docs.chargeflow.io/docs/api/2025-04-01/merchants/webhooks-events/alerts.created) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Alert Transaction Linked Event (https://docs.chargeflow.io/docs/api/2025-04-01/merchants/webhooks-events/alerts.transaction.linked) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Alerts Outcome Updated Event (https://docs.chargeflow.io/docs/api/2025-04-01/merchants/webhooks-events/alerts.updated) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Dispute Created Event (https://docs.chargeflow.io/docs/api/2025-04-01/merchants/webhooks-events/dispute.created) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Webhooks Events (https://docs.chargeflow.io/docs/api/2025-04-01/merchants/webhooks-events) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Customer Communication (https://docs.chargeflow.io/docs/api/2025-04-01/merchants/customer-communication) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Accounts (https://docs.chargeflow.io/docs/api/2025-04-01/platforms/accounts) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Evidence (https://docs.chargeflow.io/docs/api/2025-04-01/platforms/evidence) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Merchants Disputes (https://docs.chargeflow.io/docs/api/2025-04-01/platforms/merchants-disputes) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Alerts (https://docs.chargeflow.io/docs/api/2025-04-01/merchants/alerts) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Dispute Created Event (https://docs.chargeflow.io/docs/api/2025-04-01/platforms/webhooks-events/dispute.created) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Evidence Error Event (https://docs.chargeflow.io/docs/api/2025-04-01/platforms/webhooks-events/evidence.error) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Evidence Ready Event (https://docs.chargeflow.io/docs/api/2025-04-01/platforms/webhooks-events/evidence.ready) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Webhooks Events (https://docs.chargeflow.io/docs/api/2025-04-01/platforms/webhooks-events) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Integration Access Error Event (https://docs.chargeflow.io/docs/api/2025-04-01/platforms/webhooks-events/integration.access.error) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Webhooks Management (https://docs.chargeflow.io/docs/api/2025-04-01/merchants/webhooks-management) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Get All Webhooks (https://docs.chargeflow.io/docs/api/2024-03-18/merchants/webhooks-management/public/2024-03-18/webhooks/get) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Create Webhook (https://docs.chargeflow.io/docs/api/2024-03-18/merchants/webhooks-management/public/2024-03-18/webhooks/post) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Get Disputes (https://docs.chargeflow.io/docs/api/2025-04-01/merchants/disputes/public/2025-04-01/disputes/get) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Service Health Verification (https://docs.chargeflow.io/docs/api/2025-04-01/merchants/health-check/public/2025-04-01/health-check/get) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Create Account (https://docs.chargeflow.io/docs/api/2025-04-01/platforms/accounts/public/2025-04-01/accounts/post) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Generate Evidence (https://docs.chargeflow.io/docs/api/2025-04-01/platforms/evidence/public/2025-04-01/evidence/post) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Create Customer Communication (https://docs.chargeflow.io/docs/api/2025-04-01/merchants/customer-communication/public/2025-04-01/customer-communication/post) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Service Health Verification (https://docs.chargeflow.io/docs/api/2024-03-18/merchants/health-check/public/2024-03-18/health-check/get) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Get Alerts (https://docs.chargeflow.io/docs/api/2025-04-01/merchants/alerts/public/2025-04-01/alerts/get) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Get Disputes (https://docs.chargeflow.io/docs/api/2024-03-18/platforms/disputes/public/2024-03-18/disputes/get) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Create Dispute (https://docs.chargeflow.io/docs/api/2024-03-18/platforms/disputes/public/2024-03-18/disputes/post) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Get Disputes (https://docs.chargeflow.io/docs/api/2024-03-18/merchants/disputes/public/2024-03-18/disputes/get) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Create Dispute (https://docs.chargeflow.io/docs/api/2024-03-18/merchants/disputes/public/2024-03-18/disputes/post) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Get Webhooks (https://docs.chargeflow.io/docs/api/2025-04-01/merchants/webhooks-management/public/2025-04-01/webhooks/get) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Create Webhook (https://docs.chargeflow.io/docs/api/2025-04-01/merchants/webhooks-management/public/2025-04-01/webhooks/post) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Create Data Subject Removal Request (https://docs.chargeflow.io/docs/api/2025-04-01/merchants/data-subject/public/2025-04-01/data-subject/removal/post) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Get Dispute by ID (https://docs.chargeflow.io/docs/api/2025-04-01/merchants/disputes/public/2025-04-01/disputes/disputeid/get) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Enrich Dispute (https://docs.chargeflow.io/docs/api/2025-04-01/merchants/disputes/public/2025-04-01/disputes/disputeid/patch) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Delete Webhook (https://docs.chargeflow.io/docs/api/2024-03-18/merchants/webhooks-management/public/2024-03-18/webhooks/id/delete) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Validate Access Key (https://docs.chargeflow.io/docs/api/2025-04-01/merchants/health-check/public/2025-04-01/health-check/access-key/get) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Get Account By ID (https://docs.chargeflow.io/docs/api/2025-04-01/platforms/accounts/public/2025-04-01/accounts/accountid/get) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Get Evidence by ID (https://docs.chargeflow.io/docs/api/2025-04-01/platforms/evidence/public/2025-04-01/evidence/evidenceid/get) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Create Dispute (https://docs.chargeflow.io/docs/api/2025-04-01/platforms/merchants-disputes/public/2025-04-01/platform/disputes/post) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Validate Access Key (https://docs.chargeflow.io/docs/api/2024-03-18/merchants/health-check/public/2024-03-18/health-check/access-key/get) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Get Alert By ID (https://docs.chargeflow.io/docs/api/2025-04-01/merchants/alerts/public/2025-04-01/alerts/alertid/get) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Delete Webhook (https://docs.chargeflow.io/docs/api/2025-04-01/merchants/webhooks-management/public/2025-04-01/webhooks/id/delete) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Get Removal Request Status (https://docs.chargeflow.io/docs/api/2025-04-01/merchants/data-subject/public/2025-04-01/data-subject/removal/requestid/get) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Upload Evidence (https://docs.chargeflow.io/docs/api/2025-04-01/merchants/disputes/public/2025-04-01/disputes/disputeid/evidence/post) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Create Subscription (https://docs.chargeflow.io/docs/api/2025-04-01/merchants/disputes/public/2025-04-01/disputes/disputeid/subscription/post) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Update Alert Outcome (https://docs.chargeflow.io/docs/api/2025-04-01/merchants/alerts/public/2025-04-01/alerts/alertid/outcome/post) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Upload Evidence (https://docs.chargeflow.io/docs/api/2024-03-18/merchants/disputes/public/2024-03-18/disputes/disputeid/evidence/post) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}