FCRA Partner API · v1.0.0

Managing disputes

A dispute is an endpoint. Open it with the records and the date it reached you, follow it by webhook, and apply the outcome everywhere you hold the record.

What you’ll build

The dispute flow from your side: when a consumer disputes a record you received from us, open a reinvestigation on the order naming the records, the reason and when the dispute reached you; add the consumer’s new information if it arrives; receive the outcome by dispute.updated; and react to record.corrected, which reaches every partner that received the record. You will run it on the sandbox subject Dispute, whose dispute resolves deleted sixty seconds after you file it.

Before you start

  • A completed sandbox order for Pat Dispute (1980-01-01) with a criminal search; it furnishes one record with id sandbox:criminal:dispute-1980-01-01.
  • Required: recordIds[] (1–100, each furnished in this order — including by a superseded search) and reason ∈ not_me, inaccurate, incomplete, outdated, other. Optional: consumerStatement (≤ 8,000), receivedAt (a past date-time).
  • Statuses: received → investigating → verified | modified | deleted | unable_to_verify. overdue is true for an open dispute past dueAt.
Send `receivedAt`. The 30-day clock runs from when the dispute reached you (15 U.S.C. § 1681i(a)(1)); without receivedAt it runs from the call. dueAt is receivedAt + 30 days. If the consumer sends new information during the investigation, POST /v1/fcra/disputes/{dispute_id}/information moves dueAt by 15 days — once (15 U.S.C. § 1681i(a)(1)(B)).

Step by step

  1. Open the dispute. POST /v1/fcra/orders/{order_id}/disputes → 201 at received with dueAt. You also receive dispute.created.
  2. Add information if it comes. POST /v1/fcra/disputes/{dispute_id}/information with { "statement": "…" } → 200 with dueAt moved and extendedAt set; 409 dispute_not_extendable if resolved, already extended, or past due.
  3. Follow it. dispute.updated on each change; GET /v1/fcra/disputes/{dispute_id} for the current state; GET /v1/fcra/disputes?status=&orderId= lists every dispute on your orders, earliest due first.
  4. Apply the outcome. verified: nothing changes. modified: changes says what; the record carries corrections[] in later orders. deleted and unable_to_verify: the record is suppressed from every later FCRA order. All three send record.corrected to every partner that received the record.
curl -X POST https://sandbox.offendersearch.app/v1/fcra/orders/fo_ee0b34c5b52fd35b/disputes \
  -H "X-API-Key: $OFFENDERSEARCH_TEST_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "recordIds": ["sandbox:criminal:dispute-1980-01-01"],
    "reason": "not_me",
    "consumerStatement": "I have never lived in that county.",
    "receivedAt": "2026-10-25T09:12:00Z"
  }'
201 Created
{
  "id": "fd_acae08b7d57ccc18",
  "orderId": "fo_ee0b34c5b52fd35b",
  "origin": "partner",
  "recordIds": ["sandbox:criminal:dispute-1980-01-01"],
  "reason": "not_me",
  "consumerStatement": "I have never lived in that county.",
  "receivedAt": "2026-10-25T09:12:00+00:00",
  "dueAt": "2026-11-24T09:12:00+00:00",
  "extendedAt": null,
  "status": "received",
  "notes": null,
  "changes": null,
  "resolvedAt": null,
  "overdue": false
}
GET /v1/fcra/disputes/{dispute_id} a minute later (sandbox)
{
  "id": "fd_acae08b7d57ccc18",
  "orderId": "fo_ee0b34c5b52fd35b",
  "origin": "partner",
  "recordIds": ["sandbox:criminal:dispute-1980-01-01"],
  "reason": "not_me",
  "status": "deleted",
  "receivedAt": "2026-10-25T09:12:00+00:00",
  "dueAt": "2026-11-24T09:12:00+00:00",
  "extendedAt": null,
  "notes": null,
  "changes": null,
  "resolvedAt": "2026-10-25T14:31:19.004118+00:00",
  "overdue": false
}
The record.corrected event every furnished partner receives
{
  "id": "fev_9c1d3e5f7a2b4068",
  "type": "record.corrected",
  "createdAt": "2026-10-25T14:31:19.021776+00:00",
  "data": { "recordId": "sandbox:criminal:dispute-1980-01-01", "disputeId": "fd_acae08b7d57ccc18", "outcome": "deleted" }
}

Reading the result

FieldValuesWhat it decides
statusreceived, investigatingOpen. The clock is running; overdue flips when dueAt passes.
statusverifiedConfirmed as furnished. Nothing changes.
statusmodifiedCorrected. changes lists what; later orders carry corrections[] on the record.
statusdeletedRemoved, or found not to be the consumer’s. Suppressed from every later FCRA order (disputed_suppressed).
statusunable_to_verifyCould not be verified. Treated as deleted: suppressed the same way.
dueAt, extendedAtdate-timesreceivedAt + 30 days; + 15 days once when information is added, with extendedAt recording when.
originpartner, consumer_portalWho opened it. Portal disputes are the same object and reach you by dispute.created.

Edge cases and pitfalls

  • `422 unknown_record` — a recordIds entry was not furnished in this order (the message names it). Use the recordId exactly as the search returned it.
  • `receivedAt` in the future is a 422; a receivedAt long in the past makes the dispute overdue at once. Send the real date.
  • `409 dispute_not_extendable` carries one of three messages: already resolved, already extended once, or the period has ended.
  • Disputes without an access code reach us through the consumer request form, are reinvestigated by our team and are not listed among your disputes; when one deletes or corrects a record you received, you still get record.corrected.
  • `record.corrected` can arrive for an old order and from another partner’s dispute. Key your handling on recordId, not on your open disputes.
  • The list is unpaginated, ordered earliest due first; filter with status and orderId.
  • Sandbox auto-resolution applies only to the subject Dispute and only to deleted; other outcomes need a production dispute.

Production checklist

  • Open disputes with receivedAt; store fd_ ids against the consumer’s case.
  • Consume dispute.created, dispute.updated and record.corrected; suppress or correct the record in your own copies.
  • Watch overdue on the list; escalate before dueAt.
  • Notices to the consumer about the outcome, and any adverse-action steps, stay with you; the API reinvestigates and corrects the record.

Product overview