Creating Cards
This guide walks you through creating and managing cards using the Issuing API.
Card Types
The API supports two types of cards:
Virtual Cards Digital cards for online transactions. Instant issuance.
Physical Cards Physical cards shipped to cardholders. 5-7 business days delivery.
Step 1: Create a Card Account
Before creating a card, you must first create a card account:
curl -X POST https://access.utgl.io/v1/cardaccounts \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"accountId": "your-account-id",
"accountType": "prepaid",
"currency": "USD"
}'
Step 2: Create a Card
Once you have a card account, create a card:
curl -X POST https://access.utgl.io/v1/cards \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Idempotency-Key: $( uuidgen )" \
-H "Content-Type: application/json" \
-d '{
"cardAccountId": "c8e2752d-6bd7-4244-a9f6-580f5640eaeb",
"type": "virtual",
"productId": "your-product-id-uuid",
"embossedName": "John Doe"
}'
Required Fields:
cardAccountId: The card account ID (from Step 1)
type: Either "physical" or "virtual"
productId: UUID of the card product (provided by your solution manager)
embossedName: Name to appear on card (max 22 chars, letters/spaces/hyphens only)
The productId determines card features, benefits, and capabilities. Contact your solution manager for available product IDs.
Response
{
"id" : "b39fcdfe-2ca0-49fc-b941-9b94ea1a51b3" ,
"cardAccountId" : "c8e2752d-6bd7-4244-a9f6-580f5640eaeb" ,
"type" : "virtual" ,
"status" : "active" ,
"productId" : "your-product-id-uuid" ,
"embossedName" : "John Doe" ,
"createdAt" : "2025-11-27T10:00:00Z"
}
Virtual cards are instantly active and ready to use!
Step 3: Retrieve Card Details
curl "https://access.utgl.io/v1/cards?cardId=b39fcdfe-2ca0-49fc-b941-9b94ea1a51b3" \
-H "Authorization: Bearer YOUR_API_KEY"
Get Sensitive Card Details
To retrieve full PAN, CVV, and expiry, use the sensitive info endpoint:
curl "https://access.utgl.io/v1/cards/card-sensitive-info?cardAccountId=c8e2752d-6bd7-4244-a9f6-580f5640eaeb&cardId=b39fcdfe-2ca0-49fc-b941-9b94ea1a51b3&ipAddress=8.8.8.8" \
-H "Authorization: Bearer YOUR_API_KEY"
This returns a short-lived URL that you must consume directly from the client’s IP address:
{
"url" : "https://access.utgl.io/v1/secure-content/2e91c5ac-eaaf-4274-9afd-520aa35c190e" ,
"expiry" : "2025-11-27T10:05:00Z"
}
Sensitive card data should be handled securely and never logged or stored in plain text. The URL must be consumed from the client’s IP address.
Step 4: Fund the Card Account
Fund the card account (for prepaid accounts):
curl -X POST https://access.utgl.io/v1/cardaccounts/topup \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"accountId": "your-source-account-id",
"cardAccountId": "c8e2752d-6bd7-4244-a9f6-580f5640eaeb",
"amount": 5000,
"currency": "USD"
}'
Step 5: Update Card Spending Controls
Update spending controls for a card:
curl -X POST https://access.utgl.io/v1/cards/spending-controls \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"cardId": "b39fcdfe-2ca0-49fc-b941-9b94ea1a51b3",
"singleTransactionLimit": 100000
}'
Creating Physical Cards
Physical cards follow the same process. The card account and card creation steps are identical:
curl -X POST https://access.utgl.io/v1/cards \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Idempotency-Key: $( uuidgen )" \
-H "Content-Type: application/json" \
-d '{
"cardAccountId": "c8e2752d-6bd7-4244-a9f6-580f5640eaeb",
"type": "physical",
"productId": "your-product-id-uuid",
"embossedName": "Jane Smith"
}'
Shipping information is typically handled separately through your card product configuration or via the cardholder info fields. Check with your solution manager for specific requirements.
Card Lifecycle Management
Activate a Card
curl -X POST https://access.utgl.io/v1/cards/activate \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"cardId": "b39fcdfe-2ca0-49fc-b941-9b94ea1a51b3"
}'
Suspend a Card
Temporarily block transactions:
curl -X POST https://access.utgl.io/v1/cards/suspend \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"cardId": "b39fcdfe-2ca0-49fc-b941-9b94ea1a51b3"
}'
Unsuspend a Card
Resume transactions:
curl -X POST https://access.utgl.io/v1/cards/unsuspend \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"cardId": "b39fcdfe-2ca0-49fc-b941-9b94ea1a51b3"
}'
Cancel a Card
Permanently cancel (irreversible):
curl -X POST https://access.utgl.io/v1/cards/cancel \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"cardId": "b39fcdfe-2ca0-49fc-b941-9b94ea1a51b3"
}'
Closing a card is permanent and cannot be undone. Funds will be returned to your account balance.
Best Practices
1. Use Idempotency Keys
Always use idempotency keys when creating cards to prevent duplicates:
Header: Idempotency-Key: <unique-value>
Concept:
Generate a unique identifier (UUID recommended)
Include in request headers
Same key = same result (prevents duplicate cards)
Endpoint: POST /v1/cards
Example:
curl -X POST https://access.utgl.io/v1/cards \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
-H "Content-Type: application/json" \
-d '{ ... }'
2. Set Appropriate Limits
Start with conservative limits and increase as needed:
Endpoint: POST /v1/cards/spending-controls
Recommended Starting Limits:
Daily: $1,000
Monthly: $5,000
Per Transaction: $500
Concept:
Set limits based on cardholder risk profile
Adjust limits dynamically as needed
Monitor spending patterns
Store application-specific data in metadata:
Field: xmetadata (object with key-value pairs)
Use Cases:
Customer ID tracking
Department/cost center assignment
Audit trail (who created the card)
Integration with your systems
Example:
{
"cardAccountId" : "..." ,
"productId" : "..." ,
"embossedName" : "John Doe" ,
"xmetadata" : {
"customerId" : "cust_123" ,
"department" : "marketing" ,
"costCenter" : "CC-123" ,
"createdBy" : "[email protected] "
}
}
4. Monitor Card Status with Webhooks
Subscribe to card events for real-time updates:
Webhook Events:
card.created - Card successfully created
card.suspended - Card suspended
card.unsuspended - Card unsuspended
card.cancelled - Card cancelled
Concept:
Configure webhook endpoint in dashboard
Receive events when card status changes
Update your systems accordingly
See Webhooks Guide for setup details.
Complete Workflow Example
Here’s a complete workflow for creating and funding a card:
Step-by-Step Process
1. Create Card Account
Endpoint: POST /v1/cardaccounts
Request:
{
"accountId" : "your-source-account-id" ,
"accountType" : "prepaid" ,
"currency" : "USD"
}
Response: Returns cardAccountId
2. Create Card
Endpoint: POST /v1/cards
Headers:
Authorization: Bearer <JWT_TOKEN>
Idempotency-Key: <unique-uuid>
Content-Type: application/json
Request:
{
"cardAccountId" : "c8e2752d-6bd7-4244-a9f6-580f5640eaeb" ,
"type" : "virtual" ,
"productId" : "your-product-id-uuid" ,
"embossedName" : "John Doe"
}
Response: Returns card with id and status
3. Fund Card Account (Optional)
Endpoint: POST /v1/cardaccounts/topup
Request:
{
"accountId" : "your-source-account-id" ,
"cardAccountId" : "c8e2752d-6bd7-4244-a9f6-580f5640eaeb" ,
"amount" : 500000 ,
"currency" : "USD"
}
Note: Amount is in smallest currency unit (cents for USD)
4. Retrieve Card Details
Endpoint: GET /v1/cards?cardId=<card-id>
Response: Returns complete card information
5. Set Spending Controls (Optional)
Endpoint: POST /v1/cards/spending-controls
Request:
{
"cardId" : "card-id-from-step-2" ,
"dailyLimit" : 100000 ,
"monthlyLimit" : 500000 ,
"perTransactionLimit" : 50000
}
For language-specific implementation examples, see the Recipes section which contains code examples in various programming languages.
Troubleshooting
Card Creation Failed
Problem : 400 Bad Request - Invalid cardAccountId
Solution : Ensure the card account exists and you have the correct cardAccountId. Create a card account first using /v1/cardaccounts.
Problem : 400 Bad Request - Invalid productId
Solution : The productId must be a valid UUID provided by your solution manager. Contact them for available product IDs.
Card Not Active
Problem : Created card shows status: "pending"
Solution : For physical cards, status remains “pending” until the card is activated. Use the /v1/cards/activate endpoint to activate.
Sensitive Data Access Denied
Problem : 400 Bad Request when accessing /cards/card-sensitive-info
Solution : Ensure you provide all required parameters: cardAccountId, cardId, and ipAddress. The ipAddress must match the client IP that will consume the returned URL.
Next Steps