Disputes — Integration Guide
Disputes (chargebacks) are initiated by cardholders via their card issuer. CCG acts as a stateless relay — receiving dispute events from the payment processor and forwarding them to your webhook endpoint in real time. There is no CCG API to initiate, query, or close disputes.
For an overview of the dispute lifecycle, business rules, and how to respond, see the Business Disputes Guide.
- Prerequisites: Configure a webhook endpoint in the CCG platform to receive dispute events. No feature flag or merchant setup is required.
- No outbound API: Disputes are entirely webhook-driven. CCG relays events from the payment processor — you do not call an API to interact with disputes via CCG.
- Evidence Submission: Submit evidence directly through the payment processor dashboard (e.g., Stripe Dashboard), not via CCG.
- Webhook Spec: Dispute Webhook Reference
- Error Handling: See Payment Error Codes for dispute-related scenarios.
Payment Allocation & Disputes
In CCG, every payment — whether single-tender or split-tender — is composed of one or more payment allocations. Each allocation represents a single charge to a specific payment method. A dispute is always filed against a specific payment allocation, not the overall payment or transaction.
Key Identifiers
Every dispute webhook includes three identifiers so you always know exactly what was disputed:
| JSON Field | Represents |
|---|---|
paymentAllocationId | The specific allocation (charge to a single payment method) that is disputed |
paymentId | The parent payment (may contain one or more allocations) |
merchantTransactionId | The merchant's original reference for the transaction |
Dispute Scope
| Aspect | Behavior |
|---|---|
| Disputed allocation | Funds are withdrawn from the merchant's account for this allocation only. |
| Other allocations | Remain completely unaffected — no holds, no status changes, regardless of whether the payment is single-tender or split-tender. |
| CCG payment status | Not reversed or changed as a result of the dispute lifecycle. |
For a single-tender payment there is exactly one allocation, so the dispute maps 1:1 to the payment. For a split-tender payment with multiple allocations, only the individual allocation charged to the disputed payment method is affected — the remaining allocations are untouched.
Disputes Processing Flow
CCG is a stateless relay — it maps incoming Stripe webhook events to CCG event types and forwards them to the merchant endpoint. No dispute state is persisted in CCG.
Sequence Diagram
Dispute Event Relay Flow
Processing Steps
- Event received — Stripe emits a dispute event (e.g.,
charge.dispute.created). - Event mapping — CCG maps the Stripe event type to a CCG event type (see Stripe Event Mapping).
- Payload transformation — CCG enriches the payload with CCG identifiers (
paymentId,paymentAllocationId,merchantTransactionId). No dispute state is stored. - Webhook publication — CCG publishes the dispute webhook to the configured merchant endpoint.
- Acknowledgement — Merchant responds with a 2xx to confirm receipt.
Processor-Specifics
- Stateless relay — CCG does not persist dispute records or maintain a dispute state machine. Each Stripe event is independently mapped and forwarded.
- No status validation — CCG does not validate status transitions. The
statusfield is passed through as-is from Stripe. - Vendor fields — Fields prefixed with
vendor(e.g.,vendorPaymentId,vendorDisputeId,vendorEventType) carry the original Stripe identifiers for traceability and debugging. These are not intended for merchant-facing display.
API Request
Disputes are entirely webhook-driven. CCG does not expose an API endpoint to initiate, query, update, or close disputes — all dispute lifecycle changes originate from the card network and are relayed by the payment processor.
No request is required. To integrate with disputes:
- Configure a webhook endpoint in the CCG platform.
- Implement a handler for the dispute event types documented in Webhooks.
- Submit evidence through the payment processor dashboard before the response deadline.
API Response
Dispute updates are delivered as outbound webhook payloads, not as synchronous API responses. See Webhooks below for the full payload schema for each event type.
For the complete webhook payload schema, see the Dispute Webhook Reference.
Status Handling
Disputes do not affect the CCG payment status — the status on your payment object is not changed during the dispute lifecycle. The status field within each dispute webhook payload reflects the dispute's own state at the time of that event.
Status Mapping Table
| Status | Description | Typical Event(s) |
|---|---|---|
NEEDS_RESPONSE | Dispute filed. Evidence submission required before the deadline. | Dispute Initiated, Dispute Funds Withdrawn |
UNDER_REVIEW | Evidence submitted and under review by the card network. | Dispute Funds Withdrawn, Dispute Closed |
WON | Resolved in merchant's favor. Disputed funds returned. | Dispute Won, Dispute Closed |
LOST | Resolved in cardholder's favor. Funds permanently deducted. | Dispute Closed |
WARNING_NEEDS_RESPONSE | Early fraud warning. Response required. | Dispute Initiated |
WARNING_UNDER_REVIEW | Early fraud warning under review. | Dispute Initiated, Dispute Funds Withdrawn |
WARNING_CLOSED | Early fraud warning closed. | Dispute Closed |
Always use the DISPUTE_CLOSED event to determine the final outcome. DISPUTE_WON is not the terminal event — a DISPUTE_CLOSED event always follows.
Status pairings above reflect typical observed behavior. CCG passes the status through as-is from the processor and does not validate transitions.
Webhooks
CCG sends webhooks to notify you of changes in a dispute's status. Each webhook payload identifies the specific payment allocation that was disputed, along with the parent payment and the merchant's original transaction reference.
For the full webhook payload schema, see the Dispute Webhook API Reference.
Supported Events
| Event Type | Applicable Payment Methods | Description |
|---|---|---|
DISPUTE_INITIATED | Card, Bank Account | A cardholder or bank account holder has filed a dispute against a specific payment allocation. |
DISPUTE_FUNDS_WITHDRAWN | Card, Bank Account | The disputed amount (plus the dispute fee) has been withdrawn from your account. |
DISPUTE_WON | Card, Bank Account | Funds have been reinstated to your account. A DISPUTE_CLOSED event will follow as the terminal event. |
DISPUTE_CLOSED | Card, Bank Account | The terminal event. The status field carries the final outcome (WON or LOST). |
DISPUTE_WON is not final. Always wait for DISPUTE_CLOSED before updating your records with the definitive outcome.
Stripe Event Mapping
| CCG Event Type | Stripe Source Event |
|---|---|
DISPUTE_INITIATED | charge.dispute.created |
DISPUTE_FUNDS_WITHDRAWN | charge.dispute.funds_withdrawn |
DISPUTE_WON | charge.dispute.funds_reinstated |
DISPUTE_CLOSED | charge.dispute.closed |
Evidence Fields
To increase your chances of winning a dispute, submit as much relevant evidence as possible. Evidence fields should be tailored to the dispute reason.
The evidence object is typically empty for dispute initiated and dispute funds withdrawn events, as evidence is submitted after a dispute is created. For dispute won and dispute closed events, this object will contain the submitted evidence.
Not all fields within the evidence object will be populated in every dispute event. The availability of a field is contingent on the information provided by the payment processor (e.g., Stripe).
- Customer Info
- Shipping & Fulfillment
- Policies & Legal
- Other
| Field | Type | Description |
|---|---|---|
customer_name | string | Full name of the customer. |
customer_email_address | string | Contact email for the customer. |
billing_address | string | The customer's registered billing address. |
customer_purchase_ip | string | The IP address used at the time of purchase. |
customer_signature | string | The customer's signature, possibly in a digital format. |
access_activity_log | string | A log of the customer's access activity. |
| Field | Type | Description |
|---|---|---|
shipping_address | string | Where the physical goods were sent. |
shipping_carrier | string | The carrier used for shipping (UPS, FedEx, etc.). |
service_date | string | The date the service was provided. |
service_documentation | string | Documentation related to the service provided. |
| Field | Type | Description |
|---|---|---|
cancellation_policy | string | Your policy regarding order cancellations. |
cancellation_rebuttal | string | Rebuttal to a cancellation claim. |
refund_policy | string | Your policy regarding returns and refunds. |
refund_policy_disclosure | string | Disclosure of the refund policy. |
refund_refusal_explanation | string | Explanation for a refund refusal. |
| Field | Type | Description |
|---|---|---|
product_description | string | Description of the product involved. |
receipt | string | The receipt for the transaction. |
duplicate_charge_id | string | The unique identifier for the duplicate charge. |
duplicate_charge_explanation | string | Explanation for a duplicate charge. |
duplicate_charge_documentation | string | Documentation related to a duplicate charge. |
customer_communication | string | Emails or chat logs with the customer. |
Balance Transaction Structure
The balanceTransactions array content varies by event type:
- Dispute Initiated — Typically empty; no financial adjustment has occurred yet.
- Dispute Funds Withdrawn — Contains a transaction representing the withdrawal of funds and the non-refundable dispute fee.
- Dispute Won / Dispute Closed — May contain transactions reflecting the reinstatement of disputed funds. The dispute fee is not returned.
| Field | Type | Description |
|---|---|---|
amount | integer | The amount of the transaction, in cents. Negative for withdrawals, positive for reinstatements. |
fee | integer | The fee associated with the transaction, in cents (e.g., 1500 = $15.00 dispute fee). |
fee_details | array | A list of fee detail objects. See Fee Detail Structure. |
id | string | The unique identifier for the balance transaction. |
net | integer | The net amount after fees, in cents (e.g., -2000 = -$5.00 amount + -$15.00 fee). |
type | string | The type of the balance transaction (e.g., adjustment). |
Fee Detail Structure
Each item in the fee details array is an object with the following fields:
| Field | Type | Description |
|---|---|---|
amount | integer | The amount of the fee, in cents. |
description | string | A human-readable description of the specific fee (e.g., "Dispute fee"). |
Error Handling
Disputes are webhook-driven — error scenarios manifest as missing or delayed events rather than API errors. If your endpoint is not receiving expected events:
- Verify your webhook endpoint is configured and reachable in the CCG platform.
- Confirm your endpoint returns a
2xxresponse promptly. Failure to acknowledge may result in missed events. - Check for network or firewall issues blocking inbound webhooks.
For general payment and dispute-related error codes, see Payment Error Codes.
FAQ
Q: How do I know which payment was disputed?
Use the paymentAllocationId in the webhook payload to identify the specific charge. The paymentId gives you the parent payment, and merchantTransactionId is your original reference.
Q: Does a dispute affect my CCG payment status?
No. CCG does not update the payment or allocation status during the dispute lifecycle. Track dispute state independently using the webhook events.
Q: What is the terminal event for a dispute?
DISPUTE_CLOSED is always the terminal event. Do not treat DISPUTE_WON as final — a DISPUTE_CLOSED event always follows.
Q: Where do I submit evidence?
Evidence is submitted directly through the payment processor dashboard (e.g., Stripe Dashboard), not via CCG. CCG relays dispute events only — it does not expose an evidence submission API.
Q: Can a dispute only affect one card in a split-tender payment?
Yes. Disputes are filed against a specific payment allocation — only the allocation for the disputed card is affected. Other allocations in the same payment remain untouched.
Q: What happens if I miss the response deadline?
If no evidence is submitted before the card network's deadline (typically 7–21 days), the dispute is automatically lost. The deadline is set by the processor — check the Stripe Dashboard for the specific due date.
Integration Checklist
- Webhook endpoint is configured and publicly reachable
- Webhook handler responds with
2xxpromptly on receipt - Handler is idempotent — duplicate events are handled safely
-
DISPUTE_CLOSEDis used as the definitive final outcome (notDISPUTE_WON) -
paymentAllocationIdis used to correlate disputes with specific charges - All four event types are handled:
DISPUTE_INITIATED,DISPUTE_FUNDS_WITHDRAWN,DISPUTE_WON,DISPUTE_CLOSED - Financial reconciliation logic accounts for non-refundable dispute fees
- Evidence submission process is in place (via payment processor dashboard)
- Integration tested with all event types in staging