What's New

New Feature: Currency Card Controls

Partners can now restrict or allow card transactions by currency. Currency controls work alongside the existing country controls.

Updated Endpoint: PUT /api/cards/{cardId}/card-controls

Add a currencies object to the request body:

{
  "currencies": {
    "restriction": "ALLOWED | BLOCKED",
    "values": ["EUR", "USD", "GBP"]
  }
}

The currencies field is also returned in GET /api/cards/{cardId}/card-controls responses.

New Endpoint: GET /api/cards/card-controls/supported-currencies

Returns the list of currencies supported for card controls.


New Feature: Verification of Payee (VOP)

Partners can now verify that an account holder name matches a given IBAN before initiating a transfer.

New Endpoint: POST /api/beneficiaries/{beneficiaryId}/payment-details/{paymentDetailId}/verify

Response:

{
  "matchLevel": "MATCH | CLOSE_MATCH | NO_MATCH | UNAVAILABLE"
}
❗️

VOP requests are subject to a configurable daily rate limit per partner. Requests exceeding the quota will receive a rate limit error response.


New Field: accountHolderName in Beneficiary Payment Details

The accountHolderName field is now returned in beneficiary payment detail responses.

Affected Endpoint: GET /api/beneficiaries/{beneficiaryId}/payment-details

New field in response:

{
  "accountDetail": {
    "accountHolderName": "Acme GmbH"
  }
}

Improvement: comment Field on Card Limit Requests

The comment field is now included in card limit change request detail responses. Partners can retrieve the reason provided when a limit change was requested.

Affected Endpoint: GET /api/cards/limits/requests/{limitChangeRequestId}

New field: comment (String, nullable)


Improvement: taxIdentificationNumber Now Optional in Onboarding

The taxIdentificationNumber field in taxResidences is no longer mandatory for UBOs and Authorized Signatories. Partners may omit it if not available.

Affected resource: Onboarding submission taxResidences[].taxIdentificationNumber


New Callbacks: Card Benefit Load and Unload Events

Partners can now subscribe to notifications when benefit funds are loaded or unloaded from a card.

New event types:

  • CARD_BENEFIT_LOADED -- fired when benefit funds are loaded to a card
  • CARD_BENEFIT_UNLOADED -- fired when benefit funds are removed from a card

Payload fields: organizationId, cardId, cardAccountId, loadAmount / unloadAmount

Subscribe via the existing CardSubscriptionRequest with the new event types.


New Callback: Cardholder Identity Verification Status Changed

Partners can now subscribe to notifications when a cardholder's identity verification status changes.

New event type: CARDHOLDER_LEGITIMATION_STATUS_CHANGED

Payload fields: organizationId, cardholderId, previous status, new status, verification timestamps

Subscribe via the existing CardholderSubscriptionRequest.


You can now restrict card transactions by country and acceptance method via the Card Controls API. Both control types are added to the card controls object alongside existing controls (categories, merchants, dates, times, locations).

Country controls and acceptance methods can be set when:

  • Updating existing card controls via PUT /cards/{cardId}/controls
  • Issuing new cards via all three card issue endpoints (POST /cards, instant issue, instant PCI)
  • Creating card requests via POST /card-requests - controls are inherited when the request is approved

✨ New: Country Controls

Configure allowlists or blocklists at the card level using ISO 3166-1 alpha-3 country codes.

  • ALLOWED: Only transactions in listed countries are permitted (whitelist)
  • BLOCKED: Transactions in listed countries are declined (blacklist)
PUT /cards/{cardId}/controls

{
  "countries": {
    "restriction": "ALLOWED",
    "values": ["AUT", "DEU", "CHE"]
  }
}

A new reference endpoint GET /cards/card-controls/supported-countries will return the list of eligible country codes with labels, making it easy to build country selection UIs.

✨ New: Acceptance Method Controls

Restrict which payment methods a card can be used with. Only the ALLOWED restriction is supported; unlisted methods are automatically blocked.

Available methods: ONLINE, MOBILE_WALLET, MANUAL_ENTRY, CONTACTLESS, CHIP_DIP, MAGNETIC_STRIPE, NOT_AVAILABLE, OTHER

PUT /cards/{cardId}/controls

{
  "acceptanceMethods": {
    "type": "ACCEPTANCE_METHOD",
    "restriction": "ALLOWED",
    "values": ["ONLINE", "CONTACTLESS", "CHIP_DIP"]
  }
}

Card Configuration Discovery

