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

# Statuses and events

> Follow a merchant's onboarding end to end: the affiliation statuses, the 30-day deadline and cancellation, and the webhooks for affiliations, requirements, documents and biometric verifications.

Onboarding reports every step by webhook, so your system can follow a merchant from the affiliation's creation to its approval without polling. This page covers the affiliation statuses as onboarding uses them and the events each building block sends.

## Affiliation statuses

The status set is the [affiliation](/concepts/affiliations#affiliation-status) set you already use. `WAITING_DOCUMENTS` covers the collection Rinne does before submitting and a provider's request for more on an open affiliation, and `CANCELLED` ends an attempt that waited too long or that you cancelled.

Every transition between them is drawn in the [affiliation lifecycle](/concepts/affiliations#affiliation-lifecycle). What each one means for onboarding, and what you do:

| Status | Meaning | What you do |
| - | - | - |
| `WAITING_DOCUMENTS` | At least one requirement is pending, before the first submission or after a provider that takes supplements asked for more. `onboarding_url` collects them | Supply the pending items through the API, or send the link |
| `PENDING` | Every requirement is satisfied and Rinne is submitting, or retrying after a provider outage, or holding the attempt until a previous one for the same CNPJ or CPF finishes at the provider or until Rinne's review of a previous rejection lands | Wait |
| `PENDING_APPROVAL` | Submitted; the provider is checking the merchant's data | Wait |
| `PROCESSING_DOCUMENTS` | The provider is analyzing the documents and the biometric verification | Wait |
| `PROCESSING` | The provider is processing the affiliation through its own steps; a supplement lands back here | Wait |
| `ACTIVE` | Approved. `onboarding_url` is `null` and the documents sent are `VALIDATED` | Transact |
| `REJECTED` | The provider refused the attempt. `rejection_reasons` follow once Rinne reviews it | [Supply what the review asks for](/onboarding/rejections) and create a new affiliation, unless the review's `action` is `NONE`: the provider refuses a new attempt too |
| `FAILED` | A technical failure while creating or submitting | Create the affiliation again; documents and verifications are untouched |
| `CANCELLED` | Cancelled while waiting for documents, by you or by the 30-day deadline | Create a new affiliation when the merchant is ready |

`INVALID_SETTLEMENT_BANK_ACCOUNT`, `BLOCKED` and `CLOSED` work as described in [Affiliations](/concepts/affiliations#affiliation-status).

### CANCELLED

An affiliation becomes `CANCELLED` in two ways, recorded in `cancellation_reason`:

| `cancellation_reason` | When |
| - | - |
| `REQUESTED` | You cancelled it while it was `WAITING_DOCUMENTS` |
| `EXPIRED` | It waited 30 days in `WAITING_DOCUMENTS` before its first submission |

`CANCELLED` is terminal: nothing moves the affiliation out of it. Its link is abandoned, so nothing completed through it afterwards applies to the cancelled affiliation, while documents, verifications and answers stay with the merchant and satisfy its next affiliation. When an attempt the provider had already received is cancelled, the provider's process can stay open on its side, and its later result is ignored. At `CELCOIN`, a new affiliation for the same CNPJ or CPF is created normally and collects what is pending in `WAITING_DOCUMENTS`; once nothing is pending, it waits as `PENDING` until that process ends, at most 33 days after the cancelled attempt was submitted. At `CAPPTA` nothing is held: the new affiliation is submitted as soon as its requirements are satisfied.

### Cancel an affiliation

Cancel an affiliation that is waiting for documents to start over, for example after correcting the merchant's data:

```bash cURL theme={null}
curl -X POST https://api-sandbox.rinne.com.br/core/v1/merchants/a7089150-0d61-498f-b7ca-4767e4e4d6a4/affiliations/2352ebe5-97c2-4625-8535-cc21b732787a/cancel \
  -H "x-api-key: YOUR_API_KEY"
```

The call takes no body and answers `200` with the affiliation `CANCELLED`, `cancellation_reason` `REQUESTED` and `onboarding_url` `null`, and `affiliation.status-changed` fires. Any status other than `WAITING_DOCUMENTS` answers `409`, whose `message` names the status found: once submitted, the provider decides. A status change racing the cancel answers `409` too, and when the affiliation is back in `WAITING_DOCUMENTS` by then, the `message` asks you to retry. Organizations onboarding themselves call `POST /v1/affiliations/{id}/cancel`. Both routes require the `affiliation.edit` permission (`merchant.affiliation.edit` on the merchant route).

## Events

Every event uses the standard [webhook envelope](/guides/webhooks#webhook-payload-structure) and is delivered at least once, so deduplicate by the envelope `id`. Events about a merchant reach the merchant's own endpoint, when it has one, and its organization's.

| Event | When |
| - | - |
| `affiliation.created` | An affiliation was created; carries `onboarding_url` when it was created `WAITING_DOCUMENTS` |
| `affiliation.status-changed` | The affiliation changed status; carries `onboarding_url` when `new_status` is `WAITING_DOCUMENTS` |
| `affiliation.requirements-changed` | What the merchant must supply for the affiliation changed |
| `onboarding-document.status-changed` | A document changed status |
| `biometric-verification.status-changed` | A biometric verification left `PENDING` |

The handlers below run inside the verified handler of the [webhooks guide](/guides/webhooks#verifying-webhook-signatures), after the signature check.

### Affiliation requirements changed

Fires when the merchant's requirements for the affiliation's provider change while the affiliation is not `ACTIVE`: Rinne reviewed a rejection or a provider's request, Rinne staff added a requirement, or an approved biometric verification has to be redone. When the change also sends the affiliation back to `WAITING_DOCUMENTS`, `affiliation.status-changed` fires as well.

```json Event (entity trimmed) theme={null}
{
  "id": "38564e6c-7d12-45e1-8998-3b5b472a6928",
  "type": "affiliation.requirements-changed",
  "version": 1,
  "timestamp": "2026-10-03T16:40:00.000Z",
  "source": "affiliation-service",
  "company_id": "a7089150-0d61-498f-b7ca-4767e4e4d6a4",
  "correlation_id": "38564e6c-7d12-45e1-8998-3b5b472a6928",
  "payload": {
    "affiliation_id": "2352ebe5-97c2-4625-8535-cc21b732787a",
    "company_id": "a7089150-0d61-498f-b7ca-4767e4e4d6a4",
    "changed_requirement_ids": ["9d6c5c69-1c92-4d25-93cf-fc0a63f1251c"],
    "occurred_at": "2026-10-03T16:40:00.000Z",
    "entity": {
      "id": "2352ebe5-97c2-4625-8535-cc21b732787a",
      "provider": "CELCOIN",
      "status": "REJECTED",
      "rejection_reviewed_at": "2026-10-03T16:40:00.000Z",
      "rejection_reasons": [
        {
          "code": "DOCUMENT_UNREADABLE",
          "message": "The contact's identity document could not be read. Send a new, sharp photo of the front and the back.",
          "action": "RESUBMIT_DOCUMENT",
          "requirement_id": null,
          "onboarding_document_id": "161e2065-1179-4484-9ea3-faf62199595e"
        }
      ]
    }
  }
}
```

`changed_requirement_ids` lists the requirements whose evidence was refused, the ones the review added, or the biometric one sent back to `PENDING`. It is empty when the review recorded reasons that reset nothing (`FIX_COMPANY_DATA`, `NONE`). `entity` is the affiliation as `GET /v1/affiliations/{id}` returns it, without `company_snapshot`.

```javascript theme={null}
if (event.type === 'affiliation.requirements-changed') {
  const { affiliation_id, company_id, entity } = event.payload;

  if (entity.status === 'REJECTED' && entity.rejection_reviewed_at) {
    // The rejection was reviewed - show the merchant what to fix
    await showRejectionReasons(affiliation_id, entity.rejection_reasons);
  }
  // Refresh the checklist you show the merchant
  await refreshRequirements(company_id, entity.provider);
}
```

### Onboarding document status changed

Fires on every document status change after creation: an upload completed (`NOT_VALIDATED`), an affiliation that sent it was approved (`VALIDATED`), a provider refused it (`REJECTED`, with `rejections`), or a newer upload replaced it (`SUPERSEDED`). A document shared from another organization arrives `VALIDATED` with `old_status` `null`.

```json Event (entity trimmed) theme={null}
{
  "id": "7dc6060d-f12f-4f4d-97d1-291e993f77da",
  "type": "onboarding-document.status-changed",
  "version": 1,
  "timestamp": "2026-10-02T12:01:30.000Z",
  "source": "onboarding-service",
  "company_id": "a7089150-0d61-498f-b7ca-4767e4e4d6a4",
  "correlation_id": "d5defce5-d859-4a58-a504-3ad470b6de08",
  "payload": {
    "onboarding_document_id": "d5defce5-d859-4a58-a504-3ad470b6de08",
    "company_id": "a7089150-0d61-498f-b7ca-4767e4e4d6a4",
    "old_status": "PENDING_UPLOAD",
    "new_status": "NOT_VALIDATED",
    "occurred_at": "2026-10-02T12:01:30.000Z",
    "entity": {
      "id": "d5defce5-d859-4a58-a504-3ad470b6de08",
      "type": "ARTICLES_OF_INCORPORATION",
      "subject_document_number": "12345678000195",
      "status": "NOT_VALIDATED",
      "source": "UPLOAD",
      "file_size_bytes": 482133
    }
  }
}
```

```javascript theme={null}
if (event.type === 'onboarding-document.status-changed') {
  const { onboarding_document_id, new_status, entity } = event.payload;

  await recordDocumentStatus(onboarding_document_id, new_status);

  if (new_status === 'REJECTED') {
    // A provider refused it - ask the merchant for a new one of the same type
    await requestNewDocument(entity.subject_document_number, entity.type, entity.rejections);
  }
}
```

### Biometric verification status changed

Fires when a verification leaves `PENDING`: `APPROVED`, `REPROVED` with `rejection_reason`, or `EXPIRED`. It reaches the merchant the verification was created for and, when that merchant is not your organization itself, your organization too.

```json Event (entity trimmed) theme={null}
{
  "id": "030c761f-f1d9-4e32-985f-1069fff71744",
  "type": "biometric-verification.status-changed",
  "version": 1,
  "timestamp": "2026-10-02T12:09:12.000Z",
  "source": "onboarding-service",
  "company_id": "a7089150-0d61-498f-b7ca-4767e4e4d6a4",
  "correlation_id": "336b4995-d8ed-4837-97b2-b94990b30240",
  "payload": {
    "biometric_verification_id": "336b4995-d8ed-4837-97b2-b94990b30240",
    "company_id": "a7089150-0d61-498f-b7ca-4767e4e4d6a4",
    "old_status": "PENDING",
    "new_status": "APPROVED",
    "occurred_at": "2026-10-02T12:09:12.000Z",
    "entity": {
      "id": "336b4995-d8ed-4837-97b2-b94990b30240",
      "provider": "CELCOIN",
      "subject_document_number": "52998224806",
      "status": "APPROVED",
      "selfie_onboarding_document_id": "9f9f4193-9291-4b12-a7da-763e30880811",
      "approved_at": "2026-10-02T12:09:12.000Z",
      "rejection_reason": null
    }
  }
}
```

```javascript theme={null}
if (event.type === 'biometric-verification.status-changed') {
  const { biometric_verification_id, new_status, entity } = event.payload;

  if (new_status === 'APPROVED') {
    // Satisfies the person's BIOMETRIC_VERIFICATION requirement in every merchant of your organization
    await markPersonVerified(entity.subject_document_number, biometric_verification_id);
  } else {
    // REPROVED (entity.rejection_reason) or EXPIRED - start a new verification
    await askForNewVerification(entity.subject_document_number, entity.rejection_reason);
  }
}
```

## Next steps

<CardGroup cols={2}>
  <Card title="Webhooks guide" icon="webhook" href="/guides/webhooks">
    Endpoint setup, signature verification and retries.
  </Card>

  <Card title="Test in the sandbox" icon="flask" href="/onboarding/testing">
    Drive each status on purpose.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.