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

# Responding to RFIs

> How Fin.com requests additional customer information, where the RFI payload appears, and how to submit a response with the Patch Customer RFI endpoint.

A Request for Information (RFI) is raised when compliance needs something more from a customer before verification can complete. It names exactly which documents or fields are missing, expired, or invalid, so you never have to guess what to resend.

An RFI puts the customer into `ACTION_REQUIRED` and holds verification there until you respond. Nothing progresses in the meantime.

<Note>
  An RFI can also be raised after a customer is already `APPROVED`. In that case the customer status does not change. The only signal is the `customer.rfi` webhook and the populated `request_for_information` array.
</Note>

***

## How an RFI Reaches You

There are two ways to find an open RFI, and both carry the same structure.

| **Channel**                     | **Reference**                                                                                                   | **When to use it**                                                                    |
| :------------------------------ | :-------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------ |
| `customer.rfi` webhook          | [**customer.rfi**](https://developer.fin.com/api-reference/webhooks/customer-rfi)                               | Primary path. Fires the moment compliance raises the request.                         |
| `request_for_information` field | [**GET /v2/customers/:customer-id**](https://developer.fin.com/api-reference/customers/get-customer-details-v2) | Reconciliation. Read the open RFI on demand, or recover one whose webhook you missed. |

The `customer.status` webhook fires alongside `customer.rfi` when the status actually changes. Treat `customer.rfi` as the payload that tells you what to do, and `customer.status` as the state transition.

***

## Reading the RFI Payload

The payload is a list of sections. Each section holds one or more document categories, and each category holds the individual fields with a problem.

```
request_for_information[]
└── section            The document section with the issue
    └── categories[]
        └── document_type   The document that was requested or rejected
            └── fields[]
                ├── field_name   The specific field to resubmit
                ├── data_type    URI, DATE, TEXT, or ENUM
                ├── status       MISSING, EXPIRED, or INVALID
                ├── side         FRONT or BACK, file fields only
                └── reason       Why it was rejected, null when MISSING
```

### Field Status Values

| **Status** | **Meaning**                                                   | **What to send**                     |
| :--------- | :------------------------------------------------------------ | :----------------------------------- |
| `MISSING`  | The document or field was never provided. `reason` is `null`. | The missing document or value.       |
| `EXPIRED`  | The document has passed its expiry date.                      | A current document of the same type. |
| `INVALID`  | The value does not meet requirements. `reason` explains why.  | A corrected document or value.       |

### Section Values by Customer Type

| **Customer Type**     | **Sections**                                                         |
| :-------------------- | :------------------------------------------------------------------- |
| Individual            | `proof_of_identity`, `proof_of_address`, `tos_policies_value`        |
| Business V1           | `company_details`, `ownership_structure`, `legal_presence`           |
| Business V2           | `formation_documents`, `ownership_documents`, `supporting_documents` |
| Associated Party (V1) | `proof_of_identity`, `proof_of_address`                              |
| Associated Party (V2) | `identifying_documents`, `tax_info`, `address_documents`             |

An RFI can be scoped to the customer's own records or to a specific associated party. Sections from the associated party rows above tell you the request concerns a party rather than the business itself.

***

## Example: The `customer.rfi` Webhook

An individual customer whose passport has expired on the front, is damaged on the back, is missing both dates, and carries a name mismatch:

```json theme={null}
{
  "event": {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "event_reference_id": "cust-uuid-1234",
    "type": "customer.rfi",
    "created_at": "2026-04-04T10:00:00.000000Z",
    "sandbox_mode": false
  },
  "data": {
    "customer_id": "cust-uuid-1234",
    "request_for_information": [
      {
        "section": "proof_of_identity",
        "categories": [
          {
            "document_type": "GOVERNMENT_ID",
            "fields": [
              {
                "field_name": "files",
                "data_type": "URI",
                "status": "EXPIRED",
                "reason": "Document has expired",
                "side": "FRONT"
              },
              {
                "field_name": "issue_date",
                "data_type": "DATE",
                "status": "MISSING",
                "reason": null
              }
            ]
          }
        ]
      },
      {
        "section": "proof_of_address",
        "categories": [
          {
            "document_type": "PROOF_OF_ADDRESS",
            "fields": [
              {
                "field_name": "files",
                "data_type": "URI",
                "status": "MISSING",
                "reason": null
              }
            ]
          }
        ]
      }
    ]
  }
}
```

Every webhook request is signed. Verify the `x-fin-signature` header before acting on the payload. See [**Verifying webhooks**](https://developer.fin.com/guides/webhooks/verifying-webhooks).

***

## Example: Get Customer Details

The same request is readable at any time on the customer record. `request_for_information` is an empty array when nothing is outstanding.

```json theme={null}
{
  "data": {
    "customer_id": "ed54db74-7dbe-47d2-8ea0-c2bf2a9dda06",
    "type": "BUSINESS",
    "business_name": "Fin.com",
    "customer_status": "ACTION_REQUIRED",
    "request_for_information": [
      {
        "section": "ownership_documents",
        "categories": [
          {
            "document_type": "SHAREHOLDER_REGISTRY",
            "fields": [
              {
                "field_name": "files",
                "data_type": "URI",
                "status": "INVALID",
                "reason": "Unacceptable document."
              }
            ]
          }
        ]
      }
    ]
  }
}
```

For individual customers the same array is returned by [**GET /v1/customers/:customer-id**](https://developer.fin.com/api-reference/customers/get-customer-details-v2), with two additional fields per entry: `scope`, which is `CUSTOMER` or `ASSOCIATED_PARTY`, and `options`, which lists permitted values when `data_type` is `ENUM`.

***

## Responding to an RFI

Responding takes two calls: upload the files, then patch the customer with the returned URIs.

<Steps>
  <Step title="Upload the replacement files">
    Post the files to [**POST /v1/customers/upload**](https://developer.fin.com/api-reference/customers/upload-document) as `multipart/form-data`. Field names are arbitrary and are echoed back as the keys in the response.

    ```bash theme={null}
    curl -X POST https://sandbox.api.fin.com/v1/customers/upload \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -F "customer_id=ed54db74-7dbe-47d2-8ea0-c2bf2a9dda06" \
      -F "passport=@passport-front.jpg" \
      -F "poa=@utility-bill.pdf"
    ```

    ```json theme={null}
    {
      "data": {
        "files": [
          { "passport": "/CwW9PHhP_passport-front.jpg" },
          { "poa": "/KVdLfqjR_utility-bill.pdf" }
        ]
      }
    }
    ```

    Allowed file types are `PDF`, `JPG`, `JPEG`, and `PNG`. Keep the returned URIs; the next call needs them.
  </Step>

  <Step title="Submit the response">
    Send the requested fields to [**PATCH /v1/customers/:customer-id**](https://developer.fin.com/api-reference/customers/patch-customer-rfi). The same endpoint serves individual and business customers, and its body accepts the same fields as the Attach Documents endpoints.

    <Warning>
      Submit only the fields the RFI listed. Sending data that was not requested returns an error.
    </Warning>
  </Step>

  <Step title="Watch for the outcome">
    The customer returns to `REVIEWING` while compliance reassesses. Listen on `customer.status` for the result, and on `customer.rfi` in case a further request is raised.
  </Step>
</Steps>

### Individual Customer Response

Answering the `proof_of_identity` and `proof_of_address` sections from the webhook example above:

```json theme={null}
{
  "proof_of_identity": {
    "type": "PASSPORT",
    "number": "A12345678",
    "country": "USA",
    "issue_date": "2020-01-15",
    "expiry_date": "2030-01-15",
    "files": [
      { "uri": "/CwW9PHhP_passport-front.jpg", "side": "FRONT" }
    ]
  },
  "proof_of_address": {
    "type": "UTILITY_BILL",
    "country": "USA",
    "files": [
      { "uri": "/KVdLfqjR_utility-bill.pdf" }
    ]
  }
}
```

### Business Customer Response

Business sections map to top level arrays. An RFI scoped to an associated party is answered inside `associated_party_attachments`, keyed by `associated_party_id`:

```json theme={null}
{
  "ownership_documents": [
    {
      "type": "PROOF_OF_SIGNATORY_AUTHORITY",
      "description": "Shareholder Registry",
      "files": [
        { "uri": "/AbAcQ4hn_0652746727639.pdf" }
      ]
    }
  ],
  "associated_party_attachments": [
    {
      "associated_party_id": "f6b13e01-044a-4f74-a70b-d5f66b6449af",
      "identifying_documents": [
        {
          "type": "PASSPORT",
          "number": "A12345678",
          "country": "USA",
          "issue_date": "2020-01-15",
          "expiry_date": "2030-01-15",
          "files": [
            { "uri": "/AbAcQ4hn_0652746727637.pdf" }
          ]
        }
      ],
      "address_documents": [
        {
          "type": "BANK_STATEMENT",
          "files": [
            { "uri": "/AbAcQ4hn_0652746727638.pdf" }
          ]
        }
      ]
    }
  ]
}
```

A successful patch returns the customer ID:

```json theme={null}
{
  "data": {
    "customer_id": "ed54db74-7dbe-47d2-8ea0-c2bf2a9dda06"
  }
}
```

A `400` response means validation failed. The `data` object names the offending fields. A `404` means the customer ID does not exist.

***

## Common Mistakes

| **Mistake**                                                           | **Result**                                                                                                       |
| :-------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------- |
| Sending fields the RFI did not ask for                                | Request rejected with a validation error.                                                                        |
| Resubmitting the document or field value that was rejected, unchanged | A second RFI naming the same field. Read `reason` and send a corrected or replacement version, not the original. |
| Omitting `side` on a two sided document                               | The missing side stays outstanding.                                                                              |
| Patching before the upload call                                       | The URIs do not resolve and the documents are not attached.                                                      |
| Treating `ACTION_REQUIRED` as terminal                                | Verification resumes as soon as the RFI is answered.                                                             |