The available card configs response (GET /cards/available) now returns a cardControls object for each configuration, indicating which controls are supported. This includes countries, acceptanceMethods, categories, dates, locations, merchants, and times. US card configs return null for country controls.

Endpoints

MethodEndpointDescription
GET/cards/{cardId}/controlsRetrieve card controls (now includes countries and acceptanceMethods)
PUT/cards/{cardId}/controlsSet or update card controls
POST/cardsIssue card with controls pre-configured
POST/card-requestsCreate card request with controls (inherited on approval

Callbacks

The existing CARD_CONTROL_UPDATED callback event now includes countries and acceptanceMethods in the payload. This event fires when controls are updated via API or UI.

Constraints

  • Country codes must be valid ISO 3166-1 alpha-3 (e.g., DEU, not DE)
  • Country controls are not available for US-issued cards (returns 400)
  • Acceptance methods only support ALLOWED restriction (no BLOCKED)
  • At least one country code must be provided when setting country controls

Questions? Contact your Partner Success manager or email [email protected]

✨ New: Batch Unload Benefit Cards Endpoint

Its now possible to remove funds from benefit cards in batch. This is the counterpart to the existing POST /cards/load endpoint. While load adds funds, unload reclaims unused balances.

MethodEndpointDescription
POST/cards/unloadUnload funds from a batch of benefit cards

Request:

POST /cards/unload

{
  "cards": [
    {
      "cardId": "550e8400-e29b-41d4-a716-446655440000",
      "unloadAmount": {
        "value": 5000,
        "currency": "EUR"
      }
    }
  ]
}
  • cardId: UUID of the benefit card to unload
  • unloadAmount.value: Amount in minor units (e.g., 5000 = 50.00 EUR)
  • unloadAmount.currency: ISO 4217 currency code (must match the Card Account's currency)

Response: 202 Accepted: request is processed asynchronously.

Use cases:

  • Reclaim remaining balance before card termination (employee leaves)
  • Remove unused funds at end of benefit period (month/quarter)
  • Reduce benefit allocation across multiple cards (policy change)
  • Reverse accidental over-loading (error correction)

⚠️ Pre-conditions

All of the following must be met, or the entire batch is rejected synchronously:

  • All cards must be active benefit cards (load-based funding type)
  • All cards must belong to the same Organization
  • All amounts must be positive and in the Card Account's currency
  • Amounts must not exceed each card's available balance
  • No pending unload already in progress for any of the affected cards

🔔 Callbacks

Listen for CARD_BALANCE_UPDATED callback events to track completion of each card's unload.

🔧 Improved: Automatic Balance Transfer on Benefit Card Termination

When a benefit card (load-based) is terminated or expires, the system now automatically transfers remaining funds back to the Organization's main Card Account. This eliminates the need to manually unload cards before termination.

How it works:

TriggerTimingTransfer
Card terminated or expired5 days after terminationRemaining availableLimit → main Card Account
Refund/chargeback on terminated cardEnd of calendar month (rolling check for up to 365 days post-termination)Refunded transaction amount → main Card Account

After transfer, the card's availableLimit is set to 0.

A new CARD_UNLOADED event appears in the card history.


Questions? Contact your Partner Success manager or email [email protected]

Overview

Pliant is extending the Partner API to support Visa Click to Pay enrollment and management. This enables your cardholders to check out faster at participating online merchants without manually entering card details.

Key Points:

  • New Visa cards are automatically enrolled in Click to Pay (no action required)
  • Existing Visa cards can be manually enrolled via new API endpoints
  • Partners can unenroll cards on customer request
  • Callbacks notify you of enrollment state changes
  • Only Visa cards are eligible (Mastercard and Travel Purchasing Cards excluded)

What's New

New API Endpoints

1. Enroll Card in Click to Pay

POST /api/cards/{cardId}/click-to-pay/enroll

Purpose: Enroll an existing Visa card (and its associated member) into Click to Pay.

Response (200 OK):

{
  "cardId": "550e8400-e29b-41d4-a716-446655440000",
  "clickToPayInfo": {
    "status": "ENROLLED",
    "enrolledAt": "2026-01-15T10:30:00Z",
    "unenrolledAt": null
  }
}

Notes:

  • The organization’s billing address will be used implicitly when enrolling the cardholder
  • If card is already enrolled, returns current status (idempotent)
  • Only Visa cards can be enrolled
  • Returns 400 Bad Request for non-Visa cards or invalid card states

Statuses

StatusDescription
NOT_SUPPORTEDCard type doesn't support Click to Pay (e.g., TPC or Mastercard)
NOT_ENROLLEDEligible but not enrolled
ENROLLEDCurrently enrolled in Click to Pay

2. Unenroll Card from Click to Pay

POST /api/cards/{cardId}/click-to-pay/unenroll

Purpose: Remove a card from Click to Pay enrollment.

Response (200 OK):

{
  "cardId": "550e8400-e29b-41d4-a716-446655440000",
  "clickToPayInfo": {
    "status": "NOT_ENROLLED",
    "enrolledAt": "2026-01-15T10:30:00Z",
    "unenrolledAt": "2026-02-06T10:30:00Z",
  }
}

Notes:

  • Card must be currently enrolled
  • Returns 400 Bad Request if card is not enrolled


Enhanced Card Details

The existing card details endpoint will be extended to include Click to Pay information:

POST /api/cards/{cardId}

Note: GET endpoint is deprecated. Use POST for card details.

New Response Field:

{
  "cardId": "550e8400-e29b-41d4-a716-446655440000",
  "...": "existing fields",
  "clickToPayInfo": {
    "status": "NOT_ENROLLED",
    "enrolledAt": "2026-01-15T10:30:00Z",
    "unenrolledAt": "2026-01-15T10:30:00Z"
  }
}

Card Issuance Responses:

  • Card issuance callbacks and responses will include Click to Pay status for auto-enrolled cards

Card Configuration Enhancement

Card configuration endpoints will include:

  • clickToPaySupported: Boolean indicating whether the card can be added to Click to Pay

Callbacks Payloads

The clickToPayInfo object is included in all relevant card callback payloads.


Requirements & Constraints

Eligibility

  • Visa cards only (credit)
  • Mastercard cards (not supported)
  • Travel Purchasing Cards (not eligible)

Organization billing address

Cardholders will be enrolled with their organization’s billing address implicitly.


Questions? Contact your Partner Success manager or email [email protected]

✨ New: Card Account Payout Endpoint

You can now initiate payouts from a Card Account to an external bank account. This enables fund withdrawal flows where Organizations need to transfer surplus funds out of their Card Accounts.

MethodEndpointDescription
POST/card-accounts/{cardAccountId}/payoutCreate a payout to an external bank account

Request:

POST /card-accounts/{cardAccountId}/payout

{
  "bankAccountId": "550e8400-e29b-41d4-a716-446655440000",
  "amount": {
    "value": 100000,
    "currency": "EUR"
  }
}
  • bankAccountId - UUID of the destination bank account
  • amount.value - Amount in minor units (e.g., 100000 = 1,000.00 EUR)
  • amount.currency - ISO 4217 currency code

Response: 201 Created with a Payment object.

Where to get bank accounts: Use the existing GET /organizations/{organizationId}/bank-accounts endpoint to retrieve the list of available external bank accounts for an Organization. The bankAccountId from the response is what you pass to the payout request.

✨ New: Get Card Account by ID

Retrieve details of a specific Card Account directly by its identifier, without needing to list all Card Accounts for an Organization first.

MethodEndpointDescription
GET/card-accounts/{cardAccountId}Get Card Account details by ID

✨ New: Get Bank Account by ID

A new endpoint to retrieve a specific bank account by ID will be available shortly:

MethodEndpointDescription
GET/organizations/{organizationId}/bank-accounts/{bankAccountId}Get bank account details by ID

Payout Callbacks

The status changes for payouts can be tracked with the existing paymentStatusChanged callback event. It will notify you when a payout changes status (e.g., processing, completed, failed). Subscribe via the existing callback subscription endpoints.

Constraints

  • The destination bank account must already exist for the Organization. Retrieve available accounts via GET /organizations/{organizationId}/bank-accounts
  • Amount must be specified in minor currency units
  • Payout availability depends on Card Account (funding) type and balance

Questions? Contact your Partner Success manager or email [email protected]


This release includes improvements to callback visibility, card design support, and extended card state information.

Callback Status Visibility

API consumers can now check if callbacks are activated for their integration.

Endpoint:

  • GET /callbacks/subscriptions — Returns the list of active callback subscriptions and now also includes the callbacksEnabled (boolean) flag.

For more information, please check: https://partner.getpliant.com/reference/get-callback-subscriptions.


Card Design Support

A new cardDesignId property has been added to Issue Card endpoints, allowing specification of card designs (i.e., color variants for virtual cards) during card issuance.

Request & Response Changes:

{
  "cardDesignId": "design-uuid-here",
  ...
}

Affected Endpoints:

  • POST /cards — Issue Card
  • POST /cards/instant — Issue Card (Instant)
  • POST /cards/instant/pci — Issue Card (Instant as PCI-DSS)

For more information, please check: https://partner.getpliant.com/reference/issue-card


Extended Card State Information

To provide better visibility into why a card is in PENDING status, we have added a new pendingDetails property.

New Property:

  • pendingDetails (string) — The detailed reason for a card's pending state. Possible values:
    • PENDING_ACTIVATION
    • PENDING_ISSUANCE
    • PENDING_REGISTRATION
    • PENDING_VALIDITY
    • PENDING_SANCTION_SCREEN
    • PENDING_INFORMATION

This field is only populated when status is PENDING (or one of the deprecated PENDING_* statuses) and will be null for all non-pending statuses.

Deprecation Notice:

The granular PENDING_* status values (e.g., PENDING_ACTIVATION, PENDING_INFORMATION) are now deprecated. Please migrate to using the status: PENDING combined with pendingDetails for the specific reason. These deprecated statuses will be removed with the next API version.

Affected Endpoints:

  • POST /cards/details — Card Details
  • Card-related callbacks

For more information, please check: https://partner.getpliant.com/reference/get-multiple-card-details.

This release includes improvements to callback visibility, card design support, and extended card state information.


This changelog documents card-related API improvements including new properties, callback triggers, and validation enhancements.

Card Activation Method Property

A new activationMethod property has been added to the card entity based on the card manufacturer.

Response Changes:

The card entity now includes:

{
  "status": "PENDING_ACTIVATION",
  "activationMethod": "refNum" | "activationCode" | null,
  ...
}

Affected Endpoints:

  • GET /cards/{id}
  • GET /cards
  • Card-related callbacks

For virtual cards, or cards where activation does not apply, this value is set to null. For more information, please check: https://partner.getpliant.com/reference/activate-physical-card


Small Improvements / Bugfixes

  • The CARD_DETAILS_CHANGED callback is now triggered when a card's cardholder is changed via POST /cards/platform-fee/{id}/reassign
  • Enhanced validation to prevent benefit card issuance or requests with invalid configuration properties like e.g. limit or limitFrequency != TOTAL.
🚧

Changes effective the 30.01

We are introducing quotas for Auth0 Access Tokens.

Enforcement

Quotas are now enforced for new API consumers upon activation.

Monitoring Usage

Specific limits vary based on account type and program requirements.

Please refer to the API response header to monitor the available tokens and remaining quota for your specific use case.

For a comprehensive breakdown of our rate-limiting logic, please visit the Access Token Request Quotas guide.

Signed callbacks and redirects (Ed25519)

Pliant now cryptographically signs both callbacks (webhooks) and partner authorization redirects using Ed25519, enabling partners to verify authenticity and protect against tampering and replay attacks.

Callback authenticity

  • All callbacks include the standardized headers webhook-id, webhook-timestamp, and webhook-signature
  • Signatures follow the Standard Webhooks Signature Scheme
  • The signature is calculated over
    <webhook-id>.<webhook-timestamp>.<raw HTTP payload>
  • Each payment program has its own signing key
  • Public keys are available via /api/partner-management/signing/jwks.json
  • Partners can cache keys long-term; key rotations will be announced in advance

📘 Full implementation details and verification examples are available here: Callback authenticity

Redirect signing (partner authorization flow)

  • Redirects from Pliant to partner apps are now signed
  • The signature covers
    <t>.<partnerId>.<organizationId>
  • A timestamp (t) is included to mitigate replay attacks
  • Partners should validate timestamp tolerance and verify the signature using the program’s public key
  • Ensures redirects originate from Pliant and parameters were not modified

📘 Full implementation details and verification examples are available here: Integration initiated from Pliant (Signed redirects)

We’ve released an update that allows consumers to subscribe to callback events using multiple callback URLs.

(1) Add Multiple Callback Subscriptions

New Endpoint: POST /subscriptions/bulk-upsert

Remarks:

  • This creates multiple callback subscriptions in a single request;
  • The response includes both newly created subscriptions, and existing subscriptions that already match the same eventType + callbackUrl.
  • Multiple subscriptions per eventType are supported as long as callbackUrls differ.
  • If a subscription with the same eventType + callbackUrl already exists, it is not modified but is still returned in the response.
  • Only subscriptions included in the request are affected; all other existing subscriptions remain unchanged.
  • A maximum of 42 subscriptions per eventType is allowed.

(2) Delete Callback Subscription:

New Endpoint: DELETE /subscriptions/id

Remarks:

  • Deletes a callback subscription by its UUID.
  • Returns 204 No Content upon successful deletion.