KYC

When a user reaches a transaction limit, they have to pass light KYC or full KYC before the payment can be completed. There are two scenarios:

  • KYC Before Payment — optional. You verify the user in advance, in your own interface: full KYC with a SumSub share token, or light KYC with an SSN check for US users. The payment then goes through without sending the user to the Mercuryo widget.
  • KYC During Payment — fallback. The payment request returns 403001, and you hand the user over to the Mercuryo widget to complete the verification.

The scenarios work together: if a verification can't be completed in advance, or more data is still needed, the payment request falls back to KYC During Payment.


KYC Before Payment

Before the Apple Pay payment, your backend can sign the user in, check whether verification is needed for a specific quote, collect a compliance questionnaire and submit the verification.

  • Availability: like the quote, these requests are not available for users from the United Kingdom and the European Economic Area (EEA).
  • Authentication: Sdk-Partner-Token for sign-in and partner-scoped quotes; Sdk-User-Token (returned by sign-in) for all user-scoped calls. These endpoints don't use X-Signature.
  • User IP: pass the end user's real IP address in the Sdk-User-IP header. Required for sign-in, quotes and questionnaires, and for the share-token submission.

Step 1 — Sign in the user

POST /sdk-partner/native/user/sign-in registers or authenticates the user in your partner account and returns bearer_token — use it as the Sdk-User-Token header in the next steps.

Header Required Description
Sdk-Partner-Token Yes Your partner authentication token.
Sdk-User-IP Yes The end user's real IP address.
Field Type Description
email string Required. The user's email. Use the same email you send in the payment request: the verification is attached to this user and applies to their payments.
first_name string Conditional. Required together with last_name when the user doesn't have a name yet (a new user, or an existing one without a name).
last_name string Conditional. Required together with first_name, see above.
birthday string Optional. YYYY-MM-DD. Recommended for new users for better conversion.

Example request:

POST /v1.6/sdk-partner/native/user/sign-in
Sdk-Partner-Token: YOUR_SDK_PARTNER_TOKEN
Sdk-User-IP: 203.0.113.42
{
    "email": "user@example.com",
    "first_name": "Jane",
    "last_name": "Doe",
    "birthday": "1995-05-25"
}

Example response:

{
    "status": 200,
    "data": {
        "user_uuid4": "3292c753-6809-492a-9acd-1ccdbf2fa91e",
        "bearer_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."
    }
}

Step 2 — Get a quote in the user's context

GET /sdk-partner/native/rate with Sdk-User-Token returns a quote calculated for this user, including kyc_limits — whether the user has to pass full KYC to buy this amount.

Header Required Description
Sdk-User-Token Yes bearer_token from Step 1.
Sdk-User-IP Yes The end user's real IP address.

The query parameters are the same as for the quote in Native Payment.

Example request:

GET /v1.6/sdk-partner/native/rate?type=buy&from=EUR&to=BTC&amount=100&payment_method=apple&is_total=true&network=BITCOIN
Sdk-User-Token: eyJ...
Sdk-User-IP: 203.0.113.42

Example response:

{
    "status": 200,
    "data": {
        "quote_token": "eyJ...",
        "currency": "BTC",
        "amount": "0.00151",
        "fiat_amount": "100.00",
        "fiat_currency": "EUR",
        ...
        "kyc_limits": false
    }
}
  • quote_token — use it in the questionnaire check and as buy_token in the payment request.

If native Apple Pay can't be used for this user, the quote request is rejected. Don't continue with KYC Before Payment — switch to the Mercuryo widget flow instead, so the purchase isn't lost:

Code Meaning
403034 The user's country isn't supported.
403109 Apple Pay is not available for this user.

Step 3 — Complete the compliance questionnaire

Check whether a questionnaire is required for this quote with POST /sdk-partner/native/questionnaires/check-need.

Header Required Description
Sdk-User-Token Yes bearer_token from Step 1.
Sdk-User-IP Yes The end user's real IP address.
Field Type Description
quote_token string Required. quote_token from Step 2.

Example request:

{
    "quote_token": "eyJ..."
}

Example response:

