> ## Documentation Index
> Fetch the complete documentation index at: https://developer.utgl.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Creating Cards

> Step-by-step guide to creating and managing cards

# Creating Cards

This guide walks you through creating and managing cards using the Issuing API.

## Card Types

The API supports two types of cards:

<CardGroup cols={2}>
  <Card title="Virtual Cards" icon="credit-card">
    Digital cards for online transactions. Instant issuance.
  </Card>

  <Card title="Physical Cards" icon="credit-card-front">
    Physical cards shipped to cardholders. 5-7 business days delivery.
  </Card>
</CardGroup>

## Step 1: Create a Card Account

Before creating a card, you must first create a card account:

```bash theme={null}
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:

```bash theme={null}
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"
  }'
```

<Warning>
  **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.
</Warning>

### Response

```json theme={null}
{
  "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"
}
```

<Note>
  Virtual cards are instantly active and ready to use!
</Note>

## Step 3: Retrieve Card Details

```bash theme={null}
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:

```bash theme={null}
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:

```json theme={null}
{
  "url": "https://access.utgl.io/v1/secure-content/2e91c5ac-eaaf-4274-9afd-520aa35c190e",
  "expiry": "2025-11-27T10:05:00Z"
}
```

<Warning>
  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.
</Warning>

## Step 4: Fund the Card Account

Fund the card account (for prepaid accounts):

```bash theme={null}
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:

```bash theme={null}
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:

```bash theme={null}
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"
  }'
```

<Note>
  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.
</Note>

## Card Lifecycle Management

### Activate a Card

```bash theme={null}
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:

```bash theme={null}
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:

```bash theme={null}
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):

```bash theme={null}
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"
  }'
```

<Warning>
  Closing a card is permanent and cannot be undone. Funds will be returned to your account balance.
</Warning>

## 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:**

```bash theme={null}
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

### 3. Use Metadata for Tracking

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:**

```json theme={null}
{
  "cardAccountId": "...",
  "productId": "...",
  "embossedName": "John Doe",
  "xmetadata": {
    "customerId": "cust_123",
    "department": "marketing",
    "costCenter": "CC-123",
    "createdBy": "admin@example.com"
  }
}
```

### 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](/issuing/guides/webhooks-1) 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:**

```json theme={null}
{
  "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:**

```json theme={null}
{
  "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:**

```json theme={null}
{
  "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:**

```json theme={null}
{
  "cardId": "card-id-from-step-2",
  "dailyLimit": 100000,
  "monthlyLimit": 500000,
  "perTransactionLimit": 50000
}
```

<Note>
  For language-specific implementation examples, see the [Recipes section](/issuing/recipes) which contains code examples in various programming languages.
</Note>

## 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

<CardGroup cols={2}>
  <Card title="Card Account Modes" icon="credit-card" href="/issuing/guides/card-account-modes">
    Learn about different card account types
  </Card>

  <Card title="Webhooks Guide" icon="webhook" href="/issuing/guides/handling-webhooks">
    Set up real-time notifications for card events
  </Card>
</CardGroup>
