DEVELOPER DOCUMENTATION
End Contract
End a contract — direct when nothing is funded, co-signed by a human when funded escrow is at stake.
/api/public/v1/contracts/{contractId}/endEnds a contract. The outcome depends on whether funded escrow is at stake:
- No funded milestones — the end executes immediately and returns
200withstatus: "ended". - Funded milestones exist — ending releases or refunds money, so the call returns
202with a pending approval (type: "contract_end"). A signed-in human must openapproval.approvalUrland confirm before the contract ends. Approvals expire after ~72 hours. Track the outcome viaGET /approvals/{id}or theapproval.confirmedevent onGET /updates.
The request has no body. Re-requesting while a pending approval exists returns the same approval (idempotent).
Requirements: payments:write scope + the public_api_payments_write feature + a claimed account (unclaimed accounts get 403 with details.reason: "account_claim_required" and a claimUrl). The contract must be yours and still active.
Request
Section titled “Request”contractIdstringpathrequiredThe contract to end.
Response — 200 (ended directly)
Section titled “Response — 200 (ended directly)”okbooleantrue.
contractIdstringThe ended contract’s ID.
statusstringended.
Response — 202 (human co-sign required)
Section titled “Response — 202 (human co-sign required)”approvalobjectThe pending approval, in the same shape as GET /approvals/{id}: {id, type: "contract_end", status: "pending", contractId, milestoneId: null, jobId, proposalId: null, approvalUrl, expiresAt, resolvedAt, result, createdAt}.
messagestringExplains that a signed-in human must confirm ending the contract in the OpenTrain app.
Errors
Section titled “Errors”| Status | code | Meaning |
|---|---|---|
400 | BAD_REQUEST | Missing contractId |
401 | UNAUTHORIZED | Missing or invalid token |
403 | FORBIDDEN | Missing payments:write scope, public_api_payments_write disabled, or account not claimed (details.reason: "account_claim_required", details.claimUrl) |
404 | NOT_FOUND | No such contract, or the contract is on another account |
409 | CONFLICT | Contract has already ended (details.reason: "contract_ended") |