Skip to main content
Every card — virtual and physical — starts with pin_set: false. Cardholders must set their PIN before card details (card number, CVV) can be viewed, and before chip-and-PIN or ATM transactions will work. To let a cardholder set their PIN, call the view-token endpoint with enabled_views: ["pin-set"]. The API always returns 200 OK with a secure_view_url for PIN setup — regardless of whether pin_set is true or false. Open that URL in an iframe or WebView and the cardholder can set (or change) their PIN directly.
The 422 PIN_NOT_SET error only occurs when you request card data or PIN reveal (enabled_views: ["data"], ["pin-view"]) while pin_set is still false. It does not occur when requesting ["pin-set"] to set the PIN.
Card PINs are set and changed through Yativo’s hosted secure page, powered by Gnosis Pay’s Partner Secure Elements (PSE). The cardholder types their PIN directly inside a sandboxed iframe hosted by Yativo. The PIN never passes through your backend.

How it works

1

Your backend requests a PIN view token

Call POST /v1/yativo-card/customers/{yativoCardId}/cards/{cardId}/view-token with enabled_views: ["pin-set"] for initial setup or PIN change, or ["pin-view"] to reveal the current PIN. Pass your brand theme to customise the page.
2

You receive a secure_view_url

The API returns 200 OK with a short-lived secure_view_url and the current pin_set status. This always succeeds for ["pin-set"] requests — even when pin_set is false.
3

Show the hosted page to the cardholder

Open the URL in an <iframe>, mobile WebView, or a new browser tab in your app. The cardholder enters and confirms their 4-digit PIN inside the hosted page.
4

Gnosis Pay confirms via webhook

Once saved, Gnosis Pay fires physical.card.pin.changed. Yativo receives it and flips pin_set to true on the card record.
The same flow handles both initial PIN setup and PIN changes — use enabled_views: ["pin-set"] in both cases.

Request a PIN view token

Call this from your backend using your issuer access token.
POST /v1/yativo-card/customers/{yativoCardId}/cards/{cardId}/view-token
yativoCardId
string
required
The customer’s yativo_card_id.
cardId
string
required
The card ID — works for both virtual and physical cards.
enabled_views
array
required
Controls which tabs appear on the hosted page. Accepted values:
ValueTab shown
"pin-set"Set or change PIN
"pin-view"Reveal current PIN (requires pin_set: true)
"data"Card number, CVV, expiry (requires pin_set: true)
Pass ["pin-set"] for initial setup or PIN change. Pass ["data", "pin-view", "pin-set"] to show all three tabs at once. The legacy value "pin" is accepted as an alias for "pin-set".
theme
object
Brand the hosted page with your colours and logo. All fields optional.
FieldTypeDescription
accent_colorstringHex colour for buttons and highlights
background_colorstringPage background
panel_colorstringCard panel background
text_colorstringPrimary text
logo_urlstringYour logo at the top of the page
border_radiusnumberCorner radius in px (8–36)
font_familystringCSS font-family string
curl -X POST 'https://crypto-api.yativo.com/api/v1/yativo-card/customers/yativo_card_customer_8f9a..._1769031332068/cards/afeb85fe-02f8-48da-b61e-84ad02704167/view-token' \
  -H 'Authorization: Bearer YOUR_ISSUER_ACCESS_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "enabled_views": ["pin-set"],
    "theme": {
      "accent_color": "#6366f1",
      "background_color": "#f5f5f5",
      "logo_url": "https://yourapp.com/logo.png",
      "border_radius": 16
    }
  }'
{
  "success": true,
  "data": {
    "secure_view_url": "https://crypto-api.yativo.com/api/v1/yativo-card/view/eyJhbGci...",
    "expires_at": "2026-05-18T12:05:00.000Z",
    "last_four": "4291",
    "card_type": "virtual",
    "holder_name": "Jane Doe",
    "pin_set": false,
    "enabled_views": ["pin-set"],
    "requires_access_code": false
  }
}

Embed the hosted PIN page

Pass secure_view_url directly as the src of an iframe. No SDK or client-side JavaScript required.
<iframe
  src="https://crypto-api.yativo.com/api/v1/yativo-card/view/eyJhbGci..."
  title="Set Card PIN"
  width="420"
  height="520"
  style="border: 0; border-radius: 16px;"
  allow="clipboard-read; clipboard-write"
></iframe>
Recommended iframe dimensions: 420 × 520px for PIN-only. Use 420 × 740px if showing card details and PIN together.

Checking PIN status

pin_set is updated when Yativo receives the physical.card.pin.changed webhook from Gnosis Pay. It is not sourced from the Gnosis API — treat it as the last known state. You can read it from: Per-card, in GET /v1/card-issuer/customers/{customerId}:
{
  "card_id": "afeb85fe-02f8-48da-b61e-84ad02704167",
  "card_type": "virtual",
  "status": "active",
  "pin_set": false
}
Per-customer top-level (true only when every card has a PIN):
{
  "cards_count": 2,
  "pin_set": false,
  "next_action": "Card is active — customer must set card PIN before in-store (PSE) payments will work"
}
On the view-token responsedata.pin_set is returned every time you call the view-token endpoint. To list all customers who still need to set a PIN:
GET /v1/card-issuer/customers?status=card_created
Then filter the results by pin_set: false.
pin_set reflects the last state received via webhook and may lag if a webhook was delayed. If a cardholder reports unexpected PIN_NOT_SET errors after completing PIN setup, they can retry — the server will re-evaluate when the webhook catches up.

Webhook confirmation

Subscribe to physical.card.pin.changed on your webhook endpoint. Yativo updates pin_set: true automatically when this event arrives — no polling needed.
Payload example
{
  "event": "physical.card.pin.changed",
  "data": {
    "cardToken": "afeb85fe-02f8-48da-b61e-84ad02704167",
    "yativo_card_id": "yativo_card_customer_8f9a..._1769031332068"
  }
}

Notes

DetailValue
Works forVirtual and physical cards
PIN formatExactly 4 digits (00009999)
Initial setup & changeSame enabled_views: ["pin-set"] flow for both
PIN never touches your serverEntered directly in the Yativo-hosted iframe
Brand customisationPass theme in the token request — applies to the hosted PIN page
Confirmationphysical.card.pin.changed webhook → pin_set: true
pin_set sourceWebhook only — not from Gnosis API
Online vs chip PINPSE updates the online PIN. The chip syncs on first ATM use (physical cards)