持卡人
VCC Cardholder API
Create and manage individual cardholders, retrieve their details and configure spending controls.
Endpoint
Sandbox base URL
https://api.futurepay-develop.com/api/v1/issuing/cardholderProduction base URL
https://api.futurepay.global/api/v1/issuing/cardholderAPI Overview
Paths below are relative to the base URL.
| Operation | Method | Path | Request Body |
|---|---|---|---|
| Create a cardholder | POST | /create | Create parameters. |
| List cardholders | POST | /paging | Filters and pagination, or {}. |
| Retrieve a cardholder | POST | /{id}/detail | {}. |
| Update a cardholder | POST | /{id} | Update parameters, or {}. |
| Activate a cardholder | POST | /{id}/activate | {}. |
| Deactivate a cardholder | POST | /{id}/deactivate | {}. |
| Retrieve spending controls | POST | /{id}/controls/detail | {}. |
| Set spending controls | POST | /{id}/controls | Complete spending control configuration. |
id is the string returned by this API, for example ich_EXAMPLE. Use this ID for subsequent requests.
Common Response
| Field | Type | Description |
|---|---|---|
| code | string | 0 for success; otherwise an error code. |
| msg | string | Result description. API error messages are in English. |
| serverTime | string | Server timestamp in milliseconds. |
| success | boolean | Whether the request succeeded. |
| data | object | Operation result. May be null or omitted for operations without a result object. |
Check success and code; HTTP status alone does not indicate business success.
Create a Cardholder
Endpoint
POST /createRequest Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| type | string | Yes | Cardholder type. Only individual (personal) is supported. Default value: individual. |
| individual | object | Yes | Personal information. |
| individual.firstName | string | Yes | First name. See Name Validation below. |
| individual.lastName | string | Yes | Last name. See Name Validation below. |
| individual.birthday | string | Yes | A valid date in yyyy-MM-dd format. The cardholder must be at least 18 years old. |
| individual.idDocFrontPath | string | No | Front document filename returned in data.path by the File Upload API. Maximum 128 characters. |
| individual.idDocBackPath | string | No | Back document filename returned in data.path by the File Upload API. Maximum 128 characters. |
| string | Yes | Valid email address, maximum 256 characters. See Email Validation below. | |
| billing | object | Yes | Billing information. |
| billing.address | object | Yes | Billing address. |
| billing.address.country | string | Yes | A valid uppercase two-letter ISO 3166-1 alpha-2 code supported by the service, such as US or SG. |
| billing.address.line1 | string | Yes | Street address, maximum 50 characters. |
| billing.address.line2 | string | No | Apartment, unit or additional address information, maximum 50 characters. |
| billing.address.city | string | Yes | City, maximum 50 characters. |
| billing.address.state | string | Yes | State/province/region, maximum 50 characters. For US, use a valid two-letter uppercase ISO 3166-2 US subdivision suffix, such as NY or CA. |
| billing.address.postalCode | string | Yes | Postal code, maximum 32 characters. |
Document filenames must belong to files uploaded by the authenticated merchant. Send the filename exactly as returned by the File Upload API. Omit optional document fields when no file is supplied.
For US addresses, New York, US-NY, ny and NYzz are invalid state values. Other countries are not subject to a universal two-character state restriction.
Name Validation
Both name fields must be nonblank and match this pattern:
^[A-Za-z\u00C0-\u00FF\s/\-&:()'.]*$The pattern permits ASCII letters, characters in U+00C0–U+00FF, whitespace and the punctuation shown. Digits, Chinese characters and characters outside this pattern are not accepted.
The combined name, formed as trimmed firstName + one space + trimmed lastName, must not exceed 24 characters, including the separator.
Email Validation
An email already used by another successfully created cardholder under the same merchant cannot be reused. An existing pending creation also reserves its email during creation. Failed creations alone do not prevent a new creation with that email.
Request Example
{
"type": "individual",
"individual": {
"firstName": "Alex",
"lastName": "Morgan",
"birthday": "1990-01-15"
},
"email": "[email protected]",
"billing": {
"address": {
"country": "US",
"line1": "123 Main Street",
"line2": "Unit 3",
"city": "New York",
"state": "NY",
"postalCode": "10001"
}
}
}To provide documents, add idDocFrontPath and idDocBackPath inside individual, using the filenames returned by the File Upload API.
curl
curl --request POST \
'https://api.futurepay-develop.com/api/v1/issuing/cardholder/create' \
--header 'Content-Type: application/json' \
--header 'merchantId: YOUR_MERCHANT_ID' \
--header 'appId: YOUR_APP_ID' \
--header 'authorization: YOUR_SIGNATURE' \
--header 'curTime: YOUR_REQUEST_TIME' \
--data-raw '{"individual":{"firstName":"Alex","lastName":"Morgan","birthday":"1990-01-15"},"email":"[email protected]","billing":{"address":{"country":"US","line1":"123 Main Street","city":"New York","state":"NY","postalCode":"10001"}}}'Generate the signature using the actual request and your assigned signing credentials.
Response Example
{
"code": "0",
"msg": "succeeded",
"serverTime": "1794034703869",
"success": true,
"data": {
"id": "ich_EXAMPLE",
"type": "individual",
"individual": {
"firstName": "Alex",
"lastName": "Morgan",
"birthday": "1990-01-15"
},
"email": "[email protected]",
"billing": {
"address": {
"line1": "123 Main Street",
"line2": "Unit 3",
"city": "New York",
"state": "NY",
"country": "US",
"postalCode": "10001"
}
},
"status": "pending",
"failureReason": null,
"createdAt": "2026-11-07 06:58:23",
"updatedAt": "2026-11-07 06:58:23"
}
}Creation is asynchronous. success: true with status: pending means the request was accepted, rather than that creation has completed. Save the returned id. Receive the final result through a notification or retrieve the cardholder to check its status. Validation failures before acceptance return an error response.
Cardholder Response Object
Creation, update, retrieval and list items use the same cardholder structure.
| Field | Type | Description |
|---|---|---|
| id | string | Cardholder ID used in API paths. |
| type | string | individual. |
| individual | object | Contains firstName, lastName and birthday. |
| string | Cardholder email address. | |
| billing.address | object | Contains line1, line2, city, state, country and postalCode. |
| status | string | pending, active, inactive or create_failed. |
| failureReason | string | Creation failure description when available; null after successful creation. |
| createdAt | string | Creation time, formatted as yyyy-MM-dd HH:mm:ss. |
| updatedAt | string | Last update time, formatted as yyyy-MM-dd HH:mm:ss. |
| Status | Meaning |
|---|---|
| pending | Creation is being processed. Wait for a final result before modifying, activating, deactivating or issuing cards. |
| active | Successfully created and enabled. |
| inactive | Successfully created and disabled. |
| create_failed | Creation failed. Correct the information through the update endpoint using the same ID. |
Retrieve a Cardholder
Endpoint
POST /{id}/detailRequest Example
{}Response
data contains the Cardholder Response Object with the current status and failure reason. A cardholder outside the authenticated merchant is not accessible.
List Cardholders
Endpoint
POST /pagingRequest Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | string | No | Filter by cardholder ID. |
| status | string | No | Filter values: PROCESSING, ACTIVE, IN_ACTIVE, CREATE_FAILED. |
| keyword | string | No | Name or email keyword. |
| startDate | string | No | Creation time lower bound, for example 2026-11-01T00:00:00. |
| endDate | string | No | Creation time upper bound, for example 2026-11-30T23:59:59. |
| pageNum | integer | No | Page number, starting at 1. Defaults to 1 when omitted. |
| pageSize | integer | No | Records per page, from 1 to 100. Defaults to 20 when omitted. |
The current status filter uses the uppercase values above. Response statuses use lowercase values: PROCESSING maps to pending, and IN_ACTIVE maps to inactive. Explicit null pagination values are invalid.
Request Example
{
"status": "ACTIVE",
"pageNum": 1,
"pageSize": 20
}Response
| Field | Type | Description |
|---|---|---|
| data.pageNum | integer | Current page number. |
| data.pageSize | integer | Records per page. |
| data.total | integer | Total matching records. |
| data.totalPage | integer | Total pages. |
| data.list | array | Cardholder Response Objects, with the same fields as the retrieval endpoint. |
Empty result example
{
"code": "0",
"msg": "succeeded",
"serverTime": "1794034703869",
"success": true,
"data": {
"pageNum": 1,
"pageSize": 20,
"total": 0,
"totalPage": 0,
"list": []
}
}Update a Cardholder
Endpoint
POST /{id}Request Parameters
Update uses the same field names and nesting as creation. All business fields are optional; supplied values must satisfy the applicable creation validation rules.
| Parameter | Type | Required | Description |
|---|---|---|---|
| type | string | Yes | Cardholder type. Only individual (personal) is supported. Default value: individual. |
| individual | object | No | Partial personal information update. |
| individual.firstName | string | No | Can change only when creation previously failed. |
| individual.lastName | string | No | Can change only when creation previously failed. |
| individual.birthday | string | No | Valid yyyy-MM-dd date; age must be at least 18. |
| individual.idDocFrontPath | string | No | Uploaded front document filename belonging to this merchant. |
| individual.idDocBackPath | string | No | Uploaded back document filename belonging to this merchant. |
| string | No | Valid email address, maximum 256 characters. | |
| billing.address | object | No | Partial address update using country, line1, line2, city, state, postalCode. |
Except for type, omitted or null fields preserve existing values. An empty body {} returns the current cardholder without changing it. Supplied empty strings are not a substitute for omitted required personal/address fields. The merged address must remain valid, including the US state rule.
After successful creation, first and last names cannot change. If creation failed, information can be corrected and the update retries creation. An unchanged email on an already successful cardholder does not conflict with itself. A changed email, or an update to a failed cardholder, is checked against other successfully created cardholders under the same merchant.
Updates are synchronous. An update failure returns an error and does not send an update-success notification.
Request Example
{
"email": "[email protected]",
"billing": {
"address": {
"line1": "456 Main Street",
"city": "New York",
"state": "NY",
"postalCode": "10002"
}
}
}Response
data contains the updated Cardholder Response Object.
Activate / Deactivate a Cardholder
Endpoints
POST /{id}/activate
POST /{id}/deactivateRequest Example
{}Response
A successful operation returns the common success envelope without a cardholder result object. data may be null or omitted. Retrieve the cardholder to obtain the latest details.
Activating an already active cardholder returns CARDHOLDER_ALREADY_ACTIVE. Deactivating an already inactive cardholder returns CARDHOLDER_ALREADY_INACTIVE. Pending or failed creation states do not permit these operations.
Successful activation and deactivation send an UPDATE_CARDHOLDER_RESULT notification after the operation is committed, with status: "active" or status: "inactive" respectively. Failed operations do not send a success notification.
Set Spending Controls
Endpoint
POST /{id}/controlsCardholder spending limits apply to the combined spending of the cardholder's cards. Card-level controls can impose additional restrictions.
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| limits | array | Yes | Complete spending limit configuration. Use [] to clear limits. Cannot be null. |
| limits[].amount | number | Yes | Amount in USD, minimum 0.01, up to 10 integer digits and 2 decimal places. |
| limits[].interval | string | Yes | per_authorization, daily, weekly, monthly, yearly or all_time. Each interval may appear only once. |
| categories | array | Yes | Complete category configuration. Use [] to clear category rules. Cannot be null. |
| categories[].rule | string | Yes | allow or deny. The two modes cannot be mixed in one configuration. |
| categories[].mcc | array of strings | Yes | Non-empty list of supported four-digit MCC codes. Preserve leading zeros, for example 0742. Each code must exist in the service's MCC reference list. |
Both arrays must be supplied, even if only one part changes. This endpoint replaces the complete configuration, rather than merging it. Array items cannot be null. Currency is fixed to USD by the service; do not send a currency field.
Request Example
{
"limits": [
{
"amount": 5000.00,
"interval": "monthly"
},
{
"amount": 500.00,
"interval": "daily"
}
],
"categories": [
{
"rule": "deny",
"mcc": ["0742", "7311"]
}
]
}Response Example
{
"code": "0",
"msg": "succeeded",
"serverTime": "1794034703869",
"success": true,
"data": {
"limits": [
{"amount": 5000.00, "interval": "monthly", "currency": "USD"},
{"amount": 500.00, "interval": "daily", "currency": "USD"}
],
"categories": [
{"rule": "deny", "mcc": ["0742", "7311"]}
]
}
}Clear All Controls
{
"limits": [],
"categories": []
}{} is invalid for this endpoint because both fields are required.
Retrieve Spending Controls
Endpoint
POST /{id}/controls/detailRequest Example
{}Response
data has the same structure as the Set Spending Controls response: limits and categories. Every returned limit includes currency: "USD". Empty configurations return empty arrays.
Result Notifications
Configure your merchant notification URL during integration. Result notifications are sent to that URL using the Futurepay notification signing protocol. Verify signatures according to that protocol; file-upload Bearer authentication does not apply to notifications.
| Event Code | Sent When |
|---|---|
| CREATE_CARDHOLDER_RESULT | Asynchronous creation completes with active or create_failed. |
| UPDATE_CARDHOLDER_RESULT | An information update, successful retry of failed creation, activation or deactivation completes successfully. Failed operations and empty updates do not send this notification. |
Cardholder status changes also send UPDATE_CARDHOLDER_RESULT, regardless of whether the operation was performed through the API or merchant console. Use the notification's id and status to refresh your records.
Notification Parameters
| Field | Type | Description |
|---|---|---|
| merchantId | string | Merchant receiving the notification. |
| appId | string | Application associated with the operation. |
| notificationItems | array | Notification items. |
| notificationItems[].eventCode | string | Event code from the table above. |
| notificationItems[].eventDate | integer | Event timestamp in milliseconds. |
| notificationItems[].id | string | Cardholder ID. |
| notificationItems[].status | string | Cardholder status. |
| notificationItems[].failureReason | string | Creation failure description, or null. |
Notification Example
{
"merchantId": "1929723739654762496",
"appId": "1929723739684102144",
"notificationItems": [
{
"eventCode": "CREATE_CARDHOLDER_RESULT",
"eventDate": 1794034703869,
"id": "ich_EXAMPLE",
"status": "create_failed",
"failureReason": "Cardholder creation failed: Invalid US state or province"
}
]
}Handle notifications idempotently and retrieve current details when reconciling state. A notification may arrive before the original HTTP response. Different successful updates can have the same cardholder ID and status; that pair is not a unique update identifier. If no notification arrives, query the saved ID before attempting another creation.
Error Codes
| Code | Description |
|---|---|
| 400 | Invalid request parameters or JSON field types. Read msg for the affected field and validation rule. |
| 404 | Interface not found. Check both the path and HTTP method. |
| API_APP_ID_INVALID | Application is not valid for the authenticated merchant. |
| VCC_PRODUCT_NOT_ENABLED | VCC product capability is not enabled. |
| CARDHOLDER_NOT_FOUND | Cardholder is not available under the authenticated merchant. |
| CARDHOLDER_ALREADY_EXISTS | The email is already reserved or used by another applicable cardholder under this merchant. |
| CARDHOLDER_BILLING_COUNTRY_NOT_ALLOWED | Billing country is not supported. |
| CARDHOLDER_BILLING_US_STATE_INVALID | US billing state is not a valid two-letter uppercase subdivision suffix. |
| CARDHOLDER_NAME_NOT_EDITABLE | Names cannot change after successful creation. |
| CARDHOLDER_STATUS_INVALID | Current cardholder status does not permit the operation. |
| CARDHOLDER_ALREADY_ACTIVE | Cardholder is already active. |
| CARDHOLDER_ALREADY_INACTIVE | Cardholder is already inactive. |
| CARDHOLDER_UPDATE_SYNC_FAILED | Cardholder update failed. |
| CARDHOLDER_CONTROL_UPDATE_FAILED | Spending controls update failed. |
| CARDHOLDER_LIMIT_INTERVAL_DUPLICATE | A limit interval appears more than once. |
Error Response Example
{
"code": "CARDHOLDER_ALREADY_EXISTS",
"msg": "A cardholder has already been successfully created with this email: [email protected]",
"serverTime": "1794034703869",
"success": false
}After an accepted asynchronous creation fails, its final state is available through notifications and retrieval as status: "create_failed" with failureReason. Keep the cardholder ID to correct and retry through the update endpoint.
Updated about 5 hours ago