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

# RCM outreach campaigns for behind loans

> Start a multi-channel outreach campaign on a document with a BEHIND loan, configure channels and tone, and record opt-outs for compliance audit trails.

The RCM (Relationship and Collections Management) endpoints let you initiate structured outreach campaigns for documents whose loan status is `"BEHIND"`, and record opt-out events for compliance purposes. Every action you take through these endpoints is written to an immutable compliance log and emitted as an activity feed event.

<Note>
  RCM campaigns can only be started on documents that have an attached loan with a status of `"BEHIND"`. If the loan is `"CURRENT"` or no loan exists, the API returns `400`.
</Note>

***

## Start an RCM campaign

```http theme={null}
POST /v1/documents/:id/rcm
```

Creates a new outreach campaign for the specified document. You choose which communication channels to activate and provide guidance on tone and cadence. The campaign is recorded in the compliance log with an event type of `campaign_started`.

### Request headers

<ParamField header="Authorization" type="string" required>
  Bearer token obtained from your Clerk session. Example: `Bearer eyJhbGc...`
</ParamField>

<ParamField header="Content-Type" type="string" required>
  Must be `application/json`.
</ParamField>

### Path parameters

<ParamField path="id" type="string" required>
  The unique identifier of the document for which to start a campaign. The document must be owned by your account and must have a loan with status `"BEHIND"`.
</ParamField>

### Request body

At least one of `sms`, `email`, or `call` must be `true`. The API returns `400` if all three are `false`.

<ParamField body="sms" type="boolean" required>
  Set to `true` to include SMS as an outreach channel.
</ParamField>

<ParamField body="email" type="boolean" required>
  Set to `true` to include email as an outreach channel.
</ParamField>

<ParamField body="call" type="boolean" required>
  Set to `true` to include phone calls as an outreach channel.
</ParamField>

<ParamField body="tone" type="string" required>
  Guidance on the communication tone, for example `"professional and empathetic"` or `"firm but respectful"`. Maximum 80 characters.
</ParamField>

<ParamField body="cadence" type="string" required>
  Guidance on the outreach schedule, for example `"once per week"` or `"day 1, day 5, day 14"`. Maximum 80 characters.
</ParamField>

<ParamField body="notes" type="string">
  Optional free-form notes for the campaign, for example relevant account context or escalation instructions. Maximum 2000 characters. Leading and trailing whitespace is trimmed before storage.
</ParamField>

### Response

Returns `201 Created` with the newly created campaign record.

<ResponseField name="campaign" type="object" required>
  The created RCM campaign.

  <Expandable title="campaign properties">
    <ResponseField name="id" type="string" required>
      Unique campaign identifier.
    </ResponseField>

    <ResponseField name="channels" type="string" required>
      A JSON-encoded string representing the channel selections, for example `'{"sms":true,"email":false,"call":true}'`. Parse this string to read individual channel values.
    </ResponseField>

    <ResponseField name="tone" type="string" required>
      The tone guidance you submitted.
    </ResponseField>

    <ResponseField name="cadence" type="string" required>
      The cadence guidance you submitted.
    </ResponseField>

    <ResponseField name="notes" type="string or null" required>
      The trimmed notes you submitted, or `null` if none were provided.
    </ResponseField>

    <ResponseField name="active" type="boolean" required>
      `true` when the campaign is active. Becomes `false` when an `"all"` channel opt-out is recorded.
    </ResponseField>

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

### Example

<CodeGroup>
  ```bash Request theme={null}
  curl --request POST \
    --url https://your-api.example.com/v1/documents/doc_01j9z8x7w6v5u4t3s2r1q0p/rcm \
    --header 'Authorization: Bearer <your-session-token>' \
    --header 'Content-Type: application/json' \
    --data '{
      "sms": true,
      "email": true,
      "call": false,
      "tone": "professional and empathetic",
      "cadence": "day 1, day 5, day 14",
      "notes": "Borrower previously responded well to SMS outreach."
    }'
  ```

  ```json Response 201 theme={null}
  {
    "campaign": {
      "id": "rcm_01k0b2z9y8x7w6v5u4t3s2r",
      "channels": "{\"sms\":true,\"email\":true,\"call\":false}",
      "tone": "professional and empathetic",
      "cadence": "day 1, day 5, day 14",
      "notes": "Borrower previously responded well to SMS outreach.",
      "active": true,
      "createdAt": "2026-04-27T13:00:00.000Z"
    }
  }
  ```
