Integrations Guide

Hybrid Experience is a back-end-led integration. Your front-end talks to your back-end. Your back-end talks to Aarthik Labs with a server-side API key.

Hybrid product flows use the same three-call pattern. The product is selected by the URL path:

ProductPath prefix
Personal Loan/api/v1/hybrid/personal-loan
Gold Loan/api/v1/hybrid/gold-loan
Loan Against Mutual Funds/api/v1/hybrid/loan-against-mutual-funds
Business Loan/api/v1/hybrid/business-loan

Business Hybrid is one composite public application. Start returns a BUSINESS_LOAN public root ID, while Offers can contain both BUSINESS_LOAN and self-employed PERSONAL_LOAN rows. Use each row’s productType to label the product. Never expect or persist a companion journey ID: pass the public root ID as journeyID on both continuation calls.

GET /api/v1/hybrid/business-loan/borrowers/{borrowerProviderID}/journey/offers?journeyID={publicRootJourneyID}
GET /api/v1/hybrid/business-loan/borrowers/{borrowerProviderID}/journey/offers/{offerID}/hosted?journeyID={publicRootJourneyID}

The production flow uses three back-end calls:

  1. Start a new application attempt for the borrower.
  2. Poll lender-grouped offers for that journey and Account Aggregator readiness when the selected source supports it.
  3. Request a Hosted Experience URL for that journey after the borrower selects an offer.

Environment Setup

Set these on the back-end that calls Aarthik Labs. Do not expose the API key to browsers or mobile apps.

$PLATFORM_BASE_URL="https://preprod.credit.aarthiklabs.com"
$PLATFORM_API_KEY="sk_test_xxx"

For production, use the production base URL and live API key provided for your application.

1. Start Journey

Your back-end starts the borrower’s Hybrid journey.

POST /api/v1/hybrid/personal-loan/borrowers/{borrowerProviderID}/journey
POST /api/v1/hybrid/gold-loan/borrowers/{borrowerProviderID}/journey
POST /api/v1/hybrid/loan-against-mutual-funds/borrowers/{borrowerProviderID}/journey
POST /api/v1/hybrid/business-loan/borrowers/{borrowerProviderID}/journey

Use a stable borrowerProviderID for the same borrower across sessions and application attempts. This keeps borrower history, resume, and post-disbursal tracking tied to one borrower record.

Prefer sending an Idempotency-Key header on Start:

  • Use a fresh Idempotency-Key for each new application attempt.
  • Reuse the same Idempotency-Key only when retrying the same Start request after a timeout or temporary failure.
  • If you omit Idempotency-Key, the platform treats the call as a new non-idempotent application attempt by generating an internal attempt key. This preserves fresh-journey creation for compatibility, but client retries can create duplicates.
  • Do not rotate borrowerProviderID to create a new application attempt.

Send borrower profile, work, address, and journey information according to the API Reference. Personal Loan can also accept banking information and optional buyer-supplied bureau data. Loan Against Mutual Funds follows the Personal Loan-style shape and can additionally accept optional free-form mfc data. Business Loan follows the Personal Loan-style shape and adds business-specific first-form fields in businessLoan. Gold Loan does not accept bureau, banking information, or loanPreferences in this start call. For Gold Loan, send pledged-gold fields as top-level goldInformation and use journey.consent.

In the API Reference, Loan Against Mutual Funds examples are split into Credit Line and Term Loan tabs. Both tabs use the same /loan-against-mutual-funds endpoints; the start call only changes the optional loanPreferences.facilitytype preference, while the offer and handoff responses show the facility-specific fields.

The example below shows the Gold Loan shape. Use the API Reference for the product-specific Personal Loan, Loan Against Mutual Funds, and Business Loan examples.

1{
2 "personal": {
3 "userType": "individual",
4 "pan": "ABCPE1234F",
5 "panName": "John Doe",
6 "dob": "1990-01-01",
7 "gender": "male",
8 "personalemail": "john@example.com",
9 "contactNumber": "9876543210"
10 },
11 "work": {
12 "employmentType": "salaried",
13 "income": 90000,
14 "incomeType": "monthly",
15 "companyName": "Acme Global Inc."
16 },
17 "address": {
18 "addressL1": "101 Sunshine Heights",
19 "addressL2": "Gold Coast Road",
20 "city": "Rajkot",
21 "state": "Gujarat",
22 "pincode": "360001"
23 },
24 "journey": {
25 "endUse": "medicalTreatmentAndEmergencies",
26 "consent": true
27 },
28 "goldInformation": {
29 "jewelleryWeightGrams": "52",
30 "purity": "22K"
31 }
32}

The platform stores the pre-fill data and starts the offer-fetch pipeline.

After this call succeeds, store data.journey.id. Your product should show an active wait state and start polling offers from your back-end with that journey ID.

2. Poll Offers And Account Aggregator Readiness

Your back-end reads the current offer state while the borrower stays in your UI.

