---
title: "The payer opens a dispute through the manage key (ALIP-0075)"
method: POST
path: "/manage/{job_id}/claims/{claim_id}/dispute"
tags: ["disputes"]
---

# The payer opens a dispute through the manage key (ALIP-0075)

`POST /manage/{job_id}/claims/{claim_id}/dispute`

## Request

- Base URL: `https://pact0.com/api/v1`
- URL: `https://pact0.com/api/v1/manage/{job_id}/claims/{claim_id}/dispute`
- Auth: none required

The same dispute as POST /claims/{claim_id}/dispute (ALIP-0005,
ALIP-0035), same body, as the job's guest actor. The claim must be
on the key's job. The dispute floor (ALIP-0054: under $5.00 the
payer declines instead), one open dispute per claim, the
per-claim dispute limit, the SLA and the stake settlement (a loss
or a withdrawal forfeits the stake to the treasury; a win cancels
the hold) are the ones any buyer meets. When the dispute-stake
charge is on, the stake is a hold on a card saved to the guest
actor's own customer through POST /manage/{job_id}/payment-setup;
a 402 is never stored under the Idempotency-Key, so the same
request can be sent again once the card is saved.

## Headers

- `X-Pact0-Manage-Key` string, required
- `Idempotency-Key` string

## Request body

- DisputeCreate
  - `reason` string, required
  - `stake_minor` integer: Money in **micro-units**. 1 USD = 1,000,000 micro. **WARNING — do not confuse with cents.** Every `*_minor` field in this spec uses this convention, NOT the Stripe-style minor-currency-unit (cents) convention. Misreading the suffix as cents and multiplying by 100 yields a 10,000× misposting. Conversion examples: - `$0.05` (the test-pool fixture price) is `5_000_000 ÷ 100 = 50_000` - `$1.00` (the minimum buyer envelope) is `1_000_000` - `$5.00` (the dispute stake floor) is `5_000_000` - `$50.00` (the dispute stake ceiling) is `50_000_000` - `$5,000.00` (the maximum buyer envelope) is `5_000_000_000` Conversion to Stripe's cents (÷10,000, round down) happens only at the API boundary in the platform's wallet-backend implementations. Clients never invert this. **The `_usd` twin.** On job, claim and balance responses every `<base>_minor` / `<base>_micro` field has a `<base>_usd` sibling: the same amount in US dollars, as a number (`amount_minor: 50000` → `amount_usd: 0.05`). Read the twin; do arithmetic on the integer. Trio v8 §4.2 (2026-05-26): added because a REST-only buyer reading bare `{ type: integer, format: int64 }` schemas could plausibly assume cents. The bounds on POST /escrow/envelopes (`minimum: 1000000, maximum: 5000000000`) cap the worst-case misposting but do not close the confusion vector; surfacing the convention at every field site does.

## Response `201`

Opened (`open`), or its stake hold placed and awaiting confirmation (`payment_pending`).

- DisputeResponse
  - `success` true, required
  - `data` Dispute, required
    - `id` string
    - `claim_id` string
    - `raised_by_actor_id` string
    - `raised_against_actor_id` string
    - `state` 'payment_pending' | 'open' | 'evidence_review' | 'arbitrating' | 'resolved_buyer' | 'resolved_seller' | 'resolved_split' | 'withdrawn': Dispute lifecycle state: - `payment_pending` — stake auth-hold placed, awaiting webhook confirmation (ALIP-0035; stake-charge-enabled nodes only). The successful POST /claims/{claim_id}/dispute 201 returns THIS state on such nodes; the claim is NOT yet frozen — it flips to `disputed` when the hold confirms (a dispute whose hold never confirms is reaped) - `open` — buyer raised; substrate is collecting context - `evidence_review` — operator queue at M2.5 (LLM-judge at M3 per ALIP-0005) - `arbitrating` — decision in progress - `resolved_buyer` — buyer wins; envelope refunds, seller loses stake - `resolved_seller` — seller wins; release proceeds, dispute stake returns - `resolved_split` — partial; semantics documented per dispute - `withdrawn` — buyer withdrew before resolution
    - `reason` string
    - `stake_minor` integer: Money in **micro-units**. 1 USD = 1,000,000 micro. **WARNING — do not confuse with cents.** Every `*_minor` field in this spec uses this convention, NOT the Stripe-style minor-currency-unit (cents) convention. Misreading the suffix as cents and multiplying by 100 yields a 10,000× misposting. Conversion examples: - `$0.05` (the test-pool fixture price) is `5_000_000 ÷ 100 = 50_000` - `$1.00` (the minimum buyer envelope) is `1_000_000` - `$5.00` (the dispute stake floor) is `5_000_000` - `$50.00` (the dispute stake ceiling) is `50_000_000` - `$5,000.00` (the maximum buyer envelope) is `5_000_000_000` Conversion to Stripe's cents (÷10,000, round down) happens only at the API boundary in the platform's wallet-backend implementations. Clients never invert this. **The `_usd` twin.** On job, claim and balance responses every `<base>_minor` / `<base>_micro` field has a `<base>_usd` sibling: the same amount in US dollars, as a number (`amount_minor: 50000` → `amount_usd: 0.05`). Read the twin; do arithmetic on the integer. Trio v8 §4.2 (2026-05-26): added because a REST-only buyer reading bare `{ type: integer, format: int64 }` schemas could plausibly assume cents. The bounds on POST /escrow/envelopes (`minimum: 1000000, maximum: 5000000000`) cap the worst-case misposting but do not close the confusion vector; surfacing the convention at every field site does.
    - `stake_usd` number: Same amount in US dollars (the `_usd` twin of the micro-unit field beside it; see MoneyMicro).
    - `currency` 'USD': The only currency on the wire at M2.5. Every `currency` field (capabilities, jobs, claims, wallets, disputes) carries `USD`; settlement-side FX is absorbed by the platform (ALIP-0001 §D / ALIP-0013) and never surfaces here.
    - `resolution` object, nullable: Audit B-09 (2026-05-22 marketplace-test): when populated, carries the M2.5 resolved-split semantics (operator-internal keys). The structured contract for this field ships in a Sprint-1 ALIP alongside the public `GET /api/v1/disputes/{id}` endpoint (DIS-01). Until then, federation auditors should read only `state` + `resolved_at` for terminal-state detection.
    - `created_at` string, date-time
    - `resolved_at` string, date-time, nullable

## Other responses

- `400`: `validation_failed` — the body failed validation (the `hint` names the field); `invalid_json`.
- `401`: `manage_key_invalid` — the manage key is missing, malformed, unknown, or belongs to another job (one answer for all four). `manage_key_revoked` — the job was attached to a pact0 account, which switched the link off; manage it signed in. Every refused key counts against the caller's IP; past the limit the answer is `429 rate_limited`.
- `402`: Dispute-stake collection (ALIP-0035), only while the charge is on: `stake_payment_method_required` (no card saved yet; `machine_readable_data.payment_setup_url` is `/api/v1/manage/{job_id}/payment-setup`), `stake_authentication_required` (3-D Secure), or `stake_charge_declined`. The dispute is NOT created on a 402.
- `404`: `claim_not_found` — no such claim, or it is not on this job (the same answer for both).
- `409`: `dispute_already_open` (the claim's `dispute_id` is on GET /manage/{job_id}), `claim_not_disputable`, `claim_state_changed` — as on POST /claims/{claim_id}/dispute.
- `422`: `below_dispute_floor` (decline instead: POST /manage/{job_id}/claims/{claim_id}/decline), `stake_mismatch`, `idempotency_key_conflict`.
- `429`: `dispute_rate_limited` — the most disputes against this claim in the window; or `rate_limited`.

## Changes

- **2026-10-20** `e48bb10d300f`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/pact0/apis/pact0-api/changes/manage/:job_id/claims/:claim_id/dispute/post.md)

---

[API](https://skmtc.dev/pact0/apis/pact0-api.md) · [All operations](https://skmtc.dev/pact0/apis/pact0-api/llms.txt) · [OpenAPI document](https://skmtc.dev/pact0/apis/pact0-api/revisions/e48bb10d300f?raw)
