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

# Retrieve a card number with the Meow API

> Step-by-step guide to securely retrieving the full card number, CVC, and expiration date for a virtual card using a single-use reveal URL.

This guide explains how to retrieve the full card number for a card you created with the API. It covers:

* Claiming the card number and receiving a reveal grant
* Fetching the card number from the reveal URL
* Why the request must go to the reveal URL and not the API origin

## Prerequisites

* A card created through the API (see [Create Card](/api-reference/core-api/create-card))
* API key permissions: `cards:write`
* The card must be virtual, active, and not expired

<Note>
  Card number retrieval is enabled per account. Contact support to turn it on. Until it is enabled, both endpoints below return `403`.
</Note>

## How it works

The card number is never returned by the endpoint you call. Instead:

1. You claim the card number and receive a `reveal_url` plus a short-lived `reveal_token`.
2. You call that URL with the token to receive the card number, CVC, and expiration.

Meow stores tokenized placeholders rather than card numbers. The real values are substituted into the response by our PCI vault as it passes through `vault.meow.com`, so the card number is never written to our databases, logs, or backups.

## Claim the card number

Call the PAN endpoint with the `cardId` returned by Create Card:

```bash theme={null}
curl -X POST "https://api.meow.com/v1/cards/{card_id}/pan" \
  -H "x-api-key: YOUR_ENTITY_API_KEY"
```

The response contains the reveal grant, not the card:

```json theme={null}
{
  "reveal_url": "https://vault.meow.com/v1/cards/515024f9-6ad2-4ce5-bc2f-b0820bf9336b/pan/reveal",
  "reveal_token": "eyJjYXJkX2lkIjoiNTE1MDI0ZjkuLi4ifQ.0a-KPzCD0gniw2n8Dk4gcq1hOYw",
  "token_expires_in_seconds": 300,
  "exp_month": 5,
  "exp_year": 2029
}
```

<Warning>
  This can be called only once per card. Subsequent calls return an error, and that holds even if the call failed after the claim was recorded. If you lose the grant, revoke the card and create a new one.
</Warning>

## Fetch the card number

Call the `reveal_url` exactly as returned, passing the `reveal_token` as a bearer token alongside your API key:

```bash theme={null}
curl -X GET "https://vault.meow.com/v1/cards/{card_id}/pan/reveal" \
  -H "x-api-key: YOUR_ENTITY_API_KEY" \
  -H "Authorization: Bearer YOUR_REVEAL_TOKEN"
```

```json theme={null}
{
  "card_number": "4000009990002514",
  "cvc": "123",
  "exp_month": 5,
  "exp_year": 2029
}
```

The token is valid for 300 seconds. Request the card number at the point you need it rather than ahead of time.

## Use the reveal URL, not the API origin

Sending the same request to `api.meow.com` instead of `vault.meow.com` returns `200 OK` with the same field names, but the values are tokenized placeholders:

<CodeGroup>
  ```json api.meow.com theme={null}
  {
    "card_number": "tok_sandbox_azfe372ZXukbttABio4xCc",
    "cvc": "tok_sandbox_9MaYiyxaPDkzDAr3fvtpEz",
    "exp_month": 5,
    "exp_year": 2029
  }
  ```

  ```json vault.meow.com theme={null}
  {
    "card_number": "4000009990002514",
    "cvc": "123",
    "exp_month": 5,
    "exp_year": 2029
  }
  ```
</CodeGroup>

Meow returns the same response in both cases. The placeholders are what our API emits, and the card number is substituted into the response by the vault as it passes through `vault.meow.com`. Nothing about the request changes what we send.

Both responses are `200 OK`, so a failed integration looks like a working one. If your code receives a value beginning with `tok_`, it called the wrong host.

<Tip>
  Read `reveal_url` from the response rather than constructing it. The host differs between sandbox and production, and hardcoding it is the most common cause of receiving placeholders.
</Tip>

## Eligibility

A card can return its number only if all of the following are true:

* It was created through the API. Cards created in the dashboard cannot return a number.
* It is virtual, not physical.
* It is not closed, suspended, or expired.

These are checked again when you call the reveal URL, not only when you claim the number, so a card revoked within the five-minute window will not reveal.

## Handling errors

<AccordionGroup>
  <Accordion title="Card PAN has already been retrieved">
    The card number was already claimed. Revoke the card and create a new one.
  </Accordion>

  <Accordion title="Only cards created via this API can retrieve a PAN">
    The card was created in the dashboard. Create the card through [Create Card](/api-reference/core-api/create-card) instead.
  </Accordion>

  <Accordion title="Invalid or expired reveal token">
    The token is older than 300 seconds, belongs to a different card, or was altered. Claim a new card and retry, requesting the number closer to the point of use.
  </Accordion>

  <Accordion title="The response contains values beginning with tok_">
    The request went to the API origin instead of the reveal URL. Use the `reveal_url` value from the claim response verbatim.
  </Accordion>
</AccordionGroup>

## Next steps

<CardGroup cols={2}>
  <Card title="Create Card" icon="credit-card" href="/api-reference/core-api/create-card">
    Create the virtual card you will retrieve a number for.
  </Card>

  <Card title="Revoke Card" icon="ban" href="/api-reference/core-api/revoke-card">
    Revoke a card whose number was claimed and is no longer needed.
  </Card>

  <Card title="Card Transactions" icon="receipt" href="/api-reference/core-api/list-card-transactions">
    List authorizations and settled transactions for a card.
  </Card>

  <Card title="Authentication" icon="key" href="/authentication">
    API key types, scopes, and the `x-entity-id` header.
  </Card>
</CardGroup>
