dev.cocore.compute.dispute

cocore.dev

Documentation

main record

No description available.

Record Key tid Timestamp-based ID

Properties

createdAt string datetime Required

An RFC 3339 formatted timestamp.

evidenceCid string cid Optional

Optional CID of the encrypted evidence bundle the exchange relied on (request/response logs, customer correspondence, processor chargeback metadata). Encrypted to the exchange + parties; opaque to public verifiers.

exchange string did Required

Exchange DID. MUST equal the repo this record is published in. Adjudication is the exchange's prerogative; only the exchange that signed the settlement may sign its dispute.

outcome ref #disputeOutcome Optional

Required when status=resolved. Captures the verdict and any compensating settlement record.

raisedAt string datetime Required

When the complaint was first received. May predate `createdAt` (this record is published when the exchange opens or resolves the case, which can be after intake).

raisedBy string did Required

DID of the party who raised the complaint. Typically the requester (charge dispute) or the provider (non-payment claim). The exchange itself MAY raise a dispute when it detects a problem (e.g. processor chargeback fired before the requester reached out).

reason ref #disputeReason Required

Why the dispute was raised. Free-form rationale plus an enum bucket for matchmaking / analytics.

settlement ref com.atproto.repo.strongRef Required

Strong-ref to the dev.cocore.compute.settlement under dispute. Verifiers MUST resolve this to confirm both sides reference the same charge.

sig string Optional

ES256 signature (base64url, no padding) over the canonical JSON of every other field. Verified against the same verificationMethod that signs settlements for this exchange. Required for trust-tier=hardware-attested exchanges; optional in v0.3.x as we roll out signing across all records.

maxLength: 256 bytes
status string Required

Lifecycle state. The exchange opens the dispute (`open`) when intake is complete; once adjudicated, the same record is updated in place to `resolved` with outcome populated. Records at this NSID with status=open and no `outcome` are valid by construction; status=resolved without `outcome` is invalid.

Known values: open, resolved
View raw schema
{
  "key": "tid",
  "type": "record",
  "record": {
    "type": "object",
    "required": [
      "settlement",
      "exchange",
      "raisedBy",
      "raisedAt",
      "reason",
      "status",
      "createdAt"
    ],
    "properties": {
      "sig": {
        "type": "string",
        "maxLength": 256,
        "description": "ES256 signature (base64url, no padding) over the canonical JSON of every other field. Verified against the same verificationMethod that signs settlements for this exchange. Required for trust-tier=hardware-attested exchanges; optional in v0.3.x as we roll out signing across all records."
      },
      "reason": {
        "ref": "#disputeReason",
        "type": "ref",
        "description": "Why the dispute was raised. Free-form rationale plus an enum bucket for matchmaking / analytics."
      },
      "status": {
        "type": "string",
        "description": "Lifecycle state. The exchange opens the dispute (`open`) when intake is complete; once adjudicated, the same record is updated in place to `resolved` with outcome populated. Records at this NSID with status=open and no `outcome` are valid by construction; status=resolved without `outcome` is invalid.",
        "knownValues": [
          "open",
          "resolved"
        ]
      },
      "outcome": {
        "ref": "#disputeOutcome",
        "type": "ref",
        "description": "Required when status=resolved. Captures the verdict and any compensating settlement record."
      },
      "exchange": {
        "type": "string",
        "format": "did",
        "description": "Exchange DID. MUST equal the repo this record is published in. Adjudication is the exchange's prerogative; only the exchange that signed the settlement may sign its dispute."
      },
      "raisedAt": {
        "type": "string",
        "format": "datetime",
        "description": "When the complaint was first received. May predate `createdAt` (this record is published when the exchange opens or resolves the case, which can be after intake)."
      },
      "raisedBy": {
        "type": "string",
        "format": "did",
        "description": "DID of the party who raised the complaint. Typically the requester (charge dispute) or the provider (non-payment claim). The exchange itself MAY raise a dispute when it detects a problem (e.g. processor chargeback fired before the requester reached out)."
      },
      "createdAt": {
        "type": "string",
        "format": "datetime"
      },
      "settlement": {
        "ref": "com.atproto.repo.strongRef",
        "type": "ref",
        "description": "Strong-ref to the dev.cocore.compute.settlement under dispute. Verifiers MUST resolve this to confirm both sides reference the same charge."
      },
      "evidenceCid": {
        "type": "string",
        "format": "cid",
        "description": "Optional CID of the encrypted evidence bundle the exchange relied on (request/response logs, customer correspondence, processor chargeback metadata). Encrypted to the exchange + parties; opaque to public verifiers."
      }
    }
  }
}
disputeOutcome object

