> ## Documentation Index
> Fetch the complete documentation index at: https://docs.rentfax.io/llms.txt
> Use this file to discover all available pages before exploring further.

# RentFAX webhook events reference

> RentFAX sends real-time POST notifications to your configured endpoint when key events occur. Use webhooks to keep your systems in sync without polling.

RentFAX can notify your application in real time when important events happen in the platform. When an event fires, RentFAX sends an HTTP `POST` request containing a JSON payload to the webhook URL you have configured for your organization. You can use these notifications to trigger workflows, update your own records, or alert your team automatically.

## Configuration

Webhooks are configured per organization. To set your endpoint URL, go to **Settings → Webhooks** in the RentFAX dashboard and enter the URL you want RentFAX to deliver events to. Only one URL can be active per organization at a time.

## Delivery

RentFAX delivers each event as an HTTP `POST` to your configured URL with the following request headers:

```
Content-Type: application/json
```

The body is a JSON object containing an `event` field that identifies the event type, along with a `data` object containing event-specific fields.

<Warning>
  RentFAX does not currently sign webhook payloads with a signature header. You should restrict your webhook endpoint to only accept traffic from trusted sources, and consider validating the incoming `event` type and `orgId` fields against your own records before acting on a payload. Do not expose sensitive business logic behind an unauthenticated endpoint.
</Warning>

## Event types

RentFAX emits the following events.

***

### `report.submitted`

Fired when a rental history report is successfully created — either through the API (`POST /v1/reports`) or the RentFAX dashboard.

<Expandable title="Payload fields">
  <ResponseField name="event" type="string" required>
    Always `"report.submitted"`.
  </ResponseField>

  <ResponseField name="orgId" type="string" required>
    The organization ID that submitted the report.
  </ResponseField>

  <ResponseField name="data" type="object" required>
    <Expandable title="properties">
      <ResponseField name="reportId" type="string" required>
        The unique report ID. Matches the `reportId` returned by `POST /v1/reports`.
      </ResponseField>

      <ResponseField name="recordId" type="string" required>
        The human-readable record identifier (format: `RB-XXXXX`).
      </ResponseField>

      <ResponseField name="renterEmail" type="string">
        The email address of the renter covered by this report.
      </ResponseField>

      <ResponseField name="renterName" type="string">
        The full name of the renter covered by this report.
      </ResponseField>

      <ResponseField name="riskScore" type="number" required>
        The computed risk score (0–1000) for this renter.
      </ResponseField>

      <ResponseField name="eligibilityStatus" type="string" required>
        One of `"Eligible"`, `"Eligible With Conditions"`, `"Elevated Risk"`, or `"Do Not Rent"`.
      </ResponseField>

      <ResponseField name="industryType" type="string" required>
        The industry vertical associated with this report.
      </ResponseField>

      <ResponseField name="createdAt" type="string" required>
        ISO 8601 timestamp of when the report was created.
      </ResponseField>
    </Expandable>
  </ResponseField>
</Expandable>

**Example payload**

```json report.submitted theme={null}
{
  "event": "report.submitted",
  "orgId": "org_7f3a2b1c9d",
  "data": {
    "reportId": "3qFzW8mNkLpT2vXcYdAe",
    "recordId": "RB-47291",
    "renterEmail": "jane.doe@example.com",
    "renterName": "Jane Doe",
    "riskScore": 635,
    "eligibilityStatus": "Eligible With Conditions",
    "industryType": "residential",
    "createdAt": "2024-04-15T14:32:07.000Z"
  }
}
```

***

### `dispute.filed`

Fired when a renter files a dispute against a report or incident record. Disputes can be initiated by renters through the RentFAX Renter Portal.

<Expandable title="Payload fields">
  <ResponseField name="event" type="string" required>
    Always `"dispute.filed"`.
  </ResponseField>

  <ResponseField name="orgId" type="string" required>
    The organization ID whose report or record is being disputed.
  </ResponseField>

  <ResponseField name="data" type="object" required>
    <Expandable title="properties">
      <ResponseField name="disputeId" type="string" required>
        Unique identifier for the dispute.
      </ResponseField>

      <ResponseField name="recordId" type="string" required>
        The `RB-XXXXX` record ID of the report being disputed.
      </ResponseField>

      <ResponseField name="renterEmail" type="string" required>
        The email address of the renter who filed the dispute.
      </ResponseField>

      <ResponseField name="reason" type="string" required>
        A short description of the dispute reason as provided by the renter.
      </ResponseField>

      <ResponseField name="status" type="string" required>
        Current dispute status. Typically `"open"` when first filed.
      </ResponseField>

      <ResponseField name="filedAt" type="string" required>
        ISO 8601 timestamp of when the dispute was filed.
      </ResponseField>
    </Expandable>
  </ResponseField>
