> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.credit.aarthiklabs.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.credit.aarthiklabs.com/_mcp/server.

# Business Loan Dedupe

> Check participating lenders with asynchronous start and read APIs using hashed or unhashed identifiers.

Dedupe is an optional check before collecting a full business credit application. Start with an authenticated POST, store `data.journeyID`, then use GET to read the operation and lender results. HTTP `202` means accepted; it does not mean the borrower passed Dedupe.

```http
POST /api/v1/hybrid/business-loan/borrowers/{borrowerProviderID}/journey/dedupe
Authorization: Bearer <PLATFORM_API_KEY>
Content-Type: application/json
Idempotency-Key: <stable-key-for-this-attempt>
```

Omit `journeyID` to create a journey, or pass `?journeyID=<existing-journey-id>` to reuse one for the same borrower. Keep `borrowerProviderID` stable. Reuse the idempotency key only for an exact retry, including after a timeout; never create a new journey merely because the response was lost.

## Identifier modes

Both modes are available in the [API request example selector](/api-reference/hybrid-experience/business-loan/start-hybrid-business-loan-dedupe). Supply at least one identifier. Identifier handling is configured for your application by Aarthik Labs. Do not send a `mode` field.

Hashing is separate from encryption. Unhashed identifiers are original values sent over authenticated HTTPS, not an unprotected transport. Keep API keys and identity data on your backend. Agree the hashed identifier representation with Aarthik Labs before implementation; the opaque values below are synthetic examples.

## Anonymised (Hashed) Dedupe

```json
{
  "journeyType": "BUSINESS_LOAN",
  "identifiers": {
    "pan": "a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1",
    "mobileNumber": "b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2"
  }
}
```

## Un-Anonymised (Un-Hashed) Dedupe

```json
{
  "journeyType": "BUSINESS_LOAN",
  "identifiers": {
    "pan": "ABCDE1234F",
    "mobileNumber": "9999999999"
  }
}
```

## Start response and polling

The start POST returns HTTP `202` with `data.status: PENDING` and `data.journeyID`, without a polling object. Make the first Fetch Dedupe Results call after acceptance; use the polling guidance returned by that GET for subsequent reads. Both identifier examples in the API Reference show this accepted response.

```http
GET /api/v1/hybrid/business-loan/borrowers/{borrowerProviderID}/journey/dedupe?journeyID=<returned-journey-id>
Authorization: Bearer <PLATFORM_API_KEY>
```

A successful GET returns HTTP `200`, even while processing is pending. Follow `data.polling.nextPoll` and stop when `data.polling.shouldPoll` is false. Do not repeat POST to poll. Respect `Retry-After` on `429`.

## Journey-level status

`data.status` is the overall Dedupe result for the journey. Each entry in `data.lenders` also has its own `status`, retaining detailed lender-specific values, including `SKIPPED` and `ERROR`.

| Lender results                                             | Journey status |
| ---------------------------------------------------------- | -------------- |
| Any lender is `PENDING`, regardless of other results       | `PENDING`      |
| No pending lenders; at least one is `CLEAR` or `SKIPPED`   | `CLEAR`        |
| No pending lenders; all results are `NOT_CLEAR` or `ERROR` | `NOT_CLEAR`    |

`SKIPPED` counts as positive and `ERROR` counts as negative when calculating the journey outcome. The journey can only be `CLEAR`, `NOT_CLEAR`, or `PENDING`; individual lender statuses are preserved.

| Example lender results  | Journey outcome |
| ----------------------- | --------------- |
| `CLEAR` + `PENDING`     | `PENDING`       |
| `SKIPPED` + `PENDING`   | `PENDING`       |
| `CLEAR` + `NOT_CLEAR`   | `CLEAR`         |
| `SKIPPED` + `NOT_CLEAR` | `CLEAR`         |
| `SKIPPED` + `ERROR`     | `CLEAR`         |
| All `SKIPPED`           | `CLEAR`         |
| `NOT_CLEAR` + `ERROR`   | `NOT_CLEAR`     |
| All `ERROR`             | `NOT_CLEAR`     |

`polling.shouldPoll` is true only while the journey is `PENDING`. Inspect individual lender results to understand each lender's outcome.

## Lender results: pass, fail and errors

| Status      | Meaning                                                           |
| ----------- | ----------------------------------------------------------------- |
| `CLEAR`     | Pass: the lender permits the borrower to continue.                |
| `NOT_CLEAR` | Does not pass: this lender does not permit continuation.          |
| `PENDING`   | Still awaiting the lender decision; neither pass nor fail.        |
| `SKIPPED`   | This lender does not require Dedupe and may continue.             |
| `ERROR`     | Technical failure to obtain a decision, not a borrower rejection. |

Each lender result also includes `decisionReference`, `decidedAt`, `expiresAt` and `reasonCode` when available. A borrower can pass one lender's check and not pass another's. Journey-level `CLEAR` is not universal lender clearance or loan approval.

### Completed response

```json
{
  "request_id": "30000000-0000-4000-8000-000000000001",
  "correlation_id": "40000000-0000-4000-8000-000000000001",
  "timestamp": "2026-10-28T09:00:00Z",
  "data": {
    "journeyID": "10000000-0000-4000-8000-000000000001",
    "stage": "DEDUPE",
    "status": "CLEAR",
    "lenders": [
      {
        "lenderID": "example-lender-a",
        "status": "CLEAR",
        "decisionReference": "decision-example-1",
        "decidedAt": "2026-10-28T09:00:00Z",
        "expiresAt": "2026-10-29T09:00:00Z",
        "reasonCode": null
      },
      {
        "lenderID": "example-lender-b",
        "status": "NOT_CLEAR",
        "decisionReference": "decision-example-2",
        "decidedAt": "2026-10-28T09:00:00Z",
        "expiresAt": "2026-10-29T09:00:00Z",
        "reasonCode": null
      }
    ],
    "polling": {
      "shouldPoll": false,
      "lastPoll": "2026-10-28T09:00:00Z",
      "nextPoll": null
    }
  },
  "error": null
}
```

The [Fetch Dedupe Results API Reference](/api-reference/hybrid-experience/business-loan/read-hybrid-business-loan-dedupe) includes examples for all three journey statuses, including a pending journey with one lender already clear.

## Continue with the same journey

Once results are terminal, continue only with lenders whose current result is `CLEAR` or `SKIPPED`. Use the returned `data.journeyID` as the `journeyID` query parameter for optional Eligibility and for Create A Journey. You can skip Eligibility. After Start, keep the same ID for offer polling and Hosted handoff.

For validation failures, fix the input before retrying. Do not retry authentication or access errors unchanged. For `429`, follow `Retry-After`; for a transient dependency or server failure, retry with backoff and the same idempotency key. Do not substitute another journey for an invalid or unauthorized ID.