curl --request POST \
--url https://api.platform.sandbox.dakota.xyz/card_dispute_reports \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--header 'x-idempotency-key: <x-idempotency-key>' \
--data '
{
"card_id": "2tQRvvnYkN6edEJUTmF1LzTj2ug",
"card_transaction_id": "2ZFHrqBHb3cTfLVkFSGmHZqdDPi",
"client_reference": "SUP-48213",
"reason": "unauthorized",
"description": "Cardholder says they never authorized this charge and still has the card.",
"disputed_amount": "39.00",
"disputed_currency": "USD",
"consumer_notified_client_at": "2026-09-18T14:02:11Z",
"client_forwarded_at": "2026-09-18T16:40:00Z"
}
'const options = {
method: 'POST',
headers: {
'x-idempotency-key': '<x-idempotency-key>',
'x-api-key': '<api-key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
card_id: '2tQRvvnYkN6edEJUTmF1LzTj2ug',
card_transaction_id: '2ZFHrqBHb3cTfLVkFSGmHZqdDPi',
client_reference: 'SUP-48213',
reason: 'unauthorized',
description: 'Cardholder says they never authorized this charge and still has the card.',
disputed_amount: '39.00',
disputed_currency: 'USD',
consumer_notified_client_at: '2026-09-18T14:02:11Z',
client_forwarded_at: '2026-09-18T16:40:00Z'
})
};
fetch('https://api.platform.sandbox.dakota.xyz/card_dispute_reports', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.platform.sandbox.dakota.xyz/card_dispute_reports"
payload = {
"card_id": "2tQRvvnYkN6edEJUTmF1LzTj2ug",
"card_transaction_id": "2ZFHrqBHb3cTfLVkFSGmHZqdDPi",
"client_reference": "SUP-48213",
"reason": "unauthorized",
"description": "Cardholder says they never authorized this charge and still has the card.",
"disputed_amount": "39.00",
"disputed_currency": "USD",
"consumer_notified_client_at": "2026-09-18T14:02:11Z",
"client_forwarded_at": "2026-09-18T16:40:00Z"
}
headers = {
"x-idempotency-key": "<x-idempotency-key>",
"x-api-key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.platform.sandbox.dakota.xyz/card_dispute_reports"
payload := strings.NewReader("{\n \"card_id\": \"2tQRvvnYkN6edEJUTmF1LzTj2ug\",\n \"card_transaction_id\": \"2ZFHrqBHb3cTfLVkFSGmHZqdDPi\",\n \"client_reference\": \"SUP-48213\",\n \"reason\": \"unauthorized\",\n \"description\": \"Cardholder says they never authorized this charge and still has the card.\",\n \"disputed_amount\": \"39.00\",\n \"disputed_currency\": \"USD\",\n \"consumer_notified_client_at\": \"2026-09-18T14:02:11Z\",\n \"client_forwarded_at\": \"2026-09-18T16:40:00Z\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-idempotency-key", "<x-idempotency-key>")
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}{
"id": "33Lm2Xc7Vb9Nq4Rt6Yw8Ze1Ua3S",
"card_id": "2tQRvvnYkN6edEJUTmF1LzTj2ug",
"card_transaction_id": "2ZFHrqBHb3cTfLVkFSGmHZqdDPi",
"client_reference": "SUP-48213",
"reason": "unauthorized",
"disputed_amount": "39",
"disputed_currency": "USD",
"consumer_notified_client_at": "2026-09-18T14:02:11Z",
"client_forwarded_at": "2026-09-18T16:40:00Z",
"state": "received",
"filing_state": "not_filed",
"dakota_filed_with_vendor_at": null,
"vendor_dispute_reference": null,
"rejection_reason": null,
"created_at": 1758220800,
"updated_at": 1758220800
}{
"type": "https://docs.dakota.xyz/api-reference/errors#not-found",
"title": "Customer Not Found",
"status": 404,
"detail": "Customer cst_2abc123 was not found in your organization.",
"instance": "https://api.platform.dakota.xyz/customers/cst_2abc123",
"request_id": "req_7f3a8b2c"
}{
"type": "https://docs.dakota.xyz/api-reference/errors#not-found",
"title": "Customer Not Found",
"status": 404,
"detail": "Customer cst_2abc123 was not found in your organization.",
"instance": "https://api.platform.dakota.xyz/customers/cst_2abc123",
"request_id": "req_7f3a8b2c"
}{
"type": "https://docs.dakota.xyz/api-reference/errors#not-found",
"title": "Customer Not Found",
"status": 404,
"detail": "Customer cst_2abc123 was not found in your organization.",
"instance": "https://api.platform.dakota.xyz/customers/cst_2abc123",
"request_id": "req_7f3a8b2c"
}{
"type": "https://docs.dakota.xyz/api-reference/errors#not-found",
"title": "Customer Not Found",
"status": 404,
"detail": "Customer cst_2abc123 was not found in your organization.",
"instance": "https://api.platform.dakota.xyz/customers/cst_2abc123",
"request_id": "req_7f3a8b2c"
}{
"type": "https://docs.dakota.xyz/api-reference/errors#not-found",
"title": "Customer Not Found",
"status": 404,
"detail": "Customer cst_2abc123 was not found in your organization.",
"instance": "https://api.platform.dakota.xyz/customers/cst_2abc123",
"request_id": "req_7f3a8b2c"
}{
"type": "https://docs.dakota.xyz/api-reference/errors#not-found",
"title": "Customer Not Found",
"status": 404,
"detail": "Customer cst_2abc123 was not found in your organization.",
"instance": "https://api.platform.dakota.xyz/customers/cst_2abc123",
"request_id": "req_7f3a8b2c"
}{
"type": "https://docs.dakota.xyz/api-reference/errors#not-found",
"title": "Customer Not Found",
"status": 404,
"detail": "Customer cst_2abc123 was not found in your organization.",
"instance": "https://api.platform.dakota.xyz/customers/cst_2abc123",
"request_id": "req_7f3a8b2c"
}{
"type": "https://docs.dakota.xyz/api-reference/errors#not-found",
"title": "Customer Not Found",
"status": 404,
"detail": "Customer cst_2abc123 was not found in your organization.",
"instance": "https://api.platform.dakota.xyz/customers/cst_2abc123",
"request_id": "req_7f3a8b2c"
}{
"type": "https://docs.dakota.xyz/api-reference/errors#not-found",
"title": "Customer Not Found",
"status": 404,
"detail": "Customer cst_2abc123 was not found in your organization.",
"instance": "https://api.platform.dakota.xyz/customers/cst_2abc123",
"request_id": "req_7f3a8b2c"
}Report a card dispute, and optionally file it
Record that one of your cardholders told you they dispute a card transaction, and when they told you.
Whether this files a dispute depends on filing_reason.
- Send
filing_reasonand Dakota files the dispute during this request, before you get a response. Filing is not reversible through this API. You must also sendcard_transaction_idsnaming every transaction the dispute covers — except foratm_deposit_missing, the one account-level reason, which requires an empty list. - Omit
filing_reasonand the report is only recorded. Nothing reaches a card network. This is the right call when you cannot yet identify the disputed transaction, because a dispute cannot be filed without naming one.
Read filing_state on the response to learn which happened. pending
means the dispute was filed and is awaiting the information the network
requires. not_filed means it was not — either because you sent no
filing_reason, or because the filing failed. A not_filed report
that carries a filing_reason needs following up with Dakota: the
report is on file and its response clock is running, and because
client_reference is unique you cannot resubmit it.
In neither case does this endpoint change the card transaction’s status, reverse an authorization, or move money.
Send consumer_notified_client_at as the instant the cardholder told
YOU, and client_forwarded_at as the instant you passed it to Dakota.
The two are stored separately and neither is derived from the other,
because the gap between them is yours and the gap after them is
Dakota’s. consumer_notified_client_at must not be later than
client_forwarded_at, and neither may be in the future.
client_reference is your own case identifier. It is unique per
client: resubmitting a reference already on file is answered with 409
naming the report that exists, so a retry after a timeout cannot
produce a second record of one notice.
card_id is required. card_transaction_id is optional — send it when
you know which transaction is disputed, and omit it when you do not.
Omitting it is not a reason to delay: the report is recorded either
way, and the transaction can be attached later.
description is the cardholder’s own account of what happened. It is
stored for the operator who files the dispute and is deliberately
absent from the response: you sent it, and it is not echoed back.
curl --request POST \
--url https://api.platform.sandbox.dakota.xyz/card_dispute_reports \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--header 'x-idempotency-key: <x-idempotency-key>' \
--data '
{
"card_id": "2tQRvvnYkN6edEJUTmF1LzTj2ug",
"card_transaction_id": "2ZFHrqBHb3cTfLVkFSGmHZqdDPi",
"client_reference": "SUP-48213",
"reason": "unauthorized",
"description": "Cardholder says they never authorized this charge and still has the card.",
"disputed_amount": "39.00",
"disputed_currency": "USD",
"consumer_notified_client_at": "2026-09-18T14:02:11Z",
"client_forwarded_at": "2026-09-18T16:40:00Z"
}
'const options = {
method: 'POST',
headers: {
'x-idempotency-key': '<x-idempotency-key>',
'x-api-key': '<api-key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
card_id: '2tQRvvnYkN6edEJUTmF1LzTj2ug',
card_transaction_id: '2ZFHrqBHb3cTfLVkFSGmHZqdDPi',
client_reference: 'SUP-48213',
reason: 'unauthorized',
description: 'Cardholder says they never authorized this charge and still has the card.',
disputed_amount: '39.00',
disputed_currency: 'USD',
consumer_notified_client_at: '2026-09-18T14:02:11Z',
client_forwarded_at: '2026-09-18T16:40:00Z'
})
};
fetch('https://api.platform.sandbox.dakota.xyz/card_dispute_reports', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.platform.sandbox.dakota.xyz/card_dispute_reports"
payload = {
"card_id": "2tQRvvnYkN6edEJUTmF1LzTj2ug",
"card_transaction_id": "2ZFHrqBHb3cTfLVkFSGmHZqdDPi",
"client_reference": "SUP-48213",
"reason": "unauthorized",
"description": "Cardholder says they never authorized this charge and still has the card.",
"disputed_amount": "39.00",
"disputed_currency": "USD",
"consumer_notified_client_at": "2026-09-18T14:02:11Z",
"client_forwarded_at": "2026-09-18T16:40:00Z"
}
headers = {
"x-idempotency-key": "<x-idempotency-key>",
"x-api-key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.platform.sandbox.dakota.xyz/card_dispute_reports"
payload := strings.NewReader("{\n \"card_id\": \"2tQRvvnYkN6edEJUTmF1LzTj2ug\",\n \"card_transaction_id\": \"2ZFHrqBHb3cTfLVkFSGmHZqdDPi\",\n \"client_reference\": \"SUP-48213\",\n \"reason\": \"unauthorized\",\n \"description\": \"Cardholder says they never authorized this charge and still has the card.\",\n \"disputed_amount\": \"39.00\",\n \"disputed_currency\": \"USD\",\n \"consumer_notified_client_at\": \"2026-09-18T14:02:11Z\",\n \"client_forwarded_at\": \"2026-09-18T16:40:00Z\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-idempotency-key", "<x-idempotency-key>")
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}{
"id": "33Lm2Xc7Vb9Nq4Rt6Yw8Ze1Ua3S",
"card_id": "2tQRvvnYkN6edEJUTmF1LzTj2ug",
"card_transaction_id": "2ZFHrqBHb3cTfLVkFSGmHZqdDPi",
"client_reference": "SUP-48213",
"reason": "unauthorized",
"disputed_amount": "39",
"disputed_currency": "USD",
"consumer_notified_client_at": "2026-09-18T14:02:11Z",
"client_forwarded_at": "2026-09-18T16:40:00Z",
"state": "received",
"filing_state": "not_filed",
"dakota_filed_with_vendor_at": null,
"vendor_dispute_reference": null,
"rejection_reason": null,
"created_at": 1758220800,
"updated_at": 1758220800
}{
"type": "https://docs.dakota.xyz/api-reference/errors#not-found",
"title": "Customer Not Found",
"status": 404,
"detail": "Customer cst_2abc123 was not found in your organization.",
"instance": "https://api.platform.dakota.xyz/customers/cst_2abc123",
"request_id": "req_7f3a8b2c"
}{
"type": "https://docs.dakota.xyz/api-reference/errors#not-found",
"title": "Customer Not Found",
"status": 404,
"detail": "Customer cst_2abc123 was not found in your organization.",
"instance": "https://api.platform.dakota.xyz/customers/cst_2abc123",
"request_id": "req_7f3a8b2c"
}{
"type": "https://docs.dakota.xyz/api-reference/errors#not-found",
"title": "Customer Not Found",
"status": 404,
"detail": "Customer cst_2abc123 was not found in your organization.",
"instance": "https://api.platform.dakota.xyz/customers/cst_2abc123",
"request_id": "req_7f3a8b2c"
}{
"type": "https://docs.dakota.xyz/api-reference/errors#not-found",
"title": "Customer Not Found",
"status": 404,
"detail": "Customer cst_2abc123 was not found in your organization.",
"instance": "https://api.platform.dakota.xyz/customers/cst_2abc123",
"request_id": "req_7f3a8b2c"
}{
"type": "https://docs.dakota.xyz/api-reference/errors#not-found",
"title": "Customer Not Found",
"status": 404,
"detail": "Customer cst_2abc123 was not found in your organization.",
"instance": "https://api.platform.dakota.xyz/customers/cst_2abc123",
"request_id": "req_7f3a8b2c"
}{
"type": "https://docs.dakota.xyz/api-reference/errors#not-found",
"title": "Customer Not Found",
"status": 404,
"detail": "Customer cst_2abc123 was not found in your organization.",
"instance": "https://api.platform.dakota.xyz/customers/cst_2abc123",
"request_id": "req_7f3a8b2c"
}{
"type": "https://docs.dakota.xyz/api-reference/errors#not-found",
"title": "Customer Not Found",
"status": 404,
"detail": "Customer cst_2abc123 was not found in your organization.",
"instance": "https://api.platform.dakota.xyz/customers/cst_2abc123",
"request_id": "req_7f3a8b2c"
}{
"type": "https://docs.dakota.xyz/api-reference/errors#not-found",
"title": "Customer Not Found",
"status": 404,
"detail": "Customer cst_2abc123 was not found in your organization.",
"instance": "https://api.platform.dakota.xyz/customers/cst_2abc123",
"request_id": "req_7f3a8b2c"
}{
"type": "https://docs.dakota.xyz/api-reference/errors#not-found",
"title": "Customer Not Found",
"status": 404,
"detail": "Customer cst_2abc123 was not found in your organization.",
"instance": "https://api.platform.dakota.xyz/customers/cst_2abc123",
"request_id": "req_7f3a8b2c"
}Authorizations
Headers
Unique key (UUID) to ensure request idempotency on POST, PUT and PATCH requests.
A key is scoped to your client, the HTTP method and the path, and is remembered for 24 hours after a
successful (below 400) response. Repeating the same request (same JSON body, whatever the key order or
whitespace) with the same key within that window returns the original response with
X-Idempotent-Replayed: true instead of executing the request again. Using the same key on the same
endpoint with a different body returns 422 with problem type idempotency-key-reused; the request is
not executed. Error responses (4xx and 5xx) are not remembered, so a request refused for a fixable reason
can be corrected and retried under the same key. Request bodies that are not JSON (for example file
uploads) are not compared.
Body
The dispute report.
A report that a cardholder disputes a card transaction.
Recording it does not file a dispute with a card network, does not change the card transaction's status, and does not move money.
KSUID is a 27-character globally unique ID that combines a timestamp with a random component. Used for all entity identifiers in the Dakota platform.
27^[0-9A-Za-z]{27}$"1NFHrqBHb3cTfLVkFSGmHZqdDPi"
Your own case identifier for this report, unique across your reports. Resubmitting one already on file is answered with 409 naming the report that exists, so a retry after a timeout cannot record one notice twice. An idempotency key cannot do this job: it expires, and a client retrying with a fresh key would otherwise file a second report.
1 - 255"SUP-48213"
Why the cardholder disputes the transaction. A closed set, so the
portfolio can be counted by reason. Use other rather than a
reason that is nearly right — a wrong reason is worse than an
unclassified one.
unauthorized, not_received, incorrect_amount, duplicate, cancelled_recurring, other "unauthorized"
When the cardholder told you. Dakota cannot observe this, so you
assert it. Must not be later than client_forwarded_at, and must
not be in the future.
"2026-09-18T14:02:11Z"
When you passed the report to Dakota. Must not be in the future.
"2026-09-18T16:40:00Z"
KSUID is a 27-character globally unique ID that combines a timestamp with a random component. Used for all entity identifiers in the Dakota platform.
27^[0-9A-Za-z]{27}$"1NFHrqBHb3cTfLVkFSGmHZqdDPi"
Every Dakota card transaction this dispute covers. Required
whenever filing_reason is sent, except for
atm_deposit_missing — the one account-level reason, which
disputes a credit that never arrived and must send an empty list.
One dispute is raised per transaction, so this is the fan-out.
When you send it, card_transaction_id must also be set and must
be one of these: it stays the single transaction this report is
anchored to.
100KSUID is a 27-character globally unique ID that combines a timestamp with a random component. Used for all entity identifiers in the Dakota platform.
27^[0-9A-Za-z]{27}$["1NFHrqBHb3cTfLVkFSGmHZqdDPi"]
The reason to file the dispute under, from the card network's own set. Send it to file the dispute; omit it to record the report without filing.
This is NOT the same field as reason. reason classifies the
report for your own portfolio reporting and has six values; this
selects which network rules the case is fought under. Some values
are spelled the same in both sets and mean different things, so
they are kept apart deliberately.
Omitting it stays valid on purpose: a report whose transaction is not yet identified cannot be filed, and refusing to record it would lose a notice whose response clock is already running.
card_not_present, card_lost, card_stolen, card_never_received, counterfeit, account_takeover, product_not_received, not_as_described, credit_not_processed, cancelled_recurring, paid_by_other_means, duplicate_charge, late_presentment, incorrect_transaction_code, no_authorization, declined, incorrect_amount, atm_cash_not_dispensed, atm_deposit_wrong_amount, atm_deposit_missing "card_not_present"
The cardholder's own account of what happened, for the operator who files the dispute. Deliberately absent from the response: you sent it, and it is not echoed back.
4000"Cardholder says they never authorized this charge and still holds the card."
The disputed amount in MAJOR currency units, as a decimal string.
Omit both this and disputed_currency when the whole transaction
is disputed; send both for a partial dispute.
"42.50"
ISO 4217 currency code for disputed_amount. Required with it, and refused without it.
"USD"
Response
The report was recorded. state is received when a card transaction was named and awaiting_transaction when it was not.
Dakota's record that a cardholder disputed a card transaction, and of what Dakota did about it.
It carries neither description nor the identity of the operator who
filed: the first is the cardholder's own words, which you supplied and
which are not echoed back, and the second is internal.
KSUID is a 27-character globally unique ID that combines a timestamp with a random component. Used for all entity identifiers in the Dakota platform.
27^[0-9A-Za-z]{27}$"1NFHrqBHb3cTfLVkFSGmHZqdDPi"
KSUID is a 27-character globally unique ID that combines a timestamp with a random component. Used for all entity identifiers in the Dakota platform.
27^[0-9A-Za-z]{27}$"1NFHrqBHb3cTfLVkFSGmHZqdDPi"
How far the dispute's filing has got. Always present.
not_filed means Dakota has not filed this dispute — either you
sent no filing_reason, or the filing was attempted and did not
succeed. In the second case the report is still on file and its
response clock is running, so a not_filed report that names a
filing_reason needs following up.
The rest report what the provider holds: pending is a dispute
raised whose required information is still outstanding, filed is
submitted, and refused, withdrawn and abandoned are the ways
it ends without being submitted.
not_filed, pending, filed, refused, withdrawn, abandoned "pending"
Your own case identifier, as you sent it.
"SUP-48213"
How far the report has travelled. received is a report Dakota can
act on; awaiting_transaction is one whose card transaction is not
yet known; filed_at_vendor means an operator filed it by hand;
linked means it is tied to the resulting dispute; ambiguous
means several live reports share the disputed transaction and a
person must choose; rejected is how a report ends without a link.
linked and rejected are terminal.
received, awaiting_transaction, filed_at_vendor, linked, ambiguous, rejected "received"
Why the cardholder disputes the transaction, as you sent it.
unauthorized, not_received, incorrect_amount, duplicate, cancelled_recurring, other "unauthorized"
When the cardholder told you, as you asserted it.
"2026-09-18T14:02:11Z"
When you passed the report to Dakota, as you asserted it.
"2026-09-18T16:40:00Z"
Unix timestamp (seconds) when Dakota recorded the report. Server-observed, unlike the two instants you assert.
1758211200
Unix timestamp (seconds) of the last change.
1758297600
The disputed card transaction, once it is known. Null while it is not.
"2B5J8KZ9N7M1K3P6Q8R4T7V9"
The reason the dispute was filed under, as you sent it. Null on a report that was recorded without being filed.
card_not_present, card_lost, card_stolen, card_never_received, counterfeit, account_takeover, product_not_received, not_as_described, credit_not_processed, cancelled_recurring, paid_by_other_means, duplicate_charge, late_presentment, incorrect_transaction_code, no_authorization, declined, incorrect_amount, atm_cash_not_dispensed, atm_deposit_wrong_amount, atm_deposit_missing "card_not_present"
When Dakota recorded that the dispute was accepted for filing. Null until that happens, and it is not restated afterwards.
"2026-09-18T16:41:02Z"
The disputed amount in major currency units. Null when the whole transaction is disputed.
"42.5"
ISO 4217 currency code for disputed_amount.
"USD"
When a Dakota operator filed the dispute by hand. Null until that
happens, and write-once thereafter. The gap between
consumer_notified_client_at and this instant is Dakota's own
exposure window.
"2026-09-19T09:15:00Z"
The reference the filing produced, once the report is linked.
"dsp_9f2c41"
Why the report ended without a link. Set only when state is rejected.
"Cardholder withdrew the report."
Was this page helpful?

