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

# Cards

> Register and maintain cards on the OpenCard Issuer API — create, update, list, get, and delete cards under /api/v1/issuers/{slug}/cards.

The cards endpoints maintain the set of cards enrolled in OpenCard per customer organisation. Register cards before sending transaction states — `{card_id}` in the transaction path is **your** card id from the create payload.

**Base path:**

```
{base_url}/api/v1/issuers/{slug}/cards
```

***

## Endpoints

| Method   | Path               | Scope                        | Purpose       |
| -------- | ------------------ | ---------------------------- | ------------- |
| `POST`   | `/cards`           | `issuer-{slug}-cards-write`  | Create        |
| `PUT`    | `/cards/{card_id}` | `issuer-{slug}-cards-write`  | Update        |
| `GET`    | `/cards/{card_id}` | `issuer-{slug}-cards-read`   | Get one       |
| `GET`    | `/cards`           | `issuer-{slug}-cards-read`   | List / filter |
| `DELETE` | `/cards/{card_id}` | `issuer-{slug}-cards-delete` | Delete        |

***

## Create card

```
POST /api/v1/issuers/{slug}/cards
Scope: issuer-{slug}-cards-write
```

```json theme={null}
{
  "id": "12345",
  "payment_product": "acmebank_credit",
  "last_four": "1234",
  "bin_number": "123456",
  "liability": "corporate_with_personal_invoice",
  "scheme": "visa",
  "funding": "credit",
  "issuer_organization_number": "5555555551",
  "issuer_country_code": "SE",
  "identity": {
    "ssn": "190001011111",
    "ssn_country_code": "SE",
    "name": "Test Testsson",
    "company_organization_number": "5555555555",
    "company_country_code": "SE"
  }
}
```

| Field                                  | Required | Notes                                                                                                                                                               |
| -------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`                                   | ✅        | **Your** unique card id — used as `{card_id}` in transaction URLs                                                                                                   |
| `payment_product`                      | ✅        | Code for the payment product this card belongs to — the same code you receive on the TPA `initiate`. OpenCard uses it to link the card to the customer's signed TPA |
| `last_four`                            | ✅        | Last four digits                                                                                                                                                    |
| `bin_number`                           | ✅        | BIN, max 12 characters                                                                                                                                              |
| `liability`                            | ✅        | `personal`, `corporate`, or `corporate_with_personal_invoice`                                                                                                       |
| `scheme`                               | ✅        | e.g. `visa`, `mastercard`                                                                                                                                           |
| `funding`                              | ✅        | `debit` or `credit` — appears on EMS webhooks as `card_funding`                                                                                                     |
| `issuer_organization_number`           | ✅        | Your organisation number (seller party)                                                                                                                             |
| `issuer_country_code`                  | ✅        | ISO 3166-1 alpha-2                                                                                                                                                  |
| `identity.ssn`                         | ✅        | Cardholder national id                                                                                                                                              |
| `identity.ssn_country_code`            | ✅        | ISO 3166-1 alpha-2                                                                                                                                                  |
| `identity.name`                        | ✅        | Cardholder display name                                                                                                                                             |
| `identity.company_organization_number` | ✅        | Customer company org number (buyer party)                                                                                                                           |
| `identity.company_country_code`        | ✅        | ISO 3166-1 alpha-2                                                                                                                                                  |

<Warning>
  `payment_product` must match a product the customer has signed a TPA for. Cards on a product without a signed TPA are stored but their transactions are **not** delivered to the EMS.
</Warning>

**Responses:**

| Code  | Meaning                                      |
| ----- | -------------------------------------------- |
| `201` | Card created                                 |
| `200` | Card already exists (idempotent — same `id`) |

Create is **idempotent** on `id`. Re-posting the same card returns the existing record.

***

## Update card

```
PUT /api/v1/issuers/{slug}/cards/{card_id}
Scope: issuer-{slug}-cards-write
```

Same body shape as create (except `id` comes from the path). Supports moving a card between identities/companies when holder or employer changes.

**Response `200`** with `updated: true`.

***

## Get card

```
GET /api/v1/issuers/{slug}/cards/{card_id}
Scope: issuer-{slug}-cards-read
```

**Response `200`:**

```json theme={null}
{
  "ok": true,
  "card": {
    "id": "12345",
    "payment_product": "acmebank_credit",
    "last_four": "1234",
    "bin_number": "123456",
    "liability": "corporate_with_personal_invoice",
    "funding": "credit",
    "buyer_party": "5555555555",
    "seller_party": "5555555551",
    "active": true,
    "created_at": "2026-01-15T10:00:00+00:00",
    "updated_at": "2026-06-08T10:00:00+00:00"
  }
}
```

***

## List cards

```
GET /api/v1/issuers/{slug}/cards
Scope: issuer-{slug}-cards-read
```

Query parameters: `last_four`, `buyer_party`, `seller_party`, `bin_number`, `id`, `active`, `per_page` (1–100, default 15), `page`.

**Response `200`:**

```json theme={null}
{
  "ok": true,
  "data": [
    {
      "id": "12345",
      "payment_product": "acmebank_credit",
      "last_four": "1234",
      "bin_number": "123456",
      "liability": "corporate_with_personal_invoice",
      "funding": "credit",
      "buyer_party": "5555555555",
      "seller_party": "5555555551",
      "active": true,
      "created_at": "2026-01-15T10:00:00+00:00",
      "updated_at": "2026-06-08T10:00:00+00:00"
    }
  ],
  "meta": {
    "current_page": 1,
    "last_page": 1,
    "per_page": 15,
    "total": 1
  }
}
```

***

## Delete card

```
DELETE /api/v1/issuers/{slug}/cards/{card_id}
Scope: issuer-{slug}-cards-delete
```

Soft-deletes the card and marks it inactive. **Response `204`** with empty body.

***

## Why the registry matters

OpenCard matches every transaction state to a registered card, its `payment_product`, and identity. Without an up-to-date registry:

* Transaction posts return `card_not_found`
* EMS apps never see data for unknown cards
* Cards with the wrong `payment_product` are linked to the wrong TPA — or to none

Keep cards in sync when issued, replaced, or closed at your end.
