Skip to main content
If you are currently using Marqeta widgets for Activate Card or Set PIN functionality, follow this guide to migrate to Synctera widgets.
For Card Reveal functionality (displaying PAN, CVV, EXP, PIN), continue using Marqeta Widgets until the Synctera Reveal Card Widget is available.

Activate Card Migration

API Changes

Marqeta (Old)Synctera (New)
GET /v0/cards/card_widget_url?widget_type=activate_cardPOST /v1/cards/{card_id}/widget_token?widget_type=ACTIVATE
Returns { url: "..." }Returns { widget_token: "..." }

Code Changes

Before (Marqeta):
<!-- Fetch widget URL from your backend -->
<iframe 
  src="{marqetaWidgetUrl}" 
  title="Activate Card"
  width="400"
  height="300"
/>
After (Synctera):
<!-- Load the widget script -->
<script 
  type="module" 
  src="https://assets.synctera.com/widgets/activate/v1.0.1/index.js"
></script>

<!-- Use the web component -->
<activate-card 
  token="{widgetToken}" 
  env="production"
></activate-card>

<script>
  // Handle events
  document.querySelector('activate-card').addEventListener('success', (e) => {
    console.log('Card activated:', e.detail);
  });
</script>

Backend Changes

Before (Marqeta):
// Server-side: Get widget URL
const response = await fetch(
  `https://api.synctera.com/v0/cards/card_widget_url?card_id=${cardId}&customer_id=${customerId}&account_id=${accountId}&widget_type=activate_card`,
  {
    headers: { 'Authorization': `Bearer ${apiKey}` }
  }
);
const { url } = await response.json();
// Return URL to frontend
After (Synctera):
// Server-side: Get widget token
const response = await fetch(
  `https://api.synctera.com/v1/cards/${cardId}/widget_token?widget_type=ACTIVATE`,
  {
    method: 'POST',
    headers: { 
      'Authorization': `Bearer ${apiKey}`,
      'Content-Type': 'application/json'
    }
  }
);
const { widget_token } = await response.json();
// Return token to frontend

Set PIN Migration

API Changes

Marqeta (Old)Synctera (New)
GET /v0/cards/card_widget_url?widget_type=set_pinPOST /v1/cards/{card_id}/widget_token?widget_type=SET_PIN
Returns { url: "..." }Returns { widget_token: "..." }

Code Changes

Before (Marqeta):
<!-- Fetch widget URL from your backend -->
<iframe 
  src="{marqetaWidgetUrl}" 
  title="Set PIN"
  width="400"
  height="300"
/>
After (Synctera):
<!-- Load the widget script -->
<script 
  type="module" 
  src="https://assets.synctera.com/widgets/set-pin/v1.0.1/index.js"
></script>

<!-- Use the web component -->
<set-pin 
  token="{widgetToken}" 
  env="production"
></set-pin>

<script>
  // Handle events
  document.querySelector('set-pin').addEventListener('success', (e) => {
    console.log('PIN set:', e.detail);
  });
</script>

Backend Changes

Before (Marqeta):
// Server-side: Get widget URL
const response = await fetch(
  `https://api.synctera.com/v0/cards/card_widget_url?card_id=${cardId}&customer_id=${customerId}&account_id=${accountId}&widget_type=set_pin`,
  {
    headers: { 'Authorization': `Bearer ${apiKey}` }
  }
);
const { url } = await response.json();
// Return URL to frontend
After (Synctera):
// Server-side: Get widget token
const response = await fetch(
  `https://api.synctera.com/v1/cards/${cardId}/widget_token?widget_type=SET_PIN`,
  {
    method: 'POST',
    headers: { 
      'Authorization': `Bearer ${apiKey}`,
      'Content-Type': 'application/json'
    }
  }
);
const { widget_token } = await response.json();
// Return token to frontend

Key Differences

Event Handling

Marqeta widgets used postMessage or URL callbacks. Synctera widgets dispatch standard DOM events:
// Synctera widgets use standard DOM events
widget.addEventListener('success', (event) => {
  console.log('Success:', event.detail);
});

widget.addEventListener('failure', (event) => {
  console.error('Error:', event.detail);
});

Customization

Marqeta widgets had limited customization. Synctera widgets support themes and custom labels:
<activate-card
  token="..."
  env="production"
  theme="night-shift"
  custom-labels='{
    "widgetTitle": "Activate Your Card",
    "submitButtonText": "Activate Now"
  }'
></activate-card>

Token Expiration

Both widget types use tokens that expire. Generate a new token on each page load:
// Recommended: Fetch token when component mounts
async function initializeWidget() {
  const { widget_token } = await fetchWidgetToken(cardId);
  document.querySelector('activate-card').setAttribute('token', widget_token);
}

Migration Checklist

  • Update backend API calls from /v0/cards/card_widget_url to /v1/cards/{card_id}/widget_token
  • Change HTTP method from GET to POST for token endpoint
  • Add widget script to your HTML (<script type="module" src="...">)
  • Replace <iframe> elements with web components (<activate-card> or <set-pin>)
  • Update event handling to use DOM event listeners
  • Test in sandbox environment before deploying to production
  • (Optional) Add custom theming and labels

Need Help?

If you encounter issues during migration, refer to the full documentation: