READY state.
For more detailed information on creating a dispute, see Creating a Dispute.
Opening the dispute case
To open a dispute case, send aPOST /cases request with the following fields:
original_transaction_token: The clearing transaction token.dispute_amount: The amount in dispute.dispute_reason: A reason code (for example,NOT_AUTHORIZED_CARD_ABSENTfor fraud, orCARDHOLDER_DISPUTEfor goods not received).
- The request payload for dispute creation differs depending on the network and dispute reason. The following sample request for a Mastercard cleared transaction is an example of a minimal configuration.
- The
cardholder_contact_dateparameter is required forREG_Edisputes, but it is not required for this example with minimal configuration. - The
dispute_reasonenum is different fromreason_codeon a transition which is a network-side identifier.
Sample request body
Sample request
Sample request
curl --request POST \
--url https://your-subdomain.marqeta.com/v3/cases \
--header 'Content-Type: application/json' \
--data '
{
"type": "LEGACY_DISPUTE",
"dispute_details": {
"original_transaction_token": "019ca0e2-a9e3-7f30-b120-957e44eb3408",
"dispute_amount": 10,
"dispute_reason": "NOT_AUTHORIZED_CARD_ABSENT",
"cardholder_contact_date": "2023-07-18T22:24:46.251Z"
},
"memo": "A test legacy dispute case"
}
'
// transactionToken is the token of the cleared transaction
const createDispute = async (transactionToken) => {
const url = 'https://your-subdomain.marqeta.com/v3/cases';
const payload = {
type: "LEGACY_DISPUTE",
dispute_details: {
original_transaction_token: transactionToken,
dispute_amount: 10,
dispute_reason: "NOT_AUTHORIZED_CARD_ABSENT",
cardholder_contact_date: "2023-07-18T22:24:46.251Z",
},
memo: "A test legacy dispute case"
};
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Marqeta-Program-Short-Code': 'your-program-code',
'Authorization': 'Basic YOUR_BASE64_ENCODED_STRING'
},
body: JSON.stringify(payload)
});
const data = await response.json();
console.log('Dispute Case Created:', data);
};
import requests
url = "https://api.marqeta.com/v3/cases"
headers = {
"Content-Type": "application/json",
"X-Marqeta-Program-Short-Code": "your-program-code",
"Authorization": "Basic YOUR_BASE64_ENCODED_STRING"
}
payload = {
"type": "LEGACY_DISPUTE",
"dispute_details": {
"original_transaction_token": "019ca0e2-a9e3-7f30-b120-957e44eb3408",
"dispute_amount": 10,
"dispute_reason": "NOT_AUTHORIZED_CARD_ABSENT",
"cardholder_contact_date": "2023-07-18T22:24:46.251Z",
},
"memo": "A test legacy dispute case"
}
response = requests.post(url, headers=headers, json=payload)
print(response.json())
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class CreateDispute {
public static void main(String[] args) throws Exception {
HttpClient client = HttpClient.newHttpClient();
String jsonBody = """
{
"type": "LEGACY_DISPUTE",
"dispute_details": {
"original_transaction_token": "019ca0e2-a9e3-7f30-b120-957e44eb3408",
"dispute_amount": 10,
"dispute_reason": "NOT_AUTHORIZED_CARD_ABSENT",
"cardholder_contact_date": "2023-07-18T22:24:46.251Z"
},
"memo": "A test legacy dispute case"
}
""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.marqeta.com/v3/cases"))
.header("Content-Type", "application/json")
.header("X-Marqeta-Program-Short-Code", "your-program-code")
.header("Authorization", "Basic YOUR_BASE64_ENCODED_STRING")
.POST(HttpRequest.BodyPublishers.ofString(jsonBody))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println("Status: " + response.statusCode());
System.out.println("Body: " + response.body());
}
}
Sample response body
Sample response
Sample response
{
"original_transaction_token": "019ca0e2-a9e3-7f30-b120-957e44eb3408",
"original_transaction_type": "authorization.clearing",
"dispute_amount": 10.00,
"currency_code": "USD",
"dispute_reason": "NOT_AUTHORIZED_CARD_ABSENT",
"network": "MASTERCARD",
"network_case_number": "",
"card_token": "e25551b1-f47a-4310-a563-1a02cd09e0f7",
"provisional_credit_granted": false,
"acquirer_fee": 0.0000,
"associated_transaction_selection_required": false
}
OPEN or OPEN_WITH_ACTION_REQUIRED Marqeta state.
Uploading supporting documents
To upload supporting documents to defend the dispute claim, usePOST /cases/{token}/contents.
You must upload supporting documents while the case is still in OPEN, OPEN_WITH_ACTION_REQUIRED, or READY states. Once a dispute is submitted to the card network, you can no longer attach documents.
For this example in particular, Mastercard requires supporting documents for all dispute claims.
Sample request body
You can upload supporting document file to the disputes API as a binary in anapplication/json in the Content-Type field, or as part of a multipart/form-data. Examples for both modes follow below.
Sample binary in body request
Sample binary in body request
curl -X POST "https://your-subdomain.marqeta.com/v3/cases/<case_token>/contents" \
-H "X-Marqeta-Program-Short-Code: your-program-code" \
-H "Authorization: Basic YOUR_BASE64_ENCODED_STRING" \
-H "Content-Type: application/json" \
-H "Cache-Control: no-cache" \
-d '{
"document_category": "RECEIPT",
"document_name": "receipt_2.pdf",
"document_data": "<file_binary_code>"
}'
const fs = require('fs');
async function uploadDisputeEvidence(caseToken, filePath) {
// Read file and convert to Base64
const fileBuffer = fs.readFileSync(filePath);
const base64Data = fileBuffer.toString('base64');
const payload = {
document_category: "RECEIPT",
document_name: "receipt_2.pdf",
document_data: base64Data
};
const response = await fetch(`https://your-subdomain.marqeta.com/v3/cases/${caseToken}/contents`, {
method: 'POST',
headers: {
'X-Marqeta-Program-Short-Code': 'your-program-code',
'Authorization': 'Basic YOUR_BASE64_ENCODED_STRING',
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
});
const result = await response.json();
console.log('Upload Status:', result);
}
import requests
import base64
case_token = "<case_token>"
url = f"https://your-subdomain.marqeta.com/v3/cases/{case_token}/contents"
# Read and encode the file
with open("receipt_2.pdf", "rb") as pdf_file:
encoded_string = base64.b64encode(pdf_file.read()).decode('utf-8')
payload = {
"document_category": "RECEIPT",
"document_name": "receipt_2.pdf",
"document_data": encoded_string
}
headers = {
"X-Marqeta-Program-Short-Code": "your-program-code",
"Authorization": "Basic YOUR_BASE64_ENCODED_STRING",
"Content-Type": "application/json"
}
response = requests.post(url, headers=headers, json=payload)
print(response.json())
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;
public class UploadEvidence {
public static void main(String[] args) throws Exception {
String caseToken = "<case_token>";
byte[] fileContent = Files.readAllBytes(Paths.get("receipt_2.pdf"));
String encodedString = Base64.getEncoder().encodeToString(fileContent);
// Simple JSON manual build (Use Jackson/Gson for production)
String jsonBody = String.format("""
{
"document_category": "RECEIPT",
"document_name": "receipt_2.pdf",
"document_data": "%s"
}
""", encodedString);
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://your-subdomain.marqeta.com/v3/cases/" + caseToken + "/contents"))
.header("X-Marqeta-Program-Short-Code", "your-program-code")
.header("Authorization", "Basic YOUR_BASE64_ENCODED_STRING")
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(jsonBody))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println("Status: " + response.statusCode());
}
}
Sample multipart form request
Sample multipart form request
curl -X POST "https://your-subdomain.marqeta.com/v3/cases/<case_token>/contents" \
-H "X-Marqeta-Program-Short-Code: your-program-code" \
-H "Authorization: Basic YOUR_BASE64_ENCODED_STRING" \
-H "Cache-Control: no-cache" \
-F 'body={
"document_category": "AUTHORIZATION_RECORD",
"document_name": "authorization_record.pdf"
};type=application/json' \
-F "file=@/path/to/your-file ;type=application/pdf"
const fs = require('fs');
async function uploadMultipartEvidence(caseToken, filePath) {
const url = `https://your-subdomain.marqeta.com/v3/cases/${caseToken}/contents`;
const formData = new FormData();
// Add the metadata part
const metadata = JSON.stringify({
document_category: "AUTHORIZATION_RECORD",
document_name: "authorization_record.pdf"
});
formData.append('body', new Blob([metadata], { type: 'application/json' }));
// Add the file part
const fileStream = fs.createReadStream(filePath);
formData.append('file', fileStream);
const response = await fetch(url, {
method: 'POST',
headers: {
'X-Marqeta-Program-Short-Code': 'your-program-code',
'Authorization': 'Basic YOUR_BASE64_ENCODED_STRING',
'Cache-Control': 'no-cache'
},
body: formData
});
const data = await response.json();
console.log(data);
}
import requests
case_token = "<case_token>"
url = f"https://your-subdomain.marqeta.com/v3/cases/{case_token}/contents"
headers = {
"X-Marqeta-Program-Short-Code": "your-program-code",
"Authorization": "Basic YOUR_BASE64_ENCODED_STRING",
"Cache-Control": "no-cache"
}
# The 'files' dictionary mimics the -F flags
files = {
'body': (None, '{"document_category": "AUTHORIZATION_RECORD", "document_name": "authorization_record.pdf"}', 'application/json'),
'file': ('authorization_record.pdf', open('/path/to/your-file', 'rb'), 'application/pdf')
}
response = requests.post(url, headers=headers, files=files)
print(response.json())
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Path;
import java.util.UUID;
public class MultipartUpload {
public static void main(String[] args) throws Exception {
String caseToken = "<case_token>";
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://your-subdomain.marqeta.com/v3/cases/" + caseToken + "/contents"))
.header("X-Marqeta-Program-Short-Code", "your-program-code")
.header("Authorization", "Basic YOUR_BASE64_ENCODED_STRING")
// Content-Type will be automatically set to multipart/form-data with a boundary
.POST(HttpRequest.BodyPublishers.ofString("... multipart data ..."))
.build();
}
}
Sample response body
Sample response
Sample response
{
"created_time": "2026-03-09T14:03:52Z",
"last_modified_time": "2026-03-09T14:03:52Z",
"token": "6fab0fc2-fef6-4949-be2b-d0d8175fba82",
"document_category": "AUTHORIZATION_RECORD",
"document_name": "receipt.pdf",
"case_token": "<case_token>",
"document_content_type": "application/pdf",
"network_process_type": "SUBMITTED",
"network_process_time": "2026-03-09T14:03:53Z"
}
OPEN or OPEN_WITH_ACTION_REQUIRED.
Verifying the document upload
You can verify that your document was uploaded correctly by sending a request to theGET /cases/{token}/contents endpoint.
The response body includes only the list of uploaded documents. However, if you want to download these files, include download_link=true as a query parameter to receive the link in the response body.
Sample request body
curl -X GET "https://your-subdomain.marqeta.com/v3/cases/<case_token>/contents/<document_token>?download_link=true" \
-H "X-Marqeta-Program-Short-Code: your-program-code" \
-H "Authorization: Basic YOUR_BASE64_ENCODED_STRING" \
-H "Content-Type: application/json" \
-H "Cache-Control: no-cache"
const getDocumentDownloadLink = async (caseToken, documentToken) => {
const url = `https://your-subdomain.marqeta.com/v3/cases/${caseToken}/contents/${documentToken}?download_link=true`;
const response = await fetch(url, {
method: 'GET',
headers: {
'X-Marqeta-Program-Short-Code': 'your-program-code',
'Authorization': 'Basic YOUR_BASE64_ENCODED_STRING',
'Content-Type': 'application/json',
'Cache-Control': 'no-cache'
}
});
const data = await response.json();
console.log('Download Link:', data.download_link);
};
import requests
case_token = "<case_token>"
document_token = "<document_token>"
url = f"https://your-subdomain.marqeta.com/v3/cases/{case_token}/contents/{document_token}"
params = {"download_link": "true"}
headers = {
"X-Marqeta-Program-Short-Code": "your-program-code",
"Authorization": "Basic YOUR_BASE64_ENCODED_STRING",
"Content-Type": "application/json",
"Cache-Control": "no-cache"
}
response = requests.get(url, headers=headers, params=params)
if response.status_code == 200:
data = response.json()
print(f"Temporary Download URL: {data.get('download_link')}")
else:
print(f"Error: {response.status_code}")
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class GetDocumentLink {
public static void main(String[] args) throws Exception {
String caseToken = "<case_token>";
String documentToken = "<document_token>";
String url = String.format(
"https://your-subdomain.marqeta.com/v3/cases/%s/contents/%s?download_link=true",
caseToken, documentToken
);
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("X-Marqeta-Program-Short-Code", "your-program-code")
.header("Authorization", "Basic YOUR_BASE64_ENCODED_STRING")
.header("Content-Type", "application/json")
.header("Cache-Control", "no-cache")
.GET()
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println("Response JSON: " + response.body());
}
}
Transitioning a dispute case
After you provide all the required case information and upload supporting documents, transition the case to theREADY state by performing the REVIEW action. Use POST /cases/{token}/transitions and set the action field value to REVIEW.
Sample request body
Sample request
Sample request
curl -X POST "https://your-subdomain.marqeta.com/v3/cases/<case_token>/transitions" \
-H "X-Marqeta-Program-Short-Code: your-program-code" \
-H "Authorization: Basic YOUR_BASE64_ENCODED_STRING" \
-H "Content-Type: application/json" \
-d '{
"action": "REVIEW",
"reason_code": "05",
"created_by": "Your Name"
}'
const transitionDisputeCase = async (caseToken) => {
const url = `https://your-subdomain.marqeta.com/v3/cases/${caseToken}/transitions`;
const payload = {
action: "REVIEW",
reason_code: "05",
created_by: "Your Name"
};
const response = await fetch(url, {
method: 'POST',
headers: {
'X-Marqeta-Program-Short-Code': 'your-program-code',
'Authorization': 'Basic YOUR_BASE64_ENCODED_STRING',
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
});
const data = await response.json();
console.log('Transition Result:', data);
};
import requests
case_token = "<case_token>"
url = f"https://your-subdomain.marqeta.com/v3/cases/{case_token}/transitions"
headers = {
"X-Marqeta-Program-Short-Code": "your-program-code",
"Authorization": "Basic YOUR_BASE64_ENCODED_STRING",
"Content-Type": "application/json"
}
payload = {
"action": "REVIEW",
"reason_code": "05",
"created_by": "Your Name"
}
response = requests.post(url, headers=headers, json=payload)
print(response.json())
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class TransitionCase {
public static void main(String[] args) throws Exception {
String caseToken = "<case_token>";
HttpClient client = HttpClient.newHttpClient();
String jsonBody = """
{
"action": "REVIEW",
"reason_code": "05",
"created_by": "Your Name"
}
""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://your-subdomain.marqeta.com/v3/cases/" + caseToken + "/transitions"))
.header("X-Marqeta-Program-Short-Code", "your-program-code")
.header("Authorization", "Basic YOUR_BASE64_ENCODED_STRING")
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(jsonBody))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println("Status: " + response.statusCode());
System.out.println("Body: " + response.body());
}
}
Sample response body
Sample response
Sample response
{
"case_token": "<case_token>",
"token": "b70e779c-4c3a-48bf-861e-10486da57db8",
"reason_code": "05",
"reason_description": "Under Review",
"created_by": "Your Name",
"from_state": "OPEN",
"state": "READY",
"action": "REVIEW",
"created_date": "2026-03-09T19:04:30Z"
}
READY, and it is now eligible for submission to the card network.
Withdrawing a dispute voluntarily
You can withdraw a dispute while it is in theOPEN, OPEN_WITH_ACTION_REQUIRED, or READY state by sending a request to the POST /cases/<case_token>/transitions endpoint. This moves the case to a CLOSED state.
You will not be allowed to withdraw disputes once they have been submitted to the card network and assigned the
CHARGEBACK_INITIATED state.Sample request body
curl -X POST "https://your-subdomain.marqeta.com/v3/cases/<case_token>/transitions" \
-H "X-Marqeta-Program-Short-Code: your-program-code" \
-H "Authorization: Basic YOUR_BASE64_ENCODED_STRING" \
-H "Content-Type: application/json" \
-d '{
"action": "WITHDRAW_AND_CLOSE",
"reason_code": "40",
"created_by": "Your Name"
}'
const withdrawDispute = async (caseToken) => {
const url = `https://your-subdomain.marqeta.com/v3/cases/${caseToken}/transitions`;
const payload = {
action: "WITHDRAW_AND_CLOSE",
reason_code: "40",
created_by: "Your Name"
};
const response = await fetch(url, {
method: 'POST',
headers: {
'X-Marqeta-Program-Short-Code': 'your-program-code',
'Authorization': 'Basic YOUR_BASE64_ENCODED_STRING',
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
});
const data = await response.json();
console.log('Case Status:', data.state);
};
import requests
case_token = "<case_token>"
url = f"https://your-subdomain.marqeta.com/v3/cases/{case_token}/transitions"
headers = {
"X-Marqeta-Program-Short-Code": "your-program-code",
"Authorization": "Basic YOUR_BASE64_ENCODED_STRING",
"Content-Type": "application/json"
}
payload = {
"action": "WITHDRAW_AND_CLOSE",
"reason_code": "40",
"created_by": "Your Name"
}
response = requests.post(url, headers=headers, json=payload)
print(f"Status Code: {response.status_code}")
print(response.json())
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class WithdrawDispute {
public static void main(String[] args) throws Exception {
String caseToken = "<case_token>";
HttpClient client = HttpClient.newHttpClient();
String jsonBody = """
{
"action": "WITHDRAW_AND_CLOSE",
"reason_code": "40",
"created_by": "Your Name"
}
""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://your-subdomain.marqeta.com/v3/cases/" + caseToken + "/transitions"))
.header("X-Marqeta-Program-Short-Code", "your-program-code")
.header("Authorization", "Basic YOUR_BASE64_ENCODED_STRING")
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(jsonBody))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println("Dispute Final Status: " + response.body());
}
}