This guide covers integrating the AdvanGuard Web SDK using direct URL redirection — the simplest integration method.
Why Choose URL Integration?
✅ Simplest Implementation: redirect to a URL
✅ No Iframe Restrictions: avoids iframe-related browser limitations
✅ Works Everywhere: compatible with all browsers and webviews
✅ Mobile-Friendly: works for mobile apps and deep links
✅ Quick MVP: get started in minutes
How It Works
┌──────────────┐
│ Your App │
└──────┬───────┘
│
│ 1. User clicks "Verify"
│
▼
┌────────────────────────────┐
│ Your Backend │ POST /v1/individual/applications
│ │ (or POST /v1/client-integration/links to
│ │ re-issue a link for an existing application)
└──────┬─────────────────────┘
│
│ 2. Response contains link.url
│
▼
┌──────────────┐
│ Your App │ Redirect to link.url
└──────┬───────┘
│
│ 3. window.location.href = link.url
│
▼
┌─────────────────────┐
│ AAI Verification │ User completes Document / Face steps
│ (new page/tab) │
└──────┬──────────────┘
│
│ 4. Flow ends → redirect to submittedUrl / successUrl / rejectUrl
│
▼
┌──────────────────────┐
│ Your Redirect URL │ Handle the hand-off, then fetch the result:
│ (your app) │ GET /v1/individual/applications/{applicationId}
└──────────────────────┘
How To Integrate
Before you start
| Item | Where to get it |
|---|---|
accessKey / secretKey | Dashboard → Developer Hub → API Credential |
| A Level containing a Document and/or Face step | Dashboard → Configuration → Verification Levels — see Verification Level |
| API base URL | https://openapi.advance.ai (Production SG) |
Note: the newer and older integration models differ. The examples below use the current AdvanGuard API (Get started with API). If your account is still on the legacy Identity Verification model, refer to the corresponding legacy documentation instead.
1. Create the Application and Get the URL
Authenticate first — see Authentication — then create an Application:
curl -X POST https://openapi.advance.ai/v1/individual/applications \
-H "Authorization: Bearer <accessToken>" \
-H "Content-Type: application/json" \
-d '{
"levelId": "level-kyc-standard",
"externalUserId": "user-001",
"inputInfo": {
"preferences": { "language": "en-US", "prefersColorScheme": "light" }
},
"link": {
"ttlSeconds": 604800,
"redirect": {
"submittedUrl": "https://yourapp.com/kyc/submitted",
"successUrl": "https://yourapp.com/kyc/success",
"rejectUrl": "https://yourapp.com/kyc/failed"
}
}
}'Response (200 OK):
{
"applicationId": "app-7392581047263518721",
"profileId": "prof_01a0b245aa137be19e7fa44a116eedb5",
"levelId": "level-kyc-standard",
"levelVersion": 3,
"created": "2026-10-08T08:00:00Z",
"link": {
"linkId": "AAECAwQFBgcICQoLDA0ODw",
"url": "https://flow.advance.ai/ekyc/<flow-hash>?linkId=AAECAwQFBgcICQoLDA0ODw&language=en-US&theme=light",
"status": "ACTIVE",
"expiresAt": "2026-10-15T08:00:00Z"
},
"requestId": "req-example"
}Open link.url exactly as returned — linkId identifies the verification session and must not be replaced or edited.
| Field | Type | Notes |
|---|---|---|
link.ttlSeconds | integer | 1 – 2592000 (30 days); default 604800 (7 days) |
link.redirect.submittedUrl | HTTPS URL | Opened after the applicant submits (under review) |
link.redirect.successUrl | HTTPS URL | Opened when verification succeeds |
link.redirect.rejectUrl | HTTPS URL | Opened when verification is rejected or not completed |
inputInfo.preferences.language | BCP 47 tag | e.g. en-US, zh — see Supported Languages |
inputInfo.preferences.prefersColorScheme | light | dark | Default light |
link.redirect requires at least one URL and every value must be HTTPS. |
No
linkin the response? The Level contains no client collection step (for example an API-only or AML-only Level). This is not an error.
Re-issue a link for an existing Application — if a link expired or the applicant needs another attempt, create a new link instead of a new Application (Create a client access link):
curl -X POST https://openapi.advance.ai/v1/client-integration/links \
-H "Authorization: Bearer <accessToken>" -H "Content-Type: application/json" \
-d '{"target": {"targetType": "APPLICATION", "targetId": "app-7392581047263518721"},
"ttlSeconds": 1800, "language": "en-US", "prefersColorScheme": "light"}'Existing links can be reviewed with List client access links and Retrieve a client access link.
2. Open the URL in a WebView
link.url is a standard web URL, so your app opens it directly (window.location.href = link.url). No special handling is required.
The redirect targets you configured in step 1 are HTTPS only at API level. If your app must land on a custom scheme (myapp://…), let the flow finish on an HTTPS URL you control and forward to your app scheme from there.
3. Give Camera Permission
Refer to Camera Permission for Android WebView (onPermissionRequest) and iOS WebView (NSCameraUsageDescription + WKWebViewConfiguration + a pre-flight AVCaptureDevice.authorizationStatus check).
Fallback behaviour when the camera is unavailable is controlled by frontend feature flags (enableFallback, enableNoPermissionDirectReturn) — see Frontend Configuration.
4. Handle the Redirect URL
The flow ends on one of the three URLs configured in step 1.
| Case | URL used | When it happens | Parameters appended |
|---|---|---|---|
| Under review | submittedUrl | Applicant submitted all required materials and is under review | none |
| Success | successUrl | Verification passed | none |
| Failure / not completed | rejectUrl | Applicant did not complete the flow, or verification failed | errorCode, message |
| Example: |
https://yourapp.com/kyc/failed?errorCode=CAMERA_ISSUE
Parameters are appended to your URL as configured (query string, or the fragment if your URL contains one); your existing parameters are preserved.
The redirect is a signal, not a result. These parameters are not trustworthy on their own — confirm the outcome with the API (step 5) before changing any user status.
Failure errorCode values
errorCode values| errorCode | Description | Node |
|---|---|---|
ERROR | System error, backend processing exception or network issue | COMMON |
BROWSER_ISSUE | Not supported due to browser compatibility issues | COMMON |
NOT_SUPPORT | Not supported due to compatibility issues | COMMON |
CAMERA_ISSUE | Camera unavailable or the camera stream failed | COMMON |
NO_PERMISSION | Camera permission denied (returned when the flow is configured to return directly instead of showing the permission page) | COMMON |
DOCUMENT_AUTO_SCAN_TRY_COUNT_EXCEED | Document auto-scan try count exceeded the limit | DOCUMENT |
DOCUMENT_MANUAL_TRY_COUNT_EXCEED | Document manual photo try count exceeded the limit | DOCUMENT |
DOCUMENT_GALLERY_TRY_COUNT_EXCEED | Gallery upload retry count exceeded | DOCUMENT |
RESELECT_DOC_TYPE | User clicked to reselect document type | DOCUMENT |
RESELECT_REGION | User clicked to reselect region | DOCUMENT |
A message parameter accompanies errorCode for troubleshooting only — do not show it to end users. |
5. Get the Result
- Query the Application:
GET /v1/individual/applications/{applicationId}— returnsstatus(init/pending/onHold/completed/terminated) and, oncecompleted,review.reviewAnswer(GREEN/RED) with per-step results understepResults. - Or subscribe to webhooks:
APPLICATION_PENDING,APPLICATION_ON_HOLD,APPLICATION_COMPLETED,APPLICATION_TERMINATED— see Webhooks. Webhook delivery is not guaranteed; keep a polling fallback (10 minutes or greater). - Identity data lives on the Profile, not on the Application response:
GET /v1/individual/profiles/{profileId}.
Troubleshooting
| Issue | Solution |
|---|---|
No link in the create response | The Level has no client collection step — not an error. |
| Redirect never reached | Confirm the redirect URLs are HTTPS and publicly reachable from the applicant's browser. An invalid link.redirect is rejected at creation time with 400 invalid_request_error. |
| Link expired | expiresAt has passed. Re-issue with POST /v1/client-integration/links for the same Application, or create a new Application. |
409 active_application_exists | An active Application already exists for this externalUserId and is not resumed automatically. Re-issue its link, or terminate the old Application in the Dashboard. |
409 application_create_in_progress | Another creation is running for the same user — retry with backoff. |
| Camera permission denied in an in-app browser | Complete step 3, and keep the flow out of iframes. |
| Redirect received but the outcome is unclear | Expected — resolve it with the API or the webhook event, not the redirect parameters. |