Skip to main content
POST
/
v2
/
partner
/
card
/
users
curl -X POST https://services-staging.getplu.com/api/v2/partner/card/users \
  -H "Authorization: Bearer sk_staging_your_api_key" \
  -H "Content-Type: application/json" \
  -H "idempotency-key: 550e8400-e29b-41d4-a716-446655440000" \
  -d '{
    "firstName": "Jane",
    "lastName": "Doe",
    "email": "[email protected]",
    "phoneNumber": "+14155555555",
    "accountPurpose": "personal use",
    "ipAddress": "203.0.113.42",
    "isTermsOfServiceAccepted": true,
    "program": "custodial",
    "address": "123 Main Street",
    "city": "San Francisco",
    "region": "CA",
    "postalCode": "94105",
    "countryCode": "US"
  }'
{
  "status": "success",
  "message": "User created successfully",
  "data": {
    "serviceId": "acme-user-abc123def456ghi",
    "verificationUrl": "https://withpersona.com/verify?inquiry-id=inq_abc123..."
  }
}

Documentation Index

Fetch the complete documentation index at: https://docs.getplu.com/llms.txt

Use this file to discover all available pages before exploring further.

Creates a new user and initiates KYC verification through Persona. Returns a verificationUrl where the user completes identity verification. This is the v2 flow using Persona for KYC — it requires fewer fields than the legacy v1 endpoint and provides a smoother verification experience.
Authorization
string
required
Bearer token. Example: Bearer sk_staging_your_api_key
idempotency-key
string
required
Unique key to prevent duplicate user creation. Use a UUID.
firstName
string
required
User’s first name. 1-100 characters.
lastName
string
required
User’s last name. 1-100 characters.
email
string
required
User’s email address. Must be unique across your partner account.
phoneNumber
string
required
International phone number. Example: +14155555555
accountPurpose
string
required
Purpose of the account. 1-200 characters. Example: personal use, business expenses.
ipAddress
string
required
User’s IP address at the time of registration.
isTermsOfServiceAccepted
boolean
required
Must be true. Confirms the user has accepted the terms of service.
program
string
required
Card program type. Either custodial or non_custodial.
walletAddress
string
Ethereum wallet address. Required if program is non_custodial.
redirectUrl
string
HTTPS URL to redirect the user after Persona verification. Overrides the default redirect URL set in your profile.
address
string
required
User’s street address. 1-500 characters. Example: 123 Main Street.
city
string
required
User’s city. 1-100 characters.
region
string
required
User’s state or region. 1-100 characters. Example: CA, Lagos.
postalCode
string
required
User’s postal/zip code. 1-20 characters.
countryCode
string
required
ISO 3166-1 alpha-2 country code of the user’s country of residence. Example: US, KE, NG.
curl -X POST https://services-staging.getplu.com/api/v2/partner/card/users \
  -H "Authorization: Bearer sk_staging_your_api_key" \
  -H "Content-Type: application/json" \
  -H "idempotency-key: 550e8400-e29b-41d4-a716-446655440000" \
  -d '{
    "firstName": "Jane",
    "lastName": "Doe",
    "email": "[email protected]",
    "phoneNumber": "+14155555555",
    "accountPurpose": "personal use",
    "ipAddress": "203.0.113.42",
    "isTermsOfServiceAccepted": true,
    "program": "custodial",
    "address": "123 Main Street",
    "city": "San Francisco",
    "region": "CA",
    "postalCode": "94105",
    "countryCode": "US"
  }'
{
  "status": "success",
  "message": "User created successfully",
  "data": {
    "serviceId": "acme-user-abc123def456ghi",
    "verificationUrl": "https://withpersona.com/verify?inquiry-id=inq_abc123..."
  }
}

After User Creation

  1. Redirect the user to the verificationUrl to complete Persona KYC
  2. After verification, the user is redirected to your configured redirect URL with ?referenceId={serviceId}
  3. Listen for KYC webhook events to know when the user is approved
  4. Once approved (user.kyc.approved), you can create a card for the user

Sandbox Testing

In the staging environment, you can control the KYC outcome by appending a keyword to the user’s lastName field. This lets you test each scenario without going through real identity verification.
Keyword in lastNameKYC OutcomeExample lastName
ApprovedKYC approved — user can create cardsDoeApproved
DeniedKYC deniedDoeDenied
needsVerificationAdditional verification requiredDoeneedsVerification
The keyword is case-sensitive and must be appended to the end of the last name with no spaces or separators.

Example Webhook Payloads

Approved
{
  "event": "user.kyc-event",
  "timestamp": "2026-02-19T20:49:29.927Z",
  "data": {
    "serviceId": "acme-user-7mFQc5aCslAWtkd",
    "status": "approved",
    "email": "[email protected]",
    "firstName": "Jane",
    "lastName": "DoeApproved"
  }
}
Denied
{
  "event": "user.kyc-event",
  "timestamp": "2026-02-19T21:01:49.217Z",
  "data": {
    "serviceId": "acme-user-yvDaVMdFaug51H4",
    "status": "denied",
    "email": "[email protected]",
    "firstName": "Jane",
    "lastName": "DoeDenied",
    "reason": "WRONG_USER_REGION, REGULATIONS_VIOLATIONS"
  }
}
Needs Verification
{
  "event": "user.kyc-event",
  "timestamp": "2026-02-19T21:02:49.083Z",
  "data": {
    "serviceId": "acme-user-G9KZgnhgbndDdJg",
    "status": "needsVerification",
    "email": "[email protected]",
    "firstName": "Jane",
    "lastName": "DoeneedsVerification",
    "verificationLink": "https://kyc.getplu.com/verify?userId=e5508685-2771-48fd-8cbc-c8c3e6df9179"
  }
}
verificationLink is only present on needsVerification events. reason is only present on denied events and contains one or more comma-separated denial codes.