Issuing

Getting Started with PayMongo Issuing


PayMongo Issuing lets you create and manage Mastercard prepaid cards, funded by your PayMongo Wallet, entirely through the API. Issue virtual cards to your team or your customers, control them by program, and freeze, unfreeze, or cancel them in real time.

This guide walks you through the full flow — setting up a card program, creating cardholders, issuing cards, retrieving card credentials, and managing the card lifecycle — along with every constraint you need to know.

📘

Currently in this release

Issuing currently supports virtual cards only, billed in PHP, funded by your PayMongo Wallet. Physical cards are on our roadmap.

How Issuing fits together

Issuing is built around three resources, created in this order:

ResourceWhat it is
Card ProgramA grouping mechanism for your cards. Programs let you organize sets of cards for different uses (e.g. "Marketing team", "Customer rewards") and apply the same settings across them.
CardholderThe individual who owns a card — their name, contact details, and address. A cardholder can have one or more cards.
CardThe Mastercard prepaid card itself, linked to one cardholder, one card program, and the PayMongo Wallet that funds it.

So the flow is: create a card program → create a cardholder → create a card under that program for that cardholder.

Prerequisites

  1. An activated PayMongo Wallet — cards are funded by your wallet, and the wallet must be in a transactable (active) state.
  2. Your API secret key. All Issuing endpoints use Basic authentication: pass your secret key as the username with a blank password.

Step 1: Create a card program

curl -X POST https://api.paymongo.com/v1/issuing/card-programs \
  -u sk_live_xxxxxxxx: \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Marketing Team Cards",
    "description": "Virtual cards for the marketing team ad spend"
  }'
{
  "data": {
    "id": "card_prog_xxxxxxxx",
    "merchant_id": "org_xxxxxxxx",
    "name": "Marketing Team Cards",
    "description": "Virtual cards for the marketing team ad spend",
    "created_at": "2026-08-31T10:45:48.828Z",
    "updated_at": "2026-08-31T10:45:48.828Z"
  }
}

Parameters and constraints

ParameterTypeRequiredConstraints
namestringYesThe program's name.
descriptionstringYesDetails about the program.

You can retrieve a single program with GET /v1/issuing/card-programs/{id} and list all programs with GET /v1/issuing/card-programs (see Pagination below). Card programs can't be updated or deleted through the API — create a new program if your grouping needs change.

Step 2: Create a cardholder

Each card belongs to a person. Register them as a cardholder first:

curl -X POST https://api.paymongo.com/v1/issuing/cardholders \
  -u sk_live_xxxxxxxx: \
  -H "Content-Type: application/json" \
  -d '{
    "first_name": "Juan",
    "last_name": "Dela Cruz",
    "phone": "+639171234567",
    "email": "[email protected]",
    "address": {
      "line1": "123 Ayala Avenue",
      "line2": "Unit 4B",
      "city": "Makati",
      "state": "PH-00",
      "postal_code": "1226",
      "country": "PH"
    }
  }'
{
  "data": {
    "id": "ch_xxxxxxxx",
    "merchant_id": "org_xxxxxxxx",
    "first_name": "Juan",
    "last_name": "Dela Cruz",
    "phone": "+639171234567",
    "email": "[email protected]",
    "address": {
      "line1": "123 Ayala Avenue",
      "line2": "Unit 4B",
      "city": "Makati",
      "state": "PH-00",
      "postal_code": "1226",
      "country": "PH"
    },
    "created_at": "2026-08-31T10:50:12.000Z",
    "updated_at": "2026-08-31T10:50:12.000Z"
  }
}

Parameters and constraints

ParameterTypeRequiredConstraints
first_namestringYesCardholder's given name.
last_namestringYesCardholder's family name.
phonestringYesPhilippine mobile number in +639XXXXXXXXX format.
emailstringYesMust be a valid email address.
address.line1stringYesPrimary address line.
address.line2stringNoSecondary address line.
address.citystringYesCity.
address.statestringNoProvince, per ISO 3166-2:PH (e.g. PH-00 for NCR).
address.postal_codestringYesPostal code.
address.countrystringYesExactly 2 letters, ISO 3166-1 alpha-2 (e.g. PH).

A cardholder can hold multiple cards. Cardholders can't be updated or deleted through the API — if a cardholder's details change, create a new cardholder and issue their next card against it. Retrieve one with GET /v1/issuing/cardholders/{id} or list them with GET /v1/issuing/cardholders.

Step 3: Create a card

Issue a virtual card under a program, for a cardholder, funded by your wallet:

curl -X POST https://api.paymongo.com/v1/issuing/cards \
  -u sk_live_xxxxxxxx: \
  -H "Content-Type: application/json" \
  -d '{
    "cardholder": "ch_xxxxxxxx",
    "card_program": "card_prog_xxxxxxxx",
    "type": "virtual",
    "account_number": "000001234567"
  }'
{
  "data": {
    "id": "card_xxxxxxxx",
    "account_number": "000001234567",
    "cardholder": "ch_xxxxxxxx",
    "card_program": "card_prog_xxxxxxxx",
    "name": "Juan Dela Cruz",
    "currency": "php",
    "type": "virtual",
    "status": "active",
    "last4": "4242",
    "exp_month": 8,
    "exp_year": 2031,
    "livemode": true,
    "created_at": "2026-08-31T11:02:33.000Z",
    "updated_at": "2026-08-31T11:02:33.000Z"
  }
}

Parameters and constraints

ParameterTypeRequiredConstraints
cardholderstringYesAn existing cardholder ID belonging to your organization.
card_programstringYesAn existing card program ID belonging to your organization.
typestringYesOnly virtual is supported.
account_numberstringYesThe PayMongo Wallet account number that funds the card. Numeric only. The wallet must be active and transactable.
namestringNoThe name printed on the card. Defaults to the cardholder's full name.
notestringNoA free-form internal note.
currencystringNo3-letter code. Defaults to php (the only supported billing currency at this time).

