Skip to content
Insights · Engineering

Which dispute did that charge open?

Name the dispute on that charge: the id, the status, and the reason. A different dispute can point at another charge, and another account does not list it.

Scroll
EngineeringOct 30, 202613 min readBy Salman Naqvi, Founder & CEO
Which dispute did that charge open?

A cardholder says the bank took the payment back, or says it did not. Tonight, three proofs, in a console you administer. Name the dispute on that charge: the dispute id, the status, the reason, and the charge it points at. Show a different dispute whose charge, or whose reason, is not this one. Show another account's list that does not contain this dispute. If any of the three needs the person who wired checkout, you have not shown the dispute. You have a complaint and a guess.

This is the method on one dispute. It is not the refund. Which refund did that charge get? is the refund id, the status, and the amount. A dispute can be open while no refund exists, and a refund can succeed while the dispute status is still an inquiry. It is not the card. Which card did that charge use? is the brand and the last four. A reason of fraudulent is not a brand, and a last four is not a dispute id. It is not the subscription. Which status is that subscription in? is one of the names a subscription stores. subscription_canceled as a dispute reason is not the status canceled on a plan. It is not the figure on the screen. Show the price they accepted is the amount they were shown. A price can be right while the dispute amount is a different integer.

None of what follows is a rate for this product, and none of it is legal advice. The fields below are one processor's current description of a dispute. The counts below that are a 2020 study of marketplace conversations, plus the labels that study chose to keep. A status enum is not a census of your customers. A classifier that never opened your charge cannot name the dispute on the charge you opened tonight. They do tell you which numbers people mix up when they try to sound precise about a dispute they have not opened.

Stripe's sample dispute prints id du_1MtJUT2eZvKYlo2CNaw2HvEv, object dispute, amount 1000, currency usd, and created 1680651737. 1000 is an integer in the smallest currency unit. The page does not print a dollar sign next to it. Do not rewrite 1000 as a price you prefer. 1680651737 is a Unix timestamp on an example. It is not a count of disputes, and it is not a calendar date you get to invent. The sample's charge is ch_1AZtxr2eZvKYlo2CJDX8whov. The sample's payment_intent is null. A null payment intent is not a missing dispute. The sample's reason is general, and its status is warning_needs_response. livemode is false. balance_transactions is an empty array. An empty array is zero transactions, and the attribute text says the list can hold zero, one, or two. Zero is not one, and one is not two. Two balance transactions are a withdrawal and a reinstatement. An empty list is neither (Stripe, The Dispute object).

The status names and the reason names are not one list. The status enum is warning_needs_response, warning_under_review, warning_closed, needs_response, under_review, appeal_needs_response, appeal_under_review, won, lost, and prevented. Ten names. warning_needs_response is an inquiry that requires a response. needs_response is a dispute that requires a response. The sample is the first of those, not the second. warning_closed is an inquiry closed without becoming a formal dispute. prevented is a dispute that was prevented from becoming a formal chargeback. won is resolved in the merchant's favor. lost is resolved in the customer's favor. An inquiry is not a win, and prevented is not won. The reason enum is bank_cannot_process, check_returned, credit_not_processed, customer_initiated, debit_not_authorized, duplicate, fraudulent, general, incorrect_account_details, insufficient_funds, noncompliant, product_not_received, product_unacceptable, subscription_canceled, and unrecognized. Fifteen names. general is a reason. It is not a status. fraudulent as a dispute reason is not a refund's failure_reason. duplicate as a reason is not a second dispute id. Ten statuses are not fifteen reasons.

The evidence hash on the sample is twenty-seven fields, and every one of them is null. access_activity_log, billing_address, cancellation_policy, cancellation_policy_disclosure, cancellation_rebuttal, customer_communication, customer_email_address, customer_name, customer_purchase_ip, customer_signature, duplicate_charge_documentation, duplicate_charge_explanation, duplicate_charge_id, product_description, receipt, refund_policy, refund_policy_disclosure, refund_refusal_explanation, service_date, service_documentation, shipping_address, shipping_carrier, shipping_date, shipping_documentation, shipping_tracking_number, uncategorized_file, and uncategorized_text. Twenty-seven nulls. A null receipt is not a missing dispute. evidence_details on the same object prints due_by 1682294399, has_evidence false, past_due false, and submission_count 0. 0 is not false, and false is not a due date. Subtract the created integer from due_by and the difference is 1642662 seconds. Nineteen times 86400 is 1641600. The remainder is 1062 seconds. 1642662 is not 1641600, so the gap is not nineteen days. Do not round it until the page does. 1642662 is also not 1000.

