Overview

Provider W cards require a cardholder before a card can be issued. The cardholder goes through a two-stage approval:

  1. PayCA review — cardholder is created with pending_review status and must be approved by a PayCA admin.
  2. Provider audit — after PayCA approves, the cardholder is submitted to Provider W and moves through wait_auditpass_audit (or reject).

Only cardholders with status: "pass_audit" can be used to issue cards.


Cardholder Statuses

Status Meaning
pending_review Created, waiting for PayCA admin approval.
rejected_by_admin Rejected by PayCA admin (see description for reason).
wait_audit Submitted to Provider W, waiting for provider audit.
under_review Provider W is reviewing the cardholder.
pass_audit Approved — ready for card issuance.
reject Rejected by Provider W (see description and statusFlowLocation).

B2B Flow

B2B cardholders require basic personal data only. No KYC documents are needed — file IDs are uploaded manually via the file upload endpoint.

Step 1 — Create user

curl -s -X POST "$PAYCA_BASE_URL/v1/users" \
  -H 'Content-Type: application/json' \
  -H "x-client-id: $PAYCA_CLIENT_ID" \
  -H "x-client-secret: $PAYCA_CLIENT_SECRET" \
  -d '{
    "externalId": "usr-001",
    "meta": {
      "firstName": "John",
      "lastName": "Doe",
      "email": "john@example.com",
      "phone": "5551234567",
      "phoneCode": "+1",
      "birthday": "1990-01-15",
      "country": "US",
      "town": "NYC",
      "address": "123 Main St",
      "postCode": "10001"
    }
  }'

Use /v1/cardholders/regions for country codes and /v1/cardholders/cities for town codes.

Step 2 — Upload identity documents (optional, B2B only)

curl -s -X POST "$PAYCA_BASE_URL/v1/cardholders/files" \
  -H "x-client-id: $PAYCA_CLIENT_ID" \
  -H "x-client-secret: $PAYCA_CLIENT_SECRET" \
  -F "file=@passport_front.jpg"

Save the returned fileId values and include them in the user meta as idFrontImg, idBackImg, idHoldImg.

Step 3 — Create cardholder

curl -s -X POST "$PAYCA_BASE_URL/v1/users/{userId}/cardholder" \
  -H 'Content-Type: application/json' \
  -H "x-client-id: $PAYCA_CLIENT_ID" \
  -H "x-client-secret: $PAYCA_CLIENT_SECRET" \
  -d '{
    "accountId": "<account-uuid>",
    "bin": "537100"
  }'

Response returns a CardholderResponse with status: "pending_review".

Step 4 — Wait for approval

Poll GET /v1/cardholders/{id} until status changes:

  • pass_audit — proceed to card issuance.
  • rejected_by_admin — rejected by PayCA; check description for the reason.
  • reject — rejected by Provider W; check description and statusFlowLocation.

Step 5 — Issue card

curl -s -X POST "$PAYCA_BASE_URL/v1/cards" \
  -H 'Content-Type: application/json' \
  -H "x-client-id: $PAYCA_CLIENT_ID" \
  -H "x-client-secret: $PAYCA_CLIENT_SECRET" \
  -d '{
    "accountId": "<account-uuid>",
    "bin": "537100",
    "balance": "100.00",
    "idempotencyKey": "issue-001",
    "cardholderId": "<cardholder-uuid>"
  }'

3DS OTP codes are sent to the cardholder's email and phone.


B2C Flow

B2C cardholders require extended personal data and completed KYC verification. KYC documents are uploaded automatically from the KYC system when the cardholder is submitted to Provider W.

Step 1 — Create user

Include all B2B fields plus B2C-specific fields:

curl -s -X POST "$PAYCA_BASE_URL/v1/users" \
  -H 'Content-Type: application/json' \
  -H "x-client-id: $PAYCA_CLIENT_ID" \
  -H "x-client-secret: $PAYCA_CLIENT_SECRET" \
  -d '{
    "externalId": "usr-002",
    "meta": {
      "firstName": "Jane",
      "lastName": "Smith",
      "email": "jane@example.com",
      "phone": "5559876543",
      "phoneCode": "+1",
      "birthday": "1988-05-20",
      "gender": "F",
      "idType": "PASSPORT",
      "idNo": "AB1234567",
      "nationality": "US",
      "country": "US",
      "town": "LAX",
      "address": "456 Oak Ave",
      "postCode": "90001",
      "occupation": "IT"
    }
  }'

Use /v1/cardholders/occupations for occupation codes.

Step 2 — KYC verification

Upload identity documents and a selfie, then submit for review. Documents are sent as base64-encoded JSON (not multipart). Max 10 MB decoded per file.

