How to Create a Card¶
This guide walks through the complete process of issuing a card using the QPay Issuer API — from importing your HSM certificate to monitoring the card through to the ACTIVE state. It is intended for developers at issuer organizations who have already set up their sandbox tenant and obtained client credentials.
Time to complete: ~20 minutes
API: Issuer API — base URL https://sandbox.qpay.quecto.com.br
Prerequisites¶
- An access token for an
issuertenant. See Authentication. - Access to an HSM or cryptographic library capable of generating an ECC P-256 key pair and a PIN block. The QPay platform never handles PINs in plaintext — all PIN material must be encrypted before being sent.
Set your token in a shell variable for convenience:
Overview¶
flowchart TD
A[Import certificate] --> B[Get HSM public key]
B --> C[Select data prep template]
C --> D[Select embosser]
D --> E[Create card layout]
E --> F[Create card product]
F --> G[Create card]
G --> H[Monitor status] Step 1 — Import a certificate¶
QPay uses your issuer certificate to establish trust for cryptographic operations (ARQC validation, ARPC generation) during transaction authorization. You must import a certificate before issuing any cards.
Generate an ECC P-256 certificate signing request (CSR) with your HSM or openssl:
openssl ecparam -name prime256v1 -genkey -noout -out issuer.key
openssl req -new -key issuer.key -out issuer.csr \
-subj "/CN=My Issuer/O=My Organization/C=BR"
# Base64-encode the CSR (single line, no line breaks)
CSR_B64=$(base64 -w 0 issuer.csr)
Submit the CSR:
curl -s -X POST $BASE/issuer/certificates \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"certificate_request_pem\": \"$CSR_B64\"}" | tee cert.json
Example response:
{
"certificate_id": 42,
"hsm_key_reference": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"certificate_pem_base64": "LS0tLS1CRUdJTi..."
}
Save certificate_id and hsm_key_reference. Certificates are valid for 90 days — rotate before expiry to avoid authorization failures.
export CERT_ID=$(cat cert.json | jq -r '.certificate_id')
export HSM_KEY_REF=$(cat cert.json | jq -r '.hsm_key_reference')
Step 2 — Retrieve the HSM public key¶
QPay exposes an HSM public key that your system uses to encrypt the cardholder's PIN block before sending it in the card creation request. Retrieve it now so you have it ready for Step 7.
Example response:
PIN encryption is an HSM operation
Use the public key from this response to encipher the PIN block according to your HSM's key agreement protocol (typically ECDH + AES key wrap). This step is performed entirely within your secure environment — QPay never receives a plaintext PIN.
Step 3 — Select a data prep template¶
Data preparation templates are configured by your processor and define the card network parameters for your BIN range. List the templates available to your issuer:
Example response:
[
{
"id": 7,
"name": "UnionPay Classic",
"description": "Standard UnionPay debit template",
"iin": "62270000",
"applications": [...]
}
]
Pick the template that matches your product and note its id:
Step 4 — Select an embosser¶
Embossers are the card personalization bureaus that physically produce your cards. List the embossers available to your issuer:
Example response:
Note the embosser_id:
Step 5 — Create a card layout¶
A card layout defines the visual and physical design of the card that is sent to the embosser. Create one:
curl -s -X POST $BASE/issuer/card-layouts \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"layout": "standard-blue-v1"}' | jq .
Example response:
Tip
The layout field value is a layout identifier string agreed upon with your embosser. Contact your embosser for the correct value — it maps to artwork and print specifications on their side.
Step 6 — Create a card product¶
A card product ties together a layout, a data prep template, and an embosser. It represents a specific card offering (e.g., "Classic Debit Card — Blue Design"):
curl -s -X POST $BASE/issuer/card-products \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"name\": \"Classic Debit\",
\"description\": \"Standard UnionPay debit card\",
\"layout_id\": $LAYOUT_ID,
\"data_prep_template_id\": $TEMPLATE_ID,
\"default_embosser_id\": $EMBOSSER_ID
}" | jq .
Example response:
Once you have a product, you can reuse it for every card you issue under this offering — you do not need to repeat Steps 3–6 for each card.
Step 7 — Create the card¶
With a product in place, issue a card for a cardholder. This is the step where you supply the encrypted PIN block.
Prepare the PIN block first
Before calling this endpoint, your HSM must:
- Generate a PIN block for the cardholder's chosen PIN (ISO 9564 format 0 or 4)
- Encipher it using the QPay HSM public key retrieved in Step 2
- Produce the
enciphered_pin_block(hex-encoded ciphertext) and theincoming_pekkey reference
curl -s -X POST $BASE/issuer/cards/create \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"product_id\": $PRODUCT_ID,
\"reference_id\": \"MY-UNIQUE-REF-001\",
\"card_holder_name\": \"JOAO DA SILVA\",
\"billing_address\": {
\"name\": \"Joao da Silva\",
\"postal_code\": \"01310-100\",
\"country\": \"BR\",
\"state\": \"SP\",
\"city\": \"São Paulo\",
\"address_line1\": \"Av. Paulista 1000\",
\"address_line2\": \"Apto 42\"
},
\"shipping_address\": {
\"name\": \"Joao da Silva\",
\"postal_code\": \"01310-100\",
\"country\": \"BR\",
\"state\": \"SP\",
\"city\": \"São Paulo\",
\"address_line1\": \"Av. Paulista 1000\",
\"address_line2\": \"Apto 42\"
},
\"enciphered_pin_block\": \"A1B2C3D4E5F60708\",
\"incoming_pek\": {
\"key_reference\": \"$HSM_KEY_REF\"
}
}" | jq .
Request fields reference:
| Field | Type | Required | Description |
|---|---|---|---|
product_id | integer | Yes | ID from Step 6 |
reference_id | string | Yes | Your system's unique identifier for this card |
card_holder_name | string | Yes | Name to emboss on the card (uppercase) |
billing_address | object | Yes | Cardholder's billing address |
shipping_address | object | Yes | Delivery address for the physical card |
enciphered_pin_block | string | Yes | PIN block encrypted under the QPay HSM public key |
incoming_pek.key_reference | string | Yes | HSM key reference from Step 1 |
embosser_id | integer | No | Override the product's default embosser |
Example response:
{
"reference_number": "QPY-20260602-001",
"embosser_id": 3,
"status": "PROVISIONED",
"embossing_status": "pending",
"card_id": 5821,
"errors": []
}
The card is created with status PROVISIONED and enters the embossing queue.
Step 8 — Monitor card status¶
Track the card through its lifecycle using the card listing endpoint:
curl -s $BASE/issuer/cards \
-H "Authorization: Bearer $TOKEN" | jq '.cards[] | select(.card_id == 5821)'
Card status lifecycle:
| Status | Meaning |
|---|---|
PROVISIONED | Card created, awaiting embossing and delivery |
ACTIVE | Embossed and delivered — card is operational |
FROZEN | Temporarily suspended (reversible) |
BLOCKED | Permanently blocked |
In the sandbox, the embossing step is simulated automatically and the card transitions to ACTIVE shortly after creation.
Issuing multiple cards (batch)¶
For bulk issuance, use the batch endpoint instead of calling /cards/create for each card individually:
The request body takes a request_id (idempotency key) and a card_batch_info array where each entry has the same fields as a single card creation. The response includes a batch_id you can use to poll status:
See the Issuer API reference for the full batch request schema.
Related¶
- Issuer API reference — interactive endpoint documentation
- Development tutorial — quick orientation for new integrators
- Credentials & authentication — token management