Skip to navigation

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 Loan offer discovery can return both BUSINESS_LOAN and self-employed PERSONAL_LOAN offers, subject to availability for your application. Use each offer’s productType to label it correctly. Store the data.journey.id returned by Create A Journey and pass it as journeyID on both continuation calls.

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

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

{
"personal": {
"userType": "individual",
"pan": "ABCPE1234F",
"panName": "John Doe",
"dob": "1990-01-01",
"gender": "male",
"personalemail": "john@example.com",
"contactNumber": "9876543210"
},
"work": {
"employmentType": "salaried",
"income": 90000,
"incomeType": "monthly",
"companyName": "Acme Global Inc."
},
"address": {
"addressL1": "101 Sunshine Heights",
"addressL2": "Gold Coast Road",
"city": "Rajkot",
"state": "Gujarat",
"pincode": "360001"
},
"journey": {
"endUse": "medicalTreatmentAndEmergencies",
"consent": true
},
"goldInformation": {
"jewelleryWeightGrams": "52",
"purity": "22K"
}
}

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

A successful response does not mean an offer is already available. Store data.applicationID and data.journey.id. If data.operation.status is ACCEPTED, work is still pending. Continue by polling offers with the same journeyID and follow the returned schedule. Do not create a new attempt or change the retry key just because discovery is pending. OFFER_AWAITED is a waiting state; wait for an offer ID and terms before requesting a Hosted URL.

Business Loan Eligibility

Eligibility is optional and does not require Dedupe. Start the operation with POST (HTTP 202), then use GET on the same path with the returned journeyID to read progress and lender decisions. Start responses omit polling. Make the first GET after acceptance, then follow the GET response’s polling.nextPoll while polling.shouldPoll is true; do not POST again to poll. Supply at least one of Bureau, Banking or GST, or combine all three. See Eligibility Inputs for the input structure and four named examples, also available in the API Reference selector.

POST /api/v1/hybrid/business-loan/borrowers/{borrowerProviderID}/journey/eligibility?journeyID=<existing-journey-id>

Omit the query parameter to create a journey when Eligibility is the first step. Otherwise reuse the ID returned by Dedupe. Pass the returned data.journeyID to Create A Journey as ?journeyID=<same-journey-id>. Dedupe can also be used without Eligibility, and both can be skipped.

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:

{
"offerSignals": {
"offerType": "PROVISIONAL_OFFER",
"fulfillmentJourneyType": "COMBINED_ONLINE_OFFLINE",
"conversionChance": "HIGH"
}
}

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 non-Gold products, offer acceptance is controlled by Aarthik Labs configuration for the tenant, application, and lender. The configured value wins and defaults to enabled when no lender policy exists.

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 retained only for backward compatibility. Supplied values, including malformed or repeated values, are ignored. Remove it from new integrations.

Effective server policyBehavior
Enabled or not configuredAarthik Labs applies API acceptance at the established acceptance point.
DisabledThe borrower continues through Hosted offer and KFS review before acceptance.

The response always reports the effective decision in data.offer_acceptance. requested is the effective server-controlled value, not the caller’s query value. Check applied to determine whether this call applied acceptance.

  • 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 call is idempotent for the same selected offer. 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:

{
"data": {
"hosted_url": "https://credit.aarthiklabs.com/lab/handoff?handoff=...",
"expires_at": "2026-07-16T10:05:00.000Z",
"offer_acceptance": {
"requested": true,
"applied": true
},
"redirection": null,
"polling": {
"shouldPoll": false,
"lastPoll": "2026-07-16T10:00:00.000Z",
"nextPoll": null
}
}
}
  • Open the fresh signed Aarthik hosted_url immediately. The API never exposes the raw lender URL.
  • redirection.state: READY means the Hosted URL is ready to open; the lender destination may still be preparing behind its loader.
  • If the lender step is pending, the URL opens a minimal unbranded loader. The loader waits internally and automatically redirects when the canonical lender URL is ready; the integrator does not poll this third API.
  • If the journey step is complete or terminal, the URL opens the Hosted offer and journey tracker so the borrower can review status, offer details, servicing, payments, and IGM actions when available.
  • 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 hosted_url automatically forwards the borrower when an external lender step is current. 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 while waiting.

Bank mandate remains Hosted when it is an Aarthik-owned or local borrower action. A server policy that disables API acceptance retains the Hosted review behavior. If direct handoff validation fails or expires, the browser receives a minimal non-sensitive error; request a fresh hosted_url.

For Business Loans, use the same journeyID for a selected BUSINESS_LOAN or PERSONAL_LOAN offer. Supported LAMF API acceptance is limited to online single-redirection journeys; unsupported LAMF modes return HYBRID_HOSTED_STAGE_UNSUPPORTED. Gold Loan behavior is unchanged.

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

Your UI collects borrower profile Your back-end starts journey Your UI shows offer-fetch wait state Your back-end polls offers What is ready? Selectable offers Account Aggregator URL Still processing No offer Borrower completes AA consent Borrower selects offer Backend requests Hosted URL UI opens Hosted Experience

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: