> For the complete documentation index, see [llms.txt](https://docs.bullcredtech.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.bullcredtech.com/api-reference/apis-en/guias/proposal-flow.md).

# Proposal Flow

The origination process follows a mandatory sequence of 7 steps. Each step must be completed before moving on to the next.

## <mark style="color:$primary;">Step 1: Start proposal</mark>

Creates a new proposal with the customer's basic data. If there is already an active proposal for the CPF, the API returns the existing proposal.

**Endpoint:** `POST /proposals/start`

```json
{
  "cpf": "12345678901",
  "full_name": "João da Silva Santos",
  "birth_date": "1985-03-15"
}
```

**Behavior:**

* Initial status: `CREATED`
* CPF already has an active proposal: returns the existing proposal without creating a new one

***

## <mark style="color:$primary;">Step 2: Send contact</mark>

Adds the customer's contact details and automatically triggers sending the validation token by SMS.

**Endpoint:** `POST /proposals/{proposal_id}/contact`

```json
{
  "email": "joao@email.com",
  "phone": "+5511999998888"
}
```

**Behavior:**

* SMS token automatically sent to the provided phone number
* Resulting status: TOKEN\_SENT

***

## <mark style="color:$primary;">Step 3: Validate SMS token</mark>

Confirms the 6-digit code received by SMS. It is also possible to resend the token via WhatsApp (3.1) or SMS (3.2) if the customer did not receive it.

**Endpoint:** `POST /proposals/{proposal_id}/contact/validate-token`

```json
{
  "token": "123456",
  "phone": "+5511999998888"
}
```

**Behavior:**

* Resulting status: TOKEN\_VALIDATED
* Resend via WhatsApp: `POST /contact/resend-token/whatsapp`
* Resend via SMS: `POST /contact/resend-token`

***

## <mark style="color:$primary;">Step 4: Credit analysis</mark>

Requests full credit analysis and offer generation. Asynchronous endpoint; use webhooks to receive the result.

**Endpoint:** `POST /proposals/{proposal_id}/credit-analysis`

```json
{
  "ip": "203.0.113.12",
  "geolocation": {
    "latitude": -23.5505,
    "longitude": -46.6333
  },
  "document_text": "I authorize the processing of my data for payroll loan credit analysis.",
  "channel": "web"
}
```

{% hint style="info" %}
**Asynchronous processing**

This endpoint processes asynchronously. The proposal remains in `CREDIT_ANALYSIS_IN_PROGRESS` during processing. Calls during processing return `409 Conflict`.
{% endhint %}

**Possible responses:**

* `200 OK` → Analysis completed, offers available in the response
* `202 Accepted` → Processing started, poll at [`GET /proposals/{proposal_id}/credit-analysis`](/api-reference/apis-en/proposal-flow/get-proposals-credit-analysis.md) or wait for webhook
* `409 Conflict` → Already processing, wait for the result before calling again
* Approved: `CREDIT_CHECK_COMPLETED` with offers available
* Rejected: `REJECTED` flow closed

{% hint style="info" %}
**Result polling**

When the analysis is triggered in asynchronous mode (`?async=true`), use [`GET /proposals/{proposal_id}/credit-analysis`](/api-reference/apis-en/proposal-flow/get-proposals-credit-analysis.md) to poll until the final result is received. Same response shape as the synchronous POST.
{% endhint %}

***

## <mark style="color:$primary;">Credit analysis reprocessing</mark>

If credit analysis fails due to technical instability or because of Dataprev's maintenance window, Bull will send the status `CREDIT_ANALYSIS_FAILED` in the proposal webhook.

This scenario can occur due to:

* Dataprev unavailability
* Dataprev maintenance window
* Credit engine error
* Instability of partners involved in the analysis

### <mark style="color:$primary;">How the partner should act</mark>

1. Identify the webhook with status `CREDIT_ANALYSIS_FAILED`
2. Since this is an instability, wait a few minutes and then call the retry endpoint. There are three equivalent variants — choose according to the flow:
   * **Synchronous (default):** `POST /proposals/{proposal_id}/credit-analysis/retry` — blocks until completion
   * **Asynchronous via query:** `POST /proposals/{proposal_id}/credit-analysis/retry?async=true` — returns 202 immediately
   * **Dedicated asynchronous:** `POST /proposals/{proposal_id}/credit-analysis/retry/async` — equivalent to the above, recommended for new integrations (gateway has optimized timeout)
3. Wait for the confirmation webhook or poll via [`GET /proposals/{proposal_id}/credit-analysis`](/api-reference/apis-en/proposal-flow/get-proposals-credit-analysis.md) to track the new result
4. If successful, inform the customer about the available offer

{% hint style="info" %}
**Retry with the last saved consent**

The retry endpoint reuses the most recent consent from the proposal and does not require collecting the customer's consent again.
{% endhint %}

For route details, see [POST /proposals/{proposalId}/credit-analysis/retry](/api-reference/apis-en/proposal-flow/post-proposals-credit-analysis-retry.md)

***

## <mark style="color:$primary;">Step 4.1: Simulate offers (optional)</mark>

Customizes the offer within the approved limits. Can be called after credit analysis and also in the statuses `PRE_ACCEPTED` and `BANK_DATA_SUBMITTED`.

**Endpoint:** `POST /proposals/{proposal_id}/simulate`

1. **By Term:** provide `installments` to obtain the maximum financed amount.

```json
{ "installments": 12 }
```

2. **By Amount:** provide `loan_amount` to obtain the term options.

```json
{ "loan_amount": 15000 }
```

**Behavior:**

* Generates and stores new offers linked to the proposal
* The `offer.id` returned is used in pre-acceptance
* Can also be called in the statuses `PRE_ACCEPTED` and `BANK_DATA_SUBMITTED`

***

## <mark style="color:$primary;">Step 5: Pre-acceptance</mark>

Customer selects and confirms one of the available offers. Use the `offer.id` returned in step 4 or 4.1.

**Endpoint:** `POST /proposals/{proposal_id}/pre-accept`

```json
{
  "selected_offer_id": "uuid-da-oferta"
}
```

**Behavior:**

* Registers acceptance of the selected offer
* Status changes to: `PRE_ACCEPTED`

***

## <mark style="color:$primary;">Step 6: Banking data</mark>

Provides bank account or Pix key for disbursement. Pix keys go through ownership validation in DICT before confirmation.

**Endpoint:** `POST /proposals/{proposal_id}/banking-data`

```json
{
  "bank_code": "001",
  "bank_branch": "1234",
  "bank_account": "123456789",
  "bank_account_digit": "4",
  "account_type": "checking",
  "use_pix_cpf": false
}
```

**Behavior:**

* Accepts traditional bank account, `use_pix_cpf: true` or `pix_key` + `pix_key_type`
* Pix keys go through ownership and DICT validation before confirmation
* If the Pix key is not confirmed, the API may respond `200` with `ok: false`
* Status changes to: `BANK_DATA_SUBMITTED`

Example with Pix by explicit key:

```json
{
  "pix_key": "cliente@example.com",
  "pix_key_type": "EMAIL"
}
```

***

## <mark style="color:$primary;">Step 7: Generate contract</mark>

Generates the digital contract via Celcoin and starts the signing process via UNICO. Asynchronous endpoint.

**Endpoint:** `POST /proposals/{proposal_id}/contract`

{% hint style="info" %}
**Asynchronous processing**

This endpoint processes asynchronously. The proposal remains in `CONTRACT_GENERATION_IN_PROGRESS` during processing.
{% endhint %}

**Behavior:**

* Contract is generated with Celcoin integration
* Digital signing process is started via UNICO
* Status advances to: `CONTRACT_GENERATED` → `AWAITING_SIGNATURE`

***

## <mark style="color:$primary;">After the contract</mark>

After contract generation, the flow continues automatically via UNICO (signature) and Celcoin (disbursement):

| Status               | Description                                                          | Action                          |
| -------------------- | -------------------------------------------------------------------- | ------------------------------- |
| `AWAITING_SIGNATURE` | Customer accessed the UNICO link to sign                             | Wait for completion via webhook |
| `SIGNED`             | Biometric signature validated successfully                           | Wait for disbursement           |
| `SIGNATURE_FAILED`   | Biometric validation failed (fraud or technical)                     | Start new proposal              |
| `PENDING_ANALYSIS`   | Internal fraud analysis (high-value or attention-required proposals) | Bull internal process — wait    |

## <mark style="color:$primary;">Proposal cancellation</mark>

Before disbursement, the originator can cancel the proposal using `POST /proposals/{proposal_id}/cancel`.

**When allowed:**

* `CONTRACT_GENERATED`
* `AWAITING_SIGNATURE`

**Behavior:**

* the proposal moves to `CANCELED`
* cancellation is irreversible
* if there is an active application in Celcoin, the API tries to cancel it automatically

For route details, see [POST /proposals/{proposalId}/cancel](/api-reference/apis-en/proposal-flow/post-proposals-cancel.md). | `ANALYSIS_APPROVED` | Fraud analysis approved | Automatic disbursement | | `ANALYSIS_REPROVED` | Fraud analysis rejected | Flow closed without disbursement | | `DISBURSED` | Credit disbursed into account | Flow completed ✓ |

{% hint style="info" %}
**Why can SIGNATURE\_FAILED occur?**

Even if the customer completes the UNICO process, the system validates facial biometrics, liveness (real-person detection), and anti-fraud verification. If any check fails, the signature is rejected. See [Webhooks](/api-reference/apis-en/guias/webhooks.md) for details about failure scenarios.
{% endhint %}

## <mark style="color:$primary;">Asynchronous processing</mark>

The **credit analysis** and **contract generation** endpoints are processed asynchronously:

1. On the first call, processing is **started**
2. Calls during processing return **409 Conflict**
3. The result can be obtained in two ways:

### <mark style="color:$primary;">Polling</mark>

Call the endpoint again until you receive the final result:

```
POST /proposals/{id}/credit-analysis  →  409 (processing)
POST /proposals/{id}/credit-analysis  →  409 (processing)
POST /proposals/{id}/credit-analysis  →  200 (result ready)
```

### <mark style="color:$primary;">Webhooks (recommended)</mark>

Wait for the status change notification via webhook and then query `GET /proposals/{id}` to obtain the details. See [Webhooks](/api-reference/apis-en/guias/webhooks.md).

## <mark style="color:$primary;">New credit analysis</mark>

It is possible to request a new credit analysis when the proposal is in the statuses:

* `OFFER_SELECTED`
* `PRE_ACCEPTED`
* `BANK_DATA_SUBMITTED`

This allows recalculating the offer if necessary before contract generation.

## <mark style="color:$primary;">Promotional action after 20 hours</mark>

This action is intended for proposals that have already received an offer, completed 20 hours, and still have not converted.

### <mark style="color:$primary;">General rule</mark>

This flow should be applied to proposals that:

* have already had an offer generated
* have completed at least 20 hours since the offer
* have still not advanced in the expected conversion

In this promotional action, the partner reuses the proposal that already had an offer and guides the customer again into a new credit analysis with the same `proposal_id`.

### <mark style="color:$primary;">Flow through the partner channel</mark>

In this model, the partner brings the customer back into their own channel's credit analysis flow.

#### <mark style="color:$primary;">Step by step</mark>

1. The partner identifies the proposal that reached 20 hours with an offer and did not convert.
2. The partner re-engages the customer in their channel.
3. The customer returns to the partner's credit analysis flow.
4. The partner collects the user's consent again.
5. The partner calls `POST /proposals/{proposal_id}/credit-analysis` with the `proposal_id` of the proposal that had already received an offer.
6. Bull performs a new analysis on the same proposal.
7. If the proposal is eligible for the promotion, the response may return a new promotional offer.
8. The partner presents the new result and continues the flow normally.

```mermaid
flowchart TD
    A["Proposal with offer not converted"] --> B["Partner waits 20h"]
    B --> C["Partner re-engages the customer"]
    C --> D["Customer returns to the partner analysis flow"]
    D --> E["Partner collects new consent"]
    E --> F["POST /proposals/{proposal_id}/credit-analysis"]
    F --> G["New analysis on the same proposal"]
    G --> H["If eligible, returns offer with promotion"]
    H --> I["Partner follows the proposal flow"]
```

{% hint style="info" %}
**Same `proposal_id`**

In the promotional action, the partner must reuse the `proposal_id` of the proposal that already had an offer. The user returns to the flow, but the analysis is performed on the same proposal.
{% endhint %}

## <mark style="color:$primary;">Maintenance window</mark>

{% hint style="warning" %}
**Government Systems**

Credit analysis and contract recording depend on government systems that become unavailable between the **20th day (10:00 PM) and the 23rd day (6:00 AM)** of each month (Dataprev competency rollover).

Recommendations:

* Avoid generating contracts during this period
* Proposals signed during the window may remain in status `ERROR`
* Processing resumes automatically after normalization
  {% endhint %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.bullcredtech.com/api-reference/apis-en/guias/proposal-flow.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