# Helper — base64-encode a file and POST it
upload_kyc() {
  local USER_ID="$1" DOC_TYPE="$2" FILE="$3"
  local CONTENT=$(base64 < "$FILE" | tr -d '\n')
  curl -s -X POST "$PAYCA_BASE_URL/v1/users/$USER_ID/kyc/documents" \
    -H 'Content-Type: application/json' \
    -H "x-client-id: $PAYCA_CLIENT_ID" \
    -H "x-client-secret: $PAYCA_CLIENT_SECRET" \
    -d "{
      \"documentType\": \"$DOC_TYPE\",
      \"fileName\":     \"${FILE##*/}\",
      \"fileContent\":  \"$CONTENT\",
      \"mimeType\":     \"image/jpeg\"
    }"
}

upload_kyc "$USER_ID" passport             passport.jpg
upload_kyc "$USER_ID" selfie_with_document selfie.jpg

# Submit KYC for review
curl -s -X POST "$PAYCA_BASE_URL/v1/users/$USER_ID/kyc/submit" \
  -H "x-client-id: $PAYCA_CLIENT_ID" \
  -H "x-client-secret: $PAYCA_CLIENT_SECRET"

Valid documentType values: passport, driving_licence, id_card, residence_permit, proof_of_address, selfie_with_document.

Wait for status: "completed" on GET /v1/users/{userId}/kyc (or subscribe to the kyc webhook) before proceeding.

Step 3 — Create cardholder

Same as B2B Step 3. KYC must be completed — the endpoint rejects requests if KYC is not completed.

Step 4 — Wait for approval

Same as B2B Step 4. After PayCA admin approves, KYC documents are automatically uploaded to Provider W.

Step 5 — Issue card

Same as B2B Step 5 — pass the cardholderId in the card creation request.


Issuing Cards Without a Cardholder

If the BIN has a default holder configured (providerDefaultHolderId in BIN settings), cards can be issued without creating a cardholder first. The system resolves the holder using this priority:

  1. Explicit cardholderId in the request (must be pass_audit).
  2. User's approved cardholder for the card type.
  3. Default holder from BIN settings.

This allows card issuance to work while a cardholder is still going through the approval process.


Required User Meta Fields

B2B (minimum)

Field Type Description
firstName string First name.
lastName string Last name.
email string Email address.
phone string Phone number (digits only).
phoneCode string Country dial code (e.g. +1). Normalized to include + prefix.
birthday string Date of birth (YYYY-MM-DD).
country string Country code (from /v1/cardholders/regions).
town string City code (from /v1/cardholders/cities).
address string Street address.
postCode string Postal code.

B2C (additional)

Field Type Description
gender string M or F.
idType string Document type: PASSPORT, DLN, etc.
idNo string Document number.
nationality string Nationality code (from /v1/cardholders/regions).
occupation string Occupation code (from /v1/cardholders/occupations).

Optional fields (B2B and B2C)

Field Type Description
idIssueDate string Document issue date.
idExpiryDate string Document expiry date.
idFrontImg string File ID of document front (B2B only, via /v1/cardholders/files).
idBackImg string File ID of document back (B2B only).
idHoldImg string File ID of selfie holding document (B2B only).
annualSalary string Annual salary range.
accountPurpose string Purpose of account.
expectedMonthlyVolume string Expected monthly transaction volume.
ipAddress string User's IP address.

API Endpoints Reference

Method Endpoint Description
POST /v1/users/{id}/cardholder Create cardholder for a user.
GET /v1/users/{id}/cardholder Get cardholder status for a user.
GET /v1/cardholders List all cardholders for the client.
GET /v1/cardholders/{id} Get cardholder by ID.
GET /v1/cardholders/cities List city codes for registration.
GET /v1/cardholders/occupations List occupation codes (B2C).
GET /v1/cardholders/regions List country/region codes.
POST /v1/cardholders/{id}/photos Upload passport photo and/or selfie for admin review (multipart/form-data).
POST /v1/cardholders/files Upload file for B2B cardholder registration.

Error Handling

Error Cause Resolution
cardholder requires user meta fields: ... Missing required fields in user meta. Update user meta with the listed fields.
B2C cardholder requires user meta fields: ... Missing B2C-specific fields. Add gender, idType, idNo, nationality, occupation.
bin does not support provider w cardholders BIN has no cardholder type configured for Provider W. Use a BIN that supports Provider W cardholders.
KYC must be completed before creating a B2C cardholder KYC not finished. Complete KYC verification first.
cardholder not approved (status: ...) Cardholder passed to card issuance is not pass_audit. Wait for cardholder approval.