# Property management and tenant screening

> Applicant screening is a housing decision and runs as an FCRA order; awareness of the community around a property is a different job with a different endpoint. This article keeps the two apart.

- **HTML:** https://offendersearch.app/docs/solutions/property-management
- **Base URL (live):** https://api.offendersearch.app — live keys (`os_live_…`)
- **Base URL (sandbox):** https://sandbox.offendersearch.app — test keys (`os_test_…`), never billed
- **Authentication:** `X-API-Key` request header
- **OpenAPI:** https://offendersearch.app/openapi.json · https://offendersearch.app/openapi.yaml
- **Docs index for agents:** https://offendersearch.app/llms.txt

## How screening works in property management today

A rental application arrives through the property-management system or a listing site. The applicant pays a screening fee and authorises a report; the system orders it from a consumer reporting agency; the report returns credit, eviction and criminal-history components, often with a vendor score; a leasing agent or an automated rule compares it with the property's written screening criteria; and the applicant is approved, approved with conditions (a larger deposit, a guarantor) or declined. Portfolio operators centralise this in the leasing module of their property-management platform; small landlords use a screening service inside their listing tool. The cadence is per application: there is no routine re-screening of sitting tenants in ordinary residential housing.

Three bodies of rules shape it. **The FCRA.** A tenant-screening report is a consumer report furnished under the legitimate-business-need purpose (15 U.S.C. § 1681b(a)(3)(F)). Any adverse action based even in part on it — a denial, a higher deposit, a co-signer requirement — obliges the housing provider to give the applicant an adverse-action notice naming the agency, stating that the agency did not make the decision, and explaining the right to a free copy within 60 days and to dispute (§ 1681m(a)). The standalone disclosure and pre-adverse steps of § 1681b(b) are employment-specific and do not apply to housing, though many operators send a pre-decision copy anyway. **Fair housing.** HUD's Office of General Counsel guidance of April 4, 2016 explains how the Fair Housing Act's discriminatory-effects standard applies to criminal-history screening: a blanket policy may be challenged for disparate impact; arrest records alone do not justify a denial; a conviction policy must be tailored to the nature, severity and recency of the conduct and should allow an individualized assessment. **State and local fair-chance housing laws.** New Jersey's Fair Chance in Housing Act (P.L.2021, c.110) bars any criminal-history inquiry before a conditional offer, then permits consideration only within lookback windows by offence degree, never considers arrests without conviction or expunged, pardoned, vacated, sealed or juvenile records, and carves out two things a provider may consider at any stage: a lifetime sex offender registration requirement and the manufacture of methamphetamine in federally assisted housing. Seattle's Fair Chance Housing ordinance (SMC 14.09) goes further, barring most use of criminal history altogether, with an exception for registry information about adult convictions that the provider must disclose in its screening criteria along with the applicant's right to supply rehabilitation information.

Registry information has its own restrictions. California Penal Code § 290.46(j), Nevada NRS 179B.270 and New Jersey N.J.S.A. 2C:7-16(c) prohibit using information from the state's public registry website for purposes including housing or accommodations, except as authorised by other law; California also states that a lessor has no duty to screen tenants against the registry (AB 2712, 2006). That is why a registry check of an **applicant** in those states is a counsel question before it is an integration question, and why the housing decision — when counsel approves it and when the use is permitted — belongs in an FCRA order whose controls, consent attestation and evidence record are built for it. A property manager's second, separate interest is the community itself: knowing when a registrant is listed near a property so that staff can follow their notice and safety policies. That is a location question about an address, not a decision about an applicant, and the standard API serves it.

> **What a rule requires versus whether it applies.** This article states what each rule requires. Whether it governs a given property, applicant or portfolio — and whether registry information may be used at all in a given state — is for the operator's counsel. Integrating the API does not make a screening program compliant.

## Where the API fits

| Workflow step | Endpoint | Fields that matter |
| --- | --- | --- |
| Register the housing provider the reports are for | `POST /v1/fcra/end-users` | `name`, `externalId`, `permissiblePurposes: ["tenant_screening"]`, `certification` (`text`, `version`, `certifiedAt`, `certifiedBy`) |
| Order the applicant's screening after the conditional offer | `POST /v1/fcra/orders` | `endUserId`, `permissiblePurpose: "tenant_screening"`, `consent` (`obtainedAt`, `method`, `documentRef`), `subject` (full `dob`, `addresses[]`), `useLocation.state` (where the housing is), `searches[]`, `clientReference`, `Idempotency-Key` header |
| Learn the result | signed webhook → `GET /v1/fcra/orders/{order_id}` | `search.completed` and `order.completed` events; `searches[].status`, `result` (`records_found`, `clear`, `incomplete`), `recordCount`, `withheld{}`, `incompleteReasons[]` |
| Deliver the report and the consumer's copy | `GET /v1/fcra/orders/{order_id}/report` | `?format=pdf` for the stored PDF with `X-Report-SHA256`; `consumerPortal.url` and `accessCode` from the order for the applicant |
| Handle a dispute from the applicant | `POST /v1/fcra/orders/{order_id}/disputes` | `recordIds[]`, `reason`, `consumerStatement`, `receivedAt`; `dueAt` is 30 days later |
| Know who is listed near a property | `POST /v1/monitors` (`type: "location"`) | `product: "sex-offender"`, `location.lat`/`lng` or `address`, `radiusMiles` (≤ 100), `channels`; alerts carry `matchLabel: "in_radius"` |
| Show the surroundings on a map | `GET /v1/map/viewport` | The [Offender Map API](/docs/map): markers, clusters and record opens for a community view |

The standard `POST /v1/search` is not in the applicant row on purpose. It is the right call for a facility's own safety uses — a visitor at a leasing office, a vendor on site — and for research about an address, but it is not a consumer report and must not be the sole basis for a housing decision.

## Reference integration

The core job is the applicant order. The module registers the housing provider as an end user, places a tenant-screening order with both search types, waits for completion, and maps the order to a stage: **clear** (both searches complete, nothing furnished — withheld candidates are counted, not shown), **review** (records furnished; the leasing team applies the written criteria and, if declining, sends the pre-decision copy and the adverse-action notice with the consumer portal access code), or **incomplete** (a source could not be reached; hold and reverify). There is no **match** state here: a furnished record already carries `matchBasis.state` and identifiers, and the decision about what it means is the provider's. On the sandbox every `os_test_` key is an enabled partner and orders complete immediately; the subject's last name picks the scenario (`Clear`, `Records`, `Withheld`, `Unavailable`, `Dispute`).

