Tutorial: Issue your first card¶
This tutorial takes an issuer tenant from authenticating to holding a card, in the QPay sandbox. It is the short path: each step links to the how-to guide that covers the same ground with every option.
Prerequisites:
- A sandbox tenant with the
issuerrole — see Getting started - A
client_idandclient_secret— see Creating client credentials curlandjqinstalled locally
1. Get an access token¶
TOKEN=$(curl -s -X POST \
$BASE/realms/qpay/protocol/openid-connect/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET" \
| jq -r '.access_token')
Confirm it works:
Expected response:
{
"tenant_type": "issuer",
"tenant_id": "your-issuer-tenant-id",
"parent_tenant_id": "your-processor-tenant-id"
}
Every API call goes through /api
The sandbox is fronted by a gateway: the Issuer API lives at /api/issuer, credentials at /api/credentials, the ledger at /api/issuer/ledger. A request without the prefix reaches the console web app instead and comes back as HTML.
2. Pick a card template¶
Your processor publishes card templates — pre-certified BIN-level configurations. You build a product on one; you do not create one.
curl -s $ISSUER/card-templates \
-H "Authorization: Bearer $TOKEN" | jq '.[] | {id, name, currency_numeric_code}'
Note an id — it is TEMPLATE_ID in the next step. Its currency_numeric_code is the currency your product will inherit.
3. Create a product and make it issuable¶
A product is the offering; a layout is one design of it; an embosser is certified against a layout. A card needs all three, so this is four calls:
# the template you noted in step 2, and an embosser from GET $ISSUER/embossers
TEMPLATE_ID=7
EMBOSSER_ID=$(curl -s $ISSUER/embossers \
-H "Authorization: Bearer $TOKEN" | jq -r '.[0].embosser_id')
# the product
PRODUCT_ID=$(curl -s -X POST $ISSUER/card-products \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d "{\"card_template_id\": $TEMPLATE_ID, \"name\": \"My First Product\", \"description\": \"Tutorial product\"}" \
| jq -r '.product_id')
# a layout under it
LAYOUT_ID=$(curl -s -X POST $ISSUER/card-products/$PRODUCT_ID/layouts \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"layout": "tutorial-v1", "prints_pan_on_face": false, "cardholder_name_zone": "bottom_left"}' \
| jq -r '.layout_id')
# link that embosser to the layout
PE_ID=$(curl -s -X POST $ISSUER/card-products/$PRODUCT_ID/layouts/$LAYOUT_ID/embossers \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d "{\"embosser_id\": $EMBOSSER_ID, \"embosser_reference_id\": \"TUTORIAL-REF\"}" \
| jq -r '.id')
# approve the link — the last segment is the link id, not the embosser id
curl -s -X PUT $ISSUER/card-products/$PRODUCT_ID/layouts/$LAYOUT_ID/embossers/$PE_ID/approve \
-H "Authorization: Bearer $TOKEN"
Check that the product is now issuable — it appears here only if it is active and has a layout with an approved embosser:
Full detail, including artwork and the certification export: Manage Card Products.
4. Issue a card¶
A card is backed by ledger accounts, so how you issue depends on whose ledger holds them. In the sandbox the quickest route is QPay's own ledger, which creates the accounts and then calls the Issuer API for you:
curl -s -X POST $BASE/api/issuer/ledger/accounts/cards \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d "{
\"idempotency_key\": \"$(uuidgen)\",
\"product_id\": $PRODUCT_ID,
\"layout_id\": $LAYOUT_ID,
\"cardholder_id\": \"YOUR_CARDHOLDER_ID\",
\"currency_numeric_code\": 986,
\"reference_id\": \"TUTORIAL-CARD-001\",
\"card_holder_name\": \"JOAO DA SILVA\",
\"billing_address\": { \"name\": \"JOAO DA SILVA\", \"address_line1\": \"Av. Paulista 1000\", \"city\": \"Sao Paulo\", \"state\": \"SP\", \"country\": \"BR\", \"postal_code\": \"01310100\" },
\"shipping_address\": { \"name\": \"JOAO DA SILVA\", \"address_line1\": \"Av. Paulista 1000\", \"city\": \"Sao Paulo\", \"state\": \"SP\", \"country\": \"BR\", \"postal_code\": \"01310100\" }
}" | jq .
The cardholder must exist and be KYC-approved for that currency first — Use the QPay Ledger covers those steps, and it is the guide to follow if this call fails.
Running your own ledger instead? Call POST $ISSUER/cards/create directly and pass your own account_links — see Create a Card.
5. Check card status¶
A new card is PROVISIONED. It advances only when the embosser reports progress through the Embosser API, so in a sandbox with no bureau attached it stays there.
What's next?¶
- Certificates — import an issuer certificate for the cryptographic operations during authorization, and for supplying your own PINs. See Create a Card
- Products — several layouts, artwork, and moving volume between embossers: Manage Card Products
- Embossing jobs — if you run your own embosser, see the Embosser API to poll and confirm jobs
- Ledger — use QPay's internal ledger, or connect your own via the Ledger Callback API. Start with QPay Ledger Core for the concepts
- Credit invoicing — issuing credit cards on QPay's ledger? See Run a Billing Cycle
Browse the full API Reference to explore all available endpoints.