This guide explains how to deliver an IBAN to your users via the KYC process. The process includes: KYC iframe integration, IBAN creation via the CREATE_IBAN operation, and status tracking via userData.
The KYC iframe allows the user to complete their identity verification process.
Endpoint : POST /v1.2/auth/iframe
Headers :
Authorization: Bearer <access_token> (required)Content-Type: application/jsonAccept: */*Body (JSON) :
language (string, optional) : Language code for the KYC interface (e.g., "en", "fr"). By default, the browser language is used.Request Example :
POST /v1.2/auth/iframe
Content-Type: application/json
Authorization: Bearer <access_token>
{
"language": "en"
}
Response (200 OK) :
{
"chatbotURL": "https://kyc.foo.domain/flow",
"sessionId": "a1b2c3d4e5"
}
chatbotURL : Base URL of the KYC chatbotsessionId : Session identifier for this KYC sessionBuild the complete redirect URL by combining the received data:
const redirectUrl = `${chatbotURL}?session=${sessionId}&returnUrl=${encodeURIComponent(appUrl)}`;
Where:
chatbotURL : URL received in the responsesessionId : Session ID received in the responseappUrl : URL of your application where the user will be redirected after KYCImplementation Example :
// 1. Get iframe URL
const iframeResponse = await fetch('/v1.2/auth/iframe', {
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ language: 'en' })
});
const { chatbotURL, sessionId } = await iframeResponse.json();
// 2. Build redirect URL
const appUrl = window.location.origin + '/kyc-callback';
const redirectUrl = `${chatbotURL}?session=${sessionId}&returnUrl=${encodeURIComponent(appUrl)}`;
// 3. Redirect user to KYC iframe
window.location.href = redirectUrl;
Once KYC is completed, you must create the IBAN via a Safe operation. This operation signs a message declaring ownership of the Safe address.
Endpoint : POST /v1.2/safes/operations
Headers :
Authorization: Bearer <access_token> (required)Body (JSON) :
safeAddress (string, required) : Safe address for which to create the IBANoperations (array, required) : Array containing an operation of type MONERIUM_CREATE_IBANMONERIUM_CREATE_IBAN Operation :
type (string, required) : "MONERIUM_CREATE_IBAN"Request Example :
POST /v1.2/safes/operations
Content-Type: application/json
Authorization: Bearer <access_token>
{
"safeAddress": "0xd676c6188195372EC269E9C2cAf815C56436A679",
"operations": [
{
"type": "MONERIUM_CREATE_IBAN"
}
]
}
Response (200 OK) :
{
"credentialRequestOptions": {
"challenge": "<base64url_encoded_userOpHash>",
"rpId": "foo.domain",
"userVerification": "required"
}
}
credentialRequestOptions, you must:
navigator.credentials.get() with these options to obtain a credentialPUT /v1.2/safes/operations request with the credential to finalize IBAN creationEndpoint : PUT /v1.2/safes/operations
Body (JSON) :
credential (object, required) : WebAuthn credential obtained with the options from the previous stepRequest Example :
PUT /v1.2/safes/operations
Content-Type: application/json
Authorization: Bearer <access_token>
{
"credential": {
"id": "AVZs0qRCBSmfThZWu37g...",
"rawId": "AVZs0qRCBSmfThZWu37g...",
"type": "public-key",
"response": {
"authenticatorData": "SZYN5YgOjGh0NBcPZHZgW4/krrmihjLHmVzzuoMdl2MFAAAAAQ...",
"clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoi...",
"signature": "MEUCIQC..."
}
}
}
Once KYC is completed and the CREATE_IBAN operation is executed, you can track the KYC status and retrieve the IBAN via userData.
Endpoint : GET /v1.2/ibexsafe/userdata/external/{externalUserId}
Headers :
Authorization: Bearer <access_token> (required)Request Example :
GET /v1.2/ibexsafe/userdata/external/{externalUserId}
Authorization: Bearer <access_token>
Response (200 OK) :
{
"id": "user123",
"ky": "2",
"signers": [
{
"id": "signer123",
"safes": [
{
"address": "0xd676c6188195372EC269E9C2cAf815C56436A679",
"threshold": 1,
"iban": {
"chainId": 100,
"iban": "FR76 1234 5678 9012 3456 7890 123",
"bic": "CREDFRPP",
"status": "VERIFIED"
}
}
]
}
]
}
ky : KYC status (see table below)iban.iban : IBAN number (available once delivered)iban.bic : Bank BIC codeiban.status : IBAN status (PENDING, VERIFIED, etc.)iban.chainId : Chain ID associated with this IBANThe ky field in userData indicates the KYC process status. Possible values are:
| Value | Code | Description |
|---|---|---|
"0" |
NO_KYC |
No KYC |
"1" |
LVL1_IN_PROGRESS |
Process started but not completed |
"2" |
LVL1_SUBMITTED |
Process completed, documents submitted |
"3" |
LVL1_ADDITIONAL_INFO_REQUESTED |
Additional information requested |
"4" |
LVL1_REJECTED |
Rejected |
"5" |
LVL1_ACCEPTED |
Accepted |
"55" |
TEMPORARY_BLOCKED |
Temporarily blocked |
The iban.status field indicates the IBAN status:
"PENDING" : IBAN pending verification"VERIFIED" : IBAN verified and active"REJECTED" : IBAN rejected (if applicable)You can also receive real-time notifications about KYC and IBAN changes via WebSocket.
WebSocket Message - KYC Update :
{
"type": "user.ky.updated",
"data": {
"safeAddress": "0xd676c6188195372EC269E9C2cAf815C56436A679",
"previousKyc": "1",
"newKyc": "2",
"updatedAt": "2025-08-01T07:36:04.083Z"
},
"timestamp": "2025-08-01T07:36:04.083Z"
}
WebSocket Message - IBAN Update :
{
"type": "user.iban.updated",
"data": {
"safeAddress": "0xd676c6188195372EC269E9C2cAf815C56436A679",
"iban": "FR76 1234 5678 9012 3456 7890 123",
"previousState": "PENDING",
"newState": "VERIFIED",
"updatedAt": "2025-08-01T07:36:04.083Z"
},
"timestamp": "2025-08-01T07:36:04.083Z"
}
POST /v1.2/auth/iframechatbotURL, sessionId, and returnUrlPOST /v1.2/safes/operations with MONERIUM_CREATE_IBAN operationPUT /v1.2/safes/operations with WebAuthn credentialGET /v1.2/ibexsafe/userdata/external/{externalUserId} to check ky and ibaniban.status = "VERIFIED", the IBAN is available in iban.ibanThis section provides detailed technical information for AI systems integrating the IBEX IBAN delivery flow, including architecture patterns, data models, and implementation details.
POST /v1.2/auth/iframe
ky() function which generates KYC iframe URL via upstream servicechatbotURL (iframe URL) and sessionId (unique session identifier)monerium context (chainId, address) to KYC serviceIframe Redirect Flow:
{chatbotURL}?sessionId={sessionId}&returnUrl={encodedReturnUrl}returnUrl with status parametersPOST /v1.2/safes/operations
MONERIUM_CREATE_IBANtype field)"I hereby declare that I am the address owner."signMessage() helper which creates a Safe message signing operationcredentialRequestOptions with challenge = userOpHash (base64url encoded)SafeOperation record with status CREATEDOperation record linked to SafeOperation with type: MONERIUM_CREATE_IBANPUT /v1.2/safes/operations/{userOpHash}
SIGNEDsendMoneriumCreateIbanNotification()CREATED → SIGNED → EXECUTED → CONFIRMEDDatabase Schema:
Iban {
safeAddress: String (PK, composite with blockchainId)
blockchainId: Int (PK, composite with safeAddress)
provider: IbanProvider (MONERIUM)
status: String (PENDING, VERIFIED, etc.)
createdAt: DateTime
updatedAt: DateTime
Safe: Safe (relation)
}
Status Updates:
POST /recovery/iban (system endpoint)PENDING, VERIFIED, REJECTED, etc.VERIFIED, IBAN details (iban, bic) are availableUserData Retrieval:
GET /v1.2/ibexsafe/userdata/external/{externalUserId} calls upstream IBExSafe serviceky : KYC status (0-5, 55)signers[].safes[].iban : IBAN details (chainId, iban, bic) if availableThe ky field in userData represents KYC verification status:
"0" (NO_KYC) : No KYC process initiated"1" (LVL1_IN_PROGRESS) : KYC process started but not completed"2" (LVL1_SUBMITTED) : KYC documents submitted, awaiting review"3" (LVL1_ADDITIONAL_INFO_REQUESTED) : Additional information requested by KYC provider"4" (LVL1_REJECTED) : KYC rejected"5" (LVL1_ACCEPTED) : KYC approved, IBAN can be created"55" (TEMPORARY_BLOCKED) : Temporarily blocked (suspicious activity, etc.)KYC Status Flow:
"5" (LVL1_ACCEPTED) is required before IBAN creation can proceedGET /v1.2/ibexsafe/userdata/external/{externalUserId}user.ky.updated message typeKYC Status Updates:
user.ky.updated{ type: "user.ky.updated", data: { ky: "5" }, timestamp: "..." }IBAN Status Updates:
user.iban.updated{ type: "user.iban.updated", data: { iban: { chainId: 100, iban: "FR76...", bic: "CREDFRPP" } }, timestamp: "..." }POST /v1.2/auth/iframe → returns chatbotURL, sessionIdPOST /v1.2/safes/operations with MONERIUM_CREATE_IBANPUT /v1.2/safes/operations/{userOpHash} with WebAuthn credentialPOST /recovery/iban updates Iban.status to VERIFIEDGET /v1.2/ibexsafe/userdata/external/{externalUserId} returns IBAN detailssrc/routes/v1/auth.ts : POST /v1.2/auth/iframe endpointsrc/routes/v1/safesOperations.ts : MONERIUM_CREATE_IBAN operation handlersrc/routes/system.ts : POST /recovery/iban system endpoint for status updatessrc/clients/IbexSafe.ts : userData() function for retrieving userDatasrc/services/notifications.ts : sendMoneriumCreateIbanNotification() for upstream notificationsprisma/schema.prisma : Iban model definition