**Python**
```python
"""Tenant-screening order — OffenderSearch FCRA Partner API, Python 3.11+, requests.

Sandbox: every os_test_ key is an enabled sandbox partner for every permissible purpose, and an order
finishes right after the 202, so one poll is enough. Production: GET /v1/fcra/partner must say
enabled: true, and results arrive by signed webhook (search.completed, order.completed).

  OFFENDERSEARCH_API_KEY=os_test_...  OFFENDERSEARCH_BASE=https://sandbox.offendersearch.app  python tenant_order.py
"""
from __future__ import annotations

import os
import time
import uuid
from datetime import datetime, timezone

import requests

API_KEY = os.environ["OFFENDERSEARCH_API_KEY"]
BASE = os.environ.get("OFFENDERSEARCH_BASE", "https://sandbox.offendersearch.app")
HEADERS = {"X-API-Key": API_KEY, "Content-Type": "application/json"}


def _now() -> str:
    return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")


def _fcra_error(r: requests.Response) -> str:
    d = r.json().get("detail")
    return f"{d['code']}: {d['message']}" if isinstance(d, dict) else str(d)   # FcraError or validation list


def partner_status() -> dict:
    r = requests.get(f"{BASE}/v1/fcra/partner", headers=HEADERS, timeout=30)
    r.raise_for_status()
    return r.json()                      # enabled, sandbox, allowedPurposes, webhookConfigured


def register_housing_provider(name: str, external_id: str) -> str:
    """The end user is the housing provider the report is for - the owner or management entity, once."""
    body = {
        "name": name,
        "externalId": external_id,
        "permissiblePurposes": ["tenant_screening"],
        "certification": {
            "text": "The housing provider certifies that it will request and use consumer reports only for tenant "
                    "screening, with the applicant's authorization, and will comply with the FCRA and applicable law.",
            "version": "v1",
            "certifiedAt": _now(),
            "certifiedBy": "compliance@your-pm.example",
        },
    }
    r = requests.post(f"{BASE}/v1/fcra/end-users", headers=HEADERS, json=body, timeout=30)
    if r.status_code == 403:
        raise PermissionError(_fcra_error(r))        # fcra_not_enabled / fcra_purpose_not_allowed
    r.raise_for_status()
    return r.json()["id"]                             # eu_...


def order_tenant_screen(end_user_id: str, applicant: dict, property_state: str, consent_ref: str,
                        client_reference: str) -> dict:
    """One applicant, one conditional offer, one consent attestation, both search types."""
    body = {
        "endUserId": end_user_id,
        "permissiblePurpose": "tenant_screening",
        "consent": {"obtainedAt": _now(), "method": "esign", "documentRef": consent_ref},
        "subject": applicant,                          # firstName, lastName, dob (full), aliases[], addresses[]
        "useLocation": {"state": property_state},      # where the housing is - drives the state controls
        "searches": [{"type": "sex_offender"}, {"type": "criminal"}],
        "clientReference": client_reference,
    }
    headers = {**HEADERS, "Idempotency-Key": f"{client_reference}-{uuid.uuid4().hex[:8]}"}
    r = requests.post(f"{BASE}/v1/fcra/orders", headers=headers, json=body, timeout=60)
    if r.status_code in (403, 404, 409, 422):
        raise ValueError(_fcra_error(r))              # purpose, unknown_end_user, idempotency_conflict, validation
    r.raise_for_status()                              # 202: status "received"
    return r.json()


def wait_for_order(order_id: str, timeout_s: int = 600) -> dict:
    """Production: prefer the signed webhook. Polling is the fallback; the sandbox completes at once."""
    deadline = time.time() + timeout_s
    while time.time() < deadline:
        r = requests.get(f"{BASE}/v1/fcra/orders/{order_id}", headers=HEADERS, timeout=30)
        r.raise_for_status()
        order = r.json()
        if order["status"] in ("complete", "error", "cancelled"):
            return order
        time.sleep(5)
    raise TimeoutError(order_id)


def stage(order: dict) -> tuple[str, str]:
    """Where the application goes next. The decision itself is the housing provider's, under its written criteria."""
    results = {s["type"]: s for s in order["searches"]}
    if any(s["status"] in ("unavailable", "error") or s.get("result") == "incomplete" for s in results.values()):
        return "incomplete", "A search could not be completed - hold, then POST /v1/fcra/searches/{id}/reverify."
    if any(s.get("result") == "records_found" for s in results.values()):
        found = ", ".join(f"{t}: {s['recordCount']}" for t, s in results.items() if s.get("result") == "records_found")
        return "review", f"Records furnished ({found}). Individualized review under the written criteria; " \
                         "pre-adverse notice with the report copy and the consumer portal access code if declining."
    withheld = sum(sum(s.get("withheld", {}).values()) for s in results.values())
    return "clear", f"Both searches complete, nothing furnished ({withheld} candidate(s) withheld by the controls)."


def report(order_id: str) -> dict:
    r = requests.get(f"{BASE}/v1/fcra/orders/{order_id}/report", headers=HEADERS, timeout=60)   # ?format=pdf for the PDF
    if r.status_code == 409:
        raise RuntimeError(_fcra_error(r))            # report_not_ready
    r.raise_for_status()
    return r.json()                                   # searches[].records[], evidence[], integrity.reportSha256


if __name__ == "__main__":
    status = partner_status()
    assert status["enabled"], "Apply for FCRA Partner Access first (/fcra)."
    eu = register_housing_provider("Maple Court Apartments LLC", "owner-0417")

    for last in ("Clear", "Records", "Unavailable"):              # sandbox subjects, chosen by last name
        order = order_tenant_screen(
            eu,
            {"firstName": "Pat", "lastName": last, "dob": "1980-01-01",
             "addresses": [{"state": "IL", "city": "Springfield", "from": "2021-06", "to": None}]},
            property_state="IL", consent_ref="app-55120-auth", client_reference=f"app-55120-{last.lower()}",
        )
        done = wait_for_order(order["id"])
        s, why = stage(done)
        print(done["id"], done["status"], "->", s, "-", why)
        if s == "review":
            rep = report(done["id"])
            print("  report sha256:", rep["integrity"]["reportSha256"],
                  "| consumer portal code:", done["consumerPortal"]["accessCode"])
```