Exchange's verdict and any side-effects. The compensating refund (if any) is published as its own dev.cocore.compute.settlement with status=refunded and refundOf pointing at the original; this object strong-refs that record so verifiers don't need to scan.

Properties

decidedAt string datetime Required

An RFC 3339 formatted timestamp.

rationale string Optional

Exchange's plain-English explanation. Public; bind it carefully — this is the audit trail when the same parties dispute future charges.

maxLength: 2048 bytes
refundSettlement ref com.atproto.repo.strongRef Optional

When verdict is refund-*, strong-ref to the dev.cocore.compute.settlement record (status=refunded) the exchange published as the compensating action. Required when the verdict involves a refund.

verdict string Required

What happened. `refund-full` and `refund-partial` reverse value to the requester; `uphold-charge` keeps the original settlement intact; `forfeit-payout` keeps the requester's funds with the exchange but withholds the provider payout.

Known values: refund-full, refund-partial, uphold-charge, forfeit-payout
View raw schema
{
  "type": "object",
  "required": [
    "verdict",
    "decidedAt"
  ],
  "properties": {
    "verdict": {
      "type": "string",
      "description": "What happened. `refund-full` and `refund-partial` reverse value to the requester; `uphold-charge` keeps the original settlement intact; `forfeit-payout` keeps the requester's funds with the exchange but withholds the provider payout.",
      "knownValues": [
        "refund-full",
        "refund-partial",
        "uphold-charge",
        "forfeit-payout"
      ]
    },
    "decidedAt": {
      "type": "string",
      "format": "datetime"
    },
    "rationale": {
      "type": "string",
      "maxLength": 2048,
      "description": "Exchange's plain-English explanation. Public; bind it carefully — this is the audit trail when the same parties dispute future charges."
    },
    "refundSettlement": {
      "ref": "com.atproto.repo.strongRef",
      "type": "ref",
      "description": "When verdict is refund-*, strong-ref to the dev.cocore.compute.settlement record (status=refunded) the exchange published as the compensating action. Required when the verdict involves a refund."
    }
  },
  "description": "Exchange's verdict and any side-effects. The compensating refund (if any) is published as its own dev.cocore.compute.settlement with status=refunded and refundOf pointing at the original; this object strong-refs that record so verifiers don't need to scan."
}
disputeReason object

Bucketed reason plus free-form detail. Buckets exist so the AppView can index disputes; detail is for the operator's own audit.

Properties

category string Required

Bucket the dispute fits into. `processor-chargeback` is reserved for cases where the card network fired the chargeback ahead of any direct complaint.

Known values: fraud, non-delivery, quality-failure, processor-chargeback, duplicate-charge, other
detail string Optional

Operator-supplied free-form detail. Public; do not include personally identifying information.

maxLength: 2048 bytes
View raw schema
{
  "type": "object",
  "required": [
    "category"
  ],
  "properties": {
    "detail": {
      "type": "string",
      "maxLength": 2048,
      "description": "Operator-supplied free-form detail. Public; do not include personally identifying information."
    },
    "category": {
      "type": "string",
      "description": "Bucket the dispute fits into. `processor-chargeback` is reserved for cases where the card network fired the chargeback ahead of any direct complaint.",
      "knownValues": [
        "fraud",
        "non-delivery",
        "quality-failure",
        "processor-chargeback",
        "duplicate-charge",
        "other"
      ]
    }
  },
  "description": "Bucketed reason plus free-form detail. Buckets exist so the AppView can index disputes; detail is for the operator's own audit."
}

Lexicon Garden

@