> 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.

# Read (Poll) Offers

GET https://credit.aarthiklabs.com/api/v1/hybrid/personal-loan/borrowers/{borrowerProviderID}/journey/offers

Read-only API-key call. Pass the Start response `data.journey.id` as `journeyID` to poll the intended application attempt. Poll this endpoint using `data.polling.nextPoll` until selectable `OFFER_RECEIVED` offers, an actionable `data.account_aggregator.url`, `NOT_OFFERED`, `NOT_PROFILED`, or `data.polling.shouldPoll = false` is returned. `NOT_PROFILED` is terminal and returns no lenders or polling instruction because borrower profiling did not complete. Calls before `nextPoll` can return `429` with `OFFER_POLL_RATE_LIMITED`. Calls made before a recent Start Journey request finishes initializing can return `429` with `HYBRID_JOURNEY_NOT_READY` and `data.polling.shouldPoll = true`. If `journeyID` is omitted, borrower-only fallback is legacy behavior and may return a 409 ambiguity error when the same borrower has multiple active Hybrid application attempts.

Reference: https://docs.credit.aarthiklabs.com/api-reference/hybrid-experience/personal-loans/poll-hybrid-personal-loan-offers

## Authentication

- `Authorization` header (bearer token, required) — Send `Authorization: Bearer <PLATFORM_API_KEY>` from a trusted back-end.

## Servers

- `https://credit.aarthiklabs.com` (Production, default)
- `https://preprod.credit.aarthiklabs.com` (PreProduction)

## Request

### Path parameters

- `borrowerProviderID` (string, required) — Stable borrower identity from the partner system. Keep a 1:1 mapping between the borrower and `borrowerProviderID` across sessions and application attempts to preserve resume, history, and post-disbursal continuity.

### Query parameters

- `journeyID` (string, optional) — Journey ID returned as `data.journey.id` by Start. Send this on Offers and Hosted handoff calls to continue the intended application attempt. The `journey_id` query parameter and `x-aarthiklabs-journey-id` header aliases are also accepted. If more than one alias is sent, all values must match.

### Headers

- `x-correlation-id` (string, optional) — Optional caller-supplied trace identifier. When omitted, the API generates one and mirrors it as `correlation_id`.

## Response

### 200

Current Hybrid offer state.

- `request_id` (string, required)
- `correlation_id` (string, required)
- `timestamp` (datetime, required)
- `data` (HybridOffersData, required) — Current Hybrid offer state. Personal Loan and Business Loan use the Personal Loan-style lender-grouped offer shape. Gold Loan responses do not include Account Aggregator in Hybrid right now and can include lender branch locations. Loan Against Mutual Funds uses its own offer schema because lender groups do not expose minimum or maximum loan amounts.
- `error` (any, required)

## Errors

### 401 Unauthorized Error

Missing or invalid platform API key.

- `request_id` (string, required)
- `correlation_id` (string, required)
- `timestamp` (datetime, required)
- `data` (any, required)
- `error` (HybridError, required)

### 404 Not Found Error

Borrower, journey, route, or offer was not found for the authenticated application scope.

- `request_id` (string, required)
- `correlation_id` (string, required)
- `timestamp` (datetime, required)
- `data` (any, required)
- `error` (HybridError, required)

### 409 Conflict Error

The current journey or offer state does not allow the requested transition.

- `request_id` (string, required)
- `correlation_id` (string, required)
- `timestamp` (datetime, required)
- `data` (any, required)
- `error` (HybridError, required)

### 429 Too Many Requests Error

Too many requests. For offer polling, retry at the returned `polling.nextPoll` timestamp.

- `PollHybridPersonalLoanOffersRequestTooManyRequestsError`
  - HybridErrorResponse: HybridErrorResponse
  - HybridOfferPollingRateLimitedResponse: HybridOfferPollingRateLimitedResponse

### 500 Internal Server Error

Temporary upstream or platform failure.

- `request_id` (string, required)
- `correlation_id` (string, required)
- `timestamp` (datetime, required)
- `data` (any, required)
- `error` (HybridError, required)

## Types

### HybridOffersData

Current Hybrid offer state. Personal Loan and Business Loan use the Personal Loan-style lender-grouped offer shape. Gold Loan responses do not include Account Aggregator in Hybrid right now and can include lender branch locations. Loan Against Mutual Funds uses its own offer schema because lender groups do not expose minimum or maximum loan amounts.

- `status` (enum, required)
  - Allowed values: `STARTED`, `NOT_PROFILED`, `PROFILED`, `OFFERED`, `NOT_OFFERED`, `OFFER_ACCEPTED`, `LENDER_REDIRECTED`, `REJECTED`, `DISBURSED`, `EXPIRED`
- `lenders` (map from string to HybridLenderOfferGroup, required) — Map keyed by borrower-visible lender name.
- `journeyID` (string, required) — Aarthik Labs journey ID. Matches `data.journey.id` in lifecycle web-hooks for the same borrower journey.
- `polling` (HybridPolling, optional)
- `account_aggregator` (HybridAccountAggregator, optional)

### HybridError

- `code` (enum, required)
  - Allowed values: `VALIDATION_FAILED`, `AUTH_INVALID_API_KEY`, `AUTH_INVALID_SESSION`, `ACCESS_SCOPE_MISMATCH`, `RESOURCE_NOT_FOUND`, `OFFER_LOCK_CONFLICT`, `STATE_PRECONDITION_FAILED`, `OFFER_POLL_RATE_LIMITED`, `HYBRID_JOURNEY_NOT_READY`, `RATE_LIMITED`, `UPSTREAM_TEMPORARY_FAILURE`
- `message` (string, required)
- `retryable` (boolean, required) — Whether retrying the same operation can make progress. A persisted final primary-form failure is not retryable, including HTTP 500; reconcile the accepted operation before any resubmission. Correct invalid input before retrying validation failures.
- `details` (map from string to any, required, nullable)

### HybridErrorResponse

- `request_id` (string, required)
- `correlation_id` (string, required)
- `timestamp` (datetime, required)
- `data` (any, required)
- `error` (HybridError, required)

### HybridOfferPollingRateLimitedResponse

- `request_id` (string, required)
- `correlation_id` (string, required)
- `timestamp` (datetime, required)
- `data` (HybridOfferPollingRateLimitedResponseData, required)
- `error` (HybridError, required)

### HybridLenderOfferGroup

- `minimumLoanAmount` (string, required, nullable)
- `maximumLoanAmount` (string, required, nullable)
- `offers` (list of HybridOfferRow, required)

### HybridPolling

- `shouldPoll` (boolean, required)
- `lastPoll` (datetime, required)
- `nextPoll` (datetime, required)

### HybridAccountAggregator

- `url` (string, required, nullable) — Short-lived AA URL. `null` until the URL is generated. Open this URL in the borrower browser or webview when it is a string.
- `expires_at` (datetime, required, nullable) — Expiry time for the returned AA URL. `null` until the URL is generated.
- `lenders` (list of string, required)
- `productType` (enum, optional) — Present for the composite Business Hybrid flow. Identifies the source product whose AA action is being shown while the caller continues using the public Business root journey ID.
  - Allowed values: `BUSINESS_LOAN`, `PERSONAL_LOAN`

### HybridOfferPollingRateLimitedResponseData

- `polling` (HybridPolling, required)

### HybridOfferRow

- `consentHandleAvailable` (boolean, required, nullable)
- `annualPercentageRate` (string, required, nullable)
- `installmentAmount` (string, required, nullable)
- `ltvRatio` (string, required, nullable)
- `status` (enum, required, nullable)
  - Allowed values: `OFFER_AWAITED`, `OFFER_RECEIVED`, `NO_OFFER_AVAILABLE`
- `offerID` (string, required, nullable) — Use this in the Hosted URL endpoint only when it is non-null and the row is selectable.
- `amountPrincipal` (string, required, nullable)
- `interestRate` (string, required, nullable)
- `offerTerm` (string, required, nullable)
- `processingFee` (string, required, nullable) — Processing fee quoted by the lender for the offer, when available.
- `applicationFee` (string, required, nullable) — Application fee quoted by the lender for the offer, when available.
- `offerValidity` (string, required, nullable) — How long the lender offer remains valid, when available.
- `ondcTransactionID` (string, required, nullable)
- `offerSignals` (HybridOfferSignals, optional)
- `productType` (enum, optional) — Present on Business Hybrid rows to identify the source product behind the public Business application.
  - Allowed values: `BUSINESS_LOAN`, `PERSONAL_LOAN`

### HybridOfferSignals

- `offerType` (enum, required) — How firm the lender-side offer is at the polling stage.
  - Allowed values: `DEDUPE_OFFER`, `PROVISIONAL_OFFER`, `FINAL_OFFER`
- `fulfillmentJourneyType` (enum, required) — Expected borrower fulfillment path after selecting the offer.
  - Allowed values: `FULLY_DIGITAL_STP`, `COMBINED_ONLINE_OFFLINE`, `OFFLINE_ASSISTED`
- `conversionChance` (enum, required) — Business-configured conversion likelihood signal for borrower guidance.
  - Allowed values: `VERY_HIGH`, `HIGH`, `MODERATE`, `LOW`, `VERY_LOW`

## Examples

### withAccountAggregatorAndOffers

**Response**

```json
{
  "request_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "correlation_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "timestamp": "1970-01-01T00:00:00.000Z",
  "data": {
    "status": "OFFERED",
    "lenders": {
      "AA Bank": {
        "minimumLoanAmount": "50000.00",
        "maximumLoanAmount": "5000000.00",
        "offers": [
          {
            "consentHandleAvailable": true,
            "annualPercentageRate": null,
            "installmentAmount": null,
            "ltvRatio": null,
            "status": "OFFER_AWAITED",
            "offerID": null,
            "amountPrincipal": null,
            "interestRate": null,
            "offerTerm": null,
            "processingFee": null,
            "applicationFee": null,
            "offerValidity": null,
            "ondcTransactionID": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
          }
        ]
      },
      "ONDC Bank": {
        "minimumLoanAmount": "50000.00",
        "maximumLoanAmount": "5000000.00",
        "offers": [
          {
            "consentHandleAvailable": false,
            "annualPercentageRate": "5.00",
            "installmentAmount": "88460.00",
            "ltvRatio": null,
            "status": "OFFER_RECEIVED",
            "offerID": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
            "amountPrincipal": "400000",
            "interestRate": "12.00",
            "offerTerm": "5 months",
            "processingFee": "1100.00",
            "applicationFee": "1000.00",
            "offerValidity": "15 days",
            "ondcTransactionID": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
            "offerSignals": {
              "offerType": "PROVISIONAL_OFFER",
              "fulfillmentJourneyType": "COMBINED_ONLINE_OFFLINE",
              "conversionChance": "HIGH"
            }
          }
        ]
      }
    },
    "journeyID": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "polling": {
      "shouldPoll": true,
      "lastPoll": "1970-01-01T00:00:20.000Z",
      "nextPoll": "1970-01-01T00:00:30.000Z"
    },
    "account_aggregator": {
      "url": "https://credit.aarthiklabs.com/lab/account-aggregator?token=xxXxxX0x0x...",
      "expires_at": "1970-01-01T00:15:00.000Z",
      "lenders": [
        "AA Bank"
      ]
    }
  },
  "error": null
}
```

**SDK Code**

```python withAccountAggregatorAndOffers
import requests

url = "https://credit.aarthiklabs.com/api/v1/hybrid/personal-loan/borrowers/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/journey/offers"

querystring = {"journeyID":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"}

headers = {
    "x-correlation-id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "Authorization": "Bearer <token>"
}

response = requests.get(url, headers=headers, params=querystring)

print(response.json())
```

```javascript withAccountAggregatorAndOffers
const url = 'https://credit.aarthiklabs.com/api/v1/hybrid/personal-loan/borrowers/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/journey/offers?journeyID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx';
const options = {
  method: 'GET',
  headers: {
    'x-correlation-id': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
    Authorization: 'Bearer <token>'
  }
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go withAccountAggregatorAndOffers
package main

import (
	"fmt"
	"net/http"
	"io"
)

func main() {

	url := "https://credit.aarthiklabs.com/api/v1/hybrid/personal-loan/borrowers/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/journey/offers?journeyID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

	req, _ := http.NewRequest("GET", url, nil)

	req.Header.Add("x-correlation-id", "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")
	req.Header.Add("Authorization", "Bearer <token>")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby withAccountAggregatorAndOffers
require 'uri'
require 'net/http'

url = URI("https://credit.aarthiklabs.com/api/v1/hybrid/personal-loan/borrowers/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/journey/offers?journeyID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)
request["x-correlation-id"] = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
request["Authorization"] = 'Bearer <token>'

response = http.request(request)
puts response.read_body
```

```java withAccountAggregatorAndOffers
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.get("https://credit.aarthiklabs.com/api/v1/hybrid/personal-loan/borrowers/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/journey/offers?journeyID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")
  .header("x-correlation-id", "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")
  .header("Authorization", "Bearer <token>")
  .asString();
```

```php withAccountAggregatorAndOffers
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('GET', 'https://credit.aarthiklabs.com/api/v1/hybrid/personal-loan/borrowers/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/journey/offers?journeyID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', [
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'x-correlation-id' => 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
  ],
]);

echo $response->getBody();
```

```csharp withAccountAggregatorAndOffers
using RestSharp;

var client = new RestClient("https://credit.aarthiklabs.com/api/v1/hybrid/personal-loan/borrowers/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/journey/offers?journeyID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx");
var request = new RestRequest(Method.GET);
request.AddHeader("x-correlation-id", "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx");
request.AddHeader("Authorization", "Bearer <token>");
IRestResponse response = client.Execute(request);
```

```swift withAccountAggregatorAndOffers
import Foundation

let headers = [
  "x-correlation-id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "Authorization": "Bearer <token>"
]

let request = NSMutableURLRequest(url: NSURL(string: "https://credit.aarthiklabs.com/api/v1/hybrid/personal-loan/borrowers/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/journey/offers?journeyID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

### processingAccountAggregator

**Response**

```json
{
  "request_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "correlation_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "timestamp": "1970-01-01T00:00:00.000Z",
  "data": {
    "status": "OFFERED",
    "lenders": {},
    "journeyID": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "polling": {
      "shouldPoll": true,
      "lastPoll": "1970-01-01T00:00:20.000Z",
      "nextPoll": "1970-01-01T00:00:30.000Z"
    },
    "account_aggregator": {
      "url": null,
      "expires_at": null,
      "lenders": [
        "AA Bank"
      ]
    }
  },
  "error": null
}
```

**SDK Code**

```python processingAccountAggregator
import requests

url = "https://credit.aarthiklabs.com/api/v1/hybrid/personal-loan/borrowers/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/journey/offers"

querystring = {"journeyID":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"}

headers = {
    "x-correlation-id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "Authorization": "Bearer <token>"
}

response = requests.get(url, headers=headers, params=querystring)

print(response.json())
```

```javascript processingAccountAggregator
const url = 'https://credit.aarthiklabs.com/api/v1/hybrid/personal-loan/borrowers/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/journey/offers?journeyID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx';
const options = {
  method: 'GET',
  headers: {
    'x-correlation-id': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
    Authorization: 'Bearer <token>'
  }
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go processingAccountAggregator
package main

import (
	"fmt"
	"net/http"
	"io"
)

func main() {

	url := "https://credit.aarthiklabs.com/api/v1/hybrid/personal-loan/borrowers/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/journey/offers?journeyID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

	req, _ := http.NewRequest("GET", url, nil)

	req.Header.Add("x-correlation-id", "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")
	req.Header.Add("Authorization", "Bearer <token>")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby processingAccountAggregator
require 'uri'
require 'net/http'

url = URI("https://credit.aarthiklabs.com/api/v1/hybrid/personal-loan/borrowers/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/journey/offers?journeyID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)
request["x-correlation-id"] = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
request["Authorization"] = 'Bearer <token>'

response = http.request(request)
puts response.read_body
```

```java processingAccountAggregator
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.get("https://credit.aarthiklabs.com/api/v1/hybrid/personal-loan/borrowers/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/journey/offers?journeyID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")
  .header("x-correlation-id", "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")
  .header("Authorization", "Bearer <token>")
  .asString();
```

```php processingAccountAggregator
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('GET', 'https://credit.aarthiklabs.com/api/v1/hybrid/personal-loan/borrowers/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/journey/offers?journeyID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', [
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'x-correlation-id' => 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
  ],
]);

echo $response->getBody();
```

```csharp processingAccountAggregator
using RestSharp;

var client = new RestClient("https://credit.aarthiklabs.com/api/v1/hybrid/personal-loan/borrowers/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/journey/offers?journeyID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx");
var request = new RestRequest(Method.GET);
request.AddHeader("x-correlation-id", "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx");
request.AddHeader("Authorization", "Bearer <token>");
IRestResponse response = client.Execute(request);
```

```swift processingAccountAggregator
import Foundation

let headers = [
  "x-correlation-id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "Authorization": "Bearer <token>"
]

let request = NSMutableURLRequest(url: NSURL(string: "https://credit.aarthiklabs.com/api/v1/hybrid/personal-loan/borrowers/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/journey/offers?journeyID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```