**JavaScript**
```javascript
// Tenant-screening order — OffenderSearch FCRA Partner API, Node 18+ (global fetch).
// Sandbox: every os_test_ key is an enabled sandbox partner; orders finish right after the 202.
// Production: GET /v1/fcra/partner must say enabled: true; results arrive by signed webhook.
const API_KEY = process.env.OFFENDERSEARCH_API_KEY;
const BASE = process.env.OFFENDERSEARCH_BASE ?? "https://sandbox.offendersearch.app";
const HEADERS = { "X-API-Key": API_KEY, "Content-Type": "application/json" };
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
const now = () => new Date().toISOString().replace(/\.\d{3}Z$/, "Z");

async function fcraError(r) {
  const d = (await r.json()).detail;                                  // FcraError {code, message} or a validation list
  return d && d.code ? d.code + ": " + d.message : JSON.stringify(d);
}

export async function partnerStatus() {
  const r = await fetch(BASE + "/v1/fcra/partner", { headers: HEADERS });
  if (!r.ok) throw new Error("HTTP " + r.status);
  return r.json();                                                     // enabled, sandbox, allowedPurposes, webhookConfigured
}

/** The end user is the housing provider the report is for — the owner or management entity, registered once. */
export async function registerHousingProvider(name, externalId) {
  const r = await fetch(BASE + "/v1/fcra/end-users", { method: "POST", headers: HEADERS, body: JSON.stringify({
    name, externalId, permissiblePurposes: ["tenant_screening"],
    certification: {
      text: "The housing provider certifies that it will request and use consumer reports only for tenant screening, with the applicant's authorization, and will comply with the FCRA and applicable law.",
      version: "v1", certifiedAt: now(), certifiedBy: "compliance@your-pm.example",
    },
  }) });
  if (r.status === 403) throw new Error(await fcraError(r));          // fcra_not_enabled / fcra_purpose_not_allowed
  if (r.status !== 201) throw new Error("HTTP " + r.status);
  return (await r.json()).id;                                          // eu_...
}

/** One applicant, one conditional offer, one consent attestation, both search types. */
export async function orderTenantScreen(endUserId, applicant, propertyState, consentRef, clientReference) {
  const r = await fetch(BASE + "/v1/fcra/orders", {
    method: "POST",
    headers: { ...HEADERS, "Idempotency-Key": clientReference + "-" + Math.random().toString(16).slice(2, 10) },
    body: JSON.stringify({
      endUserId, permissiblePurpose: "tenant_screening",
      consent: { obtainedAt: now(), method: "esign", documentRef: consentRef },
      subject: applicant,                                              // firstName, lastName, dob, aliases[], addresses[]
      useLocation: { state: propertyState },                          // where the housing is
      searches: [{ type: "sex_offender" }, { type: "criminal" }],
      clientReference,
    }),
  });
  if ([403, 404, 409, 422].includes(r.status)) throw new Error(await fcraError(r));
  if (r.status !== 202) throw new Error("HTTP " + r.status);
  return r.json();                                                     // status "received"
}

/** Production: prefer the signed webhook. Polling is the fallback; the sandbox completes at once. */
export async function waitForOrder(orderId, timeoutMs = 600_000) {
  const deadline = Date.now() + timeoutMs;
  while (Date.now() < deadline) {
    const r = await fetch(BASE + "/v1/fcra/orders/" + orderId, { headers: HEADERS });
    if (!r.ok) throw new Error("HTTP " + r.status);
    const order = await r.json();
    if (["complete", "error", "cancelled"].includes(order.status)) return order;
    await sleep(5000);
  }
  throw new Error("timed out: " + orderId);
}

/** Where the application goes next. The decision is the housing provider's, under its written criteria. */
export function stage(order) {
  const s = order.searches;
  if (s.some((x) => ["unavailable", "error"].includes(x.status) || x.result === "incomplete"))
    return ["incomplete", "A search could not be completed - hold, then POST /v1/fcra/searches/{id}/reverify."];
  const found = s.filter((x) => x.result === "records_found");
  if (found.length)
    return ["review", "Records furnished (" + found.map((x) => x.type + ": " + x.recordCount).join(", ") +
      "). Individualized review under the written criteria; pre-adverse notice with the report copy and the consumer portal access code if declining."];
  const withheld = s.reduce((n, x) => n + Object.values(x.withheld ?? {}).reduce((a, b) => a + b, 0), 0);
  return ["clear", "Both searches complete, nothing furnished (" + withheld + " candidate(s) withheld by the controls)."];
}

export async function report(orderId) {
  const r = await fetch(BASE + "/v1/fcra/orders/" + orderId + "/report", { headers: HEADERS });   // ?format=pdf for the PDF
  if (r.status === 409) throw new Error(await fcraError(r));          // report_not_ready
  if (!r.ok) throw new Error("HTTP " + r.status);
  return r.json();                                                     // searches[].records[], evidence[], integrity.reportSha256
}

// Demo against the sandbox subjects (chosen by last name).
const status = await partnerStatus();
if (!status.enabled) throw new Error("Apply for FCRA Partner Access first (/fcra).");
const eu = await registerHousingProvider("Maple Court Apartments LLC", "owner-0417");
for (const last of ["Clear", "Records", "Unavailable"]) {
  const order = await orderTenantScreen(eu,
    { firstName: "Pat", lastName: last, dob: "1980-01-01", addresses: [{ state: "IL", city: "Springfield", from: "2021-06", to: null }] },
    "IL", "app-55120-auth", "app-55120-" + last.toLowerCase());
  const done = await waitForOrder(order.id);
  const [s, why] = stage(done);
  console.log(done.id, done.status, "->", s, "-", why);
  if (s === "review") {
    const rep = await report(done.id);
    console.log("  report sha256:", rep.integrity.reportSha256, "| consumer portal code:", done.consumerPortal.accessCode);
  }
}
```

