1. Overview
Artham's investment marketplace runs inside a webview hosted in your app. Your app renders a row of scheme cards from data Artham serves; when the user taps one, your app asks Artham for a URL and opens it in a webview. Everything after that point — scheme detail, onboarding, consent, mandate and investing — happens inside Artham's web application. Your app hosts the frame and nothing else.
How It Works
- Sign each request — every call carries an API key and an HMAC signature. There is no login step and no token to manage (Section 2).
- Fetch the schemes — one call returns every scheme available to your brokerage, with the summary fields your cards need (Section 4).
- Render cards in your app — your UI, your styling. Artham supplies the data, not the layout.
- Hand off on tap — the user taps a card, or your Artham header entry point. Your app calls Artham for a client-specific, pre-signed URL and opens it in a webview (Section 5).
- The journey continues in the webview — Artham handles the rest and signals back when the user exits (Section 6).
API Summary
| # | Method | Endpoint | Purpose | |
| 1 | GET | /api/v1/partner/schemes | All schemes available to you, with card summary fields | Required |
| 2 | POST | /api/v1/partner/webview/link | Pre-signed, client-specific webview URL | Required |
Both endpoints are hosted by Artham. You do not build or host anything for this integration — you are the caller for every request in this document, and the webview itself is served by us.
Base URLs
Production: https://api.artham.co
Sandbox: https://distributor-api.artham.co
2. Authentication
Every request carries two headers: an API key that identifies your brokerage, and an HMAC signature that proves the request is yours and has not been altered. There is no login call, no token and no session to refresh.
| Header | Description | Example |
X-Api-Key | Static API key identifying your brokerage. | artham_live_k8Fj2mNp... |
X-Signature | HMAC-SHA256 of the request, computed with your Shared Secret. Proves the request is yours and untampered. | a1b2c3d4... (64 hex chars) |
Signature Computation
message = "{HTTP_METHOD}\n{path}\n{body}"
signature = HMAC-SHA256(key: SHARED_SECRET, message: message)
→ output as lowercase hex string
| Component | Description | Example |
HTTP_METHOD | Uppercase HTTP method | GET / POST |
path | Request path — no host, no query string | /api/v1/partner/schemes |
body | Raw JSON request body, byte for byte as sent. Empty string "" for GET. | {"clientCode":"PL889900"} |
Sign the exact bytes you send. On API 2 the body is part of the message, so the JSON you sign and the JSON you transmit must be identical — same key order, same spacing, same encoding. Serialising once into a string, signing that string and sending that same string is the only reliable approach; re-serialising the object for the request will eventually produce a different byte sequence and a 401.
Sign the path only. Not the full https://… URL, and not the query string. This is the most common cause of a 401 on a first integration.
Worked Examples
Both examples use the demo secret below, so you can verify your implementation before your credentials arrive — the same inputs must produce the same digests.
secret = "artham_demo_secret_9f2b7c41e8d3"
# ─── API 1 — GET, no body ───────────────────────────────────
message = "GET\n/api/v1/partner/schemes\n"
signature = 40f682d026b436293288648b8553927c398689f336b65f23136a081fe491c61d
# ─── API 2 — POST, body included ────────────────────────────
body = {"clientCode":"PL889900","schemeCode":"ARTHAM-EQ-001"}
message = "POST\n/api/v1/partner/webview/link\n" + body
signature = 065d4730e9fe6ed227f4902869d0415c2851b10cef40252339eb0fe9921a9db1
The API 1 call, against Sandbox:
curl -X GET "https://distributor-api.artham.co/api/v1/partner/schemes" \
-H "X-Api-Key: <your API key>" \
-H "X-Signature: <64-char lowercase hex>"
Credential Handling
The secret belongs on your server, never in the app. Both API calls must be made from your backend. A secret shipped inside a mobile binary can be extracted, and it would let anyone mint webview links for your clients.
Authentication Errors
| HTTP | error.code | When | What to do |
401 | AUTH_REQUIRED | X-Api-Key or X-Signature missing | Send both headers |
401 | AUTH_TOKEN_INVALID | Unknown API key, or the signature does not match the message we recomputed | Check you signed the path only, and — on API 2 — the exact body bytes |
A 401 will not fix itself on a retry. Nothing about the signature is time-dependent, so a rejected request will be rejected again. Retry with backoff only on 5xx.
3. Error Handling
Every endpoint in this document answers with the same envelope.
Success
{
"success": true,
"data": { ... },
"error": null
}
Error
{
"success": false,
"data": null,
"error": {
"code": "CLIENT_NOT_FOUND",
"message": "No client found with code PL889900."
}
}
HTTP Status Codes
| Status | Meaning |
200 | Success |
400 | Invalid or missing request fields |
401 | Missing or invalid key / signature — see Section 2 |
404 | Referenced scheme or client does not exist |
422 | Business rule violation (e.g. scheme not available to your brokerage) |
500 | Unexpected error on Artham's side — retry with backoff |
Branch on the HTTP status and error.code, not on the message. The error.message text is written for humans reading logs and may change.
4. API 1 — Scheme List Required
Returns every scheme your brokerage is permitted to distribute, with the summary fields needed to render cards. Call it when your discovery screen loads, or cache it and refresh a few times a day.
Endpoint & Method
| Item | Value |
| Method | GET |
| Path | /api/v1/partner/schemes |
| Authentication | X-Api-Key + X-Signature — see Section 2 |
| Query parameters | None. The list is scoped to your brokerage by your API key. |
| Pagination | None. Scheme counts are in the tens, so the full set is returned in one response. |
Response — 200 OK
{
"success": true,
"error": null,
"data": {
"count": 2,
"returnsAsOf": "2026-08-31",
"schemes": [
{
"schemeCode": "ARTHAM-EQ-001",
"schemeName": "Quality Compounders",
"advisorCode": "MRC",
"advisorName": "Marcellus Investment Managers",
"logoUrl": "https://artham-assets.s3.eu-north-1.amazonaws.com/advisors/mrc.png",
"category": "Large Cap",
"riskLevel": "Moderate",
"shortDescription": "Twelve clean-accounting compounders, held through cycles.",
"benchmark": "NIFTY 50 TRI",
"minInvestment": 500000,
"feePercent": 2.5,
"aum": "1284500000.00",
"inceptionDate": "2021-04-01",
"constituentCount": 12,
"returns": {
"1m": "1.8400",
"6m": "9.2100",
"1y": "18.4200",
"3y": "21.0500",
"5y": null,
"sinceInception": "19.7700"
},
"navSeries": [100.0, 102.4, 101.8, 106.2, 109.7, 108.3,
112.9, 116.4, 115.1, 119.8, 123.5, 126.1]
}
]
}
}
Scheme Fields
| Key | Type | Description |
schemeCode | string | The identifier. Pass it back on API 2 to deep-link a card. Stable for the life of the scheme. |
schemeName | string | Display name — the card title |
advisorCode | string | Short code of the SEBI-registered advisor managing the scheme |
advisorName | string | Advisor's display name — the card subtitle |
logoUrl | string or null | Advisor logo, HTTPS. null when none is set — fall back to initials. |
category | string | Free-text grouping, e.g. "Large Cap", "Momentum". Use it for filter chips; do not hard-code the set. |
riskLevel | string | "Low", "Moderate" or "High" |
shortDescription | string | One-line thesis, ~120 characters. Written to fit a card. |
benchmark | string | Benchmark index name |
minInvestment | integer | Minimum first cheque, whole rupees |
feePercent | number | Annual advisory fee, percent |
aum | string | Assets under advice in the scheme, decimal string with 2 places |
inceptionDate | string | YYYY-MM-DD |
constituentCount | integer | Number of stocks currently in the basket |
returns | object | Trailing returns, percent, as decimal strings with 4 places. Keys: 1m, 3m, 6m, 1y, 2y, 3y, 5y, sinceInception. Any key can be null when the scheme is younger than that period. |
navSeries | array | ~12 monthly NAV points, oldest first, rebased to 100 — enough for a card sparkline. Empty array for a scheme with less than a month of history. |
Every return can be null, including the headline one. A scheme launched eight months ago has no 1y figure, and rendering null as 0% would misstate performance. Show a dash and pick the longest period that is present.
Returns are past performance and must be labelled as such. Whatever your card design, the period and the as-of date have to be visible next to any percentage — returnsAsOf is provided for exactly this.
Scope
| Rule | Detail |
| Your advisors only | The list is limited to advisors mapped to your brokerage on Artham. Adding an advisor is a configuration change on our side — tell us and it appears on the next call. |
| Live schemes only | Schemes that are closed to new subscription are omitted. A scheme disappearing from the list means stop showing its card. |
| Refresh | Returns update once daily after the overnight NAV run. Caching for a few hours is fine; caching for days will show stale performance. |
5. API 2 — Webview Link Required
Call this the moment the user taps a card or your Artham entry point, and open the returned URL in a webview. The URL is pre-signed and specific to one client — it carries the session, so the user is never asked to sign in to Artham.
Endpoint & Method
| Item | Value |
| Method | POST |
| Path | /api/v1/partner/webview/link |
| Authentication | X-Api-Key + X-Signature — see Section 2 |
| Called from | Your backend, not the app — see the warning in Section 2 |
Request Body
{
"clientCode": "PL889900",
"schemeCode": "ARTHAM-EQ-001"
}
Request Fields
| Key | Required | Description |
clientCode | Yes | Your client / UCC code — the identifier this client is known by in your systems. The returned link is bound to it. |
schemeCode | No | Present → the link opens that scheme's page (a card was tapped). Absent → the link opens the discovery page (your Artham header was tapped). Must be a schemeCode from API 1. |
Two keys, and no client identity in the payload. The request carries no name, PAN, mobile or email — Artham resolves the client from clientCode against the details it already holds for your brokerage. A code Artham does not recognise is rejected rather than created, so a client must exist on our side before their first webview link.
Response — 200 OK
{
"success": true,
"error": null,
"data": {
"url": "https://invest.artham.co/discover/quality-compounders?t=eyJhbGciOi...",
"target": "SCHEME",
"expiresAt": "2026-09-01T10:35:00+05:30",
"ttlSeconds": 300
}
}
Response Fields
| Field | Type | Description |
url | string | Open this in a webview, unmodified. Treat it as opaque. |
target | string | "SCHEME" or "DISCOVERY" — echoes which page the link resolves to |
expiresAt | string | ISO 8601 with IST offset |
ttlSeconds | integer | Seconds until expiry (300 = 5 minutes) |
Request the link at the moment of the tap, and open it immediately. The token in the URL is short-lived and single-use: it is consumed when the webview loads. Pre-fetching links to have them ready, or reusing one across two launches, produces an expired-link screen.
Never log, forward or display the URL. It authenticates as that client — anyone holding it within the TTL is that client. It should travel from your backend to the webview and nowhere else.
Do not modify the URL. Appending, reordering or re-encoding query parameters invalidates the signature. Pass it through byte for byte.
Error Responses
| HTTP | error.code | When |
400 | INVALID_REQUEST | clientCode missing or empty |
404 | CLIENT_NOT_FOUND | No client with that clientCode is mapped to your brokerage on Artham |
404 | SCHEME_NOT_FOUND | schemeCode does not exist |
422 | SCHEME_NOT_AVAILABLE | The scheme exists but is not distributable by your brokerage |
6. Inside the Webview
Once the URL is open, the journey is Artham's: scheme detail, risk profiling, KYC, advisory consent, mandate setup and order placement. Your app does not need to implement, mirror or track any of these steps. What it does need is a webview configured to let them work.
Webview Requirements
| Requirement | Why |
| JavaScript enabled | The application will not render without it |
| DOM storage and cookies enabled | Holds the session across the journey's steps |
| Third-party redirects allowed | eSign and payment steps hand off to external providers and return. A webview restricted to artham.co breaks mandate setup. |
| Downloads permitted | The user can save agreements and reports as PDFs |
Exiting
Artham signals completion or a user-initiated exit by posting a message to the webview host:
{ "source": "artham", "event": "EXIT", "reason": "COMPLETED" | "USER_CLOSED" }
Close the webview when you receive it. reason is informational — both cases mean the same thing for your app. Also give the user your own way out, such as a close button in your chrome, so a network failure inside the webview cannot trap them.
No state flows back to your app on exit. Whether the user invested is not carried in the exit event — it reports only that the webview is finished. Investment outcomes reach you through your existing post-trade reporting with Artham, not through this integration.
7. Sandbox & Testing
Integration Steps
- Artham shares credentials — an API Key and Shared Secret for Sandbox, sent over a secure channel.
- You wire up the two calls — scheme list and webview link, both signed, both from your backend.
- You build the cards — using the API 1 fields, in your own design.
- End-to-end test — you launch the webview for a test client against Sandbox, and we walk one full journey together, from card tap through to a placed order.
- Go live — we issue production credentials. No code change beyond the base URL and the credentials.
Test Checklist
Authentication
| Test Case | Expected Result |
| Self-test both digests against the demo secret in Section 2 | Both match exactly — do this before your first call |
| Valid key + correct signature | 200 |
| Valid key + tampered signature | 401 with AUTH_TOKEN_INVALID |
| Unknown API key | 401 with AUTH_TOKEN_INVALID |
| Headers omitted | 401 with AUTH_REQUIRED |
| Sign the full URL instead of the path | 401 — sign /api/v1/partner/schemes only |
| On API 2, re-serialise the body after signing it | 401 — confirms you must send the exact bytes you signed |
API 1 — Scheme List
| Test Case | Expected Result |
| Fetch the list | 200; count matches the array length |
Render a scheme with "5y": null | Card shows a dash, never 0% |
Render a scheme with logoUrl: null | Falls back to initials, no broken image |
Render a scheme with an empty navSeries | Card renders without a sparkline, no layout break |
API 2 — Webview Link
| Test Case | Expected Result |
Request with a schemeCode | target: "SCHEME"; webview opens that scheme's page |
Request without a schemeCode | target: "DISCOVERY"; webview opens the discovery page |
Unknown clientCode | 404 with CLIENT_NOT_FOUND |
Unknown schemeCode | 404 with SCHEME_NOT_FOUND |
| Open the same URL a second time | Expired-link screen — confirms the link is single-use |
| Open a URL more than 5 minutes after issue | Expired-link screen |
| Open links for two different clients in turn | Each webview shows only its own client's data |
Webview
| Test Case | Expected Result |
| Complete a mandate step that redirects to an external provider | Redirect completes and returns into the webview |
| Kill the network mid-journey | Your own close control still exits the webview |
Receive the EXIT message | Your app closes the webview |
Support
For integration questions, contact the Artham engineering team:
- Email: rahul@artham.co
- We are available for joint debugging calls during integration.