</Expandable>

**Example payload**

```json dispute.filed theme={null}
{
  "event": "dispute.filed",
  "orgId": "org_7f3a2b1c9d",
  "data": {
    "disputeId": "dsp_8mPqR2nKxLtYwZ",
    "recordId": "RB-47291",
    "renterEmail": "jane.doe@example.com",
    "reason": "The payment compliance rating is incorrect. All payments were made on time per bank records.",
    "status": "open",
    "filedAt": "2024-04-17T09:15:42.000Z"
  }
}
```

***

### `identity.check`

Fired when an identity verification check is completed for a renter. This event is triggered by RentFAX's fraud detection process when a renter's identity is evaluated against the network.

<Expandable title="Payload fields">
  <ResponseField name="event" type="string" required>
    Always `"identity.check"`.
  </ResponseField>

  <ResponseField name="orgId" type="string" required>
    The organization ID associated with the renter being checked.
  </ResponseField>

  <ResponseField name="data" type="object" required>
    <Expandable title="properties">
      <ResponseField name="renterId" type="string" required>
        Unique identifier for the renter whose identity was checked.
      </ResponseField>

      <ResponseField name="renterEmail" type="string">
        The email address associated with this renter.
      </ResponseField>

      <ResponseField name="result" type="string" required>
        The outcome of the identity check. One of `"clear"`, `"flagged"`, or `"duplicate"`.
      </ResponseField>

      <ResponseField name="flags" type="array">
        An array of strings describing any detected signals (for example, `"duplicate_identity"`, `"shared_address"`). Empty when `result` is `"clear"`.
      </ResponseField>

      <ResponseField name="checkedAt" type="string" required>
        ISO 8601 timestamp of when the check was completed.
      </ResponseField>
    </Expandable>
  </ResponseField>
</Expandable>

**Example payload**

```json identity.check theme={null}
{
  "event": "identity.check",
  "orgId": "org_7f3a2b1c9d",
  "data": {
    "renterId": "renter_abc123",
    "renterEmail": "jane.doe@example.com",
    "result": "flagged",
    "flags": ["duplicate_identity"],
    "checkedAt": "2024-04-15T14:32:10.000Z"
  }
}
```

***

## Handling webhooks

Your endpoint should respond with an HTTP `2xx` status code as quickly as possible. If your processing logic is slow, acknowledge receipt immediately and handle the payload asynchronously.

<CodeGroup>
  ```javascript Express.js theme={null}
  import express from 'express';

  const app = express();
  app.use(express.json());

  app.post('/webhooks/rentfax', (req, res) => {
    const { event, orgId, data } = req.body;

    // Acknowledge receipt immediately
    res.sendStatus(200);

    // Handle the event asynchronously
    switch (event) {
      case 'report.submitted':
        console.log(`Report ${data.recordId} submitted. Risk score: ${data.riskScore}`);
        // TODO: sync to your database
        break;
      case 'dispute.filed':
        console.log(`Dispute ${data.disputeId} filed for record ${data.recordId}`);
        // TODO: notify your team
        break;
      case 'identity.check':
        console.log(`Identity check for ${data.renterEmail}: ${data.result}`);
        // TODO: update renter profile
        break;
      default:
        console.warn(`Unrecognised event type: ${event}`);
    }
  });

  app.listen(3000);
  ```

  ```typescript Next.js (App Router) theme={null}
  // app/api/webhooks/rentfax/route.ts
  import { NextRequest, NextResponse } from 'next/server';

  export async function POST(req: NextRequest) {
    const payload = await req.json();
    const { event, orgId, data } = payload;

    switch (event) {
      case 'report.submitted':
        // Handle report submission
        break;
      case 'dispute.filed':
        // Handle dispute
        break;
      case 'identity.check':
        // Handle identity check result
        break;
      default:
        // Ignore unknown events
        break;
    }

    return NextResponse.json({ received: true });
  }
  ```
</CodeGroup>

<Note>
  RentFAX does not currently retry failed webhook deliveries. If your endpoint is unavailable or returns a non-`2xx` status, the event will not be resent. Design your integration to handle missed events by polling the relevant API endpoints if necessary.
</Note>
