---
title: "Get a PIN-entry URL"
method: GET
path: "/cards/{id}/pin-entry-url"
tags: ["Cards"]
---

# Get a PIN-entry URL

`GET /cards/{id}/pin-entry-url`

## Request

- Base URL: `https://api.lightspark.com/grid/2025-10-13`
- URL: `https://api.lightspark.com/grid/2025-10-13/cards/{id}/pin-entry-url`
- Auth: HTTP basic

Get a temporary URL for a secure PIN-entry iframe. The cardholder chooses a four-digit PIN inside the iframe, without the plaintext PIN crossing your servers or Grid's. Grid supports online PINs only.

Configure `cardConfigs.pinTargetOrigin` through `PATCH /config` before requesting a URL. It is the canonical HTTPS origin of the page that hosts the iframe. The iframe is restricted to that origin; this endpoint takes no request body or origin parameter.

Each call creates a fresh, temporary PIN-entry session. Request a URL immediately before displaying the form. Fetching the URL does not set or change the PIN. Set your iframe's `src` to the returned `iframeUrl` without modifying it. Follow the [Card PIN guide](https://docs.lightspark.com/cards/card-management/pins) to submit the form and confirm the result. Never store, cache, or log the URL or token. The session expires at `expiresAt` and permits one successful PIN submission. Responses include `Cache-Control: no-store`.

Use the iframe's submission result to confirm completion, and `GET /cards/{id}` to read `pinStatus`. `OK` alone cannot confirm a change to an already configured PIN.

If you operate your own PIN-entry UI, use `POST /cards/{id}/set-pin` with a client-encrypted payload instead.

Requires permission to manage cards. Every successful URL request is audit-logged with the requesting actor.

## Query parameters

- `styles` string

## Response `200`

A fresh PIN-entry URL and its expiration.

- CardPinUrlResponse: A temporary PIN-entry iframe URL, its credential, and expiration.
  - `iframeUrl` string, uri, required: Ready-to-use URL for the secure PIN-entry iframe. Set this as your iframe's `src` without modifying it. The cardholder enters their PIN inside the iframe, so the plaintext PIN never reaches your servers or Grid's. Use the message flow in the [Card PIN guide](https://docs.lightspark.com/cards/card-management/pins) to submit and confirm the result. The URL contains a temporary credential. Never store, cache, or log it. It expires at `expiresAt` and permits one successful PIN submission.
  - `sessionToken` string, required: Temporary credential authorizing one successful PIN submission. It is already included in `iframeUrl`; use that URL to load the form. Never store, cache, or log the token. Use the iframe's submission result to confirm a change; status `OK` alone cannot prove that an existing PIN was changed. Read `GET /cards/{id}` for its `pinStatus`.
  - `expiresAt` string, date-time, required: When the URL stops working. Request a new URL rather than reusing an expired URL or token.
  - `environment` 'SANDBOX' | 'PRODUCTION', required: Session environment. The iframeUrl already selects the matching environment.

## Other responses

- `400`: Invalid or oversized styles.
- `401`: Unauthorized
- `403`: Forbidden. The caller lacks permission to manage cards or has no attributable actor to audit the request against (for example, an impersonated dashboard session).
- `404`: Card not found
- `409`: Conflict. Returned with `CONFLICT` for a closed card, a card that does not support PIN management, or an unset `cardConfigs.pinTargetOrigin`. Configure the origin through `PATCH /config` before requesting a PIN-entry URL.
- `500`: Internal service error
- `501`: Not implemented in this environment. Cards are not enabled for every Grid deployment; environments without card support return `501 NOT_IMPLEMENTED`.

## Changes

> 115 revisions in range; 2 not diffed.

- **2026-10-28** `d996ddfb9d2b`: 5 info
  - added the optional property `details/missingFields` to the response with the `400` status
  - added the optional property `details/permission` to the response with the `403` status
  - added the optional property `details/policyDenialReason` to the response with the `403` status
  - added the optional property `details/refusalReason` to the response with the `400` status
  - …1 more
- **2026-10-28** `5abf2bb56bcb`: 1 warning
  - added the new `CORRIDOR_UNDER_MAINTENANCE` enum value to the `code` response property for the response status `403`
- **2026-10-26** `f11f1e76bdd7`: 1 warning
  - added the new `PURCHASE_CARD_LIMIT_REACHED` enum value to the `code` response property for the response status `409`
- **2026-10-26** `0a6dad5815c7`: 1 warning
  - added the new `INVOICE_ALREADY_USED` enum value to the `code` response property for the response status `409`
- **2026-10-24** `715332dcb111`: 1 warning
  - added the new `EXACT_AMOUNT_UNAVAILABLE` enum value to the `code` response property for the response status `400`

[Operation history](https://skmtc.dev/lightsparkdev/apis/grid-api/changes/cards/:id/pin-entry-url/get.md)

---

[API](https://skmtc.dev/lightsparkdev/apis/grid-api.md) - [All operations](https://skmtc.dev/lightsparkdev/apis/grid-api/llms.txt) - [OpenAPI document](https://skmtc.dev/lightsparkdev/apis/grid-api/revisions/7a1db46ec552?raw)
