Skip to main content
After creating an intent, check if compliance is required. If onboardingUrl is present in the response, you need to show the compliance iframe to the user.

Decision Tree

Auto-Complete Scenarios

The intent may skip compliance (no iframe needed) when:
  1. Returning Customer — User completed compliance for a previous intent with the same provider
  2. KYC Sharing — User authenticated via external auth and their Gnosispay KYC is shared
When auto-completed, the response has:
  • onboardingUrl: null
  • transaction object present
  • intent.status is COMPLIANCE_APPROVED or later

Iframe Integration

Embedding the Iframe

<iframe
  id="gnosis-ramp-onboarding"
  src="${onboardingUrl}"
  style="width: 100%; height: 600px; border: none;"
  allow="camera"
></iframe>
The allow="camera" attribute is required for KYC document verification that may require camera access.

Listening for Events

The iframe communicates completion via postMessage:
window.addEventListener('message', (event) => {
  // Verify origin
  if (!event.origin.includes('ramp.gnosis.io')) return;

  const { type, payload } = event.data;

  switch (type) {
    case 'INTENT_COMPLETED':
      // Compliance finished successfully
      console.log('Intent completed:', payload.intentId);
      removeIframe();
      // Proceed to execute transaction or monitor
      break;

    case 'INTENT_DISMISSED':
      // User closed or cancelled
      console.log('User dismissed onboarding');
      removeIframe();
      // Handle cancellation
      break;
  }
});

function removeIframe() {
  const iframe = document.getElementById('gnosis-ramp-onboarding');
  iframe?.remove();
}

Event Payloads

INTENT_COMPLETED
{
  "type": "INTENT_COMPLETED",
  "payload": {
    "intentId": "int_abc123def456"
  }
}
INTENT_DISMISSED
{
  "type": "INTENT_DISMISSED",
  "payload": {
    "intentId": "int_abc123def456"
  }
}

Complete Example

async function handleCompliance(intentResponse) {
  const { intent, onboardingUrl, transaction } = intentResponse;

  // Check if auto-completed
  if (!onboardingUrl && transaction) {
    console.log('Auto-completed! Monitoring transaction...');
    return monitorTransaction(intent.id);
  }

  // Check if no compliance needed
  if (!onboardingUrl) {
    console.log('Waiting for compliance...');
    return pollIntentStatus(intent.id);
  }

  // Show iframe
  return new Promise((resolve, reject) => {
    const iframe = document.createElement('iframe');
    iframe.id = 'gnosis-ramp-onboarding';
    iframe.src = onboardingUrl;
    iframe.style.cssText = 'width:100%;height:600px;border:none;';
    iframe.allow = 'camera';

    document.getElementById('onboarding-container').appendChild(iframe);

    const handler = (event) => {
      if (!event.origin.includes('ramp.gnosis.io')) return;

      const { type, payload } = event.data;

      if (type === 'INTENT_COMPLETED') {
        window.removeEventListener('message', handler);
        iframe.remove();
        resolve(payload.intentId);
      }

      if (type === 'INTENT_DISMISSED') {
        window.removeEventListener('message', handler);
        iframe.remove();
        reject(new Error('User dismissed onboarding'));
      }
    };

    window.addEventListener('message', handler);
  });
}

Polling Fallback

If postMessage events aren’t received (e.g., browser restrictions), poll the intent status:
async function pollIntentStatus(intentId) {
  const response = await fetch(
    `https://api.ramp.gnosis.io/v1/intent/${intentId}`,
    { headers: { 'Authorization': `Bearer ${accessToken}` } }
  );
  const { intent } = await response.json();

  if (intent.status === 'COMPLIANCE_APPROVED') {
    return intent;
  }

  if (intent.status === 'COMPLIANCE_FAILED') {
    throw new Error(intent.failureReason);
  }

  // Still in progress - poll again
  await new Promise(r => setTimeout(r, 2000));
  return pollIntentStatus(intentId);
}

Next Steps

Execute Transaction

Trigger the money movement.

Intent Overview

Understand all intent states.