GET /api/v1/hybrid/personal-loan/borrowers/{borrowerProviderID}/journey/offers
GET /api/v1/hybrid/gold-loan/borrowers/{borrowerProviderID}/journey/offers
GET /api/v1/hybrid/loan-against-mutual-funds/borrowers/{borrowerProviderID}/journey/offers
GET /api/v1/hybrid/business-loan/borrowers/{borrowerProviderID}/journey/offers
GET /api/v1/hybrid/personal-loan/borrowers/{borrowerProviderID}/journey/offers?journeyID={data.journey.id}
GET /api/v1/hybrid/gold-loan/borrowers/{borrowerProviderID}/journey/offers?journeyID={data.journey.id}

Pass the data.journey.id value returned by Start as journeyID. The alias journey_id is also accepted. If you omit the journey ID, the borrower-only fallback is legacy behavior and may return a 409 ambiguity error when the same borrower has more than one active Hybrid application attempt.

This response can contain:

  • current journey status
  • a polling object with the next legal poll time
  • lender-grouped offer state
  • selectable offers with OFFER_RECEIVED
  • processingFee, applicationFee, and offerValidity on Personal Loan, Gold Loan, and Business Loan offer rows when available
  • optional offerSignals on offer rows, when configured for that lender
  • branch locations for Gold Loan lenders, when returned by the lender
  • lenders waiting for Account Aggregator consent, when applicable
  • an Account Aggregator URL when consent is ready, when applicable

Gold Loan Hybrid does not include Account Aggregator right now. Gold Loan offer polling uses the same data.polling.shouldPoll, data.polling.lastPoll, and data.polling.nextPoll cadence, but the response omits data.account_aggregator and can include branches inside each lender group.

Business Loan uses the Personal Loan-style lender-grouped offer shape. Loan Against Mutual Funds uses a LAMF-specific lender-grouped shape: lender groups do not expose minimumLoanAmount or maximumLoanAmount, and each selectable offer is either a Credit Line or a Term Loan.

LAMF offer typeKey fields
Credit LineproductType: "LAMF", facilitytype: "CREDIT_LINE", sanctionedLimit, renewalFrequency, pledge requirements
Term LoanproductType: "LAMF", facilitytype: "TERM_LOAN", amountPrincipal, installmentAmount, pledge requirements

LAMF offers do not expose ltvRatio. LAMF Credit Line and Term Loan offer signals are documented as FINAL_OFFER, FULLY_DIGITAL_STP, and VERY_HIGH.

Your app should keep polling until one of these outcomes is available:

OutcomeWhat your app should do
Offers are availableShow lender-grouped offers and let the borrower choose one.
Account Aggregator is readyShow an AA consent action and open the returned URL when the borrower continues.
Account Aggregator is not ready yetKeep the borrower in a waiting state and poll again at data.polling.nextPoll.
No offers are availableShow a clear no-offer state.

The offers endpoint enforces a server-owned polling cadence. Calls before data.polling.nextPoll can return 429 with the same polling object and Retry-After / X-Aarthik-Next-Poll-At headers. Treat that as a normal timing response and retry at the returned time.

Read Offer Polling & Rate Limits for the full cadence, Account Aggregator timing, and rate-limit behavior.

Offer Signals

Offer rows can include an optional offerSignals object:

1{
2 "offerSignals": {
3 "offerType": "PROVISIONAL_OFFER",
4 "fulfillmentJourneyType": "COMBINED_ONLINE_OFFLINE",
5 "conversionChance": "HIGH"
6 }
7}

Use these values as display hints for the borrower. They do not change offer ordering, eligibility, lender availability, or the Hosted handoff contract.

FieldValues
offerTypeDEDUPE_OFFER, PROVISIONAL_OFFER, FINAL_OFFER
fulfillmentJourneyTypeFULLY_DIGITAL_STP, COMBINED_ONLINE_OFFLINE, OFFLINE_ASSISTED
conversionChanceVERY_HIGH, HIGH, MODERATE, LOW, VERY_LOW

3. Request Hosted URL

After the borrower selects an offer in your UI, your back-end requests the URL that continues that offer. For Personal Loans, the third API can also record acceptance already captured in your application.

GET /api/v1/hybrid/personal-loan/borrowers/{borrowerProviderID}/journey/offers/{offerID}/hosted
GET /api/v1/hybrid/gold-loan/borrowers/{borrowerProviderID}/journey/offers/{offerID}/branches/{branchID}/hosted
GET /api/v1/hybrid/loan-against-mutual-funds/borrowers/{borrowerProviderID}/journey/offers/{offerID}/hosted
GET /api/v1/hybrid/business-loan/borrowers/{borrowerProviderID}/journey/offers/{offerID}/hosted
GET /api/v1/hybrid/personal-loan/borrowers/{borrowerProviderID}/journey/offers/{offerID}/hosted?journeyID={data.journey.id}
GET /api/v1/hybrid/gold-loan/borrowers/{borrowerProviderID}/journey/offers/{offerID}/branches/{branchID}/hosted?journeyID={data.journey.id}
GET /api/v1/hybrid/personal-loan/borrowers/{borrowerProviderID}/journey/offers/{offerID}/hosted?journeyID={data.journey.id}&isOfferAccepted=true

isOfferAccepted is optional and accepts only the exact lowercase values true and false:

ValueBehavior
OmittedReturns the standard Hosted offer and KFS review flow.
falseSame as omission. It does not undo an offer accepted earlier.
trueRequests acceptance for the selected offer after your application has captured the borrower’s explicit consent.
Any other supplied valueReturns HTTP 400 with INVALID_IS_OFFER_ACCEPTED before acceptance or Hosted-link issuance.

Send true only after your application has shown the offer and required KFS information and captured the borrower’s explicit decision. A true request always returns data.offer_acceptance. Check data.offer_acceptance.applied rather than assuming the request accepted the offer:

  • When applied is true, the API has accepted the selected offer and may prepare the next lender step before issuing a URL.
  • When applied is false, open the returned hosted_url; the borrower completes the standard offer and KFS review in Hosted Experience.

The true call is idempotent for the same selected offer, so it is safe to retry and poll. A different offer after the selection is locked returns HTTP 409 and no Hosted URL.

When data.offer_acceptance.applied is true, inspect data.redirection and data.polling:

1{
2 "data": {
3 "hosted_url": null,
4 "expires_at": null,
5 "offer_acceptance": {
6 "requested": true,
7 "applied": true
8 },
9 "redirection": {
10 "type": "MULTIPLE",
11 "stage": "KYC",
12 "state": "PENDING"
13 },
14 "polling": {
15 "shouldPoll": true,
16 "lastPoll": "2026-07-16T10:00:00.000Z",
17 "nextPoll": "2026-07-16T10:00:05.000Z"
18 }
19 }
20}
  • READY: open the fresh signed Aarthik hosted_url immediately. The API never exposes the raw lender URL.
  • PENDING: no URL is issued. Poll again at nextPoll, initially five seconds after lastPoll.
  • TERMINAL, or redirection: null: no borrower action remains; shouldPoll is false.
  • Multiple-redirection journeys always use the first incomplete stage in this order: KYC, bank mandate when applicable, e-mandate, then loan agreement.

For Personal Loan responses where acceptance was applied, opening a READY hosted_url automatically forwards the borrower to the lender’s current step. A single-redirection journey goes to the lender destination. A multiple-redirection journey goes to the current external stage, such as KYC, e-mandate, or loan agreement/e-sign. The borrower does not need to click Verify or interact with an Aarthik Labs screen. A brief blank loading page may appear while the short-lived URL is validated.

Bank mandate remains Hosted when it is an Aarthik-owned or local borrower action. Omitted or false acceptance calls also retain the existing Hosted UI behavior. If direct handoff validation fails, the browser receives a minimal non-sensitive error instead of falling back to the journey tracker; request a fresh hosted_url after correcting or refreshing the stage.

Business Hybrid accepts either the public Business offer or a hidden Personal companion offer on its real source journey, while journey.id and target_journey_id remain the public Business root. Supported LAMF opt-in acceptance is limited to online single-redirection journeys; unsupported LAMF modes return HYBRID_HOSTED_STAGE_UNSUPPORTED. Gold Loan behavior is unchanged: its existing branch-confirmation contract is not governed by the new omitted/false semantics.

Every returned hosted_url is short-lived and should be opened immediately in the borrower browser, webview, or app shell.

Hosted Experience then takes over the selected-offer journey, including tracking, KFS, KYC, mandates, agreements, lender redirects, post-disbursal actions, and servicing.

End-To-End Flow

Implementation Notes

  • Keep PLATFORM_API_KEY server-side.
  • Use your own back-end endpoint as the front-end boundary.
  • Treat borrowerProviderID as stable application-owned borrower identity.
  • Use a fresh Idempotency-Key for each new Start attempt; reuse the same key only to retry that exact Start request.
  • Omitting Idempotency-Key is allowed for compatibility and creates a fresh non-idempotent attempt with a server-generated internal key. Add a client-supplied key when you need safe retries.
  • Do not reuse expired Account Aggregator or Hosted URLs.
  • Follow data.polling.nextPoll to avoid unnecessary polling load and 429 responses.
  • Store data.journey.id from Start and pass it as journeyID on Offers and Hosted calls. Store data.journeyID from Offers and data.journey.id from Hosted responses for reconciliation; these values match data.journey.id in lifecycle web-hooks.
  • Store offer identifiers when your product needs offer-level support, analytics, or CRM reconciliation.
  • For Gold Loan, read branch locations from the offers polling response, let the borrower select a branch, and pass that branch ID in the Hosted handoff path. The Hosted handoff response returns the selected lender, selected offer, relationship manager from fulfillment-agent data, and fresh Hosted URL.

Mobile Applications

If your Hybrid journey runs inside a mobile app, treat the Hosted handoff as a hosted mobile integration.

Your app should be ready to:

  • open Account Aggregator and Hosted URLs in an approved browser or app-controlled surface
  • keep the Aarthik Labs API key on your back-end
  • register the mobile bridge before loading Hosted screens
  • support lender-owned external steps and return behavior
  • provide camera, file, location, and related permissions when a journey step requires them
  • handle Hosted exit events cleanly

Read the Mobile Applications docs for the bridge and permission requirements: