Skip to main content
This guide walks through the complete individual user onboarding flow using the REST API — from creating the user to confirming their capabilities are unlocked.

Prerequisites

  • API client credentials with permission to create users and manage KYC.

The flow

Retrieve Terms of Service

Before creating a user, retrieve the general Terms of Service applicable to their country of residence by calling the List terms of service endpoint with type=general and the user’s country code.
GET /core/terms-of-service?type=general&country={country}
Display the Terms of Service content to the user and record their acceptance.

Create the user

Once the user has accepted the Terms of Service, call Create user to register them on the platform.
The X-Uphold-User-Ip user context header is mandatory when creating a user, as it records the user’s IP address at the time of Terms of Service acceptance.
POST /core/users
{
  "type": "individual",
  "email": "[email protected]",
  "citizenshipCountry": "GB",
  "country": "GB",
  "subdivision": "GB-MAN",
  "termsOfService": "general-gb-fca"
}
A successful response returns the created user’s information.
Response
{
  "user": {
    "id": "cd21b26d-35d2-408a-9201-b8fdbef7a604",
    "type": "individual",
    "email": "[email protected]",
    "citizenshipCountry": "GB",
    "address": {
      "country": "GB",
      "subdivision": "GB-MAN"
    },
    "createdAt": "2024-03-13T20:20:39Z",
    "updatedAt": "2024-03-13T20:20:39Z"
  }
}
You can optionally include custom entity metadata in the metadata field to store your own business data (e.g. external IDs or tracking parameters). Subscribe to the core.user.created webhook to be notified asynchronously.

Check required processes

The KYC processes required for a user are determined by the Terms of Service they accepted at registration — different ToS codes map to different regulatory regimes with different requirements. After creating the user, call Get KYC overview to see the full list of applicable processes and their current statuses.
GET /core/kyc
A successful response returns the list of processes with their statuses. Initially, all processes will typically be in pending status, indicating they are waiting for the user to provide information.
Response
{
  "email": { "status": "pending" },
  "phone": { "status": "pending" },
  "profile": { "status": "pending" },
  "address": { "status": "pending" },
  "identity": { "status": "pending" },
  "proofOfAddress": { "status": "pending" },
  "customerDueDiligence": { "status": "pending" },
  "enhancedDueDiligence": { "status": "exempt" },
  "cryptoRiskAssessment": { "status": "exempt" },
  "selfCategorizationStatement": { "status": "exempt" },
  "taxDetails": { "status": "pending" },
  "screening": { "status": "pending" },
  "risk": { "status": "pending" }
}
Processes with status: "exempt" are not required for this user’s region. See the KYC processes overview for the full requirements matrix per ToS.

Complete KYC processes

ProcessCategory
email, phoneDirect submission
profileForm-based
addressDirect submission
identityFile-based
proofOfAddressFile-based
customerDueDiligenceForm-based
enhancedDueDiligenceFile-based
cryptoRiskAssessmentForm-based
selfCategorizationStatementForm-based
taxDetailsForm-based
screening, riskBackground (automatic)
Check the submission order dependencies and the KYC introduction for how form-based, file-based, and background processes work.

Email and phone

Verify the user’s email and phone number.
Call Update email and Update phone with input containing the email address and phone number, respectively, and output containing the verification datetime.
PATCH /core/kyc/processes/email
{
  "input": {
    "email": "[email protected]"
  },
  "output": {
    "verifiedAt": "2025-01-29T10:32:00Z"
  }
}
A successful response returns the submitted information with an ok status.
Response
{
  "status": "ok",
  "input": {
    "email": "[email protected]"
  },
  "output": {
    "verifiedAt": "2025-01-29T10:32:00Z"
  }
}

Profile

