Appearance
Onboard a cardholder
Create a customer organization, provision the cardholder's identity, collect agreement acceptance, and submit an application. Issue a card after the application is approved.
Provision a customer organization
The customer organization groups cardholders you manage. It is separate from your partner organization, which the API derives from your key.
graphql
mutation CreateCustomer($input: CreatePartnerCustomerOrganizationInput!) {
createPartnerCustomerOrganization(input: $input) {
success
organizationId
error
}
}json
{ "input": { "name": "Acme Corp" } }Store organizationId after success: true. This operation has no idempotency key; do not repeat it blindly if the response is lost.
Provision a cardholder
Send the identity and contact details collected through your onboarding flow. addressCountryCode is an ISO 3166 alpha-2 code; phone fields contain digits and birthDate uses YYYY-MM-DD.
graphql
mutation CreateCardholder($input: CreatePartnerCardUserInput!) {
createPartnerCardUser(input: $input) {
success
cardUserId
reused
errorCode
errorMessage
}
}json
{
"input": {
"customerOrganizationId": "<organizationId>",
"firstName": "Alice",
"lastName": "Tester",
"email": "[email protected]",
"addressLine1": "1 Main St",
"addressCity": "Brooklyn",
"addressRegion": "NY",
"addressPostalCode": "11201",
"addressCountryCode": "US",
"phoneCountryCode": "1",
"phoneNumber": "5551234567",
"birthDate": "1990-01-15",
"nationalId": "<cardholder national identifier>"
}
}Store the returned cardUserId for the application. Provisioning is idempotent on (customerOrganizationId, email): the same pair returns the existing identifier with reused: true. Repeating the call does not update the stored profile.
All identity fields above are required. Blank fields, an invalid birth date, or an invalid country code return success: false with errorCode: "VALIDATION_ERROR" and details in errorMessage. Agio encrypts nationalId at rest and decrypts it when forwarding identity to the card processor.
Correct details before applying
patchPartnerCardUser changes supplied identity fields and keeps omitted fields. It accepts the provisioning fields except email and customerOrganizationId. The email is the provisioning idempotency key; the organization comes from the existing record.
graphql
mutation CorrectCardholder($input: PatchPartnerCardUserInput!) {
patchPartnerCardUser(input: $input) {
success
errorCode
errorMessage
}
}json
{
"input": {
"cardUserId": "<provisioned cardUserId>",
"addressLine1": "2 Main St",
"addressCity": "Brooklyn",
"addressRegion": "NY",
"addressPostalCode": "11201",
"addressCountryCode": "US"
}
}The merged address must remain complete. After an application exists for this cardholder, the mutation returns APPLICATION_ALREADY_SUBMITTED. Use this correction step before submitting, including when an application attempt returns INCOMPLETE_ADDRESS.
Collect agreement acceptance
Present the applicable card agreements to the cardholder before submitting their application. Record what they accepted, its version and hashes, and when they accepted it. agreementsAcceptance is required; isTermsOfServiceAccepted: true is also required and does not replace the evidence.
Use the agreement set Agio supplies for your configured card program and jurisdiction. Confirm the applicable document keys during integration setup; the customer organization used to scope API records does not determine the legal agreement set.
| Document key | Raw agreement |
|---|---|
card-terms-us | US card terms |
account-opening-privacy-us | US account-opening privacy notice |
card-terms-international | International card terms |
card-terms-us-b2b | US business card terms |
card-terms-international-b2b | International business card terms |
authorized-user-agreement | Authorized user agreement |
Fetch each applicable raw Markdown document and hash the response bytes with SHA-256. Do not normalize whitespace or re-encode the text before hashing. Present that same text to the cardholder and send its lowercase hex hash. Confirm the current agreement-set version with Agio when configuring your integration.
bash
curl -fsS https://www.agiodigital.com/agio-digital-ltd-card-terms-us-program.md -o card-terms-us.md
shasum -a 256 card-terms-us.md| Acceptance field | Value |
|---|---|
agreementVersion | Published agreement-set version |
documentHashes | One { key, sha256 } for each applicable document |
acceptedAt | ISO 8601 timestamp from your acceptance record |
endUserIpAddress | Optional cardholder IP when accepting |
endUserAgent | Optional cardholder browser or application user agent when accepting |
The end-user IP is the cardholder's address at acceptance, not your API server's IP. acceptedAt is your attestation; Agio records a separate server receipt time and retains consent evidence for five years. Missing evidence returns ATTESTATION_REQUIRED; invalid evidence returns a validation error. Correct the evidence before retrying.
Submit an application
Choose exactly one collateral-admin option:
createWallet: trueuses your configured partner treasury as the collateral admin for this cardholder. It does not create a separate personal wallet. Your treasury must be configured by Agio first.walletAddresssupplies an EVM address whose owner will administer the collateral. Partner treasury withdrawal cannot sign for a customer's self-custody address.
graphql
mutation Apply($input: CreatePartnerCardApplicationInput!) {
createCardApplicationForPartnerUser(input: $input) {
success
applicantId
cardApplicationId
cardApplicationExternalId
applicationStatus
applicationCompletionUrl
walletAddress
errorCode
error
}
}json
{
"input": {
"cardUserId": "<provisioned cardUserId>",
"createWallet": true,
"occupation": "Software Developers",
"annualSalary": "100000",
"accountPurpose": "Business expenses",
"expectedMonthlyVolume": "5000",
"isTermsOfServiceAccepted": true,
"agreementsAcceptance": {
"agreementVersion": "<published agreement-set version>",
"documentHashes": [
{ "key": "card-terms-us", "sha256": "<SHA-256 of presented US terms>" },
{ "key": "account-opening-privacy-us", "sha256": "<SHA-256 of presented privacy notice>" }
],
"acceptedAt": "2026-10-04T06:00:00.000Z",
"endUserIpAddress": "203.0.113.7",
"endUserAgent": "PartnerApp/2.4"
}
}
}The agreement keys above illustrate a US document set; replace them with the keys and hashes Agio supplies for your program. occupation accepts a supported SOC code or description; see occupation codes.
If your Sumsub workspace is registered with Agio, you can also supply a fresh partnerKycShareToken. Arrange that integration with Agio before using it. Agio uses the token in the KYC handover and still forwards the provisioned identity. An expired, used, invalid or ineligible token returns KYC_TOKEN_EXPIRED ("KYC share-token has expired. Please retry with a fresh token."); mint a fresh token for Agio as the recipient. Only Sumsub tokens are supported; other providers return KYC_PROVIDER_NOT_SUPPORTED. Workspace problems return KYC_WORKSPACE_NOT_AUTHORIZED. Without a share token, the stored identity is used directly.
Identifiers
| Identifier | Use |
|---|---|
Provisioned cardUserId / response applicantId | Submit the application and identify your provisioned applicant |
cardApplicationId | Numeric AgioCard_card_application.id; query the application and pass it to createCard |
cardApplicationExternalId | The same UUID as your provisioned cardUserId, stored as card_application_external_id |
Application, card and transaction card_user_id | The same UUID as your provisioned cardUserId; use it for balance, funding and withdrawal calls |
Your provisioned cardUserId identifies the cardholder on the application, its cards and its transactions, and it does not change. Partner-issued cards have no Agio user_id; their customer organization and card company provide the ownership scope.
Check application status
Query by the numeric ID returned on application creation. Its card_user_id is your provisioned cardUserId.
graphql
query ApplicationStatus($applicationId: Int!) {
AgioCard_card_application(where: { id: { _eq: $applicationId } }, limit: 1) {
id
applicant_id
card_application_external_id
card_user_id
application_status
application_completion_link
deposit_address
deposit_chain_id
updated_at
}
}json
{ "applicationId": 42 }Poll at a modest interval, such as once a minute, or use application webhooks. This is client guidance, not a guaranteed per-application polling limit.
| Status | Action |
|---|---|
PENDING | Wait for verification and provisioning |
NEEDSINFORMATION, NEEDSVERIFICATION | Give the signed completion link to the cardholder |
MANUALREVIEW | Wait for compliance review |
APPROVED, ACTIVE | Create a card when issuer cardholder data is ready |
DENIED, CANCELED | Stop issuance; contact Agio if the decision needs review |
For NEEDSINFORMATION, completionUrl is the link to give the cardholder and nextStep is AWAIT_REVIEW. After the cardholder finishes, watch for card_application.status_changed. No resubmit call is needed. For declines, treat nextStep: TERMINAL as final and RESUBMIT as retryable.
applicationCompletionUrl from the mutation and webhook completionUrl are composed signed links: open them as returned. In application_completion_link, prefer completionUrl when present. Older records may contain url with a params object; append every parameter to the URL. If there are no parameters, use url. Stripping the signature or rebuilding a link from a cardholder ID prevents verification.
If the application request times out before you receive an ID, query AgioCard_card_application with where: { applicant_id: { _eq: "<provisioned cardUserId>" } } before retrying. Application creation does not supply an idempotency key.
Next: Create and manage cards.