</CodeGroup>

***

## Record an opt-out

```http theme={null}
POST /v1/documents/:id/rcm/opt-out
```

Records an opt-out event for an active campaign. Opt-outs are written to the compliance log with an event type of `opt_out` and emitted to your activity feed. If you set `channel` to `"all"`, the campaign is deactivated (its `active` flag is set to `false`).

<Warning>
  Compliance events logged by this endpoint are permanent and cannot be deleted. Always record opt-outs accurately — they form part of your regulatory audit trail.
</Warning>

### Request headers

<ParamField header="Authorization" type="string" required>
  Bearer token obtained from your Clerk session.
</ParamField>

<ParamField header="Content-Type" type="string" required>
  Must be `application/json`.
</ParamField>

### Path parameters

<ParamField path="id" type="string" required>
  The unique identifier of the document whose campaign is being opted out of.
</ParamField>

### Request body

<ParamField body="campaignId" type="string" required>
  The unique identifier of the RCM campaign to opt out of. The campaign must belong to the document specified in the path and must be owned by your account.
</ParamField>

<ParamField body="channel" type="string" required>
  The channel being opted out. One of `"sms"`, `"email"`, `"call"`, or `"all"`. Passing `"all"` deactivates the entire campaign by setting its `active` flag to `false`.
</ParamField>

<ParamField body="notes" type="string">
  Optional notes describing the opt-out circumstances, for example `"Borrower requested no further contact by SMS"`. Maximum 2000 characters. Leading and trailing whitespace is trimmed before storage.
</ParamField>

### Response

Returns `200 OK` confirming the opt-out was recorded.

<ResponseField name="ok" type="boolean" required>
  Always `true` on a successful opt-out.
</ResponseField>

### Example

<CodeGroup>
  ```bash Opt out of SMS only theme={null}
  curl --request POST \
    --url https://your-api.example.com/v1/documents/doc_01j9z8x7w6v5u4t3s2r1q0p/rcm/opt-out \
    --header 'Authorization: Bearer <your-session-token>' \
    --header 'Content-Type: application/json' \
    --data '{
      "campaignId": "rcm_01k0b2z9y8x7w6v5u4t3s2r",
      "channel": "sms",
      "notes": "Borrower requested removal from SMS list on 2026-04-27."
    }'
  ```

  ```bash Opt out of all channels (deactivates campaign) theme={null}
  curl --request POST \
    --url https://your-api.example.com/v1/documents/doc_01j9z8x7w6v5u4t3s2r1q0p/rcm/opt-out \
    --header 'Authorization: Bearer <your-session-token>' \
    --header 'Content-Type: application/json' \
    --data '{
      "campaignId": "rcm_01k0b2z9y8x7w6v5u4t3s2r",
      "channel": "all",
      "notes": "Cease and desist received. Campaign deactivated."
    }'
  ```

  ```json Response 200 theme={null}
  {
    "ok": true
  }
  ```
</CodeGroup>

***

## Error cases

### Start campaign errors

| Status | Error message                                       | Cause                                                                         |
| ------ | --------------------------------------------------- | ----------------------------------------------------------------------------- |
| `400`  | `Invalid body.`                                     | A required field is missing or a field value exceeds its character limit.     |
| `400`  | `At least one channel must be true.`                | `sms`, `email`, and `call` are all `false`.                                   |
| `400`  | `RCM only when a loan exists and status is BEHIND.` | The document has no loan, or its loan status is `"CURRENT"`.                  |
| `401`  | `Missing Authorization Bearer token.`               | No `Authorization` header was sent.                                           |
| `401`  | `Invalid or expired token.`                         | The Bearer token is malformed or has expired.                                 |
| `404`  | `Not found.`                                        | No document with the given `id` exists, or it belongs to a different account. |

### Opt-out errors

| Status | Error message                          | Cause                                                                                                          |
| ------ | -------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
| `400`  | `Invalid body.`                        | A required field is missing or a field value exceeds its character limit.                                      |
| `401`  | `Missing Authorization Bearer token.`  | No `Authorization` header was sent.                                                                            |
| `401`  | `Invalid or expired token.`            | The Bearer token is malformed or has expired.                                                                  |
| `404`  | `Campaign not found or access denied.` | The `campaignId` does not exist, does not belong to the specified document, or belongs to a different account. |