Declare the user’s personal information, such as their name, date of birth, and citizenship. Call Update profile with input.details containing the relevant fields.
Profile is a form-based process — the required fields may vary based on the user’s region and other factors. Always check the returned hint object for the specific schema to display. See Dynamic forms for guidance on rendering the form and submitting the data.
PATCH /core/kyc/processes/profile
{
  "input": {
    "details": {
      "fullName": "John Doe",
      "primaryCitizenship": "GB",
      "birthdate": "1987-01-01"
    }
  }
}
A successful response always includes a hint object with the form schema and UI schema — even when status is ok — so the user can update their information later.
Response
{
  "profile": {
    "status": "ok",
    "input": {
      "details": {
        "fullName": "John Doe",
        "primaryCitizenship": "GB",
        "birthdate": "1987-01-01"
      }
    },
    "hint": {
      "type": "form",
      "schema": {
        "type": "object",
        "properties": { /* ... */ }
      },
      "uiSchema": {
        "type": "Categorization",
        "elements": [ /* ... */ ]
      }
    }
  }
}

Address

Declare the user’s residential address. Call Update address with input containing the address fields.
PATCH /core/kyc/processes/address
{
  "input": {
    "country": "GB",
    "city": "Manchester",
    "line1": "1 High Street",
    "postalCode": "M4 1AA"
  }
}
A successful response returns the submitted information with an ok status.
Response
{
  "address": {
    "status": "ok",
    "input": {
      "address": {
        "country": "GB",
        "subdivision": "GB-MAN",
        "city": "Manchester",
        "line1": "1 High Street",
        "line2": "Northern Quarter",
        "postalCode": "M4 1AA"
      }
    }
  }
}

Identity

Verify that the user is the person they claim to be.
Your organization performs identity verification through an already-approved method and submits the result to Uphold.Two sub-types are supported:
1

Create files

Call Create file for each document to obtain an upload URL.
POST /core/files
{
  "category": "image",
  "contentType": "image/png"
}
A successful response returns an upload object with a presigned URL and form data for uploading the file to the provided storage service.
Response
{
  "file": {
    "id": "38cce774-b225-41ed-a9fd-f9c9777a13de",
    "status": "pending",
    "category": "image",
    "contentType": "image/png",
    "upload": {
      "url": "https://example.com/upload",
      "formData": {
        "X-Amz-Algorithm": "AWS4-HMAC-SHA256",
        "X-Amz-Credential": "ASIE4FQORBNQHNQD5CG6/20240801/us-east-1/s3/aws4_request",
        "X-Amz-Date": "20240801T102500Z",
        "X-Amz-Security-Token": "IQoJb3JpZ2luX2VjEIv//////////...JBr6h2HkzH/aFSArQcs=",
        "X-Amz-Signature": "b4da8cf1a59327988a8108c965a4789fc8ba2d20f5bffda076106b2b254def29",
        "Key": "4c13b6f5-987e-43df-bc12-042b58307a80",
        "Policy": "eyJjb25kaXRpb25zIjpbeyJidWN...TA6MjU6MDAuMjAyWiJ9"
      },
      "expiresAt": "2024-03-13T20:20:39Z"
    }
  }
}
2

Upload the file

Upload the file to the provided upload.url using the returned upload.formData fields as multipart form parameters.
3

Submit the process