The update call is a second page, and its limits are not the sample's amount. Updating any evidence field submits all fields in the hash. The combined character count of all fields is limited to 150000. 150000 is not 1000, and it is not 1642662, and it is not twenty-seven. The prerequisite on that page creates a PaymentIntent with amount 100, currency usd. 100 is not the sample dispute's 1000. Do not merge the prerequisite into the dispute. The update response then prints the same dispute id, and metadata order_id 6735. The object-page sample prints metadata as an empty object. Empty is not 6735. 6735 is not 1000. submit defaults to true, which sends evidence to the bank. false stages it. Staged evidence is visible, and it is not submitted. The version header on the example is 2026-10-28.endive. That string is not the integer 1680651737. intended_submission_method has four values: manual, prefer_manual, prefer_smart_disputes, and smart_disputes. prefer_manual is not prefer_smart_disputes. manual means you will not use Smart Disputes. smart_disputes means you will not use the manual packet. Four names are not ten statuses. enhanced_eligibility_types has three values: mastercard_compliance, visa_compelling_evidence_3, and visa_compliance. visa_compelling_evidence_3 is not visa_compliance. Three is not four. is_charge_refundable is true on the sample, while the status is still warning_needs_response. True on that boolean is not the status won, and it is not a refund id (Stripe, Update a dispute).

The study people reach for when they want a win rate did not open a processor console. David Tsurel, Michael Doron, Alexander Nus, Arnon Dagan, Ido Guy, and Dafna Shahaf built a dataset of eBay disputes from 2010 to 2019, on the US site, across 8354 categories. They sampled 1000000 messages, dropped duplicates from table joins, and aggregated them into 72023 buyer-seller conversations. A second, independent fastText set is also 1000000 messages. Two samples of the same printed size are not one sample of 2000000, and the page does not print that sum. Do not add them. The years 2010 and 2019 are not the conference dates. The paper is in CIKM, 19 to 23 October 2020. The header also prints a proceedings price of 15.00. 15.00 is not the dispute sample's 1000, and it is not 72023 (Tsurel et al., E-Commerce Dispute Resolution Prediction).

The labels they kept are a cut, not the whole queue. They say there are over 40 resolution options, including partial refunds, timeouts, item arrival, and third-party fault, and that the paper keeps only two: the arbitrator ruled for the seller, or for the buyer. Seller wins are 42880, printed as 59.6%. Buyer wins are 29143, printed as 40.4%. 42880 plus 29143 is 72023. The addition of the counts matches the conversation count. The printed percents do not match the quotients rounded to one decimal. 42880 divided by 72023 is 0.595, which rounds to 59.5%, not 59.6%. 29143 divided by 72023 is 0.405, which rounds to 40.5%, not 40.4%. 59.6 plus 40.4 is 100. 59.5 plus 40.5 is also 100. They printed the pair that sums to 100 and is a tenth away from each quotient. Do not cite 59.6% as if it were 42880 over 72023. Over 40 options is not two labels, and two labels are not ten Stripe statuses.

The model table and the later all-features row are not the same run. Table 2 prints XGBoost at AUROC 0.94, accuracy 0.86, precision 0.89, recall 0.88, and F1 0.89. Table 4 prints All Features at AUROC 0.94, accuracy 0.87, precision 0.89, recall 0.89, and F1 0.89. 0.86 is not 0.87. 0.88 is not 0.89. The same AUROC does not make the accuracy cells interchangeable. Majority, in Table 2, is AUROC 0.5, accuracy 0.60, precision 0.60, recall 1.0, and F1 0.75. 0.60 is not 59.6%, and it is not 0.595. A baseline that always says seller wins is not a dispute id. Segmenting by claim type and seller type dropped XGBoost AUROC from 0.94 to 0.92. 0.92 is not 0.94. Random Forest in Table 2 is accuracy 0.84 and recall 0.89. 0.84 is not 0.86.

The appeal split does not cover the set. No appeals are 79.78% of cases, with accuracy 0.96. One appeal is 14.37%, with accuracy 0.88. Two appeals are 3.67%, with accuracy 0.8. 79.78 plus 14.37 plus 3.67 is 97.82, not 100. The page does not print the remaining share. Do not invent it. 0.96 is not 0.88, and 0.88 is not 0.8. They print 0.8 on the two-appeal cell, not 0.80. Incorrectly classified disputes had agent summaries of 923 characters on average, versus 618. 923 is not 618. Neither is 150000, and neither is the sample amount 1000. The validation set used for tuning is 70671 disputes. 70671 is not 72023. Fifty hyperparameter configurations, on a 5-fold split. 50 is not 5.

The winning settings are not one depth. KNN settled on 7 neighbors. Random Forest settled on 178 trees and a maximum depth of 72. XGBoost settled on 225 trees, a learning rate of 0.025, and a maximum depth of 309. 7 is not 178. 178 is not 225. 72 is not 309. 0.025 is not 0.5, the Majority AUROC, and it is not 0.94. The highest gain in Table 3 is First escalating party, gain 119.65, correlation 0.54. The next row, whether the seller responded, is gain 39.99 and is the 192nd most correlated feature. 119.65 is not 39.99. 192 is a rank, not a gain. A correlation of 0.54 is not a Stripe status. None of these integers is du_1MtJUT2eZvKYlo2CNaw2HvEv.

