Skip to main content

Pix on File Device Linking

Pix on File is a Pix payment flow in Brazil that links the customer's device to their bank account, so customers can authorize payments without being redirected to their bank app. Pix on File is available on both the Cross-border and Local tenants.

Device Linking is the one-time enrollment that establishes this link. It relies on FIDO2/WebAuthn: after the customer authorizes the enrollment in their banking app, they register a FIDO2 credential on their device, which is then used to authenticate every payment.

This guide outlines the key concepts and implementation details required to link a device for Pix on File via API. It covers essential steps such as creating the enrollment, handling the callback, and confirming the device linking with the customer's FIDO2 credential.

Requirements​

  • API authentication - All API requests must be authenticated using JWS (JSON Web Signature). The legacy integration_key is being deprecated — if you still use it, follow the Migration Guide to transition to JWS. If you don't have credentials yet, complete the Merchant Signup Form.
  • Familiarity with EBANX Direct - This setup follows the same general structure as other payment methods, with a few unique parameters. See EBANX Direct for more info.

How it works​

  • Initiate enrollment - The merchant creates an enrollment for the bank the customer selected from the Bank List.
  • Customer authorization - The customer is redirected to their banking app and authorizes the enrollment.
  • Credential registration - The customer returns to the merchant app and completes the FIDO2 credential registration.
  • Active enrollment - The merchant confirms the device linking, and the enrollment becomes active and ready for payments.

Instructions​

Follow the steps below.

Sample requests use the Local host