Call Update identity, referencing the file IDs in input.media and setting output to the verification results from your provider.
PATCH /core/kyc/processes/identity
{
  "type": "document-submission",
  "input": {
    "media": [
      { "context": "photo-document-front", "fileId": "470b2192-893f-4ce6-9daa-816d4c319a84" },
      { "context": "photo-selfie", "fileId": "5d3a1c72-bd4f-4e2a-a123-9f8765432100" }
    ]
  },
  "output": {
    "provider": "veriff",
    "document": {
      "type": "passport",
      "number": "7700225VH",
      "country": "GB",
      "expiresAt": "2026-03-13"
    },
    "person": {
      "givenName": "John",
      "familyName": "Doe",
      "birthdate": "1987-01-01",
      "gender": "male"
    },
    "verifiedAt": "2025-01-29T10:36:00Z"
  }
}
A successful response returns the submitted information with an ok status.
Response
{
  "status": "ok",
  "type": "document-submission",
  "input": {
    "media": [
      { "context": "photo-document-front", "fileId": "470b2192-893f-4ce6-9daa-816d4c319a84" },
      { "context": "photo-selfie", "fileId": "5d3a1c72-bd4f-4e2a-a123-9f8765432100" }
    ]
  },
  "output": {
    "provider": "veriff",
    "document": {
      "type": "passport",
      "number": "7700225VH",
      "country": "GB",
      "expiresAt": "2026-03-13"
    },
    "person": {
      "givenName": "John",
      "familyName": "Doe",
      "birthdate": "1987-01-01",
      "gender": "male"
    },
    "verifiedAt": "2025-01-29T10:36:00Z"
  }
}
Your organization performs electronic identity verification through an already-approved provider that checks the user’s declared information against public and third-party records, without requiring physical documents, and submits the result to Uphold. Call Update identity, populating input.data with the user’s declared information and output with the provider and verification datetime.
PATCH /core/kyc/processes/identity
{
  "type": "electronic-verification",
  "input": {
    "data": {
      "givenName": "John",
      "familyName": "Doe",
      "birthdate": "1987-01-01",
      "citizenshipCountry": "GB",
      "address": {
        "country": "GB",
        "city": "Manchester",
        "line1": "1 High Street",
        "postalCode": "M4 1AA"
      }
    }
  },
  "output": {
    "provider": "onfido",
    "verifiedAt": "2025-01-29T10:36:00Z"
  }
}
A successful response returns the submitted information with an ok status.
Response
{
  "status": "ok",
  "type": "electronic-verification",
  "input": {
    "data": {
      "givenName": "John",
      "familyName": "Doe",
      "birthdate": "1987-01-01",
      "citizenshipCountry": "GB",
      "address": {
        "country": "GB",
        "city": "Manchester",
        "line1": "1 High Street",
        "postalCode": "M4 1AA"
      }
    }
  },
  "output": {
    "provider": "onfido",
    "verifiedAt": "2025-01-29T10:36:00Z"
  }
}
This type does not unblock the same capabilities as document submission. See the comparison table for details.

Proof of address

Verify the user’s residential address. The process may already be ok without a submission in certain scenarios — see Proof of address conditions for details.
Your organization performs proof-of-address verification through a contracted provider and submits the result to Uphold.Two sub-types are supported:
1

Create the file

Call Create file to obtain an upload URL for the document.
POST /core/files
{
  "category": "document",
  "contentType": "image/png"
}
A successful response returns an upload object with a presigned URL and form data for uploading the file to the storage provider.
Response
{
  "file": {
    "id": "38cce774-b225-41ed-a9fd-f9c9777a13de",
    "status": "pending",
    "category": "document",
    "contentType": "image/png",
    "upload": {
      "url": "https://example.com/upload",
      "formData": {
        "X-Amz-Algorithm": "AWS4-HMAC-SHA256",
        "X-Amz-Credential": "ASIE4FQORBNQHNQD5CG6/20240801/us-east-1/s3/aws4_request",
        "X-Amz-Date": "20240801T102500Z",
        "X-Amz-Security-Token": "IQoJb3JpZ2luX2VjEIv//////////...JBr6h2HkzH/aFSArQcs=",
        "X-Amz-Signature": "b4da8cf1a59327988a8108c965a4789fc8ba2d20f5bffda076106b2b254def29",
        "Key": "4c13b6f5-987e-43df-bc12-042b58307a80",
        "Policy": "eyJjb25kaXRpb25zIjpbeyJidWN...TA6MjU6MDAuMjAyWiJ9"
      },
      "expiresAt": "2024-03-13T20:20:39Z"
    }
  }
}
2

Upload the file

Upload the file to the provided upload.url using the returned upload.formData fields as multipart form parameters.
3

Submit the process

Call Update proof-of-address, referencing the file ID in input.media and setting output to the verification results from your provider.
PATCH /core/kyc/processes/proof-of-address
{
  "type": "document-submission",
  "input": {
    "media": [
      { "context": "address-proof", "fileId": "459c0447-8916-4bad-bb67-f2354fcfb10b" }
    ]
  },
  "output": {
    "provider": "sumsub",
    "person": {
      "givenName": "John",
      "familyName": "Doe",
      "address": {
        "country": "GB",
        "subdivision": "GB-MAN",
        "city": "Manchester",
        "line1": "1 High Street",
        "line2": "Northern Quarter",
        "postalCode": "M4 1AA"
      }
    },
    "verifiedAt": "2025-01-29T10:37:00Z"
  }
}
A successful response returns the submitted information with an ok status.
Response
{
  "proofOfAddress": {
    "status": "ok",
    "type": "document-submission",
    "input": {
      "media": [
        { "context": "address-proof", "fileId": "459c0447-8916-4bad-bb67-f2354fcfb10b" }
      ]
    },
    "output": {
      "provider": "sumsub",
      "person": {
        "givenName": "John",
        "familyName": "Doe",
        "address": {
          "country": "GB",
          "subdivision": "GB-MAN",
          "city": "Manchester",
          "line1": "1 High Street",
          "line2": "Northern Quarter",
          "postalCode": "M4 1AA"
        }
      },
      "verifiedAt": "2025-01-29T10:37:00Z"
    }
  }
}
Some KYC providers can verify the user’s address electronically, without requiring a physical document, by checking the declared address against public and third-party records.Call Update proof-of-address, populating input.data with the user’s declared information and output with the provider and verification datetime.
PATCH /core/kyc/processes/proof-of-address
{
  "type": "electronic-verification",
  "input": {
    "data": {
      "givenName": "John",
      "familyName": "Doe",
      "address": {
        "country": "GB",
        "subdivision": "GB-MAN",
        "city": "Manchester",
        "line1": "1 High Street",
        "line2": "Northern Quarter",
        "postalCode": "M4 1AA"
      }
    }
  },
  "output": {
    "provider": "sumsub",
    "verifiedAt": "2025-01-29T10:37:00Z"
  }
}
A successful response returns the submitted information with an ok status.
Response
{
  "proofOfAddress": {
    "status": "ok",
    "type": "electronic-verification",
    "input": {
      "data": {
        "givenName": "John",
        "familyName": "Doe",
        "address": {
          "country": "GB",
          "subdivision": "GB-MAN",
          "city": "Manchester",
          "line1": "1 High Street",
          "line2": "Northern Quarter",
          "postalCode": "M4 1AA"
        }
      }
    },
    "output": {
      "provider": "sumsub",
      "verifiedAt": "2025-01-29T10:37:00Z"
    }
  }
}

Customer due diligence

Assess the user’s financial profile and risk level based on their expected activities, source of funds, and other relevant information.
Uphold performs customer due diligence checks based on the user’s profile and declared intent. Call Update customer due diligence with input containing the answers for each form step, repeating until status returns ok.
Customer due diligence is a form-based process with multiple steps. The required fields may vary based on the user’s region, expected activities, and other factors. Always check the returned hint object for the specific schema to display. See Dynamic forms for guidance on rendering the form and submitting the data.
PATCH /core/kyc/processes/customer-due-diligence
{
  "input": {
    "formId": "ae80271a-a3f0-453b-8dc6-36b777817217",
    "answers": {
      "intent": {
        "expected-activities": [
          "cryptocurrency_investing",
          "deposit_withdraw_crypto"
        ]
      }
    }
  }
}
A successful response returns the submitted information with an ok status, along with the calculated risk score and verification datetime.
Response
{
  "customerDueDiligence": {
    "status": "ok",
    "input": {
      "formId": "ae80271a-a3f0-453b-8dc6-36b777817217",
      "answers": {
        "intent": {
          "expected-activities": [
            "cryptocurrency_investing",
            "deposit_withdraw_crypto"
          ]
        },
        "financial-information": {
          "source-of-funds": "salary",
          "annual-income-range": "40000-60000-GBP",
          "expected-annual-deposits-range": "0-5000-GBP"
        },
        "employment": {
          "status": "employed"
        },
        "employment-details": {
          "industry": "engineering"
        }
      }
    },
    "output": {
      "score": "low",
      "expiresAt": "2025-01-01T00:00:00Z",
      "verifiedAt": "2022-01-01T00:00:00Z"
    }
  }
}
Understanding scoreThe output.score reflects the user’s assessed risk level. The higher the score, the shorter the recollection period before the user must resubmit.Understanding expirationThe output.expiresAt is the deadline by which the user must resubmit customer due diligence — it opens for recollection 60 days before that date, at which point the process status reverts to pending. The user remains approved during this window and can continue to operate without restrictions until the deadline is reached.

Enhanced due diligence

Enhanced due diligence is an additional layer of verification required for users with a high customer due diligence score.
Your organization performs enhanced due diligence through an already-approved method, such as manual review of source-of-funds document (e.g. pay stub, bank statement, portfolio statement), and submits the result to Uphold.
1

Create the file

Call Create file to obtain an upload URL for the source-of-funds document.
POST /core/files
{
  "category": "document",
  "contentType": "image/png"
}
A successful response returns an upload object with a presigned URL and form data for uploading the file to the storage provider.
Response
{
  "file": {
    "id": "57a3ecf2-5404-4654-9ece-feb504a69f86",
    "status": "pending",
    "category": "document",
    "contentType": "image/png",
    "upload": {
      "url": "https://example.com/upload",
      "formData": {
        "X-Amz-Algorithm": "AWS4-HMAC-SHA256",
        "X-Amz-Credential": "ASIE4FQORBNQHNQD5CG6/20240801/us-east-1/s3/aws4_request",
        "X-Amz-Date": "20240801T102500Z",
        "X-Amz-Security-Token": "IQoJb3JpZ2luX2VjEIv//////////...JBr6h2HkzH/aFSArQcs=",
        "X-Amz-Signature": "b4da8cf1a59327988a8108c965a4789fc8ba2d20f5bffda076106b2b254def29",
        "Key": "4c13b6f5-987e-43df-bc12-042b58307a80",
        "Policy": "eyJjb25kaXRpb25zIjpbeyJidWN...TA6MjU6MDAuMjAyWiJ9"
      },
      "expiresAt": "2024-03-13T20:20:39Z"
    }
  }
}
2

Upload the file

Upload the file to the provided upload.url using the returned upload.formData fields as multipart form parameters.
3

Submit the process

Call Update enhanced due diligence, referencing the file ID in input.media and setting output containing the verification datetime.
PATCH /core/kyc/processes/enhanced-due-diligence
{
  "input": {
    "media": [
      { "context": "source-of-funds-proof", "fileId": "57a3ecf2-5404-4654-9ece-feb504a69f86" }
    ]
  },
  "output": {
    "verifiedAt": "2025-01-29T10:38:00Z"
  }
}
A successful response returns the submitted information with an ok status.
Response
{
  "enhancedDueDiligence": {
    "status": "ok",
    "input": {
      "media": [
        { "context": "source-of-funds-proof", "fileId": "57a3ecf2-5404-4654-9ece-feb504a69f86" }
      ]
    },
    "output": {
      "verifiedAt": "2025-01-29T10:38:00Z"
    }
  }
}

Crypto risk assessment

Assess the user’s knowledge of cryptocurrency risks and their suitability for engaging in crypto-related activities.
Uphold administers a crypto risk assessment quiz to the user, with a different set of questions per attempt, and evaluates the answers to determine whether the user is approved for crypto-related activities. Call Update crypto risk assessment with input containing the answers for each form step, repeating until output is updated.
Crypto risk assessment is a form-based process with multiple steps. The required fields may vary based on the user’s region, current attempt, and other factors. Always check the returned hint object for the specific schema to display. See Dynamic forms for guidance on rendering the form and submitting the data.
PATCH /core/kyc/processes/crypto-risk-assessment
{
  "input": {
    "formId": "7a0f4229-e3de-4dfd-8f91-9b1308b2dc33",
    "answers": {
      "attitude-towards-risk": {
        "willingness-to-fluctuations": "strongly_agree"
      }
    }
  }
}
A successful response returns the submitted information with an ok status, along with approval result, attempts used and remaining, and verification datetime.
Response
{
  "cryptoRiskAssessment": {
    "status": "ok",
    "input": {
      "formId": "7a0f4229-e3de-4dfd-8f91-9b1308b2dc33",
      "answers": {
        "attitude-towards-risk": {
          "willingness-to-fluctuations": "strongly_agree"
        },
        "risks-and-returns": {
          "business-scope": "cannot_precisely_predict_risk_or_guarantee_returns"
        },
        "losses": {
          "loss-potential": "half_of_my_initial_investment"
        },
        "complexity-understanding": {
          "risk-similarity": "riskier_than_either_bank_deposits_or_share_trading"
        },
        "liquidity-understanding": {
          "difficulty-reason": "a_lack_of_market_liquidity"
        },
        "losses-protection": {
          "assets-coverage": "no_unlike_money_held_in_a_bank_crypto_assets_are_not_protected"
        },
        "risk-allocation": {
          "assets-percentage": "not_more_than_10"
        }
      }
    },
    "output": {
      "result": "approved",
      "attempts": {
        "used": 1,
        "maximum": 5
      },
      "verifiedAt": "2022-01-01T00:00:00Z"
    }
  }
}
Understanding resultWhen the output.result is approved, the user is cleared for crypto-related activities. When rejected, the user can either retry the quiz (when attempts remain) or will be offboarded (when the maximum attempts have been reached).Understanding attemptsUse the output.attempts object to track how many attempts the user has made and the maximum allowed. When a cooldown is active, retryAt is present and indicates the earliest datetime the user can submit a new attempt.
{
  "attempts": {
    "used": 1,
    "maximum": 5,
    "retryAt": "2025-01-29T12:00:00Z"
  }
}
Understanding offboardingIf a failed attempt occurs, the output.offboard object is present. endsAt indicates either the deadline by which the user must submit a new attempt (when attempts remain), or the expected offboarding datetime (when the maximum has been reached). completedAt is set to the effective datetime when the user was offboarded.
{
  "offboard": {
    "endsAt": "2025-06-29T00:00:00Z",
    "completedAt": "2025-01-29T12:00:00Z"
  }
}

Self-categorization statement

Collect the user’s self-declared financial profile and categorize them accordingly.
Uphold administers a self-categorization statement form to the user, and evaluates the answers to determine the user’s category. Call Update self-categorization statement with input containing the answers for each form step, repeating until output is updated.
Self-categorization statement is a form-based process with multiple steps. The required fields may vary based on the user’s region, category, and other factors. Always check the returned hint object for the specific schema to display. See Dynamic forms for guidance on rendering the form and submitting the data.
PATCH /core/kyc/processes/self-categorization-statement
{
  "input": {
    "formId": "ac33651f-f2d3-47c4-8e8d-06fb87361f5c",
    "answers": {
      "investor": {
        "type": "restricted_investor"
      }
    }
  }
}
A successful response returns the submitted information with an ok status, along with the categorization result and verification datetime.
Response
{
  "status": "ok",
  "input": {
    "formId": "ac33651f-f2d3-47c4-8e8d-06fb87361f5c",
    "answers": {
      "investor": {
        "type": "restricted_investor"
      },
      "investor-profile": {
        "invested-less-than-10-percent": "yes",
        "invested-percentage": "5",
        "invest-less-than-10-percent": "yes",
        "invest-percentage": "5",
        "investor-type-confirmation": "yes"
      }
    }
  },
  "output": {
    "result": "approved",
    "attempts": {
      "used": 1,
      "maximum": 30
    },
    "expiresAt": "2025-01-01T00:00:00Z",
    "verifiedAt": "2022-01-01T00:00:00Z"
  }
}
Understanding resultWhen the output.result is approved, the user is cleared for the activities allowed for their category. When rejected, the user can either retry the statement (when attempts remain) or will be offboarded (when the maximum attempts have been reached).Understanding attemptsUse the output.attempts object to track how many attempts the user has made and the maximum allowed.
{
  "attempts": {
    "used": 1,
    "maximum": 30
  }
}
Understanding expirationThe output.expiresAt is the deadline by which the user must resubmit the self-categorization statement — it opens for recollection 60 days before that date, at which point the process status reverts to pending. The user remains approved during this window and can continue to operate without restrictions until the deadline is reached.

Tax details

Collect the user’s tax residency and tax identification information for tax reporting purposes.
Uphold collects tax details through a two-step form. The first step asks for the user’s countries of tax residency. Based on the response, the second step requests the required tax identification document numbers for each specified country.
See Dynamic forms for guidance on rendering the form and submitting the data.
1

Submit tax residency

Call Update tax details with the countries where the user is tax resident.
The required information varies based on the user’s region. Always check the form schema returned in the hint dynamically to determine which fields to collect.
PATCH /core/kyc/processes/tax-details
{
  "input": {
    "taxResidency": {
      "countries": ["GB"]
    }
  }
}
The response returns pending with the next form step in hint, pre-filled with the required tax identification documents for each declared country.
Response
{
  "taxDetails": {
    "status": "pending",
    "input": {
      "taxResidency": {
        "countries": ["GB"]
      },
      "taxIdentification": {
        "documents": [
          {
            "type": "tin",
            "country": "GB"
          }
        ]
      }
    },
    "hint": {
      "type": "form",
      "schema": {
        "type": "object",
        "properties": { /* ... */ }
      },
      "uiSchema": {
        "type": "Categorization",
        "elements": [ /* ... */ ]
      }
    }
  }
}
2

Submit tax identification

Call Update tax details again with the tax identification document numbers and certification of the information’s accuracy.
The required information varies based on the user’s region. Always check the form schema returned in the hint dynamically to determine which fields to collect.
PATCH /core/kyc/processes/tax-details
{
  "input": {
    "taxResidency": {
      "countries": ["GB"]
    },
    "taxIdentification": {
      "documents": [
        {
          "type": "tin",
          "country": "GB",
          "value": "1234567890"
        }
      ],
      "certify": true
    }
  }
}
A successful response returns the submitted information with an ok status. The form is always returned — even when the process is ok — so the user can update their tax details when needed.
Response
{
  "taxDetails": {
    "status": "ok",
    "input": {
      "taxResidency": {
        "countries": [
          "GB"
        ]
      },
      "taxIdentification": {
        "documents": [
          {
            "type": "tin",
            "country": "GB",
            "number": "6405444702"
          }
        ],
        "certify": true
      }
    },
    "output": {
      "result": "approved",
      "verifiedAt": "2022-01-01T00:00:00Z"
    },
    "hint": {
      "type": "form",
      "schema": {
        "type": "object",
        "properties": { /* ... */ }
      },
      "uiSchema": {
        "type": "Categorization",
        "elements": [ /* ... */ ]
      }
    }
  }
}

Screening and risk

Uphold automatically screens users against sanctions lists and assesses their risk level based on various factors, such as their location, transaction patterns, and other relevant data.
{
  "screening": {
    "status": "ok",
    "output": {
      "result": "approved"
    }
  },
  "risk": {
    "status": "ok",
    "output": {
      "result": "approved"
    }
  }
}
Understanding result When the output.result is approved, the user has passed screening or risk assessment. When rejected, the user has been flagged for potential issues and may require further review or offboarding.

Monitor user onboarding

Prefer webhooks for real-time updates, or fall back to polling if webhooks are not feasible.
  • Webhook events (recommended):
    • core.user.created
    • core.kyc.*.status-changed
      • status: pending → waiting for the user to provide information
      • status: running → Uphold is processing the provided information
      • status: ok → the process has been successfully verified
      • status: failed → verification failed — the user may need to resubmit
      • status: exempt → the process is not required for this user
  • Polling (fallback): Get KYC overview

Check capabilities

Always check if the required capabilities for the user’s intended activities are unlocked before allowing them to transact. Call List capabilities to check restrictions and requirements for each capability.
GET /core/capabilities
The response includes the list of capabilities with any outstanding requirements or restrictions.
Response
{
  "capabilities": [
    {
      "key": "crypto-deposits",
      "enabled": true,
      "requirements": [],
      "restrictions": []
    },
    {
      "key": "crypto-withdrawals",
      "enabled": true,
      "requirements": [
        "user-must-submit-identity"
      ],
      "restrictions": []
    }
  ]
}
The user is now onboarded and ready to transact.