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" | "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 bureauConsent?: 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 bureauConsent?: boolean;
50 aaID?: string;
51 requestedAmount?: string | number;
52 requestedTenureMonths?: number;
53 };
54};
55
56type HostedSessionResponse = {
57 embedURL: string;
58};
59
60export async function POST(request: Request) {
61 const payload = (await request.json().catch(() => null)) as
62 | HostedSessionRequest
63 | null;
64
65 const borrowerProviderID = payload?.borrowerProviderID?.trim();
66 const journeyType = payload?.journeyType;
67
68 if (!borrowerProviderID) {
69 return NextResponse.json(
70 { error: "Missing borrowerProviderID." },
71 { status: 400 },
72 );
73 }
74
75 if (journeyType !== "PERSONAL_LOAN" && journeyType !== "GOLD_LOAN") {
76 return NextResponse.json(
77 { error: "journeyType must be PERSONAL_LOAN or GOLD_LOAN." },
78 { status: 400 },
79 );
80 }
81
82 const platformBaseURL = process.env.PLATFORM_BASE_URL;
83 const platformAPIKey = process.env.PLATFORM_API_KEY;
84
85 if (!platformBaseURL || !platformAPIKey) {
86 return NextResponse.json(
87 { error: "Hosted Experience configuration is missing." },
88 { status: 500 },
89 );
90 }
91
92 const response = await fetch(`${platformBaseURL}/api/lab/sessions`, {
93 method: "POST",
94 headers: {
95 Authorization: `Bearer ${platformAPIKey}`,
96 "Content-Type": "application/json",
97 },
98 body: JSON.stringify({
99 borrowerProviderID,
100 journeyType,
101 profile: payload?.profile,
102 workProfile: payload?.workProfile,
103 address: payload?.address,
104 journey: payload?.journey,
105 goldLoan: payload?.goldLoan,
106 }),
107 cache: "no-store",
108 });
109
110 if (!response.ok) {
111 const details = await response.json().catch(() => ({}));
112 return NextResponse.json(
113 { error: "Failed to create Hosted Experience URL.", details },
114 { status: response.status },
115 );
116 }
117
118 const data = (await response.json()) as HostedSessionResponse;
119
120 return NextResponse.json(
121 { embedURL: data.embedURL },
122 {
123 headers: {
124 "Cache-Control": "no-store",
125 },
126 },
127 );
128}

Product Availability Endpoint

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

1export async function readAvailableCreditProducts() {
2 const platformBaseURL = process.env.PLATFORM_BASE_URL;
3 const platformAPIKey = process.env.PLATFORM_API_KEY;
4
5 const response = await fetch(`${platformBaseURL}/api/lab/features`, {
6 method: "GET",
7 headers: {
8 Authorization: `Bearer ${platformAPIKey}`,
9 },
10 cache: "no-store",
11 });
12
13 if (!response.ok) {
14 throw new Error("Failed to read available credit products.");
15 }
16
17 return response.json() as Promise<{
18 tenantID: string;
19 applicationID: string;
20 personalLoanEnabled: boolean;
21 businessLoanEnabled: boolean;
22 goldLoanEnabled: boolean;
23 }>;
24}

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.