Constraints to be aware of:

  • Card limit per organization. By default you can have a maximum of 5 cards (cancelled cards don't count toward the limit). Attempting to create more returns an error. If you need a higher limit, contact your PayMongo account manager.
  • The funding wallet must be transactable. If your wallet is not yet activated, or is frozen or restricted, card creation is rejected with wallet is not transactable.
  • Expiry is set automatically. Cards are valid for 5 years from issuance; exp_month and exp_year are returned on the card object.
  • New cards are typically active immediately and ready to transact.

Step 4: Retrieve card credentials

For security, the card number (PAN) and CVC are never returned by default — not on create, list, or plain retrieve. To get them, retrieve the card with the expand query parameter:

curl -G https://api.paymongo.com/v1/issuing/cards/card_xxxxxxxx \
  -u sk_live_xxxxxxxx: \
  -d "expand[]=number" \
  -d "expand[]=cvc"
{
  "data": {
    "id": "card_xxxxxxxx",
    "...": "...",
    "last4": "4242",
    "number": "5200000000004242",
    "cvc": "123"
  }
}

The only accepted expand values are number and cvc — anything else returns a 400 with invalid expand field.

🛡️

Handle card credentials with care

Only request number and cvc at the moment you need to display them to the cardholder, transmit them over TLS only, and never log or store them on your servers. Everywhere else, use last4 for display.

Step 5: Manage the card lifecycle

A card is always in one of five statuses:

StatusMeaningCan transact?
pendingJust issued, not yet usable.No
activeFully functional.Yes
lockedTemporarily restricted — e.g. suspected loss or theft. Reversible.No
suspendedRestricted due to suspected fraud.No
cancelledPermanently deactivated. Terminal — cannot be undone.No

Change a card's status with PATCH /v1/issuing/cards/{id}:

# Freeze a card
curl -X PATCH https://api.paymongo.com/v1/issuing/cards/card_xxxxxxxx \
  -u sk_live_xxxxxxxx: \
  -H "Content-Type: application/json" \
  -d '{ "status": "locked" }'

# Unfreeze it
curl -X PATCH https://api.paymongo.com/v1/issuing/cards/card_xxxxxxxx \
  -u sk_live_xxxxxxxx: \
  -H "Content-Type: application/json" \
  -d '{ "status": "active" }'

# Cancel it permanently
curl -X PATCH https://api.paymongo.com/v1/issuing/cards/card_xxxxxxxx \
  -u sk_live_xxxxxxxx: \
  -H "Content-Type: application/json" \
  -d '{ "status": "cancelled" }'

Constraints:

  • Accepted status values on update: active, locked, suspended, cancelled. (pending cannot be set manually.)
  • Cancellation is permanent. Once a card is cancelled, any further update attempt is rejected with 422 card is cancelled. Use locked if you may want to re-enable the card later.
  • Updating a card to its current status is a no-op and simply returns the card.
  • A request with no fields to update returns 400 no fields to update.
  • Cancelled cards free up room under your card limit — they don't count toward the maximum.

Listing cards

GET /v1/issuing/cards supports filters on top of pagination:

Query parameterDescription
statusFilter by status: active, locked, cancelled, pending, or suspended.
cardholderFilter by cardholder ID.
card_programFilter by card program ID.
account_numberFilter by funding wallet account number (numeric).
curl -G https://api.paymongo.com/v1/issuing/cards \
  -u sk_live_xxxxxxxx: \
  -d "card_program=card_prog_xxxxxxxx" \
  -d "status=active" \
  -d "limit=20"

The list response also includes status_counts — a tally of your cards by status (with all for the total and frozen as the combined count of locked and suspended cards), handy for building a dashboard view:

{
  "data": [ { "id": "card_xxxxxxxx", "...": "..." } ],
  "has_more": false,
  "status_counts": { "all": 3, "active": 2, "locked": 1, "suspended": 0, "cancelled": 0, "pending": 0, "frozen": 1 }
}

Pagination

All three list endpoints (card-programs, cardholders, cards) use cursor-based pagination:

ParameterDescription
limitNumber of resources to return: 1–100, default 10.
afterA resource ID; returns results after this cursor (next page).
beforeA resource ID; returns results before this cursor (previous page).

Use the last resource ID of the current page as after to fetch the next page; has_more tells you whether another page exists.

Error reference

Errors follow the standard PayMongo envelope:

{
  "errors": [
    {
      "code": "domain_error",
      "detail": "card creation limit exceeded for this merchant"
    }
  ]
}
HTTPCodeDetailCause / what to do
400invalid_request_bodyfield-specific messageA required field is missing or a value fails validation (e.g. type not virtual, malformed email, country not 2 letters).
400invalid_request_bodyno fields to updateA card update was submitted with an empty body.
400invalid_query_parametersinvalid expand fieldAn expand value other than number or cvc.
401unauthorizedMissing or invalid API key.
404not_foundcard program not found / cardholder not found / card not foundThe ID doesn't exist or doesn't belong to your organization.
422domain_errorcard creation limit exceeded for this merchantYou've reached your card limit (default 5, excluding cancelled). Cancel unused cards or request a higher limit.
422domain_errorcard is cancelledAttempted to update a cancelled card. Cancellation is permanent.
422domain_errorwallet is not transactableThe funding wallet isn't active. Activate your wallet or resolve its restriction first.
422domain_erroraccount_number is requiredCard creation without the funding wallet's account number.

FAQ

Which card network are the cards on?
Mastercard. Cards are prepaid and draw on your PayMongo Wallet balance.

Can I issue physical cards?
Not yet — only virtual is accepted today. Physical card support is in development.

How many cards can I create?
Up to 5 non-cancelled cards per organization by default. Contact your account manager if you need more.

Can I update a cardholder's details or a card program?
Not via the API in this release. Create a new cardholder or program instead. Card updates are limited to status changes.

Where do card transactions settle?
Card spend is deducted from the PayMongo Wallet whose account_number funds the card.

What happens when a card expires?
Cards are valid for 5 years from issuance. Issue a new card before exp_month/exp_year passes to keep the cardholder transacting.


Did this page help you?