Do the three proofs on one real dispute, in the console that actually holds it. First, the binding. Copy the dispute id, the status, the reason, the amount, the currency, and the charge id. If the status is warning_needs_response, write that it is an inquiry. Do not rewrite it as needs_response because the words look alike. If payment_intent is null, write null. If evidence is twenty-seven nulls and submission_count is 0, write that. Do not infer fraudulent because the customer sounded angry. Do not infer 1000 because a sample prints it. Second, the other dispute. A different dispute, with a different id, or a different charge, is not this one. A chart of seller wins is not that second dispute. If you cannot show a dispute that is not this one, you have a counter, not a record. Third, the other account. A list that belongs to someone else does not contain this dispute id. If the only list is a single shared table and you cannot say whose dispute it is, write that. A tenant you cannot name is the finding.

Three moves feel like the proof and are a second problem. Accepting the dispute, or submitting evidence, because the status was embarrassing, before you have copied the id. Submitting stages or sends a packet. It does not tell you which dispute you were looking at. Quoting 59.6% because it looks precise, while the dispute you were asked about is one row, and the conversations that produced that percent had not opened your charge. Asking a model which of the ten statuses it was. The model will pick a plausible name. It will not open the dispute. A refund you have not kept, while the customer is arguing about money coming back, is which refund did that charge get?. Opening that screen does not name the dispute id.

The path is ordinary when an operator can open one merchant's payment without opening the next merchant's payment as the way to prove it. PayOrch is a payment orchestration dashboard: wallets, providers, merchants, fees, and fraud controls in one view. The shape that matters here is one payment you can point at, in an account you administer, distinct from the next payment. That case is not a dispute ledger. Nothing in the description is a headcount, a duration, or a result figure. If the only control on the screen changes every merchant's balance together, you do not have this proof. You have a totals page.

There is a version of this afternoon where hiring the path is the wrong purchase. Nothing has been charged, because the product does not take money yet. You have no product. You are still choosing who will build, and the document in front of you is a term sheet. The criteria for that choice sit on the page written for a top SaaS development company. That page is criteria. It does not rank anyone, including us. The only fact in the room is a share from a paper. 59.6% is not your dispute, and 1000 is not your dispute. A customer has already seen another customer's payment. Naming a status does not close a leak. Or you wanted a lawyer to say whether a network rule applies. Hire the lawyer.

When the charge is real and the console cannot name the dispute, the missing object is specific. An admin action, in an account you administer, that shows one dispute id, one status, one reason, and one charge, shows a different dispute that is not that one, and shows another account's list without it. A startup software development company that expects this will have put that action next to the rest of the billing screen, before a stranger's complaint is the way you discover the vendor owns the dispute. One that needs a call in order for you to see which dispute is stored is telling you who holds the case. If the first slice is a fixed capability, an AI integration sprint is the shape where the acceptance sentence can include the three proofs. If you do not yet know which system stores the dispute, a two-week AI readiness assessment maps the systems. The findings are yours. They are not a promise that a paper's share applies, and they are not 1000.

The alert a dependency raised, and the document a citation named, are different objects: which alert did that dependency raise? and which document did that citation name?. Do not record either on this page. An alert number is not a dispute id. A document index is not a dispute status. The invoice that charge paid is a different object: which invoice did that charge pay?. Do not record it on this page. An invoice id is not a dispute id.

Before you tell them the bank opened a case, do the three proofs and write the status. Name the dispute, the status, the reason, and the charge, or write that no dispute was stored. Show a different dispute that is not that one. Show another account's list that does not hold it. Do not submit evidence to avoid reading the status, and do not ask a model which of the ten it was. A paper can tell you how often a marketplace's arbitrator sided with the seller in a cut of old conversations. The binding is the dispute you can defend.

Questions

Three records, in a console you administer. The dispute id, the status, the reason, and the charge it points at. A different dispute whose charge or reason is not this one. Another account's list that does not contain this dispute. If any of the three needs the person who wired checkout, you do not have the proof.

No. A percentage is a share of someone else's conversations, and the study that prints 59.6% did not open your charge. A dispute you can defend is the id, the status, and the reason on this charge, or a written line that the console does not store one. 1000 on a sample object is not your customer's amount, and 72023 conversations is not a status.

When nothing has been charged, when you have no product, when you are still choosing a firm, when the only fact in the room is a paper's percentage, when a customer has already seen another customer's payment, or when you wanted a lawyer.

Find this useful? Tell Google to show you more of it.

Let's put AI to work in your business.

A 30-minute call. You bring the workflow or the roadmap — we'll tell you what's feasible, what it costs, and what we'd build first.

Book a call→