Chargeback Agent API
The Chargeback Agent API accepts dispute documents and returns a recommendation, recommended actions, and a formal response letter. Requests authenticate with a secret key.
Agent Lifecycle
The chargeback agent workflow consists of four main steps:
-
Initialize agent with a chargeback case (
POST) -
Attach documents to the case (
POST,PUT) - Agent recommendation (
GET) - Generate response letter (
POST) - Read response letter (
GET)
Attaching documents and reviewing the recommendation is iterative: each
recommendation reports its confidence and suggests further evidence
to attach until the case is ready.
Once the recommendation is ready, downloading the PDF is a two-step process:
- Request download (
GET) - Download document (
GET)
Initialize Chargeback Case
Initialize an agent session with chargeback case details. The response
includes a case id used in subsequent calls. A complete request body
provides optimal performance, though no individual field is required. Blank
fields are treated as omitted. null and an empty string mean the
same thing: on initialize the field is left unset, and on update it is cleared.
Request
POST /chargeback
Authorization: sk_findustryai_kkkkkkkkkkkk_nnnn
{
data: {
agent: Boolean | Object,
amountCents: Number,
cardNetwork: String,
cardholderName: String,
currency: String,
disputeDate: String,
dueDate: String,
maskedCardNumber: String,
merchantIdentifier: String,
merchantName: String,
merchantUrl: String,
reasonCode: String,
reasonDescription: String,
referenceNumber: String,
transactionDate: String
}
}
| Field | Type | Description |
|---|---|---|
agent |
Boolean or Object |
Controls behavior of the Chargeback Agent: true (the
default) follows the organization's settings, false disables
agent research, and an object sets behaviors individually. Posted, never
returned. See agent settings
|
amountCents |
Number (integer) | Disputed amount in minor units (e.g., cents) |
cardNetwork |
String | Card network for the disputed transaction (e.g., "visa"). Used to scope reasonCode matching when maskedCardNumber does not carry the card's leading digits |
cardholderName |
String | Name of the cardholder raising the dispute |
currency |
String (ISO 4217) | Defaults to "USD" |
disputeDate |
Date (ISO 8601) | Date the dispute was raised |
dueDate |
Date (ISO 8601) | Deadline for the merchant response |
maskedCardNumber |
String | Masked card number (e.g., "424242******4242"). The
leading digits name the network that scopes reasonCode matching,
so a number masked from the front ("******4242") leaves the
agent to fall back to cardNetwork |
merchantIdentifier |
String | Organization's identifier for the merchant defending the case. |
merchantName |
String |
The merchant's trading name (e.g. "Main Street Grocery").
|
merchantUrl |
String (URL) |
The merchant's public website (e.g. "https://merchant.example"). The agent reads the site's business description and
dispute-relevant policies and uses them in the recommendation. The
address is normalized before it is stored, so compare the returned
value rather than the value sent
|
reasonCode |
String |
Card network reason code (e.g., "10.4"). Codes are
matched leniently across the shapes processors export, which requires
the card network from maskedCardNumber or cardNetwork; without it, only a code cataloged exactly as written resolves
|
reasonDescription |
String | Description of the dispute in your own wording (e.g., "Other Fraud - Card-Absent Environment"). It confirms which dispute a reasonCode names when the
code is written in another network's scheme, and never overrides reasonCode |
referenceNumber |
String | Dispute reference number from the processor or card network |
transactionDate |
Date (ISO 8601) | Date of the disputed transaction |
Response
Returns the case with its id and status alongside the
submitted details. Reason code defenseRequirements
are available immediately. Requirement will be marked `satisfied: true` as evidence
is provided. Cases should meet as many requirements as possible to maximize success.
evidenceSuggested and evidenceProvided are merchant-friendly
descriptions of evidence types meeting defense requirements. More specific actions
are suggested in recommendedActions.
{
data: {
amountCents: Number,
cardNetwork: String,
cardholderName: String,
currency: String,
defenseRequirements: [{ requirement: String, satisfied: Boolean }],
disputeDate: String,
dueDate: String,
evidenceProvided: [String],
evidenceSuggested: [String],
id: String,
maskedCardNumber: String,
merchantIdentifier: String,
merchantName: String,
merchantUrl: String,
reasonCode: String,
reasonDescription: String,
referenceNumber: String,
status: "pending",
transactionDate: String
}
}
| Field | Type | Description |
|---|---|---|
defenseRequirements |
Array of Objects |
What the reason code requires the defense to show. Every item is satisfied: false until the agent assesses attached documents. Empty when the case has no
reasonCode or the code is not recognized
|
evidenceProvided |
Array of Strings | Evidence categories with at least one satisfied requirement, empty at initialization until evidence is attached or fetched by the agent. |
evidenceSuggested |
Array of Strings |
Evidence categories still to collect, listing evidence with the
highest impact first. A case whose reasonCode is absent or
unrecognized lists every category a merchant can supply, rather than nothing
|
id |
String (uuid) | Identifier for the agent session |
status |
String (enum) | pending until a document is attached |
Agent Settings
The agent field controls agent behavior for the case.
| Value | Effect |
|---|---|
Omitted or true |
Every setting keeps its default |
false |
Sets all agent behaviors to false.
|
| Object | Override default behaviors on an individual basis. |
Agent settings object
Settings are fixed when the case is created. An agent field posted
to update responds 400 Bad Request.
Defaults vary by organization. Contact Findustry AI to discuss customizations.
{
data: {
agent: {
researchTransactionDetails: Boolean,
submitDisputeToProcessor: Boolean,
useMerchantMemories: Boolean,
writeResponseLetter: Boolean
}
}
}
| Setting | Type | What it controls |
|---|---|---|
researchTransactionDetails |
Boolean | Whether the agent gathers transaction detail beyond what the case and its attached documents carry. |
submitDisputeToProcessor |
Boolean | Whether the agent files the response with the issuer/processor or only provides it for the organization to file. |
useMerchantMemories |
Boolean | Whether the agent uses past research and interactions to inform the case. By default the agent will remember types of evidence a merchant can or cannot provide. |
writeResponseLetter |
Boolean |
Whether the agent writes a response letter for the
case. When false calls to
POST /chargeback/:id/letter respond 400 Bad Request
|
Evidence Categories
evidenceProvided and evidenceSuggested use a controlled
vocabulary, listed below. Each item is all lower-case.
| Value | What it asks for |
|---|---|
refund receipt |
Refund and credit records, such as proof a credit was already issued |
delivery confirmation |
Proof the order reached the cardholder, such as signed delivery confirmation or courier tracking |
cardholder communication |
Correspondence with the cardholder, such as email conversations or post-payment agreements |
transaction authorization |
The payment platform's record of the transaction and its authorization, such as the sales slip, AVS and CVV results, or device fingerprints |
order confirmation |
Records of the order as placed, such as the confirmation email sent to the cardholder |
proof of digital goods usage |
Proof digital content was delivered, such as purchase and download timestamps or access logs |
proof of services provided |
Proof services were provided and used, such as an invoice or a service confirmation |
proof of cardholder non-contact / non-return |
Proof the cardholder neither contacted the merchant nor returned the merchandise |
refund and return policies |
The merchant's published policies and their acceptance, such as a checkout acceptance screenshot |
recurring billing records |
Subscription billing and cancellation records, such as the billing notice sent to the cardholder |
cardholder transaction history |
The cardholder's prior undisputed transactions with the merchant |
evidence of product quality |
Evidence the goods were as described, such as condition photographs or a certificate of authenticity |
Update Case Details
Update a case by posting the fields to change. Only fields present in data are updated; omitted fields are unchanged. Accepts the same fields as initialize, except agent (Returns 400 Bad Request).
A blank field clears the value on the case. null and an empty
string mean the same thing. Every field can be cleared except referenceNumber, which a case must keep (Returns 400 Bad Request).
Request
POST /chargeback/:id
Authorization: sk_findustryai_kkkkkkkkkkkk_nnnn
{
data: {
dueDate: String,
merchantUrl: String
}
}
Response
The response returns the updated case, in the same shape as initialize.
Delete Case
Delete a case and its attached documents. Deleted cases and their documents cannot be retrieved.
Request
DELETE /chargeback/:id
Authorization: sk_findustryai_kkkkkkkkkkkk_nnnn
Response
{
data: {
id: String,
status: "deleted"
}
}
Attach Documents to Case
Attach documents by posting their uploadFilenames, then sending
each file's contents to its returned signed putUrl, exactly as
in document upload. Each attached document is
assessed in the next recommendation.
Documents are attached to cases initialized with POST /chargeback. A session initialized with direct upload
takes its documents at initialization and answers this endpoint with a 400.
Request
POST /chargeback/:id/upload
Authorization: sk_findustryai_kkkkkkkkkkkk_nnnn
{
data: {
uploadFilenames: [String]
}
}
Response
{
data: {
id: String,
putUrls: [
{
evidenceId: String,
putUrl: String,
uploadFilename: String
}
]
}
}
Each signed putUrl is valid for fifteen minutes. Each evidenceId identifies the attached document and is the identifier used to delete evidence.
Delete Evidence from Case
Delete a single attached document by its evidenceId. The case
and its remaining documents are unchanged. Deleted documents cannot be
retrieved.
Removing evidence triggers a fresh assessment automatically, about thirty
seconds after the last deletion so a burst of deletions is assessed once.
The recommendation shows status: "processing" while the agent reassesses and completes with the remaining evidence. Any response
letter already written is retired at the same time, since it argued from the deleted
document: GET /chargeback/:id/letter answers 404 until
the response letter is requested again, which rewrites it
from the remaining evidence. To replace a letter without changing the evidence
behind it, discard the letter instead.
Request
DELETE /chargeback/:id/evidence/:evidenceId
Authorization: sk_findustryai_kkkkkkkkkkkk_nnnn
| Parameter | Type | Description |
|---|---|---|
id |
String (uuid) | Identifier for the agent session |
evidenceId |
String (uuid) | Identifier for the attached document, returned when the document is attached |
Response
{
data: {
id: String,
status: "deleted"
}
}
| Field | Type | Description |
|---|---|---|
id |
String (uuid) | Identifier for the deleted evidence |
status |
String (enum) | String value deleted |
Agent Recommendation
Once each document is uploaded the agent assesses the material presented to
provide a recommendation and recommended actions. The API response shows status: "processing" while the Agent is working. This process takes several minutes.
The submitted case fields are returned at every status, so the case is
readable at any time. While the agent works the response carries the case
fields with the current status; once complete the
recommendation fields join them.
Request
GET /chargeback/:id
Authorization: sk_findustryai_kkkkkkkkkkkk_nnnn
Response
Processing
{
data: {
amountCents: Number,
cardNetwork: String,
currency: String,
// ...the case fields as submitted...
defenseRequirements: [{ requirement: String, satisfied: Boolean }],
evidenceProvided: [String],
evidenceSuggested: [String],
id: String,
status: "processing"
}
}
Complete
{
data: {
amountCents: Number,
cardNetwork: String,
currency: String,
// ...the case fields as submitted...
confidence: Number,
defenseRequirements: [{ requirement: String, satisfied: Boolean }],
evidenceProvided: [String],
evidenceSuggested: [String],
id: String,
merchantAttachments: [{ evidenceId: String, uploadFilename: String }],
merchantIdentifier: String,
priority: String,
recommendation: String,
recommendedActions: [String],
referenceNumber: String,
status: String
}
}
| Field | Type | Description |
|---|---|---|
confidence |
Number |
Confidence in the recommendation, 0 to 100
|
defenseRequirements |
Array of Objects |
Each object pairs a requirement with a satisfied flag the assessment sets from the attached documents. The requirement
set is stable over the life of the case, except that evidence matching no
known requirement is appended
|
evidenceProvided |
Array of Strings | Evidence categories the assessment found satisfied |
evidenceSuggested |
Array of Strings | Evidence categories still unsatisfied that would strengthen the defense. Updated with each attachment or deletion. |
id |
String (uuid) | Identifier for the agent session |
merchantAttachments |
Array of Objects |
The case's current documents. Each object carries the evidenceId (usable to delete the evidence) and
its uploadFilename. Reflects deletions
|
merchantIdentifier |
String |
The merchantIdentifier supplied on the case, echoed back. Absent
when the case carries none
|
priority |
String (enum) | normal, high |
recommendation |
String | respond, hold |
recommendedActions |
Array of Strings | Each string describes a recommended action that may improve the merchant defense |
referenceNumber |
String | |
status |
String (enum) |
pending, queued, processing, complete, error
|
If processing fails the response carries an error message instead of a recommendation.
{
data: {
id: String,
message: String,
status: "error"
}
}
Generate Response Letter
Once the recommendation is satisfactory, request a formal response letter.
The API response shows status: "processing" while the agent is working.
This process takes several minutes. Read the letter until it is ready, or register a web hook.
A letter is written only when it is requested, and it is written once. Requesting it again does not start a new letter, but returns the existing one. To replace a letter, discard it first.
This request takes no body. A request that carries one answers 400 Bad Request.
Request
POST /chargeback/:id/letter
Authorization: sk_findustryai_kkkkkkkkkkkk_nnnn
Response
First request
{
data: {
id: String,
status: "processing"
}
}
Requested again, letter ready
{
data: {
id: String,
responseLetter: String,
status: "complete"
}
}
Read Response Letter
Poll the requested letter until it is ready. A letter that has never been requested, or one retired by discarding it or by deleting evidence, answers 404.
Request
GET /chargeback/:id/letter
Authorization: sk_findustryai_kkkkkkkkkkkk_nnnn
Response
Processing
{
data: {
id: String,
status: "processing"
}
}
Complete
{
data: {
id: String,
responseLetter: String,
status: "complete"
}
}
| Field | Type | Description |
|---|---|---|
id |
String (uuid) | Identifier for the agent session |
responseLetter |
String (markdown) | Complete rebuttal letter in markdown, intended for acquirer and card networks |
Not requested
HTTP 404
{
errors: [
{
status: 404,
title: String,
detail: String
}
]
}
Discard Response Letter
Discard the response letter for a case so that requesting a letter writes a new one. The attached documents remain attached to the case. After deleting the letter, request a letter to prepare a new one.
Discarding a letter that is still being written abandons that work: the
letter it would have produced is not delivered. A case with no letter to
discard answers 404, the same answer reading the letter gives. This request takes no body. A request that carries one answers 400 Bad Request.
Request
DELETE /chargeback/:id/letter
Authorization: sk_findustryai_kkkkkkkkkkkk_nnnn
Response
{
data: {
id: String,
status: "deleted"
}
}
Direct Upload and Download
Initialize with Direct Upload
Direct upload allows already-generated files with chargeback details to be parsed as input. Chargeback Agent must be configured to recognize upload formats before use. Contact support@findustryai.com for assistance.
Details
Initialize an agent session by posting the uploadFilename of the
document that will be uploaded. Filenames do not need to be unique across sessions.
The response will provide the signed putUrl where the file contents
are sent in the next step.
A direct-upload session carries one document. To have several documents assessed together, initialize a case with POST /chargeback and attach each document to it.
Request
POST /chargeback/upload
Authorization: sk_findustryai_kkkkkkkkkkkk_nnnn
{
data: {
uploadFilename: String
}
}
| Field | Type | Required | Description |
|---|---|---|---|
uploadFilename |
String (filename) | Yes |
Name of the file to be uploaded (e.g., "file.pdf"). A
filename, never a path
|
Response
{
data: {
id: String,
putUrls: [
{
evidenceId: String,
putUrl: String,
uploadFilename: String
}
]
}
}
| Field | Type | Description |
|---|---|---|
id |
String (uuid) | Identifier for the agent session |
putUrls |
Array of one Object |
The entry pairs the uploadFilename with the signed putUrl endpoint for its document PUT operation. Connection to this endpoint
is valid for five minutes. The evidenceId identifies the
attached document for deletion
|
Document Upload
After initializing the agent, send the file's contents to its putUrl. This is a signed URL valid for five minutes.
PUT ${putUrl}
Content-Type: ${contentType}
Example using curl:
curl -X PUT -T file.pdf
"https://bucket.s3.amazonaws.com/file.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=300&X-Amz-Signature=..."
Document Export
Document export assembles case files to custom formats (e.g., PDF, XLSX). Chargeback Agent must be configured with export formats before use. Contact support@findustryai.com for assistance.
Details
The agent produces a custom export based on a specified format. The API
response shows status: "processing" while the agent is working.
This process takes several minutes. Once the download is ready it will return
a getUrl.
Request
GET /chargeback/:id/download
Authorization: sk_findustryai_kkkkkkkkkkkk_nnnn
Multiple Formats
If multiple formats are configured, the format query parameter
specifies the format. If not specified, the default format will be returned.
Response
Processing
{
data: {
id: String,
status: "processing"
}
}
Complete
{
data: {
id: String,
getUrl: String
}
}
| Field | Type | Description |
|---|---|---|
id |
String (uuid) | Identifier for the agent session |
getUrl |
String (url) | Signed URL for the document |
Document Download
The download request will return a getUrl. This is a signed
URL valid for five minutes.
Example downloading using curl:
curl -L -o file.pdf
"https://bucket.s3.amazonaws.com/file.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=300&X-Amz-Signature=..."
Web Hooks
Web hooks may be registered as an alternative to polling the agent status.
The event body will contain the same data attribute as the HTTP response,
along with metadata and security headers for authentication.
Event Metadata
Along with the data attribute, the event body will contain a metadata
attribute describing the web hook event.
{
metadata: {
attempt: Number,
event: "chargeback:copilot",
id: String,
timestamp: Number,
type: "webhook",
webhook: String
},
data: {
// …
}
}
| Field | Type | Description |
|---|---|---|
attempt |
Number (integer) |
Numeric counter of web hook delivery attempts beginning at 1
|
event |
String | String value chargeback:copilot |
id |
String (uuid) | Identifier for the web hook event. Does not change between retry attempts. Recommended as an idempotence token to prevent duplicate processing |
timestamp |
Number (milliseconds) | Timestamp for the web hook event attempt. Changes with each attempt |
type |
String | String value webhook |
webhook |
String (uuid) | Identifier of the web hook endpoint receiving this delivery |
Acknowledgement
Web hooks interpret the HTTP response code as acknowledgement of receipt.
| Code | Result | Description |
|---|---|---|
2XX |
Success | Mark delivered |
401 |
Unauthorized | Web hook failed authentication |
429 |
Too many requests | Delay next attempt. Retry with backoff |
5XX |
Server error |
Retry with backoff. Unreachable hosts are treated as 504 Gateway Timeout
|
* |
Unknown error | Client error, do not retry |
Undeliverable Messages
Undeliverable messages will be reattempted for up to one hour. Messages that fail to deliver after one hour will be recorded for remediation. Findustry AI will reach out to discuss improving delivery rates.
Authentication
Web hook deliveries are signed with an HMAC signature in the X-Webhook-Signature header. See Web Hooks authentication.