{
    "status": 200,
    "data": {
        "questionnaires": [
            {
                "type": "HANFA_EEA",
                "version": 1,
                "questions": [
                    {
                        "key": "SOURCE_OF_FUNDS",
                        "question_text_en": "Source of funds",
                        "options": [
                            {"code": "SALARY", "label_en": "Salary or employment income"},
                            {"code": "SAVINGS", "label_en": "Savings"}
                        ]
                    }
                ]
            }
        ]
    }
}
  • questionnaires: [] — no questionnaire is required, go to Step 4.
  • One or more questionnaires — render each returned questionnaire to the user, then submit the answers with a separate POST /sdk-partner/native/questionnaires request for each questionnaire in the array.

Submit the answers with the same headers as check-need:

Field Type Description
type string Required. The questionnaire's type, unchanged.
version integer Required. The questionnaire's version, unchanged.
questions array Required. One entry for every question of the questionnaire.
questions[].key string Required. The question's key.
questions[].codes array Required. Exactly one option code of this question.
questions[].text string Conditional. Only for the citizenship country question: ISO 3166-1 alpha-2 country code, lowercase.

Example request:

{
    "type": "HANFA_EEA",
    "version": 1,
    "questions": [
        {"key": "SOURCE_OF_FUNDS", "codes": ["SALARY"]}
    ]
}

A successful submission returns 201.

Step 4 — Verify the user

Which verification to run depends on kyc_limits from Step 2 and on the user's country:

Case Verification
kyc_limits: true Full KYC — Share token
kyc_limits: false, US user Light KYC with SSN — SSN check (US users)
kyc_limits: false, other users Light KYC — the data from Step 1 is enough, go to Step 5

Submit the verification, poll its status while it is under_review, then go to Step 5. The verification methods are described in Verification Methods.

Step 5 — Start the payment

Start the Apple Pay payment and send it with quote_token as buy_token and the same email as in Step 1. If more data is still required, the payment request returns 403001 — continue with KYC During Payment.


Verification Methods

Share token

If you have a SumSub integration and the user has already passed full KYC there, reuse this verification by sharing it with Mercuryo. The user won't need to verify twice.

Note: This option requires approval from Mercuryo's Customer Success and Compliance teams, as SumSub charges for this service. Discuss it with your integration manager before proceeding.

Setup (once):

  1. Conclude a contract with SumSub for the Reusable KYC feature.
  2. Request a partner token from your integration manager.
  3. In your SumSub account: Partners → Recipients → Add Recipient → enter the partner token.
  4. Ask your integration manager to verify the setup.

Requirements:

  • The applicant must have completed ID document + liveness (selfie) verification with approved status on your side.
  • The email of the SumSub applicant must match the email you used to sign in the user.
  • Mercuryo can accept a share token only once per applicant (a SumSub limitation).
  • Field sets may differ between the systems — only the document type and country are used for matching.

Generating the share token: call the SumSub API with applicantId and forClientId=Mercuryo:

POST https://api.sumsub.com/resources/accessTokens/-/shareToken

See SumSub sharing docs and the video on how it works.

Then submit the share token to Mercuryo with POST /sdk-partner/native/kyc/crypto/share-token:

Header Required Description
Sdk-User-Token Yes bearer_token from Step 1.
Sdk-User-IP Yes The end user's real IP address.
Field Type Description
share_token string Required. The user's SumSub share token.

Example request:

{
    "share_token": "_act-75e78843-3207-4be6-asdb936-9842ae2a0c71"
}

A 200 response means the token was accepted. Then poll the status with GET /sdk-partner/native/kyc/crypto/status while it is under_review.

If the share token can't be used, the response contains one of these codes:

Code Meaning What to do
409001 The user's verification is already under review. Poll the status.
409002 The user already has an unfinished verification application — e.g. a share token with incomplete data was submitted for this user earlier. A share token can no longer be submitted for this user. Start the payment and verify the user through KYC During Payment.
403084 Share token import isn't available for the user's country. Start the payment and verify the user through KYC During Payment.
403082 The user's KYC is already complete. Start the payment.
403115 A verification is already in progress. Poll the status.
403114 The user's KYC verification is failed. Stop — the user can't pay.

SSN check (US users)

For US users, light KYC includes the SSN. Submit the user's data and SSN with POST /sdk-partner/native/kyc/ssn.

Header Required Description
Sdk-User-Token Yes bearer_token from Step 1.
Field Type Description
first_name string Required. The user's legal first name.
last_name string Required. The user's legal last name.
birthday string Required. YYYY-MM-DD.
ssn string Required. 9-digit US Social Security Number, digits only.
address1 string Required. Street address.
address2 string Optional. Apartment, suite, unit, etc.
city string Required. City.
state string Required. Two-letter US state code.
zip string Required. 12345 or 12345-6789.

Example request:

{
    "first_name": "John",
    "last_name": "Doe",
    "birthday": "1990-05-20",
    "ssn": "123456789",
    "address1": "1 Infinite Loop",
    "address2": "Apt 4",
    "city": "Cupertino",
    "state": "CA",
    "zip": "95014"
}

A 200 response means the check is accepted for processing. Then poll the status with GET /sdk-partner/native/kyc/ssn/status while it is under_review.

If the SSN check can't be started, the response contains one of these codes:

Code Meaning What to do
400027 The SSN check request was rejected. Verify the user with full KYC — a share token or KYC During Payment.
403116 The user's SSN check is failed. Verify the user with full KYC — a share token or KYC During Payment.
403082 The user's KYC is already complete, the SSN check isn't needed. Start the payment.
403115 A verification is already in progress. Poll the status.
403114 The user's full KYC verification is failed. Stop — the user can't pay.

Verification status

GET /sdk-partner/native/kyc/{feature}/status returns the verification status.

Header Required Description
Sdk-User-Token Yes bearer_token from Step 1.
Parameter Required Description
feature (path) Yes crypto — full KYC (share token); ssn — light KYC with SSN.

Example response:

{
    "status": 200,
    "data": {
        "status": "complete"
    }
}
Status Meaning What to do
under_review The verification is in progress. Keep polling.
complete The verification is passed. Start the payment.
failed_attempt / incomplete The verification isn't finished. Start the payment — the missing data is collected during the payment, see KYC During Payment.
failed The verification is failed. ssn: verify the user with full KYC — a share token or KYC During Payment.
crypto: stop — the user can't pay.

KYC During Payment

When POST /sdk-partner/native-mobile-pay/mobile-pay can't be completed without user verification, it returns code 403001. You hand the user over to the full Mercuryo widget, so the transaction isn't lost.

{
    "status": 403,
    "code": 403001,
    "message": "KYC verification needed.",
    "data": {
        "id": "0fcabca3a43709674",
        "status": "pending",
        "init_token": "0fcabca4c19121633",
        "init_token_type": "type_sdk_silent_sub"
    }
}

data.status is pending for non-US users and order_failed for US users — see below.

The response contains a short-lived init_token and init_token_type. They pre-authenticate the user in the Mercuryo widget, so the user goes straight to identity verification without entering their details again.

Non-US user

  • A 30-minute hold is placed on the user's funds. The 403001 response returns the transaction in pending; it then moves to order_scheduled and waits there while the user passes KYC.
  • If the payment isn't completed within 30 minutes of its creation, the transaction is cancelled and the hold is released.

US user

  • No hold is placed on the user's funds.
  • The transaction fails immediately with status order_failed. The 403001 response and the callback both carry order_failed.
  • After completing KYC in the widget, the user starts a new Apple Pay payment directly in the widget — the original transaction is not resumed.

Redirecting the User

Redirect the user to the Mercuryo widget immediately after the 403001 response, with your widget_id and the token values from the response:

https://exchange.mercuryo.io/?widget_id=YOUR_WIDGET_ID&init_token=INIT_TOKEN_VALUE&init_token_type=INIT_TOKEN_TYPE_VALUE
Parameter Source
widget_id Your Widget ID from the Mercuryo Dashboard
init_token data.init_token from the 403001 response
init_token_type data.init_token_type from the 403001 response

For US users, the widget must be opened with a Widget Signature v2. In addition to widget_id, init_token and init_token_type, the redirect URL must also include signature, address, ip_address and, if used, merchant_transaction_id — the parameters the signature is calculated from. See the Widget Signature guide for how to generate the signature.

The user lands on the Mercuryo widget with their transaction data pre-filled, completes the required steps (e.g., uploads documents for KYC) and finalizes the purchase.

Outcome

Non-US user

Scenario Result
The user completes KYC within 30 minutes The transaction is finalized automatically; the final status is delivered via the callback
The user doesn't complete KYC within 30 minutes The transaction is cancelled and the hold on the user's funds is released

US user

Scenario Result
Any case The transaction has already failed (order_failed) at the moment of the 403001 response; your backend receives a callback for the failed transaction. Once KYC is completed, the user starts a new payment attempt from the widget