The sample requests on this page are sent to the Local sandbox host. If you operate Cross-border, send the same request to the Cross-border host — paths and payloads are identical.

  1. Select your environment
    ​

    Select the appropriate environment for your integration. Use the sandbox environment for testing, or the production environment for live transactions. Use the URL for your HTTP requests based on your selection.

    Check the method's availability for your country and tenant in Payment Methods by Country. Questions about tenant and environment? Check our API Operability and API Endpoints.

    Cross-border sandbox
    https://sandbox.ebanxpay.com/ws/userenrollment
  2. Enrollment request
    ​

    Device Linking begins with an enrollment request towards the customer's banking institution, using the ws/userenrollment endpoint. A list of available banking institutions can be retrieved using the Bank List request. The following parameters are used for Device Linking requests:

    ParameterRequirementDescription
    integration_keyRequiredYour integration key
    payment_type_codeRequiredMust be pix-jsr
    operationRequiredMust be enrollment
    enrollment.countryRequiredMust be br
    enrollment.merchant_enrollment_codeRequiredUnique enrollment code
    enrollment.notification_urlRequiredURL to callback after customer authorizes the device linking
    enrollment.intent_urlRequiredDeeplink URL that will be used to trigger user redirection after confirming the device linking in the banking application (return to merchant app)
    enrollment.emailRequiredCustomer e-mail
    enrollment.identification_typeRequiredEither cpf or cnpj
    enrollment.identificationRequiredCustomer document
    enrollment.account_details.bank_idRequiredA valid bank_id
    enrollment.fidoOptions.platformRequiredPlatform where the enrollment is being initiated (ANDROID, IOS, BROWSER, CROSS_PLATFORM).
    enrollment.fidoOptions.risk_signalsRequiredRefer to Risk Signals.
    Risk Signals

    Risk Signals are contextual data points collected during user authentication that help Relying Parties (banks) assess the trust level of an authentication attempt.

    Sample request

    Shell
    curl -X POST \
    --location 'https://sandbox-local-latam.ebanxpay.com/ws/userenrollment' \
    --header 'Content-Type: application/json' \
    --data '{
    "integration_key": "{your_ebanx_integration_key}",
    "payment_type_code": "pix-jsr",
    "operation": "enrollment",
    "enrollment": {
    "country": "br",
    "merchant_enrollment_code": "{merchant_enrollment_code}",
    "notification_url": "{notification_url_backend}",
    "intent_url": "{intent_url_device}",
    "email": "john.doe@example.com",
    "identification_type": "{cpf/cnpj}",
    "identification": "{document_number}",
    "account_details": {
    "bank_id": "{bank_id}"
    },
    "fidoOptions": {
    "platform": "{ENUM}",
    "risk_signals": {}
    }
    }
    }'
  3. Enrollment response
    ​

    A successful request returns a JSON response like the one below, containing a redirect URL that leads the customer to their banking application.

    JSON
    {
    "status": "SUCCESS",
    "redirect_url": "{redirect_url}",
    "enrollment": {
    "enrollment_code": "{merchant_enrollment_code}",
    "status": "pending"
    }
    }
    Field naming across surfaces

    The enrollment code is named differently depending on the surface. Map each one explicitly instead of reusing a single key:

    • Request body: enrollment.merchant_enrollment_code
    • API response: enrollment.enrollment_code
    • Callback (webhook): enrollment.merchant_enrollment_code

    The FIDO2 registration options follow the same pattern: the callback sends registrationOptions (camelCase), while the enrollment query response returns registration_options (snake_case). The two are not guaranteed to be byte-identical — the query response may add authenticatorSelection.residentKey: "required" and authenticatorSelection.requireResidentKey: true if the bank did not send them. Pass whichever object you received straight to navigator.credentials.create() without merging the two.

  4. Receive the callback
    ​

    Once the customer authorizes the device linking in their banking application, the banking application will redirect the user to the {intent_url} informed in the original request and a status update will be sent to the {notification_url} informed in the initiation step with additional information that will be required to complete the FIDO2/WebAuthn authentication in the device.

    JSON
    {
    "enrollment": {
    "merchant_enrollment_code": "{merchant_enrollment_code}",
    "status": "pending",
    "registrationOptions": {
    "rp": {
    "id": "string",
    "name": "string"
    },
    "user": {
    "id": "string",
    "name": "string",
    "displayName": "string"
    },
    "challenge": "string",
    "pubKeyCredParams": [
    {
    "alg": -7,
    "type": "public-key"
    }
    ]
    }
    }
    }
  5. Device linking confirmation request
    ​

    The last stage for Device Linking is processing the results of the FIDO2/WebAuthn authentication performed by the customer after confirming the enrollment and returning to the merchant application. Send the following parameters to the ws/userenrollment/authentication endpoint:

    ParameterRequirementDescription
    integration_keyRequiredYour integration key
    payment_type_codeRequiredMust be pix-jsr
    operationRequiredMust be authentication
    enrollment.merchant_enrollment_codeRequiredUnique enrollment code
    enrollment.authentication.credentialIdRequiredCredential ID (Base64 encoded)
    enrollment.authentication.rawCredentialIdRequiredCredential ID in ArrayBuffer format (Base64 encoded)
    enrollment.authentication.authenticatorAttachmentRequiredMust be platform.
    enrollment.authentication.credentialTypeRequiredMust be public-key
    enrollment.authentication.response.clientDataJSONRequiredClient data in JSON, encoded in Base64url
    enrollment.authentication.response.attestationObjectRequiredAuthenticator attestation data, encoded in Base64url

    Sample request

    Shell
    curl -X POST \
    --location 'https://sandbox-local-latam.ebanxpay.com/ws/userenrollment/authentication' \
    --header 'Content-Type: application/json' \
    --data '{
    "integration_key": "{your_ebanx_integration_key}",
    "payment_type_code": "pix-jsr",
    "operation": "authentication",
    "enrollment": {
    "merchant_enrollment_code": "{merchant_enrollment_code}",
    "authentication": {
    "credentialId": "{fido_id}",
    "rawCredentialId": "{fido_raw_id}",
    "authenticatorAttachment": "platform",
    "credentialType": "public-key",
    "response": {
    "clientDataJSON": "{client_data_json}",
    "attestationObject": "{attestation_object}"
    }
    }
    }
    }'
  6. Device linking confirmation response
    ​

    A successful request returns a JSON response like the one below, confirming that the enrollment is ready to be used for payment processing.

    JSON
    {
    "status": "SUCCESS",
    "payment_type": "pix-jsr",
    "enrollment": {
    "status": "accepted"
    }
    }
    This response is conclusive — unlike payment authentication

    Device Linking confirmation is synchronous and conclusive. EBANX calls the bank during the request and only records the enrollment as accepted once the bank confirms it, so a SUCCESS response with accepted means the enrollment is genuinely active. You can proceed to request payments immediately — there is no notification to wait for, and no need to poll.



    Do not carry this assumption over to payment authentication, on the Payment page. That call is also synchronous, but it is not conclusive: it returns the payment still in PE, and confirmation arrives later. The two flows differ deliberately.

    An enrollment is only usable for payments once enrollment.status is accepted. The full set of enrollment status values is:

    StatusDescription
    pendingOne or more required parties have not yet accepted or rejected the enrollment agreement.
    acceptedAll required parties accepted. The enrollment is active and usable for payments.
    not_acceptedA party did not accept the enrollment agreement.
    revokedA party revoked the enrollment agreement. A provider rejection is also returned as revoked.
    cancelledThe merchant revoked the enrollment agreement.
    expiredA required party did not accept before the enrollment expired.
    pausedA party paused the enrollment agreement. It cannot be used for payments while paused.
    not_foundThe enrollment agreement no longer exists, or could no longer be found.
    Status values are lowercase

    Match these values exactly as returned. Note cancelled is spelled with a double L, and there is no rejected status — a bank rejection surfaces as revoked.

  7. Congratulations!
    ​

    You have successfully linked the customer's device for Pix on File.

    Next, request payments against the active enrollment in
    Pix on File Paymentchevron_right

Resources​

Use the following resources when testing in your sandbox environment.

Still need help?

Help Image

We hope this article was helpful. If you still have questions, you can explore the following options: