---
title: "Change card PIN"
method: PATCH
path: "/v1/vendor_cards/{vendor_card_id}/pin"
tags: ["Vendor card"]
---

# Change card PIN

`PATCH /v1/vendor_cards/{vendor_card_id}/pin`

## Request

- Base URL: `https://api.cardda.com`
- URL: `https://api.cardda.com/v1/vendor_cards/{vendor_card_id}/pin`
- Auth: HTTP bearer

Sets a new 4-digit PIN on a physical card. Authorized for admins, holders of
the `vendor_cards_manage` permission, or the cardholder.

The `pin` parameter is **required** (missing → `412`, from
`params.require(:pin)`). It must match
`^\d\d\d\d$` and the card's vendor must support PIN updates; otherwise the
endpoint returns `422` with
`{ "error_code": "vendor_cards/pin_not_supported" }`. Vendor-side failures
return `500` with the vendor's message.

## Path parameters

- `vendor_card_id` string, required

## Parameters

- `#/paths/~1v1~1merchants/get/parameters/0` (unresolved $ref)

## Request body

- VendorCardPinUpdate: Payload to change a physical card's PIN.
  - `pin` string, required: The new 4-digit PIN. Must match `^\d\d\d\d$`. Only cards whose vendor supports PIN updates accept this; others return `422`.

## Response `200`

The vendor card, after the PIN was updated.

