Skip to main content

Create and Provision Flexible Credentials

Overview

This page explains how to create and provision a flexible credential and its member cards in a single call.

created = provisioned

FlexibleCredentialStatus has exactly two values, ACTIVE and CLOSED. There is no observable state in which a credential exists but isn't yet provisioned.

The mutation provisionFlexibleCredential runs against an Application in the APPROVED state and completes synchronously, so there is no polling step. A returned FlexibleCredential always represents a finished request.

Failures surface as UserError or AccessDeniedError in the payload union rather than as transport errors.

Before you start

You need the following:

  • An application in the APPROVED state.

    The flexible credential's CardProduct and its owning AccountHolder are both derived from that application, so you do not pass either one. Provisioning against an application in any other state fails with APPLICATION_NOT_APPROVED.

  • A card profile set for each credential you intend to issue.

    You need one card profile set for the primary, and one for the secondary. The card profile set does more than style the card; it determines the role each member card plays, and the role must match the backing account. A card profile set on a debit or prepaid BIN classifies as the primary, one on a credit BIN classifies as the secondary.

One secondary credential

Highnote currently supports exactly one secondary credential, and intends to relax that limit. secondaryCards is a list so the request shape does not have to change when it does, but sending more than one fails validation today.

Describe the cards

The primaryCard field takes a single card slot and secondaryCards takes a list of them. Every slot needs the same three fields:

FieldNotes
cardProfileSetIdThe card profile set for this card. Also determines the card's role, and so which FinancialAccount backs it.
expirationDateRequired on every slot, in ISO 8601 format. Flexible credential issuance has no product-level default to fall back on.
activateOnCreateWhether this card is usable immediately. A card created inactive must be activated separately before it can be used.

Three behaviors are worth knowing before you build the request:

  • Each slot's role must match its backing account. Highnote derives a role from the slot's cardProfileSetId and rejects the request if a slot's role does not match the account it would back. You do not choose the pairing directly; the card profile set determines it: debit and prepaid BINs classify as primary, credit BINs as secondary.
  • The secondaryCards array is required and non-null. A credential issued with no secondary still has to send "secondaryCards": [].
  • The activateOnCreate: false flag only holds back the card. The backing FinancialAccount and the parent flexible credential are always materialized active. Setting it per slot lets you issue a live primary alongside an inactive secondary. This is useful when a secondary credential is enabled only after the cardholder opts in.

Provision the credential

The example below issues a live debit primary alongside a live revolving credit secondary.

ProvisionFlexibleCredential
Query
mutation ProvisionFlexibleCredential(
$input: ProvisionFlexibleCredentialInput!
) {
provisionFlexibleCredential(input: $input) {
... on FlexibleCredential {
id
name
externalId
status
createdAt
cards {
isPrimary
paymentCard {
id
last4
expirationDate
}
defaultFinancialAccount {
id
name
}
}
}
... on UserError {
errors {
code
description
errorPath
}
}
... on AccessDeniedError {
message
}
}
}
Variables
{
  "input": {
    "applicationId": "APPLICATION_ID",
    "name": "Cardholder Flexible Credential",
    "idempotencyKey": "IDEMPOTENCY_KEY",
    "primaryCard": {
      "cardProfileSetId": "CARD_PROFILE_SET_ID_DEBIT",
      "expirationDate": "2030-01-01T00:00:00Z",
      "activateOnCreate": true
    },
    "secondaryCards": [
      {
        "cardProfileSetId": "CARD_PROFILE_SET_ID_CREDIT",
        "expirationDate": "2030-06-01T00:00:00Z",
        "activateOnCreate": true
      }
    ]
  }
}
⚠️ Please login to execute queries. Visit the dashboard to authenticate.
Result
{
"data": {
"provisionFlexibleCredential": {
"id": "FLEXIBLE_CREDENTIAL_ID",
"name": "Cardholder Flexible Credential",
"externalId": "EXTERNAL_ID",
"status": "ACTIVE",
"createdAt": "2026-04-01T15:30:00.000Z",
"cards": [
{
"isPrimary": true,
"paymentCard": {
"id": "PAYMENT_CARD_ID_PRIMARY",
"last4": "4242",
"expirationDate": "2030-01-01T00:00:00.000Z"
},
"defaultFinancialAccount": {
"id": "FINANCIAL_ACCOUNT_ID_DEBIT",
"name": "Debit Account"
}
},
{
"isPrimary": false,
"paymentCard": {
"id": "PAYMENT_CARD_ID_SECONDARY",
"last4": "1881",
"expirationDate": "2030-06-01T00:00:00.000Z"
},
"defaultFinancialAccount": {
"id": "FINANCIAL_ACCOUNT_ID_CREDIT",
"name": "Revolving Credit Account"
}
}
]
}
}
}

The mutation returns the new FlexibleCredential, so you can select the card and account IDs in the same request instead of following up with a read.

Name and external ID

The name field is required and holds a human-friendly label for the credential.

The externalId field is optional and is yours to supply for your own reconciliation. It must be unique per organization and tenant, and Highnote generates one if you omit it.

Send an idempotency key

Send a UUIDv4 idempotencyKey with every request. Highnote processes only the first request carrying a given key and returns that original response to repeats for 24 hours. A retry after a timeout cannot issue a second set of cards.

Handle failures

Provisioning failures come back as UserError in the payload union rather than as a transport error, so check __typename before reading the credential.

CodeMeaning
APPLICATION_NOT_APPROVEDThe Application is not APPROVED. Provisioning cannot proceed until it is.
INVALID_INPUTA field failed validation, e.g., an expirationDate that is not ISO 8601.

The errorPath locates the offending field, including its position in a list, so a bad expiration on the primary member card returns ["input", "primaryCard", "expirationDate"]. Read it rather than parsing the description.

Next steps

The credential is active and its cards are issued. From here, find it and fetch what's attached to it using the returned ID.