*GET /v1/fcra/orders/{order_id} after completion (trimmed)*
```json
{
  "id": "fo_ee0b34c5b52fd35b",
  "status": "complete",
  "permissiblePurpose": "tenant_screening",
  "endUserId": "eu_0b44acbeefeaa7d7",
  "useLocation": { "state": "IL" },
  "controlVersion": "fcra-controls-2026-10-19.1",
  "sandbox": true,
  "clientReference": "app-55120-records",
  "searches": [
    { "id": "fs_452884eecde9a1f2", "type": "sex_offender", "status": "complete", "result": "records_found",
      "recordCount": 1, "withheld": {}, "incompleteReasons": [], "coverage": [ … ] },
    { "id": "fs_9c03d7e1a4b6f258", "type": "criminal", "status": "complete", "result": "records_found",
      "recordCount": 1, "withheld": {}, "incompleteReasons": [], "coverage": [ … ] }
  ],
  "consumerPortal": { "url": "https://offendersearch.app/consumer/report", "accessCode": "K7QF-2MXP-9RDA" }
}
```

What the leasing reviewer sees for **review**: each furnished record with `type`, `matchBasis.state` (`dob_match` on a full date-of-birth agreement) and `identifiers`, `retrievedAt` and `verifiedAt`; for a criminal record its `dispositionStatus` (`conviction`, `non_conviction`, `sanction`, `mixed`, `unknown`) and every charge's `fcraDisposition`; for a registry record the product's standard fields. `withheld{}` tells the reviewer how many candidates the controls kept out and why (`insufficient_identifiers`, `not_current_at_source`, `obsolete_non_conviction`), so an empty report is explained rather than silent. [Results & records](/docs/fcra/results), [Controls](/docs/fcra/controls).

## Ongoing monitoring

For the community, a location monitor is one standing watch around a point: `product: "sex-offender"`, `type: "location"`, the property's coordinates (or a ZIP or "City, ST" in `address`; a street address needs `lat` and `lng`), and a `radiusMiles` up to 100. It alerts with `matchLabel: "in_radius"` when a registrant is newly listed inside the radius, when a listing in the radius changes, and when one is removed. A criminal location monitor is not available: that request answers `200` with `status: "not_yet_available"` and creates nothing. Route alerts to the regional or community-safety mailbox, not to leasing — this is awareness for staff policy, not applicant information.

*Create a one-mile location monitor around a community (sandbox point)*
```bash
curl -X POST https://sandbox.offendersearch.app/v1/monitors \
  -H "X-API-Key: $OFFENDERSEARCH_API_KEY" -H "Content-Type: application/json" \
  -d '{
    "product": "sex-offender",
    "type": "location",
    "location": { "lat": 39.9612, "lng": -82.9988, "radiusMiles": 1 },
    "label": "Maple Court Apartments - 1 mile",
    "channels": { "emails": ["community-safety@your-pm.example"] }
  }'
```