- VendorCard
  - `id` string: Card id. Cardda card ids are vendor-prefixed base64-encoded strings (e.g. `Q2FyZDoxMDIwNjQ5Mw==`), not UUIDs.
  - `user_id` string: Firebase user id of the cardholder (not a UUID).
  - `company_id` string, uuid
  - `type` 'AptoCard' | 'BrexCard' | 'Cards::Increase::Card' | 'Cards::Plh::Card' | 'DivvyCard' | 'Issuing::Relay::Card' | 'Issuing::Slash::Card' | 'MercuryCard' | 'MeshCard' | 'PomeloCard' | 'StripeCard': Single Table Inheritance discriminator (issuing vendor / STI sub-class). A persisted column, so it always serializes into the row for **every** caller.
  - `name` string
  - `last4` string
  - `status` 'active' | 'inactive' | 'pending' | 'canceled'
  - `status_preference` string
  - `migrated` boolean
  - `usage` integer, nullable
  - `limit_amount` MoneyAmount, nullable: Monetary amount. All numeric fields are serialized as strings to preserve precision (BigDecimal).
    - `amount` string: Amount in the main currency unit (e.g., '3000.0' for 3,000 CLP, '176.0' for 176 USD).
    - `formatted` string: Human-readable formatted amount including currency symbol.
    - `cents` string: Amount in the currency's smallest subunit. For CLP (no subunits) this equals the main amount; for USD this is 100× the main amount.
    - `currency_iso` string: ISO 4217 currency code.
  - `limit_interval` 'daily' | 'weekly' | 'monthly' | 'yearly' | 'all_time' | 'per_authorization': Current spending limit interval.
  - `limit_amount_preference` MoneyAmount, nullable: Monetary amount. All numeric fields are serialized as strings to preserve precision (BigDecimal).
    - `amount` string: Amount in the main currency unit (e.g., '3000.0' for 3,000 CLP, '176.0' for 176 USD).
    - `formatted` string: Human-readable formatted amount including currency symbol.
    - `cents` string: Amount in the currency's smallest subunit. For CLP (no subunits) this equals the main amount; for USD this is 100× the main amount.
    - `currency_iso` string: ISO 4217 currency code.
  - `limit_interval_preference` 'daily' | 'weekly' | 'monthly' | 'yearly' | 'all_time' | 'per_authorization', nullable: Requested spending limit interval.
  - `allocated_amount` MoneyAmount, nullable: Monetary amount. All numeric fields are serialized as strings to preserve precision (BigDecimal).
    - `amount` string: Amount in the main currency unit (e.g., '3000.0' for 3,000 CLP, '176.0' for 176 USD).
    - `formatted` string: Human-readable formatted amount including currency symbol.
    - `cents` string: Amount in the currency's smallest subunit. For CLP (no subunits) this equals the main amount; for USD this is 100× the main amount.
    - `currency_iso` string: ISO 4217 currency code.
  - `allocated_amount_preference` MoneyAmount, nullable: Monetary amount. All numeric fields are serialized as strings to preserve precision (BigDecimal).
    - `amount` string: Amount in the main currency unit (e.g., '3000.0' for 3,000 CLP, '176.0' for 176 USD).
    - `formatted` string: Human-readable formatted amount including currency symbol.
    - `cents` string: Amount in the currency's smallest subunit. For CLP (no subunits) this equals the main amount; for USD this is 100× the main amount.
    - `currency_iso` string: ISO 4217 currency code.
  - `allocation_interval_preference` 'daily' | 'weekly' | 'monthly' | 'yearly', nullable: Interval at which recurring allocations are applied.
  - `allocation_priority_preference` 'low' | 'mid' | 'high' | 'max', nullable: Priority level for fund allocation across multiple cards.
  - `recurring_allocation_amount_cents` integer, nullable: Recurring allocation amount in cents.
  - `remaining_balance` string, nullable: Actual amount the card can spend right now, as a decimal string in the card's currency (not cents). This is the minimum between the user's spending limit and the company's available balance.
  - `spent` integer
  - `company_expendable_balance_in_limit_currency` string, nullable: Company funds this card can still draw, expressed in the card's `limit_currency`, as a decimal string (a BigDecimal serialized to JSON, not a number). **Show-only** — returned by `GET /v1/vendor_cards/{id}` only, and only when the caller can read the company balance (`policy(company).balance?`). Absent from the list endpoint.
  - `spent_in_interval_with_limit_currency` number, float: Amount spent in the current limit interval, converted to the card's `limit_currency`. Always a number (defaults to `0.0`); never `null`. **Show-only** — returned by `GET /v1/vendor_cards/{id}` only.
  - `vendor_max_spending_limits` unknown
  - `vendor_max_allocation` MoneyAmount, nullable: Monetary amount. All numeric fields are serialized as strings to preserve precision (BigDecimal).
    - `amount` string: Amount in the main currency unit (e.g., '3000.0' for 3,000 CLP, '176.0' for 176 USD).
    - `formatted` string: Human-readable formatted amount including currency symbol.
    - `cents` string: Amount in the currency's smallest subunit. For CLP (no subunits) this equals the main amount; for USD this is 100× the main amount.
    - `currency_iso` string: ISO 4217 currency code.
  - `non_sensitive_information` object, nullable: Non-sensitive cardholder/configuration attributes (`user_name`, `user_identifier`, `country`, `address`, `postal_code`, `restricted_merchants`, `phone`). Empty object when unavailable. **Show-only** — returned by `GET /v1/vendor_cards/{id}` only.
  - `last_allocation_transaction_status` string, nullable: Status of the most recent allocation transaction on this card. **Show-only** — returned by `GET /v1/vendor_cards/{id}` only.
  - `last_allocation_transaction_created_at` string, date-time, nullable: Creation timestamp of the most recent allocation transaction. **Show-only** — returned by `GET /v1/vendor_cards/{id}` only.
  - `allocation_priority_stats` object, nullable: Total recurring allocation (cents) per priority group across the company's active cards (e.g. `{ "low": 5000000, "mid": 3000000 }`), or `null` for card types that don't compute it. **Show-only** — returned by `GET /v1/vendor_cards/{id}` only.
  - `preference_restricted_spendable` string, nullable: Amount the card can still spend before hitting its configured spending limit, as a decimal string in the card's currency (not cents). Calculated as the spending limit minus amount already spent in the current interval. Unlike `remaining_balance`, this does not consider the company's available funds.
  - `spent_in_interval` number, float
  - `spent_in_vendor_interval` number, float
  - `fees_in_vendor_interval` number, float
  - `created_at` string, date-time
  - `updated_at` string, date-time

## Other responses

- `401`: Unauthorized
- `404`: Vendor card not found (or not visible to the caller).
- `412`: Precondition Failed — `pin` parameter is missing (`params.require(:pin)`). Body: `{ "message": "param is missing or the value is empty or invalid: pin" }`.
- `422`: Unprocessable Entity — card does not support PIN updates or `pin` is not a 4-digit string. `{ "error_code": "vendor_cards/pin_not_supported" }`.
- `500`: Internal Server Error — the issuing vendor rejected the PIN change. Body carries the vendor message.

---

[API](https://skmtc.dev/cardda/apis/banking-api.md) - [All operations](https://skmtc.dev/cardda/apis/banking-api/llms.txt) - [OpenAPI document](https://skmtc.dev/cardda/apis/banking-api/revisions/ff1aeb3fda8b?raw)
