Back-End Integrations

Your back-end is the trusted boundary for Hosted Experience. It authenticates with Aarthik Labs, decides which borrower can start a journey, passes pre-fill data, and returns only embedURL to the browser or mobile app.

Do not call Aarthik Labs directly from your front-end.

Backend Responsibilities

Your back-end should:

  • store PLATFORM_API_KEY in server-side configuration only
  • validate the authenticated borrower in your own app
  • send a stable borrowerProviderID
  • send an explicit journeyType
  • pass only pre-fill data that your app is allowed to share
  • return only { "embedURL": "..." } to the front-end
  • avoid caching session-creation responses

Most integrations create a small back-end endpoint such as:

POST /api/credit/hosted-session

Your front-end calls this endpoint. This endpoint calls Aarthik Labs.

Next.js App Router Example

Create a route such as app/api/credit/hosted-session/route.ts.

1import { NextResponse } from "next/server";
2
3type JourneyType = "PERSONAL_LOAN" | "BUSINESS_LOAN" | "GOLD_LOAN";
4
5type HostedSessionRequest = {
6 borrowerProviderID?: string;
7 journeyType?: JourneyType;
8 profile?: {
9 contactNumber?: string;
10 pan?: string;
11 panName?: string;
12 dob?: string;
13 gender?: "male" | "female" | "transgender";
14 personalemail?: string;
15 };
16 workProfile?: {
17 employmentType?: "salaried" | "selfEmployed";
18 officialemail?: string;
19 income?: string | number;
20 incomeType?: "monthly" | "annual";
21 companyName?: string;
22 udyamNumber?: string;
23 };
24 address?: {
25 addressL1?: string;
26 addressL2?: string;
27 city?: string;
28 state?: string;
29 pincode?: string;
30 };
31 journey?: {
32 endUse?: string;
33 creditReportConsent?: boolean;
34 };
35 goldLoan?: {
36 userType?: "individual" | "non-individual";
37 constitution?: string | null;
38 jewelleryWeightGrams?: string | number;
39 purity?: "24K" | "22K" | "21K" | "18K" | "14K" | "9K";
40 endUse?:
41 | "marriage"
42 | "familyFunctions"
43 | "medicalTreatmentAndEmergencies"
44 | "travelEducationExpenses"
45 | "businessExpansion"
46 | "agricultureAndFarmRelatedNeeds"
47 | "purchaseOfEquipment"
48 | "other";
49 aaID?: string;
50 requestedAmount?: string | number;
51 requestedTenureMonths?: number;
52 };
53};
54
55type HostedSessionResponse = {
56 embedURL: string;
57};
58
59export async function POST(request: Request) {
60 const payload = (await request.json().catch(() => null)) as
61 | HostedSessionRequest
62 | null;
63
64 const borrowerProviderID = payload?.borrowerProviderID?.trim();
65 const journeyType = payload?.journeyType;
66
67 if (!borrowerProviderID) {
68 return NextResponse.json(
69 { error: "Missing borrowerProviderID." },
70 { status: 400 },
71 );
72 }
73
74 if (journeyType !== "PERSONAL_LOAN" && journeyType !== "GOLD_LOAN") {
75 return NextResponse.json(
76 { error: "journeyType must be PERSONAL_LOAN or GOLD_LOAN." },
77 { status: 400 },
78 );
79 }
80
81 const platformBaseURL = process.env.PLATFORM_BASE_URL;
82 const platformAPIKey = process.env.PLATFORM_API_KEY;
83
84 if (!platformBaseURL || !platformAPIKey) {
85 return NextResponse.json(
86 { error: "Hosted Experience configuration is missing." },
87 { status: 500 },
88 );
89 }
90
91 const response = await fetch(`${platformBaseURL}/api/lab/sessions`, {
92 method: "POST",
93 headers: {
94 Authorization: `Bearer ${platformAPIKey}`,
95 "Content-Type": "application/json",
96 },
97 body: JSON.stringify({
98 borrowerProviderID,
99 journeyType,
100 profile: payload?.profile,
101 workProfile: payload?.workProfile,
102 address: payload?.address,
103 journey: payload?.journey,
104 goldLoan: payload?.goldLoan,
105 }),
106 cache: "no-store",
107 });
108
109 if (!response.ok) {
110 const details = await response.json().catch(() => ({}));
111 return NextResponse.json(
112 { error: "Failed to create Hosted Experience URL.", details },
113 { status: response.status },
114 );
115 }
116
117 const data = (await response.json()) as HostedSessionResponse;
118
119 return NextResponse.json(
120 { embedURL: data.embedURL },
121 {
122 headers: {
123 "Cache-Control": "no-store",
124 },
125 },
126 );
127}

Product Availability Endpoint

If your app shows product-specific CTAs, call GET /api/lab/features from your back-end and use the returned catalogue to decide what to show.

1type HostedLenderProductCatalogue = {
2 products: Array<{
3 key: "personalLoan" | "businessLoan" | "goldLoan";
4 type: "PERSONAL_LOAN" | "BUSINESS_LOAN" | "GOLD_LOAN";
5 name: string;
6 available: boolean;
7 unavailableReason?: string | null;
8 lenders: Array<{
9 id: string;
10 name: string;
11 available: boolean;
12 checks: Array<{
13 key:
14 | "CREDIT_REPORT"
15 | "BANK_ACCOUNT_STATEMENT"
16 | "GST_INFORMATION"
17 | "UDYAM_INFORMATION"
18 | "GOLD_INFORMATION";
19 required: boolean;
20 }>;
21 informationNeeded: {
22 lenderSpecificRequirementsKnown: boolean;
23 required: Array<{
24 key: string;
25 sendIn: string;
26 }>;
27 optional: Array<{
28 key: string;
29 sendIn: string;
30 }>;
31 conditional: Array<{
32 key: string;
33 sendIn: string;
34 }>;
35 };
36 }>;
37 }>;
38};
39
40export async function readLenderProductCatalogue() {
41 const platformBaseURL = process.env.PLATFORM_BASE_URL;
42 const platformAPIKey = process.env.PLATFORM_API_KEY;
43
44 const response = await fetch(`${platformBaseURL}/api/lab/features`, {
45 method: "GET",
46 headers: {
47 Authorization: `Bearer ${platformAPIKey}`,
48 },
49 cache: "no-store",
50 });
51
52 if (!response.ok) {
53 throw new Error("Failed to read lender product catalogue.");
54 }
55
56 return response.json() as Promise<HostedLenderProductCatalogue>;
57}

Typical UI checks:

1const catalogue = await readLenderProductCatalogue();
2const personalLoanAvailable = catalogue.products.some(
3 (product) => product.key === "personalLoan" && product.available,
4);
5const lenderFields =
6 catalogue.products
7 .find((product) => product.key === "personalLoan")
8 ?.lenders.at(0)?.informationNeeded.required ?? [];

Error Handling

Handle platform responses as follows:

StatusMeaningRecommended action
400Request shape or required data is invalid.Fix the payload before retrying.
401API key is missing, invalid, or from the wrong environment.Check server-side configuration and key rotation.
404Tenant, application, borrower, or requested journey scope could not be resolved.Verify API key scope and product availability.
500Unexpected platform error.Retry later and share request context with Aarthik Labs support if it persists.

Important Rules

  • Send profile.contactNumber for all journeys. It is a required field.
  • Send journeyType explicitly so product selection is predictable.
  • Create a fresh embedURL when the borrower returns later.
  • Do not persist or expose platform API keys in front-end code, mobile apps, logs, or analytics events.