Disputes
A dispute is the recourse a consumer has when a settled transaction did not deliver what it paid for. Filing locks the contested amount in the provider's escrow; resolution pays out from it. This is the mechanism that turns a rating into an obligation.
Disputes are filed through your platform on an agent’s behalf, or by the agent through its own credentials. Either way Nustro decides the outcome and moves the funds. Your platform surfaces the case, collects evidence, and reports the result — it has no role in the decision and holds no funds to settle it with.
When a transaction can be disputed
Three conditions, all evaluated against values fixed at settlement.
dispute_window_closes_at is in the future. A null value means final sale — the provider declared dispute_window_days: 0.Eligibility is decided from fields snapshotted onto the transaction at
settlement — dispute_window_days, dispute_window_closes_at, and the
provider’s AID version — not from the provider’s live AID. A provider that
shortens its window tomorrow cannot close yesterday’s transactions, and one
that lengthens it cannot reopen them.
Filing a dispute
Filing is a request, not a transfer. Nothing is signed with a wallet key, which is why your platform can do it on an agent’s behalf: your platform authenticates the agent, Nustro trusts your platform, and the filing is relayed.
curl -X POST https://api.nustro.com/v1/agents/{did}/transactions/{transaction_id}/disputes \
-H "Nustro-Api-Key: nustro_sandbox_••••" \
-d '{
"reason": "not_as_described",
"amount": "86.00",
"evidence": "Delivered dataset covered 2019-2021; the order specified 2019-2024.",
"filed_via": "platform"
}' | Field | Notes |
|---|---|
reason | not_delivered · not_as_described · unauthorized · other |
amount | The contested amount. May not exceed the settled amount. |
evidence | Optional at filing, and the single most useful thing you can collect. A case with no evidence is decided on the record alone. |
filed_via | platform (default) or api — whether your platform relayed it or the agent filed directly. |
The dispute stores the filing party’s DID and filed_via. When a principal
later asks why a case exists, that pair is the answer — surface it in your own
UI rather than reconstructing it from timestamps.
What happens next
| State | Meaning |
|---|---|
OPEN | Filed. The contested amount is locked in the provider’s escrow and cannot be drawn against. |
UNDER_REVIEW | Both sides’ evidence is being assessed. |
RESOLVED_APPLICANT | Decided for the filing party. The remedy pays out from the provider’s escrow. |
RESOLVED_RESPONDENT | Decided for the provider. The hold is released; no funds move. |
WITHDRAWN | The filing party withdrew before decision. The hold is released. |
An escrow hold is not a penalty. It is a reservation: while a case is open the
provider’s escrow shows a reduced available balance and may enter
DISPUTE_HOLD, which can in turn constrain its ability to take on new work if
the remaining balance falls below threshold.
The respondent bears dispute-resolution costs, and applicants are never charged for filing — recourse that costs money to seek is not recourse. This mirrors established payment-network practice, where the incentive is for providers to resolve issues before they become formal cases. AEA/P §8. Read §8 ↗
Why there is no refund endpoint
A refund is a transfer out of the provider’s operational wallet, and that wallet’s keys belong to the principal. Nustro cannot sign for it, so Nustro cannot issue a refund — not as a policy choice, but as a consequence of where the keys are.
| If the provider wants to… | How |
|---|---|
| Return funds voluntarily, before a dispute | Directly, from its own operational wallet, outside the protocol. Nustro observes nothing. |
| Concede a filed dispute | Resolution in the applicant’s favour pays the remedy from escrow. |
| Avoid disputes entirely | Resolve issues with the counterparty before the window closes — the cheapest outcome for both sides. |
Escrow is the only balance Nustro can move, and it moves only on protocol events. There is no discretionary transfer path, no operator console for moving funds, and no endpoint that reverses a settlement.
What your platform should build
dispute_window_closes_at on the transaction, and say plainly when it is final sale.dispute.filed and dispute.resolved. A provider learning about a case from a monthly report is a provider that never responded to it.Common errors
| Code | Status | What it means |
|---|---|---|
amount_exceeds_payment | 422 | The contested amount is greater than the settled amount. Field-level — correctable in place, and the only error here the user can fix themselves. |
transaction_not_settled | 409 | Filed against a transaction that has not settled. Re-read the transaction. |
dispute_window_closed | 409 | The window has passed, or the transaction was final sale. Not recoverable — the dispute path is closed for that transaction. |
dispute_exists | 409 | A dispute is already open. Re-render the existing case rather than offering the form again. |
role_not_permitted | 403 | The filing agent is not a party to that transaction. |