*The alert delivered to a webhook; emails carry the same facts*
```json
{
  "type": "monitor.alert",
  "event": "new",
  "alertId": "hit_2c91e0f7a4b8d613",
  "monitorId": "mon_4e8a1c7b9d2f0a35",
  "monitorLabel": "Maple Court Apartments - 1 mile",
  "product": "sex-offender",
  "detail": {
    "name": "EXACT SAMPLE MATCH",
    "jurisdiction": "OH",
    "locality": "Sampleville",
    "matchLabel": "in_radius",
    "matchConfidence": null,
    "personRef": "prs_3c9e1f0a7b2d4e6f8a1b",
    "recordId": "rec_6d066763131ebe8c77ea"
  },
  "occurredAt": "2026-10-25T12:00:41+00:00",
  "sentAt": "2026-10-25T12:01:03+00:00"
}
```

For an **applicant who becomes a resident**, the FCRA order is the record; there is no FCRA monitor, and a standard person monitor must not become a backdoor to a tenancy decision. If a later tenancy decision depends on a record, place a new order. [Location monitoring](/docs/monitoring/location-monitoring), [Billing](/docs/monitoring/billing).

## When this is FCRA

Deciding whether to rent to someone, on what deposit, or with what guarantor is a housing decision, and a report that informs it is a consumer report. That path is the [FCRA Partner API](/docs/fcra). It is available to approved partners under a written agreement; a property-management platform that is not itself a consumer reporting agency typically reaches it through its screening partner. What the order gives the decision: a recorded permissible purpose and consent attestation; the state controls selected by `useLocation`; records furnished only when identifiers suffice and the item is current at its source; a report with a verifiable hash and a public receipt; the consumer's portal copy and dispute path; and a `record.corrected` event to every partner that received a record later changed by a dispute. What it does not do: send the adverse-action notice, decide the application, or determine whether a given state permits registry information to be used for housing at all. Those remain the housing provider's and its counsel's.

## Evidence and audit

- **The order is the file.** Store the `fo_` id with the application; `GET /v1/fcra/orders/{order_id}` returns the status and result of each search indefinitely, and `GET /v1/fcra/orders` filters by `clientReference`.
- **The report and its hashes.** Keep the PDF and its `X-PDF-SHA256`; the public receipt at `GET /v1/fcra/receipts/{order_id}` is an Ed25519-signed statement of the order id, completion time, control version and report hash that a court, auditor or applicant can verify without an API key.
- **Evidence captures.** `GET /v1/fcra/orders/{order_id}/evidence` lists every official-source capture (`kind`, `source`, `sha256`, `retrievedAt`); the bytes are one call away. No retention period is published; keep your own copies under your policy.
- **Disputes.** `GET /v1/fcra/disputes?orderId=…` shows each dispute's `status`, `dueAt`, `extendedAt` and outcome.
- **Location alerts.** `GET /v1/monitors/{monitorId}/alerts` is the history of what was observed near a property and when; alert `personRef` values let you tell a new person from a republished listing.
- **Standard searches** used for facility safety keep their `searchId`; stored results stay readable for 14 days and `POST /v1/report` renders them for 7.

## Rollout plan

1. **Scope with counsel.** List the states in the portfolio; confirm where registry information may be used in tenant screening and which fair-chance rules apply to criminal history. The answers set which `searches[]` each property's orders carry.
2. **Sandbox orders.** With an `os_test_` key, register an end user and run the module above through `Clear`, `Records`, `Withheld` and `Unavailable`. Read `withheld{}` and `incompleteReasons[]`.
3. **Leasing workflow.** Place the order only after the conditional offer where law requires it; show furnished records with their dispositions; generate the adverse-action notice with the agency's name and the consumer portal access code when declining.
4. **Webhooks.** `PUT /v1/fcra/webhook-endpoint`, store the one-time `secret`, verify `X-Offendersearch-Signature` on the raw body, and replay from `GET /v1/fcra/events` after any outage. [Webhooks & events](/docs/fcra/webhooks).
5. **Community monitors.** Create one location monitor per property with the community-safety mailbox as the channel; document the staff procedure for an `in_radius` alert.
6. **Partner access and go-live.** Apply for [FCRA Partner Access](/fcra) or connect through your screening partner; when `GET /v1/fcra/partner` shows `enabled: true` on the live host, place a first order with a real consent record and confirm the receipt verifies.

## Related

- [FCRA Partner API](https://offendersearch.app/docs/fcra)
- [Orders](https://offendersearch.app/docs/fcra/orders)
- [Consumer portal](https://offendersearch.app/docs/fcra/consumer-portal)
- [Location monitoring](https://offendersearch.app/docs/monitoring/location-monitoring)
- [Offender Map API](https://offendersearch.app/docs/map)
