--- url: /guide/wallets/balances.md description: >- Retrieve the Balances of the Wallet. Balances include the funds currently available in the Wallet, the pending operations amount, and the authorized balance. --- # Balances The Balance object provides the amount available on a given Wallet. Read more about the different kind of balances in the [Balance definition](/guide/overview/glossary#balance) of the Glossary. ## Balance of a specific Wallet This checks the current Balance of the [Wallet](introduction) (how much money there is), making sure the funds have arrived. Note that the `walletId` is expected as a query parameter. Endpoint: [`/v1/balances`](/api-reference/api-endpoints.html#tag/Balances/getBalances){target="\_self"} ::: code-group ```bash [CURL] curl -X GET '{baseUrl}/v1/balances?walletId={walletId}' \ --header 'Authorization: Bearer {accessToken}' ``` ::: Returns the Balance object, with both the [Authorized Balance](/guide/overview/glossary#balance) (`authorizedBalance`) and [Balance](/guide/overview/glossary#balance) (`currentBalance`). ::: code-group ```json [JSON] { "balances": [ { "walletId": 1317558, "currentBalance": 280, // Actual Balance "authorizations": 0, // Currently pending authorizations "authorizedBalance": 280, // Balance, minus pending authorizations "currency": "EUR", // Currency of the balance "calculationDate": "2022-03-01 15:52:40" // When the Balance was last actualized } ] } ``` ::: ## Balances of all Wallets You can retrieve the Balances of multiple Wallets related to the same [User](/guide/users/introduction). In this case, you provide a `userId` instead of a `walletId` in the query parameters. Endpoint: [`/v1/balances`](/api-reference/api-endpoints.html#tag/Balances/getBalances){target="\_self"} ::: code-group ```bash [CURL] curl -X GET '{baseUrl}/v1/balances?userId={userId}' \ --header 'Authorization: Bearer {accessToken}' ``` ::: Returns the list of Balance of each Wallet belonging to the [User](/guide/users/introduction). ::: code-group ```json [JSON] { "balances": [ { "walletId": 3645800, "currentBalance": 4002.5, "authorizations": 0, "authorizedBalance": 4002.5, "currency": "EUR", "calculationDate": "2024-12-11 11:06:08" }, { "walletId": 3645801, "currentBalance": 100, "authorizations": 50, "authorizedBalance": 50, "currency": "EUR", "calculationDate": "2024-12-11 11:06:08" }, { "walletId": 3645802, "currentBalance": 302.5, "authorizations": 0, "authorizedBalance": 302.5, "currency": "EUR", "calculationDate": "2024-12-11 11:06:08" } ] } ``` ::: ## Check the balance history This checks the evolution of the balance over time. Only the `walletId` is mandatory, it is expected in the URL. You can optionally restrict the search time frame using the `dateFrom` and `dateTo` parameters. Endpoint: [`/core-connect/balances/{walletId}`](/api-reference/api-endpoints.html#tag/Balances/getWalletBalanceHistory){target="\_self"} ::: code-group ```bash [CURL] curl -X GET '{baseUrl}/core-connect/balances/{walletId}?dateFrom=2021-11-01&dateTo=2022-10-01' \ --header 'Authorization: Bearer {accessToken}' ``` ::: ::: code-group ```json [JSON] { "2021-03-31T09:50:02+00:00": { "solde": 51.25, "authorizedBalance": 51.25, "currency": "EUR" }, "2021-02-04T13:20:02+00:00": { "solde": 170.00, "authorizedBalance": 170.00, "currency": "EUR" }, // [...] more items are hidden } ``` ::: **Caution – Date expected format is `YYYY-MM-DD`** The time frame dates do not follow the [standard format](/guide/api-basics/data-format#dates) and are instead expected as `YYYY-MM-DD`. --- --- url: /guide/overview/api-atlas.md description: >- Get an overview of the various Treezor API objects and their relationships with an extensive flowchart. Each node links to the relevant section of the documentation. --- # API Atlas The following diagram shows a general overview of the API, allowing you to **click any node to access the relevant documentation**. ```mermaid flowchart LR User Wallet Card CardProgram CardTransaction CardTransactionExternalAuthorization[External Authorization] CardTransactionRuleEngine[Rule Engine] CardTransactionStrongCustomerAuthentication[Strong Customer Authentication] CardTransactionAuthorization[Authorization] CardTransactionRefund[Refund] CardTransactionSettlement[Settlement] CardTransactionReversal[Reversal] CardTopUp[Top Up by Card] CardRestrictions[Restrictions] CardLimits[Limits] CardOptions[Options] CardStatus[Status] CardGroupLimits[Group Limits] CardPINCode[PIN Code] CardRenew[Renewal] SCTE SCTERecall[SCTE Recall] SCTEInst[SCTE Inst] SCTEInstRecall[SCTE Inst Recall] SDDE SDDR SCTR SCTRRecall[SCTR Recall] SCTRInst[SCTR Inst] SCTRInstRecall[SCTR Inst Recall] MassSCTE[Mass SCTE] Cheque Beneficiary Mandate Transfer["Wallet to Wallet"] Document KYC KYCPreReview[Pre-Review] KYCLiveness[Live verification] ExternalAccount %% Base relations User --- Wallet User --- Document User -.- KYC Document -.- KYC KYC -.- KYCPreReview KYC -.- KYCLiveness %% Cards Relations User --- Card Wallet --- Card Card --- CardTransaction CardTransaction --- CardTransactionAuthorization CardTransactionAuthorization -.- CardTransactionStrongCustomerAuthentication CardTransactionAuthorization -.- CardTransactionExternalAuthorization CardTransactionAuthorization -.- CardTransactionRuleEngine CardTransaction --- CardTransactionRefund CardTransaction --- CardTransactionSettlement CardTransaction --- CardTransactionReversal Wallet -- Payin --- CardTopUp Card -.- CardRestrictions Card -.- CardLimits Card -.- CardOptions Card -.- CardStatus Card -.- CardGroupLimits Card -.- CardPINCode Card -.- CardRenew Card --- CardProgram %% SEPA Relations Wallet -- Payout --- SCTE Wallet -- Payin --- SCTR Wallet -- Payout --- SCTEInst Wallet -- Payin --- SCTRInst Wallet -- Payin --- SDDE Wallet -- Payout --- SDDR Wallet -- Payout --- MassSCTE SCTE --- Beneficiary SDDR --- Beneficiary SDDE --- Mandate MassSCTE --- SCTE Beneficiary -.- ExternalAccount %% Cheque Relations Wallet -- Payin --- Cheque %% Transfers Relations Wallet -- Transfer --- Transfer %% Sepa Recalls relations SCTE --- SCTERecall SCTEInst --- SCTEInstRecall SCTR --- SCTRRecall SCTRInst --- SCTRInstRecall %% Stuff that don't link to anything %% StrongCustomerAuthentication %% Webhook %% Dashboard %% Operations %% Styling class User MermaidUser class Card MermaidCard class Wallet MermaidWallet class Beneficiary MermaidBeneficiary class Mandate MermaidMandate class KYC MermaidKYC class CardTransactionExternalAuthorization MermaidNeutral class CardTransactionRuleEngine MermaidNeutral class CardTransactionStrongCustomerAuthentication MermaidNeutral class ExternalAccount MermaidNeutralAlternate class KYCPreReview MermaidNeutral class KYCLiveness MermaidNeutral %% Links click KYCLiveness "/guide/user-verification/live-verification.html" click KYCPreReview "/guide/user-verification/documents-prereview.html" click User "/guide/users/introduction.html" click Wallet "/guide/wallets/introduction.html" click Card "/guide/cards/introduction.html" click CardProgram "/guide/cards/introduction.html#card-program" click CardTransaction "/guide/cards/transactions.html" click CardTransactionExternalAuthorization "/guide/cards/transactions-external-validation.html" click CardTransactionRuleEngine "/guide/cards/transactions-rules-engine.html" click CardTransactionStrongCustomerAuthentication "/guide/cards/transactions-authentication.html" click CardTransactionAuthorization "/guide/cards/transactions-lifecycle.html#authorization" click CardTransactionRefund "/guide/cards/transactions-lifecycle.html#refunds" click CardTransactionSettlement "/guide/cards/transactions-lifecycle.html#settlement" click CardTransactionReversal "/guide/cards/transactions-lifecycle.html#reversal" click CardTopUp "/guide/cards/acquisition.html" click CardRestrictions "/guide/cards/restrictions-limits.html#mcc-restrictions" click CardLimits "/guide/cards/restrictions-limits.html#payment-withdrawal-limits" click CardOptions "/guide/cards/restrictions-limits.html#options-permission-groups" click CardStatus "/guide/cards/introduction.html#card-status-statuscode" click CardGroupLimits "/guide/cards/restrictions-limits.html#group-limits" click CardPINCode "/guide/cards/modification.html#change-pin" click CardRenew "/guide/cards/renewal.html" click SCTE "/guide/transfers/credit-transfer.html#emitted-credit-transfers-scte" click SCTR "/guide/transfers/credit-transfer.html#received-credit-transfers-sctr" click SCTEInst "/guide/transfers/credit-transfer-inst.html#emitted-instant-credit-transfers-scte-inst" click SCTRInst "/guide/transfers/credit-transfer-inst.html#received-instant-credit-transfers-sctr-inst" click SDDE "/guide/transfers/direct-debit.html#emitted-direct-debits-sdde" click SDDR "/guide/transfers/direct-debit.html#received-direct-debits-sddr" click SCTRRecall "/guide/transfers/sepa-recalls.html#sctr-recalls" click SCTRInstRecall "/guide/transfers/sepa-recalls.html#sctr-inst-recalls" click MassSCTE "/guide/transfers/credit-transfer.html#mass-scte-mass-payout" click SCTERecall "/guide/transfers/sepa-recalls.html#scte-recalls" click SCTEInstRecall "/guide/transfers/sepa-recalls.html#scte-inst-recalls" click Check "/guide/cheques/introduction.html" click Beneficiary "/guide/transfers/beneficiaries.html" click Mandate "/guide/transfers/mandates.html" click Transfer "/guide/transfers/wallet-to-wallet.html" click Document "/guide/user-verification/documents.html" click KYC "/guide/user-verification/introduction.html" ``` --- --- url: /guide/api-basics/templates.md description: >- Implement API templates to customize Treezor API outputs. This guide details Twig 3.x templating, including API calls to list, upload, test, access, and delete templates, and how to manage variables and handle errors. --- # Templates Treezor uses the [Twig 3.x templating engine](https://twig.symfony.com/doc/3.x/). Like other files, [templates should be base64-encoded](/guide/api-basics/data-format#files). ## Twig Basics A template is a file that contains **both structure (sometimes also styling) and instructions to inject content within**. Such as: "display this variable or something else if the variable is unavailable", "iterate on this array", etc. **Information – Limitations of Treezor Twig implementation** * Layouts and Blocks are unavailable * Variables are limited to [those Treezor provides](#to-design-and-test-templates) * CSS styling must be *inlined* (`my link` or within a `` in the page's ``) ## Email templates **Your Email templates must produce HTML; an additional template producing TXT is also required**. This TXT alternative is dedicated to clients that don't support HTML such as screen readers for the visually impaired. ### Example ::: code-group ```html

Confirm your account

Welcome, you are one step away from activating your account!

Validate my account ``` ::: **Reading – More information on how to format templates** * [Twig's official documentation](https://twig.symfony.com/doc/3.x/). ## Checking supported endpoints Not all Treezor endpoints support templates. To check which endpoints can be templated, you can use the following request. ::: code-group ```bash [CURL] curl -X GET '{baseUrl}/customization/templates' \ -H 'Authorization: Bearer {accessToken}' \ -H 'Content-Type: application/json' ``` ::: Returns the list of customizable templates. ::: code-group ```json [JSON] { "templates":[ "email.user.onboarding_confirmation_html", "email.user.onboarding_confirmation_text", "wallet.address_details", "wallet.balance_certificate", "wallet.closure_certificate", "wallet.domiciliation_certificate", "wallet.statement", "email.user.password_forgot_html", "email.user.password_forgot_text", "payout.proof_of_payout" ] } ``` ::: ## Listing available variables To retrieve the list of variables available within a template, you can use the following request. ::: code-group ```bash [CURL] curl -X GET '{baseUrl}/customization/templates/{templateName}' \ -H 'Authorization: Bearer {accessToken}' \ -H 'Content-Type: application/json' ``` ::: Returns the details about the template, including a list of accessible variables (`variables`). ::: code-group ```json [JSON] { "name": "payout.proof_of_payout", "description": "Proof of Payout", "mimeType": "text/html", "variables": { "wallet": { "name": "wallet", "type": "model", "description": "Wallet model", "children": [], "parentName": null }, "user": { "name": "user", "type": "model", "description": "User model", "children": [], "parentName": null }, "payout": { "name": "payout", "type": "model", "description": "Payout model", "children": [], "parentName": null }, "beneficiarie": { "name": "beneficiarie", "type": "model", "description": "Beneficiary model", "children": [], "parentName": null } } } ``` ::: If you attempt to use a non-existent variable, an [error](#errors) is returned. ## Uploading a template All templates must be uploaded to the following endpoint `{baseUrl}/customization/templates/{templateName}/template`, where the `endpointName` URL parameter corresponds to the endpoint to which you want to apply this template. **Your base64-encoded template should not contain line breaks (`\n`)** ### Example ::: code-group ```bash [CURL] curl -X PUT '{baseUrl}/customization/templates/{templateName}/template' \ -H 'Authorization: Bearer {accessToken}' \ -H 'Content-Type: application/json' \ -d '{ "template":"ewogInRvdG8iOiAiQSBtYWduaWZpY2VudCB0ZW1wbGF0ZSAhIiAsCiAiZm9vIjoiYmFyIgp9" }' ``` ::: **Caution – Replacing a Template:** * Takes effect immediately. * Cannot be undone. ## Testing a template To test a template with dummy values, you can use the following request. ::: code-group ```bash [CURL] curl -X GET '{baseUrl}/customization/templates/{templateName}/example' \ -H 'Authorization: Bearer {accessToken}' \ -H 'Content-Type: application/json' ``` ::: Returns an object containing a populated version of your template in the `template` attribute. ::: code-group ```json [JSON] { "template":"PGh0bWw+Cjxib2R5Pgo8aDE+V2VsY29tZTwvaDE+CjxwPlBsZWFzZSA8Yj5jdXJyZW50IHVzZXIgPC9iPmNsaWNrIG9uIHRoZSBsaW5rIHRvIHZhbGlkYXRlIHlvdXIgYWNjb3VudDI6IDxhIGhyZWY9Imh0dHA6Ly9nb29nbGUuZnIiPmhlcmU8L2E+PC9wPgo8L2JvZHk+CjwvaHRtbD4=" } ``` ::: ## Accessing a template To retrieve a template that you have already uploaded, you can use the following request. ::: code-group ```bash [CURL] curl -X GET '{baseUrl}/customization/templates/{templateName}/template' \ -H 'Authorization: Bearer {accessToken}' \ -H 'Content-Type: application/json' ``` ::: Returns an object containing your template in the `template` attribute. ::: code-group ```json [JSON] { "template":"ewogInRvdG8iOiAiUmVuZGVyIG5ldyB0ZW1wbGF0aW5nICEiIAp9" } ``` ::: ## Deleting a template If you want to remove a template altogether, you can use the following request. The endpoint will immediately revert the indicated template to Treezor's default template. ::: code-group ```bash [CURL] curl -X DELETE '{baseUrl}/customization/templates/{templateName}' \ -H 'Authorization: Bearer {accessToken}' ``` ::: ## Using a template To enable your template in a response, add the following header `X-TrzConnect-Custom-Template` with a value of `1`. ::: code-group ```bash [CURL] curl -X GET '{baseUrl}/v1/users' \ -H 'Authorization: Bearer {accessToken}' \ -H 'Content-Type: application/json' \ -H 'X-TrzConnect-Custom-Template: 1' \ # <--- this header enables your template for this response only # [...] parameters hidden for clarity ``` ::: ## Errors If something goes wrong while uploading a template, you can expect an [Error object](/guide/api-basics/response-codes#error-attributes). Its `message` attribute will contain useful debugging details. ### Examples of errors #### The twig template cannot be compiled ::: code-group ```json [JSON] { "errors": [ { "type": "invalid_request", "code": "input_validation_error", "message": "Your template syntax is an invalid twig syntax : \"Unexpected character \"'\" in \"5eeb7991d1cd4\" at line 18.\"", "docUrl": "https://developers.treezor.co" } ] } ``` ::: #### A variable used is not available ::: code-group ```json [JSON] { "errors": [ { "type": "invalid_request", "code": "input_validation_error", "message": "Your template is invalid : \"Variable \"my_variable\" does not exist in \"5eeb7a689e62c\" at line 12.\"", "docUrl": "https://developers.treezor.co" } ] } ``` ::: --- --- url: /guide/api-basics/authentication.md description: >- Master Treezor API authentication. This comprehensive guide covers essential authentication methods, how to use your provided API credentials, and defining scopes and permissions to control API access. --- # Authentication Treezor leverages the [OAuth2 framework](https://en.wikipedia.org/wiki/OAuth) and [JSON Web Token (JWT)](/guide/overview/glossary#json-web-token-jwt) which allows for a wide range of authentication flows. Treezor also relies on [Mutual TLS](mutual-tls) authentication as an additional security layer. **Authenticating is a two-step process:** 1. [Obtaining your token](#obtaining-an-access-token-jwt) – Call the `/oauth/token` endpoint to get a [JWT](/guide/overview/glossary#json-web-token-jwt). 2. [Using the token](#using-the-token) – For each subsequent request, include this JWT in an `Authorization` header. ## Credentials Your credentials are highly sensitive information and are provided to you in an encrypted form. Your `client_id` (integer) and `client_secret` (string) allow you to initiate the [authentication request](#obtaining-an-access-token-jwt), so you can send JWT-enabled requests to the Treezor Connect API. There is a dedicated set of credentials for each [environment](./environments). If you are in need of credentials, please contact your *Treezor Account Manager*. **Best practice – Safe storage recommendations** * Use a `secureString` type in [AWS SSM services](https://docs.aws.amazon.com/en_en/systems-manager/latest/userguide/ssm-agent.html) *(or any robust Vault system)* * Inject them in your application environment variables at the deployment phase. ## Obtaining an access token (JWT) As part of your onboarding process, your *Treezor Account Manager* has provided you with your [credentials](#credentials) including `client_id` and `client_secret`. **Security – Securely store your credentials; it is strictly forbidden to:** * **Hard-code** them *(as a constant, etc.)* * **Commit** them in a version control system *(i.e., configuration file)* * **Store, display, or use** them on the client side *(mobile app, front end, etc.)* If compromised, please contact Treezor immediately to revoke them. Use the following request to get your JWT, using the relevant `{baseUrl}` and credentials depending on the [environment](./environments). ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/oauth/token' \ --form 'grant_type="client_credentials"' \ # required --form 'client_id="{yourClientId}"' \ # required --form 'client_secret="{yourClientSecret}"' # required # --form 'scope="{scope}"' # optional, to specify scope ``` ```php [PHP] // composer require php-curl-class/php-curl-class echo (new Curl\Curl) ->post('{baseUrl}/oauth/token', [ 'grant_type' =>'client_credentials', // required 'client_id' =>'{yourClientId}', // required 'client_secret' =>'{yourClientSecret}', // required // 'scope' =>'{scope}', // optional, to specify scope ]) ->access_token; ``` ```js [Node.JS] const axios = require('axios'); async function authenticate() { try { const baseUrl = '{baseUrl}/'; // replace with your Treezor API base URL const yourClientId = 'your_client_id'; // replace with your client id const yourClientSecret = 'your_client_secret'; // replace with your client secret const response = await axios.post(`${baseUrl}oauth/token`, { grant_type: 'client_credentials', client_id: yourClientId, client_secret: yourClientSecret, }); console.log('Authentication successful!'); console.log('Access token:', response.data.access_token); } catch (error) { if (!error.response) { console.log('Error during network request'); } else { console.log(`Authentification failed with error code ${error.response.status}`); } } } authenticate(); ``` ::: The following JSON object is returned if successful, your JWT being the `access_token`: ::: code-group ```json [JSON] { "token_type": "Bearer", "expires_in": 3600, "access_token": "{accessToken}", "refresh_token": "{refreshToken}" // If refresh feature activated } ``` ::: You are now authenticated to the Treezor API. Keep your `access_token` at hand, since it will be used during the next steps. **Note – The access token expires after 1 hour, so you need to:** * Cache the token (avoiding unnecessary hits to the authentication endpoint) * Renew or [refresh](#refreshing-the-token) the token before it expires (not applicable to all situations) ## Using the token You can now use your JWT in the `Authorization` header to make your API calls as follows: * `Bearer ` – The type of your token. Make sure to keep the capitalization and space. * `{accessToken}` – The JSON Web Token, referred to as the `accessToken` in the documentation examples. The following example illustrates how a typical request to the API is structured. ::: code-group ```bash [CURL] curl -X GET '{baseUrl}/example/of/endpoint' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content: application/json' ``` ```php [PHP] // composer require php-curl-class/php-curl-class use Curl\Curl; $curl = (new Curl) ->setHeader('Authorization', 'Bearer {accessToken}'); echo $curl->get('{baseUrl}/example/of/endpoint'); ``` ::: ## Refreshing the token A token can be refreshed up to a month after the initial authentication. After a month, you will have to start the authentication process again. **Availability – Refresh is only possible with *password grant* and *authorization code* flows** If the `grant_type` is `client_credentials`, you cannot refresh a token. ### Request The following example asks for a refreshed token: ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/oauth/token' \ --form 'grant_type="refresh_token"' \ # required --form 'client_id="{yourClientId}"' \ # required --form 'scope="user admin"' \ # optional, can contain multiple scopes --form 'refresh_token="{yourRefreshToken}"' # required, your previously issued refreshToken ``` ::: ### Response ::: code-group ```json [JSON] { "token_type": "Bearer", "expires_in": 3600, "access_token": "{accessToken}", "refresh_token": "{accessTokenAllowingForJwtRefresh}" } ``` ::: You are now able to use the newly provided token. **Tip – Open-source libraries may help abstract token management** Treezor doesn't provide client libraries or SDKs to consume Treezor API, but some open-source tools are available to help you. ## Scopes & Permissions A Scope is similar to a permission; depending on the scope, you may or may not be able to view and alter certain data. Each [user](/guide/users/introduction) can have one or multiple scopes. **All endpoints are scope-restricted, you need to use an appropriate scope to access an endpoint.** ### Available scopes | Scope | Granted access | |--- |--- | | `read_only` | All **`GET`** endpoints (except `legal` and `admin`) | | `read_write` | All **`PUT`**, **`POST`**, and **`DELETE`** endpoints (except `legal` and `admin`) | | `admin` | **API Configuration** endpoints | | `legal` | **[KYC](/guide/user-verification/introduction), [users](/guide/users/introduction) and [end user documents](/guide/user-verification/documents)** endpoints | **Best practice – Align your Scopes with the default Roles** The [Dashboard](/guide/dashboard/introduction#features) comes with a set of [Roles](/guide/dashboard/dashboard-users#dashboard-user-roles), which are a concatenation of the existing Scopes. Treezor advises you create Roles in the same way for specific developments. ### Scope selection The scope selection happens when [you authenticate](/guide/api-basics/authentication), scopes get embedded in the JWT used for subsequent requests to the API. During authentication, you have the choice to either: * [A) Specify the desired scopes](#a-specify-the-desired-scopes) * [B) Don't specify anything](#b-dont-specify-anything) #### A) Specify the desired scopes In this case, you are provided with the intersection of the **desired scopes** and the **user's available scopes**. The requested scopes are expected in the `scope` request parameter. If more than one scope is requested, they should be space separated (e.g., `admin read_write`). Consider the following **desired scopes** and **user scopes**. ```js user_scopes = ['A', 'B', 'C']; desired_scopes = ['A', 'B', 'D']; ``` The returned token will cover scopes that are present in both: user scopes **and** desired scopes ```js returned_scopes = ['A', 'B']; ``` ##### Example ```bash [CURL] curl -X POST '{baseUrl}/oauth/token' \ --form 'grant_type="client_credentials"' \ # mandatory --form 'client_id="{yourClientId}"' \ # mandatory --form 'client_secret="{yourClientSecret}"' \ # mandatory --form 'scope="admin"' # optional, for specific scope ``` #### B) Don't specify anything In this case, you are provided with **all the user's scopes**. Consider the following **user scopes** and **no desired scopes**. ```js user_scopes = ['A', 'B', 'C']; ``` The returned token will cover all the user's scopes (**so be careful!**). ```js returned_scopes = ['A', 'B', 'C']; ``` ### Scopes behavior When using end user-oriented scopes (`read_only` or `read_write` without other scopes), the API only returns information related to the authenticated user. For the following requests made with the `read_only` scope, the API returns: * `GET /wallets` – The wallets of the authenticated User (and their children's). * `GET /documents` – The documents of the authenticated User (and their children's). --- --- url: /guide/dashboard/beneficiaries.md description: >- Let your team provide support regarding your end users beneficiaries using the Treezor Dashboard. --- # Beneficiaries Beneficiaries are bank accounts that are outside your Treezor ecosystem (as opposed to [Wallets](/guide/dashboard/wallets#wallets)). They are therefore the target of Payouts (SEPA Direct Debit and SEPA Credit Transfers). ## Accessing Beneficiaries You may access beneficiaries information by navigating the *Profile Boards* view, *Beneficiaries* tab [once a user is selected](/guide/dashboard/users#accessing-your-users). The view is broken down into 3 sub-tabs: * **[SEPA Credit Transfer](#sepa-credit-transfer-sub-tab)** – Lists beneficiary bank accounts to which you can make an [SCTE payout](/guide/transfers/credit-transfer#emitted-credit-transfers-scte). * **[SEPA Direct Debit (B2C)](#sepa-direct-debit-b2c-sub-tab)** – Lists beneficiary bank account from which you can make an [SDDR payout](/guide/transfers/direct-debit#received-direct-debits-sddr) (Core). * **[SEPA Direct Debit (B2B)](#sepa-direct-debit-b2b-sub-tab)** – Lists beneficiary bank account from which you can make an [SDDR payout](/guide/transfers/direct-debit#received-direct-debits-sddr) (B2B). ### SEPA Credit Transfer sub-tab The *SEPA Credit Transfer* tab displays all the bank accounts to which funds can be sent with a SEPA Credit Transfer. This operation is referred to as an [SCTE payout](/guide/transfers/credit-transfer#emitted-credit-transfers-scte) and can be made from the [Dashboard](transfers#transfers-from-wallet-to-external-bank-account). You can initiate such Payouts in the Dashboard from the *Wallets* tab. For each beneficiary, the following fields are available: * **Status** – Either "Activated" or "Deactivated" * **Name** – Displays the name of the beneficiary followed by the Tag in parentheses. * **IBAN** * **BIC** The following commands are available: |      | Action | Description | | :---: | --- | --- | | | **View** | Displays the *Beneficiary details* popup. | | | **Edit** | Displays the *Edit Beneficiary* popup. | ### SEPA Direct Debit (B2C) sub-tab The *SEPA Direct Debit (B2C)* tab displays all the bank accounts from which Wallets can be debited, using a SEPA Direct Debit. This operation is referred to as an [SDDR payout](/guide/transfers/direct-debit#received-direct-debits-sddr). Beneficiaries in this tab are automatically created when debiting a Wallet using a SEPA Direct Debit (SDDR). For each beneficiary, the following fields are available: * **Status** – Either "Activated" or "Deactivated" * **Name** – Displays the name of the beneficiary followed by the Tag in parentheses. * **IBAN** * **BIC** * **[SEPA Creditor Identifier](/guide/overview/glossary#sepa-creditor-identifier-sci)** – The unique reference of an SDDR. * **Whitelist** – List of [Unique Mandate Reference (UMR)](/guide/overview/glossary#unique-mandate-reference-umr) that have debited the user. * **Blacklist** – List of [Unique Mandate Reference (UMR)](/guide/overview/glossary#unique-mandate-reference-umr) that are revoked. The following commands are available: |      | Action | Description | | :---: | --- | --- | | | **View** | Displays the *Beneficiary details* popup. | | | **Edit** | Displays the *Edit Beneficiary* popup. | ### SEPA Direct Debit (B2B) sub-tab The *SEPA Direct Debit (B2B)* tab displays all the bank accounts from which Wallets can be debited, using a SEPA Direct Debit. This operation is referred to as an [SDDR payout](/guide/transfers/direct-debit#received-direct-debits-sddr). A beneficiary must be created first in order to be able to receive SEPA Direct Debit in B2B context. Indeed, the unique mandate reference is necessary for the reception of a SEPA Direct Debit. For each beneficiary, the following fields are available: * **Status** – Either "Activated" or "Deactivated" * **Name** – Displays the name of the beneficiary followed by the Tag in parentheses. * **IBAN** * **BIC** * **[SEPA Creditor Identifier](/guide/overview/glossary#sepa-creditor-identifier-sci)** – The unique reference of an SDDR. * **Whitelist** – List of allowed [Unique Mandate Reference (UMR)](/guide/overview/glossary#unique-mandate-reference-umr), which is mandatory for B2B Direct Debit. The following commands are available: |      | Action | Description | | :---: | --- | --- | | | **View** | Displays the *Beneficiary details* popup. | | | **Edit** | Displays the *Edit Beneficiary* popup. | ## Creating Beneficiaries To create a new Beneficiary, click on the "Create Beneficiary" button located in the upper right-corner of the *Beneficiaries* tab. The *Add Beneficiary* popup is displayed and provides different fields to fill in depending on the kind of beneficiary you wish to create (SEPA Credit Transfer, SEPA Direct Credit, or B2B SEPA Direct Debit). In the specific case of B2B SEPA Direct Debit, you need to fill in information about the Mandate for the SDDR to be processed. * **Mandate reference** – The [Unique Mandate Reference (UMR)](/guide/overview/glossary#unique-mandate-reference-umr). * **Recurrent** – Toggle the option if the mandate is a recurring payment. * **Wallet ID** – When specified, the SDD will only be accepted if the targeted wallet is the indicated one. --- --- url: /guide/acquiring/preauthorized.md description: >- Technical guide for capturing a preauthorized amount from a tokenized third-party card. Includes required parameters, request structure, and response examples. --- # Advanced capture This approach is often useful when the amount to capture is not accurately known at the time the authorization is issued. In such situations, you: 1. **Authorize an amount** to capture within 7 days later. 2. **Create one or more payins** against that authorization without exceeding the total authorized amount. Any remaining funds are automatically freed up after 7 days. This feature is only available with some [paymentProducts](/guide/acquiring/introduction#payment-products-specificities). **Prerequisites – Steps to complete before the authorization:** * [Tokenize the card](/guide/acquiring/card-tokenization) * [Create a Topup Card](/guide/acquiring/card-tokenization#associate-the-card-to-a-user) to associate with the user (if needed) ## Authorize an amount To authorize an amount, use the following endpoint, which accepts the same payload as the [direct capture](./direct-capture). ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/v1/topups/cards/authorizations' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is a `{payload}` example: ::: code-group ```json [JSON] { "amount": 20, "currency": "EUR", "walletId": "{{walletId}}", "userId": "{{userId}}", "paymentProduct": "visa", "topupCardId": "{{topupCardId}}", "messageToUser": "string", "acceptUrl": "acceptURL", "declineUrl": "declineURL", "pendingUrl": "pendingURL", "exceptionUrl": "exceptionURL", "cancelUrl": "cancelURL", "eci": "9", "authenticationIndicator": "2", "orderId": "{{order_Id}}", // According to best practices "description": "string", "deviceChannel": 0, "browserInfo": { "javaEnabled": true, "javascriptEnabled": true, "ipaddr": "0.0.0.0", "httpAccept": "string", "httpUserAgent": "string", "language": "string", "colorDepth": 8, // Can be: 1, 4, 8, 15, 16, 32, 48 "screenHeight": 0, "screenWidth": 0, "timezone": "string", "deviceFingerprint": "string" }, "firstname": "Alex", "lastname": "Oak", "email": "aoak@example.com", "phone": "string", "streetAddress": "string", "city": "string", "zipCode": "string", "country": "string", "cardHolder": "A Oak" } ``` ::: Returns the Authorization and sends an [`authorization.create`](./events#authorization-create) webhook which contains the authorization UUID necessary to create payin(s) in the next step. ::: code-group ```json [JSON] { "authorizations": [ { "authorizationId": "6de434ff-d2c5-511f-820c-6748385f2b42", "userId": "100655503", "walletId": "3152544", "userFirstname": "Alex", "walletEventName": "Main Account", "walletAlias": "main-account-669f5b8e1e9cf", "userLastname": "Oak", "messageToUser": "The financial institution has approved the payment.", "authorizationStatus": "PENDING", "paymentMethodId": "25", "amount": 20, "currency": "EUR", "createdDate": "", "codeStatus": "150116", "informationStatus": "Authorized", "refundAmount": 0, "profile": "00001342501", "DbtrIBAN": null, "clientId": "998423", "createdIp": "0.0.0.0", "authorizationTag": "", "cartId": 0, "subtotalItems": "0.00", "subtotalServices": "0.00", "subtotalTax": "0.00", "distributorFee": null, "paymentHtml": null, "paymentLanguage": null, "paymentPostUrl": null, "paymentPostDataUrl": null, "paymentAcceptedUrl": null, "paymentWaitingUrl": null, "paymentCanceledUrl": null, "paymentRefusedUrl": null, "paymentExceptionUrl": null, "ibanFullname": null, "ibanId": null, "ibanBic": null, "ibanTxEndToEndId": null, "ibanTxId": null, "forwardUrl": "", "authorizationDate": "0000-00-00", "mandateId": "0", "creditorName": null, "creditorAddressLine": null, "creditorCountry": null, "creditorIban": null, "creditorBIC": null, "virtualIbanId": null, "virtualIbanReference": null, "additionalData": "{\"card\":{\"externalProvider\":{\"state\":\"completed\",\"reason\":\"\",\"forwardUrl\":\"\",\"test\":\"true\",\"mid\":\"00001342501\",\"attemptId\":\"1\",\"authorizationCode\":\"no_code\",\"transactionReference\":\"800312407023\",\"dateCreated\":\"2024-07-23T07:30:10+0000\",\"dateUpdated\":\"2024-07-23T07:30:14+0000\",\"dateAuthorized\":\"2024-07-23T07:30:14+0000\",\"status\":\"116\",\"message\":\"Authorized\",\"authorizedAmount\":\"10.00\",\"capturedAmount\":\"0.00\",\"refundedAmount\":\"0.00\",\"creditedAmount\":\"0.00\",\"decimals\":\"2\",\"currency\":\"EUR\",\"ipAddress\":\"0.0.0.0\",\"ipCountry\":\"\",\"deviceId\":\"\",\"cdata1\":\"998423\",\"cdata2\":\"3152544\",\"cdata3\":\"100655503\",\"cdata4\":\"\",\"cdata5\":\"\",\"cdata6\":\"\",\"cdata7\":\"\",\"cdata8\":\"\",\"cdata9\":\"\",\"cdata10\":\"\",\"avsResult\":\"\",\"eci\":\"9\",\"paymentProduct\":\"visa\",\"paymentMethod\":{\"token\":\"f1bed3b91285747c2e5d332a41580e710b726880e4149fb999f271618b8d03c3\",\"cardId\":\"9fd81707-8f41-4a01-b6ed-279954336ada\",\"brand\":\"VISA\",\"pan\":\"411111******1111\",\"cardHolder\":\"M FRAY\",\"cardExpiryMonth\":\"08\",\"cardExpiryYear\":\"2029\",\"issuer\":\"CONOTOXIA SP. Z O.O\",\"country\":\"PL\"},\"threeDSecure\":\"\",\"fraudScreening\":{\"scoring\":\"0\",\"result\":\"NOT_LAUNCHED\",\"review\":\"\"},\"order\":{\"id\":\"order_1234567890\",\"dateCreated\":\"2024-07-23T07:30:10+0000\",\"attempts\":\"1\",\"amount\":\"10.00\",\"shipping\":\"0.00\",\"tax\":\"0.00\",\"decimals\":\"2\",\"currency\":\"EUR\",\"customerId\":\"\",\"language\":\"en_US\",\"email\":\"\"},\"debitAgreement\":{\"id\":\"11209240\",\"status\":\"available\"}}}}" } ] } ``` ::: ## Capture the funds To capture funds after an authorization, use the following request. ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/v1/topups/cards/authorizations/{authorizationId}/payins' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "amount":10, "currency":"EUR" } ``` ::: Returns the Payin and sends [`payin.create`](./events#payin-create) and [`payin.update`](/guide/acquiring/events#payin-update) webhooks. ::: code-group ```json [JSON] { "payins": [ { "payinId": "89f82b27-be27-527c-9b93-eab65fb7a0e4", "userId": "100655503", "walletId": "3152544", "userFirstname": "John", "walletEventName": "Event_test", "walletAlias": "event-test-669f5b8e1e9cf", "userLastname": "Smith", "messageToUser": "The financial institution has processed the payment.", "payinStatus": "VALIDATED", "paymentMethodId": "25", "amount": 10, "currency": "EUR", "createdDate": "", "codeStatus": "150118", "informationStatus": "Captured", "refundAmount": 0, "profile": "00001342501", "DbtrIBAN": null, "createdIp": "0.0.0.0", "payinTag": "", "cartId": 0, "subtotalItems": "0.00", "subtotalServices": "0.00", "subtotalTax": "0.00", "distributorFee": null, "paymentHtml": null, "paymentLanguage": null, "paymentPostUrl": null, "paymentPostDataUrl": null, "paymentAcceptedUrl": null, "paymentWaitingUrl": null, "paymentCanceledUrl": null, "paymentRefusedUrl": null, "paymentExceptionUrl": null, "ibanFullname": null, "ibanId": null, "ibanBic": null, "ibanTxEndToEndId": null, "ibanTxId": null, "forwardUrl": null, "payinDate": "0000-00-00", "mandateId": "0", "creditorName": null, "creditorAddressLine": null, "creditorCountry": null, "creditorIban": null, "creditorBIC": null, "virtualIbanId": null, "virtualIbanReference": null, "additionalData": "{\"card\":{\"externalProvider\":{\"operation\":\"capture\",\"test\":\"true\",\"mid\":\"00001342501\",\"authorizationCode\":\"no_code\",\"transactionReference\":\"800312407520\",\"dateCreated\":\"2024-07-23T08:59:40+0000\",\"dateUpdated\":\"2024-07-23T09:06:49+0000\",\"dateAuthorized\":\"2024-07-23T08:59:44+0000\",\"status\":\"118\",\"message\":\"Captured\",\"authorizedAmount\":\"10.00\",\"capturedAmount\":\"10.00\",\"refundedAmount\":\"0.00\",\"decimals\":\"2\",\"currency\":\"EUR\"}}}" } ] } ``` ::: **Note – You can create several captures for an authorization if both:** * The total amount doesn't exceed the initial authorization amount. * The capture occurs within 7 days of the authorization. --- --- url: /guide/acquiring/direct-capture.md description: >- Technical guide for capturing funds from a tokenized third-party card directly, without going through the authorization step first. Includes required parameters, request structure, and response examples. --- # Direct capture You can request a capture of funds using either the Topup Card or an alternate means of payment (specified in the `paymentProduct` parameter). This doesn't require an authorization first. **Prerequisites – Steps to complete before the capture:** * [Tokenize the card](/guide/acquiring/card-tokenization) * [Create a Topup Card](/guide/acquiring/card-tokenization#associate-the-card-to-a-user) to associate with the user (if needed) You can then use the usual [`/v1/payins`](/api-reference/api-endpoints.html#tag/Payins/postPayin){target="\_self"} request with attributes specific to the Card Acquiring feature as described in this article. ## Parameters | Attribute | Type | Description | | --- | --- | --- | | `walletId` | string | The unique identifier of the Wallet to be credited. | | `userId` | string | The unique identifier of the User requesting the topup. | | `topupCardId` | string | The unique identifier of the Topup Card, if any. | | `profile` | string | Your HiPay Merchant ID. Required if you have multiple MIDs, otherwise empty. | | `orderId` | string | The unique identifier of the order, ensuring the uniqueness of the transaction. Must be unique (so different from tokenization) and abide by the following rules: Length: min. 32 charactersStructure: `_order_` | | `amount` | number | The amount of the operation. | | `currency` | string | Currency of the operation. Format: [ISO-4217](/guide/api-basics/data-format). | | `acceptUrl` | string | The URL to which the user is returned when the payment process is successfully completed. | | `declineUrl` | string | The URL to which the user is returned when the acquirer declines the payment. | | `pendingUrl` | string | The URL to which the user is returned when the payment request was submitted to the acquirer, but the response is not available yet. | | `exceptionUrl` | string | The URL to which the user is returned when there is an error or a system failure. | | `cancelUrl` | string | The URL to which the user is returned when the payment is canceled. | | `eci` | string | The security level at which the payment information is processed. `7` – **One-time** payment (allowing for 3DS)`9` – **Recurring** payments (following an `eci=7`) Any capture made with `9` must have a previous successful authorization or transaction with an `eci` valued to `7` that enforced 3DS. | | `authenticationIndicator` | string | Whether 3DS should be performed for the transaction. Set the value to `2` for 3DS. | | `description` | string | The description of the operation. | | `paymentProduct` | string | Can be: `cb`, `visa`, `mastercard`, `ideal`, `sofort-uberweisung`. | | `issuerBankId` | string | The Bank Identifier Code of the end user's issuing bank. Only used if the `paymentProduct` is `ideal`. | | `ipaddr` | string | The IP address of the end user's device. | | `browserInfo` | object | Object containing information regarding the end user's browser. | | `firstname` | string | The first name of the user. | | `lastname` | string | The last name of the user. | | `email` | string | The email of the user. | | `phone` | string | The phone number of the user. | | `streetAddress` | string | The residence street name and number of the user. | | `city` | string | The residence city of the user. | | `zipCode` | string | The residence city zipcode of the user. | | `country` | string | The residence country of the user. Format: ISO 3166 alpha-2 | | `cardHolder` | string | The name associated to the card. | | `deviceChannel` | integer | The PSD2 Channel through which the transaction is being processed. | ## Request ::: code-group <<< @/guide/transfers/snippets/create\_payin.bash \[CURL] ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "amount": 10, "currency": "EUR", "walletId": "3152544", "userId": "100655503", "paymentProduct": "visa", "topupCardId": "3252046c-6138-44f1-a24d-8807974c7ec3", "messageToUser": "string", "acceptUrl": "acceptURL", "declineUrl": "declineURL", "pendingUrl": "pendingURL", "exceptionUrl": "exceptionURL", "cancelUrl": "cancelURL", "eci": "9", "authenticationIndicator": "2", "orderId": "order_test_1234567878911", "description": "string", "deviceChannel": 0, "browserInfo": { "javaEnabled": true, "javascriptEnabled": true, "ipaddr": "0.0.0.0", "httpAccept": "string", "httpUserAgent": "string", "language": "string", "colorDepth": 8, // Can be: 1, 4, 8, 15, 16, 32, 48 "screenHeight": 0, "screenWidth": 0, "timezone": "string", "deviceFingerprint": "string" }, "firstname": "Alex", "lastname": "Oak", "email": "aoak@example.com", "phone": "string", "streetAddress": "string", "city": "string", "zipCode": "string", "country": "string", "cardHolder": "A Oak" } ``` ::: Returns the following object and sends the [`authorization.create`](./events#authorization-create), [`payin.create`](./events#payin-create), and [`payin.udpate`](./events#payin-update) webhooks. ::: code-group ```json [JSON] { "state": "completed", "reason": "", "forwardUrl": "", // Redirect the user to this URL if populated "test": "true", "mid": "00001340255", "attemptId": "1", "authorizationCode": "test123", "transactionReference": "800150032845", "referenceToPay": "", "dateCreated": "2022-01-26T13:45:11+0000", "dateUpdated": "2022-01-26T13:45:17+0000", "dateAuthorized": "2022-01-26T13:45:17+0000", "status": "118", "message": "Captured", "authorizedAmount": "40.99", "capturedAmount": "40.99", "refundedAmount": "0.00", "creditedAmount": "0.00", "decimals": "2", "currency": "EUR", "ipAddress": "0.0.0.0", "ipCountry": "", "deviceId": "", "cdata1": "212707", "cdata2": "878744", "cdata3": "1656177", "cdata4": "", "cdata5": "", "cdata6": "", "cdata7": "", "cdata8": "", "cdata9": "", "cdata10": "", "avsResult": "", "eci": "9", "paymentProduct": "visa", "paymentMethod": { "token": "48d8ad7f642bff96387b14f0b060ad6a6194e91debc30aa0b31bdcd5a0a6680a", "cardId": "9fd81707-8f41-4a01-b6ed-279954336ada", "brand": "VISA", "pan": "411111******1111", "cardHolder": "TOM PES", "cardExpiryMonth": "12", "cardExpiryYear": "2025", "issuer": "JPMORGAN CHASE BANK, N.A.", "country": "US" }, "threeDSecure": "", "fraudScreening": { "scoring": "0", "result": "NOT_LAUNCHED", "review": "" }, "order": { "id": "order_test1643204709", "dateCreated": "2022-01-26T13:45:11+0000", "attempts": "1", "amount": "40.00", "shipping": "0.00", "tax": "0.00", "decimals": "2", "currency": "EUR", "customerId": "", "language": "en_US", "email": "" }, "debitAgreement": { "id": "10347296", "status": "available" } } ``` ::: **To know the actual payment status, please see the Payin `status` attribute of the `authorization.create`, [`payin.create`](./events#payin-create) and `payin.update` webhooks**. ## Forwarding If the `forwardUrl` attribute is populated in the response, you must redirect the end user to this URL for them to complete the funds capture process. See the list of [payment products](/guide/acquiring/introduction#payment-products-specificities) to know when redirection is necessary. When a forwarding occurs, Treezor won't send any webhook until the end user has completed the steps available at the `forwardUrl`. ## Payin status (`codeStatus`) Below the list of payin `codeStatus` values specific to the Card Acquiring feature. --- --- url: /guide/acquiring/errors.md description: >- Troubleshoot and handle card acquiring-related issues using the Treezor API's complete list of error codes, messages, and their corresponding meanings. --- # Errors **Caution – Only the legacy API sends the error code in HTTP errors** When handling errors with Connect, only the `message` attribute is returned. ## Refunds | Code | Type | `message` | |---------|---------------------|-----------------------------------------------------------------------------------| | 0001 | missingFieldError | `This field is missing. : [user]` | | 0002 | invalidRequestError | `This payin is not refundable: payin not validated` | | 0002 | invalidRequestError | `This payin is not refundable: balance not impacted yet` | | 0002 | invalidRequestError | `This payin is not refundable` | | 0002 | invalidRequestError | `Requested refund is higher than the remaining refundable amount for this payin` | | 0002 | invalidRequestError | `A refund for a payin in this transaction is ongoing. Please retry in few minutes.` | | 0002 | invalidRequestError | `Wallet not found` | | 0002 | invalidRequestError | `Wallet is not validated` | | 0002 | invalidRequestError | `User not found` | | 0002 | invalidRequestError | `User is frozen` | | 0002 | invalidRequestError | `User is not in valid status (8)` | | 0003 | internalServerError | `Internal server error` | | 0005 | notFoundError | `Payin not found` | | 0005 | notFoundError | `Wallet not found` | | 00010 | unauthorizedError | `Access to this payin is forbidden for the provided clientId` | | {anyHipayErrorCode} | hipayError | `Amount Limit Exceeded` | --- --- url: /guide/acquiring/legacy-v1.md description: >- A quick guide to the first version of Treezor Card Acquiring feature to help you migrate to the enhanced and optimized card top-ups. --- # Legacy flow This article focuses on the first version of the Acquiring feature provided by Treezor. It doesn't offer as many features as the newest services. If you have any doubt, don't hesitate to contact Treezor. Payments received using HiPay's API create **Payin** objects with a `paymentMethodId` attribute set to `25` and send [`payin.create`](events#payin-create) webhooks. **Feature activation – Contact Treezor to activate the supported cards** The Card Acquiring V1 feature supports the following cards: CB, Visa, Mastercard, and Maestro. **Best practice – Store Payin Ids as 36-character-long strings** It will facilitate your migration to acquiring v2, in which Ids are [UUIDv4](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_\(random\)). ## Step 1, Tokenize the card Tokenization is the process of converting the [PAN](/guide/overview/glossary#pan-primary-account-number), expiration date and [CVC](/guide/overview/glossary#cvc-card-verification-number) of a card into a token. The tokenization request must be sent from the end user's device (for example using Javascript), as the [PAN](/guide/overview/glossary#pan-primary-account-number) cannot transit or be stored on your servers. You may generate the token either: * **If you're not PCI DSS certified** – Generate the token [using the secure form](#process-if-you-re-not-pci-dss-certified) ([HiPay’s Hosted Page](https://developer.hipay.com/api-explorer/hpayment-api#/payments/post_v1_hpayment)), or relying on secure fields ([HiPay’s Hosted Fields](https://developer.hipay.com/online-payments/payment/hosted-fields)). * **If you're PCI DSS certified** – Generate the token directly [using the dedicated endpoint](#process-if-you-re-pci-dss-certified). ### Process if you're not PCI DSS certified If you are not PCI DSS certified, HiPay provides two endpoints so you can: 1. Generate the token of the card using a secure form. 2. Retrieve the generated token. #### 1. Generate token through secure form You can make the following HiPay request to generate the form that will then be used by the end user to tokenize the card. ::: code-group ```bash [CURL] # encode your private credentials in base64 hipayPrivateCredentials=`echo "myprivateuser:myprivatepassword" | base64 -` # tokenize the card curl -X POST '{hiPayTokenizationFormBaseUrl}/v1/hpayment' \ --header 'Authorization: Basic {hipayPrivateCredentials}' \ # as encoded above --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}`. Please bear in mind that the choice of `operation` impacts the capture mode, which depends on your configuration. Contact Treezor if you're unsure of which one to use. ::: code-group ```json [JSON] { "orderid": "order_xxxxx", // Must be unique "operation": "Authorization", // Authorization || Sale // custom_data error will result in the funds being debited from external account, // but not credited on the Treezor Wallet of the real beneficiary of the capture. "custom_data" : { "1":"{{clientId}}", "2":"{{temp_walletId}}", "3":"{{temp_userId}}" }, // Please don't use other custom_data than the ones indicated above. "payment_product_list": "visa, mastercard, cb", "template": "basic-js", "merchant_display_name": "Merchant name", "display_selector": "1", "description": "description", "email": "a.oak@example.com", "card_holder": "Alex Oak", "currency": "EUR", "amount": "1.00", "ipaddr": "", // IP of the device from which the capture is made "accept_url": "", "decline_url": "", "pending_url": "", "exception_url": "", "cancel_url": "", "language": "FR_fr", // Cardholder authentification "eci" : "7", // single-use mode "authentication_indicator": "2", // forces 3DS "device_channel" : "2", "multi_use" : 1 } ``` ::: Returns an object containing the `forwardUrl` you need to provide to your end user. ::: code-group ```json [JSON] { "forwardUrl": "https://stage-secure-gateway.hipay-tpp.com/0000-133-2882/payment/web/pay/50b6814c-27fd-49e2-adea-33bba7150c9c", "test": "true", "mid": "00001332882", "cdata1": "39625", "cdata2": "2220766", "cdata3": "4064148", "cdata4": "", // Deprecated, please ignore "cdata5": "", // Deprecated, please ignore "cdata6": "", // Deprecated, please ignore "cdata7": "", // Deprecated, please ignore "cdata8": "", // Deprecated, please ignore "cdata9": "", // Deprecated, please ignore "cdata10": "", // Deprecated, please ignore "order": { "id": "order_1685549327", "dateCreated": "2023-05-31T16:08:47+0000", "attempts": "0", "amount": "1.00", "shipping": "0.00", "tax": "0.00", "decimals": "2", "currency": "EUR", "customerId": "", "language": "FR", "email": "aoak@example.com" } } ``` ::: By using the `forwardUrl`, your end user accesses the form to enter their card information, which will in turn generate the token. **Reading – Full parameters & customization documentation available** Please refer to HiPay's documentation: * [API Explorer](https://developer.hipay.com/api-explorer/api-online-payments#/payments/generateHostedPaymentPage) for all the parameters. * [Hosted Payments](https://developer.hipay.com/online-payments/payment/hosted-payments#customize) to learn how to customize your hosted payment form. **Tip – Direct capture scenario** Your configuration may allow you to use the secure form for a direct capture by setting the `multi_use` parameter to `0` and the `operation` parameter to `Sale`. #### 2. Retrieve the token The token generation step being an authorization (hence no funds are moved), Treezor doesn't send any payin webhook. Here is how to retrieve the `token` and `paymentProduct` for the payment. ::: code-group ```bash [CURL] # encode your public credentials in base64 hipayPublicCredentials=`echo "mypublicuser:mypublicpassword" | base64 -` # tokenize the card curl -X GET '{hiPayTokenizationBaseUrl}/rest/v1/transaction?orderId={orderid}' \ --header 'Authorization: Basic {hipayPublicCredentials}' \ # as encoded above --header 'Accept: application/json' ``` ::: Returns the following: ::: code-group ```json [JSON] {37,39} { "transaction": { "state": "completed", "reason": "", "forwardUrl": "", "test": "true", "mid": "00001332882", "attemptId": "1", "authorizationCode": "", "transaction_reference": "800242932739", "dateCreated": "2023-06-30T09:07:41+0000", "dateUpdated": "2023-06-30T09:07:52+0000", "dateAuthorized": "2023-06-30T09:07:52+0000", "status": "116", "message": "Authorized", "authorizedAmount": "1.00", "capturedAmount": "0.00", "refundedAmount": "0.00", "decimals": "2", "currency": "EUR", "ipAddress": "212.114.31.26", "ipCountry": "FR", "deviceId": "", "cdata1": "client_id", "cdata2": "wallet_id", "cdata3": "user_id", "cdata4": "", "cdata5": "", "cdata6": "", "cdata7": "", "cdata8": "", "cdata9": "", "cdata10": "", "avsResult": "", "cvcResult": "", "eci": "7", "paymentProduct": "visa", "paymentMethod": { "token": "ba3dd3760142bd6fc715b99429839b06d6de6bd1c6f1eaf36a788668396d011d", "cardId": "b1113d3b-5140-4616-abf7-49aeec3f4414", "brand": "VISA", "pan": "424242******4242", "cardHolder": "ALEX OAK", "cardExpiryMonth": "05", "cardExpiryYear": "2024", "issuer": "", "country": "GB" }, "threeDSecure": { "eci": "5", "authenticationStatus": "Y", "authenticationMessage": "Authentication Successful", "authenticationToken": "", "xid": "" }, "fraudScreening": { "scoring": "0", "result": "ACCEPTED", "review": "" }, "order": { "id": "order_1688116033", "dateCreated": "2023-06-30T09:07:12+0000", "gender": "U", "firstname": "", "lastname": "", "streetAddress": "", "locality": "", "postalCode": "", "country": "", "attempts": "1", "amount": "1.00", "shipping": "0.00", "tax": "0.00", "decimals": "2", "currency": "EUR", "customerId": "", "language": "FR", "msisdn": "", "phone": "", "phoneOperator": "", "shippingAddress": { "firstname": "", "lastname": "", "streetAddress": "", "locality": "", "postalCode": "", "country": "" }, "email": "teamimplem@test.com" }, "debitAgreement": { "id": "10520843", "status": "available" } } } ``` ::: **Reading – Full parameters documentation available** Refer to [HiPay's Documentation](https://developer.hipay.com/api-explorer/api-online-payments#/transaction/getTransactionsByReference) to learn everything there is to know about the parameters. ### Process if you're PCI DSS certified #### Parameters | Attribute | Type | Description | | --- | --- | --- | | `card_number` | string | The [primary account number (PAN)](/guide/overview/glossary#pan-primary-account-number) of the card. | | `card_expiry_month` | integer | The month on which the card expires. | | `card_expiry_year` | integer | The year on which the card expires. | | `card_holder` | string | The name of the cardholder, embossed or etched on the card. | | `cvc` | integer | The [CVC](/guide/overview/glossary#cvc-card-verification-number) of the card. | | `multi_use` | integer | Indicates whether the card can be used multiple times. Either: `0` – The card can only be used once, and the token expires after a month if not used.`1` – The card can be used multiple times and the token expires at the card expiry date. | In addition, you'll need your `hipayPublicCredentials` in the request Authorization header. It is a concatenation of `hipay_public_user` `:` `hipay_public_password` credentials, without spaces and encoded in base64. #### Request example ::: code-group ```bash [CURL] # encode your public credentials in base64 hipayPublicCredentials=`echo "mypublicuser:mypublicpassword" | base64 -` # tokenize the card curl -X POST '{hiPayTokenizationBaseUrl}/rest/v2/token/create' \ --header 'Authorization: Basic {hipayPublicCredentials}' \ # as encoded above --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "card_number":"5300000000000006", "card_expiry_month":12, "card_expiry_year":2025, "card_holder":"Alex Oak", "cvc":123, "multi_use":1 } ``` ::: Returns the `token` of the card. ::: code-group ```json [JSON] { "token": "ee9ac2901f4c0d651143664659f206bb6e34ee552ab4e693fa21616b0ef69a57", "request_id": "0", "card_id": "9fd81707-8f41-4a01-b6ed-279954336ada", "multi_use": 1, "brand": "VISA", "pan": "411111xxxxxx1111", "card_holder": "Alex Oak", "card_expiry_month": "12", "card_expiry_year": "2025", "issuer": "JPMORGAN CHASE BANK, N.A.", "country": "US", "card_type": "CREDIT", "forbidden_issuer_country": false } ``` ::: **Warning – Authorize tokenized cards first with `eci`=`7` payment to enforce 3DS** You must receive a successful payment before you can either use it with `eci` = `9` or store the `cardtoken` in your database. If you're encountering an error, please check out the [HiPay's error codes](https://developer.hipay.com/payment-fundamentals/essentials/error-messages) documentation. ## Step 2, Create the payment After you have tokenized the card, you can use this token to request a payment, crediting the [Wallet](/guide/wallets/introduction) of your choice. ### Parameters | Attribute | Type | Description | | --- | --- | --- | | `custom_data` | object | Allows you to associate the payment with the Wallet and User. `custom_data[1]` – **Your [client\_id](/guide/api-basics/authentication#credentials)**`custom_data[2]` – **The recipient's [Wallet](/guide/wallets/introduction) id**`custom_data[3]` – **The recipient's [User](/guide/users/introduction) id** | | `cardtoken` | string | The token of the card, as obtained in the tokenization step. | | `accept_url` | string | The URL to which the user is to be redirected in case of an authorized payment. | | `decline_url` | string | The URL to which the user is to be redirected in case of a declined payment. | | `pending_url` | string | The URL to which the user is to be redirected in case of the payment is left pending. | | `exception_url` | string | The URL to which the user is to be redirected in case they can the payment. | | `cancel_url` | string | The URL to which the user is to be redirected in case of | | `eci` | string | The security level at which the payment information is processed. `7` – **One-time** payment (allowing for 3DS)`9` – **Recurring** payments (following an `eci=7`) Any capture made with `9` must have a previous successful authorization or transaction with an `eci` valued to `7` that enforced 3DS. | | `authentication_indicator` | string | Indicates how to handle 3DS. Can be: `0` – Bypasses 3DS `1` – 3DS will be used if the card allows it`2` – Forces the use of 3DS | | `hipayPrivateCredentials` | string | The concatenation of `hipay_private_user` `:` `hipay_private_password` [HiPay credentials](/guide/acquiring/introduction#hipay-environments-credentials), without spaces and encoded in base64. | **Warning – Authorize tokenized cards first with `eci`=`7` payment to enforce 3DS** You must receive a successful payment before you can either use it with `eci` = `9` or store the `cardtoken` in your database. ### Request ::: code-group ```bash [CURL] # encode your private credentials in base64 hipayPrivateCredentials=`echo "myprivateuser:myprivatepassword" | base64 -` # receive the payment curl -X POST '{hiPayBaseUrl}/rest/v1/order' \ --header 'Authorization: Basic {hipayPrivateCredentials}' \ # as encoded above --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}`. ::: code-group ```json [JSON] { "orderid":"Order_yyyyy", // Must be unique (so different from step 1) "operation":"Sale", "description":"IMP1639671746", "currency":"EUR", "amount":"100", "ipaddr":"192.154.28.65", "custom_data":{ "1":"123456",  // your client_id "2":"234567",  // the walletId to credit "3":"345678" // the userId to credit }, // Please don't use other custom_data than the ones indicated above. "eci": "9", // or 7 if no eci in used in step 1 "authentication_indicator":"2", // see list above "email":"teamimplem@test.com", // the cardholders email "card_holder":"Tom Pes", // the cardholders name as embossed or etched on the card "cardtoken":"{{temp_HiPayToken}}", "payment_product":"visa", "accept_url":"https://dictionary.cambridge.org/fr/dictionnaire/anglais/accept", // redirection URL in case of authorized payment "decline_url":"https://dictionary.cambridge.org/fr/dictionnaire/anglais/decline", // redirection URL in case of declined payment "pending_url":"https://dictionary.cambridge.org/fr/dictionnaire/anglais/pending", // redirection URL in case the payment is left pending "exception_url":"https://dictionary.cambridge.org/fr/dictionnaire/anglais/exception", // redirection URL in case of fatal error "cancel_url":"https://dictionary.cambridge.org/fr/dictionnaire/anglais/cancel", // redirection URL in case the end user cancels the payment "device_channel":"1" } ``` ::: **Reading – Full parameters documentation available** Refer to [HiPay's Documentation](https://support.hipay.com/hc/en-us/articles/360010582280-HiPay-Enterprise-Hosted-Fields-with-JavaScript-SDK-and-order-API) to learn everything there is to know about the parameters. Returns the details regarding the capture. ::: code-group ```json [JSON] { "state": "completed", "reason": "", "forwardUrl": "", "test": "true", "mid": "00001332882", "attemptId": "1", "authorizationCode": "test123", "transaction_reference": "800143609738", "referenceToPay": "", "dateCreated": "2021-12-21T13:42:15+0000", "dateUpdated": "2021-12-21T13:42:20+0000", "dateAuthorized": "2021-12-21T13:42:19+0000", "status": "118", "message": "Captured", "authorizedAmount": "100.00", "capturedAmount": "100.00", "refundedAmount": "0.00", "creditedAmount": "0.00", "decimals": "2", "currency": "EUR", "ipAddress": "192.154.28.65", "ipCountry": "CA", "deviceId": "", "cdata1": "212707", // is your client_id as provided previously "cdata2": "1174278", // is the recipients walletId as provided previously "cdata3": "2189821", // is the recipients userId as provided previously "cdata4": "", "cdata5": "", "cdata6": "", "cdata7": "", "cdata8": "", "cdata9": "", "cdata10": "", "avsResult": "", "eci": "9", "paymentProduct": "visa", "paymentMethod": { "token": "3b1a89dfd033307f7a9fbf8757025f2226766e125b84e1cd616de9d7b7e4ebe4", "cardId": "9fd81707-8f41-4a01-b6ed-279954336ada", "brand": "VISA", "pan": "411111******1111", "cardHolder": "TOM PES", "cardExpiryMonth": "12", "cardExpiryYear": "2025", "issuer": "JPMORGAN CHASE BANK, N.A.", "country": "US" }, "threeDSecure": "", "fraudScreening": { "scoring": "0", "result": "ACCEPTED", "review": "" }, "order": { "id": "Order_1639671746", "dateCreated": "2021-12-21T13:42:15+0000", "attempts": "1", "amount": "100.00", "shipping": "0.00", "tax": "0.00", "decimals": "2", "currency": "EUR", "customerId": "", "language": "en_US", "email": "teamimplem@test.com" }, "debitAgreement": { "id": "10337627", "status": "available" } } ``` ::: **Information** * The `custom_data` attribute that you provided is absent from this response, this is on purpose. * The `cdata{n}` attributes will be removed from the responses in the future. You should not rely on this response but [**on the Webhooks**](#step-3-receive-the-webhooks) instead. ## Step 3, Receive the webhooks Once the payment has been made by the end user, you will receive a [`payin.update`](events) webhook. This webhook informs you whether the payment is: * **Accepted** – With a `payinStatus` attribute set to `VALIDATED` * **Refused** or **impossible** – With a `payinStatus` attribute set to `CANCELED` ### Legacy `payin.update` event ::: code-group ```json [JSON (new)] { "webhook":"payin.update", "object":"payin", "object_id":"103700", "object_payload":{ "payins":[ { "payinId":"103700", "payinTag":"", "walletId":"878744", "userId":"1656177", "payinStatus":"PENDING", "paymentMethodId":"25", "messageToUser":"", "subtotalItems":"0.00", "subtotalServices":"0.00", "subtotalTax":"0.00", "amount":"12.34", "currency":"EUR", "createdDate":"2024-09-09 14:04:32", "walletEventName":"reset", "walletAlias":"alias878744", "userFirstname":"Alex", "userLastname":"Oak", "codeStatus":"150117", "informationStatus":"A capture request has been sent to the financial institution.", "refundAmount":null, "DbtrIBAN":null, "forwardUrl":null, "paymentAcceptedUrl":null, "paymentRefusedUrl":null, "paymentWaitingUrl":null, "paymentExceptionUrl":null, "paymentCanceledUrl":null, "payinDate":"0000-00-00", "mandateId":"0", "creditorName":null, "creditorAddressLine":null, "creditorCountry":null, "creditorIban":null, "creditorBIC":null, "virtualIbanId":null, "virtualIbanReference":null, "additionalData":{ "card":{ "externalProvider":{ "state":"completed", "mid":"00001341804", "authorizationCode":"no_code", "transaction_reference":"800320947416", "dateCreated":"2024-09-09T12:04:24+0000", "dateUpdated":"2024-09-09T12:04:29+0000", "status":118, "message":"Captured", "authorizedAmount":12.34, "capturedAmount":12.34, "refundedAmount":0, "currency":"EUR", "ipAddress":"0.0.0.0", "ipCountry":"", "cdata1":"212707", "cdata2":"878744", "cdata3":"1656177", "cdata4":"", "cdata5":"", "cdata6":"", "cdata7":"", "cdata8":"", "cdata9":"", "cdata10":"", "eci":"9", "paymentProduct":"mastercard", "paymentMethod":{ "pan":"514414******1246", "cardHolder":"ALEX OAK", "token":"d0******78", "issuer":"TREE BANK, INC.", "brand":"MASTERCARD", "country":"US", "cardExpiryMonth":"12", "cardExpiryYear":"2025" }, "fraudScreening":{ "scoring":"0", "result":"not_launched", "review":"" } } } }, "totalRows":1 } ] }, "webhook_created_at":17258834731609, "webhook_id":"49383fa6-f72e-43de-a288-506dcxxx9ca6", "object_payload_signature":"IO5v1nKaQorSeqsC4dWS2G3wq32ecLZY5xxxxyYFE9c=", "auth_key":"true" } ``` ```json [JSON (before)] { "webhook":"payin.update", "object":"payin", "object_id":"103711", "object_payload":{ "payins":[ { "payinId":"103711", "payinTag":"", "walletId":"878744", "userId":"1656177", "payinStatus":"PENDING", "paymentMethodId":"25", "messageToUser":"", "subtotalItems":"0.00", "subtotalServices":"0.00", "subtotalTax":"0.00", "amount":"12.34", "currency":"EUR", "createdDate":"2024-09-09 14:48:10", "walletEventName":"reset", "walletAlias":"alias878744", "userFirstname":"Alex", "userLastname":"Oak", "codeStatus":"150116", "informationStatus":"The financial institution has approved the payment.In the case of a credit card payment, funds are held and deducted from the customer s credit limit (or bank balance, in the case of a debit card), but are not yet transferred to the merchant. In the cas", "refundAmount":null, "DbtrIBAN":null, "forwardUrl":null, "paymentAcceptedUrl":null, "paymentRefusedUrl":null, "paymentWaitingUrl":null, "paymentExceptionUrl":null, "paymentCanceledUrl":null, "payinDate":"0000-00-00", "mandateId":"0", "creditorName":null, "creditorAddressLine":null, "creditorCountry":null, "creditorIban":null, "creditorBIC":null, "virtualIbanId":null, "virtualIbanReference":null, "additionalData":{ "card":{ "externalProvider":{ "transaction_reference":"800320947755" } } }, "totalRows":1 } ] }, "webhook_created_at":17258860905593, "webhook_id":"13800071-738c-4f08-be82-09f75cf88a67", "object_payload_signature":"WffEOrVEjcw0W4AKkfUFh19\/ROcqaw9XpGiVrg2\/DuU=", "auth_key":"true" } ``` ::: You may also retrieve the payin by using the [`/v1/payins/{payinId}`](/api-reference/api-endpoints.html#tag/Payins/getPayin){target="\_self"} request. ### Webhooks flow ```mermaid flowchart TD id1(Payment creation) --> id2("payin.create
payinStatus:PENDING" ) --> id3("payin.update
payinStatus:VALIDATED"); id2 --> id4("payin.update
payinStatus:CANCELED") class id1 neutral; ``` ## Disputes When a card Acquisition is disputed by the cardholder, you receive: * A [`card.acquiring.chargeback.create`](./events#card-acquiring-chargeback-create) webhook informing you of the dispute. * A [`payinrefund.create`](./events#payingrefund-create) and a [`payinrefund.update`](./events#payingrefund-update) webhook sending back the fund or locking the funds on the Wallet for future refund. ## Legacy emulation You can emulate a [Card Acquisition](./introduction) using the following request. Please note emulated payins can't be refunded. ### Parameters | Attribute | Type | Description | | --- | --- | --- | | `user_id` | string | The unique identifier of the user. | | `wallet_id` | string | The unique identifier of the Wallet to top up. | | `amount` | number | The amount to credit. | | `currency` | string | Must be `EUR`. | | `status` | integer | Can be the following: 109 for an authentication failure110 for a rejection due to fraud suspicion113 for a refusal by the payment institution115 for a payment timeout116 for an authorization request117 for a capture request118 for a successful Card Acquisition129 for a chargeback173 for a refused capture | | `transaction_reference` | integer | Arbitrary reference, generated by HiPay. You need this value to emulate the complete flow composed of multiple requests. | | `payment_product` | string | The type of card: `visa`, `mastercard`, `cb`, `maestro`.| ### Request To emulate a complete flow, you can set a `status` = `117` followed by a `118` while specifying the same `transaction_reference` for both requests. ::: code-group ```bash [CURL] - curl -X POST '{baseUrl}/simulation/acquiring/payin' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is a `{payload}` example: ::: code-group ```json [JSON] { "status":"117", "amount":34.56, "user_id": "{{userId}}", "wallet_id":"{{walletId}}", "currency":"EUR", "payment_product":"mastercard" } ``` ::: Returns the following: ::: code-group ```json [JSON] { "transaction_reference": 1725547253 } ``` ::: --- --- url: /guide/acquiring/refunds.md description: >- Learn how to create refunds and handle chargebacks for card top-up payins, for a seamless integration in your application. --- # Refunds & chargebacks ## Refunds Refunds are only available for certain [paymentProducts](/guide/acquiring/introduction#payment-products-specificities). They are always associated with Payins, you may create multiple Refunds for a single Payin (just like there can be multiple Payins for a single Authorization). ### Parameters You can optionally use the following parameters when creating a refund. | Attribute | Type | Description | | --- | --- | --- | | `currency` | string | The currency of the refund, in ISO-4217 format. | | `amount` | number | The amount of the refund. Can be specified to partially refund a payin. If omitted, the payin is entirely refunded. | | `profile` | string | The MID. Required if you have multiple Merchant IDs (MIDs). | ### Request ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/v1/payinrefunds' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "payinId":"00b9cde9-0aa5-44ba-8e3a-f91fc4c29e39", "amount":19.99, // If not specified, the whole payin is refunded "currency":"EUR" } ``` ::: Returns the Payin Refund object and sends [`payinrefund.create`](./events#payinrefund-create) and [`payinrefund.update`](./events#payinrefund-update) webhooks. ::: code-group ```json [JSON] { "payinRefunds": [ { "payinrefundId": "string", "payinrefundTag": "null", "payinrefundStatus": "string", "walletId": "string", "payinId": "string", "amount": 19.99, "currency": "EUR", "createdDate": "string", "modifiedDate": "string", "payinrefundDate": "string", "profile": "string" } ] } ``` ::: ## Chargebacks When a [chargeback](/guide/overview/glossary#chargeback) is received, Treezor sends: * A [`card.acquiring.chargeback.create`](./events#card-acquiring-chargeback-create) webhook. * As many [`payinrefund.create`](./events#payinrefund-create) and [`payinrefund.update`](./events#payinrefund-update) webhooks as necessary (if multiple captures occurred for a single authorization) The chargeback is automatically accepted, and the Wallet debited (even if insufficiently provisioned). You do not have the ability to refuse it. --- --- url: /guide/acquiring/faking-operations.md description: >- Learn how to simulate card acquiring authorization, payins, refunds, and chargeback within the Sandbox environment for development and API integration testing. --- # Emulation Emulation features are only available in the `Sandbox` [environment](/guide/api-basics/environments) (which is paired with HiPay's [staging environment](/guide/acquiring/introduction#hipay-environments-credentials)). ## Authorization To emulate an Authorization, you may use the following request with the `status` corresponding to the behavior you wish to emulate. | Value | Emulated behavior | | --- | --- | | `109` | Authentication failed | | `110` | Blocked | | `111` | Denied | | `112` | Authorized and Pending | | `113` | Refused | | `114` | Expired | | `115` | Canceled | | `116` | Authorized **(Default)** | | `142` | Authorization Requested | | `143` | Authorization Cancelled | | `175` | Authorization Cancellation Requested | ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/simulation/topups/cards/notification/authorizations' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is a `{payload}` example: ::: code-group ```json [JSON] { "amount": {amount}, "currency": "EUR", "walletId": "{walletId}", "userId": "{userId}", // Optional "cardPaymentMethod": { // Mandatory for 116 status only. Omit otherwise. "brand": "string", "cardExpiryMonth": "string", "cardExpiryYear": "string", "cardHolder": "string", "country": "string", "issuer": "string", "maskedPan": "string", "token": "string" }, "status": {statusOfTheSimulatedNotification}, // optional "transactionReference": "{transactionReference}", // Mandatory for all statuses except 116 "profile": "{profile}" // Mandatory for multi-MID } ``` ::: Returns the following. ::: code-group ```json [JSON] { "transactionReference": "string", "authorizationId": "string" } ``` ::: ## Payin To emulate a Payin, you may use the following request with the `status` corresponding to the behavior you wish to emulate. | Value | Emulated behavior | | --- | --- | | `117` | Capture Requested | | `118` | Captured **(Default)** | | `173` | Capture Refused | ::: code-group ```bash [CURL] - curl -X POST '{baseUrl}/simulation/topups/cards/notification/payins' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is a `{payload}` example: ::: code-group ```json [JSON] { "amount": {amount}, "currency": "EUR", "walletId": "{walletId}", "userId": "{userId}", // Optional // "cardPaymentMethod": "{cardPaymentMethod}", // Omit, for status 116 only "status": {statusOfTheSimulatedNotification}, // optional "transactionReference": "{transactionReference}", // Mandatory (except 116) "profile": "{profile}" // Mandatory for multi-MID } ``` ::: Returns the following: ::: code-group ```json [JSON] { "transactionReference": "string", "payinId": "string" } ``` ::: ## Refund To emulate a Refund, you may use the following request with the `status` corresponding to the behavior you wish to emulate. | Value | Emulated behavior | | --- | --- | | `124` | Refund Requested | | `125` | Refunded **(Default)** | | `126` | Partially Refunded | | `165` | Refund Refused | ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/simulation/topups/cards/notification/refunds' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is a `{payload}` example: ::: code-group ```json [JSON] { "amount": {amount}, "currency": "EUR", "walletId": "{walletId}", "userId": "{userId}", // Optional // "cardPaymentMethod": "{cardPaymentMethod}", // Omit, for status 116 only "status": {statusOfTheSimulatedNotification}, // optional "transactionReference": "{transactionReference}", // Mandatory (except 116) "profile": "{profile}" // Mandatory for multi-MID } ``` ::: Returns the following. ::: code-group ```json [JSON] { "transactionReference": "string", "refundId": "string" } ``` ::: ## Chargeback To emulate a Chargeback, you only need the `transactionReference`. The transaction reference is provided in response to the [authorization step](./preauthorized), or in response to the payin creation step if you have skipped the authorization step. The following request emulates a Chargeback for the full amount of the transaction. ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/simulation/topups/cards/notification/chargebacks' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is a `{payload}` example: ::: code-group ```json [JSON] { "transactionReference": "{transactionReference}" } ``` ::: Returns an object containing the `chargebackId`: ::: code-group ```json [JSON] { "transactionReference": "string", "chargebackId": "string" } ``` ::: ## Endpoints | Endpoint | [Scope](/guide/api-basics/authentication#available-scopes) | | --- | --- | | [`/simulation/topups/cards/notification/authorizations`](/api-reference/api-endpoints.html#tag/Acquiring%20\(Simulation\)/acquiringv2-topup-cards-simulation-notification-autorization){target="\_self"} Simulate an HiPay authorization notification | `admin` | | [`/simulation/topups/cards/notification/payins`](/api-reference/api-endpoints.html#tag/Acquiring%20\(Simulation\)/acquiringv2-topup-cards-simulation-notification-payins){target="\_self"} Simulate an HiPay payin notification | `admin` | | [`/simulation/topups/cards/notification/refunds`](/api-reference/api-endpoints.html#tag/Acquiring%20\(Simulation\)/acquiringv2-topup-cards-simulation-notification-refunds){target="\_self"} Simulate an HiPay refund notification | `admin` | | [`/simulation/topups/cards/notification/chargebacks`](/api-reference/api-endpoints.html#tag/Acquiring%20\(Simulation\)/acquiringv2-topup-cards-simulation-notification-chargebacks){target="\_self"} Simulate an HiPay chargeback notification | `admin` | --- --- url: /guide/acquiring/card-tokenization.md description: >- Technical guide for tokenizing cards in order to process third-party card payments. The card secure token can be generated either with a hosted form or directly with a dedicated endpoint if you're PCI DSS-certified. --- # Card Tokenization Tokenization is the process of converting the [PAN](/guide/overview/glossary#pan-primary-account-number), expiration date, and [CVC](/guide/overview/glossary#cvc-card-verification-number) of a card into a token. The tokenization request must be sent from the end user's device (for example using JavaScript), as the [PAN](/guide/overview/glossary#pan-primary-account-number) cannot transit or be stored on your servers. You may generate the token either: * **If you're not PCI DSS certified** – [Using the secure form](#process-if-you-re-not-pci-dss-certified) ([HiPay’s Hosted Page](https://developer.hipay.com/api-explorer/hpayment-api#/payments/post_v1_hpayment)), or relying on secure fields ([HiPay’s Hosted Fields](https://developer.hipay.com/online-payments/payment/hosted-fields)). * **If you're PCI DSS certified** – Directly [using the dedicated endpoint](#process-if-you-re-pci-dss-certified). **Information – These are the only HiPay endpoints allowed** Any other actions must be carried out using the Treezor API. ## Tokenize with the secure form If you're **not PCI DSS-certified**, HiPay provides 2 endpoints, so you can: 1. Generate the token of the card using a secure form. 2. Retrieve the generated token. ### 1. Generate token through secure form You can make the following HiPay request to generate the form that will then be used by the end user to tokenize the card. ::: code-group ```bash [CURL] # encode your private credentials in base64 hipayPrivateCredentials=`echo "myprivateuser:myprivatepassword" | base64 -` # tokenize the card curl -X POST '{hiPayTokenizationFormBaseUrl}/v1/hpayment' \ --header 'Authorization: Basic {hipayPrivateCredentials}' \ # as encoded above --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}`. Please bear in mind that the choice of `operation` impacts the capture mode, which depends on your configuration. Contact Treezor if you're unsure of which one to use. ::: code-group ```json [JSON] { "orderid": "order_xxxxx", // Must be unique "operation": "Authorization", // Authorization || Sale // custom_data error will result in the funds being debited from external account, // but not credited on the Treezor Wallet of the real beneficiary of the capture. "custom_data" : { "1":"{{clientId}}", "2":"{{temp_walletId}}", "3":"{{temp_userId}}" }, // Please don't use other custom_data than the ones indicated above. "payment_product_list": "visa, mastercard, cb", "template": "basic-js", "merchant_display_name": "Merchant name", "display_selector": "1", "description": "description", "email": "aokm@example.com", "card_holder": "Alex Oak", "currency": "EUR", "amount": "1.00", "ipaddr": "", // IP of the device from which the capture is made "accept_url": "", "decline_url": "", "pending_url": "", "exception_url": "", "cancel_url": "", "language": "FR_fr", // Cardholder authentification "eci" : "7", // single-use mode "authentication_indicator": "2", // forces 3DS "device_channel" : "2", "multi_use" : 1 } ``` ::: Returns an object containing the `forwardUrl` you need to provide to your end user. ::: code-group ```json [JSON] { "forwardUrl": "https://stage-secure-gateway.hipay-tpp.com/0000-133-2882/payment/web/pay/50b6814c-27fd-49e2-adea-33bba7150c9c", "test": "true", "mid": "00001332882", "cdata1": "39625", "cdata2": "2220766", "cdata3": "4064148", "cdata4": "", // Deprecated, please ignore "cdata5": "", // Deprecated, please ignore "cdata6": "", // Deprecated, please ignore "cdata7": "", // Deprecated, please ignore "cdata8": "", // Deprecated, please ignore "cdata9": "", // Deprecated, please ignore "cdata10": "", // Deprecated, please ignore "order": { "id": "order_1685549327", "dateCreated": "2023-05-31T16:08:47+0000", "attempts": "0", "amount": "1.00", "shipping": "0.00", "tax": "0.00", "decimals": "2", "currency": "EUR", "customerId": "", "language": "FR_fr", "email": "aoak@example.com" } } ``` ::: By using the `forwardUrl`, your end user accesses the form to enter their card information, which will in turn generate the token. **Reading – Full parameters documentation available** Refer to [HiPay's Documentation](https://developer.hipay.com/api-explorer/api-online-payments#/payments/generateHostedPaymentPage) to learn everything there is to know about the parameters. **Reading – Customize your hosted payment form** Refer to the [Hosted Payments](https://developer.hipay.com/api-explorer/hpayment-api#/payments/post_v1_hpayment) section of HiPay's documentation to learn how to customize your hosted payment form. ### 2. Retrieve the token Once the user has generated the token, you may retrieve it. ::: code-group ```bash [CURL] # encode your public credentials in base64 hipayPublicCredentials=`echo "mypublicuser:mypublicpassword" | base64 -` # tokenize the card curl -X GET '{hiPayBaseUrl}/rest/v1/transaction?orderId={orderid}' \ --header 'Authorization: Basic {hipayPublicCredentials}' \ # as encoded above --header 'Accept: application/json' ``` ::: Returns the following Transaction, with the `token` available in the `paymentMethod` object. ::: code-group ```json [JSON] {39} { "transaction": { "state": "completed", "reason": "", "forwardUrl": "", "test": "true", "mid": "00001332882", "attemptId": "1", "authorizationCode": "", "transactionReference": "800242932739", "dateCreated": "2023-06-30T09:07:41+0000", "dateUpdated": "2023-06-30T09:07:52+0000", "dateAuthorized": "2023-06-30T09:07:52+0000", "status": "116", "message": "Authorized", "authorizedAmount": "1.00", "capturedAmount": "0.00", "refundedAmount": "0.00", "decimals": "2", "currency": "EUR", "ipAddress": "212.114.31.26", "ipCountry": "FR", "deviceId": "", "cdata1": "client_id", "cdata2": "wallet_id", "cdata3": "user_id", "cdata4": "", "cdata5": "", "cdata6": "", "cdata7": "", "cdata8": "", "cdata9": "", "cdata10": "", "avsResult": "", "cvcResult": "", "eci": "7", "paymentProduct": "visa", "paymentMethod": { "token": "ba3dd3760142bd6fc715b99429839b06d6de6bd1c6f1eaf36a788668396d011d", "cardId": "b1113d3b-5140-4616-abf7-49aeec3f4414", "brand": "VISA", "pan": "424242******4242", "cardHolder": "ALEX OAK", "cardExpiryMonth": "05", "cardExpiryYear": "2024", "issuer": "", "country": "GB" }, "threeDSecure": { "eci": "5", "authenticationStatus": "Y", "authenticationMessage": "Authentication Successful", "authenticationToken": "", "xid": "" }, "fraudScreening": { "scoring": "0", "result": "ACCEPTED", "review": "" }, "order": { "id": "order_1688116033", "dateCreated": "2023-06-30T09:07:12+0000", "gender": "U", "firstname": "", "lastname": "", "streetAddress": "", "locality": "", "postalCode": "", "country": "", "attempts": "1", "amount": "1.00", "shipping": "0.00", "tax": "0.00", "decimals": "2", "currency": "EUR", "customerId": "", "language": "FR_fr", "msisdn": "", "phone": "", "phoneOperator": "", "shippingAddress": { "firstname": "", "lastname": "", "streetAddress": "", "locality": "", "postalCode": "", "country": "" }, "email": "teamimplem@test.com" }, "debitAgreement": { "id": "10520843", "status": "available" } } } ``` ::: **Reading – Full parameters documentation available** Refer to [HiPay's Documentation](https://developer.hipay.com/api-explorer/api-online-payments#/transaction/getTransactionsByReference) to learn everything there is to know about the parameters. ## Tokenize with the create token request If you are **PCI DSS-certified**, you can directly use the dedicated endpoint to generate the card token. ### Parameters | Attribute | Type | Description | | --- | --- | --- | | `card_number` | string | The [primary account number (PAN)](/guide/overview/glossary#pan-primary-account-number) of the card. | | `card_expiry_month` | integer | The month on which the card expires. | | `card_expiry_year` | integer | The year on which the card expires. | | `card_holder` | string | The name of the cardholder, embossed or etched on the card. | | `cvc` | integer | The [CVC](/guide/overview/glossary#cvc-card-verification-number) of the card. | | `multi_use` | integer | Indicates whether the card can be used multiple times. Either: `0` – The card can only be used once, and the token expires after a month if not used. `1` – The card can be used multiple times and the token expires at the card expiry date. | In addition, you'll need your `hipayPublicCredentials` in the request Authorization header. It is a concatenation of `hipay_public_user` `:` `hipay_public_password` [credentials](/guide/acquiring/introduction##hipay-environments-credentials), without spaces and encoded in base64. ### Request example ::: code-group ```bash [CURL] # encode your public credentials in base64 hipayPublicCredentials=`echo "mypublicuser:mypublicpassword" | base64 -` # tokenize the card curl -X POST '{hiPayTokenizationBaseUrl}/rest/v2/token/create' \ --header 'Authorization: Basic {hipayPublicCredentials}' \ # as encoded above --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "card_number":"5300000000000006", "card_expiry_month":12, "card_expiry_year":2025, "card_holder":"Alex Oak", "cvc":123, "multi_use":1 } ``` ::: Returns the `token` of the card. ::: code-group ```json [JSON] { "token": "ee9ac2901f4c0d651143664659f206bb6e34ee552ab4e693fa21616b0ef69a57", "request_id": "0", "card_id": "9fd81707-8f41-4a01-b6ed-279954336ada", "multi_use": 1, "brand": "VISA", "pan": "411111xxxxxx1111", "card_holder": "Alex Oak", "card_expiry_month": "12", "card_expiry_year": "2025", "issuer": "JPMORGAN CHASE BANK, N.A.", "country": "US", "card_type": "CREDIT", "forbidden_issuer_country": false } ``` ::: **Warning – Authorize tokenized cards first with `eci`=`7` payment to enforce 3DS** You must receive a successful payment before you can either use it with `eci` = `9` or store the `cardtoken` in your database. If you're encountering an error, please check out the [HiPay's error codes](https://developer.hipay.com/payment-fundamentals/essentials/error-messages) documentation. ## Associate the card to a User To acquire funds using the tokenized card, you need to create the corresponding Topup Card object in the Treezor API for a given user. To do so, use the following request with the `token` provided by HiPay during the tokenization step. ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/v1/topups/cards/users/{userId}/topupCards' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{ "token":"{temporaryHiPayToken}" }' ``` ::: Returns the Topup Card object, and sends a [`topupCard.validate`](./events#topupcard-validate) webhook. ::: code-group ```json [JSON] { "topupCards": [ { "topupCardId": "d88fa963-2cd1-4409-9adc-a06f77b11291", "token": "9741899a3e6c109f0f0162117fce703be273e56eaac2f269f9f6304f7474c07c", "userId": "1656177", "brand": "VISA", "maskedPan": "411111xxxxxx1111", "cardHolder": "Alex Oak", "cardExpiryMonth": "12", "cardExpiryYear": "2025", "issuer": "JPMORGAN CHASE BANK, N.A.", "country": "US", "domesticNetwork": null, "cardType": "CREDIT", "createdDate": "2022-01-26 14:32:17", "updatedDate": "2022-01-26 14:32:17", "status": "VALIDATED", "providerName": "HiPay", "clientId": "212707" } ] } ``` ::: To prevent abuse and misuse, there is a maximum of 10 active cards associated to a single User at any given time. You may [revoke Topup Cards](#revoke-a-topup-card) if necessary. ## Revoke a Topup Card The following request permanently revokes a Topup Card. This action revokes the token and sets the Topup Card status to `CANCELED` permanently. Revoking cards is highly recommended to prevent any kind of misuse. Please also note that there is a limit of 10 active cards associated to a single User at any given time. You can still [tokenize the card](#card-tokenization) again if necessary. ### Request ::: code-group ```bash [CURL] curl -X DELETE '{baseUrl}/v1/topups/cards/users/userId}/topupCards/{topupCardId}' \ --header 'Authorization: Bearer {accessToken}' ``` ::: Returns the disabled Tokenized Card and sends a [`topupCard.cancel`](./events#usertokenizedcard-cancel) webhook. ::: code-group ```json [JSON] { "topupCards": [ { "topupCardId": "d88fa963-xxxx-xxxx-xxxx-a06f77b11291", "token": "9741899[...]7474c07c", "userId": "1656177", "brand": "VISA", "maskedPan": "411111xxxxxx1111", "cardHolder": "Alex Oak", "cardExpiryMonth": "12", "cardExpiryYear": "2025", "issuer": "JPMORGAN CHASE BANK, N.A.", "country": "US", "domesticNetwork": null, "cardType": "CREDIT", "createdDate": "2022-01-26 14:32:17", "updatedDate": "2022-01-26 14:32:17", "status": "CANCELED", "providerName": "HiPay", "clientId": "212707" } ] } ``` ::: --- --- url: /guide/cards/x-pay-google-apple.md description: >- Tokenize your cards for wallet providers such as Google Pay and Apple Pay. Includes integration paths for both In-App and In-House provisioning, as well as merchant-initiated tokenization. --- # X-Pay The digitization of a Card is the act of tokenizing an existing [Card](/guide/cards/introduction) and storing it in a Google Pay or Apple Pay wallet, also referred to as X-Pay. **Note – X-Pay wallets are different from Treezor Wallets** In the context of X-Pay, the term “wallet” refers to digital wallet holding cards (DPANs), such as Apple Pay (iOS), or Google Pay (android) mobile applications. ## Introduction to digitization Treezor allows you to digitize the cards so that your end users can add them to their Apple Pay or Google Pay wallets, hence facilitating payments with their devices. When digitized, the card’s sensitive information is substituted by a tokenized version of the Card ([DPAN](/guide/overview/glossary#device-primary-account-number-dpan)). As a result, the [wallet providers](/guide/overview/glossary#wallet-provider) can offer the cards as a means of payment without holding the card’s [PAN](/guide/overview/glossary#primary-account-number-pan). Similarly to your issued cards, the X-Pay feature relies on your [Card Program](/guide/cards/introduction#card-program) both in terms of design and functionality. A digitized Card can be temporarily or permanently disabled using the Treezor API. ## Integrating your X-Pay solution The Treezor API only handles card digitization. Your Apple Pay and Google Pay integration and certification are independent of Treezor services. Here are the main steps to integrate X-Pay: ::: details 1. Project configuration Contact your *Treezor Implementation Manager* to activate the X-Pay feature. They will help you meet the prerequisites and provide the relevant information to the card schemes. ::: ::: details 2. Implementation of card digitization with Treezor Implement the card digitization process that fits your project; the endpoints you use differ depending on whether you have already enrolled to [PCI DSS services](/guide/cards/pci-dss). There are 2 ways of digitizing Cards. [Wallet providers](/guide/overview/glossary#wallet-provider) usually require the implementation of both: * **[In-House](#in-house-provisioning)** – The end user enters card data into their wallet provider application. * **[In-App](#in-app-provisioning)** – The end user clicks on the “Add to wallet” button in your application. ::: ::: details 3. Wallet provider certifications You must get certified by the Wallet providers for your X-Pay integration to be up and running. Google requires you to screen-record the process to ensure it follows their guidelines. Apple subcontracts the certification to a specialized company that enforces stricter controls. Please note that Treezor: * Isn’t involved with Google Pay for your certification. * Does exchange with the certifying organization for your Apple Pay certification. ::: This article only focuses on card digitization with the Treezor API. For Card digitization to work, the [Online option](./restrictions-limits#options-permission-groups) of the issued card must be activated. **Alert – Wallet providers' privacy policies & requirements** Integration guides are not provided due to wallet provider policies. You must sign a non-disclosure agreement for your Apple Pay integration and be onboarded with Google Pay. These steps provide you with access to their documentation. ## In-house provisioning With the in-house provisioning method, the end user initiates the card digitization from the wallet application of their device. To tokenize the card and generate the [DPAN](/guide/overview/glossary#device-primary-account-number-dpan), the end user enters the card details in the app. Therefore, there is no development on your part. In addition, in-house provisioning supports wearable devices (e.g., smartwatches) as well as Samsung Pay as a wallet provider. ### In-house process The in-house provisioning process goes as follows. | Step | Description | |:----:|-------------| | 1 | The cardholder enters the card details on their device application (Apple Pay, Google Pay, Samsung Pay). | | 2 | Treezor handles the authorization messages before the tokenization:[Account Status Inquiry (ASI)](/guide/overview/glossary#account-status-inquiry-asi) – Ensures the card exists.[Tokenization Authorization Request (TAR)](/guide/overview/glossary#tokenization-authorization-request-tar) – Ensures the card is compatible with X-Pay.Treezor sends a [`cardDigitalizalitation.request`](./events#carddigitalization-request) notifying you that the digitization process started. | | 3 | The card details are tokenized by the token provider (Mastercard or Visa). | | 4 | The token provider sends back the token (DPAN) to the wallet application. | | 5 | Treezor ensures the authentication by sending a one-time password (OTP) to the cardholder via email or SMS, and sends you the following webhooks:[`cardDigitalization.activation`](./events#carddigitalization-activation) – The OTP was sent to the cardholder, starting the authentication process. Corresponds to the [Activation Code Notification (ACN)](/guide/overview/glossary#activation-complete-notification-acn).[`cardDigitalization.complete`](./events#carddigitalization-complete) – The card was successfully digitized and added to the wallet provider application. Corresponds to the [Tokenization Complete Notification (TCN)](/guide/overview/glossary#tokenization-complete-notification-tcn). | **Tip – The language of the SMS is inherited from the user** The SMS sent for the OTP step is sent in the same language as the value defined in the `language` field of the User object. If the digitized card status is updated (suspension or deactivation), the wallet provider sends a Tokenization Event Notification (TVN), and Treezor notifies you with the [`cardDigitalization.update`](./events#carddigitalization-update) webhook. For more information about token updates, please refer to the [Token lifecycle](#token-lifecycle) section. ## In-app provisioning The in-app provisioning is initiated from your application. In such cases, your end users click on the “Add to Wallet” button in your interface. ::: details Button examples Please note the buttons must strictly follow the best practices of the wallet providers. ::: Once the user requests the card to be added to their Apple or Google Wallet, the following steps occur to complete the digitization. Please remember that your Wallet Provider integration must be certified by Apple Pay and Google Pay, and that Treezor isn’t involved in those steps. ### Flow The flow can be simplified into 3 main steps: 1. [**Requesting credentials**](#requesting-credentials) – Request your credentials from Treezor 2. [**Requesting cryptogram**](#requesting-cryptogram) – Use the credentials to request your cryptogram from Treezor 3. [**Digitization request**](#digitization-request) – Use the cryptogram to request tokenization from the Wallet Provider Here is a more detailed sequence diagram. ```mermaid sequenceDiagram participant You participant Token Provider participant Treezor You->>Treezor: Requests Digitization Credentials from server
POST /v1/issuerInitiatedDigitizationDatas Treezor->>Treezor: Generates IssuerInitiatedDigitizationData Treezor->>You: IssuerInitiatedDigitizationData (with credentials) You->>Treezor: Request cryptogram (TAV) from mobile application
using credentials (uuid) Treezor->>You: Sends cryptogram (TAV) You->>Token Provider: Requests digitization using TAV
from mobile application Token Provider->>Treezor: Sends TAR Treezor-->>You: Sends `cardDigitalization.request` webhook Token Provider->>Token Provider: Digitizes the card (DPAN) and sends it to the Wallet Provider Token Provider->>Treezor: Sends TCN Treezor-->>You: Sends `cardDigitalizations.complete` webhook ``` ### Authorization messages & webhooks Treezor handles the following authorization messages during the tokenization process. | Message | Description | Webhook | |------------------|-------------|---------| | [Account Status Inquiry (ASI)](/guide/overview/glossary#account-status-inquiry-asi) | Ensures the card exists. | N/A | | [Tokenization Authorization Request (TAR)](/guide/overview/glossary#tokenization-authorization-request-tar) | Ensures the card is compatible with X-Pay. | [`cardDigitalization.request`](./events#carddigitalization-request) | | [Tokenization Complete Notification (TCN)](/guide/overview/glossary#tokenization-complete-notification-tcn) | Confirms the digitization of the card. | [`cardDigitalization.complete`](./events#carddigitalization-complete) | ### Requesting credentials The credentials request requires at least the `cardId` and `tokenRequestor` parameters. Additional information may be necessary for Apple Pay. Endpoint: [`/issuerInitiatedDigitizationDatas`](/api-reference/api-endpoints.html#tag/issuerInitiatedDigitizationData/tavRequestPOST){target="\_self"} ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/v1/issuerInitiatedDigitizationDatas' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: ::: details PCI DSS endpoints If you have migrated to the [PCI DSS services](./pci-dss), then you must use the following endpoints instead: * [`/cards/{cardId}/inappcryptogram/mastercard/apple-pay`](/api-reference/pci-dss-dev.html#tag/Cards/postInappApple){target="\_self"} * [`/cards/{cardId}/inappcryptogram/mastercard/google-pay`](/api-reference/pci-dss-dev.html#tag/Cards/postInappGpay){target="\_self"} * [`/cards/{cardId}/inappcryptogram/visa/apple-pay`](/api-reference/pci-dss-dev.html#tag/Cards/postVisaInappApple){target="\_self"} * [`/cards/{cardId}/inappcryptogram/visa/google-pay`](/api-reference/pci-dss-dev.html#tag/Cards/postVisaInappGpay){target="\_self"} ::: Here is a `{payload}` example: ::: code-group ```json [JSON] { "cardId": 0, "tokenRequestor": "APPLE", "additionnalData": // required for Apple Pay only { "certificates": [ "string" ], "nonce": "string", "nonceSignature": "string" } } ``` ::: Returns the `issuerInitiatedDigitizationDatas` object, along with the `credential` necessary for the next step. ::: code-group ```json [JSON] {7} { "issuerInitiatedDigitizationDatas": [ { "id": 0, "cardId": 0, "statusId": 0, "credential": "string", "additionnalData": [ "string" ], "tokenRequestor": "string", "createdDate": "string", "modifiedDate": "string" } ] } ``` ::: ### Requesting cryptogram To retrieve your cryptogram ([TAV](/guide/overview/glossary#tokenization-authentication-value-tav)), the following request is sent from the end user's device. Contact your *Treezor Implementation Manager* for the `{specificURL}`. ::: code-group ```bash [CURL] curl -X GET '{specificURL}/issuerInitiatedDigitizationData' \ -d '"credential"="{credential}"' ``` ::: Returns the base64-encoded TAV. ### Digitization request The digitization request is made with the obtained [TAV](/guide/overview/glossary#tokenization-authentication-value-tav), from the end user's device. This request isn't made with Treezor API but the Wallet Provider. Depending on the Wallet Provider, you may need to either send the [TAV](/guide/overview/glossary#tokenization-authentication-value-tav) as received (base64 encoded) or decoded in the form of a JSON object. Please refer to the documentation shared with you by your *Treezor Implementation Manager* for more information. ## Merchant-initiated tokenization It is not uncommon for merchants to tokenize their customers’ card on their websites, hence saving the card information securely for future payments. The merchant-initiated request to tokenize the PAN of their consumers results in a token that can only be used by the merchant who initiated the request. **Information – Mandatory feature for all X-Pay subscribers** While Merchant-initiated tokenization isn’t directly related to X-Pay, it is a mandatory functionality set by the Token Providers. ::: details Merchants usually initiate a tokenization request: * While the transaction is made * When a new card is added to the customer’s profile * Per customer request, for any card attached to their profile ::: When such a tokenization scenario occurs, Treezor informs you with the [`cardDigitalization.complete`](./events#carddigitalization-complete) webhook, which also contains information about the Merchant who digitized the card. The token created can be used for the transaction and any transaction that might occur in the future, as long as the same PAN is used. ### Flow ```mermaid sequenceDiagram participant Merchant participant Treezor participant You Merchant->>Merchant: Initiates Tokenization process with Token Provider Merchant->>Treezor: Sends ASI Merchant->>Treezor: Sends TAR Treezor->>You: `cardDigitalization.request` webhook Merchant->>Treezor: Sends TCN Treezor->>Treezor: Stores token-related information Treezor->>You: Sends `cardDigitalization.complete` webhook
Which includes the merchant who initiated the digitization ``` ### Authorization messages & webhooks Treezor handles the following authorization messages from the merchant during the tokenization process. | Merchant message | Description | Webhook | |------------------|-------------|---------| | [Account Status Inquiry (ASI)](/guide/overview/glossary#account-status-inquiry-asi) | Ensures the card exists. | N/A | | [Tokenization Authorization Request (TAR)](/guide/overview/glossary#tokenization-authorization-request-tar) | Ensures the card is compatible with X-Pay. | [`cardDigitalization.request`](./events#carddigitalization-request) | | [Tokenization Complete Notification (TCN)](/guide/overview/glossary#tokenization-complete-notification-tcn) | Confirms the digitization of the card. | [`cardDigitalization.complete`](./events#carddigitalization-complete) | ## Token lifecycle Once the digitization complete and the token active, the [DPAN](/guide/overview/glossary#device-primary-account-number-dpan) can be suspended if need be, and deactivated once no longer in use. Please note that the digitized card [`statuses`](#statuses-status) are independent of the card's. When [blocking a card](./modification#block-a-card), it is your responsibility to suspend or deactivate the card token as well. However, if you're using the most recent services for card digitization, when the card status is set to `DESTROYED`, Treezor automatically sets the corresponding card tokens to deactivated (`X`). ### Updating the Card Token You can suspend and unsuspend the digitized card token with the dedicated endpoint. #### Parameters | Attribute | string | Description | | --- | --- | --- | | `status` | string | Can take the following values: `unsuspend` – Removes the suspension`suspend` – Suspends the payment token | | `reasonCode` | string | Can take the following values with `suspend`: `L` – Cardholder suspects token **device lost**`S` – Cardholder suspects token **device stolen**`T` – Issuer or cardholder suspects **fraudulent** token transactions`Z` – OtherCan take the following values with `unsuspend`: `F` – Cardholder reported token **device found or not stolen**`T` – Issuer or cardholder confirmed **no fraudulent** token transactions`Z` – Other| #### Request example Endpoint: [`/v1/digitalizedCard/{id}`](/api-reference/api-endpoints.html#tag/Digitized%20Cards/putDigitalized){target="\_self"} ::: code-group ```bash [CURL] curl -X PUT '{baseUrl}/v1/digitalizedCard/{id}' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] {6} { "status": "suspend", "reasonCode": "L" } ``` ::: Returns the digitized card object, with the `status` set to `S`. ::: code-group ```json [JSON] {6} { "cardId": "12345", "createdDate": "2025-01-19 14:30:45", "id": "1234567", "modifiedDate": "2025-02-19 14:30:45", "status": "S" } ``` ::: Treezor also sends the [`cardDigitalization.update`](./events#carddigitalization-update) webhook. ### Deactivating the Card Token The token must be deactivated if the cardholder is `CANCELED` and/or the card is in a [permanent locked status](./introduction#card-status-statuscode). To do so, use the following request, with the [`reasonCode`](#reason-codes-reasoncode) as a query parameter (for the Mastercard scheme only). #### Request example Endpoint: [`/v1/digitalizedCard/{id}`](/api-reference/api-endpoints.html#tag/Digitized%20Cards/deleteDigitalized){target="\_self"} ::: code-group ```bash [CURL] curl -X DELETE '{baseUrl}/v1/digitalizedCard/{id}?reasonCode={C}' \ --header 'Authorization: Bearer {accessToken}' ``` ::: Returns the digitized card object, with the `status` set to `X`. ::: code-group ```json [JSON] {6} { "cardId": "12345", "createdDate": "2025-01-19 14:30:45", "id": "1234567", "modifiedDate": "2025-02-19 14:30:45", "status": "X" } ``` ::: Treezor also sends the [`cardDigitalization.deactivated`](./events#carddigitalization-deactivated) webhook. ## Digitized card object ::: code-group ```json [JSON] { "activationMethod": "TEXT_TO_CARDHOLDER_NUMBER", "cardDigitalizationExternalId": "12345", "cardId": "12345", "createdDate": "2025-02-19 14:30:45", "deviceId": "987654", "deviceName": "Chris' iPhone", "deviceType": "M", "expirationDate": "2025-02-19 14:30:45", "id": "1234567", "merchantName": "…", "modifiedDate": "2025-02-19 14:30:45", "status": "A", "tokenRequestor": "APPLE", "tokenUniqueReference": "…" } ``` ::: ### Statuses (`status`) | Value | Status | Description | | :---: | ------ | ----- | | `A` | Active | Initial status of your DPAN upon card digitization. | | `S` | Suspended | DPAN suspended (card stolen, lost, or declared fraudulent). | | `X` | Deactivated | DPAN deactivated (e.g., card expired). | | `I` | Inactive | This is for Visa Scheme only. | **Information – You can't suspend/unsuspend tokens with a `U` legacy status** Such attempts generate an HTTP `400` error. Please note that you can deactivate such tokens with the [`/v1/digitalizedCard/{id}`](/api-reference/api-endpoints.html#tag/Digitized%20Cards/deleteDigitalized){target="\_self"} request. ### Reason codes (`reasonCode`) | Reason code | Description | | :----: | ----------- | | `C` | Account closed | | `D` | Issuer consumer deleted | | `F` | Cardholder reported token device found or not stolen | | `L` | Cardholder confirmed token device lost | | `S` | Cardholder confirmed token device stolen | | `T` | Issuer or cardholder confirmed fraudulent token transactions | | `Z` | Other | ### Device types (`deviceType`) | Value | Description | |:---:|---| | `A` | Clothing or apparel | | `B` | Media or Gaming device, e.g., Xbox, TV, set-top box | | `C` | Card | | `D` | Domestic application, e.g., fridge, washing machine | | `F` | Fob or key-fob | | `G` | Mobile tag, case, or sleeve | | `H` | Fashion accessory, e.g., purse, glasses | | `J` | Jewelry, e.g., necklace, rings, bracelets | | `M` | Mobile phone | | `P` | Personal computer or laptop | | `R` | Wristband (no further detail.). Possibly includes rings too | | `S` | Sticker | | `T` | Tablet | | `U` | Unknown | | `V` | Vehicle | | `W` | Watch | | `X` | Mobile phone or tablet (sender unclear) | ### Activation methods (`activationMethod`) | Value | Description | |- |- | | `TEXT_TO_CARDHOLDER_NUMBER` | Text message to the cardholder’s mobile phone number. | | `EMAIL_TO_CARDHOLDER_ADDRESS` | Email to cardholder’s email address. | | `CARDHOLDER_TO_CALL_AUTOMATED_NUMBER` | Cardholder-initiated call to automated call center phone number. | | `CARDHOLDER_TO_CALL_MANNED_NUMBER` | Cardholder-initiated call to manned call center phone number. | | `CARDHOLDER_TO_VISIT_WEBSITE` | Cardholder to visit a website. | | `CARDHOLDER_TO_USE_MOBILE_APP` | Cardholder to use a specific mobile app to activate token. | | `ISSUER_TO_CALL_CARDHOLDER_NUMBER` | Issuer-initiated voice call to cardholder’s phone. | ## Endpoints **Information – Connection to services in Production only** There is no connection to Google Pay or Apple Pay services in Sandbox. Endpoints are available for technical testing only. | Endpoint | [Scope](/guide/api-basics/authentication#available-scopes) | | --- | --- | | [`/issuerInitiatedDigitizationDatas`](/api-reference/api-endpoints.html#tag/issuerInitiatedDigitizationData/tavRequestPOST){target="\_self"} Request the issuerInitiatedDigitizationDatas | `read_write` | | [`/v1/{cardId}/digitalizedCards`](/api-reference/api-endpoints.html#tag/Digitized%20Cards){target="\_self"} List digitalized cards for a given `cardId` | N/A | | [`/v1/digitalizedCard/{id}`](/api-reference/api-endpoints.html#tag/Digitized%20Cards/getPaymentToken){target="\_self"} Retrieve a payment token | N/A | | [`/v1/digitalizedCard/{id}`](/api-reference/api-endpoints.html#tag/Digitized%20Cards/putDigitalized){target="\_self"} Update a payment token status | N/A | | [`/v1/digitalizedCard/{id}`](/api-reference/api-endpoints.html#tag/Digitized%20Cards/deleteDigitalized){target="\_self"} Deactivate a payment token | N/A | ::: details Deprecated | Endpoint | [Scope](/guide/api-basics/authentication#available-scopes) | | --- | --- | | [`/cardDigitalizations`](/api-reference/api-endpoints.html#tag/cardDigitalizations/readcardDigitalizations){target="\_self"} Search for Card Digitalizations | `read_only` | | [`/cardDigitalizations/{cardDigitalizationId}`](/api-reference/api-endpoints.html#tag/cardDigitalizations/cardDigitalizationsId){target="\_self"} Retrieve a Card Digitalization | `read_only` | | [`/cardDigitalizations/{cardDigitalizationId}`](/api-reference/api-endpoints.html#tag/cardDigitalizations/putcardDigitalizationsId){target="\_self"} Update the status of a payment Token | `read_write` | | [`/cardDigitalizations/{cardDigitalizationId}`](/api-reference/api-endpoints.html#tag/cardDigitalizations/deletecardDigitalizationsId){target="\_self"} Delete a payment Token | `read_write` | ::: --- --- url: /guide/cards/events.md description: >- Reference a comprehensive list of card events for Treezor API webhooks, detailing each event's structure and payload for integration. --- # Events This article lists the [Webhooks](/guide/webhooks/introduction) you may receive when issuing Cards. ## Cards ### `card.requestphysical` ::: code-group ```json [JSON] { "webhook": "card.requestphysical", "object": "card", "object_id": "999990081", "object_payload": { "cards": [ { "cardId": "999990081", "userId": "100642533", "walletId": "3135941", "walletCardtransactionId": "3143087", "mccRestrictionGroupId": null, "merchantRestrictionGroupId": null, "countryRestrictionGroupId": null, "eventName": "Main account", "eventAlias": "main-account-669697986861c", "publicToken": "110662949", "cardTag": "", "statusCode": "UNLOCK", "isLive": "0", "pinTryExceeds": "0", "maskedPan": "548821******3691", "embossedName": "ALEX OAK", "expiryDate": "2027-07-31", "CVV": "971", "startDate": "2024-07-24", "endDate": "0000-00-00", "countryCode": "FR", "currencyCode": "EUR", "deliveryTitle": "M", "deliveryLastname": "OAK", "deliveryFirstname": "ALEX", "deliveryAddress1": "07323 cedar hills", "deliveryAddress2": "", "deliveryAddress3": "", "deliveryCity": "PARIS", "deliveryPostcode": "75000", "deliveryCountry": "FR", "mobileSent": "+33123456789", "limitsGroup": "TRZ-VL-001", "permsGroup": "TRZ-CU-016", "cardDesign": "14708", "virtualConverted": "0", "optionAtm": "1", "optionForeign": "1", "optionOnline": "1", "optionNfc": "1", "limitAtmYear": "0", "limitAtmMonth": "0", "limitAtmWeek": "2000", "limitAtmDay": "1000", "limitAtmAll": "0", "limitPaymentYear": "0", "limitPaymentMonth": "0", "limitPaymentWeek": "3000", "limitPaymentDay": "2000", "paymentDailyLimit": "0.00", "restrictionGroupLimits": null, "limitPaymentAll": "0", "totalAtmYear": "0", "totalAtmMonth": "0", "totalAtmWeek": null, "totalAtmDay": null, "totalAtmAll": "0", "totalPaymentYear": "0", "totalPaymentMonth": "0", "totalPaymentWeek": null, "totalPaymentDay": null, "totalPaymentAll": "0", "createdBy": "929252", "createdDate": "2024-07-18 12:54:28", "modifiedBy": "0", "modifiedDate": "0000-00-00 00:00:00", "cancellationNumber": null, "physical": "1", "logoId":"", "logoBackId":"", "packageId":"", "customizedInfo":null, "letterCustomizedInfo":"", "freeCustomizedInfo":"", "deliveryMethod": "1", "pinMailer": "1", "batchDeliveryId": "1", "sendToParent": "1" } ] }, "webhook_created_at": 17213000682093, "webhook_id": "056b1e6d-17b3-4796-89e0-653f3cxxxx03", "object_payload_signature": "wqGsyqDmHOnkrkyY/mjf+AuWeTlaxhraUxxxxxwMGs=" } ``` ::: ### `card.createvirtual` ::: code-group <<< @/guide/cards/snippets/event-card-createvirtual.json\[JSON] ::: ### `card.convertvirtual` ::: code-group <<< @/guide/cards/snippets/event-card-convert.json\[JSON] ::: ### `card.changepin` ::: code-group <<< @/guide/cards/snippets/event-card-changepin.json\[JSON] ::: ### `card.activate` ::: code-group <<< @/guide/cards/snippets/event-card-activate.json\[JSON] ::: ### `card.renew` ::: code-group ```json [JSON] { "webhook": "card.renew", "webhook_id": "2xxxxxx8", "object": "card", "object_id": "6xxx6", "object_payload": { "cards": [ { "cardId": "100003123", "userId": "3075987", "walletId": "3397876", "walletCardtransactionId": "123456", "mccRestrictionGroupId": null, "merchantRestrictionGroupId": null, "countryRestrictionGroupId": null, "eventName": "Wallet", "eventAlias": "xxxxxx-wallet-5fe1208c2d47e", "publicToken": "332945545", "cardTag": "d42d0082-7bac-47be-b219-2975aed12345", "statusCode": "UNLOCK", "isLive": "0", "pinTryExceeds": "0", "maskedPan": "123456******1234", "embossedName": "Alex Oak", "expiryDate": "2026-12-31", "CVV": "123", "startDate": "2020-12-20", "endDate": "0000-00-00", "countryCode": "FR", "currencyCode": "EUR", "deliveryTitle": "M", "deliveryLastname": "ALEX", "deliveryFirstname": "OAK", "deliveryAddress1": "12 Rosewood Road", "deliveryAddress2": "", "deliveryAddress3": "", "deliveryCity": "PARIS", "deliveryPostcode": "75000", "deliveryCountry": "FRA", "mobileSent": "0033333333333", "limitsGroup": "TRZ-VL-001", "permsGroup": "TRZ-CU-015", "cardDesign": "5996", "virtualConverted": "1", "optionAtm": "1", "optionForeign": "0", "optionOnline": "1", "optionNfc": "1", "limitAtmYear": "0", "limitAtmMonth": "1000", "limitAtmWeek": "300", "limitAtmDay": "1000", "limitAtmAll": "0", "limitPaymentYear": "0", "limitPaymentMonth": "1600", "limitPaymentWeek": "1000", "limitPaymentDay": "2000", "paymentDailyLimit": "0.00", "restrictionGroupLimits": null, "limitPaymentAll": "0", "totalAtmYear": "0", "totalAtmMonth": null, "totalAtmWeek": null, "totalAtmDay": null, "totalAtmAll": "0", "totalPaymentYear": "0", "totalPaymentMonth": null, "totalPaymentWeek": null, "totalPaymentDay": null, "totalPaymentAll": "0", "createdBy": "372837", "createdDate": "2023-12-18 00:00:00", "modifiedBy": "0", "modifiedDate": "0000-00-00 00:00:00", "cancellationNumber": null, "physical": "0", "logoId":"", "logoBackId":"", "packageId":"", "customizedInfo":null, "letterCustomizedInfo":"", "freeCustomizedInfo":"", "deliveryMethod": "1", "pinMailer": "1", "batchDeliveryId": "1", "sendToParent": "1" } ] }, "object_payload_signature": "o4tf+JC0PbJ1t9kjg2PRr2xE7xh3Am/12345678abcA=" } ``` ::: ### `card.update` Treezor sends this webhook when: * The card is updated using the dedicated endpoint or * When one of the following cardholder's field is updated at the User object level: `title`, `firstname`, `lastname`, `email`, `address1`, `address2`, `postcode`, `city`, `country`, `phone`, `mobile`, or `language`. ::: code-group ```json [JSON] { "webhook": "card.update", "object": "card", "object_id": "999925786", "object_payload": { "cards": [ { "cardId": "999925786", "userId": "100549108", "walletId": "3011794", "walletCardtransactionId": "3012053", "mccRestrictionGroupId": "48203", "merchantRestrictionGroupId": "107454", "countryRestrictionGroupId": "183120", "eventName": "Main account", "eventAlias": "main-account-6670280a28c2c", "publicToken": "105618829", "cardTag": "Updated cardTag", "statusCode": "UNLOCK", "isLive": "1", "pinTryExceeds": "0", "maskedPan": "548821******0226", "embossedName": "ALEX OAK", "expiryDate": "2024-06-18", "CVV": "740", "startDate": "2024-06-24", "endDate": "2024-06-17", "countryCode": "FR", "currencyCode": "EUR", "deliveryTitle": "M", "deliveryLastname": "OAK", "deliveryFirstname": "ALEX", "deliveryAddress1": "30217 CRUICKSHANK SPRINGS", "deliveryAddress2": "", "deliveryAddress3": "", "deliveryCity": "VERSAILLES", "deliveryPostcode": "78000", "deliveryCountry": "FR", "mobileSent": "+33141358530", "limitsGroup": "TRZ-VL-001", "permsGroup": "TRZ-CU-016", "cardDesign": "8529", "virtualConverted": "1", "optionAtm": "1", "optionForeign": "1", "optionOnline": "1", "optionNfc": "1", "limitAtmYear": "2000", "limitAtmMonth": "2000", "limitAtmWeek": "2000", "limitAtmDay": "1000", "limitAtmAll": "0", "limitPaymentYear": "5000", "limitPaymentMonth": "0", "limitPaymentWeek": "3000", "limitPaymentDay": "2000", "paymentDailyLimit": "500.00", "restrictionGroupLimits": null, "limitPaymentAll": "0", "totalAtmYear": null, "totalAtmMonth": null, "totalAtmWeek": null, "totalAtmDay": null, "totalAtmAll": "0", "totalPaymentYear": "0.00", "totalPaymentMonth": "0", "totalPaymentWeek": null, "totalPaymentDay": null, "totalPaymentAll": "0", "createdBy": "929252", "createdDate": "2024-06-17 14:43:54", "modifiedBy": "929252", "modifiedDate": "2024-07-18 14:07:33", "cancellationNumber": null, "physical": "0", "logoId":"", "logoBackId":"", "packageId":"", "customizedInfo":null, "letterCustomizedInfo":"", "freeCustomizedInfo":"", "deliveryMethod": "1", "pinMailer": "1", "batchDeliveryId": "1", "sendToParent": "1" } ] }, "webhook_created_at": 17213044534278, "webhook_id": "6b0aee69-87c8-45df-a0d9-42xxxx9f38b", "object_payload_signature": "WTFf7nbDnCoT6EVMRaTTTSHkA87BxxxxxdPCU30Usmo=" } ``` ::: ### `card.limits` ::: code-group ```json [JSON] { "webhook": "card.limits", "object": "card", "object_id": "999990082", "object_payload": { "cards": [ { "cardId": "999990082", "userId": "100642533", "walletId": "3135941", "walletCardtransactionId": "3143122", "mccRestrictionGroupId": null, "merchantRestrictionGroupId": null, "countryRestrictionGroupId": null, "eventName": "Main account", "eventAlias": "main-account-669697986861c", "publicToken": "105603885", "cardTag": "sky blue", "statusCode": "UNLOCK", "isLive": "1", "pinTryExceeds": "0", "maskedPan": "548821******6470", "embossedName": "ALEX OAK", "expiryDate": "2027-07-31", "CVV": "582", "startDate": "2024-07-24", "endDate": "0000-00-00", "countryCode": "FR", "currencyCode": "EUR", "deliveryTitle": "M", "deliveryLastname": "OAK", "deliveryFirstname": "ALEX", "deliveryAddress1": "07323 SIPES SHOALS", "deliveryAddress2": "", "deliveryAddress3": "", "deliveryCity": "PARIS", "deliveryPostcode": "75017", "deliveryCountry": "FR", "mobileSent": "+33141358530", "limitsGroup": "TRZ-VL-001", "permsGroup": "TRZ-CU-012", "cardDesign": "8529", "virtualConverted": "0", "optionAtm": "0", "optionForeign": "1", "optionOnline": "1", "optionNfc": "1", "limitAtmYear": "2000", "limitAtmMonth": "2000", "limitAtmWeek": "2000", "limitAtmDay": "1000", "limitAtmAll": "0", "limitPaymentYear": "5000", "limitPaymentMonth": "0", "limitPaymentWeek": "3000", "limitPaymentDay": "2000", "paymentDailyLimit": "500.00", "restrictionGroupLimits": null, "limitPaymentAll": "0", "totalAtmYear": null, "totalAtmMonth": null, "totalAtmWeek": null, "totalAtmDay": null, "totalAtmAll": "0", "totalPaymentYear": null, "totalPaymentMonth": "0", "totalPaymentWeek": null, "totalPaymentDay": null, "totalPaymentAll": "0", "createdBy": "929252", "createdDate": "2024-07-18 14:10:51", "modifiedBy": "929252", "modifiedDate": "2024-07-18 14:10:57", "cancellationNumber": null, "physical": "0", "logoId":"", "logoBackId":"", "packageId":"", "customizedInfo":null, "letterCustomizedInfo":"", "freeCustomizedInfo":"", "deliveryMethod": "1", "pinMailer": "1", "batchDeliveryId": "1", "sendToParent": "1" } ] }, "webhook_created_at": 17213046655230, "webhook_id": "09cc975d-d9f8-4a61-a85d-c027022xx9e5", "object_payload_signature": "zXK+EMoIk88fQ4xxxxxJaMhS9RPDteRAifLZxF8fd8=" } ``` ::: ### `card.options` ::: code-group ```json [JSON] { "webhook": "card.options", "object": "card", "object_id": "999990082", "object_payload": { "cards": [ { "cardId": "999990082", "userId": "100642533", "walletId": "3135941", "walletCardtransactionId": "3143122", "mccRestrictionGroupId": null, "merchantRestrictionGroupId": null, "countryRestrictionGroupId": null, "eventName": "Main account", "eventAlias": "name-of-the-wallet-669697986861c", "publicToken": "105603885", "cardTag": "sky blue", "statusCode": "UNLOCK", "isLive": "1", "pinTryExceeds": "0", "maskedPan": "548821******6470", "embossedName": "ALEX OAK", "expiryDate": "2027-07-31", "CVV": "582", "startDate": "2024-07-24", "endDate": "0000-00-00", "countryCode": "FR", "currencyCode": "EUR", "deliveryTitle": "M", "deliveryLastname": "OAK", "deliveryFirstname": "ALEX", "deliveryAddress1": "07323 SIPES SHOALS", "deliveryAddress2": "", "deliveryAddress3": "", "deliveryCity": "PARIS", "deliveryPostcode": "75017", "deliveryCountry": "FR", "mobileSent": "+33141358530", "limitsGroup": "TRZ-VL-001", "permsGroup": "TRZ-CU-016", "cardDesign": "8529", "virtualConverted": "0", "optionAtm": "1", "optionForeign": "1", "optionOnline": "1", "optionNfc": "1", "limitAtmYear": "2000", "limitAtmMonth": "2000", "limitAtmWeek": "2000", "limitAtmDay": "1000", "limitAtmAll": "0", "limitPaymentYear": "5000", "limitPaymentMonth": "0", "limitPaymentWeek": "3000", "limitPaymentDay": "2000", "paymentDailyLimit": "500.00", "restrictionGroupLimits": null, "limitPaymentAll": "0", "totalAtmYear": null, "totalAtmMonth": null, "totalAtmWeek": null, "totalAtmDay": null, "totalAtmAll": "0", "totalPaymentYear": null, "totalPaymentMonth": "0", "totalPaymentWeek": null, "totalPaymentDay": null, "totalPaymentAll": "0", "createdBy": "929252", "createdDate": "2024-07-18 14:10:51", "modifiedBy": "929252", "modifiedDate": "2024-07-18 14:13:03", "cancellationNumber": null, "physical": "0", "logoId":"", "logoBackId":"", "packageId":"", "customizedInfo":null, "letterCustomizedInfo":"", "freeCustomizedInfo":"", "deliveryMethod": "1", "pinMailer": "1", "batchDeliveryId": "1", "sendToParent": "1" } ] }, "webhook_created_at": 17213047836871, "webhook_id": "54517817-3ec9-4c65-8f56-0a9xxb2e68c", "object_payload_signature": "6/pvFUoCdhyrhidvC2j+YihNZF9E0exxxxpEiDu72E=" } ``` ::: ### `card.assignwallet` ::: code-group ```json [JSON] { "webhook": "card.assignwallet", "object": "card", "object_id": "999925786", "object_payload": { "cards": [ { "cardId": "999925786", "userId": "100549108", "walletId": "3011794", "walletCardtransactionId": "3012053", "mccRestrictionGroupId": "48203", "merchantRestrictionGroupId": "107454", "countryRestrictionGroupId": "183120", "eventName": "Main account", "eventAlias": "main-account-6670280a28c2c", "publicToken": "105618829", "cardTag": "Updated cardTag", "statusCode": "UNLOCK", "isLive": "1", "pinTryExceeds": "0", "maskedPan": "548821******0226", "embossedName": "ALEX OAK", "expiryDate": "2024-06-18", "CVV": "740", "startDate": "2024-06-24", "endDate": "2024-06-17", "countryCode": "FR", "currencyCode": "EUR", "deliveryTitle": "M", "deliveryLastname": "OAK", "deliveryFirstname": "ALEX", "deliveryAddress1": "30217 CRUICKSHANK SPRINGS", "deliveryAddress2": "", "deliveryAddress3": "", "deliveryCity": "VERSAILLES", "deliveryPostcode": "78000", "deliveryCountry": "FR", "mobileSent": "+33141358530", "limitsGroup": "TRZ-VL-001", "permsGroup": "TRZ-CU-016", "cardDesign": "8529", "virtualConverted": "1", "optionAtm": "1", "optionForeign": "1", "optionOnline": "1", "optionNfc": "1", "limitAtmYear": "2000", "limitAtmMonth": "2000", "limitAtmWeek": "2000", "limitAtmDay": "1000", "limitAtmAll": "0", "limitPaymentYear": "5000", "limitPaymentMonth": "0", "limitPaymentWeek": "3000", "limitPaymentDay": "2000", "paymentDailyLimit": "500.00", "restrictionGroupLimits": null, "limitPaymentAll": "0", "totalAtmYear": null, "totalAtmMonth": null, "totalAtmWeek": null, "totalAtmDay": null, "totalAtmAll": "0", "totalPaymentYear": "0.00", "totalPaymentMonth": "0", "totalPaymentWeek": null, "totalPaymentDay": null, "totalPaymentAll": "0", "createdBy": "929252", "createdDate": "2024-06-17 14:43:54", "modifiedBy": "929252", "modifiedDate": "2024-07-18 14:07:33", "cancellationNumber": null, "physical": "0", "logoId":"", "logoBackId":"", "packageId":"", "customizedInfo":null, "letterCustomizedInfo":"", "freeCustomizedInfo":"", "deliveryMethod": "1", "pinMailer": "1", "batchDeliveryId": "1", "sendToParent": "1" } ] }, "webhook_created_at": 17213044534278, "webhook_id": "6b0aee69-87c8-45df-a0d9-42xxxx9f38b", "object_payload_signature": "WTFf7nbDnCoT6EVMRaTTTSHkA87BxxxxxdPCU30Usmo=" } ``` ::: ### `card.setpin` ::: code-group <<< @/./guide/cards/snippets/event-card-setpin.json\[JSON] ::: ### `card.unblockpin` ::: code-group ```json [JSON] { "webhook": "card.unblockpin", "webhook_id": "2xxxxxx0", "object": "card", "object_id": "6xxx3", "object_payload": { "cards": [ { "cardId": "6xxx3", "userId": "1xxxxx3", "walletId": "8xxxx5", "walletCardtransactionId": "8xxxx2", "pinTryExceeds": "0", // [...] some attributes are hidden } ] }, "object_payload_signature": "LnYAh2rE9DMTbDqjkM/p5Ks05cck85Vk8j05xfvLGBc=" } ``` ::: ### `card.unblockcvc2` ::: code-group ```json [JSON] { "webhook": "card.unblockcvc2", "object": "card", "object_id": "999988610", "object_payload": { "cards": [ { "cardId": "999988610", "userId": "100640138", "walletId": "3137125", "walletCardtransactionId": "3137126", "mccRestrictionGroupId": null, "merchantRestrictionGroupId": null, "countryRestrictionGroupId": null, "eventName": "Main account", "eventAlias": "main-account-669754fea40f1", "publicToken": "105592812", "cardTag": "", "statusCode": "UNLOCK", "isLive": "1", "pinTryExceeds": "0", "maskedPan": "548821******2232", "embossedName": "ALEX OAK", "expiryDate": "2027-07-31", "CVV": "790", "startDate": "2024-07-24", "endDate": "0000-00-00", "countryCode": "FR", "currencyCode": "EUR", "deliveryTitle": "M", "deliveryLastname": "ALEX", "deliveryFirstname": "OAK", "deliveryAddress1": "TES23 cedar hills", "deliveryAddress2": "", "deliveryAddress3": "", "deliveryCity": "PARIS", "deliveryPostcode": "75000", "deliveryCountry": "FR", "mobileSent": "+33612345678", "limitsGroup": "TRZ-VL-001", "permsGroup": "TRZ-CU-015", "cardDesign": "8529", "virtualConverted": "0", "optionAtm": "1", "optionForeign": "0", "optionOnline": "1", "optionNfc": "1", "limitAtmYear": "2000", "limitAtmMonth": "2000", "limitAtmWeek": "1000", "limitAtmDay": "500", "limitAtmAll": "5000", "limitPaymentYear": "10000", "limitPaymentMonth": "5000", "limitPaymentWeek": "3000", "limitPaymentDay": "1000", "paymentDailyLimit": "2000.00", "restrictionGroupLimits": [ { "merchantIdRestrictionGroups": 94748, "paymentDailyLimit": 0.01 } ], "limitPaymentAll": "30000", "totalAtmYear": null, "totalAtmMonth": null, "totalAtmWeek": null, "totalAtmDay": null, "totalAtmAll": null, "totalPaymentYear": null, "totalPaymentMonth": null, "totalPaymentWeek": null, "totalPaymentDay": null, "totalPaymentAll": null, "createdBy": "929252", "createdDate": "2024-07-17 07:22:08", "modifiedBy": "929252", "modifiedDate": "2024-07-18 13:15:21", "cancellationNumber": null, "physical": "0", "logoId":"", "logoBackId":"", "packageId":"", "customizedInfo":null, "letterCustomizedInfo":"", "freeCustomizedInfo":"", "deliveryMethod": "1", "pinMailer": "1", "batchDeliveryId": "1", "sendToParent": "1" } ] }, "webhook_created_at": 17213013210351, "webhook_id": "755c4496-ad53-4a29-9d27-2d9xxxx5b0f", "object_payload_signature": "5hPGRs+h6eF+Un2VIUJ/V5KFlN4CxxxcjmDHxh0gLQU=" } ``` ::: ### `card.lockunlock` ::: code-group ```json [JSON] { "webhook": "card.lockunlock", "object": "card", "object_id": "999988610", "object_payload": { "cards": [ { "cardId": "999988610", "userId": "100640138", "walletId": "3137125", "walletCardtransactionId": "3137126", "mccRestrictionGroupId": null, "merchantRestrictionGroupId": null, "countryRestrictionGroupId": null, "eventName": "Main account", "eventAlias": "main-account-669754fea40f1", "publicToken": "105592812", "cardTag": "", "statusCode": "LOCK", "isLive": "1", "pinTryExceeds": "0", "maskedPan": "548821******2232", "embossedName": "ALEX OAK", "expiryDate": "2027-07-31", "CVV": "790", "startDate": "2024-07-24", "endDate": "0000-00-00", "countryCode": "FR", "currencyCode": "EUR", "deliveryTitle": "M", "deliveryLastname": "ALEX", "deliveryFirstname": "OAK", "deliveryAddress1": "TES23 cedar hills", "deliveryAddress2": "", "deliveryAddress3": "", "deliveryCity": "PARIS", "deliveryPostcode": "75000", "deliveryCountry": "FR", "mobileSent": "+33612345678", "limitsGroup": "TRZ-VL-001", "permsGroup": "TRZ-CU-015", "cardDesign": "8529", "virtualConverted": "0", "optionAtm": "1", "optionForeign": "0", "optionOnline": "1", "optionNfc": "1", "limitAtmYear": "2000", "limitAtmMonth": "2000", "limitAtmWeek": "1000", "limitAtmDay": "500", "limitAtmAll": "5000", "limitPaymentYear": "10000", "limitPaymentMonth": "5000", "limitPaymentWeek": "3000", "limitPaymentDay": "1000", "paymentDailyLimit": "2000.00", "restrictionGroupLimits": [ { "merchantIdRestrictionGroups": 94748, "paymentDailyLimit": 0.01 } ], "limitPaymentAll": "30000", "totalAtmYear": null, "totalAtmMonth": null, "totalAtmWeek": null, "totalAtmDay": null, "totalAtmAll": null, "totalPaymentYear": null, "totalPaymentMonth": null, "totalPaymentWeek": null, "totalPaymentDay": null, "totalPaymentAll": null, "createdBy": "929252", "createdDate": "2024-07-17 07:22:08", "modifiedBy": "929252", "modifiedDate": "2024-07-18 13:15:21", "cancellationNumber": null, "physical": "0", "logoId":"", "logoBackId":"", "packageId":"", "customizedInfo":null, "letterCustomizedInfo":"", "freeCustomizedInfo":"", "deliveryMethod": "1", "pinMailer": "1", "batchDeliveryId": "1", "sendToParent": "1" } ] }, "webhook_created_at": 17213013210351, "webhook_id": "755c4496-ad53-4a29-9d27-2d9xxxx5b0f", "object_payload_signature": "5hPGRs+h6eF+Un2VIUJ/V5KFlN4CxxxcjmDHxh0gLQU=" } ``` ::: ### `card.regenerate` ::: code-group ```json [JSON] { "webhook": "card.regenerate", "webhook_id": "2xxxxxx4", "object": "card", "object_id": "6xxx6", "object_payload": { "cards": [ { "cardId": "6xxx6", "userId": "1xxxxx3", "walletId": "8xxxx5", "walletCardtransactionId": "8xxxx3", "expiryDate": "2024-04-30", "CVV": "724", "physical": "0" // [...] some attributes are hidden } ] }, "object_payload_signature": "aAd1gmssgfKiyWZ16njB/b/rk0qQ0NL19CSwOLXLhvY=" } ``` ::: ### `card.register3DS` ::: code-group ```json [JSON] { "webhook": "card.register3DS", "object": "card", "object_id": "9999886XX", "object_payload": { "cards": [ { "cardId": "999988610", "userId": "100640138", "walletId": "3137125", "walletCardtransactionId": "3137126", "mccRestrictionGroupId": null, "merchantRestrictionGroupId": null, "countryRestrictionGroupId": null, "eventName": "Main account", "eventAlias": "main-account-669754fea40f1", "publicToken": "105511111", "cardTag": "", "statusCode": "UNLOCK", "isLive": "1", "pinTryExceeds": "0", "maskedPan": "548821******2232", "embossedName": "ALEX OAK", "expiryDate": "2027-07-31", "CVV": "790", "startDate": "2024-07-24", "endDate": "0000-00-00", "countryCode": "FR", "currencyCode": "EUR", "deliveryTitle": "M", "deliveryLastname": "ALEX", "deliveryFirstname": "OAK", "deliveryAddress1": "15 rosewood lane", "deliveryAddress2": "", "deliveryAddress3": "", "deliveryCity": "PARIS", "deliveryPostcode": "75000", "deliveryCountry": "FR", "mobileSent": "+33612345678", "limitsGroup": "TRZ-VL-001", "permsGroup": "TRZ-CU-015", "cardDesign": "8529", "virtualConverted": "0", "optionAtm": "1", "optionForeign": "0", "optionOnline": "1", "optionNfc": "1", "limitAtmYear": "2000", "limitAtmMonth": "2000", "limitAtmWeek": "1000", "limitAtmDay": "500", "limitAtmAll": "5000", "limitPaymentYear": "10000", "limitPaymentMonth": "5000", "limitPaymentWeek": "3000", "limitPaymentDay": "1000", "paymentDailyLimit": "2000.00", "restrictionGroupLimits": "[{\"merchantIdRestrictionGroups\":94748,\"paymentDailyLimit\":0.01}]", "limitPaymentAll": "30000", "totalAtmYear": null, "totalAtmMonth": null, "totalAtmWeek": null, "totalAtmDay": null, "totalAtmAll": null, "totalPaymentYear": null, "totalPaymentMonth": null, "totalPaymentWeek": null, "totalPaymentDay": null, "totalPaymentAll": null, "createdBy": "929252", "createdDate": "2024-07-17 07:22:08", "modifiedBy": "929252", "modifiedDate": "2024-07-17 07:22:09", "cancellationNumber": null, "physical": "0", "logoId":"", "logoBackId":"", "packageId":"", "customizedInfo":null, "letterCustomizedInfo":"", "freeCustomizedInfo":"", "deliveryMethod": "1", "pinMailer": "1", "batchDeliveryId": "1", "sendToParent": "1" } ] }, "webhook_created_at": 17212967948092, "webhook_id": "7a4796f4-5ca7-478a-b5fd-3d5831xxxxxx", "object_payload_signature": "QpoPfubfnsDYCVT+iEzxxxxxAvTm7h13ieDLY5UvIA=" } ``` ::: ### `card.expiryAlert` You receive this webhook a month before the expiry date of an active or temporarily blocked card (i.e., `statusCode` is either `UNLOCK` or `LOCK`). For example, for an active card expiring on July 31st 2024, Treezor sends a `card.expiryAlert` webhook on June 1st 2024. ::: code-group ```json { "webhook": "card.expiryAlert", "object_payload": { "cards": [ { "cardId": "2111143", "expiryDate": "YYYY-MM-DD", "renewalType": "A", "userId": "1234", "publicToken": "111111682", "maskedPan": "545923****21321", "cardDesign": "555", "designCode": "01", "cardTag": "custom", "isLive": "1", "statusCode": "UNLOCK", "physical": "1" } ] }, "object_id": "2312343", "object": "card", "webhook_created_at": 17251498098864, "webhook_id": "4e4fad5b-78b5-4d7a-a8ac-bed3xxxxd66a", "object_payload_signature": "DSzhfXH4CJjCCdx5ducs/WB3vqADAvGwxxxxx6VbNz0=" } ``` ::: ### `card.expeditionTracking` You receive this webhook when the card manufacturer mails the physical card (if the [corresponding feature](/guide/cards/creation#expedition-tracking) is activated). ::: code-group ```json [JSON] { "webhook": "card.expeditionTracking", "object": "card", "object_id": "reconciliation_id", "object_payload": { "publicToken": "1234", "deliveryDate": "2024-07-17 07:22:09", "deliveryMethod": "", "batchDeliveryId": 0, "trackingNumber": 0, "requestType": "CREATION", // CREATION (new cards) or RENEWAL (replacement) }, "object_payload_signature": "++++++++++++++++++++++++++++++++++++++++++++" } ``` ::: ## Card Bulk Updates ### `cardBulkUpdate.create` ::: code-group ```json [JSON] { "webhook":"cardBulkUpdate.create", "object_payload":{ "createdDate":"2025-12-16 16:01:17", "updatedDate":"2025-12-16 16:01:17", "bulkUpdateTag":"tag", "bulkUpdateId":"0eb6a619-cdc6-4896-a7fd-479d51d46876", "bulkUpdateProgressStatus":"IN_PROGRESS", "bulkUpdateType":"CARD_LIMITS", "cardAttributes":{ "paymentDailyLimit":1.5, "limitAtmYear":1, "limitAtmMonth":2, "limitAtmWeek":3, "limitAtmDay":4, "limitAtmAll":5, "limitPaymentYear":6, "limitPaymentMonth":7, "limitPaymentWeek":8, "limitPaymentDay":9, "limitPaymentAll":10, "restrictionGroupLimits":[ { "mccRestrictionGroups":2780, "merchantIdRestrictionGroups":557, "countryRestrictionGroups":1228, "paymentDailyLimit":0.75 } ] }, "totalObjects":11 }, "object_id":"31974243-4be4-47e5-ba73-9fbd7c57a940", "object":"cardBulkUpdate", "webhook_created_at":17455072946744 } ``` ::: ### `cardBulkUpdate.update` ::: code-group ```json [JSON] { "webhook":"cardBulkUpdate.update", "object_payload":{ "createdDate":"2025-12-16 16:01:17", "updatedDate":"2025-12-16 21:01:17", "bulkUpdateTag":"tag", "bulkUpdateId":"0eb6a619-cdc6-4896-a7fd-479d51d46876", "bulkUpdateProgressStatus":"DONE", "bulkUpdateType":"CARD_LIMITS", "cardAttributes":{ "paymentDailyLimit":1.5, "limitAtmYear":1, "limitAtmMonth":2, "limitAtmWeek":3, "limitAtmDay":4, "limitAtmAll":5, "limitPaymentYear":6, "limitPaymentMonth":7, "limitPaymentWeek":8, "limitPaymentDay":9, "limitPaymentAll":10, "restrictionGroupLimits":[ { "mccRestrictionGroups":2780, "merchantIdRestrictionGroups":557, "countryRestrictionGroups":1228, "paymentDailyLimit":0.75 } ] }, "totalObjects":11 }, "object_id":"31974243-4be4-47e5-ba73-9fbd7c57a940", "object":"cardBulkUpdate", "webhook_created_at":17455072946744 } ``` ::: ## Card Digitization ### `cardDigitalization.request` Webhook [TAR](x-pay-google-apple#glossary). ::: code-group ```json [JSON] { "webhook": "cardDigitalization.request", "object": "cardDigitalization", "object_id": "11", "object_payload": { "deviceType": "PHONE", // PaymentToken_deviceType "deviceName": "", "tokenRequestor": "APPLE", // can also be "GOOGLE", "SAMSUNG", "MerchToken" "tokenServiceProvider": "Visa", "cardDigitizationExternalId": "21498", "tokenizationDecision": "ACCEPTED", // can also be "DECLINED", "reasonDecision": "", // empty in case of "ACCEPTED", populated in case of a "DECLINED" "cardId": 6127, "correlationId":"" }, "object_payload_signature": "++++++++++++++++++++++++++++++++++++++++++++" } ``` ::: ### `cardDigitalization.update` ::: code-group ```json [JSON] { "webhook": "cardDigitalization.update", "object": "cardDigitalization", "object_id": "11", "object_payload": { "id":123, "cardId": 32134, "status":"S", "createdDate":"2022-10-19 15:12:50", "modifiedDate":"2022-10-24 15:44:30", "tokenServiceProvider": "Visa", "updateType":"" }, "object_payload_signature": "++++++++++++++++++++++++++++++++++++++++++++" } ``` ::: ### `cardDigitalization.activation` ::: code-group ```json [JSON] { "webhook": " cardDigitalization.activation ", "webhook_id": "3788548", "object": " cardDigitalization ", "object_id": "11", "object_payload": { "deviceType": "UNDEFINED", "deviceName": "", "tokenRequestor": "APPLE", "tokenServiceProvider": "Visa", "cardDigitizationExternalId": "21498", "activationCode": "123456", "activationCodeExpiry": "Dec 31 2016 11:11AM", "activationMethod": "EMAIL_TO_CARDHOLDER_ADDRESS", "cardId": 6127 }, "object_payload_signature": "++++++++++++++++++++++++++++++++++++++++++++" } ``` ::: ### `cardDigitalization.complete` ::: code-group ```json [JSON] { "webhook": " cardDigitalization.complete", "webhook_id": "3788546", "object": " cardDigitalization ", "object_id": "11", "object_payload": { "deviceType": "", "deviceName": "", "tokenRequestor": "APPLE", "tokenServiceProvider": "Visa", "cardDigitalizationExternalId": "21498", "cardId": 6127, "tokenId": "48 Chars ANS - Token Unique Reference", "merchantRequestorName": "",// up to 40 chars. identifies the M4M merchant requestor "correlationId" : 4815162342 }, "object_payload_signature": "++++++++++++++++++++++++++++++++++++++++++++" } ``` ::: ### `cardDigitalization.deactivated` ::: code-group ```json [JSON] { "messageId": "7e233828-a947-5fcd-8d27-xxxxxxxxxxxxxx", "webhookId": "2b562cd5-b1ef-4962-8109-xxxxxxxxxxxxxx", "webhook": { "webhook": "cardDigitalization.deactivated", "object": "cardDigitalization", "object_id": "2773123", "object_payload": { "cardDigitalizations": [ { "id": 2773123, "cardId": 5390123, "status": "X", "createdDate": "2024-02-05 16:22:20", "modifiedDate": "2024-02-15 11:49:17" } ] }, "webhook_created_at": 17079941571098, "webhook_id": "2b562cd5-b1ef-4962-8109-xxxxxxxxxxxxxx", "object_payload_signature": "++++++++++++++++++++++++++++++++++++++++++++" } } ``` ::: ## MID Group ### `merchantIdGroup.create` ::: code-group ```json [JSON] { "webhook": "merchantIdGroup.create", "webhook_id": "2xxxxx9", "object": "merchantIdGroup", "object_id": "4xx1", "object_payload": { "merchantIdRestrictionGroups": [ { "id": 4xx1, "name": "Merchant Test", "isWhitelist": true, "status": "VALIDATED", "startDate": "2017-12-19 16:03:55", "createdDate": "2021-04-20 16:11:10", "modifiedDate": null } ] }, "object_payload_signature": "K5hea0NO9hBVwIenmZBlvV1ay85XxKWFzgvS5mRH2tI=" } ``` ::: ### `merchantIdGroup.update` ::: code-group ```json [JSON] { "webhook": "merchantIdGroup.update", "webhook_id": "2xxxxxx5", "object": "merchantIdGroup", "object_id": "4xx3", "object_payload": { "merchantIdRestrictionGroups": [ { "id": 4xx3, "name": "Merchant Test", "isWhitelist": true, "status": "VALIDATED", "startDate": "2017-12-19 16:03:55", "createdDate": "2021-04-20 16:30:22", "modifiedDate": "2021-04-21 10:02:39" } ] }, "object_payload_signature": "k46KsOCHLNXf0mc+S3+DAp71UMmHIAr00GxKxpLDL8E=" } ``` ::: ### `merchantIdGroup.cancel` ::: code-group ```json [JSON] { "webhook": "merchantIdGroup.cancel", "webhook_id": "2xxxxxx7", "object": "merchantIdGroup", "object_id": "4xx5", "object_payload": { "merchantIdRestrictionGroups": [ { "id": 4xx5, "name": "Merchant Test", "isWhitelist": true, "status": "CANCELED", "startDate": "2017-12-19 16:03:55", "createdDate": "2021-04-21 08:03:05", "modifiedDate": "2021-04-21 08:30:45" } ] }, "object_payload_signature": "NDakNFLjBVpl+b3skAfg1EO+B+SGRe81ZVpV0cYlVqk=" } ``` ::: ## MCC Group ### `mccGroup.create` ::: code-group ```json [JSON] { "webhook": "mccGroup.create", "webhook_id": "2xxxxxx8", "object": "mccGroup", "object_id": "5xx4", "object_payload": { "mccRestrictionGroups": [ { "id": 5xx4, "name": "MCC Group Test", "isWhitelist": true, "mcc": [ 8911, 763 ], "status": "VALIDATED", "startDate": "2017-11-01 10:00:00", "createdDate": "2021-04-20 15:47:26", "modifiedDate": null } ] }, "object_payload_signature": "Swx2bnNeYo0gKO+LaD1+lw6sS+ue2M7+sI5HAc6U5fU=" } ``` ::: ### `mccGroup.update` ::: code-group ```json [JSON] { "webhook": "mccGroup.update", "webhook_id": "2xxxxxx2", "object": "mccGroup", "object_id": "5xx4", "object_payload": { "mccRestrictionGroups": [ { "id": 5xx4, "name": "MCC Group Test", "isWhitelist": true, "mcc": [ 8911, 763 ], "status": "VALIDATED", "startDate": "2017-11-01 10:00:00", "createdDate": "2021-04-20 15:47:26", "modifiedDate": "2021-04-20 15:58:37" } ] }, "object_payload_signature": "L0AsXqQAEzVPITCWgXVbBd7QVeqS0VED+7Cks6JL68g=" } ``` ::: ### `mccGroup.cancel` ::: code-group ```json [JSON] { "webhook": "mccGroup.cancel", "webhook_id": "2xxxxxx9", "object": "mccGroup", "object_id": "5xx4", "object_payload": { "mccRestrictionGroups": [ { "id": 5xx4, "name": "MCC Group Test", "isWhitelist": true, "mcc": [ 8911, 763 ], "status": "CANCELED", "startDate": "2017-11-01 10:00:00", "createdDate": "2021-04-20 15:47:26", "modifiedDate": "2021-04-20 16:00:44" } ] }, "object_payload_signature": "A8/on0tyGHkPWnoRzUCIH9nahq/H1HRt1iwHehTbRjo=" } ``` ::: ## Country Group ### `countryGroup.create` ::: code-group ```json [JSON] { "webhook": "countryGroup.create", "webhook_id": "2xxxxx8", "object": "countryGroup", "object_id": "2xx8", "object_payload": { "countryRestrictionGroups": [ { "id": 2xx8, "name": "Test Country Group", "isWhitelist": true, "countries": [ "250" ], "status": "VALIDATED", "startDate": "2021-04-20 00:00:00", "createdDate": "2021-04-20 13:48:49", "modifiedDate": null } ] }, "object_payload_signature": "KHlM6UudrM/t6IHlQMUO0fxklueJJrpOt66HE/+6Pns=" } ``` ::: ### `countryGroup.update` ::: code-group ```json [JSON] { "webhook": "countryGroup.update", "webhook_id": "2xxxxx3", "object": "countryGroup", "object_id": "2xx9", "object_payload": { "countryRestrictionGroups": [ { "id": 2xx9, "name": "Test Country Group", "isWhitelist": true, "countries": [ "250" ], "status": "VALIDATED", "startDate": "2021-04-20 00:00:00", "createdDate": "2021-04-20 13:52:04", "modifiedDate": "2021-04-20 13:57:29" } ] }, "object_payload_signature": "pmVAqdJUlbreSgYth9fkq2WhOKM8wrTQxF6HM6bpGLQ=" } ``` ::: ### `countryGroup.cancel` ::: code-group ```json [JSON] { "webhook": "countryGroup.cancel", "webhook_id": "2xxxxx5", "object": "countryGroup", "object_id": "2xx9", "object_payload": { "countryRestrictionGroups": [ { "id": 2xx9, "name": "Test Country Group", "isWhitelist": true, "countries": [ "250" ], "status": "CANCELED", "startDate": "2021-04-20 00:00:00", "createdDate": "2021-04-20 13:52:04", "modifiedDate": "2021-04-20 14:08:30" } ] }, "object_payload_signature": "CDsjDd4QcEd9Kig8hzOuJuUZP/yWnRMl3MZTcgZxwg8=" } ``` ::: --- --- url: /guide/cards/errors.md description: >- Troubleshoot and handle card-related issues using the Treezor API's complete list of error codes, messages, and their corresponding meanings. --- # Errors The following API errors can be encountered when issuing cards. **Caution – Only the legacy API sends the error code in HTTP errors** When handling errors with Connect, only the `message` attribute is returned. ## Card errors | Code | Message | |:--------:|-------------------------------------------------------------------------------------------------| | `32000` | Impossible to create card. SQL error | | `32001` | WSDI required | | `32002` | ItemSrc required | | `32003` | SecId required | | `32004` | SecValPos required | | `32005` | Apply\_Fee required | | `32006` | PublicToken required | | `32007` | IsLive required | | `32008` | IssCode required | | `32009` | Tile, LastName, FirstName, Addrl1, City, Postcode, Country are required | | `32010` | LocDate(YYYY-MM-JJ) and LocTime(HHMMSS) are required | | `32011` | CreateImage is required (0 OR 1) | | `32012` | CreateType is required (0 OR 1) | | `32013` | ActivateNow is required (0 OR 1) | | `32014` | The StartDate format is MM/YY | | `32015` | The CardDesign is mandatory | | `32016` | PERMSGroup is mandatory | | `32017` | Replacement must have only 0 or 1 values | | `32018` | Delv\_AddrL1, Delv\_City, Delv\_PostCode, Delv\_County and Delv\_Country are mandatory | | `32019` | IsLive must have only 0 or 1 values | | `32020` | CardManufacturer must have only TCT, AllPay, GNC, Gemalto, Nitecrest, Exceet, Thames values | | `32021` | ExternalAuth must have only 0 OR 1 values | | `32022` | Email is mandatory | | `32023` | Email is not valid | | `32024` | MailOrSMS must have only 0, 1 or 2 values | | `32025` | TxnCode required | | `32026` | ActMethod required | | `32027` | PAN required if Track2 and PublicToken are not present | | `32028` | Track2 required if ActivMethod is '4' | | `32029` | Track2 required if PAN and PublicToken are not present | | `32030` | PublicToken required if PAN and Track2 are not present | | `32031` | LocDate is mandatory | | `32032` | LocTime is mandatory | | `32033` | SmsBalance is mandatory: Possible Values: 0 OR False - Desactivate, 1 OR True - Activate, 2 OR No - Do not change current value | | `32034` | DOB is mandatory | | `32035` | ItemSrc is mandatory | | `32036` | AuthType required | | `32037` | CVV required | | `32038` | AccCode required | | `32039` | PAN required if AuthType == '1', '2', '3', '4' or '6' and PublicToken not present | | `32040` | PublicToken is null or not present. Impossible to convert the card | | `32041` | userId is mandatory | | `32042` | CardDesign is mandatory | | `32044` | expiryDate is mandatory | | `32045` | expiryDate is not a valid date | | `32046` | expiryDate must have this form YYYY-MM-DD | | `32047` | cardId is required | | `32048` | Error impossible to convert card | | `32049` | Error impossible to change PIN | | `32050` | newPin is mandatory | | `32051` | Impossible to activate card | | `32052` | Impossible to read the card | | `32053` | Impossible to create the card | | `32054` | Impossible to modify the card | | `32055` | Impossible to convert the card | | `32056` | Impossible to change the card's PIN | | `32057` | confirmPin is mandatory | | `32058` | Impossible to renew the card | | `32059` | Impossible to lock/unlock the card | | `32060` | lockStatus is required | | `32061` | permsGroup is required | | `32062` | cardDesign is required | | `32064` | User informations are incomplete: lastname, firstname, address1 and phone (or mobile) is required | | `32065` | Country code is invalid | | `32066` | Internal error. Impossible to create physical card | | `32067` | Impossible to create physical card: insertion impossible in database | | `32068` | User's phone or user's mobile required | | `32070` | Internal error. Impossible to create virtual card | | `32071` | limitPeriod is mandatory | | `32072` | limitType is mandatory | | `32073` | The cardId provided does not exist | | `32074` | The foreign option is mandatory. 0 or 1 | | `32075` | The online option is mandatory. 0 or 1 | | `32076` | The atm option is mandatory. 0 or 1 | | `32077` | The nfc option is mandatory. 0 or 1 | | `32078` | No perms group corresponds to the options provided | | `32079` | walletId is mandatory | | `32080` | The wallet does not exist | | `32081` | There is no product in the database. Impossible to create the card | | `32082` | The currency of the wallet must be the same as the product | | `32083` | The permsGroup does not exist | | `32084` | The card is already physical. | | `32085` | The card has been already converted. | | `32086` | Impossible to insert Card image. | | `32087` | Impossible to create card. The PIN is invalid | | `32088` | Impossible to change PIN. The current PIN is mandatory | | `32089` | Impossible to change PIN. The newPIN must be the same as the confirmPin | | `32090` | Impossible to create card. The cardPrint is mandatory | | `32091` | Impossible to create card. The cardPrint is invalid | | `32092` | Impossible to update card options (GPS) | | `32093` | Impossible to regenerate card (GPS) | | `32094` | Impossible to update card image | | `32095` | Card status can not be changed, current status of the card is not reversible Code. Card lost. | | `32096` | Card status can not be changed, current status of the card is not reversible Code. Card stolen. | | `32097` | Impossible to create card. sendToParent value 1, but there is no parent user id for the main user| | `32098` | Impossible to create card. Delivery address not complete. The parent user must have delivery address informations provided. (legalName, address1, address2, postcode, city and country) | | `32099` | Impossible to create card. Delivery address not complete. The user must have delivery address informations provided. (address1, address2, postcode, city and country) | | `32100` | Impossible to create card. Delivery address not complete in user's informations. The user must have full address informations provided. (address1, postcode, city and country) | | `32101` | Card limit exceeded | | `32102` | Erreur lors du cardUpdateDeliveryInfo (GPS) | | `32103` | Erreur lors du cardUpdateDeliveryInfo (GPS) | | `32104` | GPS Error happened when attempting to get all DPAN | | `32105` | GPS Error happened when attempting to get all DPAN WRONG Status code in Return | | `32106` | GPS Error happened when attempting to change status of Payment token | | `32107` | GPS Error happened when attempting to change status of Payment token - empty response | | `32108` | GPS Error happened when attempting to change status of Payment token - wrong action code returned| | `32109` | Exception raised while attempting to reactivate all DPAN linked to card | | `32111` | Card blocked. | | `32112` | mccRestrictionGroupId provided does not exist. | | `32113` | merchantRestrictionGroupId provided does not exist. | | `32114` | EmbossedName value is empty after sanitized, the characters accepted are : a-z, A-Z, 0-9, '-' and 'espace'| | `32113` | countryRestrictionGroupId provided does not exist. | | `32115` | batchDeliveryId must be an integer between 1 and 238323 | | `32116` | batchDeliveryId can not be used. Not operational yet. | | `32117` | Delivery address is missing or incomplete. Impossible to convert the card. address1, city, postcode and country are mandatory| | `32118` | Wallet has a CANCELED status. | | `32119` | User has a CANCELED status. | | `32120` | User does not exist | | `32121` | Exception raised when a language is not in the Languages list | | `32122` | Missing program id in database | | `32123` | Invalid program id in database | | `32124` | The parentUserId does not exist | | `32125` | Missing Public Token | | `32126` | Missing clientId | | `32228` | Missing Public phone | | `32229` | Card status can not be changed, current status of the card is not reversible Code. Card locked internally.| | `32230` | Card status can not be changed, current status of the card is not reversible Code. Card is expired.| | `32231` | Card status is invalid | | `32232` | Invalid payment timeframe | | `34000` | The card must be already activated | | `34001` | The request is refused because the card has expired | | `34002` | Fail to renew card | | `34003` | The card must not be stolen or lost or destroyed | | `34004` | The card must be physical | | `34005` | Fail to replace card | | `34006` | The request is refused because it cannot be made during the month the card expires | | `32127` | Card is already activated | | `32128` | Please set card information in object | | `32129` | Impossible de renew\_cards chez GPS | | `32130` | Please set card information in object | | `32131` | Impossible to create the card, the length of an address line must be less than 38 characters | | `32131` | Parent user not found, impossible to update card information | | `32132` | Impossible to create the card, user's assets are frozen | | `32133` | Impossible to create the card, parent user's assets are frozen | | `32134` | RestrictionGroupLimits value is invalid | | `32135` | Please fill in at least one limit among these: limitPaymentDay / paymentDailyLimit / limitPaymentWeek / limitPaymentMonth for this card. | | `32136` | Please fill in at least one limit among these: limitAtmDay / limitAtmWeek / limitAtmMonth for this card. | | `32137` | Please fill in at least one limit among these: limitPaymentDay / paymentDailyLimit / limitPaymentWeek / limitPaymentMonth for this card. | | `32138` | Please fill in at least one limit among these: limitAtmDay / limitAtmWeek / limitAtmMonth for this card. | | `32139` | Impossible to create card, the product is not activated. | | `32140` | Please provide at least one argument among these: userId / walletId to reassign this card. | | `32141` | The provided card is already activated and cannot be reassigned. | | `32142` | The provided card is lost or stolen and cannot be reassigned. | | `32143` | The provided card is not anonymous and cannot be reassigned. | | `32144` | Wallet does not exist. | | `32145` | The provided user's assets are frozen, the card cannot be reassigned. | | `32146` | The provided wallet has a user with frozen assets and cannot be reassigned. | | `32147` | This wallet type cannot be assigned. | | `32148` | Impossible to create card. The customizedInfo is invalid | | `32149` | Impossible to create card. The embossLegalName and the customizedInfo cannot both be specified | | `32150` | Impossible to create card, cardLanguages has a wrong format (alphabetic, 8 char. max, format ISO 639-1) | | `32151` | Unrecognized card renewOption | | `32152` | Invalid card renewOption given the card status | | `32153` | Card status cannot be changed, current status of the card is not reversible Code. Card destroyed| | `32154` | Card expiry date failed to update | | `32155` | Card not found | | `32156` | Unable to create card. The letterCustomizedInfo is invalid | | `32157` | Unable to create card. The card type is missing | | `32158` | Unable to create card. The freeCustomizedInfo is invalid | | `32159` | Unable to create card. DeliveryMethod value must be 0, 1 or 2 | | `32160` | Unable to create card. The pinMailer is invalid | | `32161` | Unable to create card. The pinMailer is not supported by this product | | `32162` | Unable to create card. The logoBackId is invalid | | `32163` | Unable to create card. The logoId is invalid | | `32164` | Unable to save card. The maskedPan is mandatory | | `32165` | Unable to save card. The startDate is mandatory | | `32166` | Unable to save card. The expiryDate is mandatory | | `32167` | The request is refused because the value of the renewalType field must be A or N | | `32168` | CardTag exceeds 50 characters | | `32169` | The provided card is lost and cannot be reassigned. | | `32170` | The provided card is stolen and cannot be reassigned. | | `32171` | The provided card is expired and cannot be reassigned. | | `32172` | The provided card is destroyed and cannot be reassigned. | | `32173` | The provided card is locked by Treezor and cannot be reassigned. | | `32174` | Wallet assignment is not allowed on this card | | `107000` | Impossible to reach server, please try again later | | `107001` | An error occurred, please try again later | | `107002` | Missing argument. You should provide cardId or publicToken | | `107003` | Invalid argument | | `107004` | No card found | | `107005` | Duplicated record | | `107006` | Invalid argument lockStatus | | `107007` | Impossible to change the card status | | `107008` | Impossible to read the card | | `107009` | Impossible to activate card | | `107010` | Impossible to convert virtual card | | `107011` | Impossible to update card's options | | `107012` | Impossible to get cardImage | | `107013` | Impossible to unblock card's PIN code | | `109001` | cardProduct Id does not exist | | `109002` | The currencyCode format must follow the norm : Code ISO 4217 | | `109003` | The countryCode format must follow the norm : ISO-3166-1 alpha-2 | | `109004` | cardPrint print\_reference does not exist | | `109005` | cardProduct Id already used | | `109006` | clientId does not exist | | `109007` | The network can only be mastercard or visa | | `109008` | The status should be active, blocked and canceled | | `120100` | Impossible to modify limits | ## Card image errors | Code | Message | |:----------:|--------------------------------------------------------------------------------------------------------------| | `62000` | The cardId does not exist. | | `62001` | No card image found | | `62002` | cardId mandatory | | `62003` | cardimage mandatory (not empty) | | `62004` | Connection socket error | | `62005` | Writing in socket error | | `62006` | The response image is empty | | `62007` | Internal error socket | | `62008` | The card has a LOST or STOLEN status | | `62009` | Missing argument encryptionMethod (encryptionPublicKey provided) | | `62010` | Missing argument encryptionPublicKey (encryptionMethod provided) | | `62011` | Invalid encryption method | ## Card digitalization errors | Code | Message | |:----------:|--------------------------------------------------------------------------------------------------------------| | `77000` | cardDigitalization Id does not exist | | `77001` | No linked card retrieved | | `77002` | The new status that you want to apply to this card is not authorized | | `77003` | The status change has failed due to a technical error. | | `77004` | This service is not available; only GET and PUT are implemented. | | `77005` | Card\_id is mandatory to perform the Update of the Status | | `77006` | Get the Payment Token Information at provider failed - Status Code is not valid | | `77007` | The Get Payment Token Failed due to the presence of two objects instead of one | | `77008` | The Get Payment Token Failed due to the fact that the first object retrieved is empty | | `77009` | PaymentToken\_id is missing. | | `77010` | Proc\_Code is missing. | | `77011` | Unknown proc code. | | `77012` | The provided status is invalid | | `77013` | The provided reason code is invalid | | `77014` | The DPAN is deactivated, unable to update | | `77015` | Error, The SMS has not been sent | | `77016` | The Provided Card is already suspended. | | `77017` | The provided card is already deactivated. | | `77018` | The provided card is already activated. | | `99001` | Impossible to reach server, please try again later | | `99002` | Service response is KO, please try again later | ## Restriction group errors | Code | Message | |----------|------------------------------------------------------------------------------------------------------| | `82000` | MCC restriction group Id does not exist | | `82001` | MCC restriction group array validation failed | | `82002` | Status provided is not correct | | `82003` | MCC restriction group Id does not exist | | `81004` | Error appending MCC restriction group | | `83000` | Merchant restriction group Id does not exist | | `83001` | Merchant restriction group array validation failed | | `83002` | Status provided is not correct | | `83003` | Merchant restriction group Id does not exist | | `82004` | Error appending Merchant Id restriction group | | `82005` | Start date provided is incorrect | | `82006` | MerchantsOperation can be only add or remove | | `82007` | You have no merchants deleted | | `82008` | The number of merchants exceeded the max authorized, please try again with a smaller number | | `84000` | Country restriction group Id does not exist | | `84001` | Country restriction group array validation failed | | `84002` | Status provided is not correct | | `84003` | Country restriction group Id does not exist | | `84004` | Error appending Country restriction group | | `94000` | The type does not exist | | `94001` | The ID does not exist | | `94002` | Impossible to reach server, please try again later | | `94003` | Service response is KO, please try again later | | `94004` | Error using restriction groups | | `94005` | Service response is empty, please try again later | | `94006` | Impossible to format response, please try again later | | `94007` | Duplicated Record | | `94008` | More than 100,000 records have been found, please refine your request | | `94009` | Invalid Data | | `94010` | Missing Data | | `94011` | No Record Found | | `94012` | An error occurred, please try again later | --- --- url: /guide/cards/pci-dss.md description: >- Learn how to set up your certificates and sign your requests to migrate to Treezor PCI DSS services, hence offering the highest level of security for sensitive card data. --- # PCI DSS integration Treezor complies with the [**Payment Card Industry Data Security Standard (PCI DSS)**](/guide/overview/glossary#payment-card-industry-data-security-standards-pci-dss) to secure sensitive data (e.g., PAN, PIN, CVV) of payment cards. **Configuration – Migrating to PCI DSS services** If you have been working with Treezor since before PCI DSS became available, you must migrate to these new services. Please contact Treezor for more information. The implementation of PCI DSS at Treezor relies on the [**Mutual Transport Layer Security (mTLS)**](/guide/api-basics/mutual-tls) protocol, which guarantees mutual authentication and encrypted communication, and prevents interception or identity theft between systems. This protocol applies to all endpoints. In addition, all your requests transit through the following URL: * **Sandbox** – `https://.preprod.secure.treezor.co` * **Production** – `https://.secure.treezor.co` This article takes you through the steps to implement mTLS, focusing on your Sandbox environment. Please bear in mind you'll have to repeat the same procedure for your Production environment. ## Setting up your certificates To use mTLS, you first need to send a CSR (Certificate Signing Request) to Treezor for your **mTLS certificate** (to set up, with your private key, the TLS negotiation). In return, Treezor provides the signed certificate for you to configure your client and authenticate your requests. You need to provide a certificate for each of your Treezor environments (Sandbox and Production), which means you’ll have to send 2 CSR files. ### 1. Create your RSA keys You need a private key to create your certificate signing request (CSR). These keys must have the following attributes: * **Type**: RSA * **Format**: PKCS1 * **Size**: 2048 Here is the command to run for your Sandbox, please keep in mind you'll have to do the same for your Production environment. ::: code-group ```[Linux / macOS] openssl genrsa -out _privatekey_mtls.pem 2048 ``` ::: **Security – Protect your private key** Don’t share your private keys with anyone and make sure they are securely stored (e.g., secure vault, key management system). ### 2. Create your CSR files The Certificate Signing Request (CSR) is the request you send to a Certificate Authority (or CA, in this case, Treezor) to apply for a digital identity certificate. The CSR includes the public key and additional information, such as the entity requesting the certificate's common name (CN). Here is the command to run: ::: code-group ```[Linux / macOS] openssl req -new -key _privatekey_mtls.pem -out _csr_mtls.pem ``` ::: Then use the information in the table below to complete the CSR information. | Information | Description | |---------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Country | The two-letter country code representing the country where the organization is located. | | State / Province | The state or province where the organization is located (e.g., Brittany, IdF). | | Locality | The locality or city where the organization is located. | | Organization Name | The legal name of the organization to which the entity belongs. This could be the company, department, or other organizational unit. | | Organizational Unit | (optional) The specific unit within the organization. For example, "IT Department" or "Marketing". | | Common Name | Usually, the fully qualified domain name (FQDN) for which the certificate is being requested. For example, if the certificate is for a website, the CN might be the domain name (e.g., https://yourcompany.com). | | Email | The email address of the organization. | ### 3. Ask Treezor to generate your certificates CSR files and certificates aren't considered sensitive data. This is why you can exchange them by email. 1. Send your CSR files to your *Treezor Technical Account Manager*. 2. Treezor will send you back the signed certificates. **Security – Don't send your private keys, only the CSR files** If you were to send us your private key, you would have to generate new ones and start the process from scratch. You now have the necessary certificates for mTLS authentication. **Reading – More information available on mTLS** Learn more about certificates, including when to [renew](/guide/api-basics/mutual-tls#renewing-your-certificates) or [revoke](/guide/api-basics/mutual-tls#revoking-your-certificates) them. ## Make your requests Now that you have your certificates, you can make PCI DSS-specific requests (see [PCI DSS API Reference](/api-reference/pci-dss-dev.html)). ::: code-group ```go [Golang] package main import ( "crypto/tls" _ "embed" "fmt" "io" "net/http" ) var ( //go:embed _csr_mtls.pem pemCertificateMTLS []byte //go:embed _privatekey_mtls.pem pemPrivateKeyMTLS []byte ) func GenerateRequest(httpMethod, requestURL string, queryParams map[string]string, jwtToken, scaProof string, body io.Reader) (*http.Request, error) { if jwtToken == "" { return nil, fmt.Errorf("missing JWT Token") } request, err := http.NewRequest(httpMethod, requestURL, body) if err != nil { return nil, fmt.Errorf("failed to create request: %w", err) } request.Header["Authorization"] = []string{"Bearer " + jwtToken} if scaProof != "" { request.Header["X-Trz-SCA"] = []string{scaProof} } return request, nil } // SendUsingMTLS sends the given HTTP request using mTLS protocol. func SendUsingMTLS(request *http.Request) (*http.Response, error) { clientCertificate, err := tls.X509KeyPair(pemCertificateMTLS, pemPrivateKeyMTLS) if err != nil { return nil, fmt.Errorf("failed to load x509 key pair: %w", err) } httpClient := &http.Client{ Transport: &http.Transport{ TLSClientConfig: &tls.Config{ Certificates: []tls.Certificate{clientCertificate}, }, }, } return httpClient.Do(request) } ``` ```php [PHP] _csr_mtls.pem'; const MTLS_KEY_FILE = '_privatekey_mtls.pem'; function generateRequest(string $httpVerb, string $url, array $queryParams, string $jwtToken, string $scaProof, string $body): Request { if ($jwtToken === '') { throw new RuntimeException('missing JWT Token'); } $headers = [ 'X-Trz-SCA' => $scaProof, 'Authorization' => "Bearer $jwtToken", 'Content-Type' => 'application/json', ]; return new Request($httpVerb, $url . '?' . http_build_query($queryParams), $headers, $body); } /** * @throws \Psr\Http\Client\ClientExceptionInterface */ function sendUsingMTLS(Request $request) { $client = new Client([ GuzzleHttp\RequestOptions::CERT => [MTLS_CERT_FILE, ''], GuzzleHttp\RequestOptions::SSL_KEY => [MTLS_KEY_FILE, ''], ]); return $client->sendRequest($request); } ``` ::: ## PCI DSS Endpoints The PCI DSS endpoints are the ones for which you need to add the certificate. They can only be used for cards created or migrated to PCI DSS services, and replace their equivalent in the main [API Reference](/api-reference/api-endpoints). Please keep in mind that all your requests transit through the following URL: * **Sandbox** – `https://.preprod.secure.treezor.co` * **Production** – `https://.secure.treezor.co` | PCI DSS endpoint | Replaced endpoints | | --- | --- | | [`/cards`](/api-reference/pci-dss-dev.html#tag/Cards/createCard){target="\_self"} Create a Card. Use the `medium` field to create Virtual or Physical cards. | [Create Virtual Card](/api-reference/api-endpoints.html#tag/Cards/postCardVirtual){target="\_self"} [Create Physical Card](/api-reference/api-endpoints.html#tag/Cards/postCardPhysical){target="\_self"} | | [`/cards/{cardId}/tokenize`](/api-reference/pci-dss-dev.html#tag/Cards/cardTokenize){target="\_self"} Tokenize the card. | | | [`/cards/{cardId}/cardImage`](/api-reference/pci-dss-dev.html#tag/Cards/postCardImage){target="\_self"} Rebuild the card image when changing card design, company name, or when retrieving the image results in a 404. Not necessary when initially creating a Virtual Card. | [Regenerate Card](/api-reference/api-endpoints.html#tag/Cards/regenerateCard){target="\_self"} | | [`/cards/{cardId}/renew`](/api-reference/pci-dss-dev.html#tag/Cards/postRenew){target="\_self"} Renew the card manually. | [Renew Card](/api-reference/api-endpoints.html#tag/Cards/putRenew){target="\_self"} | | [`/cards/{cardId}/cardImage`](/api-reference/pci-dss-dev.html#tag/Cards/getCardImage){target="\_self"} Download the card encrypted image. Requires encryption, see [Display sensitive data](/guide/cards/sensitive-data) article. | [Retrieve Image](/api-reference/api-endpoints.html#tag/Cards/getCardImage){target="\_self"} | | [`/cards/{cardId}/pan`](/api-reference/pci-dss-dev.html#tag/Cards/getPAN){target="\_self"} Retrieve the card PAN & CVV. Use the `withCVV` field to get the encrypted CVV too. Requires encryption, see [Display sensitive data](/guide/cards/sensitive-data) article. | | | [`/cards/{cardId}/pin`](/api-reference/pci-dss-dev.html#tag/Cards/getPIN){target="\_self"} Retrieve the PIN code of the card. Requires encryption, see [Display sensitive data](/guide/cards/sensitive-data) article. | | | [`/cards/{cardId}/assignUser`](/api-reference/pci-dss-dev.html#tag/Cards/putAssignUser){target="\_self"} Assign the card to another user. | [Reassign Card](/api-reference/api-endpoints.html#tag/Cards/reassignCard){target="\_self"} (partial replacement) | | [`/cards/{cardId}/changePIN`](/api-reference/pci-dss-dev.html#tag/Cards/putChangePin){target="\_self"} Change the PIN code knowing the current one. | [Change PIN](/api-reference/api-endpoints.html#tag/Cards/changePin){target="\_self"} | | [`/cards/{cardId}/setPIN`](/api-reference/pci-dss-dev.html#tag/Cards/putSetPin){target="\_self"} Overwrite the PIN code. | [Set PIN](/api-reference/api-endpoints.html#tag/Cards/setPin){target="\_self"} | | [`/cards/{cardId}/inappcryptogram/mastercard/apple-pay`](/api-reference/pci-dss-dev.html#tag/Cards/postInappApple){target="\_self"} Generate an Apple Pay cryptogram for Mastercard digitization process. | [Request issuerInitiatedDigitizationData ](/api-reference/api-endpoints.html#tag/Digitized%20Cards/tavRequestPOST){target="\_self"} | | [`/cards/{cardId}/inappcryptogram/mastercard/google-pay`](/api-reference/pci-dss-dev.html#tag/Cards/postInappGpay){target="\_self"} Generate a Google Pay cryptogram for Mastercard digitization process. | [Request issuerInitiatedDigitizationData ](/api-reference/api-endpoints.html#tag/Digitized%20Cards/tavRequestPOST){target="\_self"} | | [`/cards/{cardId}/inappcryptogram/visa/apple-pay`](/api-reference/pci-dss-dev.html#tag/Cards/postVisaInappApple){target="\_self"} Generate an Apple Pay cryptogram for Visa digitization process. | | | [`/cards/{cardId}/inappcryptogram/visa/google-pay`](/api-reference/pci-dss-dev.html#tag/Cards/postVisaInappGpay){target="\_self"} Generate a Google Pay cryptogram for Visa digitization process. | | | [`/inappcryptogram/{credentials}`](/api-reference/pci-dss-dev.html#tag/Cards/getInapp){target="\_self"} Retrieve digitization cryptogram. | | | [`/users`](/api-reference/pci-dss-dev.html#tag/Users/postUsers){target="\_self"} Create a user. | [Create User](/api-reference/api-endpoints.html#tag/Users/postUsers){target="\_self"} | **API – API Reference available** For a complete list of attributes for these endpoints, check the [PCI DSS API Reference](/api-reference/pci-dss-dev). --- --- url: /guide/cards/renewal.md description: >- Technical guide for renewing soon-to-expire cards via the Treezor API. Includes required parameters, request structure, and response examples. --- # Renewal Renewing a Card consists of issuing a new card before the original one expires. This new card has the same attributes as their previous one. Card Renewal is tied to your [Card Program](/guide/cards/introduction#card-program) and the kind of product issued. Issuing services can be adjusted to optimize the costs and adapt the renewal experience (e.g., packaging). **Feature activation – Renewal is not activated by default** Please contact your *Treezor Account Manager* if you're interested in this feature. ## Renewed card specificities When a card is renewed, some attributes remain identical to the original one while others have new values. This ensures continuity of services (e.g., X-Pay and 3DS enrollments) and a smoother experience (identical PIN code) for cardholders. ### Inherited attributes * Card design * Limits and restrictions * [Card authentication methods](/guide/strong-customer-authentication/securing-endpoints#card-authentication-methods-enrollment) (OOB, SMS OTP) * X-Pay enrollments * PIN code * `cardTag` * Type of card (i.e., Virtual or Physical) ### New attributes * `cardId` * `PAN` * `expiryDate` * `publicToken` * `cvv` * The outstanding spending limits, which are reset (i.e., if €90/100 were spent on the previous Card, €100 will still be usable on the renewed one) **Information – Virtual Converted Cards are automatically produced** Renewing a virtual converted card results in a new virtual converted card. You don't need to go through the conversion process again. **Caution – PIN not automatically changed on both cards during Renewal** If the PIN code of the card being renewed changes during the renewal procedure, then the PIN code must also be changed manually for the renewed Card. ## Renewal process The renewal process follows these steps: 1. The card renewal process is triggered (manually or automatically) 2. The `card.renew` webhook is sent 3. The cardholder receives the new card (inactive) 4. The cardholder activates the new card 5. The original card `status` is set to `EXPIRED` **Tip – Get notified when a card is about to expire** The [`card.expiryAlert`](/guide/cards/events#card-expiryalert) webhook helps you anticipate the card expiration. ### Automatic renewal The automatic card renewal process is triggered at the beginning of each month. A request for renewal is sent to the card processor to renew all cards meeting the following conditions: * **Expire within the current month** – `expiryDate` in the current month minus 1 day. * **Are active** – `isLive` attribute is set to ` 1`. * **Are unlocked** – `cardStatus` value is `UNLOCK`. * **Are renewable** – Attached to a product code with the automatic renewal attribute, or the renewal type set to automatic (`“renewalType”: “A”`). Won’t be renewed cards which: * `renewalType` value is `N`. * Have already been renewed (i.e.,`renewalDate` value is other than `null`). ### Manual renewal In case you need to renew a card before its expiration month, you can trigger the card renewal manually. This is only possible for active cards that haven't been renewed yet, and whose status is `UNLOCK`. Use the following request with the `cardId` as a path parameter to renew a card manually. Endpoint: [`/v1/cards/{cardId}/renew`](/api-reference/api-endpoints.html#tag/Cards/putRenew){target="\_self"} ::: code-group ```bash [CURL] curl -X PUT '{baseUrl}/v1/cards/{cardId}/renew' \ --header 'Authorization: Bearer {accessToken}' ``` ::: If successful, the [`card.renew`](/guide/cards/events#card-renew) event is sent, and the Card object is returned: ::: code-group ```json [JSON] { "cards": [ { "cardId": 241709, "userId": 8290083, "walletId": 2464676, "walletCardtransactionId": 2473310, "mccRestrictionGroupId": 95447, "merchantRestrictionGroupId": 45599, "countryRestrictionGroupId": 165327, "publicToken": "107277882", "cardTag": "", "statusCode": "UNLOCK", "isLive": 0, "pinTryExceeds": 0, "maskedPan": "519872******4839", "embossedName": "ALEX OAK", "expiryDate": "2026-10-31", "CVV": "260", "startDate": "2023-10-23", "endDate": "0000-00-00", "countryCode": "FR", "currencyCode": "EUR", "lang": null, "deliveryTitle": "M", "deliveryLastname": "OAK", "deliveryFirstname": "ALEX", "deliveryAddress1": "15 EDGEWOOD ROAD", "deliveryAddress2": "", "deliveryAddress3": "", "deliveryCity": "ROSEWOOD", "deliveryPostcode": "12365", "deliveryCountry": "FR", "mobileSent": "+33633333333", "limitsGroup": "TRZ-VL-001", "permsGroup": "TRZ-CU-011", "cardDesign": "13664", "virtualConverted": 0, "physical": 0, "optionAtm": 0, "optionForeign": 0, "optionOnline": 1, "optionNfc": 1, "limitAtmYear": 0, "limitAtmMonth": 0, "limitAtmWeek": 0, "limitAtmDay": 1, "limitAtmAll": 1, "limitPaymentYear": 0, "limitPaymentMonth": 0, "limitPaymentWeek": 0, "limitPaymentDay": 25, "limitPaymentAll": 25, "paymentDailyLimit": 0.0, "totalAtmYear": null, "totalAtmMonth": null, "totalAtmWeek": null, "totalAtmDay": null, "totalAtmAll": null, "totalPaymentYear": null, "totalPaymentMonth": null, "totalPaymentWeek": null, "totalPaymentDay": null, "totalPaymentAll": null, "createdBy": 945198, "createdDate": "2023-10-31 10:37:04", "modifiedBy": 0, "modifiedDate": "0000-00-00 00:00:00", "renewalType": null, "renewalDate": "2024-04-01", "originalCardId": null, "totalRows": null, "designCode": null, "cardLanguages": "", "eventName": "Master Wallet", "eventAlias": "master-wallet-6537b83040735", "restrictionGroupLimits": null, "cancellationNumber": "", "metadata": null, "renewalDate": null, "renewalType": null, "originalCardId": null, "logoId": "", "logoBackId": "", "packageId": "", "customizeInfo": "", "letterCustomizedInfo": "", "freeCustomizedInfo": "", "deliveryMethod": null, "pinMailer": null, "batchDeliveryId": null, "sendToParent": 0 } ] } ``` ::: Endpoint: [`/cards/{cardId}/renew`](/api-reference/pci-dss-dev.html#tag/Cards/postRenew){target="\_self"} ::: code-group ```bash [CURL] curl -X PUT '{pciBaseUrl}/cards/{cardId}/renew' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "userId": "100642533", "pinRenewOption": 1 // To keep the previous PIN code } ``` ::: If successful, the [`card.renew`](/guide/cards/events#card-renew) event is sent, and the Card object is returned: ::: code-group ```json [JSON] { "cards": [ { "cardId": 241709, "userId": 8290083, "walletId": 2464676, "walletCardtransactionId": 2473310, "mccRestrictionGroupId": 95447, "merchantRestrictionGroupId": 45599, "countryRestrictionGroupId": 165327, "publicToken": "107277882", "cardTag": "", "statusCode": "UNLOCK", "isLive": 0, "pinTryExceeds": 0, "maskedPan": "519872******4839", "embossedName": "ALEX OAK", "expiryDate": "2026-10-31", "CVV": "260", "startDate": "2023-10-23", "endDate": "0000-00-00", "countryCode": "FR", "currencyCode": "EUR", "lang": null, "deliveryTitle": "M", "deliveryLastname": "OAK", "deliveryFirstname": "ALEX", "deliveryAddress1": "15 EDGEWOOD ROAD", "deliveryAddress2": "", "deliveryAddress3": "", "deliveryCity": "ROSEWOOD", "deliveryPostcode": "12365", "deliveryCountry": "FR", "mobileSent": "+33633333333", "limitsGroup": "TRZ-VL-001", "permsGroup": "TRZ-CU-011", "cardDesign": "13664", "virtualConverted": 0, "physical": 0, "optionAtm": 0, "optionForeign": 0, "optionOnline": 1, "optionNfc": 1, "limitAtmYear": 0, "limitAtmMonth": 0, "limitAtmWeek": 0, "limitAtmDay": 1, "limitAtmAll": 1, "limitPaymentYear": 0, "limitPaymentMonth": 0, "limitPaymentWeek": 0, "limitPaymentDay": 25, "limitPaymentAll": 25, "paymentDailyLimit": 0.0, "totalAtmYear": null, "totalAtmMonth": null, "totalAtmWeek": null, "totalAtmDay": null, "totalAtmAll": null, "totalPaymentYear": null, "totalPaymentMonth": null, "totalPaymentWeek": null, "totalPaymentDay": null, "totalPaymentAll": null, "createdBy": 945198, "createdDate": "2023-10-31 10:37:04", "modifiedBy": 0, "modifiedDate": "0000-00-00 00:00:00", "renewalType": null, "renewalDate": "2024-04-01", "originalCardId": null, "totalRows": null, "designCode": null, "cardLanguages": "", "eventName": "Master Wallet", "eventAlias": "master-wallet-6537b83040735", "restrictionGroupLimits": null, "cancellationNumber": "", "metadata": null, "renewalDate": null, "renewalType": null, "originalCardId": null, "logoId": "", "logoBackId": "", "packageId": "", "customizeInfo": "", "letterCustomizedInfo": "", "freeCustomizedInfo": "", "deliveryMethod": null, "pinMailer": null, "batchDeliveryId": null, "sendToParent": 0 } ] } ``` ::: #### Renewal failed responses The following HTTP 400 errors may occur when failing to renew a Card. | `errorCode` | `errorMessage` | | :---: | --- | | `34000` | The card must be already activated. |  | `34001` | The request is refused because the card has expired. |  | `34003` | The card must not be stolen or lost or destroyed. | ### Activation of a renewed card As a security measure, the new card is issued in an `inactive` state to ensure that a Card is not usable before the cardholder receives it. Once received, the card can be activated, and the previous card status will be automatically set as `EXPIRED`. Expired cards can no longer be used, and this status is permanent. ## Renewal Type (`renewalType`) When creating a Card, the card renewal type (automatic or not) is defined by your [Card Program](/guide/cards/introduction#card-program). If `renewalType` is set to `null` and the product is auto-renewing, the card will be renewed. The renewal type allows you to: * Set automatic renewal on a card-by-card basis if this is not set at product level. * Exclude a card from automatic renewal (for a user who closes their account, for example). A dedicated endpoint allows you to update the renewal type as needed: [`/v1/cards/{cardId}/renewalDetails`](/api-reference/api-endpoints.html#tag/Cards/updateRenewalDetails){target="\_self"}. **Note – Can’t update `renewalType` for cards expiring within the month** You may use the [`/v1/cards/{cardId}/renew`](/api-reference/api-endpoints.html#tag/Cards/putRenew){target="\_self"} request to renew the card manually. ### Parameters | Attribute | Type | Description | |--- |--- |--- | | `renewalType` | string | Define how the Card is to be renewed. Values can be the following: `A` – Automatic renewal. `N` – Non-automatic renewal. | Use the following request with the `cardId` as a path parameter to update the card renewal type. ::: code-group ```bash [CURL] curl -X PUT '{baseUrl}/v1/cards/{cardId}/renewalDetails' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: There is an example of `{payload}`: ::: code-group ```json [JSON] { "renewalType": "A" } ``` ::: Returns the Card Renewal Details object if successful: ::: code-group ```json [JSON] { "cardRenewalDetails": { "renewalType": "A" } } ``` ::: ## Endpoints | Endpoint |[Scope](/guide/api-basics/authentication#available-scopes) | | --- | --- | | [`/v1/cards/{cardId}/renewalDetails`](/api-reference/api-endpoints.html#tag/Cards/getRenewalDetails){target="\_self"}  Retrieve the card renewal options. | `admin`, `legal`, `read_write` | | [`/v1/cards/{cardId}/renewalDetails`](/api-reference/api-endpoints.html#tag/Cards/updateRenewalDetails){target="\_self"} Update the card renewal options. | `admin`, `legal`, `read_write` | | [`/v1/cards/{cardId}/renew`](/api-reference/api-endpoints.html#tag/Cards/putRenew){target="\_self"} Renew a Card manually. | `admin`, `legal`, `read_write` | --- --- url: /guide/cards/restrictions-limits.md description: >- Technical guide to define the card options, permissions, restrictions, and spending limits. Includes required parameters, request structure, and response examples. --- # Restrictions & Limits Following your [Card Program](/guide/cards/introduction#card-program) and your agreement with Treezor, you can configure the issued cards with options, restrictions, and limits to best suit your use case. ## Options & Permission groups Card options refer to how a given card can be used. They are preset at the Card Program level with the dedicated [`permsGroup`](#permission-groups-permsgroup) attribute. The following features are available to the cardholders if authorized at the Card Program level and activated in your Card object: You can customize each option on a card-by-card basis, as long as you keep in mind that: * You can’t bypass options blocked by your Card Program. * Updating the card options automatically updates the permission group value. ### Permission groups (`permsGroup`) Below is the list of permission group values along with the options they enable. | `permsGroup` | NFC | ATM | Online | Foreign | |- |:-: |:-: |:-: |:-: | | `TRZ-CU-001` | | | | | | `TRZ-CU-002` | | | | | | `TRZ-CU-003` | | | | | | `TRZ-CU-004` | | | | | | `TRZ-CU-005` | | | | | | `TRZ-CU-006` | | | | | | `TRZ-CU-007` | | | | | | `TRZ-CU-008` | | | | | | `TRZ-CU-009` | | | | | | `TRZ-CU-010` | | | | | | `TRZ-CU-011` | | | | | | `TRZ-CU-012` | | | | | | `TRZ-CU-013` | | | | | | `TRZ-CU-014` | | | | | | `TRZ-CU-015` | | | | | | `TRZ-CU-016` | | | | | ### Update card options Regardless of the card type (virtual or physical), all options must be specified. This aims to smoothly handle the conversion of the card to physical if need be. #### Parameters The following parameters are required (`1` for enabled, `0` for disabled). | Attribute | Type | Description | | --- | --- | --- | | `atm` | integer | Defines whether the card can be used for ATM withdrawals. | | `online` | integer | Defines whether the card can be used for online payments (this also applies to Mail Order, Telephone Order payments). | | `nfc` | integer | Defines whether the card can be used for contactless payments (NFC). | | `foreign` | integer | Defines whether the card can be used outside of the cardholder's country. | #### Request Use the following request to update the card options. ::: code-group ```bash [CURL] curl -X PUT '{baseUrl}/v1/cards/{cardId}/Options' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "atm":1, "online":1, "nfc":1, "foreign":0 } ``` ::: Returns the Card object, with the updated options and [`permsGroup`](#permission-groups-permsgroup): ::: code-group ```json [JSON] {8,12-15} { "cardId": integer, "userId": integer, "walletId": integer, "publicToken": "string", "statusCode": "string", "isLive": integer, "permsGroup": "TRZ-CU-015", "cardDesign": "string", "virtualConverted": integer, "physical": integer, "optionAtm": 1, "optionForeign": 0, "optionOnline": 1, "optionNfc": 1, // [...] some attributes are hidden } ``` ::: Treezor also sends a [`card.options`](/guide/cards/events#card-options) webhook. ## Payment & Withdrawal limits Card limits are configurable maximum payment and withdrawal amounts enforced by Treezor servers. They can therefore be updated at any time while abiding by your agreement with Treezor. ### Limit rules and functionalities Limits can be defined when creating the card, or later on using the dedicated endpoint. When creating a card, you must define at least one `limitPayment{period}` and one `limitAtm{period}`. Limits that you don't specify automaticaly default to the values set by your *Treezor Account Manager*. #### Payment limits | Attribute | Type | Description | | --- | --- | --- | | `limitPaymentAll` | integer | Lifetime payment limit | | `limitPaymentYear` | integer | Yearly payment limit | | `limitPaymentMonth` | integer | Monthly payment limit | | `limitPaymentWeek` | integer | Weekly payment limit | | `limitPaymentDay` | integer | Daily payment limit | #### Withdrawal limits | Attribute | Type | Description | | --- | --- | --- | | `limitAtmAll` | integer | Lifetime withdrawal limit | | `limitAtmYear` | integer | Yearly withdrawal limit | | `limitAtmMonth` | integer | Monthly withdrawal limit | | `limitAtmWeek` | integer | Weekly withdrawal limit | | `limitAtmDay` | integer | Daily withdrawal limit | **Limits are based on Paris timezone by default.** Meaning that daily limits may not be obvious to your end users if they live under a different timezone. **You can disable entirely a specific limit.** To do so, set its value to `0`, but at least one of the following values must be greater than `0`: `limitPaymentDay`, `paymentDailyLimit`, `limitPaymentWeek`, `limitPaymentMonth`. The same applies for ATM limits (one of `limitAtmMonth`, `limitAtmWeek` or `limitAtmDay` must be greater than `0`). **No consistency checks are made between each period limits.** The API allows you to define a higher daily than weekly limit, in which case, the lower of the two takes over. Consistency checks should be enforced by your application to avoid confusing end users. **Prefer the use of `limitPaymentDay`.** To set the daily payment limit, only one of the 2 following fields should be populated. | Attribute | Type | Usage | | --- | --- | --- | | `paymentDailyLimit` | number | The option dedicated to food vouchers use cases. This is the only limit based on the cardholder's timezone, which can be changed using the `timezone` attribute of the [User](/guide/users/introduction#key-attributes). | | `limitPaymentDay` | integer | The preferred option, applicable to all other use cases. | **Limits are sliding limits.** For example, to evaluate a monthly limit for a transaction made February 15th, Treezor considers all transactions from January 15th (excluded) until February 15th (included). ### Update limits To update the card limits, you can use the following request with the `cardId` as a path parameter. ::: code-group ```bash [CURL] curl -X PUT '{baseUrl}/v1/cards/{cardId}/Limits' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "limitPaymentAll":25, "limitPaymentYear":0, "limitPaymentMonth":0, "limitPaymentWeek":10, "limitPaymentDay":0, "limitAtmAll":0, "limitAtmYear":0, "limitAtmMonth":0, "limitAtmWeek":10, "limitAtmDay":0 } ``` ::: Returns the Card object with the updated limit attributes. ::: code-group ```json [JSON] {14-23} { "cardId": integer, "userId": integer, "walletId": integer, "publicToken": "string", "cardTag": "string", "statusCode": "UNLOCK", "isLive": 1, "pinTryExceeds": 0, "optionAtm": 1, "optionForeign": 0, "optionOnline": 1, "optionNfc": 1, "limitAtmYear": 0, "limitAtmMonth": 0, "limitAtmWeek": 10, "limitAtmDay": 0, "limitAtmAll": 0, "limitPaymentYear": 0, "limitPaymentMonth": 0, "limitPaymentWeek": 10, "limitPaymentDay": 0, "limitPaymentAll": 25, // [...] some attributes are hidden } ``` ::: Treezor also sends a [`card.limits`](/guide/cards/events#card-limits) webhook. ### Update limits in bulk You may need to update the limits of all your cards at once, as part of a change in daily spendable amount, for instance. Treezor offers dedicated endpoints to update cards in bulk, hence optimizing your processes and offering better performance. **Information – You can update up to 100,000 cards at once** The Card Bulk Updates feature processes in average 6,000 cards per minute. #### Parameters Below are the necessary parameters to update card limits in bulk. | Attribute | Type | Description | | --- | --- | --- | | `cardIds` | array | The list of cards to update. Each card is an integer, and the API accepts up to 100,000 cards. | | `bulkUpdateTag` | string | Custom attribute for you to use as you see fit. Can be used to name your bulk update, for instance. | | `cardAttributes` | object |The limits you can set, according to the rules below. | **API – API Reference available** For a complete list of attributes, check the [Card Bulk Updates](/api-reference/api-endpoints.html#tag/Card%20Bulk%20Updates){target="\_self"} section of the API Reference. #### Request example Use the following request to create a bulk order. ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/v1/bulk-updates/cardLimits' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' ``` ::: Here is an example of `{payload}` for updating limits: ::: code-group ```json [JSON] { "cardIds": [12345,23456,34567], "bulkUpdateTag": "New contract limits May 2025", "cardAttributes": { "limitAtmYear": 0, "limitAtmMonth": 2000, "limitAtmWeek": 150, "limitAtmDay": 0, "limitPaymentYear": 2000, "limitPaymentMonth": 150, "limitPaymentWeek": 0, "limitPaymentDay": 0 } } ``` ::: Treezor returns the Bulk Update object, which is `IN_PROGRESS`. ::: code-group ```json [JSON] {8} { "bulkUpdateTag":"New contract limits May 2025", "successfulUpdates":null, "failedUpdates":null, "createdDate":"2025-04-29 08:54:49", "modifiedDate":"2025-04-29 08:54:49", "bulkUpdateId":"a10bbf05-134b-4868-929d-78b12fcaa513", "bulkUpdateProgressStatus":"IN_PROGRESS", "bulkUpdateType":"CARD_LIMITS", "cardAttributes":{ "limitAtmYear":0, "limitAtmMonth":2000, "limitAtmWeek":150, "limitAtmDay":0, "limitAtmAll":null, "limitPaymentYear":2000, "limitPaymentMonth":150, "limitPaymentWeek":0, "limitPaymentDay":0, "limitPaymentAll":null, "paymentDailyLimit":null, "restrictionGroupLimits":null }, "totalObjects":3 } ``` ::: Treezor also sends you the following webhooks: * [`cardBulkUpdate.create`](./events#cardbulkupdate-create) – The bulk update is created and in progress. * [`cardBulkUpdate.create`](./events#cardbulkupdate-create) – The bulk update processing is complete. This may take up to 20 minutes. #### Manage bulk updates Once you’ve initiated your bulk update, you can follow up on it using the following request. ::: code-group ```bash [CURL] curl -X GET '{baseUrl}/v1/bulk-updates/{bulkUpdateId}' \ --header 'Authorization: Bearer {accessToken}' ``` ::: Treezor returns the Bulk Update object, in which you can check `bulkUpdateProgressStatus`, and the details of the `successfulUpdates` and `failedUpdates`. ::: code-group ```json [JSON] {3,10,22} { "bulkUpdateTag":"New contract limits May 2025", "successfulUpdates":{ "cardIds":[ 12345, 23456 ], "count":2 }, "failedUpdates":{ "cards":[ { "reason":"NOT_FOUND", "id":12345 } ], "count":1 }, "createdDate":"2025-04-29 09:00:45", "modifiedDate":"2025-04-29 09:00:48", "bulkUpdateId":"a10bbf05-134b-4868-929d-78b12fcaa513", "bulkUpdateProgressStatus":"DONE", "bulkUpdateType":"CARD_LIMITS", "cardAttributes":{ "limitAtmYear":0, "limitAtmMonth":2000, "limitAtmWeek":150, "limitAtmDay":0, "limitAtmAll":null, "limitPaymentYear":2000, "limitPaymentMonth":150, "limitPaymentWeek":0, "limitPaymentDay":0, "limitPaymentAll":null, "paymentDailyLimit":null, "restrictionGroupLimits":[ ] }, "totalObjects":3 } ``` ::: You may also use the [`/v1/bulk-updates`](/api-reference/api-endpoints.html#tag/Card%20Bulk%20Updates/listBulkCardUpdates){target="\_self"} to list all the card bulk updates. ### Check total spent amounts Specific attributes indicate the total amount spent periodically for ATM and card payments. When Treezor creates a [Card Transaction](./transactions) object, these total amount spent values are updated if relevant. You can also find them in the [`cardtransaction.create`](events-tx#cardtransactions) webhook. | Total amount spent | Description | Corresponding limit | |-------------------------|-------------------| -------------------| | `totalLimitAtmYear` | The card yearly withdrawal amount. | `limitAtmYear` | | `totalLimitAtmMonth` | The card monthly withdrawal amount. | `limitAtmMonth` | | `totalLimitAtmWeek` | The card weekly withdrawal amount. | `limitAtmWeek` | | `totalLimitAtmDay` | The card daily withdrawal amount. | `limitAtmDay` | | `totalLimitAtmAll` | The card total withdrawal amount. | `limitAtmAll` | | `totalLimitPaymentYear` | The card yearly spent amount. | `limitPaymentYear` | | `totalLimitPaymentMonth` | The card monthly spent amount. | `limitPaymentMonth` | | `totalLimitPaymentWeek` | The card weekly spent amount. | `limitPaymentWeek` | | `totalLimitPaymentDay` | The card dayly spent amount. | `limitPaymentDay` | | `totalLimitPaymentAll` | The card total spent amount. | `limitPaymentAll` | With this comparison, you can let your users know how much they have left to spend, anticipating any refused transactions due to reached limits. Please note the total attributes are populated differently depending on the context (e.g., Card or Card Transaction, [`paymentStatus`](/guide/cards/transactions#statuses-paymentstatus)), and only when necessary for performance optimization. #### Card Transactions total spent amount In the Card Transaction object, the total attributes are `null` when: * The [`paymentStatus`](/guide/cards/transactions#statuses-paymentstatus) is other than `A` (Authorized) or `I` (Declined). Authorizations declined by the Card Processor (see [authorization notes](/guide/cards/authorization-notes)) or due to card usage issue (e.g., permissions, status) also result in `null` totals. * No corresponding limit is given (e.g., if `limitAtmDay` is `0`, then `totalLimitAtmDay` is `null`) * The limit is a higher or equal to a limit of a higher periodicity (e.g., if `limitPaymentWeek` ≥ `limitPaymentMonth`, then `totalPaymentWeek` is `null`). #### Cards total spent amount The total limits are available in the Card object but are only valued when retrieving an individual Card with the [`/v1/cards/{cardId}`](/api-reference/api-endpoints.html#tag/Cards/getCard){target="\_self"} request. Contrary to card transactions, all the total limit fields are populated as long as they have a corresponding limit. When searching for a list of cards, all the total limits are set to `null`. ::: details Card object total spent amount Please note the name of the fields differ in the Card object compared to the Card transaction object. | Total amount spent | Description | Corresponding limit | |-------------------------|-------------------| -------------------| | `totalAtmYear` | The card yearly withdrawal amount. | `limitAtmYear` | | `totalAtmMonth` | The card monthly withdrawal amount. | `limitAtmMonth` | | `totalAtmWeek` | The card weekly withdrawal amount. | `limitAtmWeek` | | `totalAtmDay` | The card daily withdrawal amount. | `limitAtmDay` | | `totalAtmAll` | The card total withdrawal amount. | `limitAtmAll` | | `totalPaymentYear` | The card yearly spent amount. | `limitPaymentYear` | | `totalPaymentMonth` | The card monthly spent amount. | `limitPaymentMonth` | | `totalPaymentWeek` | The card weekly spent amount. | `limitPaymentWeek` | | `totalPaymentDay` | The card dayly spent amount. | `limitPaymentDay` | | `totalPaymentAll` | The card total spent amount. | `limitPaymentAll` | ::: ## MCC restrictions [Merchant Category Codes (MCC)](/guide/overview/glossary#merchant-category-code-mcc) restrictions are list-based restrictions allowing you to limit the usage of the card to specific categories of merchants. ### Parameters ### Request To create MCC restrictions, you can use the following request: ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/v1/mccRestrictionGroups' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "name": "Restriction Restaurant, Bar, Fast-Food", "isWhitelist": true, "mcc": [ 5812, 5813, 5814 ], "startDate": "2024-05-01 00:00:00" } ``` ::: Returns the Merchant ID Restriction Group object with its `id` (that you should keep on your side to apply these restrictions to Cards). ::: code-group ```json [JSON] { "mccRestrictionGroups": [ { "id": 47597, "name": "Restriction Restaurant, Bar, Fast-Food", "isWhitelist": true, "mcc": [ 5812, 5813, 5814 ], "status": "PENDING", "startDate": "2024-05-01 00:00:00", "createdDate": "2024-04-24 09:04:38", "modifiedDate": null } ] } ``` ::: Treezor also sends a [`mccGroup.create`](/guide/cards/events#mccgroup-create) webhook. ### Apply the restriction To apply the restriction to a card, set the `mccRestrictionGroupId` value to the previously obtained `id` when creating or updating the card: * [`/v1/cards/CreateVirtual`](/api-reference/api-endpoints.html#tag/Cards/postCardVirtual){target="\_self"} * [`/v1/cards/RequestPhysical`](/api-reference/api-endpoints.html#tag/Cards/postCardPhysical){target="\_self"} * [`/v1/cards/{cardId}`](/api-reference/api-endpoints.html#tag/Cards/putCard){target="\_self"} ## Country restrictions You may restrict a Card use in some countries only. ### Parameters **Caution – Use the ISO 3166-1 numeric format** Contrary to other endpoints, here countries are expected in [**ISO 3166-1 numeric format** (a 3-digit code)](https://en.wikipedia.org/wiki/ISO_3166-1_numeric). ### Request To create country restrictions, you can use the following request: ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/v1/countryRestrictionGroups' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "name": "Restriction Belgium, Germany, France", "isWhitelist": true, "countries": [ "250", "276", "056" ], "startDate": "2024-05-01 00:00:00" } ``` ::: Returns the Country Restriction Group object with its `id` (that you should keep on your side to apply these restrictions to Cards). ::: code-group ```json [JSON] { "countryRestrictionGroups": [ { "id": 179655, "name": "Restriction Belgium, Germany, France", "isWhitelist": true, "countries": [ "250", "276", "056" ], "status": "PENDING", "startDate": "2024-05-01 00:00:00", "createdDate": "2024-04-24 08:55:26", "modifiedDate": null } ] } ``` ::: Treezor also sends a [`countryGroup.create`](/guide/cards/events#countrygroup-create) webhook. ### Apply the restriction To apply the restriction to a card, set the `countryRestrictionGroupId` value to the previously obtained `id` when creating or updating the card: * [`/v1/cards/CreateVirtual`](/api-reference/api-endpoints.html#tag/Cards/postCardVirtual){target="\_self"} * [`/v1/cards/RequestPhysical`](/api-reference/api-endpoints.html#tag/Cards/postCardPhysical){target="\_self"} * [`/v1/cards/{cardId}`](/api-reference/api-endpoints.html#tag/Cards/putCard){target="\_self"} ## MID restrictions [Merchant Id (MID)](/guide/overview/glossary#merchant-identification-number-mid) restrictions are list-based restrictions allowing you to limit the usage of the card to specific merchants. You can restrict MID in one of two ways: * **Allowing only** a specified list of merchants (whitelist) * **Allowing all merchants except** a specified list (blacklist) If you plan on creating more than 20 MID restriction lists, please contact Treezor. ### Parameters ### Request To create MID restrictions, you can use the following request: ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/v1/merchantIdRestrictionGroups' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "name": "Restriction merchantId 2024", "isWhitelist": true, "merchants": [ "44355534500019", "ZWORT8KLOW9", "8935467" ], "startDate": "2024-05-01 00:00:00" } ``` ::: Returns the `merchantIdRestrictionGroups` object with its `id` (that you should keep on your side to apply these restrictions to Cards). ::: code-group ```json [JSON] { "merchantIdRestrictionGroups": [ { "id": 104734, "name": "Restriction merchantId 2024", "isWhitelist": true, "status": "PENDING", "startDate": "2024-05-01 00:00:00", "createdDate": "2024-04-24 09:09:59", "modifiedDate": null } ] } ``` ::: Treezor also sends a [`merchantIdGroup.create`](/guide/cards/events#merchantidgroup-create) webhook. **Alert – Chain stores don't have a unique MID** Note that each shop of a chain store has its own `merchantId`, in such a situation you may want to use [MCC](/guide/overview/glossary) instead (which could block more than expected) or explicitly list all the relevant `merchantId`. Treezor offers the [MID Metadata endpoint](/guide/cards/restrictions-limits#mid-metadata) to help you associate metadata to MIDs. ### Apply the restriction To apply the restriction to a card, set the `merchantRestrictionGroupId` value to the previously obtained `id` when creating or updating the card: * [`/v1/cards/CreateVirtual`](/api-reference/api-endpoints.html#tag/Cards/postCardVirtual){target="\_self"} * [`/v1/cards/RequestPhysical`](/api-reference/api-endpoints.html#tag/Cards/postCardPhysical){target="\_self"} * [`/v1/cards/{cardId}`](/api-reference/api-endpoints.html#tag/Cards/putCard){target="\_self"} ## MID Metadata In some cases, the [Merchant Id (MID)](/guide/overview/glossary#merchant-identification-number-mid) may not be up-to-date or the given information not enough for you to act on it. Treezor offers endpoints to add metadata to MIDs, hence allowing you to add human-readable information as you see fit. ### Add metadata to a MID To add metadata to a MID, you may use the following request by populating the metadata freely in the body (except for the `mid` attribute which is reserved). ::: code-group ```bash [CURL] curl -X PUT '{baseUrl}/core-connect/mid/{mid}/metadata' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}`. ::: code-group ```json [JSON] { "contact": "100@example.com", "address": "1208, Willow lane, 75000 Paris" } ``` ::: Returns the object you've created with a 201 Created HTTP Status code. ::: code-group ```json [JSON] { "contact": "100@example.com", "address": "1208, Willow lane, 75000 Paris" } ``` ::: You can then retrieve this information by using the following request: * [`/core-connect/mid/{mid}/metadata`](/api-reference/api-endpoints.html#tag/Merchant%20ID%20Metadata/getMidMetadata){target="\_self"} ### Manage metadata in bulk You can use the following request to either add or update metadata in bulk. ::: code-group ```bash [CURL] curl -X PUT '{baseUrl}/core-connect/mid/metadata' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}`. ::: code-group ```json [JSON] [ { "mid": "100", "contact": "100@example.com", "address": "1208, Willow lane, 75000 Paris", "siret": "348674XXXX067" }, { "mid": "200", "contact": "200@example.com", "address": "1208, Ashwood street, Madrid" }, { "mid": "300", "contact": "300@example.com", "address": "1208, Rosewood road, London" } ] ``` ::: Returns a `204` HTTP Status Code without any content. ### Retrieve all MID metadata You may use the following request to retrieve all the MID metadata you populated. ::: code-group ```bash [CURL] curl -X GET '{baseUrl}/core-connect/mid/metadata' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' ``` ::: Returns all the MID metadata object you've created. ::: code-group ```json [JSON] [ { "mid": "100", "contact": "100@example.com", "address": "1208, Willow lane, 75000 Paris", "siret": "348674XXXX067" }, { "mid": "200", "contact": "200@example.com", "address": "1208, Ashwood street, Madrid" }, { "mid": "300", "contact": "300@example.com", "address": "1208, Rosewood road, London" } ] ``` ::: You can also retrieve the metadata for all MIDs belonging to a previously created [MID Restriction Group](#mid-restrictions) using the following request: * [`/core-connect/merchantIdRestrictionGroups/{groupId}/mid/metadata`](/api-reference/api-endpoints.html#tag/Merchant%20ID%20Metadata/getAllMidMetadataBYyGroup){target="\_self"} This request returns the list of MIDs along with their metadata. The list a paginated using a [cursor](/guide/api-basics/pagination#cursor-based-pagination). ## Group limits Group limits (or multi-loop) offers more freedom configuring limits and restrictions in some advanced cases. **Information – Treezor offers its own [Transaction Rules Engine](/guide/cards/transactions-rules-engine)** Historically, group limits were designed for food vouchers use cases. Treezor [Transactions Rules Engine](./transactions-rules-engine) offers an even better way to handle such cases, allowing you to define contextual rulesets, evaluated at each transaction. Contact Treezor to find out which option works best for you. You can create groups of limits and restrictions upon creating of updating a [Card](/guide/cards/introduction) using the `restrictionGroupLimits` attribute. This array allows you to create an object for each group of limits, and each object can contain: * `paymentDailyLimit` – For [payment limits](#payments-withdrawals-limits) * `mccRestrictionGroups` – For [MCC restrictions](#mcc-restrictions) * `countryRestrictionGroups` – For [countries restrictions](#country-based-restrictions) * `merchantIdRestrictionGroups` – For [MID restrictions](#list-based-restrictions) In doing so, you may have a GroupLimit covering restaurants with its own daily payment limit, and a second GroupLimit covering fresh food stores with a different daily payment limit. Your [Cards](/guide/cards/introduction) could therefore be used in both restaurant and fresh food store, but with distinct payment limits for each situation. --- --- url: /guide/cards/sensitive-data.md description: >- Learn the end-to-end encryption best practices to expose the card sensitive data such as PAN, CVV, and PIN in the context of the PCI DSS integration. Includes code examples for private key generation and encryption. --- # Displaying sensitive data [PCI DSS](/guide/cards/pci-dss) allows for an enhanced experience for the cardholders. You can display sensitive information as an image or a text, and instantly copy it. This applies to the card PIN, number (PAN), and verification code (CVV). You must use asymmetrical **end-to-end encryption** when it comes to exposing the following card data. | Sensitive data | Endpoint | | --- | --- | | **Card Image** | [`/cards/{cardId}/cardImage`](/api-reference/pci-dss-dev.html#tag/Cards/getCardImage){target="\_self"} | | **PAN & CVV** | [`/cards/{cardId}/pan`](/api-reference/pci-dss-dev.html#tag/Cards/getPAN){target="\_self"} | | **PIN** | [`/cards/{cardId}/pin`](/api-reference/pci-dss-dev.html#tag/Cards/getPIN){target="\_self"} | **API – API Reference available** For a complete list of attributes for these endpoints, check the [PCI DSS API Reference](/api-reference/pci-dss-dev). This article focuses on the [`/cards/{cardId}/pan`](/api-reference/pci-dss-dev.html#tag/Cards/getPAN){target="\_self"} for the examples, but the same process applies for all endpoints containing sensitive data. ## Process Here are the steps for exposing sensitive data. ```mermaid sequenceDiagram participant user as Cardholder's device participant agent as Your back end participant trz as Treezor autonumber user->>user: Generates asymmetrical key pair
(public & private keys) user->>agent: Sends public key rect rgba(234, 236, 238, 0.5) agent->>trz: Makes PCI DSS request Note over agent,trz: with public key end trz->>agent: Returns base64-encrypted data agent->>user: Returns base64-encrypted data user->>user: Base64-decodes & decrypts data with private key
and exposes it to the cardholder user->>user: Destroys decrypted data and asymmetrical
key pair once consulted by cardholder ``` ## 1. Generate an asymmetrical key pair on the end user’s device Asymmetrical encryption consists of using a key pair, with each key fulfilling its specific role: * **Public key** – Used to encrypt data * **Private key** – Used to decrypt data, and can’t be shared **Security – Generate at least 1 key pair by user** Key pairs must be unique for each of your end users. For optimal security, you should rely on single-use key pairs (i.e., generate a key pair for each request). Treezor PCI DSS-specific endpoints support 2 encryption methods: `OPENPGP_ARMOR` or `LIBSODIUM_HEX`. ### Example for OpenPGP **Best practice – Formatting your keys with OpenPGP** * **Type**: RSA * **Size**: min. 2048, recommended 4096 Find below an extract of the [functional code](#example-for-openpgp-2) available at the end of the article. ::: code-group ```js [JavaScript] /* import openpgp v5.11.2. You can find it here https://github.com/openpgpjs/openpgpjs/blob/main/README.md#getting-started */ function PgpStrategy() { this.privateKey = '' this.publicKey = '' this.passphrase = '' this.option = { userIDs: [{ name: "your_company_name", email: "your_company_email@email.com" }], // TODO replace name and email by yours. type:'rsa', rsaBits: "4096", passphrase: this.passphrase, } ... return { generateKeyPair: async () => { const keyPair = await openpgp.generateKey(this.option) this.privateKey = keyPair.privateKey this.publicKey =keyPair.publicKey return this.publicKey }, ... } }; ``` ::: ### Example for Libsodium Find below an extract of the [functional code](#example-for-libsodium-2) available at the end of the article. ::: code-group ```js [JavaScript] /* import libsodium-wrappers v0.5.4. You can find it here https://www.npmjs.com/package/libsodium-wrappers?activeTab=readme */ function LibsodiumStrategy () { this.privateKey = '' this.publicKey = '' return { ... generateKeyPair: async () => { await sodium.ready const keyPair = await sodium.crypto_box_keypair() this.privateKey = sodium.to_hex(keyPair.privateKey) this.publicKey = sodium.to_hex(keyPair.publicKey) return this.publicKey }, ... } } ``` ::: Now that the key pair has been generated on the end user's device, you can send the public key on your servers to then pass it along to Treezor in the next step. **However, it is strictly forbidden to share the private key, only the cardholder's device can access it.** ## 2. Make your Treezor request with the cardholder's public key Make your Treezor request with the cardholder's public key from your server using the [mTLS](/guide/api-basics/mutual-tls) mechanism described in the [PCI DSS integration](/guide/cards/pci-dss) article. The following parameters must be used for Treezor sensitive endpoints: * `algorithm` – The encryption method used (`OPENPGP_ARMOR` or `LIBSODIUM_HEX`) * `userPublicKeyBase64` – The previously generated encrypted user public key (base64-encoded). Here is an example when retrieving the card PAN and CVV ([`/cards/{cardId}/pan`](/api-reference/pci-dss-dev.html#tag/Cards/getPAN){target="\_self"} ). ::: code-group ```go [Golang] package main import ( "encoding/base64" "encoding/json" "fmt" "io" "log" "net/http" ) type getEncryptedCardDataResponse struct { EncryptedCardData string `json:"encryptedCardData,omitempty"` } // GetPAN sends a PCI request to retrieve the PAN. func GetPAN() { request, err := GenerateRequest( http.MethodGet, "https://client.preprod.secure.treezor.co/cards/1234/pan", map[string]string{ "algorithm": "OPENPGP_ARMOR", "userId": "5678", "withCVV": "true", "userPublicKey": base64.StdEncoding.EncodeToString([]byte("cardholder's OpenPGP public key value")), "sca": "sca-proof-value", }, "jwtToken", "scaProof", nil, ) if err != nil { log.Fatalf("failed to generate request: %s", err) } response, err := SendUsingMTLS(request) if err != nil { log.Fatalf("failed to send request: %s", err) } if response.StatusCode != http.StatusOK { body, _ := io.ReadAll(response.Body) log.Fatalf("unexpected status code: %d with body: %s", response.StatusCode, string(body)) } getCardDataResponse := &getEncryptedCardDataResponse{} err = json.NewDecoder(response.Body).Decode(&getCardDataResponse) if err != nil { log.Fatalf("failed to read get encrypted card data response: %s", err) } // Base64 encrypted content fmt.Println(getCardDataResponse.EncryptedCardData) } ``` ```php [PHP] 'OPENPGP_ARMOR', 'userId' => '8364813', 'withCVV' => true, 'userPublicKey' => base64_encode(file_get_contents(PGP_FILE)), 'sca' => $scaProof, ]; try { $request = generateRequest( 'GET', 'https://.preprod.secure.treezor.co/cards/1234/pan', $queryParams, $jwtToken, $scaProof, '' ); } catch (RuntimeException $exception) { $logger->error(sprintf('Failed to generate request %s', $exception->getMessage())); return; } try { $response = sendUsingMTLS($request); } catch (ClientExceptionInterface $exception) { $logger->error(sprintf('Failed to send request %s', $exception->getMessage())); return; } if ($response->getStatusCode() !== 200) { throw new RuntimeException(sprintf('Unexpected status code: %d with body: %s', $response->getStatusCode(), $response->getBody()->getContents())); } $cardDataResponse = json_decode($response->getBody()->getContents(), true); if (!$cardDataResponse) { $logger->error('Failed to read get encrypted card data response'); } // Base64 encrypted content echo $cardDataResponse; } ``` ::: The Treezor returns the base64-encrypted data. For example, the response for the [`/cards/{cardId}/pan`](/api-reference/pci-dss-dev.html#tag/Cards/getPAN){target="\_self"} request. ::: code-group ```json [JSON] { "encryptedCardData": "" } ``` ::: The encrypted data must be sent to the end user's device for the decryption step. ## 3. Use the private key on the end users' device for decryption Once the cardholder's device retrieved the encrypted data, it can use the private key for decryption. ### Example for OpenPGP Find below an extract of the [functional code](#example-for-openpgp-2) available at the end of the article. ::: code-group ```js [JavaScript] /* import openpgp v5.11.2. You can find it here https://github.com/openpgpjs/openpgpjs/blob/main/README.md#getting-started */ function PgpStrategy() { this.privateKey = '' this.publicKey = '' this.passphrase = '' return { decrypt: async (cypherText) => { const privKey = await openpgp.decryptKey({ privateKey: await openpgp.readPrivateKey({ armoredKey: this.privateKey }), passphrase: this.passphrase }); return await openpgp.decrypt({ message: await openpgp.readMessage({armoredMessage:cypherText}), decryptionKeys: privKey }); }, ... } }; ``` ::: ### Example for Libsodium Find below an extract of the [functional code](#example-for-libsodium-2) available at the end of the article. ::: code-group ```js [JavaScript] /* import libsodium-wrappers v0.5.4. You can find it here https://www.npmjs.com/package/libsodium-wrappers?activeTab=readme */ function LibsodiumStrategy () { this.privateKey = '' this.publicKey = '' return { decrypt: async (hexCypherText) => { let outputFormat = 'text'; return await sodium.crypto_box_seal_open( sodium.from_hex(hexCypherText), sodium.from_hex(this.publicKey), sodium.from_hex(this.privateKey), outputFormat ) }, ... } } ``` ::: ### Decrypted data example Once decrypted, here is the payload you should have for the [`/cards/{cardId}/pan`](/api-reference/pci-dss-dev.html#tag/Cards/getPAN){target="\_self"} request, whether you chose to include the CVV or not. ::: code-group ```json [JSON (PAN & CVV)] { "pan": "1234567898765432", "cvv": "123" } ``` ```json [JSON (PAN only)] { "pan": "1234567898765432" } ``` ::: **Security – Destroy sensitive data once viewed by the cardholder** You must destroy both the decrypted data and the asymmetrical key pair after usage. If the user wishes to view their card information again, you must redo the whole process. ## Full examples ### Example for OpenPGP **Best practice – Formatting your keys with OpenPGP** * **Type**: RSA * **Size**: min. 2048, recommended 4096 ::: code-group ```js [JavaScript] /* import openpgp v5.11.2. You can find it here https://github.com/openpgpjs/openpgpjs/blob/main/README.md#getting-started */ function PgpStrategy() { this.algoName = 'OPENPGP_ARMOR' this.privateKey = '' this.publicKey = '' const generateRandomPassphrase = length => { const charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+{}[]|;:<>,.?/~"; let passphrase = ""; for (let i = 0; i < length; i++) { const randomIndex = Math.floor(Math.random() * charset.length); passphrase += charset[randomIndex]; } return passphrase; } this.passphrase = generateRandomPassphrase(16) this.option = { userIDs: [{ name: "cardholder", email: "cardholder_email@example.com" }], // TODO replace name and email by yours. type:'rsa', rsaBits: "4096", passphrase: this.passphrase, } return { getAlgoName: () => { return this.algoName }, generateKeyPair: async () => { const keyPair = await openpgp.generateKey(this.option) this.privateKey = keyPair.privateKey this.publicKey =keyPair.publicKey return this.publicKey }, // TODO remove encrypt function. needed only to simulate PCI-DSS encryption in this code snippet. encrypt: async (textToEncrypt) => { const pubKey = await openpgp.readKey({ armoredKey: this.publicKey}) return btoa(await openpgp.encrypt({ message: await openpgp.createMessage({ text: textToEncrypt}), encryptionKeys: pubKey })) }, decrypt: async (cypherText) => { const privKey = await openpgp.decryptKey({ privateKey: await openpgp.readPrivateKey({ armoredKey: this.privateKey }), passphrase: this.passphrase }); return await openpgp.decrypt({ message: await openpgp.readMessage({armoredMessage:cypherText}), decryptionKeys: privKey }); }, removeKeyPair: () => { this.privateKey = '' this.publicKey = '' this.passphrase = '' } } }; // displaySensitiveData function on cardholder application. async function displaySensitiveData(){ let pgp= new PgpStrategy() pgp.generateKeyPair().then((pubKey)=>{ // TODO replace the pgp.encrypt call below by the call to your back end with needed data, for example: // call(cardId, userId, pgp.getAlgoName(), pubKey,...).then(base64EncodedEncryptedData => {... pgp.encrypt('1234').then(base64EncodedEncryptedData => { // keep code below pgp.decrypt(atob(base64EncodedEncryptedData)) .then(decrypted =>{console.log('decrypted:'+decrypted.data)}) .catch(err=> {console.log(err)}) .finally(function(){ pgp.removeKeyPair(); }); }).catch(err => {console.log(err)}); }).catch(err=> {console.log(err)}) } displaySensitiveData() ``` ::: ### Example for Libsodium ::: code-group ```js [JavaScript] /* import libsodium-wrappers v0.5.4. You can find it here https://www.npmjs.com/package/libsodium-wrappers?activeTab=readme */ function LibsodiumStrategy () { this.algoName = 'LIBSODIUM_HEX' this.privateKey = '' this.publicKey = '' return { getAlgoName: () => { return this.algoName }, generateKeyPair: async () => { await sodium.ready const keyPair = await sodium.crypto_box_keypair() this.privateKey = sodium.to_hex(keyPair.privateKey) this.publicKey = sodium.to_hex(keyPair.publicKey) return this.publicKey }, decrypt: async (hexCypherText) => { let outputFormat = 'text'; return await sodium.crypto_box_seal_open( sodium.from_hex(hexCypherText), sodium.from_hex(this.publicKey), sodium.from_hex(this.privateKey), outputFormat ) }, // TODO remove encrypt function. needed only to simulate PCI-DSS encryption in this code snippet. encrypt: (plainText) => { const cypherText = sodium.crypto_box_seal( plainText, sodium.from_hex(this.publicKey) ) return btoa(sodium.to_hex(cypherText)); }, removeKeyPair: () => { this.privateKey = '' this.publicKey = '' } } } // displaySensitiveData function on cardholder application. async function displaySensitiveData(){ const libso= new LibsodiumStrategy() libso.generateKeyPair().then((pubKey) =>{ // TODO replace the libso.encrypt call below by the call to your back end with needed data, for example: // call(cardId, userId, libso.getAlgoName(), pubKey,...).then(base64EncodedEncryptedData => {... const base64EncodedEncryptedData = libso.encrypt('1234') // keep code below libso.decrypt(atob(base64EncodedEncryptedData)) .then(decrypted =>{console.log('decrypted:'+decrypted)}) .catch(err=> {console.log(err)}) .finally(function(){ libso.removeKeyPair(); }); }).catch(err=> {console.log(err)}) } displaySensitiveData() ``` ::: --- --- url: /guide/cards/transactions-lifecycle.md description: >- Explore all the steps of the card transaction life cycle, with the relevant statuses. --- # Transactions life cycle You will find below details about each possible step, why they occur, and how to use them. Most steps send a [`cardtransaction.create`](/guide/cards/events) webhook. If they are generated by the same payment, then they will share the same `paymentId` value. ## Authorization Authorization is the first step of a card payment. An authorization allows the [merchant](/guide/overview/glossary#merchant) to request the approval of the issuer for a transaction. When a cardholder pays or makes a withdrawal with their card, an authorization request is sent to Treezor, allowing the cardholder's spending limits and restrictions to be enforced. A yes/no decision ([accepted](#authorization-accepted)/[declined](#authorization-declined)) is then provided to the acquirer and merchant/[ATM](/guide/overview/glossary#automated-teller-machine-atm). ### Authorization accepted This immediately deduces the amount from the [Authorized Balance](/guide/overview/glossary#balance) of the cardholder but leaves the [Balance](/guide/overview/glossary#balance) unchanged. When an authorization is accepted, a card transaction is created, with one of the following [payment status](/guide/cards/transactions#statuses-paymentstatus). | [`paymentStatus`](/guide/cards/transactions#statuses-paymentstatus) | Event | Description | | --- | --- | --- | | `A` (Accepted) | `cardTransaction.create` | When the transaction is authorized normally. | | `C` (Cleared) | `cardTransaction.create` | When the authorization occurred offline. | **Information – Offline transactions are processed asynchronously** You're notified only once the merchant's clearing is received. It may take up to several days after the cardholer's purchase for the clearing to occur. ### Authorization declined A declined transaction is final and not followed by any other operations. It doesn't affect either the [Balance](/guide/overview/glossary#balance) nor the [Authorized Balance](/guide/overview/glossary#balance). When an authorization is declined, a card transaction is created, with the following [payment status](/guide/cards/transactions#statuses-paymentstatus). | [`paymentStatus`](/guide/cards/transactions#statuses-paymentstatus) | Event | Description | | --- | --- | --- | | `I` (Declined) | `cardTransaction.create` | When the transaction isn't authorized. | Possible [reasons](/guide/cards/authorization-notes) for decline include (but are not limited to): * An online payment is attempted, but the [Card options don't allow online payments](/guide/cards/restrictions-limits#options-permission-groups) * The payment amount is higher than the [Card payment limit](/guide/cards/restrictions-limits#payment-withdrawal-limits) * The `merchantId` that requests the authorization is [blacklisted](/guide/cards/restrictions-limits#mid-restrictions) in the Card options * The cardholder has insufficient funds * A network error occurred **Information – The decline reason is in the [`cardtransaction`](events-tx#cardtransactions) webhook:** * [`authorizationResponseCode`](/guide/cards/authorization-notes#authorization-response-codes) attribute * [`authorizationNote`](/guide/cards/authorization-notes) attribute when relevant In some situations, when an error occurred high up in the banking network (Negative Advice), you were not notified of the transaction attempt and of its decline. Producing a situation where your customer was aware of an authorization failure, but your Dashboard Users were not. **You can now opt-in to receive these notifications. They will produce `cardtransaction.create` webhooks with a `paymentStatus` valued to `I`.** ### Authorization accepted, then declined This is a very rare case. It can occur when Treezor accepts an authorization, but the acceptance doesn't reach the [merchant](/guide/overview/glossary#merchant) because of *card network* errors. When this happens, a declined authorization is emitted in the hours that follow. ## Partial Authorization A partial authorization occurs when there are insufficient funds to cover the full amount of the transaction. In such cases, if the merchant handles partial authorizations and if the transaction is in euros, then only the amount available is authorized. The partial authorization have the following attributes. | Attribute | Value | | --- | --- | | [`paymentStatus`](./transactions#statuses-paymentstatus) | A (Accepted) | | [`authorizationResponseCode`](/guide/cards/authorization-notes#authorization-response-codes) | 10 (PARTIAL\_APPROVAL) | ::: details Example Let's take the example of a transaction at an automated fuel dispenser. 1. An authorization request of €150 is issued by the dispenser. 2. The cardholder account balance is €100. 3. The card transaction is partially authorized. 4. The cardholder can use the dispenser for up to €100 of fuel. ::: ## Pre-Authorization A pre-authorization is generally used when the final transaction amount is not yet known in order to put a hold on an amount approved by the issuer. For example, [at an automated fuel dispenser](/guide/cards/transactions-examples#gas-station-transaction). Pre-Authorization behaves exactly like authorization. Only the [`authorizationNote`](/guide/cards/authorization-notes) attribute of a webhook may specify "pre-authorization". **Information – Specific processing for USA and Canada AFDs** Treezor applies a fixed pre-authorized amount of €160 for all pre-authorization requests made in the USA or Canada for automated fuel dispensers (AFD) payments. Learn more in the [automated fuel dispenser](/guide/cards/transactions-examples#gas-station-transaction) example. ## Settlement The settlement is the step where funds are actually debited from the cardholder's wallet/account and credited to the merchant's wallet/account. It generally shows up three days after the authorization and affects the [Balance](/guide/overview/glossary#balance). **A settlement can be complete, partial, and even multiple** Consider an authorization of €1,000. There could be: * A single settlement of €1,000 * One settlement of €750 and a reversal of €250 * Two settlements of €500 each * Three settlements of €333.33 each * etc. When a settlement occurs, a card transaction is created, with the following [payment status](/guide/cards/transactions#statuses-paymentstatus). | [`paymentStatus`](/guide/cards/transactions#statuses-paymentstatus) | Event | Description | | --- | --- | --- | | `S` (Settled) | `cardTransaction.create` | When the transaction is settled. | ## MoneySend **Important – Progressive feature rollout** The MoneySend transaction feature will be rolled out progressively. Your *Account Manager* will contact you to adjust your implementation as needed. A MoneySend card transaction credits the cardholder's account. It occurs in 2 steps: * **Authorization**, during which Treezor verifies the MoneySend validity (account and card). * **Settlement**, after which the funds can be used by the cardholder. This generally the day after the authorization. These transactions can be accepted or refused in the same way as authorizations. **Note – The amount is not available to the cardholder until the settlement is received** You can rely on the authorization webhook which indicates that the transaction is in progress. In the webhooks received for MoneySend transactions, amounts are displayed as negative values. For example: `"paymentAmount": "-7.00"` Also, MoneySend card transactions can have one of the following [MCC](/guide/overview/glossary#merchant-category-code-mcc): * `6536` for MONEYSEND INTRACOUNTRY * `6537` for MONEYSEND INTERCOUNTRY When a MoneySend transaction occurs, a card transaction is created, with one of the following [payment status](/guide/cards/transactions#statuses-paymentstatus). | [`paymentStatus`](/guide/cards/transactions#statuses-paymentstatus) | Event | Description | | --- | --- | --- | | `M` (MoneySend) | `cardTransaction.create` | When the MoneySend transaction is accepted. | | `S` (Settled) | `cardTransaction.create` | When the MoneySend transaction is settled. | | `I` (Declined) | `cardTransaction.create` | When the MoneySend transaction is refused. | ### MoneySend and external validation When using [Transactions external validation](/guide/cards/transactions-external-validation), you can identify MoneySend transactions thanks to the [`mcc`](/guide/overview/glossary#merchant-category-code-mcc) attribute valued to `6536` or `6537`. **Alert – MoneySend Intercountry is not available yet** Therefore, even if you accept a MoneySend transaction with the `6537` MCC through external validation, Treezor will decline the transaction. The webhooks sent will be exactly the same as for a regular MoneySend transaction, as described above. ## Reversal A reversal follows an accepted authorization and cancels it at the merchant's request. Funds have not yet been debited nor credited when a reversal occurs, so only the [**Authorized Balance**](/guide/overview/glossary#balance) of the cardholder is affected. **A reversal can be complete or partial.** Consider an authorization of €1000. There could be: * One reversal of €1,000 * One reversal of €100 and a settlement of €900 * One reversal of €900 and a settlement of €100 * etc. When a Reversal occurs, a card transaction is created, with the following [payment status](/guide/cards/transactions#statuses-paymentstatus). | [`paymentStatus`](/guide/cards/transactions#statuses-paymentstatus) | Event | Description | | --- | --- | --- | | `V` (Reversed) | `cardTransaction.create` | When the merchant cancels an accepted authorization. | ## Refunds A refund is the act of **requesting a refund**, when **funds have effectively been debited from the cardholder's wallet** (due to a previous *settlement*). Therefore, a refund affects the [**Balance**](/guide/overview/glossary#balance). They behave in a similar way as *authorizations* do: * They can be either accepted or declined * They can be followed by a complete or partial settlement (of negative amount value) ### Refund accepted When a Refund is accepted, 2 card transactions are usually created, with the following [payment status](/guide/cards/transactions#statuses-paymentstatus). | [`paymentStatus`](/guide/cards/transactions#statuses-paymentstatus) | Event | Description | | --- | --- | --- | | `R` (Refund) | `cardTransaction.create` | When the Refund is accepted. A negative `amount` is displayed. | | `S` (Settled) | `cardTransaction.create` | If the Refund is settled. A negative `amount` is displayed. | Please note however that the transaction might not be settled. In such cases, the Wallet isn't credited. ### Refund declined When a Refund is declined, a card transaction is created, with the following [payment status](/guide/cards/transactions#statuses-paymentstatus). | [`paymentStatus`](/guide/cards/transactions#statuses-paymentstatus) | Event | Description | | --- | --- | --- | | `I` (Declined) | `cardTransaction.create` | When the Refund is declined. | ## Chargeback Chargeback is a process that happens when the cardholder disputes a card payment that has been approved and settled. The reason for the dispute may be due to a suspected fraud or an unfulfilled order of goods/services. The chargeback is initiated by the issuer at the request of the cardholder. If accepted, the cardholder account will be credited. ## Expiration An expiration occurs when an *Authorization* was accepted but was not followed by any settlement or reversal in the 10 following days. On the night of the 10th to 11th day, the [Authorized Balance](/guide/overview/glossary#balance) is freed up. **Expirations don't create `cardTransaction` webhooks or operations.** --- --- url: /guide/cards/transactions-authentication.md description: >- Learn how to handle notifications of strong customer authentication (SCA) for card transactions. Includes required parameters, request structure, and response examples. --- # Transactions authentication (SCA) Most online [Card Transactions](/guide/cards/transactions) require an [SCA](/guide/strong-customer-authentication/introduction). ## Authentication of the end user Upon reception of the [`card3DSv2Authentication.create`](/guide/cards/events-tx#card3DSv2authentication-create) webhook, you must **authenticate your end user** using the SDK and a strong authentication method such as `Pin Authentication` or `Device Biometric Authentication`. ## Notification of Authentication Result Upon authentication of the end user, you must **inform Treezor** of the authentication result with the dedicated endpoint. ### Parameters The following parameters are expected in the payload. | Attribute | Type | Description | | --- | --- | --- | | `authenticationResult` | string | Whether the authentication was successful. See [Authentication result](#authentication-result) for the list of values. | #### Authentication result | `authenticationResult` | Description | | --- | --- | | `OK` | The Strong Customer Authentication of your end user was successful. | | `KO_AUTH_FAILED` | The end user failed to strongly authenticate themselves. | | `KO_TECHNICAL` | A technical error prevented the authentication. | | `FALLBACK` | Allows you to request from the sever a one-time password (OTP SMS). | ### Request example Endpoint: [`/v1/auth-requests/{authRequestId}/result`](/api-reference/api-endpoints.html#tag/Card%20Transactions%20Authentication%20\(SCA\)/putAuthRequestResult){target="\_self"} You can find the value for the `authRequestId` query parameter in the `authenticationRequestId` of the [`card3DSv2Authentication.create`](/guide/cards/events-tx#card3DSv2authentication-create) webhook. ::: code-group ```bash [CURL] curl -X PUT '{baseUrl}/v1/auth-requests/{authRequestId}/result' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content: application/json' \ -d '{payload}' ``` ::: Here is a `{payload}` example. ::: code-group ```json [JSON] { "authenticationResult": "OK", // Successful SCA } ``` ::: **Note – You have 5 minutes to provide the result to Treezor** You must provide the authentication result to Treezor within 5 minutes of the webhook emission. This delay can be modified to suit your specific needs by contacting your *Treezor Account Manager*. ### Responses Treezor may answer with the following HTTP status codes. #### `200` HTTP Status Code If your answer has been received and accepted by Treezor. #### `400` HTTP Status Code If the provided attributes are invalid or missing. ::: code-group ```json [JSON] { "errors": [ { "type": "invalid_request", "code": "input_validation_error", "message": "Invalid request data : The authenticationResult field is required|invalid.", "requestId": "request-id", "docUrl": "https://developers.treezor.co", } ] } ``` ```json [JSON (legacy)] { "authenticationResult": ["The authenticationResult field is required|invalid."], "authenticationSignature": ["The authenticationResult field is invalid."] } ``` ::: If the authentication request has already been processed by Treezor. ::: code-group ```json [JSON] { "errors": [ { "type": "invalid_grant", "code": "authentication_error", "message": "Authentication result already received", "requestId": "request-id", "docUrl": "https://developers.treezor.co", } ] } ``` ```json [JSON (legacy)] { "error": "Authentication Request Already Processed" } ``` ::: If the authentication request cannot be found on Treezor's side. ::: code-group ```json [JSON] { "errors": [ { "type": "invalid_request", "code": "resource_not_found_error", "message": "Unable to find the authenticationRequestID in our system", "requestId": "request-id", "docUrl": "https://developers.treezor.co", } ] } ``` ```json [JSON (legacy)] { "error": "Unable to find the authenticationRequestID in our system" } ``` ::: #### `500` HTTP Status Code If an internal error on our side prevented us from accepting your answer ::: code-group ```json [JSON] { "errors": [ { "type": "unexpected_internal_server_error", "code": "unexpected_error", "message": "Internal server error", "requestId": "request-id", "docUrl": "https://developers.treezor.co", } ] } ``` ```json [JSON (legacy)] { "error": "Internal server error" } ``` ::: ## Final authentication request status Depending on the [authentication result you sent to Treezor](#notification-of-authentication-result) and Treezor's final processing, you're notified of the [Card Transaction](/guide/cards/transactions) authentication status through the [`card3DSv2Authentication.update`](/guide/cards/events-tx#card3DSv2authentication-update) webhook. The `authenticationFinalResult` value can be one of the following. | Final result | Description | | --- | --- | | `SUCCESS` | Authentication is successful and the card transaction proceeds. | | `UNAUTHENTICATED` | Treezor took into account that the authentication has failed. The card transaction fails. | | `ERROR` | An error occurred during the authentication process. The card transaction fails. This may occur regardless of your response, due to an error on the card processor's side. | | `FALLBACK` | You sent a FALLBACK response. Authentication switches to SMS\_OTP mode. | | `TIMEOUT` | Authentication failed due to a timeout. The card transaction fails. This may occur regardless of your response, due to an error on the card processor's side. | **Tip – Authentication simulation available** Treezor allows you to simulate the authentication of an online card transaction. See [Simulate card transaction authentication (SCA)](./faking-operations#simulate-card-transaction-authentication-sca) for more information. --- --- url: /guide/cards/authorization-notes.md description: >- Learn how to inform the cardholder of the cause of a payment incident or status with the authorization notes. --- # Authorization notes The `authorizationNote` attribute allows you to inform the cardholder of the cause of a payment incident and/or status. You should always use the `authorizationNote` **together with the [`authorizationResponseCode`](#codes-authorizationresponsecode)** to provide accurate information to the cardholder. The [`authorizationResponseCode`](#codes-authorizationresponsecode) indicates if the transaction was Declined or Approved, while the `authorizationNote` provides more details as to why. **Tip – Multiple messages may be contained in the `authorizationNote`** In which case they are concatenated with the `\n` character to separate them. **Caution – The authorization notes list isn't exhaustive** Due to the vast number of possibilities regarding authorization notes and their variations, we document only the most common ones. ## Card processor authorization notes Find below the list of common authorization notes sent by the card processor. | Authorization Note | Description | |--- |--- | | `; DE095={amount}; DE095={amount}` | Informative message, `{amount}` is the remaining [authorized](/guide/cards/transactions-lifecycle#authorization-accepted) amount after a [partial reversal](/guide/cards/transactions-examples#gas-station-transaction) | | `ASI.... AVS check` | Informative message, the address of the cardholder has been checked | | `ASI.... CVC check` | Informative message, the CVC has been checked | | `AUTOMATIC AUTHORISATION REMOVAL BillAmt - {amount} Location - {business} {country}` | An authorization from 7 days ago has been [cancelled and reversed](/guide/cards/transactions-lifecycle#reversal), as no settlement occurred (these are generally used to ensure a Card is valid by authorizing a small amount that is never actually debited) | | `Banknet advice: APS error; unable to deliver response` | Temporary internal error, the Cardholder should retry their payment | | `BlockedCard` | The Card is [blocked](/guide/cards/modification#block-a-card). | | `Card CVV2 not matching with cvv2 in auth request` | The cardholder entered an erroneous [CVV2 (or CVC)](/guide/overview/glossary#card-verification-number-cvc) | | `ChargeBack - Credit to Card` | Informative message, the cardholder has just been refunded following a chargeback | Card Processor | | `Connection Timeout` | Temporary internal error, the Cardholder should retry their payment | | `COUNTRY CODE NOT ALLOWED` | The [merchant's country is not allowed](/guide/cards/restrictions-limits#country-restrictions) by the Card or [Card Program](/guide/cards/introduction#card-program) | | `CountryNotPermittedToCardHolder` | The payment country is not allowed by the Card or [Card Program](/guide/cards/introduction#card-program) | | `DR: AF:Mag ATM attempt` | An ATM withdrawal was attempted using the magstripe, which is forbidden for security reason. The cardholder should retry using the Card Chip\&PIN method. | | `DR: ARQC not matching` | There was a malfunction with the Card and/or the payment terminal, the cardholder may retry their payment once | | `DR: Card expiry check failed with Emboss Expiry date (DE014)` | The cardholder entered a wrong expiration date | | `DR: Card not found UnKnownCard` | The Card PAN is unknown or invalid but does match Treezor's range of Card numbers | | `DR: CVC2 tries exceeded` | The cardholder entered erroneous [CVC](/guide/overview/glossary#card-verification-number-cvc) too many times. [A ticket must be open with Treezor to unlock it.](/guide/cards/modification#unlock-cvv) | | `DR: Declined due to Card Status: Card Destroyed (Original status 83, changed to 05) ` | The Card has been [destroyed](/guide/cards/introduction#card-status-statuscode) | | `DR: Declined due to Card Status: Expired card` | The Card has expired (expiration date is in the past) | | `DR: Declined due to Card Status: Lost card (Capture)(Issuer will be charged if card is picked up)` | The Card has been [lost](/guide/cards/introduction#card-status-statuscode) and the merchant is allowed to keep the Card and send it to their bank for restitution to Treezor | | `DR: Declined due to Card Status: Restricted card (Card is not active)` | The Card is [inactive](/guide/cards/modification#activation) | | `DR: Declined due to Card Status: Short-term Debit` | The Card is [locked](/guide/cards/modification#activation) | | `DR: Declined due to Card Status: Stolen card (Capture)(Issuer will be charged if card is picked up)` | The Card has been [stolen](/guide/cards/introduction#card-status-statuscode) and the merchant is allowed to keep the Card and send it to their bank for restitution to Treezor | | `DR: Declined due to CardUsageGroupCheck GroupUsageID-{groupId} [additional information]` | The authorization was blocked due to restrictions on the use of the Card. More information are available in the details: `[additional information]`. | | `DR: Declined due to Lost Card (Capture)(Original auth resp status 41, changed to 05)` | The Card has been [declared as lost](/guide/cards/introduction#card-status-statuscode) | | `DR: Declined due to Restricted card (Card is not active)` | The Card is not activated or is disabled | | `DR: Declined due to Stolen Card (Capture)(Original auth resp status 43, changed to 05) ` | The Card has been [declared as stolen](/guide/cards/introduction#card-status-statuscode) | | `DR: Decline existing tokens(10) > Min_Tokens_To_Decline(10) DR: MDES/VDEP validation failed MDES check failed from Tokenisation Processing` | There are already 10 Cards tokenized with an X-Pay provider (Google Pay, Apple Pay, Samsung Pay...), no more tokenization are allowed | | `DR: Decline as wallet_device_score (1) <= wallet_device_max_score_decline (1)` | Card tokenization has been denied by the X-Pay provider (Apple Pay, Google Pay, Samsung Pay…) due to poor end user's device scoring | | `DR: Expiry Date missing.` | The expiration date of the Card has not been provided | | `DR: IAV:V (checked by MC-PREVAL)` | Monetary Currency mismatch between authorization and authentication | | `DR: iCVV does not match on EMV Track 2` | Either an issue with the merchant's terminal, or the chip of the card. Contact Support if the issue occurs with multiple merchants. | | `DR: Incorrect PIN` | The [PIN](/guide/overview/glossary#personal-identification-number-pin) code entered was incorrect | | `DR: MDES Invalid Card Number - payment_token not found` | The Card was properly digitized for [X-Pay](/guide/cards/x-pay-google-apple) but an incident occurred when payin with X-Pay. The cardholder should digitize their card again. | | `DR: Offline PIN incorrect` | The cardholder entered an erroneous [PIN](/guide/overview/glossary#personal-identification-number-pin) | | `DR: Offline PIN try limit exceeded` | The maximum number of erroneous PIN has been reached, [the PIN must be unlocked](/guide/cards/modification#unlock-pin) | | `DR: Requires SCA` | The transaction requires a [Strong Customer Authentication](/guide/overview/glossary#strong-customer-authentication-sca) such as [3D Secure](/guide/overview/glossary#_3d-secure-3d) or [Chip & Pin](/guide/overview/glossary#personal-identification-number-pin). | | `EH Timeout - An error occurred while sending the request.` | Temporary internal error, the Cardholder should retry their payment | | `EH Timeout - Response status code does not indicate success: 429 (Too Many Requests).` | Temporary internal error, the Cardholder should retry their payment | | `EH Timeout - Response status code does not indicate success: 502 (Bad Gateway).` | Temporary internal error, the Cardholder should retry their payment | | `EH Timeout - The operation was canceled.` | Temporary internal error, the Cardholder should retry their payment | | `EH Timeout - Unable to connect to the remote server` | Temporary internal error, the Cardholder should retry their payment | | `EH Timeout` | Temporary internal error, the Cardholder should retry their payment | | `Gen: Pre-Authorization Request` | Informative message, indicates a pre-authorization request (such as a deposit) which can be canceled later | | `Issuer Time-out` | Temporary internal error, the Cardholder should retry their payment | | `MDES FPAN Status:41` | Informative message, a payment was made with Apple Pay/Google Pay/Samsung Pay and the actual Card is lost | | `MDES FPAN Status:62` | Informative message, a payment was made with Apple Pay/Google Pay/Samsung Pay and the actual Card is stolen or disabled | | `Null or Empty Response received from client` | Temporary internal error, the Cardholder should retry their payment | | `Presentment for Partial Reversal` | Informative message, following a [Gas station](/guide/cards/transactions-examples#gas-station-transaction) transaction | | `PSD2 Counter Reset` | Informative message, the [contactless counter](/guide/overview/glossary#near-field-communication-nfc) or e-commerce counter has been reset to zero | | `Reversal due to AFD Advice with different amount. (AFD Amount=30.0000)` | Informative message, the [reversal](/guide/cards/transactions-lifecycle#reversal) cancels a previous authorization at the merchant's request. It frees up the [Authorized Balance](/guide/overview/glossary#balance) of the Wallet. | | `Signature Verification - Failed` | Occurs in countries where the authentication method consists in signing the receipt. Such authentications are refused as they can't be checked online. | The `DR:` prefix means *Decline Reason*. ## Treezor authorization notes Find below the list of common authorization notes sent by Treezor. | Authorization Note | Description | |--- |--- | | `ATM MONTHLY LEGAL LIMIT OF WALLET EXCEEDED` | The legal ATM withdrawal limit has been reached | | `Credit Other - pre-arbitration` | Arbitration case: the cardholder has definitively won the chargeback following a dispute with the merchant. | | `DECLINED BY GPS` | The card processor declined the transaction (this is always accompanied by a more detailed message) | | `Electronic Money: MCC not permitted` | The law prohibits this MCC (type of business). This only occurs with [EM projects](/guide/wallets/introduction#electronic-money-wallet-type-9) | | `Electronic Money: transaction not permitted to cardholder` | The cardholder doesn't exist or is frozen. This only occurs with [EM projects](/guide/wallets/introduction#electronic-money-wallet-type-9) | | `Electronic Money: cumulative amount authorized exceeded` | The electronic money limit on sliding period has been reached. This only occurs with [EM projects](/guide/wallets/introduction#electronic-money-wallet-type-9) | | `Electronic Money: amount exceeds the authorized amount` | The transaction amount exceeds the authorized amount. This only occurs with [EM projects](/guide/wallets/introduction#electronic-money-wallet-type-9) | | `Electronic Money: payment is not permitted in this country` | The country of the wallet and the country in which the payment is done don't match. This only occurs with [EM projects](/guide/wallets/introduction#electronic-money-wallet-type-9) | | `ErrorInternal` | Temporary internal error, the Cardholder should retry their payment | | `Fixed amount adjustment` | The difference between the pre-authorized amount for the AFD transaction and the actually charged amount has been reversed. Learn more about this specific case in the [corresponding example](/guide/cards/transactions-examples#gas-station-transaction). | | `Incoming transaction concern an unactive wallet` | The transaction is associated to an [inactive Wallet](/guide/wallets/modification#delete) | | `Incoming transaction concern an unactive user` | The transaction is associated to an [inactive User](/guide/users/introduction#deletion) | | `Incoming transaction concern an unactive card` | The transaction is associated to an [inactive Card](/guide/cards/modification#block-a-card) | | `Incoming transaction concern an unknown PAN` | The transaction is associated to an unknown PAN (absent from our system) | | `Insufficient funds` | The Wallet has insufficient funds | | `Invalid card number (no such token)` | The Card PAN is invalid or unknown | | `LIMIT ATM EXCEEDED ALL` | The lifetime [ATM withdrawal limit](/guide/cards/restrictions-limits#payment-withdrawal-limits) has been reached | | `LIMIT ATM EXCEEDED DAY` | The daily [ATM withdrawal limit](/guide/cards/restrictions-limits#payment-withdrawal-limits) has been reached | | `LIMIT ATM EXCEEDED MONTH` | The monthly [ATM withdrawal limit](/guide/cards/restrictions-limits#payment-withdrawal-limits) has been reached | | `LIMIT ATM EXCEEDED WEEK` | The weekly [ATM withdrawal limit](/guide/cards/restrictions-limits#payment-withdrawal-limits) has been reached | | `LIMIT ATM EXCEEDED YEAR` | The yearly [ATM withdrawal limit](/guide/cards/restrictions-limits#payment-withdrawal-limits) has been reached | | `LIMIT CONTACTLESS APPLE PAY EXCEEDED` | The [Apple Pay](/guide/cards/x-pay-google-apple) contactless limit has been reached | | `LIMIT CONTACTLESS EXCEEDED` | The [contactless](/guide/overview/glossary#near-field-communication-nfc) limit has been reached | | `LIMIT PAYMENT EXCEEDED ALL` | The lifetime [payment limit](/guide/cards/restrictions-limits#payment-withdrawal-limits) has been reached | | `LIMIT PAYMENT EXCEEDED DAY` | The daily [payment limit](/guide/cards/restrictions-limits#payment-withdrawal-limits) has been reached | | `LIMIT PAYMENT EXCEEDED MONTH` | The monthly [payment limit](/guide/cards/restrictions-limits#payment-withdrawal-limits) has been reached | | `LIMIT PAYMENT EXCEEDED WEEK` | The weekly [payment limit](/guide/cards/restrictions-limits#payment-withdrawal-limits) has been reached | | `LIMIT PAYMENT EXCEEDED YEAR` | The yearly [payment limit](/guide/cards/restrictions-limits#payment-withdrawal-limits) has been reached | | `MCC NOT ALLOWED` | The [Merchant Category Code (category of business) is not allowed](/guide/cards/restrictions-limits#mcc-restrictions) by the Card or [Card Program](/guide/cards/introduction#card-program) | | `MccNotPermittedToCardHolder` | The [Merchant Category Code (category of business) is not allowed](/guide/cards/restrictions-limits#mcc-restrictions) by the Card or [Card Program](/guide/cards/introduction#card-program) | | `MDC DECLINED - did not match: {rulesetIds}` | The transaction was refused by the [Treezor transaction rules engine](/guide/cards/transactions-rules-engine). | | `MERCHANT ID NOT ALLOWED` | The [merchant's ID (one specific business) is not allowed](/guide/cards/restrictions-limits#mid-restrictions) | | `MerchantIdNotPermittedToCardHolder` | The [merchant's ID (one specific business) is not allowed](/guide/cards/restrictions-limits#mid-restrictions) | | `POSDailyLimitExceeded` | The daily [payment limit](/guide/cards/restrictions-limits#payment-withdrawal-limits) has been reached | | `Refund` | Informative message, refund authorization | | `REVERSAL` | Informative message, the [reversal](/guide/cards/transactions-lifecycle#reversal) cancels a previous authorization at the merchant's request. It frees up the [Authorized Balance](/guide/overview/glossary#balance) of the Wallet. | | `SIMULTANEOUS OPERATIONS ON THE SAME WALLET` | Multiple operations occurred at the very same time on the Wallet, the cardholder should retry their payment | | `Specific to AFD: fixed amount authorization` | The fixed amount of €160 has been applied for a automated fuel dispenser (AFD) transaction. Learn more about this specific case in the [corresponding example](/guide/cards/transactions-examples#gas-station-transaction). | | `System Error.` | Temporary internal error, the Cardholder should retry their payment. | | `User's assets are freezed` | The Wallet or payment account of the User is [frozen](/guide/users/restricted-users) by an [AML-CFT](/guide/overview/glossary#anti-money-laundering-and-countering-the-financing-of-terrorism-aml-cft) sanction. | | `{rulesetIds}` | The transaction was accepted by the [Treezor transaction rules engine](/guide/cards/transactions-rules-engine). | ## External Authorization authorization notes Find below the list of common authorization notes sent by you in the context of the [External Authorization](/guide/cards/transactions-external-validation) feature. | Authorization Note | Description | |--- |--- | | `External Authorization - DECLINED` | You declined the card transaction through the [External Authorization](/guide/cards/transactions-external-validation) feature. | | `External Authorization - DECLINED_CARD_UNKNOW` | You declined the card transaction through the [External Authorization](/guide/cards/transactions-external-validation) feature. | | `External Authorization - DECLINED_DATETIME_INVALID` | You declined the card transaction through the [External Authorization](/guide/cards/transactions-external-validation) feature. | | `External Authorization - DECLINED_DUE_TO_REGULATORY_RULE` | You declined the card transaction through the [External Authorization](/guide/cards/transactions-external-validation) feature. | | `External Authorization - DECLINED_INSUFFICIENT_FUNDS` | You declined the card transaction through the [External Authorization](/guide/cards/transactions-external-validation) feature. | | `External Authorization - DECLINED_INSUFFICIENT_FUNDS_WITHDRAWAL_LIMIT_REACHED` | You declined the card transaction through the [External Authorization](/guide/cards/transactions-external-validation) feature. | | `External Authorization - DECLINED_LOCAL_CURRENCY_INVALID` | You declined the card transaction through the [External Authorization](/guide/cards/transactions-external-validation) feature. | | `External Authorization - DECLINED_MCC_INVALID` | You declined the card transaction through the [External Authorization](/guide/cards/transactions-external-validation) feature. | | `External Authorization - DECLINED_MERCHANT_CITY_INVALID` | You declined the card transaction through the [External Authorization](/guide/cards/transactions-external-validation) feature. | | `External Authorization - DECLINED_MERCHANT_COUNTRY_INVALID` | You declined the card transaction through the [External Authorization](/guide/cards/transactions-external-validation) feature. | | `External Authorization - DECLINED_MERCHANTID_INVALID` | You declined the card transaction through the [External Authorization](/guide/cards/transactions-external-validation) feature. | ## Authorization response codes This information is provided in the `authorizationResponseCode` attribute. It provides clues as to why the transaction was accepted or refused, and pointers regarding what to do next. This information comes in addition to [the status](/guide/cards/transactions#statuses) of a transaction. | Code | | Action | Description | |:-: |- |- | - | | `00` | | Approve | APPROVED | | `08` | | Approve | HONOR\_WITH\_ID | | `10` | | Approve | PARTIAL\_APPROVAL | | `87` | | Approve | PURCHASE\_AMOUNT\_ONLY\_NO\_CASH\_BACK\_ALLOWED | | `98` | | Approve | REFUND\_GIVEN\_TO\_CUSTOMER | | `85` | | Approve | NOT\_DECLINED\_VALID\_FOR\_ALL\_ZERO\_AMOUNT\_TRANSACTIONS | | `01` | | Call-Issuer | REFER\_TO\_CARD\_ISSUER | | `70` | | Call-issuer | CONTACT\_CARD\_ISSUER | | `41` | | Capture | LOST\_CARD | | `43` | | Capture | STOLEN\_CARD | | `02` | | Decline | CARD\_NOT\_YET\_ACTIVATED | | `03` | | Decline | INVALID\_MERCHANT | | `04` | | Decline | CAPTURE\_CARD\_CAPTURE | | `05` | | Decline | DO\_NOT\_HONOR | | `06` | | Decline | ERROR (REVERSAL ONLY) | | `12` | | Decline | INVALID\_TRANSACTION | | `13` | | Decline | INVALID\_AMOUNT | | `14` | | Decline | INVALID\_CARD\_NUMBER | | `15` | | Decline | INVALID\_ISSUER | | `30` | | Decline | FORMAT\_ERROR | | `51` | | Decline | INSUFFICIENT\_FUNDS | | `54` | | Decline | EXPIRED\_CARD | | `55` | | Decline | INVALID\_PIN | | `57` | | Decline | TRANSACTION\_NOT\_PERMITTED\_TO\_CARDHOLDER | | `58` | | Decline | TRANSACTION\_NOT\_PERMITTED\_TO\_ACQUIRER\_TERMINAL | | `61` | | Decline | EXCEEDS\_WITHDRAWAL\_AMOUNT\_LIMIT | | `62` | | Decline | RESTRICTED\_CARD | | `63` | | Decline | SECURITY\_VIOLATION | | `65` | | Decline | EXCEEDS\_WITHDRAWAL\_COUNT\_LIMIT | | `71` | | Decline | PIN\_NOT\_CHANGED | | `75` | | Decline | ALLOWABLE\_NUMBER\_OF\_PIN\_TRIES\_EXCEEDED | | `76` | | Decline | INVALID\_TO\_ACCOUNT\_SPECIFIED | | `77` | | Decline | INVALID\_FROM\_ACCOUNT\_SPECIFIED | | `78` | | Decline | INVALID\_ACCOUNT\_SPECIFIED\_GENERAL | | `81` | | Decline | DOMESTIC\_DEBIT\_TRANSACTION\_NOT\_ALLOWED\_REGIONAL\_USE\_ONLY | | `83` | | Decline | CARD\_DESTROYED | | `84` | | Decline | INVALID\_AUTHORIZATION\_LIFE\_CYCLE | | `86` | | Decline | PIN\_VALIDATION\_NOT\_POSSIBLE | | `88` | | Decline | CRYPTOGRAPHIC\_FAILURE | | `89` | | Decline | UNACCEPTABLE\_PIN\_\_TRANSACTION\_DECLINED\_\_RETRY | | `91` | | Decline | AUTHORIZATION\_PLATFORM\_OR\_ISSUER\_SYSTEM\_INOPERATIVE | | `92` | | Decline | UNABLE\_TO\_ROUTE\_TRANSACTION | | `94` | | Decline | DUPLICATE\_TRANSMISSION\_DETECTED | | `96` | | Decline | SYSTEM\_ERROR | | `99` | | Decline | CARD\_VOIDED | --- --- url: /guide/cards/errors-tx.md description: >- Troubleshoot and handle card transaction-related issues using the Treezor API's complete list of error codes, messages, and their corresponding meanings. --- # Errors The following API errors can be encountered with card transactions. **Caution – Only the legacy API sends the error code in HTTP errors** When handling errors with Connect, only the `message` attribute is returned. ## Card Transaction errors | Code | Message | |:----------:|--------------------------------------------------------------------------------------------------------------| | `61000` | Length of acceptorId must be lower than 16 characters | | `61001` | Length of acceptorName must be lower than 23 characters | | `61002` | Length of acceptorCity must be lower than 14 characters | | `61003` | Length of acceptorCountry must be lower than 4 characters | | `61004` | Length of paymentLocalTime must be lower than 6 characters | | `61005` | Length of panToken must be lower than 2^63-1 and higher than 1. | | `61006` | paymentAmount is mandatory | | `61007` | Length of paymentCurrency must equal 3 numbers | | `61008` | Length of fees must be lower than 9 numbers | | `61009` | Length of paymentCountry must equal 3 characters | | `61010` | paymentId is mandatory | | `61011` | paymentStatus is mandatory | | `61012` | posCardholderPresence length must be lower than 2 numbers | | `61013` | posCardPresence length must be lower than 2 numbers | | `61014` | panEntryMethod length must be lower than 3 numbers | | `61015` | Length of authorizationResponseCode must equal 2 numbers | | `61016` | authorizationIssuerId is mandatory | | `61017` | authorizationMti length must be equal to 4 numbers | | `61018` | authorizedBalance is mandatory | | `61019` | acceptorName is mandatory | | `61020` | acceptorCity is mandatory | | `61021` | acceptorCountry is mandatory | | `61022` | panToken is mandatory | | `61023` | authorizationResponseCode is mandatory | | `61024` | authorizationMti is mandatory | | `61025` | paymentCurrency is mandatory | | `61026` | Impossible to read card transactions | | `61027` | Unable to filter card transactions by merchantId without at least one of its input parameters: id, cardId, walletId, publicToken, paymentId. | | `61028` | Card Transaction Id is mandatory | | `61029` | Card Transaction Id does not exist | | `61030` | clientId is mandatory | | `61031` | The request must contain at least one of those inputs: cardId, paymentId, publicToken, walletId | | `61032` | cardTransactionId must be an integer | | `61033` | cardId must be an integer | | `61034` | walletId must be an integer | | `61035` | publicToken must be a string | | `61036` | paymentId must be an integer | | `61037` | merchantId must be a string | | `61038` | Invalid cardTransactionId format (numeric is expected) | | `61039` | Invalid format (numeric is expected) | | `61040` | The request must contain at least one of those inputs: cardTransactionId, cardId, paymentId, publicToken, walletId | | `61041` | Impossible to read card transactions | --- --- url: /guide/cards/events-tx.md description: >- Reference a comprehensive list of card transaction events for Treezor API webhooks, detailing each event's structure and payload for integration. --- # Events This article lists the [Webhooks](/guide/webhooks/introduction) you may receive when regarding Card Transactions. ## Card Transactions ### Authorized `cardtransaction.create` ::: code-group ```json [JSON] {23} { "webhook":"cardtransaction.create", "object":"cardtransaction", "object_id":"190314", "object_payload":{ "cardtransactions":[ { "cardtransactionId":"700013016", "cardId":"4821765", "walletId":"13183230", "walletCurrency":"978", "merchantId":"526567002078132", "merchantName":"Action 4105", "merchantCity":"Paris", "merchantCountry":"FRA", "paymentLocalTime":"72316", "publicToken":"288316333", "paymentAmount":"1.99", "paymentCurrency":"978", "fees":"0.00", "paymentCountry":"FRA", "paymentId":"382305888", "paymentStatus":"A", "paymentLocalAmount":"1.99", "posCardholderPresence":"0", "posPostcode":"75100", "posCountry":"250", "posTerminalId":"7547999", "posCardPresence":"0", "panEntryMethod":"7", "authorizationNote":"", "authorizationResponseCode":"0", "authorizationIssuerId":"14215320554", "authorizationIssuerTime":"2024-04-16 08:23:20", "authorizationMti":"100", "authorizedBalance":"42.60", "limitAtmYear":"0", "limitAtmMonth":"1000", "limitAtmWeek":"500", "limitAtmDay":"0", "limitAtmAll":"0", "limitPaymentYear":"0", "limitPaymentMonth":"5000", "limitPaymentWeek":"5000", "limitPaymentDay":"0", "limitPaymentAll":"0", "paymentDailyLimit":"0.00", "totalLimitAtmYear":"0.00", "totalLimitAtmMonth":"0.00", "totalLimitAtmWeek":"0.00", "totalLimitAtmDay":"0.00", "totalLimitAtmAll":"0.00", "totalLimitPaymentYear":"0.00", "totalLimitPaymentMonth":"79.47", "totalLimitPaymentWeek":"0.00", "totalLimitPaymentDay":"0.00", "totalLimitPaymentAll":"0.00", "cardDigitalizationExternalId":"0", "mccCode":"5310", "acquirerId":"13445", "is3DS":"0", "merchantAddress":null, "paymentLocalDate":null, "3dsExemptionType": "5", "optimizedMerchantName": "string", "merchantLogo": "http://yourmerchantlogo.png", "merchantCategory": "string", "transactionSubtype": "PRE", "receiverData": "0104ENZO0308LUVIBILA", "senderData": "0114Capital Com SV0314Capital Com SV0450LOPHITIS BUSINESS CENTER II, Floor 6,, 28 OKTOVRIO0508Limassol0703CYP080430351106205838", "transactionTypeIdentifier": "C07", "localMerchantId": "12345678900001" } ] }, "webhook_created_at":17132761057381, "webhook_id":"32d41919-8390-4431-b74e-04f6c3xxx9a4", "object_payload_signature":"/qTn7yr+xxx9e8Qx/DTTY+2a0mTKLnj5BQ0GT/snIvk=" } ``` ::: ### Settled `cardtransaction.create` ::: code-group ```json [JSON] {23} { "webhook":"cardtransaction.create", "object":"cardtransaction", "object_id":"190314", "object_payload":{ "cardtransactions":[ { "cardtransactionId":"700017059", "cardId":"3658911", "walletId":"253327", "walletCurrency":"978", "merchantId":"08051835 ", "merchantName":"ELA SAINT OUEN", "merchantCity":"L ILE SAINT D", "merchantCountry":"FRA", "paymentLocalTime":"183905", "publicToken":"230647558", "paymentAmount":"13.85", "paymentCurrency":"978", "fees":"0.00", "paymentCountry":"FRA", "paymentId":"382197633", "paymentStatus":"S", "paymentLocalAmount":"13.85", "posCardholderPresence":"0", "posPostcode":"", "posCountry":"0", "posTerminalId":"00000001", "posCardPresence":"1", "panEntryMethod":"0", "authorizationNote":"", "authorizationResponseCode":"0", "authorizationIssuerId":"14214543446", "authorizationIssuerTime":"2024-04-16 04:41:02", "authorizationMti":"1240", "authorizedBalance":"10876604.71", "limitAtmYear":"0", "limitAtmMonth":"0", "limitAtmWeek":"2000", "limitAtmDay":"1000", "limitAtmAll":"0", "limitPaymentYear":"0", "limitPaymentMonth":"0", "limitPaymentWeek":"3000", "limitPaymentDay":"2000", "limitPaymentAll":"0", "paymentDailyLimit":"0.01", "totalLimitAtmYear":"0.00", "totalLimitAtmMonth":"0.00", "totalLimitAtmWeek":"0.00", "totalLimitAtmDay":"0.00", "totalLimitAtmAll":"0.00", "totalLimitPaymentYear":"0.00", "totalLimitPaymentMonth":"0.00", "totalLimitPaymentWeek":"0.00", "totalLimitPaymentDay":"0.00", "totalLimitPaymentAll":"0.00", "cardDigitalizationExternalId":"0", "mccCode":"5331", "acquirerId":"12865", "is3DS":"0", "merchantAddress":"7 RUE MECHIN", "paymentLocalDate":"240415", "3dsExemptionType": "5", "optimizedMerchantName": "string", "merchantLogo": "string", "merchantCategory": "string", "transactionSubtype": "PRE", "receiverData": "0104ENZO0308LUVIBILA", "senderData": "0114Capital Com SV0314Capital Com SV0450LOPHITIS BUSINESS CENTER II, Floor 6,, 28 OKTOVRIO0508Limassol0703CYP080430351106205838", "transactionTypeIdentifier": "C07", "localMerchantId": "12345678900001" } ] }, "webhook_created_at":17132761057381, "webhook_id":"32d41919-8390-4431-b74e-04f6c3xxx9a4", "object_payload_signature":"/qTn7yr+xxx9e8Qx/DTTY+2a0mTKLnj5BQ0GT/snIvk=" } ``` ::: ### Declined `cardtransaction.create` ::: code-group ```json [JSON] {23,31} { "webhook":"cardtransaction.create", "object":"cardtransaction", "object_id":"190314", "object_payload":{ "cardtransactions":[ { "cardtransactionId":"700014695", "cardId":"4504801", "walletId":"6091295", "walletCurrency":"978", "merchantId":"8102132", "merchantName":"MAMP Mobilites", "merchantCity":"MARSEILLE", "merchantCountry":"FRA", "paymentLocalTime":"92636", "publicToken":"256063690", "paymentAmount":"1.70", "paymentCurrency":"978", "fees":"0.00", "paymentCountry":"FRA", "paymentId":"382306486", "paymentStatus":"I", "paymentLocalAmount":"1.70", "posCardholderPresence":"1", "posPostcode":"13007", "posCountry":"250", "posTerminalId":"13061504", "posCardPresence":"1", "panEntryMethod":"1", "authorizationNote":"MERCHANT ID NOT ALLOWED", "authorizationResponseCode":"57", "authorizationIssuerId":"14215325375", "authorizationIssuerTime":"2024-04-16 08:25:57", "authorizationMti":"100", "authorizedBalance":"0.00", "limitAtmYear":"0", "limitAtmMonth":"1000", "limitAtmWeek":"0", "limitAtmDay":"0", "limitAtmAll":"0", "limitPaymentYear":"0", "limitPaymentMonth":"5000", "limitPaymentWeek":"0", "limitPaymentDay":"0", "limitPaymentAll":"0", "paymentDailyLimit":"0.00", "totalLimitAtmYear":"0.00", "totalLimitAtmMonth":"0.00", "totalLimitAtmWeek":"0.00", "totalLimitAtmDay":"0.00", "totalLimitAtmAll":"0.00", "totalLimitPaymentYear":"0.00", "totalLimitPaymentMonth":"307.48", "totalLimitPaymentWeek":"0.00", "totalLimitPaymentDay":"0.00", "totalLimitPaymentAll":"0.00", "cardDigitalizationExternalId":"0", "mccCode":"4111", "acquirerId":"12865", "is3DS":"0", "merchantAddress":null, "paymentLocalDate":null, "3dsExemptionType": "5", "optimizedMerchantName": "string", "merchantLogo": "string", "merchantCategory": "string", "transactionSubtype": "PRE", "receiverData": "0104ENZO0308LUVIBILA", "senderData": "0114Capital Com SV0314Capital Com SV0450LOPHITIS BUSINESS CENTER II, Floor 6,, 28 OKTOVRIO0508Limassol0703CYP080430351106205838", "transactionTypeIdentifier": "C07", "localMerchantId": "12345678900001" } ] }, "webhook_created_at":17132761057381, "webhook_id":"32d41919-8390-4431-b74e-04f6c3xxx9a4", "object_payload_signature":"/qTn7yr+xxx9e8Qx/DTTY+2a0mTKLnj5BQ0GT/snIvk=" } ``` ::: ## 3DSecure ### `card3DSv2Authentication.create` ::: code-group ```json [JSON] { "object_payload": { "authenticationRequestId": "cd679525-c341-4018-92f5-594b06fec05f", // Authentication request UUID, should be returned in the URL of the auth-requests (previously authenticationRequestID) "userId": "123456", // Unique identifier of the user "publicToken": "123456789", // Public token of the card (previously PublicToken) "cardId": "123456", // Unique identifier of the card "maskedPan": "546923******1234", // Card number partially masked "3DSVersion": "2.2.0", // 3DS Version used for the message (1.x or 2.x) "acquirerId": "513264", // Identifier of the merchant's acquirer (previously AcquirerID) "merchantId": "05008620641413", // Identifier of the merchant (previously MerchantID) "merchantName": "Merchant 89111532", // Name of the merchant (previously MerchantName) "merchantURL": "https://example.com", // Merchant URL (previously MerchantURL) "merchantCategoryCode": "0000", // MCC of the merchant (previously MerchantCategoryCode) "merchantCountryCode": "440", // Country code of the merchant (previously MerchantCountryCode) "merchantAppRedirectURL": "", // Merchant app redirect URL (previously MerchantAppRedirectURL) "paymentDate": "2024-03-25T14:26:36.482Z", // Previously transactionTimeStamp, date and time of the authentication "paymentAmount": "1822", // Previously transactionAmount, amount in cents of the transaction "paymentCurrency": "978" // Previously transactionCurrency, currency of the transaction }, "webhook": "card3DSv2Authentication.create", "webhook_id": "", "object": "card3DSv2Authentication", "object_id": "ID of the authentication request (uuid v4)", "webhook_created_at": 17498062335122, "object_payload_signature":"/qTn7yr+xxx9e8Qx/DTTY+2a0mTKLnj5BQ0GT/snIvk=" } ``` ::: ### `card3DSv2Authentication.update` ::: code-group ```json [JSON] { "object_payload": { "publicToken": "354362410", // Public token of the card "authenticationRequestId": "2bca40bc-f23a-4f8d-9625-8671b72b601a", // Authentication request UUID (previously authenticationRequestID) "authenticationFinalResult": "SUCCESS", // Can be: SUCCESS|TIMEOUT|ERROR|UNAUTHENTICATED|FALLBACK "authenticationErrorRef": null, // Error reference given by the processor "authenticationErrorDescription": "" // Error description given by the processor }, "webhook": "card3DSv2Authentication.update", "webhook_id": "9a48cdf3-fe3f-484c-b8b5-c82f152f7c35", "object": "card3DSv2Authentication", "object_id": "2bca40bc-f23a-4f8d-9625-8671b72b601a", "webhook_created_at": 17498062335122, "object_payload_signature":"/qTn7yr+xxx9e8Qx/DTTY+2a0mTKLnj5BQ0GT/snIvk=" } ``` ::: --- --- url: /guide/cards/transactions-examples.md description: >- Dive into various examples of card transaction life cycles, with their subsequent statuses and the impact on the balances at each step. Covers accepted, declined, canceled, and refunded transactions. --- # Transaction examples The following examples cover most of the use cases. **Information – Assumptions about all the following examples** * The initial transaction amount is €150 and is initiated by the cardholder * At the transaction time, the cardholder's wallet has a balance of €1000 * At the transaction time, the cardholder has no pending transactions. Therefore, their [Balance](/guide/overview/glossary#balance) and [Authorized Balance](/guide/overview/glossary#balance) are identical. ## Accepted transaction * The cardholder makes a purchase (online or in a physical shop). * The cardholder's bank accepts the authorization. * The payment is received by the merchant. | # | Operation | Status | Amount | Balance | Authorized Balance | |:-: |- |:-: |-: |-: |-: | | | | | | 1000 | 1000 | | 1 | [Authorization](./transactions-lifecycle#authorization) | `A` | 150 | 1000 | **850** | | 2 | [Settlement](./transactions-lifecycle#settlement) | `S` | 150 | **850** | 850 | ## Declined transaction * The cardholder makes a purchase (online or in a physical shop). * The cardholder's bank declines the payment. | # | Operation | Status | Amount | Balance | Authorized Balance | |:-: |- |:-: |-: |-: |-: | | | | | | 1000 | 1000 | | 1 | [Decline](./transactions-lifecycle#authorization-declined) | `I` | 150 | 1000 | 1000 | ## Canceled transaction * The cardholder makes a purchase (online or in a physical shop). * The cardholder's bank accepts the authorization. * The transaction is **canceled** by the merchant, **before the settlement**. | # | Operation | Status | Amount | Balance | Authorized Balance | |:-: |- |:-: |-: |-: |-: | | | | | | 1000 | 1000 | | 1 | [Authorization](./transactions-lifecycle#authorization) | `A` | 150 | 1000 | **850** | | 2 | [Reversal](./transactions-lifecycle#reversal) | `V` | 150 | 1000 | **1000** | ## Gas station transaction * The cardholder requests a €150 authorization at a gas station before refilling their vehicle. * The cardholder's bank accepts the authorization (#1). * The cardholder actually fills for €90 of fuel. * The difference between the authorization amount and the actual amount (€60) is `reversed` (#2). * The actual amount (€90) is `settled` (#3). | # | Operation | Status | Amount | Balance | Authorized Balance | |:-: |- |:-: |-: |-: |-: | | | | | | 1000 | 1000 | | 1 | [Authorization](./transactions-lifecycle#authorization) | `A` | 150 | 1000 | **850** | | 2 | [Reversal](./transactions-lifecycle#reversal) | `V` | 60 | 1000 | **910** | | 3 | [Settlement](./transactions-lifecycle#settlement) | `S` | 90 | **910** | 910 | ### Specific case of automated fuel dispensers in the US and Canada Please note that Treezor applies a fixed pre-authorized amount of €160 for all pre-authorization requests made in the USA or Canada for automated fuel dispensers (AFD) payments. This applies to transactions with the following values: * `"mccCode":"5542"` * `"paymentCountry":"USA"` (or `"CAN"`) * `"paymentLocalAmount":"1"` In such cases, additional information can be found in the `authorizationNote`: * `Specific to AFD: fixed amount authorization` — Indicates that the fixed amount has been applied. * `Fixed amount adjustment` — Indicates that the actual amount has been charged and the leftover, if any, is reversed. Below is a sample of a [`cardtransaction.create`](/guide/cards/events-tx#cardtransaction-create) webhook corresponding to our example. As previously described, the `paymentLocalAmount` is $1, and the `paymentAmount` is €160. ::: code-group ```json [JSON] { "merchantName": "SHELL", "merchantCity": "EVANSTON", "merchantCountry": "USA", "paymentLocalTime": "135911", "publicToken": "999999999", "paymentAmount": "160.00", "paymentCurrency": "840", "fees": "0.00", "paymentCountry": "USA", "paymentId": "1xxx63", "paymentStatus": "A", "paymentLocalAmount": "1.00" } ``` ::: ## Multi-settlement transaction * The cardholder purchases multiple products on an online shop. * The cardholder's bank accepts the authorization (#1). * The merchant does a settlement per product (#2, #3). | # | Operation | Status | Amount | Balance | Authorized Balance | |:-: |- |:-: |-: |-: |-: | | | | | | 1000 | 1000 | | 1 | [Authorization](./transactions-lifecycle#authorization) | `A` | 150 | 1000 | **850** | | 2 | [Settlement](./transactions-lifecycle#settlement) | `S` | 75 | **925** | 850 | | 3 | [Settlement](./transactions-lifecycle#settlement) | `S` | 75 | **850** | 850 | ## Reversal transaction A reversal follows an accepted authorization and cancels it at the merchant's request. A reversal can be complete, partial, or multiple. * The cardholder purchases multiple products on an online shop. * The cardholder's bank accepts the authorization (#1). * The merchant makes a cancellation for one of the products (#2). | # | Operation | Status | Amount | Balance | Authorized Balance | |:-: |- |:-: |-: |-: |-: | | | | | | 1000 | 1000 | | 1 | [Authorization](./transactions-lifecycle#authorization) | `A` | 150 | 1000 | **850** | | 2 | [Reversal](./transactions-lifecycle#reversal) | `V` | 75 | 1000 | **925** | ### Multi-reversal transaction * The cardholder purchases multiple products on an online shop. * The cardholder's bank accepts the authorization (#1). * The merchant makes a cancellation per product (#2, #3). | # | Operation | Status | Amount | Balance | Authorized Balance | |:-: |- |:-: |-: |-: |-: | | | | | | 1000 | 1000 | | 1 | [Authorization](./transactions-lifecycle#authorization) | `A` | 150 | 1000 | **850** | | 2 | [Reversal](./transactions-lifecycle#reversal) | `V` | 75 | 1000 | **925** | | 3 | [Reversal](./transactions-lifecycle#reversal) | `V` | 75 | 1000 | **1000** | ## Non-Euro transaction * The cardholder pays for service or products **in a currency other than Euro**, in a physical or online shop. * The cardholder's bank accepts the authorization **at the current exchange rate** (#1). * The merchant cashes in the transaction at the **settlement-time exchange rate**. **Information – Assumptions** * Exchange rate of £100 = €150 at authorization time * Exchange rate of £100 = €160 at settlement time | # | Operation | Status | Amount | Balance | Authorized Balance | |:-: |- |:-: |-: |-: |-: | | | | | | 1000 | 1000 | | 1 | [Authorization](./transactions-lifecycle#authorization) | `A` | 150 | 1000 | **850** | | 2 | [Settlement](./transactions-lifecycle#settlement) | `S` | **160** | **840** | **840** | ## Refunded transaction The Refund is usually requested by the cardholder after funds have effectively been debited from the cardholder's wallet (due to a previous settlement). This is the case when returning a purchased article for instance. Please note a transaction can be partially refunded. * The cardholder makes a purchase (online or in a physical shop). * The cardholder's bank accepts the authorization (#1). * The merchant settles the payment (#2). | # | Operation | Status | Amount | Balance | Authorized Balance | |:-: |- |:-: |-: |-: |-: | | | | | | 1000 | 1000 | | 1 | [Authorization](./transactions-lifecycle#authorization) | `A` | 150 | 1000 | **850** | | 2 | [Settlement](./transactions-lifecycle#settlement) | `S` | 150 | **850** | 850 | If the merchant decides to refund the transaction **after settlement**. ### Accepted refund | # | Operation | Status | Amount | Balance | Authorized Balance | |:-: |- |:-: |-: |-: |-: | | | | | | 850 | 850 | | 3 | [Refund](./transactions-lifecycle#refunds) | `R` | -150 | 850 | 850 | | 4 | [Settlement](./transactions-lifecycle#settlement) | `S` | -150 | **1000** | **1000** | ### Refused refund Refund can be refused if the account is closed or if the card expired for instance. | # | Operation | Status | Amount | Balance | Authorized Balance | |:-: |- |:-: |-: |-: |-: | | | | | | 850 | 850 | | 3 | [Decline](./transactions-lifecycle#authorization-declined) | `I` | -150 | 850 | 850 | ## Accepted transaction, without settlement nor reversal * The cardholder makes a purchase (online or in a physical shop). * The cardholder's bank accepts the authorization (#1). * No settlements nor reversals occur. The authorization remains active, and **funds are blocked on the Authorized Balance**. | # | Operation | Status | Amount | Balance | Authorized Balance | |:-: |- |:-: |-: |-: |-: | | | | | | 1000 | 1000 | | 1 | [Authorization](./transactions-lifecycle#authorization) | `A` | 150 | 1000 | **850** | If no further action is taken, the authorization is considered as expired after 10 days (on the night of the 10th to 11th day). The Authorized Balance is then freed of this transaction. | # | Operation | Status | Amount | Balance | Authorized Balance | |:-: |- |:-: |-: |-: |-: | | 1 | - | - | - | 1000 | 1000 | When the authorization expires: * No [`cardtransaction.create`](./events-tx#card-transactions) webhooks are sent at all (because no additional operations are generated). * A [`balance.update`](/guide/wallets/events#balance-update) webhook is sent. ## Accepted transaction, refused afterwards * The cardholder makes a purchase (online or in a physical shop). * The cardholder's bank accepts the authorization (#1). * The transaction is then refused within one to two hours (#2). | # | Operation | Status | Amount | Balance | Authorized Balance | |:-: |- |:-: |-: |-: |-: | | | | | | 1000 | 1000 | | 1 | [Authorization](./transactions-lifecycle#authorization) | `A` | 150 | 1000 | **850** | | 2 | [Decline](./transactions-lifecycle#authorization-declined) | `I` | 150 | 1000 | **1000** | When an incident occurs on the scheme network, a previously approved authorization can fail to reach the acquirer. In such cases, the network catches the error and immediately triggers a transaction refusal. Treezor is informed within 2 hours, and the transaction initially authorized (`A`) will be declined (`I`). ## Direct settlement transaction * The merchant bypasses the authorization and proceeds to a "Direct Settlement" | # | Operation | Status | Amount | Balance | Authorized Balance | |:-: |- |:-: |-: |-: |-: | | | | | | 1000 | 1000 | | 1 | [Settlement](./transactions-lifecycle#settlement) | `S` | 150 | **850** | **850** | ## Convoluted example Consider the following scenario: * A user has a balance of €1,000. * The user orders 3 products at the same time on a marketplace (#1). * One €100 product, a second €100 product and one €300 product. * Later that day, the user tries to order a €700 product, but their authorized balance is insufficient (#2). * The next day, the seller of the €300 product informs him that this product is not available anymore and cannot fulfill the order (#3). * The user tries again to order that €700 product (#4). * The sellers of the €100 products and €700 product inform them that they shipped their respective products (#5, #6, #7). * One week later, the user returns one of the €100 products for a refund (#8, #9). ### Associated wallet operations | # | Operation | Status | Amount | Balance | Authorized Balance | |:-: |- | :-: |-: |-: |-: | | | | | | 1000 | 1000 | | 1 | [Authorization](./transactions-lifecycle#authorization) | `A` | 500 | 1000 | **500** | | 2 | [Decline](./transactions-lifecycle#authorization-declined) | `I` | 700 | 1000 | 500 | | 3 | [Reversal](./transactions-lifecycle#reversal) | `V` | 300 | 1000 | **800** | | 4 | [Authorization](./transactions-lifecycle#authorization) | `A` | 700 | 1000 | **100** | | 5 | [Settlement](./transactions-lifecycle#settlement) | `S` | 100 | **900** | 100 | | 6 | [Settlement](./transactions-lifecycle#settlement) | `S` | 100 | **800** | 100 | | 7 | [Settlement](./transactions-lifecycle#settlement) | `S` | 700 | **100** | 100 | | 8 | [Refund](./transactions-lifecycle#refunds) | `R` | -100 | 100 | 100 | | 9 | [Settlement](./transactions-lifecycle#settlement) | `S` | -100 | **200** | **200** | ### Explanations * \#2: Even though the user has a Balance of €1,000 at the time, their Authorized Balance is of €500, insufficient to authorize a €700 payment. * \#3: The unavailable €300 product is reversed, freeing up the Authorized Balance from €500 to €800. * \#4: The €700 purchase is now acceptable. * \#5,6,7: Each merchant of the marketplace receives an independent settlement. * \#9: Refund appears as negative-value settlements. --- --- url: /guide/cards/transactions-rules-engine.md description: >- Introduction to the Multi-Criteria Dynamic Card (MDC) feature, the rule engine that allows you to authorize or refuse card transactions based on rulesets. --- # Multi-Criteria Dynamic Card (MDC) The **Multi-Criteria Dynamic Card (MDC)** is a rules engine allowing you to authorize or refuse [Card Transactions](transactions) using powerful yet human-readable decision trees known as **Rulesets**. **Configuration – MDC is not enabled by default** You can request access to this feature by contacting your *Treezor Account Manager*. ## Use Cases The Multi-Criteria Dynamic Card rules engine is extremely flexible and has many use cases that can be categorized as follows. ### Controlling Card Transactions You can use MDC to restrict a Card usage to predefined scenarios. For instance, in the case of meal vouchers, you may allow payments in restaurants and food outlets while denying the use of the Card to buy other goods. ### Tracking Card Transactions MDC allows you to tag and group transactions by purpose. To do so, define Rulesets that match certain types of transactions. Once identified, you can categorize transactions and display them to your customers as you see fit. For instance, you can display in separate virtual Wallets transportation and food-related expenses. ## Flow The use of the Multi-Criteria Dynamic Card (MDC) feature can be summed up with the following diagram. ```mermaid sequenceDiagram autonumber You->>Treezor: Define Rulesets You->>Treezor: Assign Rulesets to Cards loop For each card transaction request Cardholder->>Treezor: Card Transaction Request Note over Cardholder,Treezor: Everytime a Card is used,
Treezor evaluates the assigned Rulesets
without having to contact your servers Treezor->>Cardholder: Immediate authorization or refusal Treezor-->>You: Webhook Note over Treezor,You: You are notified of the final decision end ``` ## Set up **Reading – Restricted API Documentation** Read all you need to know about managing Rulesets in the Support Center articles: * [Multi-Criteria Dynamic Card](https://treezor.zendesk.com/hc/en-us/articles/13231619074844-Multi-Criteria-Dynamic-Card-MDC) * [Managing Merchant Lists for MDC](https://treezor.zendesk.com/hc/en-us/articles/19177913508252-Managing-Merchant-Lists-for-MDC) ## Endpoints ### Rulesets | Endpoint | Description | |--- |--- | | [`/v1/mdc/{cardId}/rulesets`](/api-reference/api-endpoints.html#tag/Rulesets/attach-ruleset-to-card){target="\_self"} | Assign a Ruleset to a Card | | [`/v1/mdc/rulesets`](/api-reference/api-endpoints.html#tag/Rulesets/create-ruleset){target="\_self"} | Create a Ruleset | | [`/v1/mdc/{cardId}/ruleset/{rulesetId}/factsBalance`](/api-reference/api-endpoints.html#/Rulesets/get_v1_mdc__cardId__ruleset__rulesetId__factsBalance) | Retrieve the virtual balance of a Ruleset | | [`/v1/mdc/{cardId}/rulesets`](/api-reference/api-endpoints.html#tag/Rulesets/get-ruleset-from-card){target="\_self"} | Retrieve a Card Rulesets | | [`/v1/mdc/rulesets`](/api-reference/api-endpoints.html#tag/Rulesets/get-rulesets){target="\_self"} | Retrieve all Rulesets (which supports [cursor-based pagination](/guide/api-basics/pagination#cursor-based-pagination)) | | [`/v1/mdc/rulesets/{rulesetId}`](/api-reference/api-endpoints.html#tag/Rulesets/get-ruleset){target="\_self"} | Retrieve a Ruleset | | [`/v1/mdc/rulesets/{rulesetId}`](/api-reference/api-endpoints.html#tag/Rulesets/put-ruleset){target="\_self"} | Update a Ruleset | | [`/v1/mdc/rulesets/{rulesetId}`](/api-reference/api-endpoints.html#tag/Rulesets/disable-ruleset){target="\_self"} | Delete a Ruleset | ### Merchant Category Code Lists | Endpoint | Description | |--- |--- | | [`/v1/mdc/mccLists`](/api-reference/api-endpoints.html#tag/MCC%20Lists%20\(MDC\)/postMdcMccList){target="\_self"} | Create MCC List | | [`/v1/mdc/mccLists/{id}/codes`](/api-reference/api-endpoints.html#tag/MCC%20Lists%20\(MDC\)/importMdcMccListCodes){target="\_self"} | Import MCCs | | [`/v1/mdc/mccLists`](/api-reference/api-endpoints.html#tag/MCC%20Lists%20\(MDC\)/getMdcMccLists){target="\_self"} | Get all MCC Lists | | [`/v1/mdc/mccLists/{id}`](/api-reference/api-endpoints.html#tag/MCC%20Lists%20\(MDC\)/getMdcMccList){target="\_self"} | Get MCC List | | [`/v1/mdc/mccLists/{id}/codes/{mcc}`](/api-reference/api-endpoints.html#tag/MCC%20Lists%20\(MDC\)/checkMdcMccListCode){target="\_self"} | Check MCC Presence | | [`/v1/mdc/mccLists/{id}`](/api-reference/api-endpoints.html#tag/MCC%20Lists%20\(MDC\)/updateMdcMccList){target="\_self"} | Update MCC List | | [`/v1/mdc/mccLists/{id}/codes/{mcc}`](/api-reference/api-endpoints.html#tag/MCC%20Lists%20\(MDC\)/addMdcMccListCode){target="\_self"} | Add MCC to MCC List | | [`/v1/mdc/mccLists/{id}`](/api-reference/api-endpoints.html#tag/MCC%20Lists%20\(MDC\)/deleteMdcMccList){target="\_self"} | Delete MCC List | | [`/v1/mdc/mccLists/{id}/codes/{mcc}`](/api-reference/api-endpoints.html#tag/MCC%20Lists%20\(MDC\)/removeMdcMccListCode){target="\_self"} | Remove MCC from List | ### Merchant Id Lists | Endpoint | Description | |--- |--- | | [`/v1/mdc/midLists`](/api-reference/api-endpoints.html#tag/MID%20Lists%20\(MDC\)/postMdcMidList){target="\_self"} | Create MID List | | [`/v1/mdc/midLists/{id}/merchantIds`](/api-reference/api-endpoints.html#tag/MID%20Lists%20\(MDC\)/importMdcMidListCodes){target="\_self"} | Import MIDs | | [`/v1/mdc/midLists`](/api-reference/api-endpoints.html#tag/MID%20Lists%20\(MDC\)/getMdcMidLists){target="\_self"} | Get all MID Lists | | [`/v1/mdc/midLists/{id}`](/api-reference/api-endpoints.html#tag/MID%20Lists%20\(MDC\)/getMidMccList){target="\_self"} | Get MID List | | [`/v1/mdc/midLists/{id}/merchantIds/{mid}`](/api-reference/api-endpoints.html#tag/MID%20Lists%20\(MDC\)/checkMdcMidListCode){target="\_self"} | Check MID Presence | | [`/v1/mdc/midLists/{id}`](/api-reference/api-endpoints.html#tag/MID%20Lists%20\(MDC\)/updateMdcMidList){target="\_self"} | Update MID List | | [`/v1/mdc/midLists/{id}/merchantIds/{mid}`](/api-reference/api-endpoints.html#tag/MID%20Lists%20\(MDC\)/addMdcMidListCode){target="\_self"} | Add MID to MID List | | [`/v1/mdc/midLists/{id}`](/api-reference/api-endpoints.html#tag/MID%20Lists%20\(MDC\)/deleteMdcMidList){target="\_self"} | Delete MID List | | [`/v1/mdc/midLists/{id}/merchantIds/{mid}`](/api-reference/api-endpoints.html#tag/MID%20Lists%20\(MDC\)/removeMdcMidListCode){target="\_self"} | Remove MID from List | --- --- url: /guide/cards/faking-operations.md description: >- Learn how to simulate card transactions (including complete transaction life cycles) within the Sandbox environment for development and API integration testing. --- # Emulation Emulation features are only available in the `Sandbox` [environment](/guide/api-basics/environments). **Tip – You can also rely on webhooks** For operations that cannot be emulated in Sandbox, [webhook examples](events) are provided. ## Card Transactions You can emulate [Card Transactions](./transactions) using the following request. ### Parameters | Attribute | Type | Description | | --- | --- | --- | | `publicToken` | string | The public token of the Card to use for the Card Transaction. | | `transLink` | string | A unique reference used to associate the Card Transaction with a `paymentId`. Must be `100000000000000` or greater. | | `paymentStatus` | string | The type of CardTransaction, which for simulation purposes can be `A` or `S`. See [list of values](./transactions#statuses-paymentstatus). | | `date` | string | The date of the CardTransaction, as seen in the `authorizationIssuerTime` attribute. | | `amount` | number | The amount of the CardTransaction, as seen it the `paymentAmount` and `paymentLocalAmount` attributes. | | `mcc` | string | The Merchant Category Code for this CardTransaction, allowing you to check [your Card MCC restrictions](./modification#mcc-restrictions). | | `merchantId`  | string | The Merchant's ID for this CardTransaction, allowing you to check [your Card MID restrictions](./modification#mid-restrictions). | | `merchantName`  | string | The name of the merchant. | **Tip – You can emulate a complete flow** To emulate a [complete flow](./transactions-lifecycle), set a `paymentStatus` = `A` followed by `S` while specifying the same `transLink` for both requests. Learn more about the different transaction flows in the [Transaction examples](./transactions-examples) article. ### Request ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/simulation/cardtransactions' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ --data-raw '{payload}' ``` ::: Here is a `{payload}` example: ::: code-group ```json [JSON] { "publicToken": "103020378", "date": "2022-02-12 13:00:00", "amount": 15.90, "mcc": "8574", "merchantId": "3256", "merchantName": "Merchant Name", "paymentStatus": "A", "paymentCode": "100000000000004" } ``` ::: The request returns a `201` HTTP Status Code without any content and sends a [`cardtransaction.create`](./events-tx#cardtransaction-create) webhook. **Note – Disclaimers about simulating card transactions** * No Wallet balance update: sends a [`balance.update`](/guide/wallets/events#balance-update) webhook with `0` values. * No refunds and negative amount settlements support yet. ## Simulate Card Transaction Authentication (SCA) The Treezor API allows you to simulate the [authentication (SCA)](/guide/cards/transactions-authentication) process of an online card transaction. With these dedicated endpoints, you can trigger the relevant webhooks. This is a 2-step process: 1. Simulate the authentication of an online card transaction for a given card. 2. Submit the result of the authentication to obtain the final result from Treezor. Optionally, you can also simulate the cancellation of the authentication process. ```mermaid sequenceDiagram autonumber participant ag as You participant s as Treezor participant se as Authentication Server
simulator ag->>se: Simulate authentication request: POST /simulation/auth-requests se->>s: Sends OOB information s->>s: Save authentication request with authenticationRequestId s->>ag: card3DSv2Authentication.create
with authenticationRequestId alt Authentication canceled ag->>se: POST /simulation/authrequests/{authRequestId}/cancel se->>s: Communicate final authentication result end ag->>s: PUT /auth-requests/{authRequestId}/result s->>ag: card3DSv2Authentication.update
with final result ``` **Prerequisites – Enroll the user card for OOB authentication first** The card must be enrolled for OOB in order to simulate an authentication. [`/v1/cards/{cardId}/authentication-methods`](/api-reference/api-endpoints.html#tag/Card%203DSecure%20Enrollment%20\(SCA\)/postAuthMethods){target="\_self"} ### Simulate an authentication This request simulates the authentication of an online card transaction for a given card. #### Parameters | Attribute | Type | Description | | --- | --- | --- | | `cardId` | integer | The unique identifier of the Card for which you want to simulate card transaction authentication. | | `merchantName` | string | The name of the merchant processing the transaction for the simulated authentication. | | `paymentAmount` | number | The amount of the transaction for the simulated authentication. | | `paymentCurrency` | string | The currency of the transaction for the simulated authentication, in the ISO 4217 format. | | `merchantAppRedirectURL` | string | As defined in the 3DS 2.2 specification, links back to the merchant application from an OOB app. | #### Request example Endpoint: [`/simulation/auth-requests`](/api-reference/api-endpoints.html#tag/Card%20Transactions%20Authentication%20\(SCA\)/simulateAuthRequest){target="\_self"} ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/simulation/auth-requests' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ --d '{payload}' ``` ::: Here is a `{payload}` example: ::: code-group ```json [JSON] { "cardId": 12345, "merchantName": "Tree Company", "paymentAmount": 10.01, "paymentCurrency": "EUR", "merchantAppRedirectURL": "https://your.app.com/redirect" } ``` ::: Treezor sends a [`card3DSv2Authentication.create`](/guide/cards/events-tx#card3DSv2authentication-create) webhook. From there, you can either: * [Simulate a canceled authentication](#simulate-a-canceled-authentication) * [Submit the authentication result](#submit-the-authentication-result) ### Simulate a canceled authentication If the cardholder cancels the authentication process before it can be completed (i.e., leaves the application), the server indicates to Treezor that the authentication couldn't be carried out. This information is available to you after you've submitted the authentication result through the [`card3DSv2Authentication.update`](/guide/cards/events-tx#card3DSv2authentication-update) webhook `authenticationFinalResult`. Treezor provides a dedicated endpoint to simulate this situation. #### Request example Endpoint: [`/simulation/auth-requests/{authRequestId}/cancel`](/api-reference/api-endpoints.html#tag/Card%20Transactions%20Authentication%20\(SCA\)/simulateAuthRequest){target="\_self"} The `authRequestId` is available in the [`card3DSv2Authentication.create`](/guide/cards/events-tx#card3DSv2authentication-create) webhook. ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/simulation/authrequests/{authRequestId}/cancel' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' ``` ::: Treezor answers with an HTTP 204. You can now [submit the authentication result](#submit-the-authentication-result). ### Submit the authentication result Whether you use the cancellation simulation or not, you must submit the authentication result to Treezor, so that Treezor can inform you of the final authentication result with the relevant webhook. #### Parameters | Attribute | Type | Description | | --- | --- | --- | | `authenticationResult` | integer | The result of your [end user authentication](/guide/cards/transactions-authentication.html#authentication-result), which can be: `OK`, `KO_TECHNICAL`, `KO_AUTH_FAILED`, or `FALLBACK`. | #### Request example Endpoint: [`/v1/auth-requests/{authRequestId}/result`](/api-reference/api-endpoints.html#tag/Card%20Transactions%20Authentication%20\(SCA\)/putAuthRequestResult){target="\_self"} ::: code-group ```bash [CURL] curl -X PUT '{baseUrl}/v1/auth-requests/{authRequestId}/result' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content: application/json' \ -d '{payload}' ``` ::: Here is a `{payload}` example: ::: code-group ```json [JSON] { "authenticationResult": "OK" } ``` ::: Treezor sends the [`card3DSv2Authentication.update`](/guide/cards/events-tx#card3DSv2authentication-update) webhook with the `authenticationFinalResult` set as follows. | Submitted `authenticationResult` | `authenticationFinalResult` | | --- | --- | | `OK` | `SUCCESS` | | `KO_AUTH_FAILED` | `UNAUTHENTICATED` | | `KO_TECHNICAL` | `ERROR` | | `FALLBACK` | `FALLBACK` | If you've simulated a cancellation by the server, the `authenticationFinalResult` is set to `ERROR`. --- --- url: /guide/cards/transactions.md description: >- Get a foundational understanding of the Treezor API card transaction object. Includes key attributes, JSON structure, and related endpoints list. --- # Introduction A Card Transaction represents a step of a card payment made with a Treezor-issued Card (e.g., authorization, settlement, or refund). They share the same `paymentId` value when generated by the same card payment. ## Key attributes Below are some of the most important Card Transaction attributes. | Attribute | Type | Description | | --- | --- | --- | | `cardtransactionId` | string | The unique identifier of the card transaction. | | `cardId` | string | The unique identifier of the card used for the transaction. | | `walletId` | string | The unique identifier of the Wallet the card is attached to. | | `walletCurrency` | string | The currency of the Wallet, ISO 4217 3-digit code. | | `merchantId` | string | The [MID](/guide/overview/glossary#merchant-identifier-number-mid) | | `merchantName` | string | The name of the merchant. | | `merchantCountry` | string | The country of the merchant. ISO 3166 3-letter code (except of the US which is a two-letter code) | | `publicToken` | string | The token of the card (a way to identify a card without knowing or communicating its [PAN](/guide/overview/glossary#primary-account-number-pan)) | | `paymentId` | string | The unique identifier of the card payment (or attempted payment), allowing you to follow the card transaction life cycle. | | `paymentAmount` | string | The amount of the transaction, always expressed in Euros. | | `paymentCurrency` | string | The local currency in which the transaction was made, ISO 4217 3-digit code. | | `paymentLocalAmount` | string | The amount of the transaction in the local currency. | | `paymentLocalDate` | string | The local date on which the transaction occurred. | | `paymentLocalTime` | string | The local time at which the transaction occurred. | | `paymentCountry` | string | Country in which the transaction occurred, ISO 3166 3-letter code. | | `paymentStatus` | string | The general status of the transaction. **See [table](#statuses-paymentstatus) below** | | `posCardholderPresence` | string | Describes more precisely how the card was used. **See [list](#cardholder-presence-poscardholderpresence) below** | | `posCountry` | string | Country of the point of sale, ISO 3166 3-digit code (e.g., `250` for France). | | `posTerminalId` | string | The id of the terminal used for the transaction. | | `posCardPresence` | string | Indicates whether the card was physically present during the transaction: `0` – The card was **present**`1` – The card was **absent** `9` – The card presence **cannot be determined** | | `panEntryMethod` | string | How the [PAN](/guide/overview/glossary#primary-account-number-pan) was captured by the merchant. **See [list](#pan-entry-method-panentrymethod) below** | | `authorizationNote` | string | Contains detailed information regarding a declined card transaction. **See [Authorization notes](/guide/cards/authorization-notes)** for examples. | | `authorizationResponseCode` | string | The precise status of the transaction. **See [Authorization response codes](/guide/cards/authorization-notes#authorization-response-codes)** | | `authorizationIssuerId` | string | The transaction identifier as generated by the payment processor. | | `authorizedBalance` | string | The [Authorized Balance](/guide/overview/glossary#balance) of the wallet after the transaction. | | `mcc` | string | The [Merchant Category Code (MCC)](/guide/overview/glossary#merchant-category-code-mcc). **A MCC valued to `6011` indicates a withdrawal**. Some MCC are prohibited for [anonymous electronic money](/guide/wallets/introduction#electronic-money-wallet-type-9), such as: money transfer, money order, foreign currency, liquid and cryptocurrency assets, lotteries, on-line gambling, betting, etc. | | `acquirerId` | string | The identifier of the merchant's bank (acquirer) in the form of 5 to 6 digits. | | `is3DS` | string | Indicates whether [3DSecure](/guide/overview/glossary#_3ds-3d-secure) was used for authentication: `1` – 3DS was **used**`0` – 3DS was **not used** | | `totalLimitPaymentYear` | string | The related Card yearly spent amount. **This is used with [Cards Limits](/guide/cards/restrictions-limits#payment-withdrawal-limits)** | | `totalLimitPaymentMonth` | string | The related Card monthly spent amount. **This is used with [Cards Limits](/guide/cards/restrictions-limits#payment-withdrawal-limits)** | | `totalLimitPaymentWeek` | string | The related Card weekly spent amount. **This is used with [Cards Limits](/guide/cards/restrictions-limits#payment-withdrawal-limits)** | | `totalLimitPaymentDay` | string | The related Card daily spent amount. **This is used with [Cards Limits](/guide/cards/restrictions-limits#payment-withdrawal-limits)** | | `totalLimitPaymentAll` | string | The related Card lifetime spent amount. **This is used with [Cards Limits](/guide/cards/restrictions-limits#payment-withdrawal-limits)** | | `totalLimitAtmWeek` | string | The related Card weekly ATM withdrawal amount. **This is used with [Cards Limits](/guide/cards/restrictions-limits#payment-withdrawal-limits)** | | `totalLimitAtmDay` | string | The related Card daily ATM withdrawal amount. **This is used with [Cards Limits](/guide/cards/restrictions-limits#payment-withdrawal-limits)** | | `totalLimitAtmAll` | string | The related Card lifetime ATM withdrawal amount. **This is used with [Cards Limits](/guide/cards/restrictions-limits#payment-withdrawal-limits)** | | `cardDigitalizationExternalId` | string | The digital payment token identifier (only present if payment was made with a digital token such as Apple Pay or Google Pay for example). | | `localMerchantId` | string | Indicates the merchant's SIREN or SIRET if available. | Please note that when a CardTransaction produces a [Transaction](/guide/transfers/events#transaction-create) object, the `CardTransaction.id` is reflected in the `Transaction.foreignId` attribute. **Caution – Data formats may differ** The date, time, and country formats are different from [Treezor usual API format](/guide/api-basics/data-format) because Treezor displays the information as provided by the Card processor. **API – API Reference available** For a complete list of Card Transaction attributes, check the [Card Transactions](/api-reference/api-endpoints.html#tag/Card%20Transactions){target="\_self"} section of the API Reference. ### Statuses (`paymentStatus`) This attribute allows you to identify the type of transaction, as Card payments almost always go through [many steps](./transactions-lifecycle). | | Description | [Current Balance](/guide/overview/glossary#balance) impact | [AuthorizedBalance](/guide/overview/glossary#balance) impact | Note | |:---:|---|:---:|:---:|----| | `A` | [Authorization accepted](./transactions-lifecycle#authorization) | | | Authorization request accepted by Treezor | | `R` | [Refund](./transactions-lifecycle#refunds) | | | Refunded authorization | | `S` | [Settled](./transactions-lifecycle#settlement) | | Generally no | Can be:Refund is successful and the buyer has been refundedPayment is successful and the merchant has been paidMoneySend is successful and the cardholder's bank account has been credited | | `M` | [MoneySend](./transactions-lifecycle#money-send) | | | MoneySend authorization | | `C` | [Cleared](./transactions-lifecycle#authorization) | | | Settlement received without a previous matching authorization request. This happens when the payment terminal approves the transaction offline. The resulting asynchronous processing can take several days. | | `I` | [Declined](./transactions-lifecycle#authorization) | | | Authorization refused | | `V` | [Reversed](./transactions-lifecycle#reversed) | | | Authorization reversed. This may happen when an automated gas station authorized an amount greater than the actual amount of [fuel pumped](/guide/cards/transactions-examples#gas-station-transaction). | Negative amounts and Non-Euro Settlement (`S`) can affect the Authorized Balance. See [Non-Euro example](/guide/cards/transactions-examples#non-euro-transaction) and [Negative amount settlement example](/guide/cards/transactions-examples#accepted-refund). ### PAN Entry Method (`panEntryMethod`) This attribute informs you of how the [PAN](/guide/overview/glossary#primary-account-number-pan) was *provided to* or *accessed by* a merchant for a transaction. | | Description | |:-: |- | | `0` | Unknown or no terminal | | `1` | Manual Key Entry | | `2` | Partial Magnetic Stripe Read | | `3` | Barcode | | `4` | OCR | | `5` | Chip (contact interface) | | `7` | Chip (contactless interface) | | `10` | Credential-on-file (e.g., one-click purchase) | | `79` | PAN & Expiration date entered by acquirer | | `80` | Magnetic Stripe fallback (The terminal was not able to read the chip) | | `81` | e-commerce | | `91` | Contactless magstripe mod | ### Cardholder Presence (`posCardholderPresence`) This attribute indicates whether the cardholder was present at the point of sale and provides details if they were not present. | | | Cardholder Presence | Description | |:---: |:---: |--- |--- | | `0` | | Present | Cardholder present | | `1` | | Not-present | Unspecified | | `2` | | Not-present | Mail/facsimile order | | `3` | | Not-present | Phone/ARU order | | `4` | | Not-present | Standing order/recurring transactions | | `5` | | Not-present | Electronic order (home computer, internet, mobile phone, PDA) | | `6` | | Not-present | Installment transaction (similar to recurring but fixed number of installments) | | `9` | | Unknown | Unknown | ### 3DS Exemption Type (`3dsExemptionType`) | | Description | |:---------:| ----------- | | `0` | Transaction not exempt from SCA or unknown. | | `1` | Transaction is exempt from SCA due to being on an exempt Merchant Category Code (MCC).(Acquirer did not provide an SCA exemption indicator.)(As of 11/02/2020, exempt MCCs are: 4111, 4112, 4131, 4784, 7523) | | `2` | Contactless transaction under low-value limits. | | `3` | E-commerce transaction under low-value limits. | | `4` | Recurring/installment transaction. | | `5` | Credit. Visa expects credit transactions to be out-of-scope. | | `6` | Mail Order, Telephone Order or other cardholder-not-present transaction (except recurring which is above) which is excluded from SCA requirements. | | `7` | Acquirer is exempt (located in a country outside of the EEA or UK, so do not fall under the PSD2 jurisdiction). | | `8` | Not a transaction under PSD2 rules | | `9` | Reserved for a possible future detected exemption | | `A` | Acquirer transaction risk analysis. | | `C` | Secure corporate payment. | | `D` | SCA delegation. | | `M` | Merchant initiated transaction. | | `O` | Authentication outage exemption. | | `R` | Recurring payment. | | `T` | Trusted merchant. | | `V` | Low value payment. | ## Card Transaction object ::: code-group ```json [JSON] { "cardtransactionId":"2xxx88", "cardId":"1xx9", "walletId":"9xx32", "walletCurrency":"978", "merchantId":"2288442AO1EOAZQ", "merchantName":"REGULARISATION TVA", "merchantCity":"330768976257 ", "merchantCountry":"FRA", "paymentLocalTime":"94902", "publicToken":"58xxxx220", "paymentAmount":"180.00", "paymentCurrency":"978", "fees":"0.00", "paymentCountry":"FRA", "paymentId":"1xxx63", "paymentStatus":"A", "paymentLocalAmount":"180.00", "posCardholderPresence":"0", "posPostcode":"5008", "posCountry":"507", "posTerminalId":"13061803", "posCardPresence":"4", "panEntryMethod":"1", "authorizationNote":"", "authorizationResponseCode":"0", "authorizationIssuerId":"2354807787", "authorizationIssuerTime":"2017-10-16 10:49:03", "authorizationMti":"100", "authorizedBalance":"18186.65", "limitAtmYear":"0", "limitAtmMonth":"0", "limitAtmWeek":"100", "limitAtmAll":"0", "limitPaymentYear":"0", "limitPaymentMonth":"5000", "limitPaymentWeek":"5000", "limitPaymentDay":"5000", "limitPaymentAll":"0", "totalLimitAtmWeek":"0.00", "totalLimitAtmDay":"0.00", "totalLimitAtmAll":"0.00", "totalLimitPaymentYear":"0.00", "totalLimitPaymentMonth":"1980.00", "totalLimitPaymentWeek":"1980.00", "totalLimitPaymentDay":"180.00", "totalLimitPaymentAll":"0.00", "cardDigitalizationExternalId": "0", "mccCode":"5734", "acquirerId": "12653", "is3DS": null, "merchantAddress": "", "paymentLocalDate": "", "3dsExemptionType": "", "optimizedMerchantName": "", "merchantLogo": "", "merchantCategory": "", "transactionSubtype": "", "receiverData": "", "senderData": "", "transactionTypeIdentifier": "", "localMerchantId": "" } ``` ::: ## Endpoints | Endpoint |[Scope](/guide/api-basics/authentication#available-scopes) | | --- | --- | | [`/v1/cardtransactions`](/api-reference/api-endpoints.html#tag/Card%20Transactions/readCardTransaction){target="\_self"} Search Card transactions | `read_only` | | [`/v1/cardtransactions/{cardTransactionId}`](/api-reference/api-endpoints.html#tag/Card%20Transactions/getCardtransaction){target="\_self"} Retrieve a specific transaction, using its `id` | `read_only` | | [`/v1/auth-requests/{authenticationRequestID}/result`](/api-reference/api-endpoints.html#/) Answer to a [Strong Customer Authentication](/guide/strong-customer-authentication/introduction) request | `read_write` | **Reading – Find out more about Transactions** * [Transactions lifecycle](/guide/cards/transactions-lifecycle) * [Transactions examples](/guide/cards/transactions-examples) * [Transactions authentication](/guide/cards/transactions-authentication) ## Object relations diagram ```mermaid flowchart TD CardTransaction(Card Transaction) Authorization(Authorization) AuthorizationExternal(External Authorization) AuthorizationRuleEngine(Transaction Rules Engine) Reversal(Reversal) Settlement(Settlement) Refund(Refund) CardTransaction --- Authorization CardTransaction --- Reversal CardTransaction --- Settlement CardTransaction --- Refund Authorization -.- AuthorizationExternal Authorization -.- AuthorizationRuleEngine class CardTransaction MermaidNeutralAlternate class AuthorizationExternal MermaidNeutral class AuthorizationRuleEngine MermaidNeutral click CardTransaction "/guide/cards/transactions-lifecycle.html" click AuthorizationExternal "/guide/cards/transactions-external-validation.html" click AuthorizationRuleEngine "/guide/cards/transactions-rules-engine.html" click Authorization "/guide/cards/transactions-lifecycle.html#authorization" click Reversal "/guide/cards/transactions-lifecycle.html#reversal" click Settlement "/guide/cards/transactions-lifecycle.html#settlement" click Refund "/guide/cards/transactions-lifecycle.html#refunds" ``` **Tip – Diagram is interactive** Click on the diagram nodes to access the relevant documentation. --- --- url: /guide/cards/transactions-external-validation.md description: >- Customize the criteria to validate or decline card payments with the external validation feature. --- # Transactions external validation This feature allows you to validate or refuse end users payments, in real time and based on your custom criteria. **Information – Treezor offers its own [Transaction Rules Engine](/guide/cards/transactions-rules-engine)** Therefore, you no longer need to implement your criteria with the external validation. Contact Treezor to find out which option works best for you. ## General process The external validation process works as follows. 1. **Authorization Request** – The end user makes a purchase with a [Card](creation). 2. **External Validation Request** – Treezor sends you an HTTP Request to a predefined endpoint of your own REST API. 3. **External Validation Response** – Your software makes a decision based on your own criteria and returns the decision in the HTTP Response. * If you refuse, the transaction is **declined**. * If you fail to answer within the allowed time frame, the transaction is **declined**. * If you accept, Treezor handles the [Authorization](transactions-lifecycle#authorization) request like it would normally ([Authorized Balance](/guide/overview/glossary#balance) verifications, [MID/MCC restrictions](/guide/cards/restrictions-limits#mcc-restrictions), etc.). 4. A [`cardtransaction.create`](events-tx#cardtransaction-create) webhook is sent. It includes the `requestId` of the External Validation request. **Information – Your response must be provided within an allotted time frame** The time frame is defined on a per-client basis. In the absence of a response in the allotted time, the Authorization is automatically declined. ## Request example A POST request is sent to your own API endpoint, as defined during the subscription to this feature. ::: code-group ```json [JSON] { "request_id": "e03df174-ff01-571c-8677-e52af53affda", // UUIDv5 "card_public_token": "988927734", // card Public Token "request_date": "2021-04-20T10:29:44+00:00", // Date/time of sending (RFC 3339 format) "payment_amount": { "value": 17.01, // Payment amount, including all fees, float. Positive for a Debit, Negative for a Credit. "value_smallest_unit": 1701, // Payment amount, including all fees, in the smallest unit of associated currency "currency_code": "978" // Billing currency - ISO 4217 3 digit }, "payment_local_amount": { "value": 7.01, // Payment amount in local currency, float "value_smallest_unit":701, // Payment amount in local currency, in the smallest unit of associated currency "currency_code": "978" // Local currency - ISO 4217 3 digit }, "payment_local_time": "145958", // Local time of transaction - “hhmmss” "payment_local_date": "20210420", // Local date of transaction - "yyyymmdd" "local_day_of_week": 5, // local day of week: 1,2,3,4,5,6,7 with 1 being Monday "authorization_issuer_id": "928257521", // Transaction Unique ID from the Card Processor "merchant_data" : { "id": "000980200909995", // Merchant ID "name": "PAYPAL ", // Merchant Name "city": "PARIS", // Merchant City "country": "FRA", // Merchant Country - ISO 3-alpha country code "mcc": "4512", // Merchant Category Code "acquirer_id": "06004441", // Acquirer ID } } ``` ::: ## Response example All requests must be answered to. #### Approve the transaction If you approve the card transaction, you can answer with the following JSON response. ::: code-group ```json [JSON] { "response_date": "2021-04-20T10:29:49+00:00", // Date/time of your decision (RFC 3339 format) "response_code" : "AUTHORIZED", // Your decision "response_id": "e03df174-ff01-571c-8677-e52af53affda" // Unique response ID that you have generated (It can be a signature of the provided requestId) } ``` ::: #### Refuse the transaction If you refuse the card transaction, you can answer with the following JSON response. ::: code-group ```json [JSON] { "response_date": "2021-04-20T10:29:49+00:00", // Date/time of your decision (RFC 3339 format) "response_code" : "DECLINED", // Your decision, other values are available in the list below "response_id": "e03df174-ff01-571c-8677-e52af53affda" // Unique response ID that you have generated (It can be a signature of the provided requestId) } ``` ::: ## Response Codes (`responseCode`) You can answer to an External Validation request with the following codes: | | Code | | :---: | --- | | | `AUTHORIZED` | | | `DECLINED` | | | `DECLINED_CARD_UNKNOW` | | | `DECLINED_DATETIME_INVALID` | | | `DECLINED_DUE_TO_REGULATORY_RULES` | | | `DECLINED_INSUFFICIENT_FUNDS` | | | `DECLINED_INSUFFICIENT_FUNDS_WITHDRAWAL_LIMIT_REACHED` | | | `DECLINED_LOCAL_CURRENCY_INVALID` | | | `DECLINED_MCC_INVALID` | | | `DECLINED_MERCHANTID_INVALID` | | | `DECLINED_MERCHANT_CITY_INVALID` | | | `DECLINED_MERCHANT_COUNTRY_INVALID` | **Information – Other responses may occur** Any other response will be considered as `DECLINED`. ## Special case of Balances not managed by Treezor In the use case where you manage the Balance and Authorized Balance yourself: * No funds withholding will take place, as Treezor doesn't manage the funds * At [settlement](transactions-lifecycle#settlement), the funds are debited or credited on your main Wallet (which should be provisioned accordingly). --- --- url: /guide/dashboard/cards.md description: >- Let your team provide support regarding your end users cards using the Treezor Dashboard. --- # Cards The Cards are the payment cards you issue for your end users, either in a virtual or physical form. They can be directly created and managed from your Dashboard. ## Accessing Cards You may access card information by: * Taking advantage of the main *Search toolbar* * Navigating the *Profile Boards* view, *Cards* tab once a user is selected ### Search toolbar The Dashboard main toolbar provides a series of search fields, most of them being based on user attributes. Among those fields, the **Card Token** one takes into account the `cardId` or the `publicToken` of the [Card](/guide/cards/introduction). **Tip – Find out more about the filters** You may read the [Search toolbar](/guide/dashboard/users#search-toolbar) article to learn everything you need to know about the search fields. Once you've clicked on the "Search" button for a given card, you are redirected to the corresponding user Profile, *Cards* tab. ### Profiles Board view, Cards tab Once you've accessed a user Profile, you may click on the *Cards* tab in order to view all the cards attached to the user. The view is divided into two sections: * **Cards** – On the left-hand side, you can navigate and manage the user cards. * **Transactions** – On the right-hand side, you can view the transactions of the selected card. When the card is not activated yet, this section contains the "Activate Card" button. ## Navigating the Card information ### Card preview In the *Cards* tab, Cards section, the card preview is displayed. When several cards are available, you can navigate by using the numbers below the card. The following card information is available in the preview: card type (whether it is virtual, physical or converted to virtual), cardholder's name, card status, partially masked [PAN](/guide/overview/glossary#primary-account-number-pan), expiration date, unique identifier and public token. The following commands can be available (depending on the situation): * **Create card** – Takes you through the card creation process, where you define the card main information and select the restrictions and limits. * **Block Card** – Opens the *Card settings* popup, [*Block Card*](#block-a-card) tab * **More** – Provides access to the following options: * Card settings – Opens the *Card settings* popup. This popup may be read-only if the card is in an inactive status. * Wallet redirect – Switches the view to the *Wallets* tab, with the wallet to which the card is attached displayed. * **Details** – Switches to the detailed fields of the card, providing additional fields and renewal information if relevant. The card display is different depending on its status: | Status | Description | Card display | |--- | --- | --- | | **Active** | Cards that have been activated. | | | **Inactive** | Cards that have not been activated yet, or which have been locked or blocked (i.e., exceeded the number of PIN attempts). | | | **Blocked** | Cards that are either declared as lost or stolen.| | | **Expired** | Cards that are either past their expiration date or destroyed. | | | **Frozen** | Cards that have been blocked by Treezor. | | ### Transactions section Once a card is selected, the corresponding transactions (if any) are displayed in the right-hand side of the view. The list of transactions can be sorted, filtered and customized as you see fit. |      | Option | Description | |:---: |--- |--- | | | Date range | Allows you to define after (From) and/or before (To) which dates the transactions are considered. Any transaction whose authorization date is not in the defined time frame is filtered out. | | | Amount range | Allows you to define the minimum and maximum amounts for the transactions to be considered. Any transaction outside the frame is filtered out. | | | Merchant Id | Allows you to enter a Merchant Id. Only transactions with this MID are then displayed. | | | Payment Type | Allows you to select whether to display only withdrawals or payments (i.e., online, in-person and NFC). | | | Payment Status | Allows you to select the transactions to be displayed based on their Status (e.g., Accepted, Declined, etc.) | | | Clear | Resets all the sorting and filtering options. | | | Organize columns | Opens a panel that allows you to select which columns to display and in which order (drag & drop). You may save your changes or reset to the initial display by using the corresponding buttons. | ## Creating a Card You can create a new card for a user from the *Profile Boards* view, *Cards* tab. Please note: * You need to create a [Wallet](./wallets) beforehand. * Options to create virtual or physical cards depend on your card program. The *Create card* dialog box corresponding to your selection is displayed. Once you have selected the wallet and the card program, you can click next to proceed. In the next step, the default limits and options from your card program are displayed. You can adjust them before creating the card. Once this done, you can click on the "Create card" button to complete the creation. ## Creating Cards in bulk You can order Cards in bulk using the *Bulk Cards* view. At the end of the process, the Cards will be sent to a unique address. Click on the "Create bulk cards" button in the upper right corner of the view to start the process and follow the steps. | Step | Description | |--- |--- | | **Cards quantity** | Indicate the number of cards you wish to create. | | **Card program** | Select your card program (`cardPrint`) and whether to create physical or virtual cards. Options available depend on your card program. | | **Perms group** | Define your card options by activating the toggles:**Online** – Enables e-commerce payments**NFC** – Enables contactless payments**ATM** – Enables ATM withdrawals **International** – Enables usage outside of the cardholder's country | | **Wallet & User Id** | Cards are always attached to a user and a wallet. Define:**The Wallet** – Either a new wallet that will be created at the same time as the card (select the type) or an existing one (enter the Id)**The User(s)** – A unique user Id (e.g., all your cards are attached to a Master Wallet) or multiple users (users will be automatically generated when the cards are created). You may need to select a [distribution country](/guide/users/introduction#distribution-country-distributioncountry) as well. | | **Name** | Define whether the user name is displayed on the card. This is only possible if you have a unique user Id in the previous step. | | **Options** | Define additional options for your card:**Logo Id** – If provided with your Card Program**Package reference** – If provided with your Card Program**Design code reference** – If you have multiple card designs.**Restriction groups** – If some predefined restriction groups have been created, you can already define MCC, MID and Country restrictions for your cards.**Limits** – Define limits to apply to your set of cards. | | **Create** | Review the bulk card creation to make sure everything is in order before validating the order. | Once your order complete, you are redirected to the *Bulk orders list*, in which you can follow the status of the order. ### Bulk orders list The main display of the *Bulk Cards* view lists all your previous orders, whether they have succeeded or not. You can track the progress of a Bulk Card creation using the dedicated interface below. For each bulk creation, key information such as the Order Id and Creation Date are available. Please note that the GPS Id stands for your Card Program card print. The following commands are available. |       | Action | Description | |:---: |--- |--- | | | View error report | Downloads the error report in the CSV format. | | | View creation details | Opens the Bulk Card creation details popup. | | | Download creation details | Downloads the creation details in the CSV format. | ## Managing Cards You have the ability to manage existing cards from the *Profile Boards* view, *Cards* tab for any selected user. Most options are available in the *Card Settings* popup, available upon clicking on the "More" button and selecting the "Card settings" option. You'll have the ability to: * [**Activate the Card**](#activate-a-card) * [**Enroll the Card for 3D Secure**](#enroll-card-for-3ds) * [**Update the Card options**](#update-card-options) and [**Limits**](#update-card-limits) * [**Manage Card restrictions**](#manage-card-restrictions) (MCC, MID and Country) * [**Block the Card**](#block-a-card) – Disable and enable the card use on a temporary basis or declare the card as stolen or lost * [**Unblock PIN**](#unblock-pin-code) – Unblock a card locked due to too many PIN attempts * [**Unblock CVC**](#unblock-cvc) – Unblock a card locked due to too many CVC attempts * [**Convert to Physical**](#convert-a-virtual-card-to-physical) – Create a physical version or a Virtual Card * [**Manage Digitized Cards**](#manage-digitized-cards) – Suspend, unsuspend, and delete digitized cards. ### Activate a Card As a security measure, all Cards are issued in an inactive state to ensure that a Physical Card is not usable before the cardholder receives it. Inactive cards can’t be used to make any type of payment or withdrawal. Cards must therefore be activated once before they can be used, this can be done using the "Activate" button available in the right-hand side of the user Profile, *Cards* tab. The following confirmation popup will be displayed for you to activate the card. **Best practice – Enhance the customer experience by having cardholders activating their cards** Cardholders are usually able to activate their Card by themselves using a code (`publicToken`) printed on their Card and entering it in your App. ### Enroll Card for 3DS [3D Secure](/guide/overview/glossary#_3d-secure-3ds) is a protocol designed to add an additional security layer to online card payments. Cards must be registered with the following methods to accept secure online payments. | Method | Description | | --- | --- | | **[SMS method](/guide/cards/creation#enrolling-a-card-for-3d-secure)** | The cardholder receives a code on their mobile phone when an authentication is required for the online payment. This code is unique for each payment and needs to be entered on the merchant's website or mobile application when prompted. | | **[Out of Band (OOB)](/guide/strong-customer-authentication/securing-endpoints#enrolling-to-out-of-band-authentication)** | The cardholder must go through a strong customer authentication through their payment application. | **Tip – Cards can be enrolled with both methods at the same time** This allows you to request a fallback to the SMS method if the Out of Band authentication is not possible during a card transaction. To enable 3DS, go to the *Card Settings* popup, click on the "Enroll 3DS" button available in the *Card* section and select the enrollment options that suit your need. **Caution – Users must have a mobile phone number** If they don't, update the [User](/guide/dashboard/users) with a mobile phone number. ### Update Card options The card options allow you to define the conditions in which a card can be used. In the *Card Settings* popup, *Settings* tab, *Options* section, the following settings are available for you to update: * **Online** – Enables e-commerce payments * **NFC** – Enables contactless payments * **ATM** – Enables ATM withdrawals * **International** – Enables usage outside of the cardholder's country ### Update Card limits You can modify both the **Payment limits** and **Withdrawal (ATM) limits** of a Card in the *Card settings* popup, *Limits* tab. **Tip – Rules about limit setting** * Setting a limit value to 0 deactivates the limit. * For each category, at least one of `Daily`, `Weekly` or `Monthly` **must** be > 0. * If two limits conflict with each other, the lowest will always be authoritative. #### Configurable limits Below is the list of configurable limits. | Limit type | Limit | Description | |--- |--- |--- | | Withdrawal | Limit ATM by day | Defines the maximum amount the user can withdraw on a sliding day. | | Withdrawal | Limit ATM by week | Defines the maximum amount the user can withdraw on a sliding week. | | Withdrawal | Limit ATM by month | Defines the maximum amount the user can withdraw on a sliding month. | | Withdrawal | Limit ATM by year | Defines the maximum amount the user can withdraw on a sliding year. | | Withdrawal | Global ATM limit | Defines the overall amount the user can withdraw. | | Payment | Limit Payment by day | Defines the maximum amount the user can use on a sliding day. | | Payment | Limit Payment by week | Defines the maximum amount the user can use on a sliding week. | | Payment | Limit Payment by month | Defines the maximum amount the user can use on a sliding month. | | Payment | Limit Payment by year | Defines the maximum amount the user can use on a sliding year. | | Payment | Global Limit Payment | Defines the overall amount the user can pay. | ### Manage Card restrictions Card restrictions allow you to define in which countries and for which merchants a card may be used. In the *Card Settings* popup, *Restrictions* tab, you can enable or prevent the use of the card for an individual or a set of: * **MCC** – Defines the card use for specific [Merchant Category Code(s)](/guide/overview/glossary#merchant-category-code-mcc) * **MID** – Defines the card use for specific [Merchant Id(s)](/guide/overview/glossary#merchant-identifier-number-mid) * **Country** – Defines the card use for specific Country(ies) **Tip – Restriction groups can be predefined** If you have the relevant [Role](/guide/dashboard/dashboard-users#dashboard-user-roles), you can predefine a series of restriction groups in the Administration *Predef Restriction Groups* view. Otherwise, you may ask your administrator. #### Select the type of restriction to add or update In order to update the card restriction, select a restriction category on the left-hand side of the view. The display is different depending on whether a restriction group already applies or if there are no restrictions for the category. #### Define the restrictions Once a restriction category selected, you need to choose between the following options: * **Use a predefined list** – Update an existing predefined list by adding new elements * **Create a list manually** – Create a new list manually * **Upload a CSV** – Upload a CSV file to update your restrictions. #### Remove restrictions You may use the "Delete" option available upon clicking on the "More" button of a selected restriction in order to remove it. You're then free to replace it. ### Block a Card The Dashboard lets you block a card in case of a security issue. In the *Card settings* popup, *Block Card* tab, you can manage the card blocked status. Options available depends on the current card status: | Action | Description | | --- | --- | | **Secure the card** | Temporarily lock (or custom lock) the card, you may unblock it afterward. | | **Card Opposition** | Declare the card as stolen or lost. This action is irreversible. | | **Close Card** | Blocks permanently the card, at the end of the relationship with the end user for instance. This action is irreversible. | | **Unlock Card** | Unlock the card. Only available when the card has been temporarily locked. | Once the relevant option selected, click on the "Save Changes" button to apply your choice. ### Unblock PIN code The card can be blocked when the end user enters 3 erroneous PIN codes in a row. You can unblock a card CVC in the *Card settings* popup, *Unblock PIN/CVC* tab, *Unblock PIN* section. The button is only displayed when relevant. ### Unblock CVC The [card verification code (CVC)](/guide/overview/glossary#card-verification-number-cvc) can get locked if the cardholder enters an erroneous CVC multiple times in a row while attempting an online payment. You can unblock a card CVC in the *Card settings* popup, *Unblock PIN/CVC* tab, *Unblock CVC* section. **You must ensure the cardholder's identity** The card verification code is a security measure, you must make sure the request for unblocking the card comes from the legitimate cardholder. ### Convert a Virtual Card to Physical A Virtual Card can be converted to a Physical one, which will be sent to the cardholder. To convert a card, go to the *Card Settings* popup and click on the "Convert to Physical Card" button available in the *Card* section on the left-hand side. A success message is displayed in the top of the screen if the operation succeeds. ### Manage Digitized Cards Treezor offers your [Dashboard Users](/guide/dashboard/dashboard-users) the ability to suspend and delete digitized cards (i.e., cards that are tokenized in a Google Pay, Apple Pay, or Samsung Pay wallet). This way, they can swiftly handle customer requests when it comes to dealing with fraud and lost cards for instance. To manage digitized cards, go to the *Card Settings* popup, *Digitized Cards* tab. It displays the list of digitized cards for the currently selected card. Digitized cards may have one of the following statuses: * **Active** – The digitized card is active and can be used as a means of payment. * **Suspensed** – The digitized card is suspended, it can't be used, but could be reactivated if need be. * **Deactivated** – The digitized card is deleted, it can't be used and this status if final. The following commands are available depending on the digitized card status. | | Action | Description |  | :---: | --- | --- | | | Suspend | Prompts a dialog to suspend the digitized card, with a picklist to select the reason (e.g., device is lost or stolen). | | | Unsuspend | Prompts a dialog to unsuspend the digitized card, with a picklist to select the reason. | | | Delete | Prompts a dialog to deactivate the digitized card, with a picklist to select the reason (e.g., device is lost or stolen). This action is irreversible. | --- --- url: /guide/cheques/errors.md description: >- Troubleshoot and handle check cashing-related issues using the Treezor API's complete list of error codes, messages, and their corresponding meanings. --- # Errors Find below the list of API Errors that may occur when handling checks. | Code | Message | |:-: |- | | 1 | Generic Error | | 10010 | Invalid Argument. Wallet not found | | 14003 | Impossible to create Payin | | 14005 | This payin does not exist | | 14007 | Impossible to cancel the payin | | 14008 | The userId does not exist or is not in a status VALIDATED. | | 14009 | Unable to create payin with the provided walletId. It does not exist. | | 14010 | The RLMCKey is not valid | | 14011 | Unable to create payin. The wallet is not in a status VALIDATED | | 14012 | The specified currency for payin must be the same as the currency of the wallet | | 14015 | The provided amount must be greater than 1. | | 14018 | Unable to cancel the payin. The payin is already in a status CANCELED | | 14019 | Unable to cancel the payin. The payin is in a status VALIDATED | | 14088 | Impossible to create the payin the user has a kyc Level refused | | 50005 | Authentication failed | | 73001 | An invalid argument was given | | 88003 | The userId parameter is automatically set by the API in the case of a payin of type cheque. Do not set this value | | 88004 | The additionalData field is not in a correct format. | | 88005 | The additionalData field is mandatory | | 88011 | The API call to our partner failed | | 88013 | The RLMC Key is not valid | | 88014 | This cheque has already been treated | | 88020 | You are not set to use this type of Payin please contact your account Manager | | 88023 | Impossible to update the status of the payin | | 88046 | Cannot create the payin, amount exceed the maximal amount | | 90000 | Cannot cancel the payin, treatment ongoing at the treatment center | | 140011 | The client is already configured and can not be created again | | 140101 | The cheque client configuration deletion failed | | 150010 | The provided token is expired | | 160000 | The payin was not found | | 211000 | Impossible to create the operation, no reason code | | 211001 | Impossible to create the operation, not enough account's funds | | 211002 | Impossible to create the operation, the assets of the user are frozen | | 211003 | Impossible to create the operation, the assets of the user are frozen | | 211005 | Impossible to create the operation, the KYC Level of the parent user is not Light, Regular | | 211006 | Impossible to create the operation, the currency of the authorization and the account's currency are different | | 211008 | Impossible to create the operation, the authorization is a duplicate of an existing authorization | | 211009 | Impossible to create the operation, the account's user is not found | | 211011 | Impossible to create the operation, the account's balance is not found | | 211012 | Impossible to create the operation, Unknown error (internal error) | | 211013 | Impossible to create the operation, the context of the authorization is canceled (timeout or initiated by the client) | | 211014 | Impossible to create the operation, the original authorization is not found (for reversal or cancel) | | 211015 | Impossible to create the operation, the original authorization has an unexpected status | | 211018 | Impossible to create the operation, the authorization is forbidden due to authorization type, user, account | | 211019 | Impossible to create the operation, the total debit exceed the max total debit limit on sliding period | | 211020 | Impossible to create the operation, the authorization amount exceed the max amount limit | | 211021 | Impossible to create the operation, the authorization amount added to the account limit exceed the max account amount limit | | 211022 | Impossible to create the operation, the transfer creditor user is invalid | | 211023 | Impossible to create the operation, the transfer debitor user is invalid | | 211024 | Impossible to create the operation, the transfer creditor account is not found | | 211025 | Impossible to create the operation, the transfer creditor account's user is not found | | 211026 | Impossible to create the operation, the total credit exceed the max total credit limit on sliding period | | 211032 | Impossible to create the operation, the transfer creditor and debtor account are not found | | 211033 | Impossible to create the operation, the user is legal frozen | | 213001 | Unable to process payin authorization | | 213002 | Unable to process payin transaction | | 230001 | Cannot cancel the payin, its current state does not allow it | | 300000 | Generic Internal Error | | 300001 | A mandatory argument was not provided | --- --- url: /guide/cheques/events.md description: >- Reference a comprehensive list of check acquiring events for Treezor API webhooks, detailing each event's structure and payload for integration. --- # Events This article lists the [Webhooks](/guide/webhooks/introduction) you may receive when regarding Check acquiring. ## Payins ### `payin.create` ::: code-group ```json [JSON] { "webhook": "payin.create", "webhook_created_at": 17097149232358, "object_id": "93a3a3f9-a3f2-4352-96f6-e6670cd3aa6a", "object": "payin", "object_payload": { "payins": [ { "payinId": "93a3a3f9-a3f2-4352-96f6-e6670cd3aa6a", "payinTag": "tag-Checking Account", "walletId": "68014791", "userId": "865508", "payinStatus": "PENDING", "paymentMethodId": "26", "messageToUser": "Message to the user", "subtotalItems": "0.00", "subtotalServices": "0.00", "subtotalTax": "0.00", "amount": "10000.00", "currency": "EUR", "createdDate": "2024-03-06 09:48:40", "walletEventName": "Checking account", "walletAlias": "checkingaccount-6593e02138fd8", "userFirstname": "Alex", "userLastname": "Oak", "codeStatus": "160003", "informationStatus": "The cheque can now be sent to the treatment center", "refundAmount": null, "DbtrIBAN": null, "forwardUrl": null, "paymentAcceptedUrl": null, "paymentRefusedUrl": null, "paymentWaitingUrl": null, "paymentExceptionUrl": null, "paymentCanceledUrl": null, "payinDate": "0000-00-00", "mandateId": "0", "creditorName": null, "creditorAddressLine": null, "creditorCountry": null, "creditorIban": null, "creditorBIC": null, "virtualIbanId": null, "virtualIbanReference": null, "additionalData":{ "cheque":{ "cmc7":{ "a":"0557016", "b":"045010041908", "c":"001071920333" }, "drawerData":{ "firstName":"M. ALEX OAK", "isNaturalPerson":true }, "RLMCKey":"62" } }, "totalRows":1, "paymentHtml":null } ] }, "webhook_id": "498a9122-8e92-4dfe-9c76-40ebc39a6e24", "object_payload_signature": "PPFEQwEYkQKlSNrUhhKN1V7afoOoCa225Shgh+SDqxg=" } ``` ::: ### `payin.update` ::: code-group ```json [JSON] { "webhook":"payin.update", "webhook_created_at":17067103308448, "object_id":"25be7879-2fee-4080-bf45-fc93ecf97xx3", "object":"payin", "object_payload": { "payins": [ { "payinId":"25be7879-2fee-4080-bf45-fc93ecf97xx3", "payinTag":"tag-Checking Account", "walletId":"68009611", "userId": "865522", "payinStatus":"PENDING", "paymentMethodId":"26", "messageToUser":"Message to the user", "subtotalItems":"0.00", "subtotalServices":"0.00", "subtotalTax":"0.00", "amount":"10000.00", "currency":"EUR", "createdDate":"2024-01-31 15:12:07", "walletEventName":"Checking account", "walletAlias":"Checking account-100002428", "userFirstname": "Alex", "userLastname": "Oak", "codeStatus":"151132", "informationStatus":"The check has been received by the treatment center of our partner.", "refundAmount":null, "DbtrIBAN":null, "forwardUrl":null, "paymentAcceptedUrl":null, "paymentRefusedUrl":null, "paymentWaitingUrl":null, "paymentExceptionUrl":null, "paymentCanceledUrl":null, "payinDate":"0000-00-00", "mandateId":"0", "creditorName":null, "creditorAddressLine":null, "creditorCountry":null, "creditorIban":null, "creditorBIC":null, "virtualIbanId":null, "virtualIbanReference":null, "additionalData":{ "cheque":{ "cmc7":{ "a":"0557016", "b":"045010041908", "c":"001071920333" }, "drawerData":{ "firstName":"M. ALEX OAK", "isNaturalPerson":true }, "RLMCKey":"62" } }, "totalRows":1, "paymentHtml":null } ] }, "webhook_id":"669911f2-3177-4655-93d4-6eaad0xx4727", "object_payload_signature":"OSet8MKvrd8xVG6turNr3ZWHbH+T0IUPmEh8pNxxxT4=" } ``` ::: ### `payin.cancel` ::: code-group ```json [JSON] { "webhook":"payin.cancel", "webhook_created_at":17067103308448, "object_id":"25be7879-2fee-4080-bf45-fc93ecf97ac3", "object":"payin", "object_payload": { "payins": [ { "payinId":"25be7879-2fee-4080-bf45-fc93ecf97xx3", "payinTag":"Checking account", "walletId":"68009677", "userId": "865508", "payinStatus":"CANCELED", "paymentMethodId":"26", "messageToUser":"Message to the user", "subtotalItems":"0.00", "subtotalServices":"0.00", "subtotalTax":"0.00", "amount":"10000.00", "currency":"EUR", "createdDate":"2024-01-31 15:12:07", "walletEventName":"Checking Account", "walletAlias":"checkingAccount-100002428", "userFirstname": "Alex", "userLastname": "Oak", "codeStatus":"151134", "informationStatus":"The check has not been received by the treatement center in the allowed delay of 15 calendar days", "refundAmount":null, "DbtrIBAN":null, "forwardUrl":null, "paymentAcceptedUrl":null, "paymentRefusedUrl":null, "paymentWaitingUrl":null, "paymentExceptionUrl":null, "paymentCanceledUrl":null, "payinDate":"0000-00-00", "mandateId":"0", "creditorName":null, "creditorAddressLine":null, "creditorCountry":null, "creditorIban":null, "creditorBIC":null, "virtualIbanId":null, "virtualIbanReference":null, "additionalData":{ "cheque":{ "cmc7":{ "a":"0557016", "b":"045010041908", "c":"001071920333" }, "drawerData":{ "firstName":"M. ALEX OAK", "isNaturalPerson":true }, "RLMCKey":"62" } }, "totalRows":1, "paymentHtml":null } ] }, "webhook_id":"669911f2-3177-4655-93d4-6eaad0xx4727", "object_payload_signature":"OSet8MKvrd8xVG6turNr3ZWHbH+T0IUPmEh8pNxxxT4=" } ``` ::: --- --- url: /guide/cheques/cashing.md description: >- Learn how to cash-in checks to credit Treezor Wallets. Includes required parameters, request structure, and response examples, as well as the Check object life cycle. --- # Cashing Cashing checks implies a digital and a physical process. 1. [Payin creation](#creation) – You create a `Payin` object, with information about the Check 2. [Check mail in](#mail-in) – You send the physical check to Treezor via mail (within 14 days) The funds are credited to the wallet when the physical check is received and approved. When a check is physically processed, [`payin.update`](/guide/cheques/events) webhooks are sent informing you of the changes. **Information – Checks must:** * Be sent via mail, as no physical agencies are available * Be received within 14 calendar days of the Payin creation (otherwise, the [Payin status](introduction#status-payinstatus) is set to `151134`) * Bear the following information: Name, Account Number, Date, Signature ## Creation ### Parameters | Attribute | Type | Description | | --- | --- | --- | | `paymentMethodId` | integer | Must be `26` for checks. | | `amount` | number | The amount of the check. | | `walletId` | string | The unique identifier of the Wallet to credit (recipient). | | `currency` | string | The currency of the check. | | `additionalData` | object | Contains the cmc7 line, the drawer data and the RLMC key of the check. | ### Request example Use the following request to create a Payin object for your check: ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/payins' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "walletId": "123456", "paymentMethodId":26, "amount":991.25, "currency":"EUR", "additionalData": { "cheque":{ "cmc7" : { "a":"000036", // required, 1st section of CMC7 line "b":"0230021566985", // required, 2nd section of CMC7 line "c":"00700065456" // required, 3rd section of CMC7 line }, "RLMCKey":"22", // required, RMLC key "drawerData":{ // required object "isNaturalPerson" : true, // required, boolean, true: physical / false: legal entity "email":"aoak@example.com", // drawer's email "firstName" : "Alex", // drawer's firstname "lastName" : "Oak", // drawer's lastname "address" : "22 Rosewood Lane", // drawer's address "address2" : "App. 12", // drawer's address continued "zipCode" : "75001", // drawer's postcode "city" : "Paris" // drawer's city } } } } ``` ::: Returns the Payin object if successful. ::: code-group ```json [JSON] {8,9,21} { "payins": [ { "payinId": "cf7544f4-15ef-44df-9e6b-ac50ef5xxxx", "payinTag": null, "walletId": "123456", "userId": "852741", "payinStatus": "PENDING", "paymentMethodId": "26", "messageToUser": "", "subtotalItems": "100.00", "subtotalServices": "0.00", "subtotalTax": "0.00", "amount": "100.00", "currency": "EUR", "createdDate": "2018-01-01 17:00:00", "walletEventName": "Wallet Test", "walletAlias": "test-wallet-abcd", "userFirstname": "CMA", "userLastname": "", "codeStatus": "160001", "informationStatus": "", "refundAmount": null, "ibanFullname": "", "DbtrIBAN": "", "ibanBic": "", "ibanTxEndToEndId": "XXXXXXXXX", "ibanTxId": "180799999990292", "forwardUrl": null, "paymentAcceptedUrl": null, "paymentRefusedUrl": null, "paymentWaitingUrl": null, "paymentExceptionUrl": null, "paymentCanceledUrl": null, "payinDate": null, "mandateId": null, "creditorName": "ALEX OAK", "creditorAddressLine": null, "creditorCountry": null, "creditorIban": "FR761679999999999XX9011835", "creditorBIC": "TRZOFR21XXX", "virtualIbanId": null, "virtualIbanReference": null, "ibanId": "995d69d1839999999999a6935979ea8110d8" } ] } ``` ::: ## Mail in Once the Payin is created, the Check can mailed to the address indicated below. Checks must be received within **14 days** after the Payin Creation. CENTRE DE TRAITEMENT TSA 80007 33625 BORDEAUX CEDEX 9 ## Life cycle Checks cash-in may have different outcomes, whether they are accepted or not. If the check bounces within the 11-day delay, the Payin is canceled. Otherwise, a Payin refund is created. Here is an illustration of the check life cyle: ### Examples Find below Check life cycle examples. #### Accepted check | Step | | [Status](/guide/cheques/introduction#status-payinstatus) | [Code](/guide/cheques/introduction#status-payinstatus) | Description | |- |-: |- |- |- | | #1 | | **PENDING** | `160001` | Waiting for treatment center akwnoldgement | | #2 | | **PENDING** | `160003` | Waiting for check mail-in | | #3 | | **PENDING** | `151132` | Check has been received | | #4 | | **PENDING** | `151129` | Check has been submitted to the bank | | #5 | | **PENDING** | `151130` | Check is awaiting validation | | #6 | | **VALIDATED** | `140005` | **Payment validated** | #### Error during handling | Step | | [Status](/guide/cheques/introduction#status-payinstatus) | [Code](/guide/cheques/introduction#status-payinstatus) | Description | |- | -: |- |- |- | | #1 | | **PENDING** | `160001` | Waiting for treatment center akwnoldgement | | #2 | | **PENDING** | `160003` | Waiting for check mail-in | | #3 | | **PENDING** | `151132` | Check has been received | | #4 | | **CANCELED** | `151125` | Payin has been canceled due to an **issue with the check** | --- --- url: /use-cases/prerequisites/creating-your-company.md description: >- Get some context regarding the necessity to create and verify your company before starting your implementation. This introduction includes the functional architecture of your company and keywords you need to know to get started. --- # Creating your company Before starting with any of the use cases, you first need to verify your company, which means going through the KYC/KYB process for your company’s legal representative and shareholders, as well as your company as a legal entity. We propose two guides to help you through the onboarding of your company: ### No-code guide Recommended for people who wish to get started with no development effort. Once in possession of your credentials to access your Dashboard, you’re good to go! [Start your no-code implementation →](/use-cases/prerequisites/create-your-company-nc) ### API guide (coming soon) Recommended for people with experience working with APIs. Once you’ve got your credentials, you’re good to set up your favorite development and testing tools (e.g., set up our Postman Collection). **Important – Rely on the KYC Form shared with you by Treezor** All the requirements for declarative data and supporting documents are available in your KYC form. ## Functional architecture Your company is a legal entity, to which are attached (with a children-parent relationship) its shareholders (UBOs) and its legal representative. Use cases also rely on a Master Wallet, which is directly attached to your legal entity, and through which all the funds will be transiting. ## Keywords Find below a few terms specific to the guides. If you have any doubts, you may find more definitions in the [Glossary](/guide/overview/glossary). ### Know Your Business (KYB) KYB stands for Know Your Business and, in this guide, covers the verification process of: * Your company (as a legal entity) * Its legal representative * Its shareholders User (legal entities and individuals) verification is a legal and mandatory process. All banking institutions are subject to these rules, as part of the AML/CFT. Without being verified, your company won’t be allowed to use the funds stored in its wallet. This process is very similar to the KYC (Know Your Customer) process through which your end users may have to go. You will find the term KYC in the guide, especially when referring to the Dashboard screens for instance. *Treezor Compliance* creates a KYC Form which is specific for your company. You must abide by the documents and declarative data to be provided for your company to be verified. ### Shareholders As part of the KYB process, you must declare and verify any shareholder who owns 25% or more of your company (directly or via a holding company). These majority shareholders are usually defined as ultimate beneficial owners (UBO) or beneficial owners. For convenience purposes, this guide will use the term **shareholder**. ### Legal representative The legal representative is the person legally appointed to represent your company. They are the signatory for all company operational activities, and they must ensure the good operation and standing of the company. ### Master Wallet The Master Wallet refers to the single wallet attached to a company through which all the funds transit. You may also find the term [*Titres Spéciaux de Paiements*](/guide/wallets/introduction#titres-speciaux-de-paiement-type-15). --- --- url: /guide/transfers/beneficiaries.md description: >- Technical guide for creating and managing beneciaries, which are accounts outside your Treezor environment. Includes required parameters, request structure, and response examples. --- # Beneficiaries Beneficiaries are bank accounts that are outside your Treezor ecosystem (as opposed to [Wallets](/guide/dashboard/wallets#wallets)). They are therefore the target of payouts (SEPA Direct Debit and SEPA Credit Transfers), and are necessarily attached to a User. **Information – Treezor is connected to the SEPA STEP2 transfer network** This network is used by all European banks, and a few other outside of Europe. To transfers fund in and out, both parties must be in same network. When making a payout (outgoing funds), Beneficiaries are created: * **Manually** prior to emitting a [SEPA Credit Transfer](/guide/transfers/credit-transfer#emitted-credit-transfers-scte) ([`usableForSct`](#key-attributes) set to **`true`**). * **Automatically** when paying with a [SEPA Direct Debit](/guide/transfers/direct-debit#received-direct-debits-sddr) ([`usableForSct`](#key-attributes) set to **`false`**). **Note – Beneficiaries must be created before for B2B SDDR** The Beneficiary `sddB2bWhitelist.uniqueMandateReference` field must be populated once the User receives their UMR from their creditor. If not, the SDDR will be [declined upon reception](/guide/transfers/direct-debit#rejection-of-an-sddr). A Beneficiary can only be associated to a single user at a time. If multiple Users need to send/receive funds to/from the same identical Beneficiary, it can either be duplicated or [associated to a parent user](/guide/users/parent-children). ## Beneficiary object ::: code-group ```json [JSON] { "tag": "string", "userId": 0, "nickName": "string", "name": "string", "address": "string", "iban": "string", "bic": "string", "sepaCreditorIdentifier": "string", "sddB2bWhitelist": [ { "uniqueMandateReference": "nn888890886DGFIP2020045229KFDZBOAB", "isRecurrent": true, "walletId": 0 } ], "sddCoreBlacklist": [ "string" ], "usableForSct": false, "sddCoreKnownUniqueMandateReference": [ "string" ], "isActive": true, "createdDate": "string", "modifiedDate": "string" } ``` ::: ## Key attributes Below are some of the most important Beneficiary attributes. | Attribute | Type | Description | |--- |--- |--- | | `nickName` | string | Field that you are free to populate to identify the Beneficiary. | | `iban` | string | The IBAN of the Beneficiary. | | `bic` | string | The [BIC](/guide/overview/glossary#bank-identifier-code-bic) of the Beneficiary. | | `name` | string | The name of the Beneficiary *(see charset restrictions below)*. | | `sepaCreditorIdentifier` | string | The [SCI](/guide/overview/glossary#sepa-creditor-identifier-sci). | | `uniqueMandateReference` | string | The [UMR](/guide/overview/glossary#unique-mandate-reference-umr). | | `sddCoreBlacklist` | array | List of [UMR](/guide/overview/glossary#unique-mandate-reference-umr) that are revoked. **Core scheme only**. | | `sddCoreKnownUniqueMandateReference` | array | List of all [UMR](/guide/overview/glossary#unique-mandate-reference-umr) that have debited the User | | `sddB2bWhitelist.uniqueMandateReference` | array | List of [UMR](/guide/overview/glossary#unique-mandate-reference-umr) that are allowed to debit the Wallet. **B2B scheme only**. | | `sddB2bWhitelist.isRecurrent` | boolean | `true` – Allows **multiple** debits for this Beneficiary`false` – Allows a **single** debit for this Beneficiary | | `sddB2bWhitelist.walletId` | integer | Defines which Wallet can be debited by the Beneficiary. | | `isActive` | boolean | Toggle the Beneficiary (for both SDDR and SCTE): `true` – Enables the Beneficiary`false` – Disables the Beneficiary | | `usableForSct` | boolean | Defines if this Beneficiary can be used to send [SCTE](/guide/transfers/credit-transfer#emitted-credit-transfers-scte) | **Information – Rules for the `name` attribute** * Must be **at least 1-character long**, but not a single space character. * Can only contain the following characters: `a-z`, `A-Z`, `0-9`, `/`, `-`, `?`, `:`, `(`, `)`, `.`, `,`, `'`, `+` and ` ` (space). ### Accepted countries SEPA Transfers are only supported for beneficiaries domiciled in one of the SEPA Scheme countries. If the Beneficiary `bic` or `iban` country code is not a SEPA Scheme country, an HTTP error will be returned. **Reading – EPC list of Countries in the SEPA Scheme** You may find the list of accepted BIC and IBAN countries (and the corresponding country codes) in the [EPC list of Countries in the SEPA Schemes](https://www.europeanpaymentscouncil.eu/sites/default/files/kb/file/2023-01/EPC409-09%20EPC%20List%20of%20SEPA%20Scheme%20Countries%20v4.0_0.pdf) document. ## Creation | Attribute | Type | Description | |--- |--- |--- | | `userId` | string | The unique identifier of the User to which the Beneficiary is attached. | | `name` | string | The name of the Beneficiary *(see charset restrictions below)*. | | `iban` | string | The IBAN of the Beneficiary. | | `bic` | string | The [BIC](/guide/overview/glossary#bank-identifier-code-bic) of the Beneficiary. | **Information – Rules for the `name` attribute** * Must be **at least 1-character long**, but not a single space character. * Can only contain the following characters: `a-z`, `A-Z`, `0-9`, `/`, `-`, `?`, `:`, `(`, `)`, `.`, `,`, `'`, `+` and ` ` (space). ### Example To create a Beneficiary, use the following request: ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/v1/beneficiaries' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "userId":123456, "name":"Alex Oak", "tag":"aoak-1982", "nickName":"A Oak checking", "address":"Woods Bank", "iban":"FR7616798000010000012345678", "bic":"TRZOFR21XXX", "usableForSct":true } ``` ::: **Tip – Make sure you use a real IBAN** If the provided IBAN is incorrect, an error is returned and the Beneficiary is not created. Returns a Beneficiary object, with its `beneficiaryId` (11XXXX8). It can be used to initiate an [outgoing transfer (SCTE)](/guide/transfers/credit-transfer#emitted-credit-transfers-scte) right away. ::: code-group ```json [JSON] { "id": 11XXXX8, "tag": "aoak-1982", "userId": 22XXXX6, "nickName": "A Oak checking", "name": "STE A", "address": "Woods Bank", "iban": "2XXXXXXXX X X 7XXXXXXXXX5 X X 75XXXXXXXX6 X X 1XXXXX4", "bic": "BNPAFRPP", "sepaCreditorIdentifier": "", "sddB2bWhitelist": [], "sddCoreBlacklist": [], "usableForSct": true, "sddCoreKnownUniqueMandateReference": [], "isActive": true } ``` ::: Treezor also sends a [`beneficiary.create`](events#beneficiary-create) webhook. **Tip – Useful information about the returned object** * `usableForSct` indicates if the beneficiary can be used to [initiate outgoing transfers](/guide/transfers/introduction) (`SCTE`). * `iban` is returned in an encoded format and cannot be read directly. ## Endpoints | Endpoint | [Scope](/guide/api-basics/authentication#available-scopes) | | --- | --- | | [`/v1/beneficiaries`](/api-reference/api-endpoints.html#tag/Beneficiaries/postBeneficiary){target="\_self"} Create a Beneficiary | `read_write` | | [`/v1/beneficiaries`](/api-reference/api-endpoints.html#tag/Beneficiaries/getBeneficiaries){target="\_self"} Search for Beneficiaries | `read_only` | | [`/v1/beneficiaries/{beneficiaryId}`](/api-reference/api-endpoints.html#tag/Beneficiaries/getBeneficiary){target="\_self"} Retrieve a Beneficiary | `read_only` | | [`/v1/beneficiaries/{beneficiaryId}`](/api-reference/api-endpoints.html#tag/Beneficiaries/putBeneficiary){target="\_self"} Update a Beneficiary | `read_write` | --- --- url: /guide/cards/creation.md description: >- Technical guide for issuing physical and virtual cards, individually or in bulk. Includes required parameters, request structure, and response examples. --- # Creation This page describes the processes of Card creation, delivery, and activation. **Note – Cards may be both Virtual and Physical** If your [Card Program](/guide/cards/introduction#card-program) allows it, the same Card may exist in both [Physical](#physical-card-creation) and [Virtual](#virtual-card-creation) forms. In such cases, you can't know which one was used for a given transaction. ## Process ### Mandatory creation steps * **Create** a [Physical](#physical-card-creation) or [Virtual Card](#virtual-card-creation) associated to a Wallet. * **Register 3D Secure** using [the dedicated endpoint](#enrolling-a-card-for-3d-secure). * **Activate** the Card (Cards are created in an inactive state; you must [activate them](#activation)). ### Optional steps * Define or [change the Card PIN code](/guide/cards/modification#change-pin) * Modify Card [options](/guide/cards/restrictions-limits#options-permission-groups) or [limits](/guide/cards/restrictions-limits#payment-withdrawal-limits) (payment limits, NFC activation, online payment, etc.) * Update Card [restrictions](/guide/cards/restrictions-limits#mcc-restrictions) * [Lock or unlock the Card](/guide/cards/modification#block-a-card) * [Convert a Virtual Card to a Physical one](#converting-to-physical) Treezor encourages you to set all limits, options, and PIN code during the creation of the card, avoiding additional steps. **Tip – To create cards for a company's employees:** Set the employee's ([Physical User](/guide/users/physical)) `parentUserId` attribute with the `userId` of the company ([Legal Entity](/guide/users/legal-entity)). The Card can be shipped at the company's address by setting `sendToParent` value to `true`. If so, the envelope bears the children's complete name and the parent address. ### Card life cycle Cards come with an `expiryDate`, indicating when the card expires and when it should be [renewed](./renewal). Treezor sends webhooks to better handle this situation: * [`card.expiryAlert`](/guide/cards/events#card-expiryalert) – Indicates the card expires at the end of next month. * [`card.update`](/guide/cards/events#card-udpate) with `EXPIRED` status – Indicates the card expired. ## Virtual Card creation A Virtual Card is a card (with a [PAN](/guide/overview/glossary#primary-account-number-pan), [CVC](/guide/overview/glossary#card-verification-code-cvc), and expiration date) that does not exist in a physical form. **It is made available to the end user in the form of an image** (that looks like a Card). It can be used for online payments. ### Parameters Here are some of the most important parameters to define when creating a Virtual Card. | Attribute | Type | Description | | --- | --- | --- | | `userId`  | integer | The unique identifier of the [cardholder](/guide/users/introduction). | | `walletId` | integer | The unique identifier of the [Wallet](/guide/wallets/introduction) associated with the card. | | `permsGroup` | string | A code for a [preset of permissions](/guide/cards/restrictions-limits#options-permission-groups). It indicates whether the card main options (contactless, online payments, withdrawals, and international payments) are activated or not. | | `cardPrint` | string | The [Card Program](introduction#card-program) to associate to the Card and the options provided with it. This information is shared with you by Treezor. | | `merchantRestrictionGroupId` | integer | The unique identifier of your MID restriction group if you’ve created one in the [previous step](#merchant-id-restrictions). | | `mccRestrictionGroupId` | integer | The unique identifier of your MCC restriction group if you’ve created one in the [previous step](#merchant-category-restrictions). | | `countryRestrictionGroupId` | integer | The unique identifier of your Country restriction group if you’ve created one in the [previous step](#country-restrictions). | | `designCode` | string | [Customization code](#designs-designcode) for the card design. If missing, falls back to the default Design Code. | | `cardTag` | string | Custom information for you to use as you see fit. See the [Object tags](/guide/api-basics/objects-tags) article. | **API – API Reference available** For a complete list of Card attributes, check the [Cards](/api-reference/api-endpoints.html#tag/Cards){target="\_self"} section of the API Reference. ### Request example Endpoint: [`/v1/cards/CreateVirtual`](/api-reference/api-endpoints.html#tag/Cards/postCardVirtual){target="\_self"} ::: code-group <<< @/guide/cards/snippets/create-card-virtual.bash \[CURL] ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "cardPrint": "{cardPrint}", "userId": 8290083, "walletId": 2464676, "permsGroup": "TRZ-CU-011", "mccRestrictionGroupId": 95447, "merchantRestrictionGroupId": 45599, "countryRestrictionGroupId": 165327, "limitPaymentDaily":{limitPaymentDaily}, "limitAtmDaily":{limitAtmDaily} } ``` ::: Returns the Card object, with its `cardId` (present in all [CardTransactions](transactions)). ::: code-group ```json [JSON] {4} { "cards": [ { "cardId": 241709, "userId": 8290083, "walletId": 2464676, "walletCardtransactionId": 2473310, "mccRestrictionGroupId": 95447, "merchantRestrictionGroupId": 45599, "countryRestrictionGroupId": 165327, "publicToken": "107277882", "cardTag": "", "statusCode": "UNLOCK", "isLive": 0, "pinTryExceeds": 0, "maskedPan": "519872******4839", "embossedName": "ALEX OAK", "expiryDate": "2026-10-31", "CVV": "000", // Retrieve the CVV with cardImage or PCI DSS "startDate": "2023-10-23", "endDate": "0000-00-00", "countryCode": "FR", "currencyCode": "EUR", "lang": null, "deliveryTitle": "M", "deliveryLastname": "OAK", "deliveryFirstname": "ALEX", "deliveryAddress1": "15 EDGEWOOD ROAD", "deliveryAddress2": "", "deliveryAddress3": "", "deliveryCity": "ROSEWOOD", "deliveryPostcode": "12365", "deliveryCountry": "FR", "mobileSent": "+33633333333", "limitsGroup": "TRZ-VL-001", "permsGroup": "TRZ-CU-011", "cardDesign": "13664", "virtualConverted": 0, "physical": 0, "optionAtm": 0, "optionForeign": 0, "optionOnline": 1, "optionNfc": 1, "limitAtmYear": 0, "limitAtmMonth": 0, "limitAtmWeek": 0, "limitAtmDay": 1, "limitAtmAll": 1, "limitPaymentYear": 0, "limitPaymentMonth": 0, "limitPaymentWeek": 0, "limitPaymentDay": 25, "limitPaymentAll": 25, "paymentDailyLimit": 0.0, "totalAtmYear": null, "totalAtmMonth": null, "totalAtmWeek": null, "totalAtmDay": null, "totalAtmAll": null, "totalPaymentYear": null, "totalPaymentMonth": null, "totalPaymentWeek": null, "totalPaymentDay": null, "totalPaymentAll": null, "createdBy": 945198, "createdDate": "2023-10-31 10:37:04", "modifiedBy": 0, "modifiedDate": "0000-00-00 00:00:00", "renewalType": "A", "renewalDate": null, "originalCardId": null, "totalRows": null, "designCode": null, "cardLanguages": "", "eventName": "Master Wallet", "eventAlias": "master-wallet-6537b83040735", "restrictionGroupLimits": null, "cancellationNumber": "", "metadata": null, "renewalDate": null, "renewalType": null, "originalCardId": null, "logoId": "", "logoBackId": "", "packageId": "", "customizeInfo": "", "letterCustomizedInfo": "", "freeCustomizedInfo": "", "deliveryMethod": null, "pinMailer": null, "batchDeliveryId": null, "sendToParent": 0 } ] } ``` ::: Endpoint: [`/cards`](/api-reference/pci-dss-dev.html#tag/Cards/createCard){target="\_self"} ::: code-group <<< @/guide/cards/snippets/create-card-pci.bash \[CURL] ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "cardPrint": "{cardPrint}", "userId": 8290083, "medium": "virtual", "walletId": 2464676, "permsGroup": "TRZ-CU-011", "mccRestrictionGroupId": 95447, "merchantRestrictionGroupId": 45599, "countryRestrictionGroupId": 165327, "limitPaymentDaily":{limitPaymentDaily}, "limitAtmDaily":{limitAtmDaily}, "sca": "eyJh_UxfQ.nNIH_n9kA" } ``` ::: Returns the Card object, with its `cardId` (present in all [CardTransactions](transactions)). ::: code-group ```json [JSON] {4} { "cards": [ { "cardId": 241709, "userId": 8290083, "walletId": 2464676, "walletCardtransactionId": 2473310, "mccRestrictionGroupId": 95447, "merchantRestrictionGroupId": 45599, "countryRestrictionGroupId": 165327, "publicToken": "107277882", "cardTag": "", "statusCode": "UNLOCK", "isLive": 0, "pinTryExceeds": 0, "maskedPan": "519872******4839", "embossedName": "ALEX OAK", "expiryDate": "2026-10-31", "CVV": "000", // Retrieve the CVV with cardImage or PCI DSS "startDate": "2023-10-23", "endDate": "0000-00-00", "countryCode": "FR", "currencyCode": "EUR", "lang": null, "deliveryTitle": "M", "deliveryLastname": "OAK", "deliveryFirstname": "ALEX", "deliveryAddress1": "15 EDGEWOOD ROAD", "deliveryAddress2": "", "deliveryAddress3": "", "deliveryCity": "ROSEWOOD", "deliveryPostcode": "12365", "deliveryCountry": "FR", "mobileSent": "+33633333333", "limitsGroup": "TRZ-VL-001", "permsGroup": "TRZ-CU-011", "cardDesign": "13664", "virtualConverted": 0, "physical": 0, "optionAtm": 0, "optionForeign": 0, "optionOnline": 1, "optionNfc": 1, "limitAtmYear": 0, "limitAtmMonth": 0, "limitAtmWeek": 0, "limitAtmDay": 1, "limitAtmAll": 1, "limitPaymentYear": 0, "limitPaymentMonth": 0, "limitPaymentWeek": 0, "limitPaymentDay": 25, "limitPaymentAll": 25, "paymentDailyLimit": 0.0, "totalAtmYear": null, "totalAtmMonth": null, "totalAtmWeek": null, "totalAtmDay": null, "totalAtmAll": null, "totalPaymentYear": null, "totalPaymentMonth": null, "totalPaymentWeek": null, "totalPaymentDay": null, "totalPaymentAll": null, "createdBy": 945198, "createdDate": "2023-10-31 10:37:04", "modifiedBy": 0, "modifiedDate": "0000-00-00 00:00:00", "renewalType": "A", "renewalDate": null, "originalCardId": null, "totalRows": null, "designCode": null, "cardLanguages": "", "eventName": "Master Wallet", "eventAlias": "master-wallet-6537b83040735", "restrictionGroupLimits": null, "cancellationNumber": "", "metadata": null, "renewalDate": null, "renewalType": null, "originalCardId": null, "logoId": "", "logoBackId": "", "packageId": "", "customizeInfo": "", "letterCustomizedInfo": "", "freeCustomizedInfo": "", "deliveryMethod": null, "pinMailer": null, "batchDeliveryId": null, "sendToParent": 0 } ] } ``` ::: Treezor also sends a [`card.createvirtual`](./events#cardcreatevirtual) webhook. ### Retrieving a Virtual Card image The created virtual cards are available as an image (base64 encoded format). You can retrieve a card and expose it to your users. Endpoint: [`/v1/cardimages`](/api-reference/api-endpoints.html#tag/Cards/getCardImage){target="\_self"} ::: code-group ```bash [CURL] curl -X GET '{baseUrl}/v1/cardimages?cardId={cardId}' \ --header 'Authorization: Bearer {accessToken}' ``` ::: It returns the Card Image object if successful: ::: code-group ```json [JSON] { "cardimages": [ { "id": "155341", "cardId": "239391", "file": "/xj/base64encodedfile" } ] } ``` ::: Endpoint: [`/cards/{cardId}/cardImage`](/api-reference/pci-dss-dev.html#tag/Cards/getCardImage){target="\_self"} ::: code-group ```bash [CURL] curl -X GET '{pciBaseUrl}/cards/{cardId}/cardImage' \ --header 'Authorization: Bearer {accessToken}' ``` ::: It returns the Card Image object if successful: ::: code-group ```json [JSON] { "encryptedCardImage": "…" } ``` ::: Please refer to the [Displaying sensitive data](./sensitive-data) article for more information regarding the exposition of the card image. **Security – Sensitive data storage is forbidden** You are prohibited from storing card images on your servers (except if you are PCI DSS certified). ### Converting to physical Converting a card consists in turning a virtual card into a physical one. The availability of this option depends on your Card Program. When doing so, all the card information, settings, and options remain unchanged. **Information – Conversion requires a delivery address for the Physical Card** If the [User](/guide/users/introduction) doesn't already have an address defined, you have to update it beforehand. ::: code-group ```bash [CURL] curl -X PUT '{baseUrl}/v1/cards/{cardId}/ConvertVirtual' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' ``` ::: Returns the Card object, with a `virtualConverted` attribute set to `1`. ::: code-group ```json{38} { "cards": [ { "cardId": 999894952, "userId": 100198207, "walletId": 2728965, "walletCardtransactionId": 2905467, "mccRestrictionGroupId": 0, "merchantRestrictionGroupId": 0, "countryRestrictionGroupId": 0, "publicToken": "105608965", "cardTag": "Event-test-card", "statusCode": "UNLOCK", "isLive": 0, "pinTryExceeds": 0, "maskedPan": "548821******4661", "embossedName": "SPRINTREVIEW GRANDMA", "expiryDate": "2027-05-31", "CVV": "624", "startDate": "2024-05-24", "endDate": "0000-00-00", "countryCode": "FR", "currencyCode": "EUR", "lang": null, "deliveryTitle": "M", "deliveryLastname": "GRANDMA", "deliveryFirstname": "SPRINTREVIEW", "deliveryAddress1": "12 RUE DE LA LIBERTE", "deliveryAddress2": "", "deliveryAddress3": "", "deliveryCity": "PARIS", "deliveryPostcode": "7501", "deliveryCountry": "FR", "mobileSent": "+33687432367", "limitsGroup": "TRZ-VL-001", "permsGroup": "TRZ-CU-012", "cardDesign": "8529", "virtualConverted": 1, "physical": 0, "optionAtm": 0, "optionForeign": 1, "optionOnline": 1, "optionNfc": 1, "limitAtmYear": 0, "limitAtmMonth": 0, "limitAtmWeek": 2000, "limitAtmDay": 1000, "limitAtmAll": 0, "limitPaymentYear": 0, "limitPaymentMonth": 0, "limitPaymentWeek": 3000, "limitPaymentDay": 2000, "limitPaymentAll": 0, "paymentDailyLimit": 500.0, "totalAtmYear": null, "totalAtmMonth": null, "totalAtmWeek": null, "totalAtmDay": null, "totalAtmAll": null, "totalPaymentYear": null, "totalPaymentMonth": null, "totalPaymentWeek": null, "totalPaymentDay": null, "totalPaymentAll": null, "createdBy": 929252, "createdDate": "2024-05-14 10:28:07", "modifiedBy": 929252, "modifiedDate": "2024-05-14 10:28:20", "totalRows": null, "designCode": null, "cardLanguages": "", "eventName": "Wallet transfer", "eventAlias": "wallet-transfer-65eafdf301f56", "restrictionGroupLimits": null, "cancellationNumber": "", "metadata": null, "renewalDate": null, "renewalType": null, "originalCardId": null, "logoId": "", "logoBackId": "", "packageId": "", "customizeInfo": "", "letterCustomizedInfo": "", "freeCustomizedInfo": "", "deliveryMethod": null, "pinMailer": null, "batchDeliveryId": null, "sendToParent": 0 } ] } ``` ::: ## Physical card creation A Physical Card is a card that is shipped to the cardholder by mail and can, for example, be used in retail shops, gas station, etc. depending on [applied restrictions](/guide/cards/modification#applying-a-restriction-list). If you want to display an image of a Physical Card to the end user, you must first create a Virtual Card and [convert](#converting-to-physical) it to a Physical one. This allows you to show an image of the Virtual Card which bears the same PAN, CVC and expiration date. **Tip – Physical Cards are mailed to users** The following [User attributes](/guide/users/introduction#key-attributes) are required to send physical cards: `title`, `firstname`, `lastname`, `address{1-3}`, `city`, `postcode` and `country`. ### Parameters Here are some of the most important parameters to define when creating a Virtual Card. | Attribute | Type | Description | | --- | --- | --- | | `userId`  | integer | The unique identifier of the [cardholder](/guide/users/introduction) | | `walletId` | integer | The unique identifier of the [Wallet](/guide/wallets/introduction) associated with the card. | | `permsGroup` | string | A code for a [preset of permissions](/guide/cards/restrictions-limits#options-permission-groups). It indicates whether the card main options (contactless, online payments, withdrawals, and international payments) are activated or not. | | `cardPrint` | string | The [Card Program](introduction#card-program) to associate to the Card and the options provided with it. This information is shared with you by Treezor. | | `anonymous` | integer | Must be defined to `1` if the Card is assigned to an [Anonymous User](/guide/users/physical#anonymous-users). | | `merchantRestrictionGroupId` | integer | The unique identifier of your MID restriction group if you’ve created one in the [previous step](#merchant-id-restrictions). | | `mccRestrictionGroupId` | integer | The unique identifier of your MCC restriction group if you’ve created one in the [previous step](#merchant-category-restrictions). | | `countryRestrictionGroupId` | integer | The unique identifier of your Country restriction group if you’ve created one in the [previous step](#country-restrictions). | | `designCode` | string | [Customization code](#designs-designcode) for the card design. If missing, falls back to the default Design Code. | | `cardTag` | string | Custom information for you to use as you see fit. See the [Object tags](/guide/api-basics/objects-tags) article. | | `pin` | string | The Card PIN code. Treezor recommends you set this value when creating the card, but if not, a random value is set by default. | | `cardLanguages` | string | Specifies a maximum of 4 preferred languages used to communicate with the cardholder on [ATMs](/guide/overview/glossary#automated-teller-machine-atm). Expected as ISO 639-1 (code alpha-2) concatenated by priority (e.g., `nrfrenes` for Dutch 1st, French 2nd, English 3rd, Spanish 4th). | | `batchDeliveryId` | integer | Allows you to [group Cards shipping together](#batch-delivery-batchdeliveryid) by specifying the same delivery ID to multiple Cards. | | `logoId` | string | Allows you to [add a logo on the Card](#logo-logoid) by specifying the file's name. | | `logoBackId` | string | Allows you to [add a logo on the backside of the Card](#back-logo-logobackid) by specifying the file's name. | | `packageId` | string | Allows you to customize [the Card packaging](./introduction#card-program). | | `customizedInfo` | string | Allows you to [add text](#customized-info-customizedinfo) on the Card. | | `freeCustomizedInfo` | string | Allows you to [add more text](#free-customized-info-freecustomizedinfo) on the Card. | | `letterCustomizedInfo` | string | Allows you to [add text](#customized-info-lettercustomizedinfo) on letter that accompanies the Card. | | `embossLegalName` | boolean | Allows to emboss the User's `legalName` on the Card in addition to the cardholder's name, if defined to `true`. | | `sendToParent` | integer | Allows you to send the Card to the [parent User](/guide/users/parent-children), if defined to `1`. | **Configuration – Some fields are not available by default** Contact your *Treezor Account Manager* to set the `batchDeliveryId`, `customizedInfo`, `freeCustomizedInfo`, `letterCustomizedInfo`, `logoId`, `logoBackId`, and `packageId`. ### Request Endpoint: [`/v1/cards/RequestPhysical`](/api-reference/api-endpoints.html#tag/Cards/postCardPhysical){target="\_self"} ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/v1/cards/RequestPhysical' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "userId":{userId}, "walletId":{walletId}, "permsGroup":"TRZ-CU-016", "cardPrint":{cardPrint}, "cardTag":"This field can be populated as you see fit", "limitPaymentDaily":{limitPaymentDaily}, "limitAtmDaily":{limitAtmDaily} } ``` ::: Returns the Card, with its `cardId` (available in [CardTransactions](transactions)). For security reasons, cards are created in an inactive state. Once you are sure the end user has received the card, it must be [activated](#activation). ::: code-group ```json [JSON] { "cardId": 0, "userId": 0, "walletId": 0, "cardTag": "string", "statusCode": "UNLOCK", "isLive": 0, "pinTryExceeds": 0, "embossedName": "string", "expiryDate": "string", "CVV": "string", "limitsGroup": "string", "permsGroup": "string", "cardDesign": "string", "virtualConverted": 0, "optionAtm": 0, "optionForeign": 0, "optionOnline": 0, "optionNfc": 0, "limitAtmYear": 0, "limitAtmMonth": 0, "limitAtmWeek": 0, "limitAtmDay": 0, "limitAtmAll": 0, "limitPaymentYear": 0, "limitPaymentMonth": 0, "limitPaymentWeek": 0, "limitPaymentDay": 0, "limitPaymentAll": 0, "paymentDailyLimit": 0, "restrictionGroupLimits": [ { "paymentDailyLimit": 0, "mccRestrictionGroups": 0, "countryRestrictionGroups": 0, "merchantIdRestrictionGroups": 0 } ], "createdBy": 945198, "createdDate": "2023-10-31 10:37:04", "modifiedBy": 0, "modifiedDate": "0000-00-00 00:00:00", "renewalType": "A", "renewalDate": null, "originalCardId": null, "totalRows": null, // [...] some attributes are hidden } ``` ::: Endpoint: [`/cards`](/api-reference/pci-dss-dev.html#tag/Cards/createCard){target="\_self"} ::: code-group <<< @/guide/cards/snippets/create-card-pci.bash \[CURL] ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "userId":{userId}, "medium": "physical", "walletId":{walletId}, "permsGroup":"TRZ-CU-016", "cardPrint":{cardPrint}, "cardTag":"This field can be populated as you see fit", "limitPaymentDaily":{limitPaymentDaily}, "limitAtmDaily":{limitAtmDaily}, "sca": "eyJh_UxfQ.nNIH_n9kA" } ``` ::: Returns the Card, with its `cardId` (available in [CardTransactions](transactions)). For security reasons, cards are created in an inactive state. Once you are sure the end user has received the card, it must be [activated](#activation). ::: code-group ```json [JSON] { "cardId": 0, "userId": 0, "walletId": 0, "cardTag": "string", "statusCode": "UNLOCK", "isLive": 0, "pinTryExceeds": 0, "embossedName": "string", "expiryDate": "string", "CVV": "string", "limitsGroup": "string", "permsGroup": "string", "cardDesign": "string", "virtualConverted": 0, "optionAtm": 0, "optionForeign": 0, "optionOnline": 0, "optionNfc": 0, "limitAtmYear": 0, "limitAtmMonth": 0, "limitAtmWeek": 0, "limitAtmDay": 0, "limitAtmAll": 0, "limitPaymentYear": 0, "limitPaymentMonth": 0, "limitPaymentWeek": 0, "limitPaymentDay": 0, "limitPaymentAll": 0, "paymentDailyLimit": 0, "restrictionGroupLimits": [ { "paymentDailyLimit": 0, "mccRestrictionGroups": 0, "countryRestrictionGroups": 0, "merchantIdRestrictionGroups": 0 } ], "createdBy": 945198, "createdDate": "2023-10-31 10:37:04", "modifiedBy": 0, "modifiedDate": "0000-00-00 00:00:00", "renewalType": "A", "renewalDate": null, "originalCardId": null, "totalRows": null, // [...] some attributes are hidden } ``` ::: Physical Cards can be identified by the following attributes: * `physical` = `1` or * `physical` = `0` along with `virtualConverted` = `1` Treezor also sends a [`card.requestphysical`](./events#cardrequestphysical) webhook. ### Expedition tracking Treezor sends a [`card.expeditionTracking`](/guide/cards/events#card-expeditiontracking) webhook when the card manufacturer mails the physical card, allowing you to track the expedition and inform your end users. Expedition tracking is only available if your manufacturer is Idemia. ## Bulk Creation Depending on your use case, it may be more suitable for you to create Cards in bulk. **Configuration – Bulk Creation is not enabled by default** You can request access to this feature by contacting your *Treezor Account Manager*. ### Creation #### Parameters | Attribute | Type | Description | | --- | --- | --- | | `number` | integer | The number of cards to be created. There may be limitations to the maximum number of cards you can create at once. | | `medium` | integer | Defines whether the cards are to be Physical (1) or Virtual (1), or Virtual cards that can be converted into Physical ones (3). | | `userIdOwner` | boolean | The unique identifier of the user owning the cards. Required if `createUserForEach` is set to `false` or undefined. | | `createUserForEach` | boolean | Whether to automatically create users for each created card. Required if `userIdOwner` is set to `false`. | | `distributionCountry` | string | The country in which the end user is using your services. Available values may vary depending on your configuration, see [Distribution Country](/guide/users/introduction#distribution-country-distributioncountry) for more information. This field is only required when you operate in multiple countries and if `createUserForEach` is set to `true`. | | `defaultPermsGroup` | string | A code for a [preset of permissions](/guide/cards/restrictions-limits#options-permission-groups). It indicates whether the card main options (contactless, online payments, withdrawals, and international payments) are activated or not. | | `walletTypeId` | integer | The [type of Wallets](/guide/wallets/introduction#types-of-wallets) the cards will be associated to. | | `createWalletForEach` | boolean | Defines whether to create one Wallet per card. | | `cardDeliveryAddress1` | string | The first line of the delivery address for physical cards. | | `cardDeliveryPostCode` | string | The postal code of the delivery address. | | `cardDeliveryCity` | string | The city of the delivery address. | | `cardDeliveryCountry` | string | The [country](/guide/api-basics/data-format#countries) of the delivery address. | | `anonymous` | integer | Defines whether the cards are to belong to [Anonymous Users](/guide/users/physical#anonymous-users). If so set the value to `1`, otherwise `0`. | | `cardPrint` | string | The [Card Program](introduction#card-program) to associate to the Card and the options provided with it. This information is shared with you by Treezor. | | `logoId` | string | Customizes the cards with a [logo](#logo-logoid). | | `logoBackId` | string | Customizes the backside of the cards with a [logo](#back-logo-logobackid) by specifying the file's name. | | `packageId` | string | Customizes the [packaging](#packaging-packageid) of the cards. | | `customizedInfo` | string | Adds [text](#customized-info-customizedinfo) on the cards. | | `freeCustomizedInfo` | string | Adds [more text](#additional-customized-info-freecustomizedinfo) on the cards. | | `letterCustomizedInfo` | string | Adds [text](#customized-info-lettercustomizedinfo) on the letter that comes with the cards. | | `defaultMccRestrictionGroupId` | integer | The unique identifier of the MCC Restriction Group to associate with the cards. | | `defaultMerchantRestrictionGroupId` | integer | The unique identifier of the MID Restriction Group to associate with the cards. | | `defaultCountryRestrictionGroupId` | integer | The unique identifier of the Country Restriction Group to associate with the cards. | ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/core-connect/card/bulk' \ --header 'accept: application/json' \ --header 'authorization: Bearer {accessToken}' \ --header 'content-type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}`. ::: code-group ```json [JSON] { "number":5, "medium":2, "defaultPermsGroup":"TRZ-CU-016", "walletTypeId":10, "createWalletForEach":true, "createUserForEach":true, "cardDeliveryAddress1":"33 avenue Wagram", "cardDeliveryPostCode":"75017", "cardDeliveryCity":"Paris", "cardDeliveryCountry":"FR", "anonymous":1, "cardPrint":"8528", "logoId":"", "packageId":"" } ``` ::: Answers with a `201` HTTP Status Code and returns the following: ::: code-group ```json [JSON] { "number":5, "createUserForEach":true, "distributionCountry":"FR", "createWalletForEach":true, "walletTypeId":10, "medium":2, "cardPrint":"8528", "anonymous":1, "defaultPermsGroup":"TRZ-CU-016", "packageId":"", "logoId":"", "cardDeliveryAddress1":"33 avenue Wagram", "cardDeliveryPostCode":"75017", "cardDeliveryCity":"Paris", "cardDeliveryCountry":"FR", "orderId":"d1fca687-9dbd-4530-8a80-336f2b56421a", "status":"PENDING" } ``` ::: Bulk Creation are asynchronous, you therefore have a second endpoint to [follow their progress](#follow-bulk-creations). ### Follow Bulk Creations To follow your [Bulk Creations progress](#bulk-creation), you can use the following request ::: code-group ```bash [CURL] curl -X GET '{baseUrl}/core-connect/card/bulk' \ --header 'accept: application/json' \ --header 'authorization: Bearer {accessToken}' ``` ::: Returns the following. ::: code-group ```json [JSON] [ // this represents a Bulk Creation that completed with some errors // more information is contained in the "errors" attribute { "orderId":"0c6251ad-6b84-4e74-a926-8a193974248d", "walletIdAttach":null, "createWalletForEach":true, "walletTypeId":9, "userIdOwner":null, "createUserForEach":true, "number":1, "defaultMccRestrictionGroupId":null, "defaultMerchantRestrictionGroupId":null, "defaultCountryRestrictionGroupId":null, "defaultPermsGroup":"TRZ-CU-003", "status":"COMPLETE_WITH_ERROR", "createdAt":"2021-09-02T14:00:59+02:00", "errors":[ "[{\"code\":\"unexpected_error\",\"docurl\":\"https:\/\/developers.treezor.co\",\"type\":\"unexpected_internal_server_error\",\"message\":\"An unexpected error was raised in our server. Please try again later, if same result please contact support\"}]" ], "packageId":null, "logoId":null, "anonymous":1, "cardPrint":"8528", "paymentDailyLimit":null, "limitPaymentAll":null, "limitPaymentDay":null, "limitPaymentWeek":null, "limitPaymentMonth":null, "limitPaymentYear":null, "limitAtmAll":null, "limitAtmDay":null, "limitAtmWeek":null, "limitAtmMonth":null, "limitAtmYear":null, "medium":2, "cardDeliveryAddress1":"33 avenue Wagram", "cardDeliveryAddress2":null, "cardDeliveryAddress3":null, "cardDeliveryPostCode":"75017", "cardDeliveryCity":"Paris", "cardDeliveryState":null, "cardDeliveryCountry":"FR", "distributionCountry": null }, // this represents a Bulk Creation that succeeded without any errors { "orderId":"11520318-6c26-4207-aebb-97280a857537", "walletIdAttach":922972, "createWalletForEach":null, "walletTypeId":null, "userIdOwner":1731771, "createUserForEach":null, "number":50, "defaultMccRestrictionGroupId":null, "defaultMerchantRestrictionGroupId":null, "defaultCountryRestrictionGroupId":null, "defaultPermsGroup":"TRZ-CU-016", "status":"COMPLETE", "createdAt":"2021-08-23T10:55:28+02:00", "errors":[], "packageId":null, "logoId":null, "anonymous":1, "cardPrint":"8528", "paymentDailyLimit":null, "limitPaymentAll":null, "limitPaymentDay":null, "limitPaymentWeek":null, "limitPaymentMonth":null, "limitPaymentYear":null, "limitAtmAll":null, "limitAtmDay":null, "limitAtmWeek":null, "limitAtmMonth":null, "limitAtmYear":null, "medium":1, "cardDeliveryAddress1":null, "cardDeliveryAddress2":null, "cardDeliveryAddress3":null, "cardDeliveryPostCode":null, "cardDeliveryCity":null, "cardDeliveryState":null, "cardDeliveryCountry":null, "distributionCountry": null }, // this represents a Bulk Creation that is still pending { "orderId":"1775d8da-2edc-46b6-87d6-948bc184511b", "walletIdAttach":null, "createWalletForEach":true, "walletTypeId":10, "userIdOwner":null, "createUserForEach":true, "number":5, "defaultMccRestrictionGroupId":5053, "defaultMerchantRestrictionGroupId":4932, "defaultCountryRestrictionGroupId":2410, "defaultPermsGroup":"TRZ-CU-016", "status":"PENDING", "createdAt":"2021-10-26T10:54:53+02:00", "errors":[], "packageId":null, "logoId":null, "anonymous":1, "cardPrint":"8529", "paymentDailyLimit":null, "limitPaymentAll":null, "limitPaymentDay":null, "limitPaymentWeek":null, "limitPaymentMonth":null, "limitPaymentYear":null, "limitAtmAll":null, "limitAtmDay":null, "limitAtmWeek":null, "limitAtmMonth":null, "limitAtmYear":null, "medium":1, "cardDeliveryAddress1":"10 avenue Vagram", "cardDeliveryAddress2":null, "cardDeliveryAddress3":null, "cardDeliveryPostCode":"75000", "cardDeliveryCity":"Paris", "cardDeliveryState":null, "cardDeliveryCountry":"FR", "distributionCountry": null } ] ``` ::: ## Activation As a security measure, all Cards are issued in an `inactive` state to ensure that a Physical Card is not usable before the cardholder receives it. A Card in an `inactive` state cannot be used to make any type of payment or withdrawal. Typically, the end user would be required to activate the card in your application by entering the `publicToken` as printed on the back of the received Card. ::: code-group ```bash [CURL] curl -X PUT '{baseUrl}/v1/cards/{id}/Activate' \ --header 'Authorization: Bearer {accessToken}' ``` ::: Returns a Card object, with its `isLive` attribute set to `1`. ::: code-group ```json [JSON] { "cardId": 0, "userId": 0, "walletId": 0, "walletCardtransactionId": 0, "mccRestrictionGroupId": 0, "merchantRestrictionGroupId": 0, "countryRestrictionGroupId": 0, "publicToken": "string", "cardTag": "string", "statusCode": "UNLOCK", "isLive": 1, // <--- affected attribute // [...] some attributes are hidden } ``` ::: Users of may also activate a Card in one step, using its `publicToken` directly. ::: code-group ```bash [CURL] curl -X PUT '{baseUrl}/v1/cards/{cardToken}/public-token-activation' \ --header 'Authorization: Bearer {accessToken}' ``` ::: Also returns a Card object, with its `isLive` attribute set to `1`. Treezor also sends a [`card.activate`](./events#card-activate) webhook. ## Enrolling a Card for 3D Secure ## Customization Cards can be customized with the following values. **Configuration – There is no API endpoint to manage these features.** If you are interested in customizing the cards, please contact your *Treezor Account Manager*. ### Logo (`logoId`) You can add a customized logo by setting its filename in the `logoId` parameter. This logo is overlaid to your usual Card Design. The constraints are as follows: * **Format**: `.jpeg`, `.pcx` or `.png` (other formats need to be checked for compatibility) * **Definition**: 600 PPI * **Maximum size**: depends on your Card Design * **String**: Can't exceed 30 characters * **Transparent background** is recommended. In any case, white content will not be printed. ### Back Logo (`logoBackId`) You can add a customized logo on the backside of the Card by setting its filename in the `logoBackId` parameter. This logo is overlaid to your usual Card Design. The constraints are as follows: * **Format**: `.jpeg`, `.pcx` or `.png` (any other format will have to be checked for compatibility) * **Definition**: 600 PPI * **Maximum size**: depends on your Card Design * **String**: Can't exceed 30 characters * **Transparent background** is recommended. In any case, white content will not be printed. ### Card Delivery Method (`deliveryMethod`) You can define the method the manufacturer uses to send the cards (e.g., delivery with or without tracking). The possible options are to be defined with your *Treezor Account Manager*. They range from `0` to `9` and depend on your specific implementation with the manufacturer. ### Pin Mailer (`pinMailer`) You can request the card manufacturer to send the card PIN code by letter. This requires a specific configuration of the card production chain with the manufacturer by your *Treezor Account Manager*. Then, this option can be activated by your *Technical Account Manager* or *Implementation Manager*. Once the feature activated, you can define whether to use the card PIN code by letter by setting the `pinMailer` value to `1`. ### Batch Delivery (`batchDeliveryId`) The Batch Delivery system lets you receive physical cards in batches if enabled. Cards with the same values for the parameters below are sent together. | Information | Description | | --- | --- | | **Delivery ID** | All the cards must have the same `batchDeliveryId` value (must be between `1` and `238327`). | | **Address** | All the cards must have the same delivery address. Please keep in mind that the delivery parameters of the card default to either: The address defined at the user levelThe address of the parent of the user the card belongs to if the `sendToParent` parameter is set to `1`. | **Information – Batch orders are generated daily** Treezor usually sends the batch orders to the manufacturer in the afternoon. If cards with the same `batchDeliveryId` are created before and after the cut-off time, they are likely to be sent in 2 different batches. ### Packaging (`packageId`) The `packageId` allows you to use multiple Cards Packaging with the same [Card Program](./introduction#card-program). This feature can also be used to handle packaging in different languages. This is set up between you and your *Treezor Account Manager*. ### Designs (`designCode`) The `designCode` allows you to use multiple Card Designs with the same [Card Program](./introduction#card-program). This design applies to [Virtual Cards](#virtual-card-creation), [Physical Cards](#physical-card-creation), and [digitized Cards](x-pay-google-apple). To use a specific design, you will need to specify the `designCode` along with your usual `cardPrintId`. The final design identification code will be a concatenation of the `cardPrintId` + `z` + `designCode`. Once created, Card objects returned by the API will not specify which `designCode` was used. It is therefore recommended that you store this information in your own databases. ### Customized Info (`customizedInfo`) The `customizedInfo` allows you to add specific text on each Card. There is a maximum of 27 alphanumeric characters excluding `!"#%'(),:;<>?@[]^` and the backtick symbol. The actual length limitation will depend on the choosen font and on the position of the text on the Card. ### Additional Customized Info (`freeCustomizedInfo`) The `freeCustomizedInfo` allows you to add more specific text on each Card in a similar way to `customizedInfo`. There is a maximum of 50 alphanumeric characters excluding `!"#%'(),:;<>?@[]^` and the backtick symbol. The actual length limitation will depend on the choosen font and on the position of the text on the Card. ### Letter Customized Info (`letterCustomizedInfo`) The `letterCustomizedInfo` allows you to add specific text on the letter that accompanies a Card. There is a maximum of 50 alphanumeric characters excluding `!"#%'(),:;<>?@[]^` and the backtick symbol. --- --- url: /guide/user-verification/documents.md description: >- Technical guide for creating and managing KYC documents via the Treezor API. Includes required parameters, request structure, and response examples. --- # Documents Documents are evidence required by Treezor to ensure Users are who they claim to be. During the KYC/B review, Treezor compares documents to the user’s declarative data. The user is verified if the documents are in order (as well as any other verification requirement). Users may follow different verification processes depending on their type and distribution country. Processes that result in the creation of a Document object in the Treezor API are uploads through: * [Your application](#process) (document endpoints) * [The Document pre-review](./documents-prereview) feature (pre-signed form) * [The Live verification](./live-verification) features * [The Qualified Electronic Signature](./qes) feature This article focuses on the Document object and the upload made directly using the Treezor API Document endpoints. **Configuration – Documents must:** * Abide by size restrictions (encoded file < 6Mo / original file < 4.5Mo) * Be in mime type: `application/pdf`, `image/jpg`, `image/png`, `image/tiff`, or `image/svg+xml` * Be converted to [base64](/guide/api-basics/data-format#files) ## Process Uploading documents through the dedicated endpoints can be done in 2 ways. | | Method | Description | | --- | --- | --- | | | As application | The user first uploads documents to your application, so you can check them before uploading them to Treezor. | | | As end user | You upload the documents in the end user’s name with the grant type `delegated_end_user` JWT. This method is only available if the SCA feature is activated for your environment. It may result in a lower success rate of the KYC review since you don’t review documents first. | Each method has its advantages and drawbacks. If you are unsure about which to implement, don’t hesitate to contact Treezor. If we take the first case, the steps are the following: * [User](/guide/users/introduction) uploads documents to your application (requiring dedicated code on your side) * You check that the documents are acceptable * You forward the documents to the [`/v1/documents`](/api-reference/api-endpoints.html#tag/User%20Documents/createDocuments){target="\_self"} endpoint. You receive a [`document.create`](/guide/user-verification/events#document-create) webhook for each document upload. * Once all the documents for a given user are uploaded, you request a review process using the following endpoint: [`/v1/users/{id}/Kycreview`](/api-reference/api-endpoints.html#tag/User%20KYC%20Review){target="\_self"} * Treezor sends you a [`user.kycreview`](/guide/user-verification/events#user-kycreview) webhook upon validation or refusal. **Note – More steps may be required** This is a simple example of a KYC Review process. It doesn’t consider multiple methods usage, parent-children hierarchical relations, and additional vigilance measures. ## Collect documents This is the first step if you choose to have the user upload documents to your application or website. You store documents in your cloud infrastructure before passing them on to Treezor. Your teams should review the documents before uploading them to Treezor. Ensuring documents abide by the requirements results in a higher KYC success rate. **Caution – Regulation** Depending on your local regulations, you may not be allowed to keep or store KYC documents on your infrastructure. ## Upload documents You need to upload all the documents of a given user before requesting a KYC review. It may include the documents of the children users in the case of a parent-children hierarchical relation. ### Parameters Below are the necessary parameters to create Documents. | Attribute | Type | Description | |--- |--- |--- | | `userId` | integer | The unique identifier of the User the document belongs to. | | `documentTypeId` | integer | The type of the document. See the [Types list](#types-documenttypeid) below. | | `name` | string | The name of the document, including its extension. | | `fileContentBase64` | string | The document itself. The file must be encoded in standard base64 (RFC 4648). | | `residenceId` | integer | The unique identifier of the User's Tax Residence. Only required if the `documentTypeId` is `24` or `25`. | **API – API Reference available** For a complete list of Document attributes, check the [User Documents](/api-reference/api-endpoints.html#tag/User%20Documents){target="\_self"} section of the API Reference. ### Request You can use the [`/v1/documents`](/api-reference/api-endpoints.html#tag/User%20Documents/createDocuments){target="\_self"} request for each document you need to upload. Use an access token with the `delegated_end_user` grant type if you’re uploading the documents in the end user's name. ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/v1/documents' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload} ``` ::: Here is a `{payload}` example: ::: code-group ```json [JSON] { "fileContentBase64": "{base64file}", "userId":123456, "documentTypeId":9, "name":"aoak_identity_card.pdf" } ``` ::: Returns the Document object. ::: code-group ```json [JSON] { "documents": [ { "documentId": 980190, "documentTag": null, "clientId": 929252, "userId": 100344292, // Associated user "userFirstname": null, "userLastname": null, "name": "Test_id", "documentStatus": "PENDING", // Document current review status "documentTypeId": 9, "documentType": "ID", "fileName": "980190.pdf", "thumbFileName": "", "createdDate": "2024-04-30 14:13:40", "modifiedDate": "0000-00-00 00:00:00", "codeStatus": "600003", "informationStatus": null, "residenceId": 0, "temporaryUrl": "", // Deprecated "temporaryUrlThumb": "" // Deprecated } ] } ``` ::: Treezor also sends a [`document.create`](./events#document-create) webhook. ## Upload large Documents Treezor provides a specific endpoint for documents whose original file size exceeds 4.5Mo. Instead of directly [uploading the document](#upload-documents) in base64, you will follow 2 steps: 1. [Generate pre-signed URL](#1-generate-pre-signed-url) – Send document information to get the pre-signed URL. 2. [Upload document](#2-upload-document) – Make the request to the `uploadUrl`. ### 1. Generate pre-signed URL #### Parameters Below are the necessary parameters to create Documents. | Attribute | Type | Description | |--- |--- |--- | | `userId` | integer | The unique identifier of the User the document belongs to. | | `documentTypeId` | integer | The type of the document. See the [Types list](#types-documenttypeid) below. | | `name` | string | The name of the document, including its extension. | | `residenceId` | integer | The unique identifier of the User's Tax Residence. Only required if the `documentTypeId` is `24` or `25`. | | `fileExtension` | string | The file extension of the document (jpg, png, svg, tif, or pdf). | | `fileSize` | integer | The size of the document (max: 50MB). | | `fileHash` | string | Hexadecimal hash of the document file (SHA256). | **API – API Reference available** For a complete list of Document attributes, check the [User Documents](/api-reference/api-endpoints.html#tag/User%20Documents){target="\_self"} section of the API Reference. #### Request example Use the [`/v1/documents/uploadUrl`](/api-reference/api-endpoints.html#tag/User%20Documents/createDocuments){target="\_self"} request for each document you need to upload. ::: code-group ```bash [CURL] curl -X POST'{baseUrl}/v1/documents/uploadUrl' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload} ``` ::: Here is a `{payload}` example: ::: code-group ```json [JSON] { "userId":123456, "documentTypeId":9, "name": "alex oak identity card", "fileExtension": "pdf", "fileSize": 1048576, "fileHash": "c27d4142972f30ac6ead183e54437f1b993a64994b342a7261337bc5a7a7e447" } ``` ::: Returns the Upload URL with all the necessary information for step 2. ::: code-group ```json [JSON] { "documentId": 1236516, "uploadUrl": "https://test.s3.eu-central-1.amazonaws.com", "values": { "Content-Type": "application/pdf", "X-Amz-Algorithm": "AWS4-HMAC-SHA256", "X-Amz-Credential": "ASIAWTKIE63XXXYQM735/20250627/eu-central-1/s3/aws4_request", "X-Amz-Date": "20250627T134703Z", "X-Amz-Meta-autovalidate": "true", "X-Amz-Meta-client": "12345", "X-Amz-Meta-full_filename": "1236516.jpg", "X-Amz-Security-Token": "IQoJb3JpZ2luX2VjEXxXxXXV1LW[...]heZZA==", "X-Amz-Signature": "f06cdc708e87b2b007bcbf7a1af2df[...]c2407d594cbd452ee34b7", "X-Amz-checksum-algorithm": "SHA256", "X-Amz-checksum-sha256": "wn1BQpcvMKxurRg+VEN/G5k6[...]TN7xaen5Ec=", "key": "client_12345/user_102273999/1236516.jpg", "policy": "eyJjb25[...]AzWiJ9" }, "expireIn": 120 } ``` ::: The upload link expires after 2 minutes. ### 2. Upload Document Make a POST request to the `uploadUrl` with all the relevant values within 2 minutes after the URL was generated. ::: code-group ```bash [CURL] curl -X POST "https://test.s3.eu-central-1.amazonaws.com" \ --form "X-Amz-checksum-algorithm=SHA256" \ --form "X-Amz-checksum-sha256=wn1BQpcvMKxurRg+VEN/G5k6[...]TN7xaen5Ec=" \ --form "Content-Type=application/pdf" \ --form "X-Amz-Date=20250627T134703Z" \ --form "key=client_929252/user_102273999/1236516.jpg" \ --form "policy=eyJjb25[...]AzWiJ9" \ --form "X-Amz-Algorithm=AWS4-HMAC-SHA256" \ --form "X-Amz-Credential=ASIAWTKIE63XXXYQM735/20250627/eu-central-1/s3/aws4_request" \ --form "X-Amz-Security-Token=IQoJb3JpZ2luX2VjEXxXxXXV1LW[...]heZZA==" \ --form "X-Amz-Signature=f06cdc708e87b2b007bcbf7a1af2df[...]c2407d594cbd452ee34b7" \ --form "X-Amz-Meta-autovalidate=true" \ --form "X-Amz-Meta-client=12345" \ --form "X-Amz-Meta-full_filename=123456.pdf" --form "file=@/path/to/file.pdf" ``` ::: If the upload is successful, you receive an HTTP 204 No Content response. Treezor also sends a [`document.create`](./events#document-create) webhook. ## Download documents If you're eligible, you may be able to collect some of the uploaded documents whose `documentTypeId` allows for it. **Configuration – Download is not enabled by default** Please contact Treezor to request access to this feature. Downloading a document is a 2-step process, in which you: 1. [Request the download URL](#request-the-download-url) 2. [Download the document within 30 seconds](#download-the-document) ### Request the download URL To request the download URL, you need the corresponding `documentId` (available in the `document.create` webhook for instance). ::: code-group ```bash [CURL] curl -X GET '{baseUrl}/v1/documents/{documentId}/download' \ --header 'Authorization: Bearer {accessToken}' \ ``` ::: Returns the URL to download the document, with all the necessary query parameters for the next step. ::: code-group ```json [JSON] { "url": "{documentDownloadUrl}" } ``` ::: The link expires after 5 minutes. ### Download the document You have 5 minutes to download the document from the moment the presigned URL has been generated in the previous step. ::: code-group ```bash [CURL] curl -X GET '{documentDownloadUrl}' ``` ::: The document is returned in its initial format. ## Document key attributes | Attribute | Type | Description | | --- | --- | --- | | `userId` | integer | The unique identifier of the User. | | `documentStatus` | string | The current KYC review status of the document. See [table](#status-documentstatus) below. | | `documentTypeId` | integer | The type of document, such as ID Card, driving license, etc. See [table](#types-documenttypeid) below. | | `name` | string | The name of the file, including the extension. | | `residenceId` | integer | The unique identifier of the User's [`taxResidence`](/guide/user-verification/tax-residence), which is mandatory with `documentTypeId` set to `24` and `25`. | | `fileContentBase64` | string | Base64-encoded [file](/guide/api-basics/data-format#files). | ### Types (`documentTypeId`) | `documentTypeId` | `documentType` | Description | |:---: |--- |--- | | `2` | `Police record` | Police record | | `4` | `KBIS` | Company Registration | | `6` | `CV` | CV | | `7` | `Sworn statement` | Sworn statement | | `8` | `Prévisionnels` | Turnover | | `9` | `ID` | Identity card | | `11` | `RIB` | Bank Identity Statement | | `12` | `Proof of address` | Proof of address | | `13` | `MOBILE_BILL` | Mobile phone invoice | | `14` | `INVOICE` | Invoice, other than Mobile phone invoice | | `15` | `RESIDENCE_PERMIT` | Residence permit | | `16` | `DRIVING_LICENCE` | Driving license | | `17` | `PASSPORT` | Passport | | `18` | `PROXY` | Proxy granting an employee | | `19` | `COMPANY_REGISTRATION` | Company registration official paper | | `20` | `TAX_CERTIFICATE` | Official tax certificate | | `21` | `PAYSLIP` | Employee payment notice | | `22` | `BANK_STATEMENT` | User bank statement | | `23` | `LEGAL_STATUS` | Business legal status | | `24` | `TAX_STATEMENT` | Tax Statement | | `25` | `EXEMPTION_STATEMENT` | Exemption Statement | | `26` | `LIVENESS_RESULT` | Liveness result | | `27` | `HEALTH_INSURANCE_CARD` | Health insurance card | | `28` | `SIREN` | SIREN | | `29` | `RBE` | RBE - List of beneficial owners | | `31` | `PEP_ASSETS_DECLARATION` | PEP - Assets Declaration | | `32` | `PRO_REVENUE_DECLARATION` | Professional - Revenue Declaration | | `33` | `NON_PROFIT_ORG_DECLARATION` | Non-Profit Organization - Financial Declaration | | `34` | `CERTIFIED_LIVENESS_RESULT` | Certified Liveness Result | | `35` | `NATURAL_REVENUE_ASSETS_REPORT` | Natural Person - Revenue and Assets Declaration | | `36` | `REAL_ESTATE_PROOF_OF_OWN` | Real Estate - Proof of ownership | | `37` | `PROOF_OF_SECURITIES_EXCHANGE` | Proof of Securities Exchange Listing | | `38` | `IDENTITY_VIA_AUTH_THIRD_PARTY` | Identity Verification Form via an Authorized Third Party | | `39` | `FINANCIAL_STATEMENT` | Financial Statement | | `40` | `PUBLIC_ACCOUNTANT_STATEMENT` | Public Accountant Statement | | `41` | `FAMILY_RECORD_BOOK` | Family Record Book | | `42` | `BIRTH_CERTIFICATE` | Birth certificate | | `43` | `POWER_OF_ATTORNEY` | Power of attorney | | `44` | `ORG_CHART_VIA_AUTH_THIRD_PARTY` | Organizational Chart via an Authorized Third Party | | `45` | `COMPANY_REPORT_VIA_INDEP_PARTY` | Official Company Declaration via an Independent Third Party | | `46` | `DECLARATION_ACTIVITY_REVENUES` | Declaration of activity and revenues | | `47` | `QES_CERTIFICATE` | Certificate of the qualified e-signature. | | `48` | `QES_RESULT` | Result of the qualified e-signature | | `49` | `VIDEO_CONFERENCE_RESULT` | Result of the Video Conference | | `50` | `CAPITALIZATION_TABLE` | Capitalization table | ### Status (`documentStatus`) | `codeStatus` | |`documentStatus` | Description | |:---: |:---: | --- |--- | | `600001` | | **PENDING** | Initial status before upload into the container | | `600002` | | **PENDING** | Suspected fraud or [AML/CFT](/guide/overview/glossary#anti-money-laundering-and-countering-the-financing-of-terrorism-aml-cft) | | `600003` | | **PENDING** | Successfully uploaded into the container | | `600004` | | **CANCELED** | Cancelled by the user | | `600005` | | **CANCELED** | Cancelled by the operator | | `600006` | | **CANCELED** | Failed to write the document into the container | | `600007` | | **CANCELED** | Failed to read the document from the container | | `600008` | | **REFUSED** | Refused | | `600009` | | **VALIDATED** | Validated | | `600010` | | **REFUSED** | Out of scope | | `600011` | | **REFUSED** | Expired | | `600012` | | **REFUSED** | Falsified | | `600013` | | **REFUSED** | Illegible | | `600014` | | **REFUSED** | Truncated document | | `600015` | | **REFUSED** | Truncated | | `600016` | | **REFUSED** | Incoherent | | `600017` | | **REFUSED** | Other | ## Document object ::: code-group ```json [JSON] { "documentId": 0, "documentTag": "string", "clientId": 0, "userId": 0, "userFirstname": "string", // Deprecated "userLastname": "string", // Deprecated "name": "string", "documentStatus": "string", "documentTypeId": 0, "documentType": "sring", "fileName": "string", "thumbFileName": "string", // Deprecated "createdDate": "string", "modifiedDate": "string", "codeStatus": "string", "informationStatus": "string", "residenceId": 0, "temporaryUrl": "string", // Deprecated "temporaryUrlThumb": "string" // Deprecated } ``` ::: ## Endpoints | Endpoint |[Scope](/guide/api-basics/authentication#available-scopes) | | --- | --- | | [`/v1/documents`](/api-reference/api-endpoints.html#tag/User%20Documents/createDocuments){target="\_self"} Create a document | `read_write` | | [`/v1/documents/uploadUrl`](/api-reference/api-endpoints.html#tag/User%20Documents/createDocuments){target="\_self"} Upload a large document | `read_write` | | [`/v1/documents`](/api-reference/api-endpoints.html#tag/User%20Documents/getDocuments){target="\_self"} Search for documents | `read_only` | | [`/v1/documents/{documentId}`](/api-reference/api-endpoints.html#tag/User%20Documents/getDocument){target="\_self"} Retrieve a specific document based on its `id` | `read_only` | | [`/v1/documents/{documentId}`](/api-reference/api-endpoints.html#tag/User%20Documents/putDocument){target="\_self"} Update a document `name` | `read_write` | | [`/v1/documents/{documentId}`](/api-reference/api-endpoints.html#tag/User%20Documents/deleteDocument){target="\_self"} Delete a document | `read_write` | | [`/v1/documents/{documentId}/download`](/api-reference/api-endpoints.html#tag/User%20Documents/getDocumentDownloadUrl){target="\_self"} Retrieve a document download URL | `read_only` | | [`/v1/users/{userId}/Kycreview`](/api-reference/api-endpoints.html#tag/User%20KYC%20Review/putKycreview){target="\_self"} Initiate the user [KYC review](/guide/user-verification/introduction) process | `read_write` | --- --- url: /guide/users/legal-entity.md description: >- Technical guide for creating legal entities via the Treezor API. Also explains how to check for information veracity and finding the legal representatives. Includes required parameters, request structure, and response examples. --- # Legal Entities A **Legal Entity** is a company, a governmental or non-governmental organization, or an association. It is identified by a legal name, legal register number, etc. The legal representatives and majority shareholders must have a [parent-children](/guide/users/parent-children) hierarchical relation with the Legal Entity. They are themselves created as [Physical Users](/guide/users/physical). **Information – Specific case of self-employed persons** Freelancers and self-employed persons (known as *auto-entrepreneur* in France) should be created as [Physical Users](/guide/users/physical) with a `legalForm` set to `1000`. ## Creation ### Parameters Below are the necessary parameters to create Legal Entities. While some parameters might not be required by the API, they are necessary when it comes to the KYC validation of the user. They should be collected from the creation (or you may have to update the user information later on). | Attribute | Type | Description | |--- |--- |--- | | `userTypeId` | integer | Must be `2` (business), `3` (non-governmental organization), or `4` (governmental organization) for legal entities. | | `specifiedUSPerson`  | integer | Indicates if the user [is a US Person](/guide/user-verification/tax-residence#the-specific-case-of-us-taxpayers). | | `email` | string | The email of the legal entity, which must be [unique and valid](./introduction#using-unique-and-valid-email-addresses) and can't exceed 200 characters. |  | `address{1-3}` (required for KYC) | string | The legal entity's postal address. The max value for each address line is 150 characters. If you're issuing cards, see the [Data Formats](/guide/api-basics/data-format#addresses) article for information on further limitations. | | `postcode` (required for KYC) | string | The legal entity's address postcode. | | `city` (required for KYC) | string | The legal entity's address city. | | `country` (required for KYC) | string | The legal entity's address country (format ISO 3166-1 alpha-2) | | `phone` (required for KYC) | string | The legal entity's phone number, in international E.164 format. | | `legalName` (required for KYC) | string | The name of the company. | | `legalRegistrationNumber` (required for KYC) | string | The registration number of the legal entity (e.g., SIREN/SIRET). | | `legalForm` (required for KYC) | string | The legal category of the legal entity. See the [list of legal forms](#legal-forms-legalform). | | `legalTvaNumber` | string | The VAT number of the legal entity. | | `legalRegistrationDate` (required for KYC) | string | The registration date of the company. Format: YYYY-MM-DD. | | `legalShareCapital` | integer | The share capital of the legal entity. | | `legalAnnualTurnOver` (required for KYC) | string | The annual turn over of the legal entity in k€, among the following ranges: `0-39`, `40-99`, `100-249`, `250-999`, `1000-2999`, `3000-9999`, `10000-99999`, and `100000-*` | | `legalNetIncomeRange` (required for KYC) | string | The net income of the legal entity in k€, among the following ranges: `0-4`, `5-9`, `10-49`, `50-149`, `150-499`, and `500-*`. | | `legalNumberOfEmployeeRange` (required for KYC) | string | The number of employees of the legal entity among the following ranges: `0`, `1-9`, `10-99`, `100-249`, and `250-*` | | `legalSectorType` | string | Either `NAF` or `NACE`, qualifies the type of data in the `legalSector` field. | | `legalSector` (required for KYC) | string | The business sector of the legal entity. Either a 4-digit code if NACE or a 5-digit code followed by an uppercase letter if [NAF](/guide/overview/glossary#nomenclature-activites-francaise-naf), depending on the value of the `legalSectorType`. | | `distributionCountry` | string | The country in which the end user is using your services. This field is only required when you operate in multiple countries. See [Distribution country](/guide/users/introduction#distribution-country-distributioncountry) for more information. | ### Request example Endpoint: [`/v1/users`](/api-reference/api-endpoints.html#tag/Users/postUsers){target="\_self"} ::: code-group <<< @/guide/users/snippets/create\_user.bash \[CURL] ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "userTypeId":2, "specifiedUSPerson":0, "email":"contact.company@example.com", "address1":"56 Bluewoods lane", "postcode":"75000", "city":"Paris", "country":"FR", "phone":"+33102030405", "legalName":"Treehouse Company", "legalRegistrationNumber":"42877171100028", "legalTvaNumber":"FR27807465059", "legalRegistrationDate":"2007-10-24", "legalShareCapital": 4236474, "legalForm":"5510", "legalAnnualTurnOver":"100-249", "legalNetIncomeRange":"50-149", "legalNumberOfEmployeeRange":"100-249", "legalSectorType":"NAF", "legalSector":"1234F", "entitySanctionsQuestionnaire": 1, "activityOutsideEu": 1, "economicSanctions": 0, "residentCountriesSanctions": 0, "involvedSanctions": 0 } ``` ::: Returns a User object: ::: code-group ```json [JSON] { "users": [ { "userId": 100138128, "userTypeId": 2, "userStatus": "VALIDATED", "userTag": "", "parentUserId": 0, "parentType": "", "controllingPersonType": 0, "employeeType": 0, "specifiedUSPerson": 0, "title": "", "firstname": "", "lastname": "", "middleNames": "", "birthday": "0000-00-00", "email": "contact.company@example.com", "address1": "56 Bluewoods lane", "address2": "", "postcode": "75000", "city": "Paris", "state": "", "country": "FR", "countryName": "France", "phone": "+33102030405", "mobile": "", "nationality": "", "nationalityOther": "", "placeOfBirth": "", "birthCountry": "", "occupation": "", "incomeRange": "", "legalName": "Treehouse Company", "legalNameEmbossed": "Treehouse Company", "legalRegistrationNumber": "42877171100028", "legalTvaNumber": "FR27807465XX", "legalRegistrationDate": "2007-10-24", "legalForm": "5510", "legalShareCapital": 4236474, "entityType": null, "legalSector": "1234F", "legalAnnualTurnOver": "100-249", "legalNetIncomeRange": "50-149", "legalNumberOfEmployeeRange": "100-249", "effectiveBeneficiary": 0, "kycLevel": 2, "kycReview": 0, "kycReviewComment": "", "isFreezed": 0, "isFrozen": null, "language": "", "optInMailing": null, "sepaCreditorIdentifier": "", "taxNumber": "", "taxResidence": "", "position": "", "personalAssets": "", "createdDate": "2024-02-15 09:10:05", "modifiedDate": "0000-00-00 00:00:00", "walletCount": 0, "payinCount": 0, "totalRows": "1", "activityOutsideEu": 1, "economicSanctions": 0, "residentCountriesSanctions": 0, "involvedSanctions": 0, "entitySanctionsQuestionnaire": 1, "address3": null, "timezone": null, "occupationType": "", "isOnStockExchange": 0, "secondaryAddress1": "", "secondaryAddress2": "", "secondaryAddress3": "", "secondaryPostcode": "", "secondaryCity": "", "secondaryState": "", "secondaryCountry": "", "clientId": "929252", "sanctionsQuestionnaireDate": null, "codeStatus": "110009", "informationStatus": "", "legalSectorType": "NAF", "sourceOfFunds": "", "occupationCategory": null, "personalAssetsRange": null, "monthlyIncomeRange": null } ] } ``` ::: Endpoint: [`/users`](/api-reference/pci-dss-dev.html#tag/Users/postUsers){target="\_self"} ::: code-group <<< @/guide/users/snippets/create\_user\_pci.bash \[CURL] ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "userTypeId":2, "specifiedUSPerson":0, "email":"contact.company@example.com", "address1":"56 Bluewoods lane", "postcode":"75000", "city":"Paris", "country":"FR", "phone":"+33102030405", "legalName":"Treehouse Company", "legalRegistrationNumber":"42877171100028", "legalTvaNumber":"FR27807465059", "legalRegistrationDate":"2007-10-24", "legalShareCapital": 4236474, "legalForm":"5510", "legalAnnualTurnOver":"100-249", "legalNetIncomeRange":"50-149", "legalNumberOfEmployeeRange":"100-249", "legalSectorType":"NAF", "legalSector":"1234F", "entitySanctionsQuestionnaire": 1, "activityOutsideEu": 1, "economicSanctions": 0, "residentCountriesSanctions": 0, "involvedSanctions": 0 } ``` ::: Returns a User object: ::: code-group ```json [JSON] { "users": [ { "userId": 100138128, "userTypeId": 2, "userStatus": "VALIDATED", "userTag": "", "parentUserId": 0, "parentType": "", "controllingPersonType": 0, "employeeType": 0, "specifiedUSPerson": 0, "title": "", "firstname": "", "lastname": "", "middleNames": "", "birthday": "0000-00-00", "email": "contact.company@example.com", "address1": "56 Bluewoods lane", "address2": "", "postcode": "75000", "city": "Paris", "state": "", "country": "FR", "countryName": "France", "phone": "+33102030405", "mobile": "", "nationality": "", "nationalityOther": "", "placeOfBirth": "", "birthCountry": "", "occupation": "", "incomeRange": "", "legalName": "Treehouse Company", "legalNameEmbossed": "Treehouse Company", "legalRegistrationNumber": "42877171100028", "legalTvaNumber": "FR27807465XX", "legalRegistrationDate": "2007-10-24", "legalForm": "5510", "legalShareCapital": 4236474, "entityType": null, "legalSector": "1234F", "legalAnnualTurnOver": "100-249", "legalNetIncomeRange": "50-149", "legalNumberOfEmployeeRange": "100-249", "effectiveBeneficiary": 0, "kycLevel": 2, "kycReview": 0, "kycReviewComment": "", "isFreezed": 0, "isFrozen": null, "language": "", "optInMailing": null, "sepaCreditorIdentifier": "", "taxNumber": "", "taxResidence": "", "position": "", "personalAssets": "", "createdDate": "2024-02-15 09:10:05", "modifiedDate": "0000-00-00 00:00:00", "walletCount": 0, "payinCount": 0, "totalRows": "1", "activityOutsideEu": 1, "economicSanctions": 0, "residentCountriesSanctions": 0, "involvedSanctions": 0, "entitySanctionsQuestionnaire": 1, "address3": null, "timezone": null, "occupationType": "", "isOnStockExchange": 0, "secondaryAddress1": "", "secondaryAddress2": "", "secondaryAddress3": "", "secondaryPostcode": "", "secondaryCity": "", "secondaryState": "", "secondaryCountry": "", "clientId": "929252", "sanctionsQuestionnaireDate": null, "codeStatus": "110009", "informationStatus": "", "legalSectorType": "NAF", "sourceOfFunds": "", "occupationCategory": null, "personalAssetsRange": null, "monthlyIncomeRange": null } ] } ``` ::: Treezor also sends a [`user.create`](./events#user-create) webhook. ## Checking for veracity When onboarding a Legal Entity, checking for the veracity of the provided information is key. Treezor offers a dedicated endpoint to help you in checking these. ### Query parameters Here are the necessary parameters to pass in the queryString. | Attribute | Type | Description | |--- |--- |--- | | `country` | string | The country of registration of the legal entity. | | `vatNumber` | string | The VAT number of the legal entity. Required if the `registrationNumber` is left empty. | | `registrationNumber` | string | The registration number (e.g., SIREN) of the legal entity. Required if the `vatNumber` is left empty. | ### Request examples Endpoint: [`/v1/businesssearchs`](/api-reference/api-endpoints.html#tag/Businesses/searchBusiness){target="\_self"} Using the `vatNumber`: ::: code-group ```bash [CURL] curl -X GET '{baseUrl}/v1/businesssearchs?country={country}&vatNumber={vatNumber}' \ --header 'Authorization: Bearer {accessToken}' ``` ::: Or alternatively, using the `registrationNumber`: ::: code-group ```bash [CURL] curl -X GET '{baseUrl}/v1/businesssearchs?country={country}®istrationNumber={registrationNumber}' \ --header 'Authorization: Bearer {accessToken}' ``` ::: Returns the Business Search object that contains everything *CreditSafe* knows about this business. You can cross-check these with other reliable source of information (such as [infogreffe.fr](https://www.infogreffe.fr/) or [societe.com](https://www.societe.com/)). ::: code-group ```json [JSON] { "businesssearchs": [ { "legalName": "Treehouse Company", "phone": "", "legalTvaNumber": "FR018798XXXXX", "legalRegistrationNumber": "879804805XXXXX", "status": "I", "officeType": "1", "safeNumber": "FR30XXXXXXX", "activityType": "6312Z", "externalId": "FR-X-87980480XXXXXXX", "address1": "26 Willow Road", "postcode": "75000", "city": "PARIS", "state": "ILE DE FRANCE", "country": "FR", "tradename": "Treehouse Company" } ] } ``` ::: **Information – This endpoint relies on *CreditSafe*** Despite *CreditSafe*'s best efforts, some information may be inaccurate or up to 72 hours outdated. ## Finding the legal representatives Treezor offers an endpoint to quickly identify the business legal representatives and majority shareholders (assuming they hold more than 25% worth of shares). ### Query parameters Here are the necessary parameters to pass in the queryString. | Attribute | Type | Description | |--- |--- |--- | | `country` | string | The country of registration of the legal entity. | | `vatNumber` | string | The VAT number of the legal entity. Required if the `registrationNumber` is left empty. | | `registrationNumber` | string | The registration number (e.g., SIREN) of the legal entity. Required if the `vatNumber` is left empty. | ### Request examples Endpoint: [`/v1/businessinformations`](/api-reference/api-endpoints.html#tag/Businesses/getBusinessInfo){target="\_self"} Using the `vatNumber`: ::: code-group ```bash [CURL] curl -X GET {baseUrl}/v1/businessinformations?country={country}&vatNumber={vatNumber} \ --header 'Authorization: Bearer {accessToken}' ``` ::: Or alternatively, using the `registrationNumber`: ::: code-group ```bash [CURL] curl -X GET '{baseUrl}/v1/businessinformations?country={country}®istrationNumber={registrationNumber}' \ --header 'Authorization: Bearer {accessToken}' ``` ::: Returns the Business Information object, with the `users` attribute, which contains an array of representatives. ::: code-group ```json [JSON] { "businessinformations": [ { "legalName": "Treehouse Company", "legalRegistrationNumber": "807465059XXXX", "legalRegistrationDate": "2014/10/29", "legalForm": "5710", "legalShareCapital": "", "legalSector": "", "legalAnnualTurnOver": "100-249", "legalNetIncomeRange": "0-4", "legalNumberOfEmployeeRange": "100-249", "phone": "0102030405", "email": "", "address1": "33 Rosewood Lane", "postcode": "75000", "city": "PARIS", "state": "Ile-de-France", "country": "FR", "status": "A", "tradename": "Treehouse Company", "users": [ { "firstname": "", "lastname": "", "fullnames": "M Alex Oak", "birthday": "1974-12-30T00:00:00Z", "parentType": "Managing director", "userTypeId": 2 }, { "firstname": "", "lastname": "", "fullnames": "M Chris Willow", "birthday": "1982-07-26T00:00:00Z", "parentType": "President", "userTypeId": 2 }, // More users can be returned ] } ] } ``` ::: **Information – Children relationship for legal representatives** The legal representatives and majority shareholders must be created as [Physical Users](/guide/users/physical) and [associated](/guide/users/parent-children) to the Business User. **Information – This endpoint relies on *CreditSafe*** Despite *CreditSafe*'s best efforts, some information may be inaccurate or up to 72 hours outdated. ## Sanctions and embargo Some legal entities may be obligated to complete a due diligence questionnaire regarding sanctions and embargoes. Treezor provides a series of parameters for your end users to declare this information directly through the API. The need to answer the questionnaire concerns: * Legal entities (`userType` set to `2`, `3`, or `4`) * Self-employed individuals (i.e., individuals with a `legalForm` set to `1000`) More information is available in the [KYB - Embargo survey](https://treezor.zendesk.com/hc/en-us/articles/18030546139420-KYB-Embargo-survey) article of the Support Center. ### Filling out the questionnaire To fill out the questionnaire through the API, collect the information while creating a user ([`/v1/users`](/api-reference/api-endpoints.html#tag/Users/postUsers){target="\_self"}) or requesting a user update ([`/v1/users/{userId}`](/api-reference/api-endpoints.html#tag/Users/putUser){target="\_self"}). Through the collected answers, the User must: 1. Specify for which part of the entity the user answers the questionnaire (`entitySanctionsQuestionnaire`). 2. Indicate whether they have activity outside the European Union (`activityOutsideEu`). 3. If they operate outside the EU, answer the questions regarding economics, resident countries, and involved sanctions. #### Parameters Below are the parameters available for the sanctions and embargo questionnaire. | Attribute | Type | Description | | --- | --- | --- | | `entitySanctionsQuestionnaire` | integer | Defines for which part of the entity the user answers the questionnaire (and therefore the scope to which the `activityOutsideEu` field applies): `1` – Only the legal entity`2` – The legal entity and all its subsidiaries held at 100%`3` – The legal entity and all its subsidiaries held at 50% or more`4` – The legal entity and a list of subsidiaries | | `activityOutsideEu` | integer | Whether the entity and its business units, subsidiaries, and joint ventures have a commercial activity the European Union. Can be: `0` – False`1` – True. When set to this value, the next attributes become mandatory. | | `economicSanctions` | integer | Whether the entity, its subsidiaries, entities, employees, directors, beneficial owners, or joint ventures are subject to Economic Sanctions. Can be: `0` – False`1` – True | | `residentCountriesSanctions` | integer | Whether the entity, its subsidiaries, or joint ventures, located within or operating from any countries or territories are subject to Comprehensive Sanctions. Can be: `0` – False`1` – True | | `involvedSanctions` | integer | Whether the entity, its subsidiaries, or joint ventures, are engaged in transactions, investments, business, or other dealings that directly or indirectly involve or benefit: Any countries or territories subject to Comprehensive Sanctions, or Any person or entity which is the target of any Sanctions (“Sanctioned Targets”). Can be: `0` – False`1` – True | #### Example Here is an example of a legal entity creation with the questionnaire. Endpoint: [`/v1/users`](/api-reference/api-endpoints.html#tag/Users/postUsers){target="\_self"} ::: code-group <<< @/guide/users/snippets/create\_user.bash \[CURL] ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] {22-26} { "userTypeId":2, "specifiedUSPerson":0, "email":"contact.company@example.com", "address1":"56 Bluewoods lane", "postcode":"75000", "city":"Paris", "country":"FR", "phone":"+33102030405", "legalName":"Treehouse Company", "legalRegistrationNumber":"42877171100028", "legalTvaNumber":"FR27807465059", "legalRegistrationDate":"2007-10-24", "legalShareCapital": 4236474, "legalNetIncomeRange":"50-149", "legalNumberOfEmployeeRange":"100-249", "legalSectorType":"NAF", "legalForm": "5499", "legalSector": "2051Z", "legalAnnualTurnOver": "1000-2999", "entityType": 4, "entitySanctionsQuestionnaire": 1, "activityOutsideEu": 1, "economicSanctions": 0, "residentCountriesSanctions": 0, "involvedSanctions": 0 } ``` ::: Returns a User object: ::: code-group ```json [JSON] {65-69} { "users": [ { "userId": 100138128, "userTypeId": 2, "userStatus": "VALIDATED", "userTag": "", "parentUserId": 0, "parentType": "", "controllingPersonType": 0, "employeeType": 0, "specifiedUSPerson": 0, "title": "", "firstname": "", "lastname": "", "middleNames": "", "birthday": "0000-00-00", "email": "contact.company@example.com", "address1": "56 Bluewoods lane", "address2": "", "postcode": "75000", "city": "Paris", "state": "", "country": "FR", "countryName": "France", "distributionCountry": null, "phone": "+33102030405", "mobile": "", "nationality": "", "nationalityOther": "", "placeOfBirth": "", "birthCountry": "", "occupation": "", "incomeRange": "", "legalName": "Treehouse Company", "legalNameEmbossed": "Treehouse Company", "legalRegistrationNumber": "42877171100028", "legalTvaNumber": "FR27807465XX", "legalRegistrationDate": "2007-10-24", "legalForm": "5499", "legalShareCapital": 4236474, "entityType": "4", "legalSector": "2051Z", "legalAnnualTurnOver": "1000-2999", "legalNetIncomeRange": "50-149", "legalNumberOfEmployeeRange": "100-249", "effectiveBeneficiary": 0, "kycLevel": 2, "kycReview": 0, "kycReviewComment": "", "isFreezed": 0, "isFrozen": null, "language": "", "optInMailing": null, "sepaCreditorIdentifier": "", "taxNumber": "", "taxResidence": "", "position": "", "personalAssets": "", "createdDate": "2024-02-15 09:10:05", "modifiedDate": "0000-00-00 00:00:00", "walletCount": 0, "payinCount": 0, "totalRows": "1", "activityOutsideEu": 1, "economicSanctions": 0, "residentCountriesSanctions": 0, "involvedSanctions": 0, "entitySanctionsQuestionnaire": 1, "address3": null, "timezone": null, "occupationType": "", "isOnStockExchange": 0, "secondaryAddress1": "", "secondaryAddress2": "", "secondaryAddress3": "", "secondaryPostcode": "", "secondaryCity": "", "secondaryState": "", "secondaryCountry": "", "clientId": "929252", "sanctionsQuestionnaireDate": null, "codeStatus": "110009", "informationStatus": "", "legalSectorType": "NAF", "sourceOfFunds": "", "occupationCategory": null, "personalAssetsRange": null, "monthlyIncomeRange": null } ] } ``` ::: Endpoint: [`/users`](/api-reference/pci-dss-dev.html#tag/Users/postUsers){target="\_self"} ::: code-group <<< @/guide/users/snippets/create\_user\_pci.bash \[CURL] ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] {22-26} { "userTypeId":2, "specifiedUSPerson":0, "email":"contact.company@example.com", "address1":"56 Bluewoods lane", "postcode":"75000", "city":"Paris", "country":"FR", "phone":"+33102030405", "legalName":"Treehouse Company", "legalRegistrationNumber":"42877171100028", "legalTvaNumber":"FR27807465059", "legalRegistrationDate":"2007-10-24", "legalShareCapital": 4236474, "legalNetIncomeRange":"50-149", "legalNumberOfEmployeeRange":"100-249", "legalSectorType":"NAF", "legalForm": "5499", "legalSector": "2051Z", "legalAnnualTurnOver": "1000-2999", "entityType": 4, "entitySanctionsQuestionnaire": 1, "activityOutsideEu": 1, "economicSanctions": 0, "residentCountriesSanctions": 0, "involvedSanctions": 0 } ``` ::: Returns a User object: ::: code-group ```json [JSON] {65-69} { "users": [ { "userId": 100138128, "userTypeId": 2, "userStatus": "VALIDATED", "userTag": "", "parentUserId": 0, "parentType": "", "controllingPersonType": 0, "employeeType": 0, "specifiedUSPerson": 0, "title": "", "firstname": "", "lastname": "", "middleNames": "", "birthday": "0000-00-00", "email": "contact.company@example.com", "address1": "56 Bluewoods lane", "address2": "", "postcode": "75000", "city": "Paris", "state": "", "country": "FR", "countryName": "France", "distributionCountry": null, "phone": "+33102030405", "mobile": "", "nationality": "", "nationalityOther": "", "placeOfBirth": "", "birthCountry": "", "occupation": "", "incomeRange": "", "legalName": "Treehouse Company", "legalNameEmbossed": "Treehouse Company", "legalRegistrationNumber": "42877171100028", "legalTvaNumber": "FR27807465XX", "legalRegistrationDate": "2007-10-24", "legalForm": "5499", "legalShareCapital": 4236474, "entityType": "4", "legalSector": "2051Z", "legalAnnualTurnOver": "1000-2999", "legalNetIncomeRange": "50-149", "legalNumberOfEmployeeRange": "100-249", "effectiveBeneficiary": 0, "kycLevel": 2, "kycReview": 0, "kycReviewComment": "", "isFreezed": 0, "isFrozen": null, "language": "", "optInMailing": null, "sepaCreditorIdentifier": "", "taxNumber": "", "taxResidence": "", "position": "", "personalAssets": "", "createdDate": "2024-02-15 09:10:05", "modifiedDate": "0000-00-00 00:00:00", "walletCount": 0, "payinCount": 0, "totalRows": "1", "activityOutsideEu": 1, "economicSanctions": 0, "residentCountriesSanctions": 0, "involvedSanctions": 0, "entitySanctionsQuestionnaire": 1, "address3": null, "timezone": null, "occupationType": "", "isOnStockExchange": 0, "secondaryAddress1": "", "secondaryAddress2": "", "secondaryAddress3": "", "secondaryPostcode": "", "secondaryCity": "", "secondaryState": "", "secondaryCountry": "", "clientId": "929252", "sanctionsQuestionnaireDate": null, "codeStatus": "110009", "informationStatus": "", "legalSectorType": "NAF", "sourceOfFunds": "", "occupationCategory": null, "personalAssetsRange": null, "monthlyIncomeRange": null } ] } ``` ::: Treezor also sends a [`user.create`](./events#user-create) webhook. ## Know Your Customer (KYC) The legal representatives and majority shareholders of the business must have [Physical Users](/guide/users/physical) created and [associated](/guide/users/parent-children) to the Legal Entity. The Legal Entity can then undergo [KYC review](/guide/user-verification/introduction), **this will trigger the review of all its children** (representatives and shareholders) at the same time. **Information – The mandatory requirements regarding KYC review of businesses are constantly evolving** For the most up-to-date information, we recommend that you check the documents Treezor provided you with. ### Types (`userTypeId`) Below the `userTypeId` values for legal entities. | Value | Description | | :---: | --- | | `2` | Business user | | `3` | Non-governmental organization | | `4` | Governmental organization | **Reading – Special case of charity, clubs, and syndicates** More information is available on Treezor Support Center regarding [charity, clubs, and syndicates](https://treezor.zendesk.com/hc/en-us/articles/360018874259-KYB-Associations). ### Legal Forms (`legalForm`) The `legalForm` indicates the legal category of the User. It is required for the [KYC Review](/guide/user-verification/introduction) of any user with a professional activity: * `userTypeId` of `2`, `3`, or `4` * `userTypeId` of `1` with a `legalForm` set to `1000` (self-employed physical users) You can use the [`/v1/businessinformations`](/api-reference/api-endpoints.html#tag/Businesses/getBusinessInfo){target="\_self"} request if you have any doubt regarding the `legalForm` of your User. An example is available in the [Finding the legal representatives](#finding-the-legal-representatives) section. **Reading – The list of French Legal Forms available on the Insee website** For the most up-to-date list, you can check out the [Insee website](https://www.insee.fr/fr/information/2028129). --- --- url: /guide/transfers/mandates.md description: >- Technical guide for creating and managing mandates to emit SEPA Direct Debit (SDDE). Includes required parameters, request structure, and response examples. --- # Mandates Mandates allow [Legal Entities](/guide/users/legal-entity) to initiate a transfer of funds from somebody else's account, to theirs. The transfer is made using [SEPA Direct Debit (SDDE)](direct-debit#emitted-direct-debits-sdde) and can be used to receive one-time or recurring payments. **Information – SEPA Creditor Identifier mandatory in France** In France, only companies holding a [SEPA creditor identifier (SCI)](/guide/overview/glossary#sepa-creditor-identifier-sci) are allowed to use Mandates and [SDDE](direct-debit#emitted-direct-debits-sdde). A physical person cannot be allowed to actively retrieve funds from somebody else's account. **Important – Mandates should be kept as proofs in case of litigation** As litigation rules of the SEPA Network are generally in favor of the debtor, ensure you keep Mandates to be used as proof if the need arises. ## Mandate object ::: code-group ```json [JSON] { "mandateId": 0, "title": "string", "legalInformations": "string", "uniqueMandateReference": "string", "mandateStatus": "PENDING", "userId": 0, "debtorName": "string", "debtorAddress": "string", "debtorCity": "string", "debtorZipCode": "string", "debtorCountry": "string", "debtorIban": "string", "debtorBic": "string", "sequenceType": "string", "creditorName": "string", "sepaCreditorIdentifier": "string", "creditorAddress": "string", "creditorCity": "string", "creditorZipCode": "string", "creditorCountry": "string", "signatureDate": "string", "debtorSignatureIp": "string", "signed": 0, "debtorIdentificationCode": "string", "debtorReferencePartyName": "string", "debtorReferenceIdentificationCode": "string", "creditorReferencePartyName": "string", "creditorReferenceIdentificationCode": "string", "contractIdentificationNumber": "string", "contractDescription":"string", "isPaper": true, "sddType":"core", "revocationSignatureDate": null, "createdIP": "string", "createdDate": "string", "modifiedDate": "string", "codeStatus": 0, "informationStatus": "string", "userIdUltimateCreditor": 0 } ``` ::: **API – API Reference available** For a complete list of Mandate attributes, check the [Mandates](/api-reference/api-endpoints.html#tag/Mandates){target="\_self"} section of the API Reference. ## Creation As of today, Treezor doesn't offer electronic signature services. Therefore, `isPaper` should always be `true` and you should assume the physical mandate signature. **This paper Mandate must include the UMR** (`uniqueMandateReference` attribute of the Mandate object). ### Mandatory parameters | Attribute | Type | Description | | --- | --- | --- | | `sddType` | string | Defines the type of SDD. May be:`core` – To debit individuals (physical persons).`b2b` – To debit legal entities. |  | `sequenceType` | string | Defines whether the debtor will be debited multiple times: `one-off` – For a one-time payment.`recurrent` – For recurring payments. |  | `isPaper` | boolean | Indicates whether the mandate is a paper-based document or electronically signed. **Always set to true**. |  | `userId` | integer | The unique identifier of the [end user](/guide/users/introduction) requesting the SDD. |  | `debtorName` | string | Full name of the debited end user (person or entity). Format: alphanumeric with **at least 3 alphabetic characters**. | | `debtorAddress` | string | The address of the debited end user. | | `debtorCity` | string | City in which the debited end user is domiciled. |  | `debtorZipCode` | string | Postcode of the city in which the debited end user is domiciled. |  | `debtorCountry` | string | Country in which the debited end user is domiciled. Format: ISO 3166-1 alpha-2. | | `debtorIban` | string | [IBAN](/guide/wallets/iban) of the debited end user. |  | `signatureDate` | string | Date on which the Mandate has been signed by the end user. Format: YYYY-MM-DD |  **API – API Reference available** For a complete list of Mandate attributes, check the [Mandates](/api-reference/api-endpoints.html#tag/Mandates){target="\_self"} section of the API Reference. ### Request example Endpoint: [`/v1/mandates`](/api-reference/api-endpoints.html#tag/Mandates/postMandates){target="\_self"} ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/v1/mandates' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "sddType":"core", "isPaper":true, "userId":123456, "debtorName":"Alex Oak", "debtorAddress":"99 Rosewood lane", "debtorCity":"Paris", "debtorZipCode":"75001", "debtorCountry":"FR", "debtorIban":"FR763000100794123XXXXXXXXXX", "debtorBic":"BDFXXXXXXXXX", "sequenceType":"recurrent", "signatureDate":"2020-04-01", "createdIp":"0.0.0.0" } ``` ::: Returns the Mandate object, with the corresponding `mandateId`. ::: code-group ```json [JSON] { "mandates": [ { "mandateId": 2356, "title": "M", "legalInformations": "Treezor", "uniqueMandateReference": "79069343D1A80C931FABBC5813E3DB", "mandateStatus": "PENDING", "userId": 1529390, "debtorName": "Alex Oak", "debtorAddress": "99 Rosewood lane", "debtorCity": "Paris", "debtorZipCode": "75001", "debtorCountry": "FR", "debtorIban": "FR763000100794123XXXXXXXX", "debtorBic": "BDFXXXXXX", "sequenceType": "recurrent", "creditorName": "Treezor", "sepaCreditorIdentifier": "FR90ZZZ874785", "creditorAddress": "99 Rosewood lane", "creditorCity": "Paris", "creditorZipCode": "75001", "creditorCountry": "FR", "signatureDate": "2020-04-01", "debtorSignatureIp": "", "signed": 0, "revocationSignatureDate": null, "debtorIdentificationCode": "", "debtorReferencePartyName": "", "debtorReferenceIdentificationCode": "", "creditorReferencePartyName": "", "creditorReferenceIdentificationCode": "", "contractIdentificationNumber": "", "contractDescription": "", "isPaper": true, "sddType":"core", "createdIP": "10.xx.x.37", "createdDate": null, "modifiedDate": "", "codeStatus": 220001, "informationStatus": "Mandat complété", "userIdUltimateCreditor": 0 } ] } ``` ::: Treezor assumes you had it signed by the end user as requested, so you can now initiate the corresponding [SEPA Direct Debit](./direct-debit#emitted-direct-debits-sdde) Treezor also sends a [`mandate.create`](events#mandate-create) webhook. **Note – Contact Treezor if you encounter a `22026` error** This error indicates `Unable to create the mandate. User does not have sepa creditor identifier`. Contact your *Treezor Account Manager* to set up an [SCI (SEPA Creditor Identifier)](/guide/overview/glossary#sepa-creditor-identifier-sci) for that User. ## Endpoints | Endpoint | [Scope](/guide/api-basics/authentication#available-scopes) | | --- | --- | | [`/v1/mandates`](/api-reference/api-endpoints.html#tag/Mandates/postMandates){target="\_self"}  Create a mandate | `read_write` | | [`/v1/mandates`](/api-reference/api-endpoints.html#tag/Mandates/getMandates){target="\_self"}  Search for mandates | `read_only` | | [`/v1/mandates/{mandateId}`](/api-reference/api-endpoints.html#tag/Mandates/getMandate){target="\_self"}  Retrieve a mandate | `read_only` | | [`/v1/mandates/{mandateId}`](/api-reference/api-endpoints.html#tag/Mandates/deleteMandate){target="\_self"}  Revoke a mandate | `read_write` | --- --- url: /guide/users/physical.md description: >- Technical guide for creating physical users, including anonymous and self-employed users, via the Treezor API. Includes required parameters, request structure, and response examples. --- # Physical Users A **Physical User** is a human individual, identified by a first name, last name, date of birth, address, etc. They have a `userTypeId` of `1`. ## Creation ### Parameters Below are the necessary parameters to create Physical Users. While some parameters might not be required by the API, they are necessary when it comes to the [KYC validation](/guide/user-verification/introduction) of the user. Data should be collected from the creation (or you may have to update the user information later on). | Attribute | Type | Description | |--- |--- |--- | | `userTypeId` | integer | Must be `1` for physical users. | | `specifiedUSPerson`  | integer | Indicates if the user [is a US Person](/guide/user-verification/tax-residence#the-specific-case-of-us-taxpayers). | | `email` | string | The email of the user, which must be [unique and valid](./introduction#using-unique-and-valid-email-addresses) and can't exceed 200 characters. |  | `title` (required for KYC) | string | The title of the user. Can be one of the following: `M` – Stands for mister (Mr.)`MME` – Stands for misses (Mrs.)`MLLE` – Stands for miss`MX` – Gender-neutral title | | `firstname` (required for KYC) | string | The user's first name. | | `lastname` (required for KYC) | string | The user's last name. | | `birthday` (required for KYC) | string | The user's birthdate. Format: `YYYY-MM-DD` | | `placeOfBirth` (required for KYC) | string | The user's place of birth. | | `birthCountry` (required for KYC) | string | The user's birth country (format ISO 3166-1 alpha-2) | | `nationality` (required for KYC) | string | The user's nationality (format ISO 3166-1 alpha-2) | | `mobile` | string | The user's mobile phone number, in international E.164 format. | | `address{1-3}` (required for KYC) | string | The user's postal address. The max value for each address line is 150 characters. If you're issuing cards, see the [Data Formats](/guide/api-basics/data-format#addresses) article for information on further limitations. | | `postcode` (required for KYC) | string | The user's address postcode. | | `city` (required for KYC) | string | The user's address city. | | `country` (required for KYC) | string | The user's address country (format ISO 3166-1 alpha-2) | | `phone` (required for KYC) | string | The User phone number in [international E.164 format](https://en.wikipedia.org/wiki/E.164). | | `occupationType` | string | Deprecated, use `occupationCategory` instead. | | `occupationCategory` | integer | Type of occupation of the user. Might be required for KYC, please refer to your *KYC Form*. See [occupation category](#occupation-category-occupationcategory) for the list of values. | | `incomeRange`  (required for KYC) | string | Deprecated, use `monthlyIncomeRange` instead. | | `monthlyIncomeRange` | integer | Net monthly income of the user. Might be required for KYC, please refer to your *KYC Form*. See [monthly income range](#monthly-income-range-monthlyincomerange) for the list of values.| | `personalAssets` | string | Deprecated, use `personalAssetsRange` instead. | | `personalAssetsRange` | integer | The personal assets of the user. Might be required for KYC, please refer to your *KYC Form*. See [personal assets](#personal-assets-range-personalassets) for the list of values. | | `distributionCountry` | string | The country in which the end user is using your services. This field is only required when you operate in multiple countries. See [Distribution country](/guide/users/introduction#distribution-country-distributioncountry) for more information. | #### Occupation Category (`occupationCategory`) Below is the list of values for the occupation category. | Value | Label | |:-------:|--------------------------------------------| | `1` | Pupil, student or apprentice | | `2` | Beneficiaries of unemployment assistance | | `3` | Without professional activity | | `4` | Executive and Intellectual Profession in the private sector | | `5` | Employee in the private sector | | `6` | Business owner | | `7` | Executive and Intellectual Profession in the public sector | | `8` | Employee and Officer in the public sector | | `9` | Farmer | | `10` | Self-employed | | `11` | Craftsman | | `12` | Shopkeeper and related professions | | `13` | Freelance profession | | `14` | Medical freelance professions (or medical practitioners) | | `15` | Retired | #### Personal Assets Range (`personalAssetsRange`) Below is the list of values for the personal assets range. | Value | Label | |:-------:|---------------------------------------| | `0` | None | | `1` | 0 to 15 000 Euros | | `2` | From 15 001 Euros to 50 000 Euros | | `3` | From 50 001 Euros to 150 000 Euros | | `4` | From 150 001 Euros to 350 000 Euros | | `5` | From 350 001 Euros to 750 000 Euros | | `6` | From 750 001 Euros to 1 500 000 Euros | | `7` | Greater than 1 500 000 Euros | #### Monthly Income Range (`monthlyIncomeRange`) Below is the list of values for the net monthly income range. | Value | Label | |:-------:|--------------------------------| | `1` | 0 - 999 Euros per month | | `2` | 1000 - 1800 Euros per month | | `3` | 1801 - 3500 Euros per month | | `4` | 3501 - 5000 Euros per month | | `5` | 5001 - 6500 Euros per month | | `6` | 6501 - 10000 Euros per month | | `7` | Greater than 10000 Euros per month | ### Request example Endpoint: [`/v1/users`](/api-reference/api-endpoints.html#tag/Users/postUsers){target="\_self"} ::: code-group <<< @/guide/users/snippets/create\_user.bash \[CURL] ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "userTypeId": 1, "specifiedUSPerson": 0, "firstname": "Alex", "lastname": "Oak", "birthday": "1982-05-31", "placeOfBirth": "Edgewood", "birthCountry": "FR", "nationality": "FR", "email": "alex.oak@example.com", "address1": "33 rosewood road", "postcode": "75017", "city": "Paris", "country": "FR", "phone": "+3311111111" } ``` ::: Returns a User object, with both its `kycLevel` and `kycReview` initially set to `NONE`. The user now needs to [go through the KYC validation](/guide/user-verification/introduction) process. ::: code-group ```json [JSON] {48,49} { "users": [ { "userId": 8327278, "userTypeId": 1, "userStatus": "VALIDATED", "userTag": "", "parentUserId": 0, "parentType": "", "controllingPersonType": 0, "employeeType": 0, "specifiedUSPerson": 0, "title": "", "firstname": "Alex", "lastname": "Oak", "middleNames": "", "birthday": "1982-05-31", "email": "alex.oak@example.com", "address1": "33 rosewood road", "address2": "", "postcode": "75017", "city": "Paris", "state": "", "country": "FR", "countryName": "France", "distributionCountry": null, "phone": "+3311111111", "mobile": "", "nationality": "FR", "nationalityOther": "", "placeOfBirth": "Paris", "birthCountry": "FR", "occupation": "", "incomeRange": "0-18", "legalName": "", "legalNameEmbossed": "", "legalRegistrationNumber": "", "legalTvaNumber": "", "legalRegistrationDate": "0000-00-00", "legalForm": "", "legalShareCapital": 0, "entityType": 0, "legalSector": "", "legalAnnualTurnOver": "", "legalNetIncomeRange": "", "legalNumberOfEmployeeRange": "", "effectiveBeneficiary": 0, "kycLevel": 0, "kycReview": 0, "kycReviewComment": "", "isFreezed": 0, "isFrozen": null, "language": "", "optInMailing": null, "sepaCreditorIdentifier": "", "taxNumber": "", "taxResidence": "", "position": "", "personalAssets": "", "createdDate": "2024-11-13 07:40:10", "modifiedDate": "0000-00-00 00:00:00", "walletCount": 0, "payinCount": 0, "totalRows": "1", "activityOutsideEu": 0, "economicSanctions": 0, "residentCountriesSanctions": 0, "involvedSanctions": 0, "address3": null, "timezone": null, "occupationType": "", "isOnStockExchange": 0, "secondaryAddress1": "", "secondaryAddress2": "", "secondaryAddress3": "", "secondaryPostcode": "", "secondaryCity": "", "secondaryState": "", "secondaryCountry": "", "clientId": "929252", "sanctionsQuestionnaireDate": null, "codeStatus": "110009", "informationStatus": "", "legalSectorType": "", "sourceOfFunds": "", "distributionCountry": null, "entitySanctionsQuestionnaire": 0, "occupationCategory": 5, "personalAssetsRange": 2, "monthlyIncomeRange": 2 } ] } ``` ::: Endpoint: [`/users`](/api-reference/pci-dss-dev.html#tag/Users/postUsers){target="\_self"} ::: code-group <<< @/guide/users/snippets/create\_user\_pci.bash \[CURL] ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "userTypeId": 1, "specifiedUSPerson": 0, "firstname": "Alex", "lastname": "Oak", "birthday": "1982-05-31", "placeOfBirth": "Edgewood", "birthCountry": "FR", "nationality": "FR", "email": "alex.oak@example.com", "address1": "33 rosewood road", "postcode": "75017", "city": "Paris", "country": "FR", "phone": "+3311111111" } ``` ::: Returns a User object, with both its `kycLevel` and `kycReview` initially set to `NONE`. The user now needs to [go through the KYC validation](/guide/user-verification/introduction) process. ::: code-group ```json [JSON] {48,49} { "users": [ { "userId": 8327278, "userTypeId": 1, "userStatus": "VALIDATED", "userTag": "", "parentUserId": 0, "parentType": "", "controllingPersonType": 0, "employeeType": 0, "specifiedUSPerson": 0, "title": "", "firstname": "Alex", "lastname": "Oak", "middleNames": "", "birthday": "1982-05-31", "email": "alex.oak@example.com", "address1": "33 rosewood road", "address2": "", "postcode": "75017", "city": "Paris", "state": "", "country": "FR", "countryName": "France", "distributionCountry": null, "phone": "+3311111111", "mobile": "", "nationality": "FR", "nationalityOther": "", "placeOfBirth": "Paris", "birthCountry": "FR", "occupation": "", "incomeRange": "0-18", "legalName": "", "legalNameEmbossed": "", "legalRegistrationNumber": "", "legalTvaNumber": "", "legalRegistrationDate": "0000-00-00", "legalForm": "", "legalShareCapital": 0, "entityType": 0, "legalSector": "", "legalAnnualTurnOver": "", "legalNetIncomeRange": "", "legalNumberOfEmployeeRange": "", "effectiveBeneficiary": 0, "kycLevel": 0, "kycReview": 0, "kycReviewComment": "", "isFreezed": 0, "isFrozen": null, "language": "", "optInMailing": null, "sepaCreditorIdentifier": "", "taxNumber": "", "taxResidence": "", "position": "", "personalAssets": "", "createdDate": "2024-11-13 07:40:10", "modifiedDate": "0000-00-00 00:00:00", "walletCount": 0, "payinCount": 0, "totalRows": "1", "activityOutsideEu": 0, "economicSanctions": 0, "residentCountriesSanctions": 0, "involvedSanctions": 0, "address3": null, "timezone": null, "occupationType": "", "isOnStockExchange": 0, "secondaryAddress1": "", "secondaryAddress2": "", "secondaryAddress3": "", "secondaryPostcode": "", "secondaryCity": "", "secondaryState": "", "secondaryCountry": "", "clientId": "929252", "sanctionsQuestionnaireDate": null, "codeStatus": "110009", "informationStatus": "", "legalSectorType": "", "sourceOfFunds": "", "distributionCountry": null, "entitySanctionsQuestionnaire": 0, "occupationCategory": 5, "personalAssetsRange": 2, "monthlyIncomeRange": 2 } ] } ``` ::: Treezor also sends a [`user.create`](./events#user-create) webhook. ## Anonymous Users An Anonymous User is a user only represented by its unique email address. No other declarative data is required, nor is the [mandatory KYC validation](/guide/user-verification/introduction). This specific user is intended for limited use cases such as: * **Gift cards** which are not associated to a specific user. * **Bulk card creation**, where the anonymous user is used as a placeholder until the card can be assigned to its owner. **Information – Anonymous users have limited usage (not KYC-validated)** * [Payment, withdrawal](/guide/cards/restrictions-limits#payment-withdrawal-limits), and [transfer](/guide/transfers/introduction) limits are highly restricted. * The transaction can be refused if an address verification (AVS) occurs. * [3DS verifications](/guide/cards/creation#enrolling-a-card-for-3d-secure) are rejected as no secondary means of validation are available. ### Parameters | Attribute | Type | Description | |--- |--- |--- | | `userTypeId` | integer | Must be `1` for physical users. | | `specifiedUSPerson`  | integer | Indicates if the user [is a US Person](/guide/user-verification/tax-residence#the-specific-case-of-us-taxpayers). | | `email` | string | The email of the anonymous user, which must be [unique and valid](./introduction#using-unique-and-valid-email-addresses) and can't exceed 200 characters. |  **Tip – User address must be unique even for bulk card creation** When generating a batch of [Cards](/guide/cards/introduction) in advance and associating them to Anonymous Users, your can generate random and fictitious email addresses ### Request example Endpoint: [`/v1/users`](/api-reference/api-endpoints.html#tag/Users/postUsers){target="\_self"} ::: code-group <<< @/guide/users/snippets/create\_user.bash \[CURL] ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "userTypeId": 1, "specifiedUSPerson": 0, "email": "anonymous@example.com" } ``` ::: Returns a User object if successful: ::: code-group ```json [JSON] { "users": [ { "userId": "", "userTypeId": 1, "userStatus": "", "specifiedUSPerson": 0, "email": "anonymous@example.com", // [...] some attributes are hidden } ] } ``` ::: Endpoint: [`/users`](/api-reference/pci-dss-dev.html#tag/Users/postUsers){target="\_self"} ::: code-group <<< @/guide/users/snippets/create\_user\_pci.bash \[CURL] ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "userTypeId": 1, "specifiedUSPerson": 0, "email": "anonymous@example.com" } ``` ::: Returns a User object if successful: ::: code-group ```json [JSON] { "users": [ { "userId": "", "userTypeId": 1, "userStatus": "", "specifiedUSPerson": 0, "email": "anonymous@example.com", // [...] some attributes are hidden } ] } ``` ::: Treezor also sends a [`user.create`](./events#user-create) webhook. ## Self-employed Users Self-employed individuals are a specific case since they work for their own account. That makes them physical users (`userTypeId=1`) with many attributes of a legal entity. Therefore: * The attributes required for [`/v1/users/{userId}/Kycreview`](/api-reference/api-endpoints.html#tag/User%20KYC%20Review/putKycreview){target="\_self"} cumulates the ones for the [creation of a physical user](#parameters) and [legal entities](/guide/users/legal-entity#parameters). * Declarative data to submit is specific, you must refer to the KYC Form provided by Treezor. Here are a few specificities regarding data to provide. | Attribute | Type | Description | |--- |--- |--- | | `userTypeId` | integer | Must be `1` for self-employed users. | | `email` | string | The email of the user, which must be valid and can't exceed 200 characters. |  | `specifiedUSPerson`  | integer | Indicates if the user [is a US Person](/guide/user-verification/tax-residence#the-specific-case-of-us-taxpayers). | | `legalForm` | integer | **Must be `1000`** for self-employed users. | | `address{1-3}` (required for KYC) | string | The user's **professional postal address**. See the [Data Formats](/guide/api-basics/data-format#addresses) article for information on limitations. | | `secondaryAddress{1-3}` (required for KYC) | string | The user's **personal postal address**. See the [Data Formats](/guide/api-basics/data-format#addresses) article for information on limitations. | In addition, a self-employed user must answer the [Sanctions & Embargo questionnaire](/guide/users/legal-entity#sanctions-and-embargo) and provide their [Tax residence](/guide/user-verification/tax-residence). ## Shareholders and Legal representatives Among the Physical Users that can be created in Treezor, there is the case of the Shareholders and the Legal Representatives of a company. These specific physical users, identified with the `parentType` attribute: * Are attached to the [Legal entity](/guide/users/legal-entity) (the company) with a [parent-children relation](/guide/users/parent-children). * May require more documents and declarative data to be verified. --- --- url: /guide/transfers/scheduled-payments.md description: >- Technical guide for creating and managing Scheduled Payments (one-time or recurring) for SEPA Credit Transfers and Wallet-to-Wallet Transfers. Includes required parameters, request structure, and response examples. --- # Scheduled Payments Scheduled Payment orders allow you to plan a payment execution in the future, whether it is a unique operation or recurring ones. Scheduled Payments can be used for both [Payouts (SCTE)](/guide/transfers/credit-transfer#emitted-credit-transfers-scte) and [Wallet-to-Wallet Transfers](/guide/transfers/wallet-to-wallet#wallet-to-wallet-transfers). The steps are as follows: 1. You create a Scheduled Payment order with the desired settings (type, dates, etc.) 2. The resulting Transfer(s) or Payout(s) occur at the scheduled date(s). An error in the execution of the payment cancels the occurrence and adds it to the `failedPayment` attribute of the [Scheduled Payment](#scheduled-payment-object) object. In such cases, the end user must complete the payment manually. **Information – Scheduled Payment is a Beta feature** Please contact your *Treezor Account Manager* if you're interested in this feature. ## Attributes Find below the list of attributes for the Scheduled Payment object. | Attribute | Type | Description | | --- | --- | --- | | `id` | string | The unique identifier of the Scheduled Payment (UUIDv4). | | `status` | string | The status of the Scheduled Payment, which is either `VALIDATED` or `CANCELED`. | | `scheduledPaymentName` | string | The label describing the goal of the Scheduled Payment. | | `walletId` | integer | The unique identifier of the Wallet to debit. | | `beneficiaryType` | string | The type of beneficiary for the operation, which can be: `payout` – The Scheduled Payment targets an external account.`walletTransfer` – The Scheduled Payment targets another Wallet in your Treezor environment. | | `beneficiary` | integer | The unique identifier of the beneficiary of the Scheduled Payment, which can be either `beneficiaryId` for Payouts or `beneficiaryWalletId` for Wallet-to-Wallet transfers. | | `amount` | number | The amount of the Scheduled Payment. | | `type` | string | The type of Scheduled Payment, which can be: `oneshot` – The payment will occur only once.`periodic` – The payment will occur periodically over a defined time frame. | | `execAt` | string | The date on which the a `oneshot` Scheduled Payment is to be executed. This date must be set at least one day in the future. Format: `YYYY-MM-DD`. | | `startAt` | string | The date from which a `periodic` Scheduled Payment execution starts. This date must be set at least one day in the future. Format: `YYYY-MM-DD`. | | `endAt` | string | The date on which a `periodic` Scheduled Payment ends. This date must be set after the `startAt` date. Format: `YYYY-MM-DD`. | | `creationDate` | string | The date and time at which the Scheduled Payment was created. | | `period` | string | The frequency at which a `periodic` Scheduled Payment is to occur. Can be: `weekly`, `monthly`, `quarterly`, `bi-annual`, or `annual`. | | `beneficiaryLabel` | string | The label that will be displayed for the Scheduled Payments, regardless of the type. Max. 140 characters. | | `currency` | string | The currency of the Scheduled Payments. Can only be `EUR`. | | `userId` | integer | The unique identifier of the User owning the Wallet to debit. | | `amr` | array | The type of SCA for per-operation SCA (e.g., `CLOUD_PIN`, `HYBRID_PIN`, `DEVICE_BIOMETRIC`). | | `failedPayment` | object  | Additional information in case of a failed payment (date, error code and error message). | | `endToEndId` | string | The end-to-end identifier, for Payouts only. Max. 24 characters. Allowed characters: alphanumeric and `/` `-` `?` `:` `(` `)` `.` `,` `+` ` `  (space). Mustn't start nor end with `/`, and mustn't contain `//`. | ### Scheduled Payment object ::: code-group ```json [JSON] { "id":"string", "status":"string", "scheduledPaymentName":"string", "walletId":integer, "beneficiaryType":"string", "beneficiary":integer, "amount":number, "type":"string", "execAt":"string", "startAt":"string", "endAt":"string", "creationDate":"string", "period":"string", "beneficiaryLabel":"string", "currency":"string", "userId":integer, "amr":["string"], "failedPayment":[ { "date": "string", "errorCode": "string", "errorMessage": "string" } ], "endToEndId":"string" } ``` ::: ## Creating a Scheduled Payment order The required parameters to create a Scheduled Payment order vary depending on the type: * [One-time payment](#schedule-a-one-time-payment) * [Periodic payment](#schedule-a-periodic-payment) ### Schedule a one-time payment | Attribute | Type | Description | | --- | --- | --- | | `scheduledPaymentName` | string | The label describing the goal of the Scheduled Payment. | | `walletId` | integer | The unique identifier of the Wallet to debit. | | `beneficiaryType` | string | The type of beneficiary for the operation, which can be: `payout` – The Scheduled Payment targets an external account.`walletTransfer` – The Scheduled Payment targets another Wallet in your Treezor environment. | | `beneficiary` | integer | The unique identifier of the beneficiary of the Scheduled Payment, which can be either `beneficiaryId` for Payouts or `beneficiaryWalletId` for Wallet-to-Wallet transfers. | | `amount` | number | The amount of the Scheduled Payment. | | `type` | string | The type of Scheduled Payment, which can be: `oneshot` – The payment will occur only once.`periodic` – The payment will occur periodically over a defined time frame. | | `execAt` | string | The date on which the `oneshot` Scheduled Payment is to be executed. This date must be set at least one day in the future. Format: YYYY-MM-DD. | | `beneficiaryLabel` | string | The label that will be displayed for the Scheduled Payments, regardless of the type. Max. 140 characters. | | `currency` | string | The currency of the Scheduled Payments. Can only be `EUR`. | | `endToEndId` | string | The end-to-end identifier, for Payouts only. Max. 24 characters. | You can use the following request to create your scheduled payment order. ::: code-group <<< @/guide/transfers/snippets/create\_scheduled\_payment.bash \[CURL] ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "scheduledPaymentName":"gas", "walletId":2695112, "beneficiaryType":"payout", "beneficiary":434403, "amount":10, "type":"oneshot", "execAt":"2024-02-27", "beneficiaryLabel":"one-time payment", "currency":"EUR", "userId":100165322, "endToEndId":"GwZzGqwc" } ``` ::: Returns the Scheduled Payment object: ::: code-group ```json [JSON] { "id":"6492e280-16be-4c15-81c3-13d4c82d111x", "status":"VALIDATED", "scheduledPaymentName":"gas", "walletId":2695112, "beneficiaryType":"payout", "beneficiary":434403, "amount":10, "type":"oneshot", "execAt":"2024-02-27", "startAt":null, "endAt":null, "creationDate":"2024-02-26T01:50:08+00:00", "period":null, "beneficiaryLabel":"one-time payment", "currency":"EUR", "userId":100165322, "amr":[ ], "failedPayment":[ ], "endToEndId":"GwZzGqwc" } ``` ::: ### Schedule a periodic payment | Attribute | Type | Description | | --- | --- | --- | | `scheduledPaymentName` | string | The label describing the goal of the Scheduled Payment. | | `walletId` | integer | The unique identifier of the Wallet to debit. | | `beneficiaryType` | string | The type of beneficiary for the operation, which can be: `payout` – The Scheduled Payment targets an external account.`walletTransfer` – The Scheduled Payment targets another Wallet in your Treezor environment. | | `beneficiary` | integer | The unique identifier of the beneficiary of the Scheduled Payment, which can be either `beneficiaryId` for Payouts or `beneficiaryWalletId` for Wallet-to-Wallet transfers. | | `amount` | number | The amount of the Scheduled Payment. | | `type` | string | The type of Scheduled Payment, which can be: `oneshot` – The payment will occur only once.`periodic` – The payment will occur periodically over a defined time frame. | | `startAt` | string | The date from which a `periodic` Scheduled Payment execution starts. This date must be set at least one day in the future. Format: YYYY-MM-DD. | | `endAt` | string | The date on which a `periodic` Scheduled Payment ends. This date must be set after the `startAt` date. Format: YYYY-MM-DD. | | `period` | string | The frequency at which a `periodic` Scheduled Payment is to occur. Can be: `weekly`, `monthly`, `quarterly`, `bi-annual`, or `annual`. | | `beneficiaryLabel` | string | The label that will be displayed for the Scheduled Payments, regardless of the type. Max. 140 characters. | | `currency` | string | The currency of the Scheduled Payments. Can only be `EUR`. | | `endToEndId` | string | The end-to-end identifier, for Payouts only. Max. 24 characters. | You can use the following request to create your scheduled payment order. ::: code-group <<< @/guide/transfers/snippets/create\_scheduled\_payment.bash \[CURL] ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "scheduledPaymentName": "gas", "walletId":2695112, "beneficiaryType":"payout", "beneficiary":434403, "amount":10, "type":"periodic", "startAt":"2024-02-27", "endAt":"2024-12-31", "period":"weekly", "beneficiaryLabel":"subscription", "currency":"EUR", "endToEndId":"GwZzGqwc" } ``` ::: Returns the Scheduled Payment object: ::: code-group ```json [JSON] { "id":"6492e280-16be-4c15-81c3-13d4c82d111x", "status":"VALIDATED", "scheduledPaymentName":"gas", "walletId":2695112, "beneficiaryType":"payout", "beneficiary":434403, "amount":10, "type":"periodic", "execAt":null, "startAt":"2024-02-27", "endAt":"2024-12-31", "creationDate":"2024-02-26T01:50:08+00:00", "period":"weekly", "beneficiaryLabel":"subscription", "currency":"EUR", "userId":100165322, "amr":[ ], "failedPayment":[ ], "endToEndId":"GwZzGqwc" } ``` ::: ## Retrieving the executed payments To see all the operations linked to a given Scheduled Payment order, you can use the following request (which supports [cursor-based pagination](/guide/api-basics/pagination#cursor-based-pagination)). ::: code-group ```bash [CURL] curl -X GET '{baseUrl}/core-connect/scheduledPayment/{scheduledPaymentId}/payments' \ --header 'Authorization: Bearer {accessToken}' ``` ::: Returns an array of payment objects, along with a cursor if some payments have already been made against the order. ::: code-group ```json [JSON] { "cursor": { "current": "string", "next": "string", "prev": "string" }, "payments": [ { "date": "2024-02-27 08:15:51", "amount": "10.00", "currency": "EUR", "label": "school fees", "status": "PENDING", "paymentId": "184427", "errorCode": "", "errorMessage": "", "endToEndId": "yqCqGiMU-2024-02-27" } ] } ``` ::: If no payment have been made against the Scheduled Payment order, an HTTP 204 is returned with an empty list. ## Cancelling a Scheduled Payment You may want to cancel a Scheduled Payment order, especially in the case of recurring payments with no end dates. You can use the following request: ::: code-group ```bash [CURL] curl -X DELETE '{baseUrl}/core-connect/scheduledPayment/{scheduledPaymentId}' \ --header 'Authorization: Bearer {accessToken}' ``` ::: Returns the corresponding Scheduled Payment object with a `status` set to `CANCELED`. ::: code-group ```json [JSON] {3} { "id":"6492e280-16be-4c15-81c3-13d4c82d111x", "status":"CANCELED", "scheduledPaymentName":"gas", "walletId":2695112, "beneficiaryType":"payout", "beneficiary":434403, "amount":10, "type":"oneshot", "execAt":"2024-02-27", "startAt":null, "endAt":null, "creationDate":"2024-02-26T01:50:08+00:00", "period":null, "beneficiaryLabel":"one-time payment", "currency":"EUR", "userId":100165322, "amr":[ ], "failedPayment":[ ], "endToEndId":"GwZzGqwc" } ``` ::: ## Endpoints | Endpoint | [Scope](/guide/api-basics/authentication#available-scopes) | | --- | --- | | [`/core-connect/scheduledPayment`](/api-reference/api-endpoints.html#tag/Scheduled%20Payments/postScheduledPayment){target="\_self"} Create a Scheduled Payment | `read_write` | | [`/core-connect/scheduledPayment`](/api-reference/api-endpoints.html#tag/Scheduled%20Payments/getScheduledPayment){target="\_self"} Retrieve Scheduled Payments based on the `userId` and/or `walletId` | `read_only` | | [`/core-connect/scheduledPayment/{scheduledPaymentId}`](/api-reference/api-endpoints.html#tag/Scheduled%20Payments/deleteScheduledPayment){target="\_self"} Cancel a Scheduled Payment order | `read_write` | | [`/core-connect/scheduledPayment/{scheduledPaymentId}/payments`](/api-reference/api-endpoints.html#tag/Scheduled%20Payments/getScheduledPaymentOperations){target="\_self"} Retrieve the list of executed payments for a given Scheduled Payment order | `read_write` | --- --- url: /guide/user-verification/tax-residence.md description: >- Technical guide for creating and managing user Tax Residence via the Treezor API. Includes required parameters, request structure, and response examples. --- # Tax residence ## Introduction All users (both physical users and legal entities) going through the KYC verification process must declare at least one country of tax residency. This is an obligation enforced by the [CRS](/guide/overview/glossary#common-reporting-standard-crs) and [FATCA](/guide/overview/glossary#foreign-account-tax-compliance-act-fatca). **Tip – Not requested for Legal representatives** The legal representative of a legal entity isn’t required to declare a tax residency. When declaring the tax residence, besides the country, you can also provide: * The Tax Identification Number (TIN) of the user (optional except for [US taxpayers](#the-specific-case-of-us-taxpayers) and users whose `distributionCountry` is `IT`). * The waiver exempting Treezor from liability in case of a missing TIN. ### The specific case of US taxpayers Every US taxpayer must declare the United States as a tax residence along with the Tax Identification Number (TIN). This applies to all users as soon as one of the following elements value is `US`: * **Nationality** – Corresponds to the `nationality` or the `nationalityOther` field for the physical users * **Birth country** – Corresponds to the `birthCountry` field for physical users * **Address** – Corresponds to the `country` or `secondaryCountry` field for both physical users and legal entities In addition, when at least one of these values is `US`, the user `specificiedUSPerson` attribute must be set to `1`. ::: details Is considered a US citizen or resident… A physical user is presumed to be a citizen of the United States: * From the moment they have an American passport or * If they are born on the territory of the United States, even when such a place of birth appears on a passport of another country, or the person also holds another nationality or has their residence in another country. A physical user is a resident of the United States if: * They are holding a green card for permanent residence in the United States. * They are residing permanently in the United States or have spent a sufficient period of time in the United States over the last three years. ::: ## Creation ### Parameters | Parameters | Type | Description | |--- |--- |--- | | `userId` | integer | The unique identifier of the user whose tax residence country is to be declared. | | `country` | string | The country code for the [country](/guide/api-basics/data-format#countries) of tax residence. Must be `US` if the corresponding user `specificiedUSPerson` attribute is set to `1`. | | `taxPayerId` | string | The Tax Identification Number (TIN) or Tax Code, which is optional except for [US taxpayers](#the-specific-case-of-us-taxpayers) and users whose `distributionCountry` is `IT`. | | `liabilityWaiver` | boolean | The waiver exempting Treezor from liability in case of a missing TIN. Must be set to `true` if the `taxPayerId` field is null or empty. | **API – API Reference available** For a complete list of Tax Residence attributes, check the [Tax Residences](/api-reference/api-endpoints.html#tag/User%20Tax%20Residences){target="\_self"} section of the API Reference. ### Request Endpoint: [`/v1/taxResidences`](/api-reference/api-endpoints.html#tag/User%20Tax%20Residences/postTaxresidence){target="\_self"} ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/v1/taxResidences' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "userId":100642533, "country":"FR", "taxPayerId":"12345", "liabilityWaiver":false } ``` ::: Returns the Tax Residence object: ::: code-group ```json [JSON] { "taxResidences": [ { "id": 199519, "userId": 100642533, "country": "FR", "taxPayerId": "12345", "liabilityWaiver": false, "createdDate": "2024-07-22 10:38:37", "lastUpdate": "", "deletedDate": "", "isDeleted": false } ] } ``` ::: ## Retrieval You may use the dedicated endpoints to search for tax residences. Here is an example with the [`/v1/taxResidences`](/api-reference/api-endpoints.html#tag/User%20Tax%20Residences/getTaxresidences){target="\_self"} request and the `userId` query parameter to filter the search for a specific user. ::: code-group ```bash [CURL] curl -X GET '{baseUrl}/v1/taxResidences?userId=100642533' \ --header 'Authorization: Bearer {accessToken}' ``` ::: Returns the list of tax residences filtered for the selected user. ::: code-group ```json [JSON] { "taxResidences": [ { "id": 199519, "userId": 100642533, "country": "FR", "taxPayerId": "12345", "liabilityWaiver": false, "createdDate": "2024-07-22 10:38:37", "lastUpdate": "", "deletedDate": "", "isDeleted": false } ], "meta": { "maxPerPage": 10, "pageNumber": 1, "totalPages": 1, "totalResults": 1 } } ``` ::: ## Tax Residence object ::: code-group ```json [JSON] { "id": 0, "userId": 0, "country": "string", "taxPayerId": "string", "liabilityWaiver": true, "createdDate": "string", "lastUpdate": "string", "deletedDate": "string", "isDeleted": false } ``` ::: **API – API Reference available** For a complete list of Tax Residence attributes, check the [Tax Residences](/api-reference/api-endpoints.html#tag/User%20Tax%20Residences){target="\_self"} section of the API Reference. ## Endpoints | Endpoint |[Scope](/guide/api-basics/authentication#available-scopes) | | --- | --- | | [`/v1/taxResidences`](/api-reference/api-endpoints.html#tag/User%20Tax%20Residences/postTaxresidence){target="\_self"} Create a Tax Residence | `read_write` | | [`/v1/taxResidences`](/api-reference/api-endpoints.html#tag/User%20Tax%20Residences/getTaxresidences){target="\_self"} Search for Tax Residences | `read_only` | | [`/v1/taxResidences/{taxResidenceId}`](/api-reference/api-endpoints.html#tag/User%20Tax%20Residences/getTaxresidence){target="\_self"} Retrieve a Tax Residence based on its `id` | `read_only` | | [`/v1/taxResidences/{taxResidenceId}`](/api-reference/api-endpoints.html#tag/User%Tax%20Residences/putTaxresidence){target="\_self"} Update a Tax Residence | `read_write` | | [`/v1/taxResidences/{taxResidenceId}`](/api-reference/api-endpoints.html#tag/User%Tax%20Residences/deleteTaxresidence){target="\_self"} Delete a Tax Residence | `read_write` | --- --- url: /guide/transfers/wallet-to-wallet.md description: >- Technical guide for making peer-to-peer fund movements between Treezor Wallets from the same environment. Includes required parameters, request structure, and response examples. --- # Wallet-to-Wallet Transfers You can transfer funds from Wallet to Wallet, without using the [SEPA network](/guide/overview/glossary#sepa-single-euro-payments-aera), offering much quicker transfers. Transfers are instantaneous, are available 24/7 and can be scheduled (see [Scheduled Payments](/guide/transfers/scheduled-payments)). They send [`transfer.create`](/guide/transfers/events#transfer-create) webhooks and are mapped to `Transfers` objects. **Prerequisites – Funds can be transferred if:** * Both [Wallets](/guide/wallets/introduction) are active and belong to your Treezor environment * Both Wallets have the same [BIC](/guide/overview/glossary#bank-identifier-code-bic) (not compatible with [Local IBAN](/guide/wallets/iban)) * The [Authorized Balance](/guide/overview/glossary#balance) of the debited Wallet is sufficient * The amount is within the sender's [KYC](/guide/user-verification/introduction) limits and greater or equal to €0,05 ## Creation **Information – [SCA](/guide/strong-customer-authentication/introduction) depends on the Wallet owner (`beneficiaryWalletId`)** * **Per session** – The credited Wallet belongs to the user initiating the transfer. * **Per operation** – The credited Wallet doesn't belong to the user initiating the transfer. ### Parameters | Attribute | Type | Description | |--- | --- | --- | | `walletId` | integer | The unique identifier of the Wallet to be debited. | | `beneficiaryWalletId`  | integer | The unique identifier of the Wallet to be credited. | | `amount` | number | The amount of the Transfer. | | `currency` | string | The currency of the Transfer. Both Wallets must have the same currency. As of today, can only be `EUR`. | | `transferTypeId` | integer | The type of Transfer, which can be: `1` (**default**) – Wallet-to-Wallet Transfer `3` – Client fees, which allows you to debit fees from end users wallets `4` – Credit note, which allows you handle reimbursement of charges | | `transferTag` | string | Custom attribute to use as you see fit. Learn more in the [Object tags](/guide/api-basics/objects-tags#objects-tags) article. | | `label` | string | Custom data. | **Best practice – Make good use of the `transferTypeId` parameter** Using the `transferTypeId=3` when billing your customers for your services is strongly recommended. Improper use of `transferTypeId` prevents you from displaying fees on [Account Statements](/guide/wallets/account-documents). **API – API Reference available** For a complete list of Transfer attributes, check the [Transfers](/api-reference/api-endpoints.html#tag/Transfers){target="\_self"} section of the API Reference. ### Request example Endpoint: [`/v1/transfer`](/api-reference/api-endpoints.html#tag/Transfers/postTransfers){target="\_self"} ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/v1/transfers' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is a `{payload}` example: ::: code-group ```json [JSON] { "walletId":{integer}, "beneficiaryWalletId":{integer}, "transferTypeId":1, "amount":{amount}, "currency":"EUR" } ``` ::: Returns the Transfer object if successful: ::: code-group ```json [JSON] { "transfers": [ { "transferId": 4269222, "transferStatus": "VALIDATED", "transferTag": "", "walletId": 1927699, "walletTypeId": 9, "beneficiaryWalletId": 2301937, "beneficiaryWalletTypeId": 9, "walletEventName": "Account A", "walletAlias": "account-63346a643a7fa", "beneficiaryWalletEventName": "Main account", "beneficiaryWalletAlias": "main-account-64ad18c128f29", "amount": "101.25", "currency": "EUR", "label": "", "transferTypeId": 1, "createdDate": "2024-02-07 14:17:51", "modifiedDate": "2024-02-07 14:17:51", "totalRows": null, "foreignId": null, "partnerFee": null, "codeStatus": "150005", "informationStatus": null, "metadata": null } ] } ``` ::: Treezor also sends a [`transfer.create`](/guide/transfers/events#transfer-create) webhooks. **Note – Treezor sends 1 webhook per transfer-related event** Treezor **doesn't** send a webhook per Wallet (e.g., one for the debited Wallet and another for the credited Wallet). Only one [`transfer.create`](/guide/transfers/events#transfer-create) and [`transfer.update`](/guide/transfers/events#transfer-update) webhook is sent per transfer-related event. ## Endpoints | Endpoint |[Scope](/guide/api-basics/authentication#available-scopes) | | --- | --- | | [`/v1/transfers`](/api-reference/api-endpoints.html#tag/Transfers/getTransfers){target="\_self"} Search Transfers | `read_only` | | [`/v1/transfer`](/api-reference/api-endpoints.html#tag/Transfers/postTransfers){target="\_self"} Create a Transfers | `read_write` | | [`/v1/transfers/{transferId}`](/api-reference/api-endpoints.html#tag/Transfers/getTransfer){target="\_self"} Retrieve a Transfer using its `id` | `read_only` | | [`/v1/transfers/{transferId}`](/api-reference/api-endpoints.html#tag/Transfers/deleteTransfer){target="\_self"} Delete a Transfer using its `id`| `read_write` | --- --- url: /guide/wallets/creation.md description: >- Technical guide for creating payment accounts and electronic money wallets via the Treezor API. Includes required parameters, request structure, and response examples. --- # Creation Find in this article examples on how to create different types of wallets. Some wallets might require you contact Treezor to create them. Regardless the type of Wallet created, the [`wallet.create`](/guide/wallets/events#wallet-create) webhook is sent upon creation. **Prerequisites – Ensure the User is fit to have a Wallet** Users must have a `VALIDATED` status, and Legal Entities must have a legal representative declared in order to own a Wallet. ## Payment Account Wallet The Payment Account Wallet has a `walletTypeId` of **`10`**. This type of wallet requires [KYC validation](/guide/user-verification/introduction) of the associated [User](/guide/users/introduction), and can only be created if the Wallet owner has a `VALIDATED` status. ### Mandatory parameters Below are the necessary parameters to create a Payment Account Wallet. | Attribute | Type | Description | |--- |--- |--- | | `tariffId` | integer | The fees applied to the Wallet, as defined by your contract with Treezor. Usually required, but may have a default value set by Treezor. | | `walletTypeId` | integer | `10` for [Payment Account Wallet](introduction#payment-account-wallet-type-10). | | `userId` | integer | The unique identifier of the User who owns the Wallet. |  | `currency` | string | The currency of the Wallet. Can only be `EUR`. |  | `eventName` | string | The name of the Wallet. | | `bic` | string | The country in which the wallet is domiciled. The BIC is required depending on your configuration; see [Local IBAN](/guide/wallets/iban#local-iban) | **API – API Reference available** For a complete list of Wallet attributes, check the [Wallets](/api-reference/api-endpoints.html#tag/Wallets){target="\_self"} section of the API Reference. ### Request Endpoint: [`/v1/wallets`](/api-reference/api-endpoints.html#tag/Wallets/postWallets){target="\_self"} ::: code-group <<< @/guide/wallets/snippets/create\_wallet.bash \[CURL] ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "walletTypeId":10, "tariffId":{tariffId}, "userId":123456, "currency":"EUR", "eventName":"My Payment Account Wallet" } ``` ::: Returns a Wallet object, with its `id`. An IBAN (`iban`) and BIC (`bic`) are also automatically assigned and populated. You may [create Virtual IBANs](iban) in a second step. ::: code-group ```json [JSON] { "wallets": [ { "walletId": 2605378, "walletTypeId": 10, "walletStatus": "VALIDATED", "codeStatus": 120005, "informationStatus": "", "walletTag": "", "userId": 100078924, "userLastname": "Alex", "userFirstname": "Oak", "jointUserId": 0, "tariffId": 396, "eventName": "Event_test", "eventAlias": "event-test-65aa83976d9df", "eventDate": "2024-01-26", "eventMessage": "", "eventPayinStartDate": "2024-01-19", "eventPayinEndDate": "0000-00-00", "contractSigned": 0, "bic": "TRZOFR21XXX", // BIC automatically assigned to the Wallet "iban": "FR761679800001000012345678", // IBAN automatically assigned to the Wallet "urlImage": "", "currency": "EUR", "createdDate": "2024-01-19 15:13:43", "modifiedDate": "0000-00-00 00:00:00", "payinCount": 0, "payoutCount": 0, "transferCount": 0, "solde": 0, "authorizedBalance": 0, "totalRows": 1, "country": "FR" } ] } ``` ::: Treezor also sends the [`wallet.create`](/guide/wallets/events#wallet-create) webhook. ## Electronic Money Wallet The Electronic Money Wallet has a `walletTypeId` of **`9`**. While this type of wallet doens't need KYC validation of the associated User, they can only be created if they have a `VALIDATED` status. ### Mandatory parameters Below are the necessary parameters to create an Electronic Money Wallet. | Attribute | Type | Description | |--- |--- |--- | | `tariffId` | integer | The fees applied to the Wallet, as defined by your contract with Treezor. Usually required, but may have a default value set by Treezor. | | `walletTypeId` | integer | `9` for [Electronic Money Wallet](introduction#electronic-money-wallet-type-9). | | `userId` | integer | The unique identifier of the User who owns the Wallet. |  | `currency` | string | Currency of the Wallet. Can only be `EUR`. |  | `eventName` | string | The Name of the Wallet. | | `bic` | string | The country in which the wallet is domiciled. The BIC is required depending on your configuration; see [Local IBAN](/guide/wallets/iban#local-iban) | **API – API Reference available** For a complete list of Wallet attributes, check the [Wallets](/api-reference/api-endpoints.html#tag/Wallets){target="\_self"} section of the API Reference. ### Request Endpoint: [`/v1/wallets`](/api-reference/api-endpoints.html#tag/Wallets/postWallets){target="\_self"} ::: code-group <<< @/guide/wallets/snippets/create\_wallet.bash \[CURL] ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "walletTypeId":9, "tariffId":{tariffId}, "userId":123456, "currency":"EUR", "eventName":"My Electronic Money Wallet" } ``` ::: Returns a Wallet object with its `id`. An IBAN (`iban`) and BIC (`bic`) are also automatically assigned and populated. You may [create Virtual IBANs](iban) in a second step. ::: code-group ```json [JSON] { "wallets": [ { "walletId": 2605123, "walletTypeId": 0, "walletStatus": "VALIDATED", "codeStatus": 120005, "informationStatus": "", "walletTag": "", "userId": 100078924, "userLastname": "Alex", "userFirstname": "Oak", "jointUserId": 0, "tariffId": 396, "eventName": "Event_test", "eventAlias": "event-test-65aa83976d9df", "eventDate": "2024-01-26", "eventMessage": "", "eventPayinStartDate": "2024-01-19", "eventPayinEndDate": "0000-00-00", "contractSigned": 0, "bic": "TRZOFR21XXX", // BIC automatically assigned to the Wallet "iban": "FR761679800001000012345678", // IBAN automatically assigned to the Wallet "urlImage": "", "currency": "EUR", "createdDate": "2024-01-19 15:13:43", "modifiedDate": "0000-00-00 00:00:00", "payinCount": 0, "payoutCount": 0, "transferCount": 0, "solde": 0, "authorizedBalance": 0, "totalRows": 1, "country": "FR" } ] } ``` ::: Treezor also sends the [`wallet.create`](/guide/wallets/events#wallet-create) webhook. --- --- url: /use-cases/prerequisites/create-your-company-nc.md description: >- Create and verify your company as a legal entity using the Treezor Dashboard application. This implementation guide takes you through the steps without need of any technical knowledge. --- # Create and verify your company (no-code) The no-code guide will take you through the following steps to successfully create and verify your company: 1. [Get to know your Dashboard](#get-to-know-your-dashboard) – Learn how to log into the Dashboard and discover the interface. 2. [Create your company and its members](#select-the-business-user-creation-path) – Create the legal entity, its legal representative and shareholders. 3. [Review KYC Documents](#review-the-kyc-documents) – Make sure the proper documents have been uploaded in accordance with your KYC Form. 4. [Submit your company's KYB](#submit-your-company-s-kyb-to-treezor) – Send the documents to Treezor for verification. 5. [Create your Master Wallet](#create-your-master-wallet) – Create the company's Wallet. 6. [Abide by additional vigilance measures](#abide-by-additional-vigilance-measures) – Make a SEPA Credit Transfer to your Wallet in production if indicated by your KYC Form. ## Get to know your Dashboard The no-code guide relies on Treezor's Dashboard, a user interface allowing you to interact with the Treezor API without relying on developer tools. ### Log into your Dashboard Treezor provided you with the URL to log into your Dashboard. For your Sandbox, the URL is built as follows: * `https://dashboard-{yourCompanyName}.sandbox.treezor.co` Upon entering this URL, you'll be redirected to the sign-in page. You may then enter your email and password or use the SSO feature to log in, depending on the available options. Below is an example of Treezor's default login page. ### Discover the Dashboard interface Before you start, let’s take a quick guided tour of the key components of the Dashboard interface. **Note – Your Dashboard is customizable** The views may differ from the displayed screenshots, depending on: * Where you’re at in your integration process, if you’re customizing the design * The [Role](/guide/dashboard/dashboard-users#dashboard-user-roles) of the logged-in user, if you’re not using all of Treezor’s features ### Accessing your users Once your users created, you may access the detailed information by: * Taking advantage of the main *Search toolbar* * Navigating the *All Users* view Upon selecting a user, the corresponding details will be displayed in the *Profile Boards* view. #### Search toolbar The Dashboard main toolbar provides a series of user attributes-based search fields. You may take advantage of the search fields available in the main toolbar to find a specific user based on its: * **User Id** – Corresponds to the `userId` automatically generated by Treezor when creating a user. * **User Tag** – Corresponds to the [`userTag`](/guide/api-basics/objects-tags), a field you can populate to suit your needs. * **Email** – The `email` provided during the user creation. * **Name** – Takes into account the `firstName`, `lastName`, `legalName` and `email` provided during the user creation. Once one of the fields is populated, click on the "Search" button to launch the search. #### All Users view The *All Users* view provides a table listing all your users with some key information. Upon clicking on a user, it opens the corresponding profile in the *Profiles Board* view. ## Select the Business User creation path The Dashboard offers tailored user creation paths for you to do all the steps to create your company in one go. Your company is a legal entity, a user that is referred to as a Business User in the Dashboard. → Access the *Create User* view by clicking on "Create a new User" in the Navigation menu. → Select the "Business User" creation path and click on the "Continue" button to start creating your company. ## Fill the main information of your company You can now provide the declarative data of your company, as requested by the KYC Form shared with you by Treezor. If your company is listed in Credit Safe, entering the legal registration number will allow you to automatically prefill information. → Enter your company registration number or SIREN. After a short loading time, the following may occur: ::: details The company is found → Click on the "Prefill data" button. → Thoroughly check and edit the prefilled information if need be. ::: ::: details Several companies are found → Click on the "Select the company" button. → In the *Select the company* popup, select the correct company from the list. If not available, you may cancel and enter data manually. ::: ::: details The company is not found → Click on the "Enter Data Manually" button to display the fields for you to fill in. ::: Legal sector information differs depending on the Legal Sector Type: * **Legal Sector Type** – Will define which data you will have to enter in the Legal Sector field (either NACE, or NAF) * **Legal Sector** – Either a 4-digit code (NACE) or a 4-digit code followed by an uppercase character (NAF). Once all the mandatory information is entered, you may click on the "Next" button to proceed to the next step. ## Add verification details and documents The verification details step focuses on the declarative data necessary for the KYC Review of your compnay. → Fill the information as requested by the KYC Form shared with you by Treezor. → Upload all the necessary documents for the legal entity as well, still abiding by the KYC Form shared with you by Treezor. **Tip – You can upload the documents later** You may upload documents after the creation process is done. Ensure however that all documents for all users (legal entity and company members) are provided before requesting the KYC Review. Once all the mandatory information is entered, you may click on the "Next" button to proceed to the next step. ## Add the company members Now, you can directly declare the legal representatives and shareholders of your company. ### Add the legal representatives The legal representative is the person legally appointed to represent your company. As such, you need to create a child user of your company in order to declare this legal representative. → Click on the "Add Members" button. → Provide the name and unique email of the legal representative in the displayed fields. → Select the "Legal representative" role. → Navigate the *User information*, *Birth and Nationality*, *Situation and tax residence*, and *Documents* tabs to fill in all the required information regarding your legal representative. ### Add the shareholders You must declare any shareholder who owns 25% or more of your company (directly or via a holding company). → Scroll up to click on the "Add Members" button located in the upper right corner of the view. Upon doing so, a new section is displayed at the bottom for you to fill with the shareholder information. → Provide the name and unique email of the Shareholder in the displayed fields. → Select the "Shareholder" role and add the ownership percentage. → Navigate the *User information*, *Birth and Nationality*, *Situation and tax residence*, and *Documents* tabs to fill in all the required information regarding your shareholder. Repeat the operation for as many shareholders as you need to declare. Once all the company members are declared, click on the "Next" button located at the bottom of the view. ## Confirm the creation The *Summary* view displays all the information entered for your company (legal entity) and the company members. Review the information before confirming the creation. A success message is displayed, and you’re redirected to the *Profile Boards* view, with your company selected. ## Review the KYC Documents **Tip – Make sure all the necessary documents are uploaded** If you didn't upload the documents during the user creation steps, you can go to the *Profile Boards* view, *KYB* tab to [upload more documents](/guide/dashboard/kyc#uploading-kyc-documents). To make sure you’re about to submit the relevant documents to Treezor, a validation step is required. For each one of your users' documents (company, legal representative, and shareholders): → In the *Profile Boards* view, *KYC* (or *KYB*) tab, *Documents* section, click on the ellipsis button and select the “Review document” command for each document whose [status](/guide/dashboard/kyc#document-statuses) is “Pending (you)”. → In the prompted *Review Document* popup, review the uploaded document on the left section of the popup. → If the document is accurate, selected the "Reviewed" option of the *Status* and enter a comment. → Click on the “Submit” button to complete the validation. As a result, the document status becomes "Reviewed". → Repeat this process for as many documents and users as you need for the KYB process of your legal entity. Once all the documents are validated, the status changed for "Reviewed, to submit". ## Submit your company's KYB to Treezor Once you have uploaded and validated all the required documents for your company, legal representative and shareholders, you can send this information to Treezor for review. To do so: → In the *Profiles Board* view, make sure the currently selected user is your company’s legal entity. → In the *KYC* tab, click on the “Submit KYC to Treezor” button in the upper right corner of the view. You don’t need to repeat this operation for the legal representative and the shareholders, it has automatically been done by Treezor. → In Sandbox, contact your *Implementation Manager* to validate your KYB in order to continue testing your implementation. **Information – In Production, verification is done by Treezor Compliance team** Verification usually takes about 24h, but may take up to 48h or more (working days only). ## Create your Master Wallet Your Master Wallet is a wallet of type 15, but only Treezor can create them. You need to create a dummy wallet and then contact your *Implementation Manager* to turn it into a Master Wallet. To do so: → In the *Profile Boards* view, select your legal entity user and click on the *Wallets* tab. → Click on the “Add Wallet” available in the upper right corner. → In the prompted *Creeate Wallet* popup, enter the following information: * **Wallet name** – Name of the wallet * **Wallet type** – The Wallet Type 15 is not available by default. You can select any wallet you want and request for an update afterwards. → Click on the "Create wallet" button to confirm the creation. → Contact your *Implementation Manager* and provide them with the Wallet ID to change your wallet type to 15. ## Abide by additional vigilance measures Your KYC Form provided by Treezor may indicate that you need to make a credit transfer to complete your company validation process. This is usually covered in the use cases by the initial transfer made to your Master Wallet. You can’t make this transfer through the Dashboard. In Sandbox, you will need to go through this step with an API Transfer emulation if you wish to test card transactions. ## Check your company’s status Once Treezor has validated your company, the *Global KYC Status* section will indicate a “Validated” status. The Master Wallet can only be used once the company is validated. --- --- url: /guide/strong-customer-authentication/cross-device.md description: >- Technical guide for implementing strong customer authentication for web applications, by delegating the generation of SCA proofs to another enrolled device. Includes required parameters, request structure, and response examples. --- # Cross-Device SCA ## When to use cross-device SCA If you expose a web application that uses the Treezor API in any way, it must also enforce SCA. This means having at least one enrolled device capable of generating SCA proofs. Without an SCA proof, Users can connect to your back end but can't make any request to the Treezor API. Your web application would then be limited to non-Treezor features. You can however delegate the generation of SCA proofs to another device that has been previously enrolled, therefore allowing for full-featured web application experience from any device. In a nutshell, when logging in from a computer using a non-enrolled web browser, the User either: * Logs only into your back end and cannot make any request to the Treezor API, or * Approves the login attempt from an enrolled device, using the methods described in this article. Treezor offers 2 solutions to delegate SCA proofs to an enrolled device. | Solution | Description | | --- | --- | | [**Web Native**](introduction#web-native) | This method uses exclusively **web-based** technologies provided by Treezor. | | [**Mobile SDK**](sdk) | This method consists in running your **mobile application**, but is only relevant if you provide both a mobile and a web application. | ### Process Cross-Device SCA implies the following steps. | | Step | Device | | :---: | --- | --- | | | **[Queuing new SCA proof requests from the non-enrolled device](#create-the-operation-on-the-web-browser)** `/core-connect/sca/scaOperations` | | | | **Retrieving the queued SCA proof request on an enrolled device** `/core-connect/sca/scaOperations` | | | | **[Generating SCA proof on the enrolled device](#sca-signature-on-enrolled-device)**| | | | **Updating the queue with the signed SCA proof** `/core-connect/sca/scaOperations/{id}` | | | | **Retrieving the signed proof from the queue on the non-enrolled device** `/core-connect/sca/scaOperations/{id}` | | | | **[Sending the SCA proofed query to Treezor from the non-enrolled device](#final-submission-on-the-web-browser)** | | ::: details Sequence diagram Find below the code for the exhaustive diagram for you to view in [Mermaid](https://mermaid.live/edit). ``` sequenceDiagram autonumber actor endUser as End user participant notenr as Not-enrolled device participant enr as Enrolled device participant agent as Your back end participant trz as Treezor endUser->>notenr: Try to make a sensitive operation or a login notenr->>agent: Queue new SCA proof requests (POST /core-connect/sca/scaOperations) agent->>trz: POST /core-connect/sca/scaOperations with end user JWT trz->>trz: Store operation request trz->>agent: Return SCA Operation ID agent->>notenr: Return SCA Operation ID par Pulling on non-enrolled device loop Every X seconds notenr-->agent: Pull the SCA Operation status (GET /core-connect/sca/scaOperations/{operationId}) agent-->trz: GET /core-connect/sca/scaOperations/{operationId} with end user JWT end and End user validates operation on enrolled device alt Send a notification to end user enrolled device (if it's mobile device) agent->>enr: Send push notification end endUser->>enr: Log in (with SCA) enr->>agent: Send credentials agent->>agent: Validate credentials agent->>trz: Get end user JWT (delegated_end_user grant type) endUser->>enr: List SCA Operation PENDING enr->>agent: Request SCA Operation PENDING (GET /core-connect/sca/scaOperations) agent->>trz: Request SCA Operation PENDING (GET /core-connect/sca/scaOperations) with end user JWT trz->>agent: Response agent->>enr: Response endUser-->enr: Trigger SCA to validate operation alt User refuse operation endUser-->enr: Refuse operation enr-->agent: PUT /core-connect/sca/scaOperations/{operationId} agent->>trz: PUT /core-connect/sca/scaOperations/{operationId} with end user JWT notenr-->endUser: Display message "Your operation was refused" end enr-->agent: Send SCA Proof agent-->trz: PUT /core-connect/sca/scaOperations/{operationId} with SCA proof and end user JWT notenr-->endUser: Display message "Operation validated" end notenr->>agent: Call the requested endpoint like POST /beneficiaries agent->>trz: Call the requested endpoint like POST /beneficiaries with the SCA proof generated on enrolled device ``` ::: ## Prerequisites Treezor exposes a set of endpoints to queue and update operations mandating an SCA signature. On your back end, you should proxy the following endpoints: | Endpoint | Description | | --- | --- | | `/core-connect/sca/scaOperations/` | Queue an operation that requires SCA signature | | `/core-connect/sca/scaOperations/` | Retrieve a list of all operations pending SCA signature | | `/core-connect/sca/scaOperations/{scaOperationRequestId}` | Retrieve a specific operating pending SCA signature | | `/core-connect/sca/scaOperations/{scaOperationRequestId}` | Update a pending operation with the appropriate signature (SCA proof) | ## Create the operation on the web browser The end user submits an operation on your web app using a form (e.g., creating a [Beneficiary](/guide/transfers/beneficiaries)) which you save to the queue as it cannot be sent to Treezor without an SCA proof. ### Attributes | Attribute | Type | Description| | --- | --- | --- | | `dataToSign` | string | The expected [data to be signed](securing-endpoints) for the desired endpoint and action. | | `actionName` | string | Must be one of the allowed actions. We recommend you concatenate the HTTP verb and the route name (e.g., `postPayouts`). | | `actionDescription` | string | Describes the action to help the User understand what they are validating. | | `requestBy` | string | The User `id` that must sign the operation. This value is either: **Mandatory** if your `{accessToken}` was obtained with `grant_type` = `client_credentials`**Optional** if your `{accessToken}` was obtained with `grant_type` = `delegated_end_user` as the User `id` is already available in the JWT | **Tip – `iat` attribute always available in `dataToSign`** While the `iat` (current timestamp in milliseconds) is only necessary for [Web Native](introduction#web-native) signing, Treezor provides it regardless of the Treezor SCA proofing options ([SDK](sdk), [SDK Abstraction](sdk-abstraction), [Web Native](introduction#web-native)). This way, you don't have to alter the `dataToSign` depending on the signing solution which isn't known at the time of operation queuing. ### Examples Below is an example to request an SCA proof of a [per-operation](securing-endpoints#individual-actions) action (the creation of a Beneficiary). ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/core-connect/sca/scaOperations' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "dataToSign": { "iat": {currentTimestampInMillisecond}, "url":"{baseURL}/v1/beneficiaries?accessTag=12345", "body":{ "userId": "12345", "name": "Alex Oak", "address": "15 Magnolia road", "iban": "FR113000300030592123456789", "bic": "SOGEFRPPXXX", "usableForSct": true } }, "actionName": "postPayouts", "actionDescription": "Creates a payout", "requestBy": "", } ``` ::: Below is an example to obtain an SCA proof that can be used authenticate the User with a `grant_type` set to [`delegated_end_user`](/guide/strong-customer-authentication/introduction#authentication), allowing for [per-session operations](securing-endpoints#per-session). ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/core-connect/sca/scaOperations' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "dataToSign": { "iat": {currentTimestampInMillisecond}, }, "actionName": "postPayouts", "actionDescription": "Creates a payout", "requestBy": "", } ``` ::: Returns an object containing the UUIDv4 (`scaOperationRequestId`) of the operation, allowing you to [check on its evolution](#checking-for-signature) later on. ::: code-group ```json [JSON] { "scaOperationRequestId": "" } ``` ::: This pending operation is made available via the `/core-connect/sca/scaOperations/{scaOperationRequestId}?userId={userId}` endpoint. ## Checking for signature The browser should display a message indicating to the end user that they must check their enrolled device for pending operations. In the meantime the browser must continuously check if a signature has been provided yet. To do so, check the `status` attribute of the scaOperation by either: * Querying your `/core-connect/sca/scaOperations/{scaOperationRequestId}` endpoint at fixed intervals (e.g., every 5 seconds), or * Using [HTTP long-polling](https://www.rfc-editor.org/rfc/rfc6202) to be updated as soon as the operation gets signed. The `status` is initially valued to `PENDING` and can change to `REFUSED` or `VALIDATED` upon User confirmation on the enrolled device. ### Example ::: code-group ```bash [CURL] curl -X GET '{baseUrl}/core-connect/sca/scaOperations/{scaOperationRequestId}' \ --header 'Authorization: Bearer {accessToken}' ``` ::: Returns the following. ::: code-group ```json [JSON] { "scaOperationRequestId": "", "dataToSign": {}, "actionName": "postPayouts", "actionDescription": "Creates a payout", "createdAt": "{date time with timezone, RFC 3339}", "status": "PENDING|REFUSED|VALIDATED", "validatedAt": "{date time with timezone, RFC 3339}"|null, "refusedAt": "{date time with timezone, RFC 3339}"|null, "scaProof": "" } ``` ::: ## Push to the enrolled device If you have implemented push notifications with your Mobile or Web App, you should push a notification to the device asking it to check for pending SCA operations. ## SCA Signature on enrolled device Your Mobile or Web App has retrieved the operations (`/core-connect/sca/scaOperations`) either: * By automatically following the push notification or * By the action of the end user who opened the App and clicked on your *Pending operations* button. From the enrolled device, and with a JWT obtained with a `grant_type` = `delegated_end_user` ::: code-group ```bash [CURL] curl -X GET '{baseUrl}/core-connect/sca/scaOperations' \ --header 'Authorization: Bearer {accessToken}' ``` ::: **Tip – You may also:** * Filter SCA operations by appending `?status=PENDING` to the URL. * Retrieve only the specific SCA operation using `{baseUrl}/core-connect/sca/scaOperations/{scaOperationRequestId}`. Returns the list of SCA Operations. ::: code-group ```json [JSON] [ { "scaOperationRequestId": "", "dataToSign": {}, "actionName": "", "actionDescription": "", "createdAt": "{date time with timezone, RFC 3339}", "status": "PENDING|REFUSED|VALIDATED", "validatedAt": "{date time with timezone, RFC 3339}"|null, "refusedAt": "{date time with timezone, RFC 3339}"|null, "scaProof": "", } ] ``` ::: You can now display the details of the pending operation to your end user so that can make sure that they validate or refuse the correct operation. If the end user decides to approve the operation, you: * Use the [SDK](sdk), [SDK wrapper](sdk-abstraction) or [Web Native](introduction#web-native) option to sign the operation. * Update the operation (`/core-connect/sca/scaOperations/{scaOperationRequestId}`) with the SCA proof `scaProof` generated on the enrolled device. ::: code-group ```bash [CURL] {5,6} curl -X PUT '{baseUrl}/core-connect/sca/scaOperations/{scaOperationRequestId}' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{ "status": "REFUSED|VALIDATED", "scaProof": "" # the scaProof is only mandatory if status=VALIDATED }' ``` ::: **Security – Grant Type** This endpoint is only accessible using a JWT obtained with `grant_type` = `delegated_end_user` ## Final submission on the web browser Using periodic requests to `/core-connect/sca/scaOperations/{scaOperationRequestId}?userId={userId}` or using HTTP long-polling, the web browser is informed that the previously created operation is now signed. ::: code-group ```json{7,8,10} [JSON] { "scaOperationRequestId": "", "dataToSign": {}, "actionName": "postPayouts", "actionDescription": "Creates a payout", "createdAt": "{date time with timezone, RFC 3339}", "status": "VALIDATED", "validatedAt": "{date time with timezone, RFC 3339}", "refusedAt": null, "scaProof": "ZHVtbXlwYXNzY29kZQ==.ZHVtbXl3ZWJhdXRobg==", } ``` ::: The browser can now [submit the operation to Treezor](/guide/strong-customer-authentication/introduction), along with the SCA proof. The request therefore has exactly the same structure as if it was sent from the enrolled device itself. --- --- url: /guide/dashboard/dashboard-users.md description: >- Provide access to the Dashboard to your teams. Fine-tune your operational efficiency by assigning dedicated roles, which grant permissions for specific views and actions. --- # Dashboard Users Dashboard Users are the users that can access your Dashboard for administration and support purposes. You can manage them in the *Dashboard Users* view available from the main navigation, *Administration* section. ## Create a Dashboard User If you have an Administrator or a Manager Role, you can create new Dashboard users by clicking on the “Add a new user” button available in the upper right corner. In the prompted dialog box, you need to fill in the following fields: * Username (or email), which must be unique * Role (as described in the table below) * Password * SAML Key (when using your own SSO solution, to link automatically a Dashboard User to a Dashboard OAuth2 client) ## Dashboard User Roles Dashboard Users can have different Roles, granting different [Scopes](/guide/api-basics/authentication). | Role | Ab. | Description | |--- | --- | --- | | Read-only | RO | Restricted role with first-level viewing rights. | | Basic editor | BE | Restricted role for first-level edition rights. | | User management | UM | For operators to edit information and create users. | | User & beneficiary management | BM | For operators to create beneficiaries and manage users. | | Transfer management only | TM | For operators to create transfers only. | | All rights editor | AR | For operators with advanced editing rights. | | Manager | M | Dashboard managers, with exhaustive rights and Dashboard User management rights. | | Administrator | A | Administrators with all the rights including configuration and bulk card creation. | **Note – Administrator Role specificities** Only Administrators can create, edit and delete other Administrators. Also, only Administrators can grant the Administrator Role. ### Accessible views per role ::: tabs \== Dashboard views | Dashboard views | RO | BE | UM | BM | TM | AR | M | A | |--- |:---: |:---: |:---: |:---: |:---: | :---: | :---: | :---: | | Search Users | | | | | | | | | | Profiles Board | | | | | | | | | | All Users | | | | | | | | | | Create a new User | | | | | | | | | | All Cards | | | | | | | | | | All Card Transactions | | | | | | | | | | Bulk Cards | | | | | | | | | \== Administration views | Administration views | RO | BE | UM | BM | TM | AR | M | A | |--- |:---: |:---: |:---: |:---: |:---: | :---: | :---: | :---: | | Dashboard Users | | | | | | | | | | Predef Restriction Groups | | | | | | | | | | Templating management | | | | | | | | | | Webhooks | | | | | | | | | ::: ### Possible actions per user role ::: tabs \== Overview | Action | RO | BE | UM | BM | TM | AR | M | A | |--- |:---: |:---: |:---: |:---: |:---: | :---: | :---: | :---: | | Edit User main information | | | | | | | | | | Delete User | | | | | | | | | | Secure SCA on this device | | | | | | | | | | Unlock SCA on this device | | | | | | | | | | Reset PIN on the device | | | | | | | | | | Delete SCA on this device | | | | | | | | | \== KYC / KYB | Action | RO | BE | UM | BM | TM | AR | M | A | |--- |:---: |:---: |:---: |:---: |:---: | :---: | :---: | :---: | | Edit User information | | | | | | | | | | Add KYC document | | | | | | | | | | Submit KYC to Treezor | | | | | | | | | | Review document | | | | | | | | | | Delete document | | | | | | | | | | View processed KYC documents | | | | | | | | | | Download processed KYC documents | | | | | | | | | \== Children / Company members | Action | RO | BE | UM | BM | TM | AR | M | A | |--- |:---: |:---: |:---: |:---: |:---: | :---: | :---: | :---: | | Add Child User | | | | | | | | | \== Wallets | Action | RO | BE | UM | BM | TM | AR | M | A | |--- |:---: |:---: |:---: |:---: |:---: | :---: | :---: | :---: | | Add Wallet | | | | | | | | | | Make a Payout | | | | | | | | | | Create Wallet to Wallet Transfer | | | | | | | | | | Download Operations | | | | | | | | | | View Wallet Details | | | | | | | | | | Generate PDF Documents | | | | | | | | | | Edit Wallet | | | | | | | | | | Deactivate Wallet | | | | | | | | | \== Cards | Action | RO | BE | UM | BM | TM | AR | M | A | |--- |:---: |:---: |:---: |:---: |:---: | :---: | :---: | :---: | | Create card | | | | | | | | | | Activate card | | | | | | | | | | Block card | | | | | | | | | | Update card settings | | | | | | | | | \== Beneficiaries | Action | RO | BE | UM | BM | TM | AR | M | A | |--- |:---: |:---: |:---: |:---: |:---: | :---: | :---: | :---: | | Create Beneficiary | | | | | | | | | | Edit Beneficiary | | | | | | | | | ::: ## Manage a Dashboard User | | Action | Description | | :---: | --- | --- | | | **Update** | Edit an existing Dashboard User (using the same dialog box as for the creation). | | | **Delete** | Remove a Dashboard User. This action is irreversible. | | | **More** | Provides access to the "Reset 2FA" command. The corresponding user will have to set up their [2FA](./introduction#standard-login-with-2fa) the next time they logged in. | | | **Unblock** | Unblock a blocked Dashboard User. This action is only available for Dashboard Users who failed to log in 3 times in a row. | --- --- url: /guide/api-basics/data-format.md description: >- Learn about the supported data structures for API requests and responses. Covers JSON conventions, data type mapping, and best practices for accurate API interaction. --- # Data Format The Treezor API follows the standards below regarding the formats of data it returns and accepts. Exceptions are detailed in the documentation when relevant. ## Amounts Amounts are expected as `number` with two decimals. They do not include the currency name. ### Example * `180.99` for an amount of **180,99** * `1285.00` for an amount of **1285** ## Currencies Currencies follow the **ISO 4217** standard, a 3-character code. While this code is usually in the 3-letter capitalized format, you may encounter the numerical version on some endpoints (e.g., `EUR` or `978` for **Euro**). ## Countries Countries follow the **ISO 3166-1 alpha-2** standard, a 2 capitalized letter code (e.g., `FR` for France). ::: details Examples * `FR` for **France** * `DE` for **Germany** * `CH` for **Switzerland** ::: ## Dates Most dates follow the **[RFC3339](https://tools.ietf.org/html/rfc3339)** standard. They are provided and expected to be in Paris time, which is: * `UTC+2` Central European **DST (Daylight Saving Time)** * `UTC+1` Central European **otherwise**. Some exceptions such as the card transaction `authorizationIssuerTime` can apply a different timezone. When in doubt, please refer to the [API Reference](/api-reference/api-endpoints). ### Examples ::: code-group ```php [PHP] date('Y-m-d\TH:i:sP'); // 2020-08-25T07:06:13+02:00 ``` ::: ```console 2020-08-25T07:06:13-07:00 ``` You can [read about UTC here](https://en.wikipedia.org/wiki/Coordinated_Universal_Time) and [check UTC timezones by country there](https://en.wikipedia.org/wiki/List_of_time_zones_by_country). ## Phones Phone numbers are expected with the country code prefix (e.g., `+33`), without leading zero. ::: details Examples * The French number `06 05 04 03 02` is expected as `+33605040302` * The German number `013 456 7899` is expected as `+491234567899` ::: ## Files Files (such as [documents](/guide/user-verification/documents) and [templates](/guide/api-basics/templates)) are expected to be in [`base64` encoded format](https://en.wikipedia.org/wiki/Base64) in a JSON object attribute. They are also returned as base64. ### Example ::: code-group ```php [PHP] // composer require php-curl-class/php-curl-class $request = new Curl\Curl; $request->setHeader('Authorization', 'Bearer '); // Don't forget to replace with your token $request->setHeader('Content-Type', 'application/json'); $request->post( 'https://.sandbox.treezor.co/v1/documents/', [ // [...] this example doesn't show all the mandatory parameters 'userId' =>'', 'documentTypeId' =>'', 'name' =>'19-Extrait-Kbis.pdf', 'fileContentBase64' =>base64_encode( file_get_contents( '/home/johnsmith/Downloads/19-Extrait-Kbis.pdf' ) ) ] ); ``` ```bash [CURL] # encode the file into base64 base64 /home/johnsmith/Downloads/19-Extrait-Kbis.pdf > /home/johnsmith/Downloads/19-Extrait-Kbis.base64 # show the content of the encoded file cat /home/johnsmith/Downloads/19-Extrait-Kbis.base64 # ZHVtbXkg[...]dGVzdAo= # post the encoded file curl -X POST '{baseUrl}/v1/documents' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{ "userId":"{userId}", "documentTypeId":"[documentTypeId}", "name":"19-Extrait KBis.pdf", "fileContentBase64":"ZHVtbXkg[...]dGVzdAo=", }' # [...] # This example doesn't show all the mandatory parameters ``` ::: ## IDs * **Numerical identifiers** such as [`userId`](/guide/users/introduction), should be provided as `integer`. * **Textual identifiers** such as [`client_id`](/guide/api-basics/authentication#credentials), should be provided as `string`. **Ids are progressively migrated to [UUIDv4](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_\(random\)).** You should anticipate this API-wide migration by typing all IDs as 36-character **strings** in your databases. ### Numerical example ::: code-group ```json [JSON] { "userId":18742 // No quotes (legacy ID) } ``` ::: ### Textual example ::: code-group ```json [JSON] { "client_id":"" // with quotes } ``` ::: ### UUIDv4 example ::: code-group ```json [JSON] { "webhook_id":"45a10236-4e55-41b5-8cbd-00acea4cb553" } ``` ::: ## Texts, metas, tags Strings are expected in Unicode (UTF-8). ## Addresses Address lines (`address{1-3}` attributes) for User addresses allow for 150 characters, but you may limit them to 56 characters following the [AFNOR XP Z 10-011](https://fr.wikipedia.org/wiki/Restructuration,_normalisation_et_validation_postale) standard of May 1997. If you're issuing [Cards](/guide/cards/introduction), the Card object applies further restrictions and we recommend even shorter strings due to mail carrier limitations. Below the maximum number of characters per field. | Field | User object | Card object | Mail carrier recommendation | | --- | ---: | ---: | ---: | | `address1` | 150 | 50 | ~38 | | `address2` | 150 | 50 | ~38 | | `address3` | 150 | 35 | 35 | **Important – Mail carrier limitations** The table above provides a rough estimate for mail carrier maximum amount of printed characters, as those limitations may change depending on the selected font for instance. --- --- url: /guide/api-basics/using-treezor-as-oauth-identity-provider.md description: >- Leverage Treezor as your OAuth Identity Provider for delegated authentication. This guide details the process of authenticating end users, covering the OAuth 2.0 flow, JWT exchange and validation, and extracting user identity for your application. --- # Delegated Authentication Treezor allows you to use its [OAuth](https://oauth.net/) industry standard authentication mechanism to **authenticate your customers through your application**. Delegating the authentication to Treezor allows you to focus on your business while having the peace of mind provided by an expertly set up authentication mechanism. Using Treezor as an Identity Provider means that: * You don't need to handle passwords yourself (nor password retrievals/resets) * You don't need to maintain a database of User credentials * You don't need to keep up with hashing and salting best practices * You only keep an association between the `userId` provided by Treezor authentication mechanism and the User's information in your own databases **Prerequisites – To use delegated authentication, you need** * **To onboard end users with [Connect](/guide/overview/getting-started#treezor-api)** – Creates their credentials in Treezor Identity Provider. * **A post-authentication URL to be declared to [Connect](/guide/overview/getting-started#treezor-api)** – Where users are redirected after authenticating with Treezor. * **A private/public key pair to be generated by Treezor** – The public key will be provided to you, allowing you to [assert the Tokens authenticity](#asserting-the-jwt-s-legitimacy). ## Flow ```mermaid sequenceDiagram autonumber participant user as User participant app as Regular Web App participant auth as Auth0 Tenant participant api as Your API user->>app: Click to login app->>auth: Authorization Code Request to /authorize auth->>user: Redirect login/authorize prompt user->>auth: Authenticate and Consent auth->>app: Authorization Code app->>auth: Authorization Code + Client ID + Client Secret to /oauth/token auth->>auth: Validate Authorization Code + Client ID + Client Secret auth->>app: ID Token and Access Token app->>api: Request user data with Access Token api->>app: Response ``` ## Logging-in When a User accesses your application and doesn't have a JWT, you redirect them to a [customizable login page](#templating-the-login-page) hosted by Treezor. The User enters their credentials and submits the login form. If the authentication is successful, the user is redirected to a previously [configured URL](#defining-the-redirection-url) of your application with a `code` query parameter appended by Treezor. In and of itself, the `code` doesn't allow you to authenticate the User. You will have to exchange this single-use `code` for a [JWT](/guide/overview/glossary#json-web-token-jwt) using the following request. ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/oauth/token' \ --form 'grant_type="authorization_code"' \ # mandatory --form 'code="{yourTemporaryCode}"' \ # mandatory --form 'client_id="{yourClientId}"' \ # mandatory # --form 'scope=""' # optional, if you want a specific scope ``` ::: Returns an object containing the User's [JWT](/guide/overview/glossary#json-web-token-jwt). ::: code-group ```json [JSON] { "token_type": "Bearer", "expires_in": 3600, "access_token": "{theUsersAccessToken}", "refresh_token": "{theTokenAllowingForJwtRefresh}" } ``` ::: The User can now add this `access_token` in the `Authentication` header of all requests made to your application so that you can [authenticate](#authenticating) them. ## Authenticating To authenticate an end user, you must: * [Ensure that their JWT is legitimate](#asserting-the-jwt-s-legitimacy) * [Extract their identity from the JWT](#extracting-the-user-s-identity) ### Asserting the JWT legitimacy **Security – Ensure your application validates the JWT legitimacy** You must implement and test this step with great care. If your application were to accidentally accept invalid tokens would leave it open to anyone. To check that the token is legitimate, you will use: * The User's JWT Token, * The `RSASSA_PKCS1_V1_5_SHA_256` algorithm, * Your Connect public key. The User's JWT is composed of three sections each encoded in base64 and separated by dots. * The **second** section is the token payload * The **last** section is the token signature Consider the following JWT, as provided by your User in the `Authentication` header. ::: code-group ```json [JSON] eyJ0eXAiOiJKV1QiLCJhbGciOiJSU0FTU0FfUEtDUzFfVjFfNV9TSEFfMjU2In0.eyJpc3MiOiJ0cmVlem9yX2Nvbm5lY3QiLCJpYXQiOjE2MzM1MTMyMjEsImV4cCI6MTYzMzUxNjgyMSwic3ViIjoiNzkwMzdlNmUtYzFlMS00MmYyLWJlOWEtZTI0OWM3NjdjNDc2Iiwic2NvcGUiOlsiYWRtaW4iLCJrZXlzIiwibGVnYWwiLCJyZWFkX29ubHkiLCJyZWFkX3dyaXRlIiwicmVhZF9hbGwiXSwidXNlcklkIjpudWxsLCJjYXJkcyI6W10sIndhbGxldHMiOltdLCJjaGlsZHJlbiI6W10sInVzZXJUeXBlIjoiYXBwbGljYXRpb24iLCJjbGllbnRJZCI6IjkyOTI1MiJ9.cPWi6RY1n0tPIJ1jG8600wZQvMUU1eIZPq1uzIju7OI8SnJ77FBmj25q8w0JcUwGIZf0GDKI51tovi0aqFNZsVrsP1V8o3b_5eJiEA2LtUVimAyWWtheMEa1J5Seqh3_rH5BO0xos2fRXM6CyFK1xDwc5EJeD0Pko5Yq3ls4-bcJt3yYBPH3JkaaADt2ettYATnpv9KnBeTPU7INDwNd2d6orVdc0yUgx9dmO9-NPbYBQuNsPTDOV8nnCWu6P0RAqUdjDZKbrr71Vj61ULur5yIr0oHLYg--80p6mgrMMAbPHQTKHO-wrcA94NvTCQ_5STXxUVfxh34xbOotdmeUeQ ``` ::: You encrypt the payload using the `RSASSA_PKCS1_V1_5_SHA_256` algorithm and Connect public key. ::: code-group ```bash [CURL] # an example will soon be provided aws kms sign \ --key-id '{connectPublicKey}' \ --signing-algorithm RSASSA_PKCS1_V1_5_SHA_256 \ --message '{payload}' ``` ::: You then compare the newly generated signature with the JWT signature. * **If they match**: you can proceed to the next step. * **If they do not match**: * Deny any access to your application, * Consider the event as a potential attack and take appropriate measures. ### Extracting the User's identity As you now can trust the token payload, simply use a base64 decoding function on the token second section (payload). ::: code-group ```bash [CURL] base64 -d "eyJpc3MiOiJ0cmVlem9yX2Nvbm5lY3QiLCJpYXQiOjE2MzM1MTMyMjEsImV4cCI6MTYzMzUxNjgyMSwic3ViIjoiNzkwMzdlNmUtYzFlMS00MmYyLWJlOWEtZTI0OWM3NjdjNDc2Iiwic2NvcGUiOlsiYWRtaW4iLCJrZXlzIiwibGVnYWwiLCJyZWFkX29ubHkiLCJyZWFkX3dyaXRlIiwicmVhZF9hbGwiXSwidXNlcklkIjpudWxsLCJjYXJkcyI6W10sIndhbGxldHMiOltdLCJjaGlsZHJlbiI6W10sInVzZXJUeXBlIjoiYXBwbGljYXRpb24iLCJjbGllbnRJZCI6IjkyOTI1MiJ9" ``` ::: Returns the decoded payload. ::: code-group ```json [JSON] { "iss": "treezor_connect", "iat": 1624439479, "exp": 1624443079, "sub": "79037e6e-c1e1-42f2-be9a-e249c767c476", // here is the trzConnectUserId "scope": [ "keys", "legal", "read_only", "read_write" ], "userId": {userId}, // here is the userId "clientId": {yourClientId}, "cards": [], "wallets": [], "children": [], "userType": "user" } ``` ::: Note that two distinct IDs are contained in this object: * `userId` used across the Treezor API to identify the User (to use to match Connect Users with your locally stored Users). * `sub` (`trzConnectUserId`) used initially during the Connect Onboarding, and when changing password. It is very important to store the `userId` as a string since `userId` will be migrated to UUID in the future. Now you could for example retrieve your locally stored User using the following pseudocode: ::: code-group ```java [Javascript] try { // assert that the JWT signature is valid // and retrieve trzConnectUserId from the JWT payload connectUserId = JWT .assertSignatureIntegrity() .decodePayload() .getConnectUserId() } catch(Exception authenticationError) { // The JWT has an invalid signature, forbid access and terminate App.die(authenticationError.toString(), 403) } // retrieve the locally stored User from your database customer = Customers.getByConnectUserId(connectUserId) // perform any action necessary : display wallets balances, recent operations, etc. wallets = customer.getWallets() ``` ::: **Reading – Learn more about OAuth** You may find [OAuth website](https://oauth.net/) helpful in implementing Treezor's OAuth Identity Provider. --- --- url: /guide/strong-customer-authentication/enrolled-devices.md description: >- Technical guide to retrieve the SCA Wallets created from the Mobile SDK or the Web Native solution via the Treezor API. Includes required parameters, request structure, and response examples. --- # Enrolled devices The [SCA Wallet](introduction#sca-wallet-object) objects returned may be valued differently depending on whether they've been created through the [Mobile SDK](sdk) or Web Native solution. You can define which by having a look at the `settingsProfile` value. ::: details Mobile SCA Wallet example ::: code-group ```json [JSON] {9} { "id": "b72c48e91af6543db755cf24gf2d31e1", "status": "CREATED", "subStatus": "CREATED_READY", "passcodeStatus": "NOT_SET", "locked": false, "lockReasons": [], "lockMessage": null, "settingsProfile": "default", "mobileWallet": { "appBuildNumber": null, "sdkVersion": null, "os": null, "osVersion": null, "brand": null, "productModel": null, "deviceId": null, "deviceIdType": null, "productFingerprint": null, "secretFingerprint": null, "root": null, "pushMessagingId": null, "pushMessagingProvider": null, "mobileUpdateDate": null, "lastEligibilityCheck": null, "nfc": null, "emulator": false, "appleTeamId": null }, "activationCode": null, "creationDate": "2024-12-24T09:40:00+01:00", "deletionDate": null, "activationCodeExpiryDate": "2024-12-24T10:00:00+01:00", "authenticationMethods": [ { "type": "DEVICE_BIOMETRIC", "usages": [ "STRONG_CUSTOMER_AUTHENTICATION" ], "parameters": { "validityDuration": 60 } }, { "type": "NONE", "usages": [ "STRONG_CUSTOMER_AUTHENTICATION" ], "parameters": [] }, { "type": "HYBRID_PIN", "usages": [ "WALLET_MANAGEMENT", "STRONG_CUSTOMER_AUTHENTICATION" ], "parameters": { "maxAttempts": 3, "validityDuration": 60 } } ], "invalidActivationAttempts": null, "userId": "1234567", "scaWalletTag": null, "clientId": "0998765", "activationDate": null, "lockDate":null, "unlockDate":null, "resetPinDate":null } ``` ::: ::: details Web Native SCA Wallet example ::: code-group ```json [JSON] {9} { "id": "a[...]]9kjw_k", "status": "ACTIVE", "subStatus": null, // Always null "passcodeStatus": null, // "SET" if user has a defined passcode (same passcode for all webauthn wallets) "locked": false, // false by default "lockReasons": [], // empty array by default, see list of values "lockMessage": null, // null or string "settingsProfile": "webauthn", // "webauthn" (Web Native) or "default" (Mobile SDK) "mobileWallet": null, // Always null for webauthn "activationCode": null, // Always null for webauthn "creationDate": "2024-12-24T09:57:01+00:00", "deletionDate": null, "activationCodeExpiryDate": null, // Always null for webauthn "authenticationMethods": [ // array of objects, PublicKeyCredentialInterface is a webauthn-only parameter { "userHandle": "dXNlcjEyM0BleGFtcGxlLmNvbQ==", // base64 encoded id of the user you've given during credentials.create for webauthn. "publicKeyCredentialId": "x9yT3mR-1KG-BNSpGMXbgP_WzxY1ywk6wujUkJHzQoL", // Unique identifier of the webauthn public key "transports": [ "internal" ], "aaguid": "bcde1234-56ef-78ab-90cd-123456789012", "backupStatus": false, "uvInitialized": true, "credentialPublicKey": "pQECAyYgASFYIFXcd7YDfxFsfyPEp187k0WVZ5lEE_GHW2ub-fpHuPxSIlggQXMDVfyhBXl1T3LwzohgKJmC_oS4p_EVNeLzRycWz5x", "attestationType": "self", "trustPath": { "type": "Webauthn\\TrustPath\\EmptyTrustPath" }, "backupEligible": false, "counter": 0, "type": "public-key" } ], "invalidActivationAttempts": null, // Always null for webauthn "userId": "100218468", // The user id for the webauthn scaWallet "scaWalletTag": "", "clientId": "http://example", // URL on which the webauthn public key can be used "activationDate": "2024-12-24T09:57:01+00:00", // Identical to creationDate "lockDate":null, "unlockDate":null, "resetPinDate":null } ``` ::: ## Retrieve an SCA Wallet To retrieve a specific SCA Wallet you can use the following request. ::: code-group ```bash [CURL] curl -X GET '{baseUrl}/core-connect/sca/scawallets/{scaWalletId}' \ --header 'Authorization: Bearer {accessToken}' ``` ::: Answers with a `200` HTTP Status Code and returns the SCA Wallets object. ::: code-group ```json [JSON] { "id": "b72c48e91af6543db755cf24gf2d31e1", "status": "CREATED", "subStatus": "CREATED_READY", "passcodeStatus": "NOT_SET", "locked": false, "lockReasons": [], "lockMessage": null, "settingsProfile": "default", "mobileWallet": { "appBuildNumber": null, "sdkVersion": null, "os": null, "osVersion": null, "brand": null, "productModel": null, "deviceId": null, "deviceIdType": null, "productFingerprint": null, "secretFingerprint": null, "root": null, "pushMessagingId": null, "pushMessagingProvider": null, "mobileUpdateDate": null, "lastEligibilityCheck": null, "nfc": null, "emulator": false, "appleTeamId": null }, "activationCode": null, "creationDate": "2024-12-24T09:40:00+01:00", "deletionDate": null, "activationCodeExpiryDate": "2024-12-24T10:00:00+01:00", "authenticationMethods": [ { "type": "DEVICE_BIOMETRIC", "usages": [ "STRONG_CUSTOMER_AUTHENTICATION" ], "parameters": { "validityDuration": 60 } }, { "type": "NONE", "usages": [ "STRONG_CUSTOMER_AUTHENTICATION" ], "parameters": [] }, { "type": "HYBRID_PIN", "usages": [ "WALLET_MANAGEMENT", "STRONG_CUSTOMER_AUTHENTICATION" ], "parameters": { "maxAttempts": 3, "validityDuration": 60 } } ], "invalidActivationAttempts": null, "userId": "1234567", "scaWalletTag": null, "clientId": "0998765", "activationDate": null, "lockDate":null, "unlockDate":null, "resetPinDate":null } ``` ::: ## List SCA Wallets for a User You may also retrieve all SCA Wallets belonging to a User using the following request. This request doesn't return SCA Wallets whose status is `DELETED`. ::: code-group ```bash [CURL] curl -X GET '{baseUrl}/core-connect/sca/scawallets?userId={userId}' \ --header 'Authorization: Bearer {accessToken}' ``` ::: Answers with a `200` HTTP Status Code and returns the list of SCA Wallet objects. ::: code-group ```json [JSON] { "scawallets": [ { "id": "b72c48e91af6543db755cf24gf2d31e1", "status": "CREATED", "subStatus": "CREATED_READY", "passcodeStatus": "NOT_SET", "locked": false, "lockReasons": [], "lockMessage": null, "settingsProfile": "default", "mobileWallet": { "appBuildNumber": null, "sdkVersion": null, "os": null, "osVersion": null, "brand": null, "productModel": null, "deviceId": null, "deviceIdType": null, "productFingerprint": null, "secretFingerprint": null, "root": null, "pushMessagingId": null, "pushMessagingProvider": null, "mobileUpdateDate": null, "lastEligibilityCheck": null, "nfc": null, "emulator": false, "appleTeamId": null }, "activationCode": null, "creationDate": "2024-12-24T09:40:00+01:00", "deletionDate": null, "activationCodeExpiryDate": "2024-12-24T10:00:00+01:00", "authenticationMethods": [ { "type": "DEVICE_BIOMETRIC", "usages": [ "STRONG_CUSTOMER_AUTHENTICATION" ], "parameters": { "validityDuration": 60 } }, { "type": "NONE", "usages": [ "STRONG_CUSTOMER_AUTHENTICATION" ], "parameters": [] }, { "type": "HYBRID_PIN", "usages": [ "WALLET_MANAGEMENT", "STRONG_CUSTOMER_AUTHENTICATION" ], "parameters": { "maxAttempts": 3, "validityDuration": 60 } } ], "invalidActivationAttempts": null, "userId": "1234567", "scaWalletTag": null, "clientId": "0998765", "activationDate": null, "lockDate":null, "unlockDate":null, "resetPinDate":null }, { "id": "a[...]]9kjw_k", "status": "ACTIVE", "subStatus": null, "passcodeStatus": null, "locked": false, "lockReasons": [], "lockMessage": null, "settingsProfile": "webauthn", "mobileWallet": null, "activationCode": null, "creationDate": "2024-12-24T09:57:01+00:00", "deletionDate": null, "activationCodeExpiryDate": null, "authenticationMethods": [ { "userHandle": "dXNlcjEyM0BleGFtcGxlLmNvbQ==", "publicKeyCredentialId": "x9yT3mR-1KG-BNSpGMXbgP_WzxY1ywk6wujUkJHzQoL", "transports": [ "internal" ], "aaguid": "bcde1234-56ef-78ab-90cd-123456789012", "backupStatus": false, "uvInitialized": true, "credentialPublicKey": "pQECAyYgASFYIFXcd7YDfxFsfyPEp187k0WVZ5lEE_GHW2ub-fpHuPxSIlggQXMDVfyhBXl1T3LwzohgKJmC_oS4p_EVNeLzRycWz5x", "attestationType": "self", "trustPath": { "type": "Webauthn\\TrustPath\\EmptyTrustPath" }, "backupEligible": false, "counter": 0, "type": "public-key" } ], "invalidActivationAttempts": null, "userId": "100218468", "scaWalletTag": "", "clientId": "http://example", "activationDate": "2024-12-24T09:57:01+00:00", "lockDate":null, "unlockDate":null, "resetPinDate":null } ], "cursor": { "prev": "356a192b7913b04c54574d18c28d46e6395428ab", "current": "da4b9237bacccdf19c0760cab7aec4a8359010b0", "next": "da4b9237bacccdf19c0760cab7aec4a8359010b0" } } ``` ::: --- --- url: /guide/strong-customer-authentication/user-enrollment.md description: >- Technical guide for creating SCA Wallets to enroll users. The SCA Wallet is a secure enclave stored on a device, containing the private key necessary for Strong Customer Authentication. --- # Enrolling Users Enrolling users consists in creating [SCA Wallets](introduction#sca-wallet-object) for them. An SCA Wallet is the secure enclave locally present on a device. This digital safe contains a private key necessary for Strong Customer Authentication. Below the enrollment steps and device limits per solution: | Device | Enrollment steps | Limits | | --- | --- | --- | | **Mobile** | 1 – Creation of the SCA Wallet on the user's device2 – Provisioning of the SCA Wallet with the `activationCode`3 – Definition of PIN code or biometry by the user to finalize device enrollment |1 active SCA Wallet per device | | **Web** | 1 – Generation of the passkeys on the user's device2 – Passcode creation and encryption on the user's device3 – Forwarding of the public key and encrypted passcode to Treezor to finalize the device enrollment | 5 active SCA Wallets per device | If these limits are exceeded, an HTTP error is returned. ## Mobile enrollment This section describes the main steps involved in mobile enrollment, regardless of the mobile solution you chose. You can learn more in the [Mobile SDK](sdk) and [Mobile Abstraction Layer](sdk-abstraction) articles. With mobile solutions, only one active SCA Wallet can be created per device. You can take advantage of the [Swap](#swap-sca-wallets) feature to create a new wallet on an existing device without needing to delete the old one. ### New User enrollment When using the [SDK](sdk), an SCA Wallet can be automatically created when creating a new User. In such cases, the following occurs: * A key pair is generated for this SCA Wallet. * The SCA Wallet is associated to the new User. * Treezor sends you a [`sca.wallet.create`](events#sca-wallet-create) webhook notifying you of the SCA Wallet creation. By default, there is a limit of 1 active SCA Wallet per device when using the mobile solution. If this limit is exceeded, an HTTP error is returned. ### Existing User enrollment You may need to create an SCA Wallet for an existing user, when migrating to SCA services for instance. To manually create an SCA Wallet when choosing a mobile solution, you can use the following request. #### Parameters Below are the parameters to create an SCA Wallet manually. | Attribute | Type | Description | | --- | --- | --- | | `userId` | string | The unique identifier of the user the SCA Wallet is to be attached to. | | `scaWalletTag` | string | Custom value for the SCA Wallet. Can be used to name the device for which the new SCA Wallet is created. Max length: 256 characters. | | `authMethod` | array | The chosen methods for the 2-factor authentication. Can be the following strings: `ID`, `OTP EMAIL`, `OTP SMS`, `OTHER` | #### Request example ::: code-group <<< @/guide/strong-customer-authentication/snippets/create\_scaWallet.bash \[CURL] ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "userId":"123456", "scaWalletTag":"Iphone 13 mini", // Can be the device name (the SCA Wallet is created for) "authMethod":["ID", "OTP SMS"] // Optional } ``` ::: Answers with a `200` HTTP Status Code and the following response. ::: code-group ```json [JSON] {     "id": "3532d3d44dd999e8957e07cc7e860b2a",     "status": "CREATED",     "subStatus": "CREATED_READY",     "passcodeStatus": "NOT_SET",     "locked": false,     "lockReasons": [],     "lockMessage": null,     "settingsProfile": "default",     "activationCode": "**********************",     "creationDate": "2023-07-12T17:15:25+02:00",     "deletionDate": null,     "activationCodeExpiryDate": "2023-07-12T17:35:25+02:00",     "authenticationMethods": [         {             "type": "DEVICE_BIOMETRIC",             "usages": [                 "STRONG_CUSTOMER_AUTHENTICATION"             ],             "parameters": {                 "validityDuration": 60             }         },         {             "type": "HYBRID_PIN",             "usages": [                 "WALLET_MANAGEMENT",                 "STRONG_CUSTOMER_AUTHENTICATION"             ],             "parameters": {                 "maxAttempts": 3,                 "validityDuration": 60             }         },         {             "type": "NONE",             "usages": [                 "STRONG_CUSTOMER_AUTHENTICATION"             ],             "parameters": []         },         {             "type": "CLOUD_PIN",             "usages": [                 "WALLET_MANAGEMENT",                 "STRONG_CUSTOMER_AUTHENTICATION"             ],             "parameters": {                 "maxAttempts": 3,                 "validityDuration": 60             }         }     ],     "invalidActivationAttempts": null,     "userId": "3400118",     "scaWalletTag": "Iphone 13 mini", "clientId": "0998765" } ``` ::: Note that the `activationCode` attribute is only populated in the response, it cannot be retrieved later. Treezor also sends you a [`sca.wallet.create`](events#sca-wallet-create) webhook which contains the `activationCode` to use before the `activationCodeExpiryDate` to [provision the SCA Wallet](#provision-the-sca-wallet). ### Provision the SCA Wallet You must provision the SCA Wallet when using the SDK on the end user's device before the `activationCodeExpiryDate` using either: * The `connect(activationCode)` method from the [abstraction layer](sdk-abstraction) * The `WalletProvisioning#launch(activationCode)` [SDK method](sdk) The `activationCode` is provided in the [`sca.wallet.create`](events#sca-wallet-create) webhook (or in the response when created manually). You may push silently the code to the end user's device to enable a seamless provisioning. Once a given SCA Wallet has been provisioned into one app installation, it cannot be provisioned anymore and the `activationCode` is consumed. **Note – SCA Wallets must be provisioned before the expiration date** The `activationCodeExpiryDate` is available in the [`sca.wallet.create`](events#sca-wallet-create) webhook. If the provisioning fails due to an expired `activationCode`, you must [delete the SCA Wallet](#deletion) and create a new one. ### Set PIN or Biometry ::: tabs \== Mobile SDK The user is prompted to authenticate differently depending on the method: * **Pin** – Using a 6 to 8 digits PIN code. * **Biometric** – Using the local biometric authentication system of the device. * **None** – No input required, the operation is transparent. You may use indistinctly **Pin** or **Biometric**, depending on the capabilities of the device. Regardless of the method, basic checks are carried out to ensure the mobile device is legitimate and has not been altered or cloned. ::: ### Swap SCA Wallets Treezor offers a way for end users to enroll a new device for SCA while automatically deleting the previously enrolled device. It makes for a smoother experience than deleting the SCA Wallet first then creating a new one. Swapping devices is a sensitive action, so users must be strongly authenticated before proceeding. How it is done depends on whether the user owns the previous device. | Owns previous device | Swapping scenario | Grant type | | :---: | --- | --- | | | The user swaps with the SCA Proof from the previous device. | `delegated_end_user` | | | You secure the swap with 2-factor authentication (e.g., OTP, ID check). | `client_credentials` | When swapping devices: 1. The previous [SCA Wallet](introduction#sca-wallet-object) is deleted (i.e., status set to `DELETED`). 2. The new [SCA Wallet](introduction#sca-wallet-object) is created, and is activated and/or usable on the new device. 3. Treezor sends the relevant [webhooks](events) for deletion, creation, and swap. #### Parameters Below the key parameters for the swap endpoint. The necessary parameters may differ depending on the use case. | Attribute | Type | Description | | --- | --- | --- | | `removeScaWalletId` | string | The unique identifier of the SCA Wallet that is to be deleted. | | `swapReason` | string | The reason for swapping SCA Wallet. Can be: `LOST`, `STOLEN`, or `OTHER`. | | `authMethod` | array | The chosen methods for the 2-factor authentication. **Required if** no `sca` is provided. Must be two of the following (strings): `OTP SMS`, `OTP EMAIL`, `ID`, `OTHER`. | | `sca` | string | The valid proof that authenticated the swap. **Required if** no `authMethod` is provided. | | `scaWalletTag` | string | Custom value for the SCA Wallet. Can be used to name the device for which the new SCA Wallet is created. Max length: 256 characters. | #### Swap with SCA proof In this case, the user still owns the previous device and can provide an SCA proof with it. This method is end user-oriented, and therefore requires a `delegated_end_user` grant type. ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/core-connect/sca/scawallets/swap' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}` (with SCA proof): ::: code-group ```json [JSON] { "removeScaWalletId":"5710a5536cf04712b922f04exx9da5e2", "swapReason": "OTHER", "sca":"{scaProof}", "scaWalletTag":"Pixel 6" } ``` ::: Returns the newly created SCA Wallet object when successful. ::: code-group ```json [JSON] { "id": "992596bacded4c2fba18c716929df58e", "status": "CREATED", "subStatus": "CREATED_READY", "passcodeStatus": "NOT_SET", "locked": false, "lockReasons": [], "lockMessage": null, "settingsProfile": "default", "mobileWallet": null, "activationCode": "0xb95404c543d5549a2eb04b4b94e2e110", "creationDate": "2025-03-20T09:21:18+01:00", "deletionDate": null, "activationCodeExpiryDate": "2025-03-20T09:41:18+01:00", "authenticationMethods": [ { "type": "DEVICE_BIOMETRIC", "usages": [ "STRONG_CUSTOMER_AUTHENTICATION" ], "parameters": { "validityDuration": 60 } }, { "type": "NONE", "usages": [ "STRONG_CUSTOMER_AUTHENTICATION" ], "parameters": [] }, { "type": "HYBRID_PIN", "usages": [ "WALLET_MANAGEMENT", "STRONG_CUSTOMER_AUTHENTICATION" ], "parameters": { "maxAttempts": 3, "validityDuration": 60 } } ], "invalidActivationAttempts": null, "userId": "101706958", "scaWalletTag": "Pixel 6", "clientId": "12345", "activationDate": null, "lockDate": null, "unlockDate": null, "resetPinDate": null } ``` ::: Treezor also sends a [`sca.wallet.swap`](events#sca-wallet-swa) webhook, with the `activationCode`. You must [provision](#provision-the-sca-wallet) before its `activationCodeExpiryDate`. #### Swap with 2-factor authentication This method is not for your end users, but for your back end to swap wallets. Therefore, it requires a `client_credentials` grant type. ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/core-connect/sca/scawallets/swap' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}` (without SCA proof): ::: code-group ```json [JSON] { "swapReason":"LOST", "removeScaWalletId":"5710a5536cf04712b922f04exx9da5e2", "authMethod":["OTP SMS", "ID"], "scaWalletTag":"iPhone 13" } ``` ::: Returns the SCA Wallet object when successful. ::: code-group ```json [JSON] { "id": "498e5cd161214a128ccc65b376113b94", "status": "CREATED", "subStatus": "CREATED_READY", "passcodeStatus": "NOT_SET", "locked": false, "lockReasons": [], "lockMessage": null, "settingsProfile": "default", "mobileWallet": null, "activationCode": "0x9cd852b8cdcaa5c63e21797b6b5976c9", "creationDate": "2025-03-19T09:15:24+01:00", "deletionDate": null, "activationCodeExpiryDate": "2025-03-19T09:35:24+01:00", "authenticationMethods": [ { "type": "DEVICE_BIOMETRIC", "usages": [ "STRONG_CUSTOMER_AUTHENTICATION" ], "parameters": { "validityDuration": 60 } }, { "type": "NONE", "usages": [ "STRONG_CUSTOMER_AUTHENTICATION" ], "parameters": [] }, { "type": "HYBRID_PIN", "usages": [ "WALLET_MANAGEMENT", "STRONG_CUSTOMER_AUTHENTICATION" ], "parameters": { "maxAttempts": 3, "validityDuration": 60 } } ], "invalidActivationAttempts": null, "userId": "101699619", "scaWalletTag": "Pixel-5", "clientId": "12345", "activationDate": null, "lockDate": null, "unlockDate": null, "resetPinDate": null } ``` ::: Treezor also sends a [`sca.wallet.swap`](events#sca-wallet-swa) webhook, with the `activationCode`. You must [provision](#provision-the-sca-wallet) before its `activationCodeExpiryDate`. ## Web Native enrollment This section describes the main steps involved in enrolling users with the [Web Native](introduction#web-native) solution. By default, there is a limit of 5 active SCA Wallets per device when using the Web Native solution. If this limit is exceeded, an HTTP error is returned. Please note you have to [delete an SCA Wallet](sca-wallet-lifecycle#deletion) to enroll a new additional device. ### New User enrollment The device enrollment process pairs the User with their WebAuthn secured passkeys and passcode. This must happen when first creating the User in the Treezor API as the User can't use the Treezor API without an enrolled device. The following steps are required: 1. Generation of the passkeys using WebAuthn on the User's device 2. Creation of a passcode (min. length: 6 characters) and its encryption on the User's device 3. Forwarding of the public key and encrypted passcode to Treezor to finalize the device enrollment The following snippet triggers the passkeys creation process using Web Authentication API on the User's device. ::: code-group ```js [JavaScript] const publicKeyCredentialCreationOptions = { // Mandatory, must be set to "device-enrollment" challenge: convertToArrayBuffer('device-enrollment'), user: { // Mandatory, the User's login (this name will be displayed on WebAuthn key selection screen during the authentication process) name: 'foobar', // Optional, the User's full name (Firstname LASTNAME) displayName: '', // Mandatory, a random ID for each User's device, this is never displayed to the user and doesn't need to be stored anywhere id: convertToArrayBuffer(randomId), }, pubKeyCredParams: [{ alg: -7, type: "public-key" }], // Mandatory, as specified authenticatorSelection: { // Optional, can be set to "platform", "cross-platform" or omited to allow all authenticators types authenticatorAttachment: '', }, // Mandatory, timeout to complete the enrollment in milliseconds. We recommend keeping a fairly high value, as user might be unfamiliar with the process it could take them some time 600000, // Mandatory, this value must be set to "direct" "direct", { name: "Your website name", // FQDN, Must be the same at the current domain where your trigger WebAuthn id: 'www.example.com', }, }; // trigger Web Authn to register the current device const credential = await navigator.credentials.create({ publicKey: publicKeyCredentialCreationOptions, }); const response = credential.response; const rawId = arrayBufferToBase64Url(credential.rawId).toString(); const clientDataJSON = arrayBufferToBase64Url( credential.response.clientDataJSON ).toString(); const attestationObject = arrayBufferToBase64Url( (credential.response).attestationObject ).toString(); // this base 64 encoded string will be required at a later stage let encodedResponse = btoa( JSON.stringify({ response: { attestationObject, clientDataJSON, transports: ["string"] // ajout de cette propriété }, id: credential.id, rawId, type: "public-key", authenticatorAttachment:"platform" // platform or cross-platform }) ); // helper function function convertToArrayBuffer(input) { return Uint8Array.from(input, (c) => c.charCodeAt(0)); } // helper function function arrayBufferToBase64Url(arrayBuffer) { const bytes = new Uint8Array(arrayBuffer); let str = ""; for (const charCode of bytes) { str += String.fromCharCode(charCode); } const base64String = btoa(str); return base64String.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, ""); } ``` ::: **Note – Platform vs. Roaming authenticator (`authenticatorAttachment`)** * **Platform** – Attached with client device-specific transport (`platform` attachment). Usually not removable from the client device. * **Roaming** – Attached with cross-platform transports (`cross-platform` attachment). Removable and can “roam” between client devices. If the keys are created successfully, you can now ask the User to define a passcode (minimum length 6 characters) and [encrypt it](#passcode-encryption). ::: code-group ```js [JavaScript] const encryptedPassCode = encryptPasscode(passCode) // see Passcode encryption section below for how to encrypt the passcode ``` ::: At this point, you may use the User creation request ([`/v1/users`](/api-reference/api-endpoints.html#tag/Users/postUsers){target="\_self"}) with: * A `legal` [scope](/guide/api-basics/authentication.html#available-scopes), * The `passcode` and `webauthn` attributes to the usual payload. ::: code-group <<< @/guide/users/snippets/create\_user.bash \[CURL] ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] {7,8} { "userTypeId":1, "specifiedUSPerson":0, "firstname":"Alex", "lastname":"Oak", // [...] other User attributes hidden for brevity "passcode": "2kdqUTkb3MF[...]My+VIBZB6Xm/tECw+RE9L02/K3x97cvwFXKDTIEZzzwAv1OYbS0w==", "webauthn":"eyJyZXNwbrRG[...]9CejhlWWNxem9mUSIsInR5cGUiOiJwdWJsaWMta2V5In0=" } ``` ::: In this case, no webhook is sent upon creating the SCA Wallet. ### Existing User enrollment You may need to create an SCA Wallet for an existing user, either for migrating purposes or for additional devices. By default, 5 devices may be enrolled with Web Native. If you've reached the limit, you first need to [delete an SCA Wallet](sca-wallet-lifecycle#deletion) to enroll a new additional device. When a new device must be enrolled for an existing User, two options are available to you: * [Using an already enrolled device](#using-an-already-enrolled-device) to ensure that the request is legitimate * [Validating the User's identity using questions](#using-questions) that only they can answer (i.e., birthdate, email OTP, etc.) Both methods aim at ensuring that the User is who they claim to be before allowing the new device to be enrolled and generate SCA signatures. #### Parameters Below are the parameters to create an SCA Wallet manually. | Attribute | Type | Description | | --- | --- | --- | | `userId` | string | The unique identifier of the user the SCA Wallet is to be attached to. | | `scaWalletTag` | string | Custom value for the SCA Wallet. Can be used to name the device for which the new SCA Wallet is created. Max length: 256 characters. | | `authMethod` | array | The chosen method for the 2-factor authentication when signing the operation with the [Web Native](introduction#web-native) solution. Must be two of the following (strings): `OTP SMS`, `OTP EMAIL`, `ID`, `OTHER`. | | `sca` | string | For the [Web Native](introduction#web-native) solution, when creating the SCA Wallet as an end user (required if no `authMethod` is provided). | | `webauthn` | string | For the [Web Native](introduction#web-native) solution. The `PublicKeyCredential` after the WebAuthn Register, encoded in base64. | | `passcode` | string | Required if the `webauthn` field is provided and if there is no existing passcode for the user yet. Must be base64-encoded and encrypted. Initial passcode must at least 6 characters. | #### Using an already enrolled device If the User already has a device enrolled and accessible, you may use the [cross-device method](cross-device), requesting that the User approves the new device from their already enrolled device. The passkeys generation process should be carried out on the non-enrolled device (without carrying out last User creation step). Once the `encodedResponse` from the non-enrolled device available, you can finalize the new device enrollment using the following request. ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/core-connect/sca/scawallets' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}`. ::: code-group ```json [JSON] { "userId":"{userId}", "webauthn":"{encryptedPublicKey}", "sca":"{scaProofObtainedAtThePreviousStep}" } ``` ::: #### Using questions This method can typically be used when the User: * Has lost or cannot access their already enrolled device * Was created in the Treezor API before the enforcement of SCA regulations **Security – Verify the User's identity** In this situation, you are sole responsible for verifying the User's identity. In addition to authenticating the User using your usual authentication mechanism, you should ensure the User is able to provide personal information. Use as much relevant information as necessary, such as: * Their birthdate, current password, email address, mobile phone number * A one-time-password that you sent to their email address * A one-time-password that you sent to their mobile phone If enough conditions are met, you may contact Treezor endpoint and enroll the new device with the following request. ::: code-group <<< @/guide/strong-customer-authentication/snippets/create\_scaWallet.bash \[CURL] ::: Treezor expects the following `{payload}`: ::: code-group ```json [JSON] { "userId":"", "authMethod":["OTP SMS", "OTP EMAIL", "ID", "OTHER"], // List methods used to ensure the user's identity "passcode":"{theUsersCurrentPasscodeInEncryptedForm}", "webauthn":"{newDevicesPublicKey}" } ``` ::: Answers with a `200` HTTP Status Code and the following response. ::: code-group ```json [JSON] { "id": "3532d3d44dd999e8957e07cc7e860b2a", "status": "CREATED", "subStatus": "CREATED_READY", "passcodeStatus": "NOT_SET", "locked": false, "lockReasons": [], "lockMessage": null, "settingsProfile": "default", "mobileWallet": null,     "activationCode": "**********************",     "creationDate": "2023-07-12T17:15:25+02:00", "activationDate":null, "lockDate":null, "unlockDate":null, "resetPinDate":null, "deletionDate": null,     "activationCodeExpiryDate": "2023-07-12T17:35:25+02:00", "authenticationMethods": [ { "userHandle": "dGVzdEB3ZWJhdXRobg", "publicKeyCredentialId": "-7TzaTMjA3dk-1fLf3fEch_Rwqp3hxB0-yaxQXoqEeo", "aaguid": "adce0002-35bc-c60a-648b-0b25f1f05503", "uvInitialized": true, "attestationType": "self", "backupEligible": false, "counter": 0, "otherUI": null, "type": "public-key", "transports": [], "backupStatus": false, "credentialPublicKey": "pQECAyYgA[...]qWcprI5yqvTz5P7-frvEHIzI", // Truncated for readability "trustPath": { "type": "Webauthn\\TrustPath\\EmptyTrustPath" } } ], "invalidActivationAttempts": null, "userId": "3400118", "scaWalletTag": "Iphone 12 mini", "clientId": "0998765" } ``` ::: In this case, no webhook is sent upon creating the SCA Wallet. ### Passcode encryption Anytime Treezor requires the User's passcode to be provided, you must use Treezor public key to encrypt the passcode. **Security – Passcode privacy** The User's passcode must only be known to the User. It must never be stored on your infrastructure in any form. The following code snippet includes all the necessary code for client-side encryption of the passcode. ::: code-group ```js [JavaScript] (async () => { const str2ab = (str) => { const buf = new ArrayBuffer(str.length); const bufView = new Uint8Array(buf); for (let i = 0, strLen = str.length; i < strLen; i++) { bufView[i] = str.charCodeAt(i); } return buf; } const pemEncodedKey = `-----BEGIN PUBLIC KEY----- -----END PUBLIC KEY-----`; const importRsaKey = async (pem) => { // fetch the part of the PEM string between header and footer const pemHeader = "-----BEGIN PUBLIC KEY-----"; const pemFooter = "-----END PUBLIC KEY-----"; const pemContents = pem.substring( pemHeader.length, pem.length - pemFooter.length - 1, ); // base64 decode the string to get the binary data const binaryDerString = window.atob(pemContents); // convert from a binary string to an ArrayBuffer const binaryDer = str2ab(binaryDerString); return await window.crypto.subtle.importKey( "spki", binaryDer, { name: "RSA-OAEP", hash: "SHA-256", }, true, ["encrypt"], ); } let key = await importRsaKey(pemEncodedKey) const encryptMessage = async (publicKey) => { let message = 'nicolas' let enc = new TextEncoder(); let encoded = enc.encode(message) return window.crypto.subtle.encrypt( { name: "RSA-OAEP", }, publicKey, encoded, ); } let result = await encryptMessage(key) _arrayBufferToBase64 = ( buffer ) => { var binary = ''; var bytes = new Uint8Array( buffer ); var len = bytes.byteLength; for (var i = 0; i < len; i++) { binary += String.fromCharCode( bytes[ i ] ); } return window.btoa( binary ); } let enc = new TextDecoder(); // enc.encode(enc.decode(result)) console.log(_arrayBufferToBase64(result)) })() ``` ::: --- --- url: /guide/api-basics/environments.md description: >- Understand Treezor API environments. This guide details the Sandbox and Production environments, including their base URLs and how to configure your setup for development and testing. --- # Environments To help you integrate the Treezor Connect API with your project, Treezor provides two distinct environments. Each environment offers its own set of: * **API URLs** (different URLs must be used to access different environments) * **Webhooks URLs** (different webhook URLs must be used to receive events from different environments) * [**Credentials**](/guide/api-basics/authentication#credentials) (different credentials must be used to access different environments) * **Dataset** (data is sealed and doesn't leak one from one environment to the next) * **Features** (features available in one environment may not be present in the next) * [**Dashboards**](/guide/dashboard/introduction) **Best practice – Choose your environment wisely** Each environment has a specific use case, you should use the environment best suited for the current stage of your development. ## Sandbox This environment receives stable releases and **has features identical to the `production` environment**. It provides a safe place to test (with no consequences in the real world), develop and run functional tests with your CI tools before going to production: * **Use case**: Day-to-day software development. * **URL scheme**: `https://.sandbox.treezor.co` when encountering `{baseUrl}` in code examples, replace it with this URL. Please note that performance is **slower** than in [Production](#production) due to the cold-start effect of low traffic on Serverless architectures. If this presents a critical issue, please get in touch with your *Treezor Implementation Manager* to set up automatic warm-ups. **Alert – Some features and their webhooks are not available in Sandbox** * [SEPA transfers](/guide/transfers/introduction) can only be **emulated** (no real funds movements). * [Card payments](/guide/cards/introduction) can only be **emulated**. * [Card digitization](/guide/cards/introduction) not available with Apple Pay. [Webhooks](/guide/webhooks/introduction) that cannot be sent in Sandbox are available through the documentation, giving you a reference of what to expect in [Production](#production). ## Production **This environment is connected to the real world.** It's the environment your users experience and interact with, and on which you must comply with banking services regulations. * **Use case**: Production exclusively. **Do NOT use it for your CI or other testing processes.** * **URL scheme**: `https://.api.treezor.co` **Security – Keep your credentials safe** Don't share your credentials with anyone, especially for your Production environment. --- --- url: /guide/wallets/account-documents.md description: >- Generate official bank account documents for a given Wallet in PDF or JSON format, such as account details, account statements, and certificates (closure, domiciliation, and balance). --- # Account documents Account documents are official records that can be generated with Treezor for your Wallets. Treezor offers the flexibility to retrieve these documents either as ready-to-use PDFs (generated using configurable templates) or as raw JSON data, giving you full control over the document's final presentation and integration into your services. ## Available account documents ### Account details Account Details corresponds to the bank details of the Wallet, with all the relevant information such as the IBAN and the owner's identity. This is known as *RIB* in French. ### Account statements Account Statements synthesize all operations affecting the [Balance](/guide/overview/glossary#balance) of a [Wallet](/guide/wallets/introduction) for a given month. It also provides the Balance at the start and end of that month, the sum of debits, and the sum of credits. **Feature activation – Accounts Statements are disabled by default** You can request access to this feature by contacting Treezor. Please keep in mind this service only applies starting February, 2022. Banks are legally obligated to provide Accounts Statements for a duration of 5 years, although the requirements differ depending on the nature of the end user. Account statements must provide the following mandatory information about the **account holder** and the **mediator**: name, legal status, address, capital, VAT no., and Company Registration no. (RCS). Please note that in the context of parent-children relations, [Parent Users](/guide/users/parent-children) can access Accounts Statement of their [Children Users](/guide/users/parent-children). **Reading – Your legal obligations explained** Learn more about the requirements regarding [statement of account and statement of fees](https://treezor.zendesk.com/hc/en-us/articles/360019159279-Statement-of-account-and-statement-of-fees). ### Account certificates For reporting or declarative purposes, your Wallets or the ones of your end users might require some official documents. The Treezor API now natively provides 3 documents for financial auditors and tax services: | Certificate | Description | | --- | --- | | **Balance certificate** | Attestation proving the current balance on your account. | | **Closure certificate** | Attestation proving the account was closed. | | **Domiciliation certificate** | Attestation proving the account registered address. | ## Retrieve raw JSON data The process for generating a document from raw data is as follows: 1. Retrieve the required data using the dedicated endpoint. 2. Optionally decrypt the data (for statements, if encrypted). 3. Generate the document in your preferred format using the collected data. **Note – when the [Encryption](https://treezor.zendesk.com/hc/en-us/articles/12862766194844-Encryption) feature is active for Statements** * The operation `name` field returns an empty string. * Encrypted fields are returned among the header parameters with the following structure: `operations.metadata.`. ### Query parameters | Attribute | Type | Description | | --- | --- | --- | | `walletId` | string | The unique identifier of the Wallet. | | `month` | integer | **Statements only**. The month of the statement (2 digits leading with `0`) | | `year` | integer | **Statements only**. The year of the statement (4 digits, e.g., `2025`) | **Caution – You can generate statements from Feb, 2022 only** Treezor can't generate statements before the service was made available. Therefore, the earliest statement you can generate is for 02/2022. ### Request examples ::: code-group ```bash [Account details] curl -X GET '{baseUrl}/core-connect/account-details/{walletId}/raw' \ --header 'Authorization: Bearer {accessToken}' ``` ```bash [Statement] curl -X GET '{baseUrl}/core-connect/statements/{walletId}/raw?month={month}&year={year}' \ --header 'Authorization: Bearer {accessToken}' ``` ```bash [Balance cert.] curl -X GET '{baseUrl}/core-connect/certificates/walletBalance/{walletId}/raw' \ --header 'Authorization: Bearer {accessToken}' ``` ```bash [Closure cert.] curl -X GET '{baseUrl}/core-connect/certificates/walletClosure/{walletId}/raw' \ --header 'Authorization: Bearer {accessToken}' ``` ```bash [Domiciliation cert.] curl -X GET '{baseUrl}/core-connect/certificates/walletDomiciliation/{walletId}/raw' \ --header 'Authorization: Bearer {accessToken}' ``` ::: Returns the JSON version of the document. ::: code-group ```json [Account details] { "bic": "TRZOFR21XXX", "iban": "FR7616798000010000XXXXXXXXX", "title": "", "firstname": "Alex", "lastname": "Willow", "postcode": "75000", "city": "Paris", "address1": "15 Hazel road", "address2": "", "countryName": "Allemagne", "treezorAddress": { "name": "Treezor SAS", "address1": "33, av de Wagram", "address2": null, "postcode": "75017", "city": "Paris" } } ``` ```json [Statement] { "firstBalance": { "amount": "50.10", "date": "2025-02-01" }, "lastBalance": { "amount": "-322.25", "date": "2025-02-28" }, "operations": [ { "date": "2025-02-08", "type": "Prlv SEPA", "name": "Hertha Abbott Ipsa quod dolores modi quia et. RUM: 864a91c7-e7f7-3a3f-a688-2a6271bdd9af", "direction": "DEBIT", "amount": "56.90", "metadata": { "payoutId": "649715658", "payoutTag": "Eos voluptatum impedit quasi rem adipisci.", "label": "Ipsa quod dolores modi quia et.", "beneficiaryId": "1181276320", "beneficiaryName": "Hertha Abbott", "endToEndId": null, "reasonCode": null, "reasonDescription": null, "uniqueMandateReference": "864a91c7-e7f7-3a3f-a688-2a6271bdd9af" } }, { "date": "2025-02-10", "type": "Vir SEPA", "name": "Miss Katherine Swift ", "direction": "DEBIT", "amount": "15.11", "metadata": { "payoutId": "331556016", "payoutTag": "Facere nihil odit error et.", "label": "", "beneficiaryId": "415584822", "beneficiaryName": "Miss Katherine Swift", "endToEndId": null, "reasonCode": null, "reasonDescription": null, "uniqueMandateReference": "" } }, { "date": "2025-02-21", "type": "Carte", "name": "Austyn Nolan (EUR 36.91) Card ****9835", "direction": "DEBIT", "amount": "36.91", "metadata": { "maskedPan": "****9835", "merchantName": "Austyn Nolan", "localAmount": { "amount": 3691, "currency": "978" }, "paymentId": "1173130796" } }, ], "totalDebit": 586.83, "totalCredit": 214.48, "user": { "title": "", "firstname": "", "lastname": "", "address1": "99 rue de test", "address2": "", "address3": null, "postcode": "75001", "city": "Paris", "country": "FR", "userTypeId": 2, "state": "", "legalName": "Compagnie", "legalRegistrationNumber": "42877171100028" }, "wallet": { "iban": "FR7616798000010002753144040", "bic": "TRZOFR21XXX", "eventName": "Name of the Wallet", "walletTag": "" }, "totalAmountFees": 0, "totalAmountCreditNote": 0 } ``` ```json [Balance cert.] { "user": { "userTypeId": 1, "title": "MX", "firstname": "Alex", "lastname": "Oak", "birthday": "1989-09-03", "placeOfBirth": "Paris", "birthCountry": "France", "legalName": "Tree Company", "legalRegistrationNumber": "34567", "legalRegistrationDate": "2021-09-23" }, "wallet": { "walletStatus": "VALIDATED", "bic": "TRZOFR21XXX", "iban": "FR7616798000010000101039007", "createdDate": "2021-09-23 16:33:50" }, "balance": { "currentBalance": 638.98, "calculationDate": "2021-09-23 16:33:50" }, "certificateDate": "2025-06-02T13:07:58+00:00" } ``` ```json [Closure cert.] { "user": { "userTypeId": 1, "title": "MX", "firstname": "Alex", "lastname": "Oak", "birthday": "1989-09-03", "placeOfBirth": "Paris", "birthCountry": "France", "legalName": "Tree Company", "legalRegistrationNumber": "34567", "legalRegistrationDate": "2021-09-23" }, "wallet": { "walletStatus": "CANCELED", "bic": "TRZOFR21XXX", "iban": "FR7630006000011234567890189", "modifiedDate": "2025-09-23 15:31:53" }, "modifiedDate": "2025-09-23T15:31:53.777Z", "certificateDate": "2025-06-02T13:07:58+00:00" } ``` ```json [Domiciliation cert.] { "user": { "userTypeId": 1, "title": "MX", "firstname": "Alex", "lastname": "Oak", "birthday": "1989-09-03", "placeOfBirth": "Paris", "birthCountry": "France", "legalName": "Tree Company", "legalRegistrationNumber": "34567", "legalRegistrationDate": "2021-09-23" }, "wallet": { "walletStatus": "VALIDATED", "bic": "TRZOFR21XXX", "iban": "FR7616798000010000101039007", "createdDate": "2021-09-23 16:33:50" }, "certificateDate": "2025-06-02T13:07:58+00:00" } ``` ::: ## Retrieve PDFs ### Query parameters | Attribute | Type | Description | | --- | --- | --- | | `walletId` | string | The unique identifier of the Wallet. | | `month` | integer | **Statements only**. The month of the statement (2 digits leading with `0`) | | `year` | integer | **Statements only**. The year of the statement (4 digits, e.g., `2025`) | **Caution – You can generate statements from Feb, 2022 only** Treezor can't generate statements before the service was made available. Therefore, the earliest statement you can generate is for 02/2022. ### Request example ::: code-group ```bash [Account details] curl -X GET '{baseUrl}/core-connect/account-details/{walletId}/computed' \ --header 'Authorization: Bearer {accessToken}' ``` ```bash [Statement] curl -X GET '{baseUrl}/core-connect/statements/{walletId}/computed?year={year}&month={month}' \ --header 'Authorization: Bearer {accessToken}' ``` ```bash [Balance cert.] curl -X GET '{baseUrl}/core-connect/certificates/walletBalance/{walletId}/computed' \ --header 'Authorization: Bearer {accessToken}' ``` ```bash [Closure cert.] curl -X GET '{baseUrl}/core-connect/certificates/walletClosure/{walletId}/computed' \ --header 'Authorization: Bearer {accessToken}' ``` ```bash [Domiciliation cert.] curl -X GET '{baseUrl}/core-connect/certificates/walletDomiciliation/{walletId}/computed' \ --header 'Authorization: Bearer {accessToken}' ``` ::: Returns an object containing a URL to download the PDF. ::: code-group ```json [JSON] { "link": "https://xxx.s3.eu-west-3.amazonaws.com/tmp/xxx.pdf", "expireIn": 300 } ``` ::: The PDF must be **downloaded within 5 minutes**, after which it expires. ## Customize PDFs with Templates ### Produce the template The templating engine that should be used for the template is [Twig with some limitations](/guide/api-basics/templates). Providing a new template will not affect previously generated documents. ::: code-group ```html [HTML – Account statement example] Statement
agent-logo RELEVE D'OPERATIONS

Compte - en euros

{% if user.userTypeId and user.legalName and user.legalRegistrationNumber and user.userTypeId != 1 %} {% else %} {% endif %}
{{ user.legalName }} {{ user.legalRegistrationNumber }}{{ user.firstname }} {{ user.lastname }}
{{ user.address1 }}
{{ user.postcode }} {{ user.city }} {% if user.state %} {{ user.state }} {% endif %} {% if user.country %} {{ user.country }} {% endif %}

Relevé d'opérations

du {{ firstBalance.date|date("d/m/Y") }} au {{ lastBalance.date|date("d/m/Y") }}

Votre précédent solde au {{ firstBalance.date|date("d/m/Y") }}

{{ firstBalance.amount }} €

{% for operation in operations %} {% endfor %}
Date Type Opération Débit Crédit
{{ operation.date|date("d/m/Y") }} {% if operation.type == 'Carte' %} Card Transaction {% elseif operation.type == 'Prlv SEPA' %} Bank Direct Debit {% elseif operation.type == 'Vir SEPA' %} Bank Transfer {% elseif operation.type == 'Top up carte' %} Card Topup {% elseif operation.type == 'Chèque' %} Check {% else %} {{ operation.type }} {% endif %} {{ operation.name }} {% if operation.direction == 'DEBIT' %} {{ operation.amount }} {% endif %} {% if operation.direction == 'CREDIT' %} {{ operation.amount }} {% endif %}
Total des mouvements {{ totalDebit }} {{ totalCredit }}

Total des frais de gestion sur la période : {{ totalAmountFees }} €

Total des remboursements des frais de gestion sur la période : {{ totalAmountCreditNote }} €

``` ::: You can check the list of [available variables for account statements](#variables-for-account-statements). **Notes for statements** * The `operation.type` variable is always provided in French. * The `totalAmountFees` must be present * The `totalAmountCreditNote` is optional ### Upload the template Use the following request to upload your [base-64 encoded template](/guide/api-basics/data-format#files). ::: code-group ```bash [CURL] curl -X PUT '{baseUrl}/customization/templates/{templateName}/template' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{ "template": "{base64encodedTemplate}" }' ``` ::: Returns a `201`HTTP Status Code, without any content. If something goes wrong, you can also get an [error](/guide/api-basics/templates#errors). You may also customize the template using the [Dashboard](/guide/dashboard/introduction). ### Test the template You can easily test your document templates by generating the PDFs, except for the statements, which requires you to simulate operations. Endpoint: [`/simulation/operations`](/api-reference/api-endpoints.html#tag/Operations/simulateOperations){target="\_self"} ::: code-group <<< @/guide/wallets/snippets/simu\_operations.bash \[CURL] ::: Here is a `{payload}` example: ::: code-group ```json [JSON] { "walletId": "{walletId}", "date": "2023-10", "operations": { "payin": 5, "payinrefund": 2, "payout": 6, "payoutrefund": 1, "transfer": 3, "cardtransaction": 7, "transferfees":2, "transfercreditnote":1 } } ``` ::: Returns a `201` HTTP Status Code. You can then follow with a [normal request of Account Statement](#request-an-account-statement) to download it. **Tips** * Use the same value for `payin` and `payinrefund` to include payin refunds in your test. * Use a fairly high `payin` value, as types (cheque, sctr) are generated randomly. * An Account Statement generated for a given month can't be overridden nor regenerated. ### Variables for account statements Below is a list of available variables for Account Statement templates. | Variable | Related to | Additional information (if any) | | --- | --- | --- | | `wallet.iban` | [Wallet](/guide/wallets/introduction) | | | `wallet.bic` | [Wallet](/guide/wallets/introduction) | | | `wallet.eventName` | [Wallet](/guide/wallets/introduction) | | | `wallet.walletTag` | [Wallet](/guide/wallets/introduction) | | | `user.title` | [User](/guide/users/introduction) | | | `user.firstname` | [User](/guide/users/introduction) | | | `user.lastname` | [User](/guide/users/introduction) | | | `user.address1` | [User](/guide/users/introduction) | | | `user.address2` | [User](/guide/users/introduction) | | | `user.address3` | [User](/guide/users/introduction) | | | `user.postcode` | [User](/guide/users/introduction) | | | `user.city` | [User](/guide/users/introduction) | | | `user.country` | [User](/guide/users/introduction) | | | `operations[*].date` |  | | | `operations[*].type` | | Always provided in French, but can be [customized](#customize-pdfs-with-templates). | | `operations[*].name` |  | | | `operations[*].direction` |  | | | `operations[*].amount` | | | | `firstBalance.currency` | [Balances](/guide/wallets/balances) | | | `firstBalance.date` | [Balances](/guide/wallets/balances) | The date of the first Balance of the month. | | `firstBalance.amount` | [Balances](/guide/wallets/balances) | The amount of the first Balance of the month. | | `lastBalance.currency` | [Balances](/guide/wallets/balances) | | | `lastBalance.date` | [Balances](/guide/wallets/balances) | The date of the last Balance of the month. | | `lastBalance.amount` | [Balances](/guide/wallets/balances) | The amount of the last Balance of the month. | | `totalDebit` | [Balances](/guide/wallets/balances) | The cumulated amount of debit Operations. | | `totalCredit` | [Balances](/guide/wallets/balances) | The cumulated amount of credit Operations. | | `totalOperation` | Totals | The sum of all Operations | | `totalAmountFees` | Totals | The sum of [Transfers of type **Fees**](/guide/transfers/wallet-to-wallet#types-transfertypeid) | | `totalAmountCreditNote` | Totals | The sum of [Transfers of type **Credit note**](/guide/transfers/wallet-to-wallet#types-transfertypeid) | ## Endpoints | Endpoint |[Scope](/guide/api-basics/authentication#available-scopes) | | --- | --- | | [`/core‑connect/account‑details/{walletId}/computed`](/api-reference/api-endpoints.html#tag/Account%20Documents/getComputedWalletAccountDetail){target="\_self"} Request a PDF account details for a given Wallet | `read_only` | | [`/core‑connect/account‑details/{walletId}/raw`](/api-reference/api-endpoints.html#tag/Account%20Documents/getRawWalletAccountDetail){target="\_self"} Retrieve a JSON account details for a given Wallet | `read_only` | | [`/core-connect/statements/{walletId}/computed`](/api-reference/api-endpoints.html#tag/Account%20Documents/getPdfAccountStatement){target="\_self"} Request a PDF statement for a given Wallet | `read_only` | | [`/core-connect/statements/{walletId}/raw`](/api-reference/api-endpoints.html#tag/Account%20Documents/getRawStatement){target="\_self"} Retrieve statement information for a given Wallet | `read_only` | | [`/core-connect/certificates/walletBalance/{walletId}/computed`](/api-reference/api-endpoints.html#tag/Account%20Documents/getWalletBalanceComputed){target="\_self"} Request a PDF Balance Certificate for a given Wallet | `read_write` | | [`/core-connect/certificates/walletBalance/{walletId}/raw`](/api-reference/api-endpoints.html#tag/Account%20Documents/getWalletBalanceRaw){target="\_self"} Request a JSON Balance Certificate for a given Wallet | `read_write` | | [`/core-connect/certificates/walletClosure/{walletId}/computed`](/api-reference/api-endpoints.html#tag/Account%20Documents/getWalletClosureComputed){target="\_self"} Request a PDF Closure Certificate for a given Wallet | `read_write` | | [`/core-connect/certificates/walletClosure/{walletId}/raw`](/api-reference/api-endpoints.html#tag/Account%20Documents/getWalletClosureRaw){target="\_self"} Request a JSON Closure Certificate for a given Wallet | `read_write` | | [`/core-connect/certificates/walletDomiciliation/{walletId}/computed`](/api-reference/api-endpoints.html#tag/Account%20Documents/getWalletDomiciliationComputed){target="\_self"} Request a PDF Domiciliation Certificate for a given Wallet | `read_write` | | [`/core-connect/certificates/walletDomiciliation/{walletId}/raw`](/api-reference/api-endpoints.html#tag/Account%20Documents/getPdfAccountStatement){target="\_self"} Request a JSON Domiciliation Certificate for a given Wallet | `read_write` | --- --- url: /guide/overview/getting-started.md description: >- Welcome to Treezor Documentation, which provides the tools and knowledge for you to implement Treezor's solutions. Find out more about Treezor, the payment flows and services, as well as your documentation journey before diving into the API. --- # Getting started with Treezor Treezor documentation aims to provide all the tools and knowledge you need to implement Treezor’s solutions. ## What is Treezor? Treezor is a Banking-as-a-Service solution provider. It relies on a REST API to offer embedded finance services, allowing you to accelerate your banking projects while remaining compliant and secure in a highly regulated banking sector. ### Treezor services Once you’re all set up, you’ll be able to consume the API to create and verify users, and benefit from the following banking services. | | Service | Description | | - |--- |--- | | | **Payment accounts** | Rely on Treezor [Wallets](/guide/wallets/introduction) to create accounts adapted to your needs. Included features: [Virtual IBAN](/guide/wallets/iban#virtual-iban)[Local IBAN](/guide/wallets/iban#local-iban)[Account Statements](/guide/wallets/account-documents) | | | **Card issuing** | Design and print physical and virtual Cards. Included features: [Rules engine](/guide/cards/transactions-rules-engine)[X-Pay](/guide/cards/x-pay-google-apple) | | | **Transfers** | Move funds in and out of your [Wallets](/guide/wallets/introduction) using international networks. Included features: [SEPA Credit Transfers](/guide/transfers/credit-transfer)[SEPA Inst. Payments](/guide/transfers/credit-transfer-inst)[SEPA Direct Debit](/guide/transfers/direct-debit)[Wallet-to-Wallet](/guide/transfers/wallet-to-wallet#wallet-to-wallet-transfers) | | | **Card acquiring** | Credit [Wallets](/guide/wallets/introduction) using cards as a means of payment. | | | **Check cashing** | Credit Wallets using [Checks](/guide/cheques/introduction). | ### Treezor flows The use of Treezor services and features can be illustrated with the following money flows: ## Your documentation journey Some prerequisites are necessary before you can fully take advantage of Treezor Documentation. If it’s not the case yet, contact [Treezor commercial team](https://www.treezor.com/contact-us/contact-sales/) to get started on your project with us! Once you’ve got your [Sandbox environment and credentials](#environments-and-credentials), and your onboarding is moving along with Treezor teams, you can start testing your implementation. While it may vary depending on your project, you’re usually going through the following steps before exploring our banking services: * [Authentication](/guide/api-basics/authentication) * [Webhook subscription](/guide/webhooks/introduction) * [User creation](/guide/users/introduction) and [verification (KYC)](/guide/user-verification/introduction) * [Wallet creation](/guide/wallets/introduction) **Caution – Regulatory and compliance steps are required** Banking is a highly regulated environment. Treezor will guide you through the steps you must complete for your project to remain compliant. ### LLM-optimized documentation The Treezor documentation provides the necessary plain text content for easy ingestion by **large language models (LLMs)** such as ChatGPT, Gemini, or Claude. * **[llm.txt](/llms.txt)** – Structure of the documentation, summarizing all sections. * **[llm-full.txt](/llms-full.txt)** – Unordered compilation of the whole documentation into one file. * **Copy as Markdown** – Button available on each page for you to copy the content in Markdown. * **Download as Markdown** – Button available on each page for you to download the .md file. These allow you to leverage LLMs for tasks like generating code examples, writing integration scripts, or asking questions about the API without needing to navigate the full site. While the [API Reference](/api-reference/api-endpoints) can't be included in the documentation compilation, you can download the openAPI file to facilitate your integration. ## Treezor API As a REST API, Treezor accepts and returns JSON payloads, along with the associated `application/json` content type header. You can read more in the [Data formats](/guide/api-basics/data-format) article. **Information – Documentation focuses on the most recent version** You may find mentions to Treezor BaaS (legacy) and Treezor Connect (new services). Please bear in mind that the documentation focuses on the latest behavior of the Treezor Connect API. ### Security Every call to the API must use HTTP**S** and requires the presence of a [JSON Web Token](/guide/api-basics/authentication) in the `Authorization` header. To obtain this token, you need [to authenticate](/guide/api-basics/authentication) against our OAuth 2.0 provider or with an alternative provider. Treezor also relies on: * The [mutual TLS](/guide/api-basics/mutual-tls) protocol for the latest services such as [PCI DSS](/guide/cards/pci-dss). * The optional [encryption](https://treezor.zendesk.com/hc/en-us/articles/12862766194844-Encryption) layer for sensitive data. ### Environments and credentials Two environments are available: `sandbox` and `production`. Each have sealed data, distinct credentials, features, and URLs. You can read more details in the summaries below, or go to the dedicated [Environments](/guide/api-basics/environments) article. #### Sandbox Upon subscription and to discover the API, your *Treezor Implementation Manager* will send you your [**`sandbox`**](/guide/api-basics/environments#sandbox) credentials. If you have received them and are in the development phase of your project, [here is a guide to make your first requests](/guide/overview/tinker). #### Production Once you reach the *alpha production* stage of your development, you will need [**`production`**](/guide/api-basics/environments#production) credentials. As these credentials are very sensitive information, Treezor will provide them in an encrypted format using the Pretty Good Privacy (PGP) encryption program. **Reading – Implementation path** You can read about the different stages of implementation in the [Validating your implementation](https://treezor.zendesk.com/hc/en-us/sections/360002673359-Your-Implementation-Path) articles of the Support Center. ## Getting help **Information – Treezor API Status available at all times** A real-time status of the Treezor API services is available at [treezor.statuspage.io](https://treezor.statuspage.io/). Answers to your questions may be available in the following articles: * [HTTP Status Codes](/guide/api-basics/response-codes) returned by the API * Card transactions [Status](/guide/cards/transactions#statuses-paymentstatus), [Authorization Notes](/guide/cards/authorization-notes), [Codes](/guide/cards/authorization-notes#authorization-response-codes), and [Life cycle](/guide/cards/transactions-lifecycle) * KYC [Status, Levels, and life cycle](/guide/user-verification/introduction) * SEPA [Codes](/guide/transfers/error-codes) * Checks [Codes](/guide/cheques/introduction#codes-codestatus), [Errors](/guide/cheques/introduction#api-errors), and [Life cycle](/guide/cheques/cashing#life-cycle) ### Contacting Treezor Support When [opening a ticket](https://treezor.zendesk.com/hc/en-us/articles/4403978479634-How-to-create-a-Zendesk-ticket), make sure to provide: * **The request** – The API request made, including the URI, the HTTP verb, and the payload. * **The response** – The response returned by the API, including the HTTP Status Code and the payload. * **The expected behavior** – The description of what should have occurred. * **The actual behavior** – The description of what actually occurred. * **The date and time** – The approximate date and time at which the request was sent (for us to check the logs). The [more detailed](https://stackoverflow.com/help/how-to-ask) your message is, the better and quicker Treezor can assist! **Security – Never share your credentials with Treezor** You must redact the token or credentials when sharing an issue. If somebody asks for your credentials, report them immediately by [opening a ticket](https://treezor.zendesk.com/hc/en-us/articles/4403978479634-How-to-create-a-Zendesk-ticket). --- --- url: /use-cases/gift-cards/api-guide.md description: >- Issue and manage Gift Cards programmatically via the Treezor API. This API implementation guide takes you step-by-step through creating users, issuing cards, setting restrictions, activating, and handling card lifecycle with detailed API calls and examples. --- # API guide The API guide will take you through the following steps to successfully create users and gift cards: 1. [Create a physical user](#create-a-physical-user) – Define your users with the required information. 2. [Create a card](#create-a-card) – Create cards for your users, with their limits and restriction groups. 3. [Activate the card](#activate-a-card) – Activate the card for the user to be able use it. 4. [Manage cards](#manage-cards) – Update your card information as needed. 5. [Handle the end of life cycle](#handle-the-end-of-the-gift-card-life-cycle) – Make sure your destroy the card and delete the user once the funds are used. ## Create a physical user Physical users are your end users, that is to say, individuals who will use the gift cards. They are identified with the `userTypeId` value `1`. You must create users with the declarative data Treezor Compliance indicated in your KYC Form. In this use case, it corresponds to the following parameters. | Attribute | Type | Description | |--- |--- |--- | | `firstname` | string | The end user's first name. | | `lastname` | string | The end user's last name. In Sandbox, you might need to simulate the `VALIDATED` status with the dedicated suffix. | | `birthday` | string | The end user's birth date. Format: `YYYY-MM-DD` | | `placeOfBirth` | string | The end user's place of birth. | | `birthCountry` | string | The end user's birth country (format: ISO 3166-1 alpha-2) | | `nationality` | string | The end user's nationality (format: ISO 3166-1 alpha-2) | | `specifiedUSPerson` | integer | Needs to be set to `1` if the user is a citizen or a resident of the United States. In such cases a US tax residence (`taxResidence`) must be declared as well. | | `email` | string | The end user's email, which must be valid and can't exceed 200 characters. | | `mobile` | string | The end user's mobile phone number, in international E.164 format. | | `address{1-3}` | string | The end user's postal address. The max value for each address line is 56 characters, although due to mail carrier limitations, only the first 36 are printed on envelopes used to deliver Cards. | | `postcode` | string | The end user's address postcode. | | `city` | string | The end user's address city. | | `country` | string | The end user's address country (format ISO 3166-1 alpha-2) | **Information – Declarative data to submit depends on the use case** In our use case, users are not KYC-validated, so only the fields indicated in the KYC Form provided by Treezor are to be filled in. You need to use the following request: ::: code-group <<< @/guide/users/snippets/create\_user.bash\[CURL] ::: Here is a `{payload}` example: ::: code-group ```json [JSON] { "userTypeId": 1, "specifiedUSPerson": 0, "title": "MX", "firstname": "Alex", "lastname": "Oak.userStatusValidated", // Suffix to emulate VALIDATED status "birthday": "1982-05-31", "placeOfBirth": "Edgewood", "birthCountry": "FR", "nationality": "FR", "email": "alex.oak@example.com", "address1": "33 rosewood road", "postcode": "75017", "city": "Paris", "country": "FR", "phone": "+3311111111", } ``` ::: It returns a User object if successful: ::: code-group ```json{4} [JSON] { "users": [ { "userId": 8327278, "userTypeId": 1, "userStatus": "VALIDATED", "userTag": "", "parentUserId": 0, "parentType": "", "controllingPersonType": 0, "employeeType": 0, "specifiedUSPerson": 0, "title": "", "firstname": "Alex", "lastname": "Oak", "middleNames": "", "birthday": "1982-05-31", "email": "alex.oak@example.com", "address1": "33 rosewood road", "address2": "", "postcode": "75017", "city": "Paris", "state": "", "country": "FR", "countryName": "France", "distributionCountry": null, "phone": "+3311111111", "mobile": "", "nationality": "FR", "nationalityOther": "", "placeOfBirth": "Edgewood", "birthCountry": "FR", "occupation": "", "incomeRange": "", "legalName": "", "legalNameEmbossed": "", "legalRegistrationNumber": "", "legalTvaNumber": "", "legalRegistrationDate": "0000-00-00", "legalForm": "", "legalShareCapital": 0, "entityType": null, "legalSector": "", "legalAnnualTurnOver": "", "legalNetIncomeRange": "", "legalNumberOfEmployeeRange": "", "effectiveBeneficiary": 0, "kycLevel": 1, "kycReview": 0, "kycReviewComment": "", "isFreezed": 0, "isFrozen": null, "language": "", "optInMailing": null, "sepaCreditorIdentifier": "", "taxNumber": "", "taxResidence": "", "position": "", "personalAssets": "", "createdDate": "2023-10-23 12:28:00", "modifiedDate": "0000-00-00 00:00:00", "walletCount": 0, "payinCount": 0, "totalRows": "1", "activityOutsideEu": null, "economicSanctions": null, "residentCountriesSanctions": null, "involvedSanctions": null, "entitySanctionsQuestionnaire": null, "address3": null, "timezone": null, "occupationType": "", "isOnStockExchange": 0, "secondaryAddress1": "", "secondaryAddress2": "", "secondaryAddress3": "", "secondaryPostcode": "", "secondaryCity": "", "secondaryState": "", "secondaryCountry": "", "clientId": "945198", "sanctionsQuestionnaireDate": null, "codeStatus": "110009", "informationStatus": "", "legalSectorType": "", "sourceOfFunds": "", "occupationCategory": null, "personalAssetsRange": null, "monthlyIncomeRange": null } ] } ``` ::: You’ll need the `userId` parameter value for the next step. ## Create a card The card is connected to both your company Master Wallet and the user it’s going to be allocated to. You need the corresponding `userId` and `walletId` in the next steps. Creating a card in this use case is divided into the following steps: 1. **[Create the card restriction groups](#create-your-restriction-groups)** 2. **[Create a virtual card](#create-a-virtual-card)** 3. **[Convert a virtual card into a physicial one](#convert-a-virtual-card-into-a-physical-one)** ### Create your restriction groups To select the relevant options for the cards that you’ll be creating in the next step, you may create the restriction groups that apply to your use case. **Information – Restrictions are not testable in Sandbox** When emulating card transactions to test your integration, restrictions won’t apply. #### Merchant Id restrictions Defining the Merchant ID (MID) restrictions allows you to easily define if the card should be usable in some specific shops. Here are the attributes you need to create a MID restriction group. To create MID restrictions, use the following request: ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/v1/merchantIdRestrictionGroups' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}` to create a single-merchant whitelist restriction: ::: code-group ```json [JSON] { "name": "Single-merchant example", "merchants": [ "128787" ], "status": "VALIDATED" } ``` ::: It returns a Merchant ID Restriction Group object if successful: ::: code-group ```json [JSON] {4} { "merchantIdRestrictionGroups": [ { "id": 95447, "name": "Single-merchant example", "isWhitelist": true, "merchants": [ "128787" ], "status": "VALIDATED", "startDate": "2023-10-23 12:19:49", "createdDate": "2023-10-23 12:19:49", "modifiedDate": "" } ] } ``` ::: Later on, you'll need the `id` to take into account the restriction during the card creation. #### Merchant category restrictions Defining specific merchant category codes (MCC) restrictions allows you to easily define if the card should be used in only certain categories of merchants (or, to blacklist some categories of merchants). Here are the attributes you need to create a MCC restriction group. To create MCC restrictions, use the following request: ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/v1/mccRestrictionGroups' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}` to blacklist specific merchant categories: ::: code-group ```json [JSON] { "name": "MCC blacklist", "mcc": [ 5813, 5993 ], "status": "VALIDATED", "isWhitelist": false } ``` ::: It returns the MCC Restriction Group object if successful: ::: code-group ```json [JSON] {4} { "mccRestrictionGroups": [ { "id": 45599, "name": "MCC blacklist", "isWhitelist": false, "mcc": [ 5813, 5993 ], "status": "VALIDATED", "startDate": "2023-10-31 08:58:50", "createdDate": "2023-10-31 08:58:50", "modifiedDate": "" } ] } ``` ::: Later on, you'll need the `id` to take into account the restriction during the card creation. #### Country restrictions Defining specific countries allows you to easily define if the card should be used in certain countries only (or, to blacklist some countries). Here are the attributes you need to create a Country restriction group. To create country restrictions, use the following request: ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/v1/countryRestrictionGroups' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload} ``` ::: Here is an example of `{payload}` to create a single-country whitelist restriction: ::: code-group ```json [JSON] { "name": "Spanish only cards", "countries": [ "724" ], "status": "VALIDATED" } ``` ::: It returns the following Country Restriction Group object if successful: ::: code-group ```json [JSON] {4} { "countryRestrictionGroups": [ { "id": 165327, "name": "Spanish only cards", "isWhitelist": true, "countries": [ "724" ], "status": "VALIDATED", "startDate": "2022-02-18 14:58:54", "createdDate": "2023-10-23 12:17:26", "modifiedDate": "" } ] } ``` ::: Later on, you'll need the `id` to take into account the restriction during the card creation. ### Create a virtual card To create a virtual card and attach to your user, you’ll need: * The `walletId` of the Master Wallet * The `userId` of the end user who will use the card * The Id of the restriction groups you want to apply to your card #### Main attributes Here are the attributes you need to create a virtual card: | Attribute | Type | Description | | --- | --- | --- | | `userId` | integer | The unique identifier of the cardholder. | | `walletId` | integer | The unique identifier of your company Master Wallet. | | `permsGroup` | string | A code indicating whether the card main options (contactless, online payments, withdrawals, and international payments) are activated or not. In this use case, it may be one of the following values: `TRZ-CU-011` (contactless and online payments, recommended)`TRZ-CU-003` (online payments)`TRZ-CU-009` (contactless payments)`TRZ-CU-001` (no option activated)| | `cardPrint` | string | It corresponds to your Card Program and the options provided with them. This information is shared with you by Treezor. | | `merchantRestrictionGroupId` | integer | The unique identifier of your MID restriction group if you’ve created one in the [previous step](#merchant-id-restrictions). | | `mccRestrictionGroupId` | integer | The unique identifier of your MCC restriction group if you’ve created one in the [previous step](#merchant-category-restrictions). | | `countryRestrictionGroupId` | integer | The unique identifier of your Country restriction group if you’ve created one in the [previous step](#country-restrictions). | #### Payment and ATM limits parameters In addition, you need to define limits in order to credit the amount you want on the card. **Best practice – ATM limit must be defined** Even if the ATM option has been deactivated for your cards, ATM limits must be defined for the card creation to be successful. #### Request & Response example To create a virtual card, use the following request: ::: code-group <<< @/guide/cards/snippets/create-card-virtual.bash\[CURL] ::: Here is an example of `{payload}` to create a virtual gift card of €25 using the previously created restriction groups: ::: code-group ```json [JSON] { "cardPrint": "{cardPrint}", "userId": 8290083, "walletId": 2464676, "permsGroup": "TRZ-CU-011", "mccRestrictionGroupId": 95447, "merchantRestrictionGroupId": 45599, "countryRestrictionGroupId": 165327, "limitAtmYear": 0, "limitAtmMonth": 0, "limitAtmWeek": 0, "limitAtmDay": 1, "limitAtmAll": 1, "limitPaymentYear": 0, "limitPaymentMonth": 0, "limitPaymentWeek": 0, "limitPaymentDay": 25, "limitPaymentAll": 25 } ``` ::: It returns the Card object if successful: ::: code-group ```json [JSON] { "cards": [ { "cardId": 241709, "userId": 8290083, "walletId": 2464676, "walletCardtransactionId": 2473310, "mccRestrictionGroupId": 95447, "merchantRestrictionGroupId": 45599, "countryRestrictionGroupId": 165327, "publicToken": "107277882", "cardTag": "", "statusCode": "UNLOCK", "isLive": 0, "pinTryExceeds": 0, "maskedPan": "519872******4839", "embossedName": "ALEX OAK", "expiryDate": "2026-10-31", "CVV": "260", "startDate": "2023-10-23", "endDate": "0000-00-00", "countryCode": "FR", "currencyCode": "EUR", "lang": null, "deliveryTitle": "M", "deliveryLastname": "OAK", "deliveryFirstname": "ALEX", "deliveryAddress1": "15 EDGEWOOD ROAD", "deliveryAddress2": "", "deliveryAddress3": "", "deliveryCity": "ROSEWOOD", "deliveryPostcode": "12365", "deliveryCountry": "FR", "mobileSent": "+33633333333", "limitsGroup": "TRZ-VL-001", "permsGroup": "TRZ-CU-011", "cardDesign": "13664", "virtualConverted": 0, "physical": 0, "optionAtm": 0, "optionForeign": 0, "optionOnline": 1, "optionNfc": 1, "limitAtmYear": 0, "limitAtmMonth": 0, "limitAtmWeek": 0, "limitAtmDay": 1, "limitAtmAll": 1, "limitPaymentYear": 0, "limitPaymentMonth": 0, "limitPaymentWeek": 0, "limitPaymentDay": 25, "limitPaymentAll": 25, "paymentDailyLimit": 0.0, "totalAtmYear": null, "totalAtmMonth": null, "totalAtmWeek": null, "totalAtmDay": null, "totalAtmAll": null, "totalPaymentYear": null, "totalPaymentMonth": null, "totalPaymentWeek": null, "totalPaymentDay": null, "totalPaymentAll": null, "createdBy": 945198, "createdDate": "2023-10-31 10:37:04", "modifiedBy": 0, "modifiedDate": "0000-00-00 00:00:00", "renewalType": "A", "renewalDate": null, "originalCardId": null, "totalRows": null, "designCode": null, "cardLanguages": "", "eventName": "Master Wallet", "eventAlias": "master-wallet-6537b83040735", "restrictionGroupLimits": null, "cancellationNumber": "", "metadata": null, "renewalDate": null, "renewalType": null, "originalCardId": null, "logoId": "", "logoBackId": "", "packageId": "", "customizeInfo": "", "letterCustomizedInfo": "", "freeCustomizedInfo": "", "deliveryMethod": null, "pinMailer": null, "batchDeliveryId": null, "sendToParent": 0 } ] } ``` ::: ### Convert a virtual card into a physical one You can convert a virtual card into a physical one (the card will become "virtual converted", which means it will exist in both forms). When doing so, a physical card is created and delivered to the end user’s address. **Tip – The ability to create physical cards directly depends on the Card Program** The default Card Program supports both virtual and physical cards. As a result, the endpoint to create directly a physical card is not available. You must create a virtual card to convert, even if you don't plan on exposing it to your end users. To convert a card, use the following request, with the `id` of the card to convert as a path parameter: ::: code-group ```bash [CURL] curl -X PUT '{baseUrl}/v1/cards/{cardId}/ConvertVirtual' \ --header 'Authorization: Bearer {accessToken}' ``` ::: It returns the Card object if successful, with the `virtualConverted` attribute set to `1`. ::: code-group ```json [JSON] {38} { "cards": [ { "cardId": 239391, "userId": 8322635, "walletId": 2462231, "walletCardtransactionId": 2462233, "mccRestrictionGroupId": 0, "merchantRestrictionGroupId": 0, "countryRestrictionGroupId": 0, "publicToken": "107199750", "cardTag": "Event-test-card", "statusCode": "UNLOCK", "isLive": 0, "pinTryExceeds": 0, "maskedPan": "519872******5608", "embossedName": "JOHN SMITH", "expiryDate": "2026-10-31", "CVV": "901", "startDate": "2023-10-23", "endDate": "0000-00-00", "countryCode": "FR", "currencyCode": "EUR", "lang": null, "deliveryTitle": "M", "deliveryLastname": "SMITH", "deliveryFirstname": "JOHN", "deliveryAddress1": "33 AVENUE DE WAGRAM", "deliveryAddress2": "", "deliveryAddress3": "", "deliveryCity": "PARIS", "deliveryPostcode": "75017", "deliveryCountry": "FR", "mobileSent": "+33141358530", "limitsGroup": "TRZ-VL-001", "permsGroup": "TRZ-CU-016", "cardDesign": "13664", "virtualConverted": 1, "physical": 0, "optionAtm": 1, "optionForeign": 1, "optionOnline": 1, "optionNfc": 1, "limitAtmYear": 0, "limitAtmMonth": 0, "limitAtmWeek": 2000, "limitAtmDay": 1000, "limitAtmAll": 0, "limitPaymentYear": 0, "limitPaymentMonth": 0, "limitPaymentWeek": 3000, "limitPaymentDay": 2000, "limitPaymentAll": 0, "paymentDailyLimit": 0.0, "totalAtmYear": null, "totalAtmMonth": null, "totalAtmWeek": null, "totalAtmDay": null, "totalAtmAll": null, "totalPaymentYear": null, "totalPaymentMonth": null, "totalPaymentWeek": null, "totalPaymentDay": null, "totalPaymentAll": null, "createdBy": 945198, "createdDate": "2023-10-23 13:55:34", "modifiedBy": 945198, "modifiedDate": "2023-10-23 14:09:18", "renewalType": "A", "renewalDate": null, "originalCardId": null, "totalRows": null, "designCode": null, "cardLanguages": "", "eventName": "Event_test", "eventAlias": "event-test-65365bb9d864b", "restrictionGroupLimits": null, "cancellationNumber": "", "metadata": null, "renewalDate": null, "renewalType": null, "originalCardId": null, "logoId": "", "logoBackId": "", "packageId": "", "customizeInfo": "", "letterCustomizedInfo": "", "freeCustomizedInfo": "", "deliveryMethod": null, "pinMailer": null, "batchDeliveryId": null, "sendToParent": 0 } ] } ``` ::: ### Retrieve a virtual card The created virtual cards are available as an image (base64 encoded format). You can retrieve a card and expose it to your users. To retrieve a virtual card, use the following request with the `cardId` as a query parameter. ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/v1/cardimages?cardId={cardId}' \ --header 'Authorization: Bearer {accessToken}' \ ``` ::: It returns the Card Image object if successful: ::: code-group ```json [JSON] { "cardimages": [ { "id": "155341", "cardId": "239391", "file": "/xj/base64encodedfile" } ] } ``` ::: **Security – Sensitive data storage is forbidden** You are forbidden from storing card images on your servers (except if you are PCI/DSS-certified). ## Activate a card As a security measure, all Cards are issued in an `inactive` state to ensure that a Card is not usable before the cardholder receives it. Inactive cards can’t be used to make any type of payment or withdrawal. There are two possible ways to activate a card: * **[Machine-to-machine](#machine-to-machine-activation)** – To automate the activation without any action from your end users (e.g., they directly receive the virtual card through your app). * **[User-oriented](#user-oriented-activation)** – To process an end user action (when you provide in your app a way for your end users to activate the card). In addition, you have to [Enroll the card for 3DS](#enroll-the-card-for-3d-secure). ### Machine-to-machine activation To activate a card, use the following request, with the `id` of the card to activate as a path parameter: ::: code-group ```bash [CURL] curl -X PUT '{baseUrl}/v1/cards/{id}/Activate' \ --header 'Authorization: Bearer {accessToken}' ``` ::: It returns the Card object if successful, with the `isLive` attribute set to `1`. ::: code-group ```json [JSON] {14} { "cards": [ { "cardId": 244989, "userId": 8290083, "walletId": 2464676, "walletCardtransactionId": 2487810, "mccRestrictionGroupId": 0, "merchantRestrictionGroupId": 0, "countryRestrictionGroupId": 0, "publicToken": "107290575", "cardTag": "", "statusCode": "UNLOCK", "isLive": 1, "pinTryExceeds": 0, "maskedPan": "519872******8922", "embossedName": "ALEX OAK", "expiryDate": "2026-11-30", "CVV": "843", "startDate": "2023-11-23", "endDate": "0000-00-00", "countryCode": "FR", "currencyCode": "EUR", "lang": null, "deliveryTitle": "M", "deliveryLastname": "OAK", "deliveryFirstname": "ALEX", "deliveryAddress1": "15 EDGEWOOD ROAD", "deliveryAddress2": "", "deliveryAddress3": "", "deliveryCity": "ROSEWOOD", "deliveryPostcode": "12365", "deliveryCountry": "FR", "mobileSent": "+33633333333", "limitsGroup": "TRZ-VL-001", "permsGroup": "TRZ-CU-011", "cardDesign": "13664", "virtualConverted": 0, "physical": 0, "optionAtm": 0, "optionForeign": 0, "optionOnline": 1, "optionNfc": 1, "limitAtmYear": 0, "limitAtmMonth": 0, "limitAtmWeek": 0, "limitAtmDay": 1, "limitAtmAll": 1, "limitPaymentYear": 0, "limitPaymentMonth": 0, "limitPaymentWeek": 0, "limitPaymentDay": 25, "limitPaymentAll": 25, "paymentDailyLimit": 0.0, "totalAtmYear": null, "totalAtmMonth": null, "totalAtmWeek": null, "totalAtmDay": null, "totalAtmAll": null, "totalPaymentYear": null, "totalPaymentMonth": null, "totalPaymentWeek": null, "totalPaymentDay": null, "totalPaymentAll": null, "createdBy": 945198, "createdDate": "2023-11-13 12:40:35", "modifiedBy": 945198, "modifiedDate": "2023-11-13 13:41:27", "renewalType": "A", "renewalDate": null, "originalCardId": null, "totalRows": null, "designCode": null, "cardLanguages": "", "eventName": "Master Wallet", "eventAlias": "master-wallet-6537b83040735", "restrictionGroupLimits": null, "cancellationNumber": "", "metadata": null, "renewalDate": null, "renewalType": null, "originalCardId": null, "logoId": "", "logoBackId": "", "packageId": "", "customizeInfo": "", "letterCustomizedInfo": "", "freeCustomizedInfo": "", "deliveryMethod": null, "pinMailer": null, "batchDeliveryId": null, "sendToParent": 0 } ] } ``` ::: ### User-oriented activation To activate a card, use the following request, with the `publicToken` of the card to activate as a path parameter: ::: code-group ```bash [CURL] curl -X PUT '{baseUrl}/v1/cards/{cardToken}/public-token-activation' \ --header 'Authorization: Bearer {accessToken}' ``` ::: It returns the Card object if successful, with the `isLive` attribute set to `1`. ::: code-group ```json [JSON] {14} { "cards": [ { "cardId": 244989, "userId": 8290083, "walletId": 2464676, "walletCardtransactionId": 2487810, "mccRestrictionGroupId": 0, "merchantRestrictionGroupId": 0, "countryRestrictionGroupId": 0, "publicToken": "107290575", "cardTag": "", "statusCode": "UNLOCK", "isLive": 1, "pinTryExceeds": 0, "maskedPan": "519872******8922", "embossedName": "ALEX OAK", "expiryDate": "2026-11-30", "CVV": "843", "startDate": "2023-11-23", "endDate": "0000-00-00", "countryCode": "FR", "currencyCode": "EUR", "lang": null, "deliveryTitle": "M", "deliveryLastname": "OAK", "deliveryFirstname": "ALEX", "deliveryAddress1": "15 EDGEWOOD ROAD", "deliveryAddress2": "", "deliveryAddress3": "", "deliveryCity": "ROSEWOOD", "deliveryPostcode": "12365", "deliveryCountry": "FR", "mobileSent": "+33633333333", "limitsGroup": "TRZ-VL-001", "permsGroup": "TRZ-CU-011", "cardDesign": "13664", "virtualConverted": 0, "physical": 0, "optionAtm": 0, "optionForeign": 0, "optionOnline": 1, "optionNfc": 1, "limitAtmYear": 0, "limitAtmMonth": 0, "limitAtmWeek": 0, "limitAtmDay": 1, "limitAtmAll": 1, "limitPaymentYear": 0, "limitPaymentMonth": 0, "limitPaymentWeek": 0, "limitPaymentDay": 25, "limitPaymentAll": 25, "paymentDailyLimit": 0.0, "totalAtmYear": null, "totalAtmMonth": null, "totalAtmWeek": null, "totalAtmDay": null, "totalAtmAll": null, "totalPaymentYear": null, "totalPaymentMonth": null, "totalPaymentWeek": null, "totalPaymentDay": null, "totalPaymentAll": null, "createdBy": 945198, "createdDate": "2023-11-13 12:40:35", "modifiedBy": 945198, "modifiedDate": "2023-11-13 13:41:27", "renewalType": "A", "renewalDate": null, "originalCardId": null, "totalRows": null, "designCode": null, "cardLanguages": "", "eventName": "Master Wallet", "eventAlias": "master-wallet-6537b83040735", "restrictionGroupLimits": null, "cancellationNumber": "", "metadata": null, "renewalDate": null, "renewalType": null, "originalCardId": null, "logoId": "", "logoBackId": "", "packageId": "", "customizeInfo": "", "letterCustomizedInfo": "", "freeCustomizedInfo": "", "deliveryMethod": null, "pinMailer": null, "batchDeliveryId": null, "sendToParent": 0 } ] } ``` ::: ## Enroll the card for 3D Secure Enrolling the card with the 3DS protocol will ensure the payment isn't declined if strong customer authentication is triggered during an online payment. To enroll a card for 3DS, use the following request: ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/v1/cards/Register3DS' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content: application/json' \ -d '{payload} ``` ::: With the `{payload}` containing the `cardId`: ::: code-group ```json [JSON] { "cardId": 241709 } ``` ::: An HTTP 200 response confirms the operation. ## Manage cards You can manage and update the cards after their creation. Here are a few actions that may prove useful to your use case: * [Update card options](#update-card-options) * [Update card limits](#update-card-limits) * [Update card restrictions](#update-card-restrictions) * [Block a card](#block-a-card) ### Update card options To update the card options, use the following request with the `id` of the card to update as a path parameter: ::: code-group ```bash [CURL] curl -X PUT '{baseUrl}/v1/cards/{id}/Options' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}` ``` ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "atm":1, "online":1, "nfc":1, "foreign":0 } ``` ::: It returns the Card object if successful: ::: code-group ```json [JSON] {36,40-43} { "cards": [ { "cardId": 241709, "userId": 8290083, "walletId": 2464676, "walletCardtransactionId": 2473310, "mccRestrictionGroupId": 0, "merchantRestrictionGroupId": 0, "countryRestrictionGroupId": 0, "publicToken": "107277882", "cardTag": "", "statusCode": "UNLOCK", "isLive": 1, "pinTryExceeds": 0, "maskedPan": "519872******4839", "embossedName": "ALEX OAK", "expiryDate": "2026-10-31", "CVV": "260", "startDate": "2023-10-23", "endDate": "0000-00-00", "countryCode": "FR", "currencyCode": "EUR", "lang": null, "deliveryTitle": "M", "deliveryLastname": "OAK", "deliveryFirstname": "ALEX", "deliveryAddress1": "15 EDGEWOOD ROAD", "deliveryAddress2": "", "deliveryAddress3": "", "deliveryCity": "ROSEWOOD", "deliveryPostcode": "12365", "deliveryCountry": "FR", "mobileSent": "+33633333333", "limitsGroup": "TRZ-VL-001", "permsGroup": "TRZ-CU-016", "cardDesign": "13664", "virtualConverted": 0, "physical": 0, "optionAtm": 1, "optionForeign": 1, "optionOnline": 1, "optionNfc": 1, "limitAtmYear": 0, "limitAtmMonth": 0, "limitAtmWeek": 2000, "limitAtmDay": 1000, "limitAtmAll": 0, "limitPaymentYear": 0, "limitPaymentMonth": 0, "limitPaymentWeek": 3000, "limitPaymentDay": 2000, "limitPaymentAll": 2500, "paymentDailyLimit": 0.0, "totalAtmYear": null, "totalAtmMonth": null, "totalAtmWeek": null, "totalAtmDay": null, "totalAtmAll": null, "totalPaymentYear": null, "totalPaymentMonth": null, "totalPaymentWeek": null, "totalPaymentDay": null, "totalPaymentAll": null, "createdBy": 945198, "createdDate": "2023-10-31 10:37:04", "modifiedBy": 945198, "modifiedDate": "2023-11-07 15:34:33", "renewalType": "A", "renewalDate": null, "originalCardId": null, "totalRows": null, "designCode": null, "cardLanguages": "", "eventName": "Master Wallet", "eventAlias": "master-wallet-6537b83040735", "restrictionGroupLimits": null, "cancellationNumber": "", "metadata": null, "renewalDate": null, "renewalType": null, "originalCardId": null, "logoId": "", "logoBackId": "", "packageId": "", "customizeInfo": "", "letterCustomizedInfo": "", "freeCustomizedInfo": "", "deliveryMethod": null, "pinMailer": null, "batchDeliveryId": null, "sendToParent": 0 } ] } ``` ::: **Information – Options are correlated with the `permsGroup` parameter** When updating your card options, the Card [Permission Group](/guide/cards/restrictions-limits#options-permission-groups) is automatically updated as well. ### Update card limits To update the card limits, use the following request with the `id` of the card to update as a path parameter: ::: code-group ```bash [CURL] curl -X PUT '{baseUrl}/v1/cards/{id}/Limits' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "limitPaymentAll":25, "limitPaymentYear":0, "limitPaymentMonth":0, "limitPaymentWeek":10, "limitPaymentDay":0, "limitAtmAll":0, "limitAtmYear":0, "limitAtmMonth":0, "limitAtmWeek":1, "limitAtmDay":0 } ``` ::: It returns the Card object if successful: ::: code-group ```json [JSON] {44-53} { "cards": [ { "cardId": 241709, "userId": 8290083, "walletId": 2464676, "walletCardtransactionId": 2473310, "mccRestrictionGroupId": 0, "merchantRestrictionGroupId": 0, "countryRestrictionGroupId": 0, "publicToken": "107277882", "cardTag": "", "statusCode": "UNLOCK", "isLive": 1, "pinTryExceeds": 0, "maskedPan": "519872******4839", "embossedName": "ALEX OAK", "expiryDate": "2026-10-31", "CVV": "260", "startDate": "2023-10-23", "endDate": "0000-00-00", "countryCode": "FR", "currencyCode": "EUR", "lang": null, "deliveryTitle": "M", "deliveryLastname": "OAK", "deliveryFirstname": "ALEX", "deliveryAddress1": "15 EDGEWOOD ROAD", "deliveryAddress2": "", "deliveryAddress3": "", "deliveryCity": "ROSEWOOD", "deliveryPostcode": "12365", "deliveryCountry": "FR", "mobileSent": "+33633333333", "limitsGroup": "TRZ-VL-001", "permsGroup": "TRZ-CU-016", "cardDesign": "13664", "virtualConverted": 0, "physical": 0, "optionAtm": 1, "optionForeign": 1, "optionOnline": 1, "optionNfc": 1, "limitAtmYear": 2000, "limitAtmMonth": 2000, "limitAtmWeek": 2000, "limitAtmDay": 1000, "limitAtmAll": 0, "limitPaymentYear": 5000, "limitPaymentMonth": 0, "limitPaymentWeek": 3000, "limitPaymentDay": 2000, "limitPaymentAll": 2500, "paymentDailyLimit": 0.0, "totalAtmYear": null, "totalAtmMonth": null, "totalAtmWeek": null, "totalAtmDay": null, "totalAtmAll": null, "totalPaymentYear": null, "totalPaymentMonth": null, "totalPaymentWeek": null, "totalPaymentDay": null, "totalPaymentAll": null, "createdBy": 945198, "createdDate": "2023-10-31 10:37:04", "modifiedBy": 945198, "modifiedDate": "2023-11-07 15:34:33", "renewalType": "A", "renewalDate": null, "originalCardId": null, "totalRows": null, "designCode": null, "cardLanguages": "", "eventName": "Master Wallet", "eventAlias": "master-wallet-6537b83040735", "restrictionGroupLimits": null, "cancellationNumber": "", "metadata": null, "renewalDate": null, "renewalType": null, "originalCardId": null, "logoId": "", "logoBackId": "", "packageId": "", "customizeInfo": "", "letterCustomizedInfo": "", "freeCustomizedInfo": "", "deliveryMethod": null, "pinMailer": null, "batchDeliveryId": null, "sendToParent": 0 } ] } ``` ::: ### Update card restrictions To update the card restrictions, use the following request with the `id` of the card to update as a path parameter: ::: code-group ```bash [CURL] curl -X PUT '{baseUrl}/v1/cards/{id}' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}`, which contains each of the possible restriction groups: ::: code-group ```json [JSON] { "mccRestrictionGroupId": 95447, "merchantRestrictionGroupId": 45599, "countryRestrictionGroupId": 165327 } ``` ::: It returns the Card object if successful: ::: code-group ```json [JSON] {8-10} { "cards": [ { "cardId": 241709, "userId": 8290083, "walletId": 2464676, "walletCardtransactionId": 2473310, "mccRestrictionGroupId": 45633, "merchantRestrictionGroupId": 95988, "countryRestrictionGroupId": 165327, "publicToken": "107277882", "cardTag": "", "statusCode": "UNLOCK", "isLive": 1, "pinTryExceeds": 0, "maskedPan": "519872******4839", "embossedName": "ALEX OAK", "expiryDate": "2026-10-31", "CVV": "260", "startDate": "2023-10-23", "endDate": "0000-00-00", "countryCode": "FR", "currencyCode": "EUR", "lang": null, "deliveryTitle": "M", "deliveryLastname": "OAK", "deliveryFirstname": "ALEX", "deliveryAddress1": "15 EDGEWOOD ROAD", "deliveryAddress2": "", "deliveryAddress3": "", "deliveryCity": "ROSEWOOD", "deliveryPostcode": "12365", "deliveryCountry": "FR", "mobileSent": "+33633333333", "limitsGroup": "TRZ-VL-001", "permsGroup": "TRZ-CU-016", "cardDesign": "13664", "virtualConverted": 0, "physical": 0, "optionAtm": 1, "optionForeign": 1, "optionOnline": 1, "optionNfc": 1, "limitAtmYear": 2000, "limitAtmMonth": 2000, "limitAtmWeek": 2000, "limitAtmDay": 1000, "limitAtmAll": 0, "limitPaymentYear": 5000, "limitPaymentMonth": 0, "limitPaymentWeek": 3000, "limitPaymentDay": 2000, "limitPaymentAll": 2500, "paymentDailyLimit": 0.0, "totalAtmYear": null, "totalAtmMonth": null, "totalAtmWeek": null, "totalAtmDay": null, "totalAtmAll": null, "totalPaymentYear": null, "totalPaymentMonth": null, "totalPaymentWeek": null, "totalPaymentDay": null, "totalPaymentAll": null, "createdBy": 945198, "createdDate": "2023-10-31 10:37:04", "modifiedBy": 945198, "modifiedDate": "2023-11-07 16:29:52", "renewalType": "A", "renewalDate": null, "originalCardId": null, "totalRows": null, "designCode": null, "cardLanguages": "", "eventName": "Master Wallet", "eventAlias": "master-wallet-6537b83040735", "restrictionGroupLimits": null, "cancellationNumber": "", "metadata": null, "renewalDate": null, "renewalType": null, "originalCardId": null, "logoId": "", "logoBackId": "", "packageId": "", "customizeInfo": "", "letterCustomizedInfo": "", "freeCustomizedInfo": "", "deliveryMethod": null, "pinMailer": null, "batchDeliveryId": null, "sendToParent": 0 } ] } ``` ::: ### Block a card If you suspect fraud or misuse, the API allows you to temporarily or permanently block a card, effective immediately. The `lockStatus` attribute allows you to set the desired `statusCode` for the card, hence choosing to block it in a way that is relevant to the encountered situation. To block a card, use the following request with the `id` of the card to block as a path parameter: ::: code-group ```bash [CURL] curl -X PUT '{baseUrl}/v1/cards/{id}/LockUnlock' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}` setting the `lockStatus` to locked (temporarily): ::: code-group ```json [JSON] { "lockStatus":1 } ``` ::: It returns the Card object if successful, with the updated `statusCode` (displayed a plaintext value): ::: code-group ```json [JSON] {13} { "cards": [ { "cardId": 241709, "userId": 8290083, "walletId": 2464676, "walletCardtransactionId": 2473310, "mccRestrictionGroupId": 45633, "merchantRestrictionGroupId": 95988, "countryRestrictionGroupId": 165327, "publicToken": "107277882", "cardTag": "", "statusCode": "LOCK", "isLive": 1, "pinTryExceeds": 0, "maskedPan": "519872******4839", "embossedName": "ALEX OAK", "expiryDate": "2026-10-31", "CVV": "260", "startDate": "2023-10-23", "endDate": "0000-00-00", "countryCode": "FR", "currencyCode": "EUR", "lang": null, "deliveryTitle": "M", "deliveryLastname": "OAK", "deliveryFirstname": "ALEX", "deliveryAddress1": "15 EDGEWOOD ROAD", "deliveryAddress2": "", "deliveryAddress3": "", "deliveryCity": "ROSEWOOD", "deliveryPostcode": "12365", "deliveryCountry": "FR", "mobileSent": "+33633333333", "limitsGroup": "TRZ-VL-001", "permsGroup": "TRZ-CU-016", "cardDesign": "13664", "virtualConverted": 0, "physical": 0, "optionAtm": 1, "optionForeign": 1, "optionOnline": 1, "optionNfc": 1, "limitAtmYear": 2000, "limitAtmMonth": 2000, "limitAtmWeek": 2000, "limitAtmDay": 1000, "limitAtmAll": 0, "limitPaymentYear": 5000, "limitPaymentMonth": 0, "limitPaymentWeek": 3000, "limitPaymentDay": 2000, "limitPaymentAll": 2500, "paymentDailyLimit": 0.0, "totalAtmYear": null, "totalAtmMonth": null, "totalAtmWeek": null, "totalAtmDay": null, "totalAtmAll": null, "totalPaymentYear": null, "totalPaymentMonth": null, "totalPaymentWeek": null, "totalPaymentDay": null, "totalPaymentAll": null, "createdBy": 945198, "createdDate": "2023-10-31 10:37:04", "modifiedBy": 945198, "modifiedDate": "2023-11-07 17:01:40", "renewalType": "A", "renewalDate": null, "originalCardId": null, "totalRows": null, "designCode": null, "cardLanguages": "", "eventName": "Master Wallet", "eventAlias": "master-wallet-6537b83040735", "restrictionGroupLimits": null, "cancellationNumber": "", "metadata": null, "renewalDate": null, "renewalType": null, "originalCardId": null, "logoId": "", "logoBackId": "", "packageId": "", "customizeInfo": "", "letterCustomizedInfo": "", "freeCustomizedInfo": "", "deliveryMethod": null, "pinMailer": null, "batchDeliveryId": null, "sendToParent": 0 } ] } ``` ::: ## Handle the end of the gift card life cycle Once the gift card is used by the end user (`totalPaymentAll` is reached), and if this was a one-time use card, you need to perform the following actions: 1. [Destroy the card](#destroy-the-card) 2. [Deactivate the user](#deactivate-the-user) ### Check the card has been used Because you’ve defined the card amount using the `limitPaymentAll` parameter, you can use the `cardtransaction.create` webhook to be notified once the card has been used. In such cases, the `totalPaymentAll` value equals the `limitPaymentAll`. Here is an example of `cardtransaction.create` webhook using fully the gift card available amount: ::: code-group ```json [JSON] {10,11} { "webhook":"cardtransaction.create", "webhook_id":"42xxxxxx7", "object":"cardtransaction", "object_id":"8xxxxxx5", "object_payload": { "cardtransactions":[ { // [...] some attributes are hidden "limitPaymentAll": "25.00", "totalPaymentAll": "25.00", "paymentAmount":"25.00", "paymentStatus":"A", "authorizationNote":"", "authorizationResponseCode":"0", // [...] some attributes are hidden } ] }, "object_payload_signature": "2rshbUX7b2xtxPOYKgHKvvDx9MA/19Aep07yzSpDm5U=" } ``` ::: ### Destroy the card Once the card has been used, you must destroy it by updating its status accordingly (see [Block a card](#block-a-card) section for more information on card statuses). To destroy a card, use the following request with the `id` of the card to destroy as a path parameter: ::: code-group ```bash [CURL] curl -X PUT '{baseUrl}/v1/cards/{cardId}/LockUnlock' | --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: And in the `{payload}`, set the `lockStatus` to `4` for `DESTROYED`: ::: code-group ```json [JSON] { "lockStatus":4 } ``` ::: It returns the Card object if successful, with the updated `statusCode` (displayed a plaintext value): ::: code-group ```json [JSON] {13} { "cards": [ { "cardId": 241709, "userId": 8290083, "walletId": 2464676, "walletCardtransactionId": 2473310, "mccRestrictionGroupId": 45633, "merchantRestrictionGroupId": 95988, "countryRestrictionGroupId": 165327, "publicToken": "107277882", "cardTag": "", "statusCode": "DESTROYED", "isLive": 1, "pinTryExceeds": 0, "maskedPan": "519872******4839", "embossedName": "ALEX OAK", "expiryDate": "2026-10-31", "CVV": "260", "startDate": "2023-10-23", "endDate": "0000-00-00", "countryCode": "FR", "currencyCode": "EUR", "lang": null, "deliveryTitle": "M", "deliveryLastname": "OAK", "deliveryFirstname": "ALEX", "deliveryAddress1": "15 EDGEWOOD ROAD", "deliveryAddress2": "", "deliveryAddress3": "", "deliveryCity": "ROSEWOOD", "deliveryPostcode": "12365", "deliveryCountry": "FR", "mobileSent": "+33633333333", "limitsGroup": "TRZ-VL-001", "permsGroup": "TRZ-CU-016", "cardDesign": "13664", "virtualConverted": 0, "physical": 0, "optionAtm": 1, "optionForeign": 1, "optionOnline": 1, "optionNfc": 1, "limitAtmYear": 2000, "limitAtmMonth": 2000, "limitAtmWeek": 2000, "limitAtmDay": 1000, "limitAtmAll": 0, "limitPaymentYear": 5000, "limitPaymentMonth": 0, "limitPaymentWeek": 3000, "limitPaymentDay": 2000, "limitPaymentAll": 2500, "paymentDailyLimit": 0.0, "totalAtmYear": null, "totalAtmMonth": null, "totalAtmWeek": null, "totalAtmDay": null, "totalAtmAll": null, "totalPaymentYear": null, "totalPaymentMonth": null, "totalPaymentWeek": null, "totalPaymentDay": null, "totalPaymentAll": 2500, "createdBy": 945198, "createdDate": "2023-10-31 10:37:04", "modifiedBy": 945198, "modifiedDate": "2023-11-07 17:01:40", "renewalType": "A", "renewalDate": null, "originalCardId": null, "totalRows": null, "designCode": null, "cardLanguages": "", "eventName": "Master Wallet", "eventAlias": "master-wallet-6537b83040735", "restrictionGroupLimits": null, "cancellationNumber": "", "metadata": null, "renewalDate": null, "renewalType": null, "originalCardId": null, "logoId": "", "logoBackId": "", "packageId": "", "customizeInfo": "", "letterCustomizedInfo": "", "freeCustomizedInfo": "", "deliveryMethod": null, "pinMailer": null, "batchDeliveryId": null, "sendToParent": 0 } ] } ``` ::: ### Deactivate the user For legal reasons, Users cannot be deleted. They are permanently “Canceled” instead. To cancel a user, use the following request with the `id` of the user to cancel as a path parameter: ::: code-group <<< @/guide/users/snippets/delete\_user.bash \[CURL] ::: In the `{payload}`, specify the mandatory `origin` parameter to `OPERATOR`, indicating you’re at the origin of the cancellation. ::: code-group <<< @/guide/users/snippets/origin\_operator.json \[JSON] ::: It returns a User object if successful, with the `userStatus` set to `CANCELED`: ::: code-group <<< @/./guide/users/snippets/deleted\_user.json {6} \[JSON] ::: **Tip – Recreate a user with the same email** The unique email rule only applies to active users. In other words, once the user canceled, you can create them again using the same email. --- --- url: /use-cases/gift-cards/nocode-guide.md description: >- Issue and manage Gift Cards using the Treezor Dashboard application. This no-code implementation guide takes you step-by-step through creating cards, managing users, applying restrictions, and handling card lifecycle without needing technical knowledge. --- # No-code guide The no-code guide will take you through the following steps to successfully create users and gift cards: 1. [Get to know your Dashboard](#get-to-know-your-dashboard) – Learn how to log into the Dashboard and discover the interface. 2. [Create card restriction groups](#create-card-restriction-groups) – Predefine your restriction groups to save time during the card creation process. 3. [Create physical cards in bulk](#create-physical-cards-in-bulk) – Create several cards at once while automatically generating users. 4. [Update the user declarative data](#update-the-user-declarative-data) – Define your users with the required information. 5. [Activate and manage cards](#activate-cards) – Make the final changes to the card for the end user to use. 6. [Handle the end of life cycle](#handle-the-end-of-the-gift-card-life-cycle) – Make sure your destroy the card and delete the user once the funds are used. **Information – Some features are unavailable** The no-code guide may propose fewer options as some features are not available in the Dashboard. Workarounds are available in the API guide (coming soon). ## Get to know your Dashboard The no-code guide relies on Treezor's Dashboard, a user interface allowing you to interact with the Treezor API without relying on developer tools. ### Log into your Dashboard Treezor provided you with the URL to log into your Dashboard. For your Sandbox, the URL is built as follows: * `https://dashboard-{yourCompanyName}.sandbox.treezor.co` Upon entering this URL, you'll be redirected to the sign-in page. You may then enter your email and password or use the SSO feature to log in, depending on the available options. Below is an example of Treezor's default login page. ### Discover the Dashboard interface Before you start, let’s take a quick guided tour of the key components of the Dashboard interface. **Note – Your Dashboard is customizable** The views may differ from the displayed screenshots, depending on: * Where you’re at in your integration process, if you’re customizing the design * The [Role](/guide/dashboard/dashboard-users#dashboard-user-roles) of the logged-in user, if you’re not using all of Treezor’s features ## Predefine card restriction groups To select the relevant options for the cards that you’ll be creating in the next step, you may create the restriction groups that apply to your use case. In doing so, you’ll save up time, as you won’t have to individually update the cards later on. **Information – Restrictions are not testable in Sandbox** When emulating card transactions to test your integration, restrictions won’t apply. In the *Administration* section of the navigation menu, select the *Predefined Restriction Groups* view to start creating restrictions. ### Merchant ID restrictions Defining the [Merchant ID (MID)](/guide/overview/glossary#mid-merchant-identifier) restrictions allows you to define if the card should be usable in some specific merchants. → In the *Merchant Id Groups* tab, click on the “Add a new restriction” button to start creating your Merchant Id restriction group. → In the displayed popup: * Define a name and a start date for your restriction group * Select whether you want to blacklist or whitelist a group of Merchant Ids * Enter the codes manually or upload a CSV file (the list of values in a single column) * Click on the “Save” button to validate your creation ### MCC restrictions Defining the [merchant category codes (MCC)](/guide/overview/glossary#mcc-merchant-category-code) restrictions allows you to define if the card should be used in only certain categories of merchants (or, to blacklist some categories of merchants). → In the *MCC Groups* tab, click on the “Add a new restriction” button to start creating your MCC restriction group. → In the displayed popup: * Define a name and a start date for your restriction group * Select whether you want to blacklist or whitelist a group of MCC codes * Enter the codes manually or upload a CSV file (the list of values in a single column) * Click on the “Save” button to validate your creation ### Country restrictions Defining specific country restrictions allows you to define if the card should be used in certain countries only (or, to blacklist some countries). → In the *Country Restrictions* tab, click on the “Add a new restriction” button to start creating your Country restriction group. → In the displayed popup: * Define a name and a start date for your restriction group * Select whether you want to blacklist or whitelist a group of countries * Enter the codes manually or upload a CSV file (the list of values in a single column) * Click on the “Save” button to validate your creation Once all your desired restriction groups have been created, you can move on to the next step. ## Create physical cards in bulk In the Dashboard, you can create several cards at once while automatically generating users that you can edit afterward. Before you start, ensure that you already have: * A Card Print reference (as indicated in the [prerequisites](/use-cases/gift-cards/overview#introduction-prerequisites)) * The Id of your Master Wallet (i.e., the Wallet attached to your company user). → Select the *Bulk Cards* view in the menu, and click on the “Create bulk cards” button to start your bulk card creation. ### Step 1 – Define the number of cards Be mindful of the number of cards you enter. Any ordered card will be charged to you. You must create at least 2 cards for the creation to be successful. If you’ve subscribed to a specific offer with a preset Sandbox and set of cards, you are limited to 15 cards. → Enter the number of cards to create and click “next”. ### Step 2 – Select your card type Let's make sure you have both virtual and physical cards. Cards will be displayed as virtual cards converted into physical ones in your user profile. → Select the Virtual card program in the pick-list and the “Virtual converted to physical” before going to the next step. ### Step 3 – Select your permission groups Usually, only “NFC” and “online” toggles should be activated for this use case. → Switch on the relevant toggle buttons and click “next”. ### Step 4 – Select the wallet and users for the cards to create For cards to be created, you need both a wallet and users to link them to. → In this case, you need to: * Select the “An existing wallet” option and enter the Id of your company Wallet (i.e., Master Wallet) * Select the “Several User Ids” option (new users will be automatically generated) * Ensure your company address is properly defined for the physical cards to be delivered. You may need to select a [distribution country](/guide/users/introduction#distribution-country-distributioncountry) as well. ### Step 5 – Define the name to be displayed on the cards In this specific case, the cards will have no names displayed on them as the users, as generic users, are automatically created (you will be able to edit user information only after the card creation). → Click “next” to continue. ### Step 6 – Define your card options #### Enter more card design information (optional) In the top of this page, additional card design fields are available. If provided at the same time as your credentials, you may enter the “Logo Id reference” and the “Package Id reference” for your cards. → Enter your references in the dedicated fields. #### Select restrictions If you’ve created card restriction groups, you can define what restrictions apply to your set of cards. → Click on the arrow icon available next to the “Attach restriction groups” label. → In the *Select restrictions* popup, use the drop-down to select the desired predefined restriction groups and click “confirm”. #### Define the limits The card limits will define the available amount on the gift card. You must set one by default, but you can update this information later. → Click on the arrow icon available next to the “Define limits” label. The prompted popup already displays limits which are the default limits of your card program. → In the prompted popup: * Define a random limit for ATMs (at least one must be entered for the creation to be successful). This will not be taken into account since you deactivated the “Withdrawal” default permission group in Step 3. * Define a “Global Payment limit” of the desired default amount for your gift cards. → Save your changes before going to the next step. ### Step 7 – Finalize your card creation Because you're ordering cards in bulk and you're going to be charged for these cards, you need to make sure everything is as expected. → Review the details of the cards to be created before validating your order. The bulk creation may take a few minutes. You can check the progression in the *Bulk Cards* view. Once the order Status is “Complete,” you can go to the next step. ## Update the user declarative data The bulk card creation process created as many users as cards. As a result, you have to edit each one of these users with the necessary declarative data as indicated by *Treezor Compliance*. **Information – Declarative data to submit depends on the use case** In our use case, users are not KYC-validated, so only the fields indicated in the KYC Form provided by Treezor are to be filled in. → In the *All Users* view, the automatically generated users are identifiable with their random email address and the absence of name. → Click on an automatically generated user to open the corresponding profile in the *Profile Boards* view. → In the *Profile* tab, select the “More” button (vertical ellipsis) for the following sections and select the “Edit information” option to access the relevant popups. → In each popup, enter the required declarative data as indicated below. *Information* section: * First Name * Last Name * Birthday * Birthplace * Birth country * Nationality * U.S. Person *Contact Details* section: * Email * Phone number * Address → Repeat the operation for as many users as you’ve created. Once all your users are correctly defined, you can proceed to activate and manage their individual cards. ## Activate cards As a security measure, all Cards are issued in an inactive state to ensure that a Physical Card is not usable before the cardholder receives it. Inactive cards can’t be used to make any type of payment or withdrawal. → In the *Profile Boards* view, select the *Cards* tab for your user to display the inactive card. Click on the “Activate Card” button on the right-hand side. → In the prompted confirmation popup, click on the “Yes, Activate the Card” button. Now that the card is activated, payments can be made, and you can update the card settings as you see fit. ## Enroll 3DS Enrolling the card with the 3DS protocol will ensure the payment isn't declined if strong customer authentication is triggered during an online payment. → In the *Card settings* popup, click on the “Enroll 3DS” button located in the *Card* section on the left-hand side. → Select the enrollment option that best fit your need: * **[OTP SMS](/guide/cards/creation#enrolling-a-card-for-3d-secure)** – A one-time password (OTP) sent by SMS. * **[Add Out of Band](/guide/strong-customer-authentication/securing-endpoints#enrolling-to-out-of-band-authentication)** – A strong customer authentication of the cardholder through their payment application. ## Manage cards ### Update card settings → In the *Cards* tab of your user *Profile*, select the “More” button (vertical ellipsis) for the card whose settings are to be updated, and select the “Card settings” option. The *Card settings* popup displayed allows you to manage all the card options, including enrolling the card with the [3DS protocol](#enroll-3ds) and updating limits and restrictions. #### Update card limits You may want to update the card limits to define the amount available for the gift card. → In the *Card settings* popup, *Limits* tab, set the *Global Payment limit* with the desired amount. → Save your changes to apply the new limit. #### Update card restrictions You may update or set MID, MCC, or Country restrictions directly in the *Card settings* popup. → To do so, in the *Card settings* popup, *Restrictions* tab, follow the steps below. | Step | What to do | | --- | --- | | | Select the restriction to update or to create in the right-hand side of the popup. | | | Select how you want to define the selected restriction: **Use a predefined list** – Update an existing predefined list by adding new elements**Create a list manually** – Create a new list manually**Upload a CSV** – Upload a CSV file to update your restrictions. | | | Save your changes for them to apply. | If you have any doubts about defining your restriction groups, please refer to the [Create card restriction groups](#predefine-card-restriction-groups) section of this guide. ## Handle the end of the gift card life cycle Once the gift card is used by the end user (Global Payment limit is reached), and if this was a one-time use card, you need to perform the following actions: 1. [Destroy the card](#destroy-the-card) 2. [Deactivate the user](#deactivate-the-user) ### Destroy the card Once the card has been used, you must destroy it. To do so: → In the *Card settings* popup, *Block Card tab*, select the “Close Card” option. → Click on the “Save Changes” button. As a result, the card status is changed to destroyed, and the new card status is displayed in the left-hand side of the popup. ### Deactivate the user For legal reasons, Users information can't be removed from your Dashboard. They have a permanent "Deleted" status instead. → In the *Profile Boards* view, once the user selected, click on the “Delete User” button. → In the prompted confirmation popup, click “Yes, delete this user” to continue. As a result, the user is now “Deleted”. **Tip – Recreate a user with the same email** The unique email rule only applies to active users. In other words, once the user canceled, you can create them again using the same email. --- --- url: /use-cases/gift-cards/overview.md description: >- Get some preliminary context regarding the Gift Cards use case before choosing to follow the API or No-Code guide. Includes functional architecture, financial flows, and keywords to fully understand the Gift Cards model. --- # Overview ## Introduction & Prerequisites The Gift Cards use case is meant for companies who wish to distribute gift cards to their customers or employees. In this specific case, the cardholders are not KYC-validated. It may be applied to: * **Single-merchant gift cards** – Cards that may only be used in one merchant’s point of sale. * **Special events gift cards** – Usually specific to your country's legislation, these are cards allocated by a company on special occasions such as marriages and children’s births. We propose two guides to help you through the Gift Cards use case: No-code or API. ### No-code guide Recommended for people who wish to get started with no development effort. Once you’ve gone through the prerequisites listed below and have access to your Dashboard, you’re good to go! [Start your no-code implementation →](/use-cases/gift-cards/nocode-guide) ### API guide Recommended for people with experience working with APIs. Once you’ve completed the prerequisites and got your credentials, you’re good to set up your favorite development and testing tools (e.g., set up our Postman Collection). [Start integrating Treezor API →](/use-cases/gift-cards/api-guide) **Prerequisites – Before starting this use case, make sure that you’ve:** * Created your company, its legal representatives, shareholders and its Master Wallet (see [Creating your company](/use-cases/prerequisites/creating-your-company.html) guides) * Gone through the KYC validation process for your legal entity * Set up a Card Program with Treezor (it may be a default one provided with your Sandbox) ## Functional architecture The use case relies on the following actors and objects: * **Your company** – The legal entity (corporate user, legal representatives and ultimate beneficial owners). * **End users** – Physical persons (not KYC-validated) who will use the gift cards. * **Master Wallet** – The wallet attached to the legal entity (your company), and through which all the funds are going to transit. * **Cards** – The final gift cards, which may be physical or virtual. They are attached to both your Master Wallet and the end users they are allocated to. ## Financial flows The following money flows will occur in this use case: 1. **SEPA Credit Transfers** – Your company wires the necessary amount into its Master Wallet. (Usually to cover about 3 to 4 days of expenses, hence avoiding being short on funds). 2. **Card transactions** – Your end users pay in the approved merchants' point of sale (POS) with the cards (attached to the company’s Master Wallet). **Best practice – Develop alerting for your Master Wallet** To ensure your transactions never fail due to insufficient funds, we recommend you develop an alerting system to be notified when your Master Wallet is low on funds. ## Keywords Find below a few terms specific to the use case. If you have any doubts, you may find more definitions in the [Glossary](/guide/overview/glossary). ### Master Wallet The Master Wallet refers to the single wallet attached to a company through which all the funds transit. You may also find the term [*Titres Spéciaux de Paiements*](/guide/wallets/introduction#master-wallet-type-15). ### Card Program The Card Program covers everything regarding the final issued card, from its design and packaging to the features the card provides (i.e., limits, restrictions, etc.). When creating your cards, you'll need the Id of your Card Program which has been communicated to you by Treezor. This Id is usually referred to as the `cardPrintId`, card print reference or GPS Id. --- --- url: /guide/overview/glossary.md description: >- Find out about Treezor and Banking as a Service (BaaS) terms, concepts, and definitions. Don't let acronyms get the best of you! --- # Glossary Treezor documentation’s glossary lists all the terms and acronyms you need to fully grasp the concepts of our embedded finance services. **Tip — Not finding what you're looking for?** This may be because you’re looking for business-oriented content. Don’t hesitate to have a look at the [Support Center](https://treezor.zendesk.com/hc/en-us) articles! ## 3D Secure (3DS) A protocol designed to add security layer to online card payments. When the 3D Secure protocol is triggered, the cardholder is required to perform a validation step (such as entering a code received by SMS or validating the operation on an already enrolled device) to authenticate. The second version (3DS2) facilitates [strong customer authentication (SCA)](#strong-customer-authentication-sca) to meet the regulatory technical standards of the EU Revised Payments Services Directive (PSD2). *** ## Anti-Money Laundering and Countering the Financing of Terrorism (AML/CFT) Regulations applying to entities of the financial sector to prevent the illicit use of the money transacting through their system. AML/CFT regulations focus notably on: * **Money laundering** (concealing the source of money acquired illegally to reinvest in legal activities). * **Terrorism financing** (e.g., providing funds with the intent of using them in an act of terrorism). AML/CFT also applies to entities of the non-financial sector (both public and private). It isn’t restricted to the use of licit or illicit funds, but any act participating in terrorism (e.g., lending a car). The equivalent in French is LCB/FT (“lutte contre le blanchiment des capitaux et le financement du terrorisme”). *** ## Account Status Inquiry (ASI) Authorization request from the card token provider to ensure the card exists. Before tokenizing the card, the token provider sends an ASI to Treezor. The ASI is an authorization request of a `0` amount. The proper processing of the authorization confirms the existence of the card. See the [X-Pay](/guide/cards/x-pay-google-apple) article for more information. *** ## Activation Complete Notification (ACN) Authentication message sent to the cardholder with their activation code to tokenize their card. This message triggered directly from the [wallet provider](#wallet-provider) application. When receiving it, Treezor sends the code to the cardholder by email or SMS according their preference. See the [X-Pay](/guide/cards/x-pay-google-apple) article for more information. *** ## ARA Processing message from the banking system, acknowledging the reception of the transaction. The banking system uses this functional Payment Status Report (PSR) to notify Treezor that it received the transaction. Once acknowledged, the banking system is in charge of routing the transaction to the designated entity. ARA stands for *“Accusé de réception applicatif”* in French. It translates into “application acknowledgment of receipt”. *** ## Authorization Step of the card transaction during which: * The merchant requests the issuer’s approval for the initiated transaction. * The issuer approves or rejects the payment based on the card status, spending limits, and restrictions to be enforced. See the [Transactions life cycle](/guide/cards/transactions-lifecycle#authorization) article for more information. *** ## Automated Teller Machine (ATM) A computerized device that allows the cardholder to perform banking operations such cash withdrawals, balance inquiries, deposits, fund transfers, PIN updates and mini statements. Available banking operations depend on what is supported by the card issuer. *** ## Balance The amount available in a Wallet. There are different kinds of Balances to consider: * **Current Balance** – The amount of money currently available on the wallet without considering pending operations. This is usually the balance exposed to end users. * **Authorizations** – Refers to the pending operations amount. * **Authorized Balance** – The simulated balance, which amount takes into account pending operations (i.e., authorizations amount is deducted from the balance). In other words, Current Balance = Authorized Balance + Authorizations You can fetch the Balances value using the [`/v1/balances`](/api-reference/api-endpoints.html#tag/Balances/getBalances){target="\_self"} request. ::: details Example Consider a current balance of €500.00 and an authorized payment of €100.00 (i.e., authorizations) that is not yet settled. In this case, the values will be as follows: * Current Balance – €500.00 * Authorized Balance – €400.00 (i.e., the balance minus the pending operation). * Authorizations – €100.00 ::: *** ## Bank Identifier Code (BIC) The unique international identifier of the bank. This code can be 8 or 11 alphanumeric characters, which concatenates the following information: * **Bank code** or **institution code** (first 4 characters) * **Country code** (next 2 characters), indicating the country the bank is located in * **Location** (next 2 characters), indicating the location of the bank * **Branch code** or another additional identifier (last 3 characters) ::: details Example Let's consider the following BIC: "AAAABBCCXXX" In which: * AAAA is the bank code * BB is the country code * CC is the location code * XXX is the branch code (or any other optional identifier) ::: *** ## Card Verification Code (CVC) The 3-digit code usually printed on the back of a physical card. The CVC aims to enhance security when the card is not physically present (e.g., online payments). Many acronyms are used to refer to this code, including CVV, CVC2, CSC, CVD, CVN, and SPC. *** ## Chargeback The cancellation of a financial transaction which occurs when the customer contacts their issuer to dispute a charge made to their account and request a refund. The chargeback process is designed to: * Protect consumers from fraudulent or unauthorized transactions. * Address issues such as non-delivery of goods or services, defective products, or billing errors. When a user initiates a chargeback, the funds from the disputed transaction are temporarily withdrawn from the merchant’s account. The issuer investigates the claim and determines whether the chargeback is valid. If deemed legitimate, the customer account is credited, and the merchant may incur additional fees or penalties. *** ## Chip The embedded microchip of the card. This chip is an integrated circuit that contains encrypted details about the card and securely transmits payment data to the terminal or the ATM during the transaction. *** ## Common Reporting Standard (CRS) Standard developed by the OECD in 2014 for the automatic exchange of information between partner countries to fight tax evasion. It applies to each country that has committed to the CRS and transposed it into its law. *** ## Contactless See [Near field communication (NFC)](#near-field-communication-nfc). *** ## Device Primary Account Number (DPAN) The [tokenized](/guide/cards/x-pay-google-apple) version of the [Primary Account Number (PAN)](#pan-primary-account-number) dedicated to a device such as a smartphone. It aims to securely identify a Card. It cannot be used to pay on its own. The DPAN has to be detokenized by the Card network (e.g., Mastercard) during the payment. *** ## Effective Date The date on which funds are effectively credited or debited. You may also find the term settlement date or collection date. This date differs from the date the transaction is requested in the case of a [SEPA Credit Transfer (SCT)](/guide/transfers/credit-transfer) or a [SEPA Direct Debit (SDD)](/guide/transfers/direct-debit) for example. ::: details Example Consider an SCT requested on February 3rd, but which is set to be credited on February 7th. February 7th is the effective date of the transaction. ::: *** ## Electronic money (e-money) Monetary value stored electronically and issued upon receiving funds. It is a digital equivalent of cash. E-money is stored on an electronic device (or remotely on a server) and can be used to pay for goods and services. Specific regulations (e.g., [EU’s E-Money Directive](https://eur-lex.europa.eu/legal-content/en/TXT/?uri=CELEX%3A32009L0110)) enforce restrictions and limits to e-money usage. E-money also requires an [EM approval](https://treezor.zendesk.com/hc/en-us/articles/360014672580-Note-EM-5th-Directive) of your project. See [Electronic Money Wallets](/guide/wallets/introduction#electronic-money-wallet-type-9) for more information. *** ## Foreign Account Tax Compliance Act (FATCA) US extraterritorial regulation (in force since July 1st, 2014) that aims to identify and report US taxpayers to the US tax authorities. *** ## French Cybersecurity Agency (ANSSI) The French national security cybersecurity agency (*Agence nationale de la sécurité des systèmes d'information*), in charge of granting the [PVID](#remote-identity-verification-providers-pvid) certification. Learn more on the [ANSSI official website](https://cyber.gouv.fr/en/about-french-cybersecurity-agency-anssi). *** ## JSON Web Token (JWT) Authentication token which also contains information about the User (e.g., `id`) and their [Scopes](/guide/api-basics/authentication#available-scopes). The token claimed information can be verified using a signature mechanism. You need to provide this Token for any request made to the Treezor API. Read more about the JWT in the [Authentication](/guide/api-basics/authentication#obtaining-an-access-token-jwt) article. *** ## Mag Stripe The magnetic stripe found on the back of a card. It is encoded with data, hence providing similar information as the card’s Chip. *** ## Merchant A business accepting electronic payment transactions. Merchants are therefore equipped to accept and process card payments. This term applies to both in-person and online transactions. *** ## Merchant Category Code (MCC) The code categorizing the merchant’s commercial activity (e.g., clothing retailers, restaurants, etc.). This code is included in any card transaction (withdrawals or payments) and allows you to restrict payments based on the merchant’s activity. Find the list of MCC in the [MasterCard's Quick Reference Booklet](https://www.mastercard.us/content/dam/public/mastercardcom/na/global-site/documents/quick-reference-booklet-merchant.pdf). *** ## Merchant Identification Number (MID) The unique identifier assigned to a [merchant](/guide/overview/glossary#merchant) by their bank. This 15-digit identifier is usually included in the card transaction, which: * Helps identify a merchant. * Allows you to [restrict payments based on the MID](/guide/cards/restrictions-limits#mid-restrictions). You may also find the terms Merchant Identifier or Merchant ID to refer to this number. *** ## Near Field Communication (NFC) Technology that powers contactless payments with credit cards or smartphones for instance. *** ## Nomenclature Activités Française (NAF) The French coding system categorizing business and [merchant](/guide/overview/glossary#merchant) activities. **Reading – Additional documentation in French** * [CITI-NACE-NAF correspondence table](https://www.insee.fr/fr/statistiques/fichier/2408180/CITI_NACE_NAFrev1_2003.pdf) * Full list of NAF codes on [insee.fr](https://www.insee.fr/fr/statistiques/fichier/2120875/Nomenclatures_NAF_et_CPF_Reedition_2020.pdf) *** ## Payment Card Industry Data Security Standards (PCI DSS) Payment industry security standards to secure the sensitive data of payment cards. It sets the technical and operational requirements to create a secure environment for sensitive card data, such as the PAN, CVV, and PIN. PCI DSS was created by the [Payment Card Industry Security Standards Council (PCI SSC)](https://www.pcisecuritystandards.org/standards/pci-dss/) and is a contractual obligation adopted by major card schemes (Visa, Mastercard, etc.). It applies to all card payment process actors, including issuers and service providers. **Reading – PCI DSS integration** Find out more in the dedicated [PCI DSS integration](/guide/cards/pci-dss) article. *** ## Personal Identification Number (PIN) The 4-digit code of the card, entered by the cardholder during a “card present” payment. *** ## Primary Account Number (PAN) The main card number, made up of 16 to 19 digits displayed on the card. The first 6 to 8 numbers correspond to the IIN (Issuer Identification Number) or BIN (Bank Identification Number), hence identifying the entity that emitted the card. **Tip – The IIN first number identifies the network** Card schemes are easily identified with the IIN. For instance, 4 stands for Visa, and 5 for Mastercard. *** ## Qualified Electronic Signature (QES) Electronic signature with the highest level of security. These electronic signatures are “qualified” because the user’s identity is verified through a selfie at the same time as they electronically sign the document. QES is therefore [eIDAS-compliant](https://digital-strategy.ec.europa.eu/en/policies/eidas-regulation) and: * Ensures the signer identification * Protects the signature against forgery and tampering * Provides a certificate for electronic signature issued by a certified provider *** ## Regulated institution [Legal Entity](/guide/users/legal-entity) that has gone through a thorough administrative process with the regulators (*ACPR* in France) to be allowed to provide payment services to customers. Regulated Institutions encompass a wide group of institutions such as Payment Institutions, Microfinance institutions, Financial holding companies, etc. They benefit from additional features in return for added legal and administrative responsibilities. **Tip – Dedicated Regulated Institutions badge in the documentation** Features that are available only to Regulated Institutions are tagged with the badge across the documentation. ::: details **Benefits** * Dedicated IT infrastructure at Treezor * [Custom IBAN/BIC](/guide/wallets/iban#create-a-virtual-iban) * [Users Freezing](/guide/users/introduction#freezing) * Choosing whether to use Treezor's technical features or build alternatives yourself (e.g., KYC) ::: ::: details **Constraints** * You are responsible for your customers' [KYC](/guide/user-verification/introduction) * You must enforce anti-fraud and anti-laundering systems * You must report to the regulators * You are responsible for monitoring [outgoing funds](/guide/transfers/introduction#types-of-transfers) (although this can be delegated to Treezor TMS (Transaction Monitoring System)) ::: **Reading – Learn more about Payment Institutions** You can read more about Payment Institutions (a type of Regulated Institution) on the [European Payment Institutions Federation's website](https://paymentinstitutions.eu/the-payment-institutions-sector/about/). *** ## Remote Identity Verification Providers (PVID) Standard for robust and reliable remote identity verification processes to minimize fraud risks. Becoming a PVID (*Prestataires de vérification d’identité à distance* in French) requires passing a certification with the [French Cybersecurity Agency (ANSSI)](#french-cybersecurity-agency-anssi). *** ## SEPA Creditor Identifier (SCI) The unique and mandatory reference for [SEPA Direct Debit mandates](/guide/transfers/direct-debit#emitted-direct-debits-sdde). It must appear in any direct debit application. Its main purpose is to allow each creditor, who may be located in any SEPA country, and their bank to know the precise identity of the issuer of the direct debit. This facilitates claims for reimbursement or action in the event of a complaint. ::: details Structure of the SCI The SCI length varies from country to country, but never exceeds 35 characters. Its structure is AABBCCCX, in which: * AA – ISO country code (e.g., FR for France) * BB – 2 control numbers * CCC – Activity code that can be freely used by the creditor * X – National identifier, which is up to 28 figures. This is the NNE (National Issuer Number), 13 characters long in France, formerly used for national debits. ::: *** ## SEPA Credit Transfer (SCT) [SEPA](/guide/overview/glossary#single-euro-payments-area-sepa) transfers initiated by the sender; the debtor *credits* another account. This feature allows the sender to make Euro-denominated payments to SEPA countries accounts. Learn more from the European Payments Council [SEPA Credit Transfers](https://www.europeanpaymentscouncil.eu/what-we-do/sepa-credit-transfer) article. *** ## SEPA Direct Debit (SDD) [SEPA](/guide/overview/glossary#single-euro-payments-area-sepa) transfers initiated by the receiver; the receiver *debits* another account, allowed to do so by a [*Mandate*](/guide/transfers/mandates). This feature allows the recipient to collect Euro-denominated payments from SEPA countries accounts. Learn more from the European Payments Council [SEPA Direct Debit](https://www.europeanpaymentscouncil.eu/what-we-do/sepa-direct-debit) article. *** ## SEPA Instant Payments Real-time electronic payment method allowing for rapid and secure fund transfers between bank accounts within the [SEPA](/guide/overview/glossary#single-euro-payments-area-sepa) region. The rapid processing offers a settlement within a matter of seconds, providing users with immediate access to transferred funds. Learn more about [SEPA Instant Credit Transfers](https://www.europeanpaymentscouncil.eu/what-we-do/sepa-instant-credit-transfer) from the European Payments Council article. *** ## SEPA Open Banking Days Days on which operations using the SEPA network are processed. Operations on the SEPA Network are indeed subject to handling delays and time frames. Operations aren't processed on **closed days**, which are the weekends (Saturdays & Sundays) and the following [TARGET2](https://www.ecb.europa.eu/paym/target/target2/html/index.en.html) closed days: * January, 1st (New Year's Day) * Good Friday (*Vendredi saint*) * Easter day (Monday) * May, 1st (Labor Day) * December, 25th (Christmas) * December, 26th When a delay or time frame is indicated as *Open Banking Days*, these closed days must be excluded. The list of closed days for the current year is available on the [European Central Bank website](https://www.ecb.europa.eu/paym/target/target2/html/index.en.html). *** ## Settlement Step of the card transaction during which the funds are debited from the cardholder's account and credited to the merchant's account. See the [Transactions life cycle](/guide/cards/transactions-lifecycle#settlement) article for more information. *** ## Single Euro Payments Area (SEPA) Payment integration initiative of the European Union which simplified euro bank transfers (credit transfers and direct debits). Learn more from the [European Central Bank website](https://www.ecb.europa.eu/paym/integration/retail/sepa/html/index.en.html). *** ## Strong Customer Authentication (SCA) A regulatory requirement aiming at reducing fraud and making payments more secure. It enforces two-factor authentication for cardholders to validate online transactions. The factors must be two of the following elements: * **Knowledge** – Something only the user knows (e.g., password) * **Possession** – Something only the user has (e.g., phone) * **Inherence** – Something only the user is (e.g., fingerprint) Strong Customer Authentication (SCA) was introduced by the EU Revised Directive on Payment Services (PSD2) in 2015. Learn more about SCA in the [dedicated section of the documentation](/guide/strong-customer-authentication/introduction). *** ## Terminal Electronic device usually found in physical points of sale, allowing merchants to process card transactions. You may also find the term point of sale (POS); it refers to a more global definition of terminals (including cash registers, for instance). *** ## Token provider Actor who tokenizes the PAN to allow its storage as a DPAN by the Wallet provider. The token provider also detokenizes the DPAN during payments. In the context of Treezor card digitization services, the token providers are the schemes through their corresponding services: * Mastercard Digitalization Enablement Service (MDES) * Visa Tokenization System (VTS) See the [X-Pay](/guide/cards/x-pay-google-apple) article for more information. *** ## Tokenization Authentication Value (TAV) Encrypted card data which allows the token provider to identify the card and allows to start the digitization process. At Treezor, the TAV is often referred to as the “cryptogram”. See the [X-Pay](/guide/cards/x-pay-google-apple) article for more information. *** ## Tokenization Authorization Request (TAR) Message sent to Treezor’s card processor to verify the card configuration. The wallet provider requests the tokenization authorization verification to the card processor which confirms to Treezor that the tokenization services are available. During this step, Treezor may refuse the digitization of the card for various reasons, such as the lack of compliance with anti-fraud requirements. Treezor sends you the `cardDigitalization.request` webhook, in which the `tokenizationDecision` field indicates whether the request is ACCEPTED or DECLINED. See the [X-Pay](/guide/cards/x-pay-google-apple) article for more information. *** ## Tokenization Complete Notification (TCN) Notification from the token provider that the card was digitized and added to the wallet provider application. Treezor forwards this information to you with the `cardDigitalization.complete` webhook, and also sends a one-time password (OTP) to the cardholder by SMS or email. See the [X-Pay](/guide/cards/x-pay-google-apple) article for more information. *** ## Top-up The act of crediting (or recharging) an account. At Treezor, [Wallets](/guide/wallets/introduction) can be credited with [card payments](/guide/acquiring/introduction) and [check cashing](/guide/cheques/cashing) for instance. *** ## Unique Mandate Reference (UMR) The mandatory reference provided by the owner of an account, allowing the account to be debited by [SEPA Direct Debit](#sepa-direct-debit-sdd). At Treezor, the UMR is: * **Obtained by creating a Mandate** – For [SDDE](/guide/transfers/direct-debit#emitted-direct-debits-sdde). * **Provided by the Beneficiary** – For [SDDR](/guide/transfers/direct-debit#received-direct-debits-sddr). This value is available in the `mandate_id` attribute of the [`sepa.sddr_reception`](/guide/transfers/events#sepa-sddr-reception) webhook. The UMR is a sequence of characters that ensures the mandate traceability. UMR coupled with SCI allows to uniquely identify a creditor and a contract for any mandate. *** ## Verification of Payee (VoP) Regulatory obligation allowing the initiator of a SEPA transfer to verify that the beneficiary’s name and IBAN match with the information registered at their bank. This service aims to prevent fraud and misdirected payments, and applies when emitting: * SEPA Credit Transfers (SCT) * SEPA Instant Credit Transfers (SCT Inst) At Treezor, verification of the beneficiary will occur when initiating the payout request, and end users will confirm the payout once the results of the VoP are returned to them. **Reading – Please refer to the technical specifications shared by Treezor** If you are already using Treezor services, you’ve received the technical specifications to anticipate the Verification of Payee implementation. The Verification of Payee (VoP) obligation is mandated by the [European Payments Council (EPC)](https://www.europeanpaymentscouncil.eu/) and comes into force on October 5, 2025. *** ## Wallet provider Actor who stores the DPAN of a card for the cardholder to use their devices as a payment method (e.g., Apple, Google). See the [X-Pay](/guide/cards/x-pay-google-apple) article for more information. --- --- url: /guide/api-basics/response-codes.md description: >- Understand HTTP Status Codes in the Treezor API. This guide explains common 2xx, 4xx, and 5xx response codes, detailing their meaning and the JSON error structure for effective API response processing. --- # HTTP Status codes The Treezor API returns an *HTTP Status Code* that indicates how your request generally went. It points you to the general direction of the issue (if any). The table below details the meaning of each *HTTP Status Code* and possible solutions. | HTTP Code | Status name | Meaning | Solution | |:-: |- |- |- | | `200` | OK | The most common code, **everything is fine**. | None needed | | `201` | Created | **The resource has been created by the API**. | None needed | | `204` | No content | **The server handled the request successfully but did not produce a response**. | This can be a normal behavior with `POST` requests | | `303` | See other | **The response to the request can be found using the GET method**. | This occurs when you attempt to create a duplicate document for instance. | | `400` | Bad request | **Something is wrong with your request itself**. | Your parameters or payload might be erroneous, check the [API Reference](/api-reference/api-endpoints) for the endpoint | | `401` | Authentication problem | **The provided JWT is not valid**. | Check if the JWT is properly set in the `Authorization` header and make sure that it hasn't expired | | `403` | Authorization problem | **You do not have access to this endpoint**. | Check your JWT scopes and [API Reference](/api-reference/api-endpoints) for that endpoint to check what scope is required | | `404` | Not found | **The endpoint was not found or the resource was not found**. | Make sure the object's ID you are requesting is valid and exists | | `413` | Content Too Large | **The file size exceeds the limit**. | Make sure the documents to upload comply with the limits | | `500` | Treezor Connect server error | **Our servers failed while handling your request**. | Try again and/or look at the response's payload, it can provide more information regarding the cause | | `501` | Not implemented | **The endpoint called is not implemented** or not implemented with your *Treezor Connect* configuration. | Make sure the endpoint is correct, or contact your *Treezor Account Manager* to enable the feature | | `502` `504` `522` | Bad gateway | **Our servers didn't respond in a timely manner**. | Try again or [contact the Treezor Support team](/guide/overview/getting-started#getting-help) if the error persists | **Important – If you're not receiving any response, check that** * You are using HTTPS. Treezor doesn't automatically upgrade HTTP to HTTP**S**. * Your IP was declared to Treezor (when using the [Production environment](/guide/api-basics/environments#production)). **Alongside the HTTP Status code, the API will generally return one or more Errors objects in a json array.** These objects contain detailed information to help you understand and debug the situation. They are always provided in English. **Security – Don't display any part of these errors to your end user** This could leak sensitive information. You should create your own generic error messages. ## Error attributes Errors have the following attributes | Field | Type | Description | Nullable | |---|----|----|----| | `type` | `string` | Machine-readable type (authentication, request format…) | No | | `code` | `string` | Machine-readable code (expired JWT, missing parameter…) | No | | `message` | `string` | Human readable explanation | No | | `docUrl` | `string` | URL of the relevant documentation page | No | | `requestId` | `string` | Unique identifier of the error, to help Treezor trace back the error | No | Example of a response containing a single error. ::: code-group ```json [JSON] { "errors": [ { "type": "invalid_request", "code": "authorization_error", "message": "You cannot read operations for this wallet.", "docUrl": "https://developers.treezor.co", "requestId": "fa433c8c-1232-4c14-9f9e-95eddad19764" } ] } ``` ::: ## Error types The `type` attribute may take the following values. | Type | Description | |:---|:----| | `invalid_client` | Client is not valid | | `invalid_grant` | Issue with the user credentials or permissions | | `invalid_request` | Request is malformed: Invalid Option, Input validation not passed | | `unexpected_internal_server_error` | Something unexpected happened | | `unsupported_grant_type` | Issue with the grant\_type which may not be recognized or supported by the server | ## Error codes The `code` attribute may take the following values. | Code | Description | Solution | |- |- |- | | `authentication_error` | An authentication error occurred | Check that your [JWT](/guide/api-basics/authentication) is valid and hasn't expired | | `authorization_error` | Core Banking returned an `unauthorized` error | | | `functional_error` | A Core Banking functional error occurred | Make sure that all the functional requirements for the action are met | | `input_validation_error` | Input validation failed | Double-check the provided [parameters format](/guide/api-basics/data-format) and content | | `invalid_parameter_in_request` | An unexpected request parameter was found | Check that you don't have non-allowed parameters in your request | | `invalid_user_id` | The provided User ID is invalid. | Check that the [User ID](/guide/users/introduction) is correct (either uuid `trzconnectUser` or int Treezor `userId`) | | `resource_not_found_error` | The resource was not found | Make sure the object or endpoint you are trying to access actually exists | | `undefined_cursor_error` | Undefined cursor | Check the [pagination](/guide/api-basics/pagination) or cursor documentation | | `unexpected_error` | An unexpected error occurred | Try again or [contact Treezor](/guide/overview/getting-started#getting-help) if the error persists | | `0` | The requested URL is malformed | Make sure no trailing `/` exists when they shouldn't (or the opposite) | --- --- url: /guide/api-basics/idempotency.md description: >- Understand idempotency in the Treezor API. This guide explains how to prevent duplicate operations and ensure data consistency by implementing idempotency keys in your requests. --- # Idempotency Accidentally sending a request twice can cause duplicates and errors. To avoid such situations, Treezor recommends adding a unique identifier to your `POST` and `PUT` requests using the `accessTag` attribute. The `accessTag` parameter is a string with a maximum length of 250 characters for you to use in accordance with the best practices to generate unique identifiers in your development environment. Here are tips for [Java](https://docs.oracle.com/javase/8/docs/api/java/util/UUID.html), [npm](https://www.npmjs.com/package/uniqid), and [PHP](https://stackoverflow.com/questions/4070110/how-unique-is-uniqid), for instance. **Information – The `accessTag` values are only kept for 24 hours** Therefore, it is not a permanent solution to reconcile Treezor objects to your local database objects. To reconcile objects, use the persistent [object tags](/guide/api-basics/objects-tags). ## Examples with idempotency ### User creation Let's take an example in which you send a User creation request with an `accessTag`. The following occurs: * Treezor receives the request and creates the user. * You do not receive an answer from Treezor, or the request times out on your side. * You reasonably send the User creation request again. * Treezor receives the new request, **identifies it as a duplicate (same `accessTag`)**, and **returns the previously created User** object. ### Money transfer Let's take an example in which you send a Transfer request from a Wallet to another Wallet with an `accessTag`. The following occurs: * Treeezor receives the Transfer request and moves funds to the other Wallet. * You do not receive an answer from Treezor, or the request times out on your side. * You reasonably send the Transfer request again. * Treezor receives the new request, **identifies it as a duplicate (same `accessTag`)**, and **returns the previously created Transfer** object. ## Examples without idempotency ### User creation Let's take an example in which you send a User creation request without any idempotency `accessTag`. The following occurs: * Treezor receives the request and creates a user. * You do not get an answer from Treezor, or the request times out on your side. * You reasonably send the User creation request again. * Treezor receives the new request, treats it as a different request and **attempts to create the same user a second time**. **Alert – This situation returns an error** Duplicate users are not allowed, using an `accessTag` would have prevented this situation. ### Money transfer Let's take an example in which you send a Transfer request from a Wallet to another Wallet without any idempotency `accessTag`. The following occurs: * Treezor receives the Transfer request and moves funds to the other Wallet. * You do not receive an answer from Treezor, or the request times out on your side. * You reasonably send the Transfer request again. * Treezor receives the request, handles it as a different request and **transfers the same amount a second time**. **Alert – Twice the expected amount is moved** Because the transfer occurs twice, you will then need to refund the duplicate transfer in order to solve the issue. Using an `accessTag` would have prevented this situation. --- --- url: /guide/acquiring/events.md description: >- Reference a comprehensive list of card acquiring events for Treezor API webhooks, detailing each event's structure and payload for integration. --- # Events This article lists the [webhooks](/guide/webhooks/introduction) you may receive when using the Acquiring feature. For the [legacy flow](./legacy-v1), the reception of any `payin` webhook meant that a payment had been accepted. This is **no longer the case** in the newest version. Please refer to the `payinStatus` attribute of the `payin`. The payment is accepted when valued to `VALIDATED`. ::: details Webhooks flow chart ```mermaid flowchart TD id1[Payment creation] --> id2("authorization.create
authorizationStatus:PENDING") --> id3("authorization.update
authorizationStatus:PENDING") ----> id5("payin.create
payinStatus:PENDING") --> id6("payin.update
payinStatus:VALIDATED"); id3 --> id4("authorization.cancel
authorizationStatus:CANCELED") ; id1 --> id4; id5 --> id8("payin.cancel
payinStatus:CANCELED"); class id1 neutral; ``` ::: ## TopupCard ### `topupCard.validate` ::: code-group ```json [JSON] { "webhook":"topupCard.validate", "webhook_created_at":16867326126402, "object_id":"61e46d74-54db-4170-968f-28c307ba255c", "object":"topupCard", "object_payload":{ "topupCards":[ { "topupCardId":"61e46d74-54db-4170-968f-28c307ba255c", "userId":"1656177", "profile":"00001340585", "token":"4d2e3ce0aa972bb3726fa609b648535c803d725dccf3d8cbe738762f84281d3e", "brand":"MASTERCARD", "maskedPan":"545454xxxxxx5454", "cardHolder":"Tom Pes", "cardExpiryMonth":"12", "cardExpiryYear":"2025", "issuer":"CENTRAL TRUST BANK, THE", "country":"US", "domesticNetwork":null, "cardType":"CREDIT", "status":"VALIDATED", "createdDate":"2023-06-14 10:50:08", "updatedDate":"2023-06-14 10:50:08" } ] }, "webhook_id":"185cf5c2-766d-4168-8848-6bd754083ef4", "object_payload_signature":"CktrgqtW2rknbedybQ3VIDTxygjZRE3zrY6dR\/g3YpE=", "auth_key":"true" } ``` ::: ### `topupCard.cancel` ::: code-group ```json [JSON] { "webhook":"topupCard.cancel", "webhook_created_at":16867326507819, "object_id":"61e46d74-54db-4170-968f-28c307ba255c", "object":"topupCard", "object_payload":{ "topupCards":[ { "topupCardId":"61e46d74-54db-4170-968f-28c307ba255c", "userId":"1656177", "profile":"00001340585", "token":"4d2e3ce0aa972bb3726fa609b648535c803d725dccf3d8cbe738762f84281d3e", "brand":"MASTERCARD", "maskedPan":"545454xxxxxx5454", "cardHolder":"Tom Pes", "cardExpiryMonth":"12", "cardExpiryYear":"2025", "issuer":"CENTRAL TRUST BANK, THE", "country":"US", "domesticNetwork":null, "cardType":"CREDIT", "status":"CANCELED", "createdDate":"2023-06-14 10:50:08", "updatedDate":"2023-06-14 10:50:50" } ] }, "webhook_id":"c69a1148-ea41-479c-a33d-af0df5e95f72", "object_payload_signature":"fn\/rOnp3\/YWJFodXHIRUzMmKmT82ohYIqapwcRG5VvI=", "auth_key":"true" } ``` ::: ## Authorization ### `authorization.create` ::: code-group ```json [JSON] { "webhook":"authorization.create", "webhook_created_at":16867327260694, "object_id":"7ec56e11-02fe-5f53-a7e9-d8403e95bbe5", "object":"authorization", "object_payload":{ "authorizations":[ { "authorizationId":"7ec56e11-02fe-5f53-a7e9-d8403e95bbe5", "walletId":"878744", "userId":"1656177", "authorizationStatus":"PENDING", "messageToUser":"The financial institution has approved the payment.", "amount":"100.00", "currency":"EUR", "createdDate":"2023-06-14 10:51:56", "walletEventName":"Hondwallet", "walletAlias":"Hondwallet-620e13cb0760f", "userFirstname":"John", "userLastname":"Doe", "codeStatus":"150116", "informationStatus":"Authorized", "payinDate":"0000-00-00 00:00:00", "additionalData":"{\"card\":{\"externalProvider\":{\"transactionReference\":\"800240081686\"}}}" } ] }, "webhook_id":"65ad7aad-2c72-4abd-920d-e73107afcf78", "object_payload_signature":"d6u1VgSn+hWZHpb4Z2nfbwm3\/RtyAVdsyS3CTD0+Qc8=", "auth_key":"true" } ``` ::: ### `authorization.update` ::: code-group ```json [JSON] { "webhook":"authorization.update", "webhook_created_at":16867328446792, "object_id":"7ec56e11-02fe-5f53-a7e9-d8403e95bbe5", "object":"authorization", "object_payload":{ "authorizations":[ { "authorizationId":"7ec56e11-02fe-5f53-a7e9-d8403e95bbe5", "walletId":"878744", "userId":"1656177", "authorizationStatus":"PENDING", "messageToUser":"Authorization cancellation requested.", "amount":"100.00", "currency":"EUR", "createdDate":"2023-06-14 10:51:56", "walletEventName":"Hondwallet", "walletAlias":"Hondwallet-620e13cb0760f", "userFirstname":"John", "userLastname":"Doe", "codeStatus":"150175", "informationStatus":"Authorization Cancellation Requested", "payinDate":"0000-00-00 00:00:00", "additionalData":"{\"card\":{\"externalProvider\":{\"transactionReference\":\"800240081686\"}}}" } ] }, "webhook_id":"c9e92612-6780-4fb0-871e-137158a870a3", "object_payload_signature":"wa9DCqC1wj0XKBmexQSmwlu1lZbi8Vvl+t277sxDTGs=", "auth_key":"true" } ``` ::: ### `authorization.cancel` ::: code-group ```json [JSON] { "webhook":"authorization.cancel", "webhook_created_at":16867328881913, "object_id":"7ec56e11-02fe-5f53-a7e9-d8403e95bbe5", "object":"authorization", "object_payload":{ "authorizations":[ { "authorizationId":"7ec56e11-02fe-5f53-a7e9-d8403e95bbe5", "walletId":"878744", "userId":"1656177", "authorizationStatus":"CANCELED", "messageToUser":"Merchant cancelled the payment attempt.", "amount":"100.00", "currency":"EUR", "createdDate":"2023-06-14 10:51:56", "walletEventName":"Hondwallet", "walletAlias":"Hondwallet-620e13cb0760f", "userFirstname":"John", "userLastname":"Doe", "codeStatus":"150115", "informationStatus":"Canceled", "payinDate":"0000-00-00 00:00:00", "additionalData":"{\"card\":{\"externalProvider\":{\"transactionReference\":\"800240081686\"}}}" } ] }, "webhook_id":"40ca0506-00c8-469f-b5c1-d0016bcc277f", "object_payload_signature":"\/h8+\/ekdSsDHYSsmyJaQmP75XJT8Il7wOJ5PutVqmeY=", "auth_key":"true" } ``` ::: ## Payin ### `payin.create` ::: code-group ```json [JSON] { "webhook":"payin.create", "webhook_created_at":17232080879509, "object_id":"ddd4a268-ac2a-5359-afa1-2c1c92ed83c5", "object":"payin", "object_payload":{ "payins":[ { "payinId":"ddd4a268-ac2a-5359-afa1-2c1cxxed83c5", "payinTag":"", "walletId":"878744", "userId":"1656177", "payinStatus":"PENDING", "paymentMethodId":"25", "messageToUser":"A capture request has been sent to the financial institution.", "subtotalItems":"0.00", "subtotalServices":"0.00", "subtotalTax":"0.00", "amount":"12.48", "currency":"EUR", "createdDate":"2024-08-09 14:54:38", "walletEventName":"reset", "walletAlias":"alias878744", "userFirstname":"Alex", "userLastname":"Oak", "codeStatus":"150117", "informationStatus":"Capture Requested", "refundAmount":null, "ibanId":null, "ibanFullname":null, "DbtrIBAN":null, "ibanBic":null, "ibanTxEndToEndId":null, "ibanTxId":null, "forwardUrl":null, "paymentAcceptedUrl":null, "paymentRefusedUrl":null, "paymentWaitingUrl":null, "paymentExceptionUrl":null, "paymentCanceledUrl":null, "payinDate":"0000-00-00 00:00:00", "mandateId":"0", "creditorName":null, "creditorAddressLine":null, "creditorCountry":null, "creditorIban":null, "creditorBIC":null, "virtualIbanId":null, "virtualIbanReference":null, "additionalData":"{\"card\":{\"externalProvider\":{\"state\":\"completed\",\"mid\":\"00001340255\",\"authorizationCode\":\"no_code\",\"transactionReference\":\"800315441134\",\"dateCreated\":\"2024-08-09T14:54:38+0200\",\"dateUpdated\":\"2024-08-09T14:54:43+0200\",\"status\":117,\"message\":\"Capture Requested\",\"authorizedAmount\":12.48,\"capturedAmount\":12.48,\"refundedAmount\":0,\"currency\":\"EUR\",\"ipAddress\":\"0.0.0.0\",\"ipCountry\":\"\",\"cdata1\":\"212707\",\"cdata2\":\"878744\",\"cdata3\":\"1656177\",\"cdata4\":\"\",\"cdata5\":\"\",\"cdata6\":\"\",\"cdata7\":\"\",\"cdata8\":\"\",\"cdata9\":\"\",\"cdata10\":\"\",\"eci\":\"9\",\"paymentProduct\":\"mastercard\",\"paymentMethod\":{\"pan\":\"545454******5454\",\"cardHolder\":\"ALEX OAK\",\"token\":\"5d******63\",\"issuer\":\"TREE BANK, THE\",\"brand\":\"MASTERCARD\",\"country\":\"US\",\"cardExpiryMonth\":\"12\",\"cardExpiryYear\":\"2025\"},\"fraudScreening\":{\"scoring\":\"0\",\"result\":\"not_launched\",\"review\":\"\"}}}}" } ] }, "webhook_id":"a58d8791-2e74-4b04-8351-6b421931f80e", "object_payload_signature":"SItdZHqCRm64kHVlcNsf/7Txxvuj6/tC274xFq4p6BU=" } ``` ::: ### `payin.update` ::: code-group ```json [JSON] { "webhook":"payin.update", "webhook_created_at":17232080901832, "object_id":"ddd4a268-ac2a-5359-afa1-2c1c92ed83c5", "object":"payin", "object_payload":{ "payins":[ { "payinId":"ddd4a268-ac2a-5359-afa1-2c1c92ed83c5", "payinTag":"", "walletId":"878744", "userId":"1656177", "payinStatus":"VALIDATED", "paymentMethodId":"25", "messageToUser":"The financial institution has processed the payment.", "subtotalItems":"0.00", "subtotalServices":"0.00", "subtotalTax":"0.00", "amount":"12.48", "currency":"EUR", "createdDate":"2024-08-09 14:54:38", "walletEventName":"reset", "walletAlias":"alias878744", "userFirstname":"Alex", "userLastname":"Oak", "codeStatus":"150118", "informationStatus":"Captured", "refundAmount":null, "ibanId":null, "ibanFullname":null, "DbtrIBAN":null, "ibanBic":null, "ibanTxEndToEndId":null, "ibanTxId":null, "forwardUrl":null, "paymentAcceptedUrl":null, "paymentRefusedUrl":null, "paymentWaitingUrl":null, "paymentExceptionUrl":null, "paymentCanceledUrl":null, "payinDate":"0000-00-00 00:00:00", "mandateId":"0", "creditorName":null, "creditorAddressLine":null, "creditorCountry":null, "creditorIban":null, "creditorBIC":null, "virtualIbanId":null, "virtualIbanReference":null, "additionalData":"{\"card\":{\"externalProvider\":{\"state\":\"completed\",\"mid\":\"00001340255\",\"authorizationCode\":\"no_code\",\"transactionReference\":\"800315441134\",\"dateCreated\":\"2024-08-09T14:54:38+0200\",\"dateUpdated\":\"2024-08-09T14:54:43+0200\",\"status\":118,\"message\":\"Captured\",\"authorizedAmount\":12.48,\"capturedAmount\":12.48,\"refundedAmount\":0,\"currency\":\"EUR\",\"ipAddress\":\"0.0.0.0\",\"ipCountry\":\"\",\"cdata1\":\"212707\",\"cdata2\":\"878744\",\"cdata3\":\"1656177\",\"cdata4\":\"\",\"cdata5\":\"\",\"cdata6\":\"\",\"cdata7\":\"\",\"cdata8\":\"\",\"cdata9\":\"\",\"cdata10\":\"\",\"eci\":\"9\",\"paymentProduct\":\"mastercard\",\"paymentMethod\":{\"pan\":\"545454******5454\",\"cardHolder\":\"ALEX OAK\",\"token\":\"5d******63\",\"issuer\":\"TREE BANK, THE\",\"brand\":\"MASTERCARD\",\"country\":\"US\",\"cardExpiryMonth\":\"12\",\"cardExpiryYear\":\"2025\"},\"fraudScreening\":{\"scoring\":\"0\",\"result\":\"not_launched\",\"review\":\"\"}}}}" } ] }, "webhook_id":"e45a778a-12b5-49fd-8646-28d127ba68f8", "object_payload_signature":"KuAWRSGPPEIwLmMuowh5cxxEucsyAri3zIH4ZxwsDTM=" } ``` ::: ### `payin.cancel` ::: code-group ```json [JSON] { "webhook":"payin.cancel", "object_id":"248c79b7-fc5e-5c32-96b3-c434fd0d2639", "object":"payin", "object_payload":{ "payins":[ { "payinId":"248c79b7-fc5e-5c32-96b3-c434fd0d2639", "payinTag":"", "walletId":"878744", "userId":"1656177", "payinStatus":"CANCELED", "paymentMethodId":25, "messageToUser":"", "subtotalItems":"0.00", "subtotalServices":"0.00", "subtotalTax":"0.00", "amount":"20", "currency":"EUR", "createdDate":"2021-09-17T09:32:49+00:00", "walletEventName":"Wallet", "walletAlias":"alias", "userFirstname":"Louis", "userLastname":"Pinsard", "codeStatus":"150113", "informationStatus":"The financial institution refused to authorize the payment.", "refundAmount":null, "ibanId":null, "ibanFullname":null, "DbtrIBAN":null, "ibanBic":null, "ibanTxEndToEndId":null, "ibanTxId":null, "forwardUrl":null, "paymentAcceptedUrl":null, "paymentRefusedUrl":null, "paymentWaitingUrl":null, "paymentExceptionUrl":null, "paymentCanceledUrl":null, "payinDate":"2021-09-17T11:32:49+02:00", "mandateId":"0", "creditorName":null, "creditorAddressLine":null, "creditorCountry":null, "creditorIban":null, "creditorBIC":null, "virtualIbanId":null, "virtualIbanReference":null, "additionalData":{ "card":{ "externalProvider":{ "transaction_reference":"mock_385371f00f004d42" } } } } ] }, "webhook_id":"d6d58cd7-46d6-4159-bab6-48cae27a1a6a", "object_payload_signature":"Ze1KRBH5EzV+56h9LCq048ECU3WiXiIPxrFJDgPBWA0=", "auth_key":"true" } ``` ::: ## PayinRefund ### `payinrefund.create` ::: code-group ```json [JSON] { "webhook":"payinrefund.create", "webhook_created_at":16426047629673, "object_id":"b457966e-6cf9-5d1d-8483-45425cfc8101", "object":"payinrefund", "object_payload":{ "payinrefunds":[ { "payinrefundId":"b457966e-6cf9-5d1d-8483-45425cfc8101", "payinrefundTag":null, "payinrefundStatus":"PENDING", "payinrefundDate":"2022-01-19 16:06:01", "walletId":"971021", "payinId":"29b4e8a8-0abc-5a24-8405-808c5eb34835", "amount":"5", "currency":"EUR", "createdDate":"2022-01-19 16:04:11", "modifiedDate":"2022-01-19 16:06:00", "userId":"1778843", "codeStatus":"150124", "informationStatus":"A refund request has been sent to the financial institution.", "reasonTms":null } ] }, "webhook_id":"935260ff-dd91-466c-9148-f27364db0857", "object_payload_signature":"oFj6BWt8N4dSU7j6lamfBJoxqS0l1AczQzbRvyBwTY4=", "auth_key":"true" } ``` ::: ### `payinrefund.update` ::: code-group ```json [JSON] { "webhook":"payinrefund.update", "webhook_created_at":16426049523256, "object_id":"b457966e-6cf9-5d1d-8483-45425cfc8101", "object":"payinrefund", "object_payload":{ "payinrefunds":[ { "payinrefundId":"b457966e-6cf9-5d1d-8483-45425cfc8101", "payinrefundTag":null, "payinrefundStatus":"VALIDATED", "payinrefundDate":"2022-01-19 16:09:09", "walletId":"971021", "payinId":"29b4e8a8-0abc-5a24-8405-808c5eb34835", "amount":"5", "currency":"EUR", "createdDate":"2022-01-19 16:04:11", "modifiedDate":"2022-01-19 16:09:07", "userId":"1778843", "codeStatus":"150126", "informationStatus":"The payment was partially refunded.", "reasonTms":null } ] }, "webhook_id":"e81865f8-4258-488c-b960-28035fa5c665", "object_payload_signature":"76H1+eZsgCU\/2VrhUOES0CgFQARZPRCXX6b\/NCv2sAg=", "auth_key":"true" } ``` ::: ### `payinrefund.cancel` ::: code-group ```json [JSON] { "webhook":"payinrefund.cancel", "webhook_id":"701629730", "object":"payinrefund", "object_id":"7dd5d61b-22db-404f-9899-d473109a6aad", "object_payload":{ "payinrefunds":[ { "payinrefundId":"7dd5d61b-22db-404f-9899-d473109a6aad", "payinrefundTag":null, "payinrefundStatus":"CANCELED", "walletId":"366026", "payinId":"6455658", "payinrefundDate":"0000-00-00", "amount":"921.00", "currency":"EUR", "createdDate":"2021-05-10 09:20:07", "modifiedDate":"2021-06-01 11:30:11", "codeStatus":"170003", "informationStatus":"", "reasonTms":null } ] }, "object_payload_signature":"pdbm9lmV2Q5ggl4EAugoT4\/HWGScmS6umv251CsBn0A=" } ``` ::: ## Chargeback ### `card.acquiring.chargeback.create` ::: code-group ```json [JSON] { "webhook":"card.acquiring.chargeback.create", "object_id":"0b1787dc-02f6-5c6f-a559-cb033d6890a0", "object":"card.acquiring", "object_payload":{ "chargebacks":[ { "userId":"1656177", "walletId":"878744", "payinId":"be17c043-9287-50b2-8fb2-188546dfc72a", "transactionReference":"10", "payinrefundId":"0b1787dc-02f6-5c6f-a559-cb033d6890a0", "payinMethodId":25, "paymentBrand":"mastercard", "currency":"EUR", "amount":"20", "country":"CA", "isRefunded":false, "chargebackReason":"", "payinCreatedDate":"2021-08-10 15:33:50", "chargebackCreatedDate":"2021-08-16 11:38:45", "payinRefundCreatedDate":null } ] }, "webhook_id":"48902d9b-bb04-4698-ae26-46ba6fb6233c", "object_payload_signature":"HDkynjtisOCPOcHeD8t7Kz6Le+UBBEvjmrBJTBGPESU=", "auth_key":"true" } ``` ::: --- --- url: /guide/acquiring/introduction.md description: >- Understand Treezor card acquiring; how to process third-party card payments to credit a Wallet and explore common topup use cases. --- # Introduction Card Acquiring involves capturing funds from a third-party card to credit a Treezor [Wallet](/guide/wallets/introduction). Treezor relies on HiPay as a payment service provider (PSP) for card acquiring. It is compatible with various [payment products](#payment-products-specificities) such as CB, Visa, and Mastercard. **Feature activation – Acquiring is not enabled by default** Please contact Treezor to obtain your [HiPay credentials](#hipay-environments-credentials) and to activate your [payment products](#payment-products-specificities). Treezor supports two versions of Acquiring. While this documentation mainly focuses on the newest version, you may find information specific to the in the corresponding [Legacy flow](./legacy-v1) article. ## Use cases The Card Acquiring feature can be used in the following use cases. | Use case | Description | | --- | --- | | **Top-up** | The end user credits their Treezor Wallet by using their external account payment card. In such cases, the end user can credit their wallet either: Occasionally – Single payment made to credit the Treezor Wallet.Periodically – Recurring payments to credit the Wallet at regular intervals. | | **Complement** | When the end user doesn't have enough funds on their Treezor Wallet to make the payment, they may complement the payment with funds captured on their external account payment card. This use case requires the "recurring" mode. | ## HiPay environments & credentials HiPay provides 2 environments: *Staging* (sandbox) and *Production*. Each environment has its own set of credentials (public and private) that Treezor provides to you. Your public credentials are to be base64-encoded before being used in the Authorization header of your requests (basic access authentication). You may replace the values in the code snippets of this documentation as follows: | Value | URLs | | --- | --- | | `{hiPayBaseUrl}` | Staging: `https://stage-secure-gateway.hipay-tpp.com/`Production: `https://secure-gateway.hipay-tpp.com/` | | `{hiPayTokenizationFormBaseUrl}` | Staging: `https://stage-api.hipay.com/` Production: `https://api.hipay.com/` | | `{hiPayTokenizationBaseUrl}` | Staging: `https://stage-secure2-vault.hipay-tpp.com/`Production: `https://secure2-vault.hipay-tpp.com/` | HiPay also provides 2 dashboards: * Staging: * Production: **Tip – Test cards available** Because HiPay's staging environment and Treezor's sandbox are linked, you can use [HiPay's test cards](https://support.hipay.com/hc/en-us/articles/213882649-How-can-I-test-payment-methods) in Sandbox. ## Payment products specificities Below are the specific details for each payment product. | `paymentProduct` | Mandatory attributes | End user forwarding | Advanced capture | Refunds | |--- |:---: |:---: |:---: |:---: | | `mastercard` | `topupCardId` | | | | | `visa` | `topupCardId` | | | | | `cb` | `topupCardId` | | | | | `maestro` | `topupCardId` | | | | | `bcmc` | `topupCardId` | | | | | `sofort-uberweisung` | ∅ | To `forwardUrl` | | | | `ideal` | `issuerBankId` | To `forwardUrl` | | | ## Endpoints | Endpoint | [Scope](/guide/api-basics/authentication#available-scopes) | | --- | --- | | [`/v1/topups/cards/users/{userId}/topupCards`](/api-reference/api-endpoints.html#tag/Acquiring%20\(Card%20Topups\)/postTopupCard){target="\_self"} Associate a tokenized topup card to a user | `read_write` | | [`/v1/topups/cards/users/{userId}/topupCards`](/api-reference/api-endpoints.html#tag/Acquiring%20\(Card%20Topups\)/getTopupCards){target="\_self"} Search topup cards for a given user | `read_only` | | [`/v1/topups/cards/users/{userId}/topupCards/{topupCardId}`](/api-reference/api-endpoints.html#tag/Acquiring%20\(Card%20Topups\)/getTopupCard){target="\_self"} Retrieve information about a topup card | `read_only` | | [`/v1/topups/cards/users/{userId}/topupCards/{topupCardId}`](/api-reference/api-endpoints.html#tag/Acquiring%20\(Card%20Topups\)/deleteTopupCard){target="\_self"} Cancel a topup card | `read_write` | | [`/v1/topups/cards/authorizations`](/api-reference/api-endpoints.html#tag/Acquiring%20\(Card%20Topups\)/postAcqAuth){target="\_self"} Create a card topup authorization | `read_write`| | [`/v1/topups/cards/authorizations/{authorizationId}`](/api-reference/api-endpoints.html#tag/Acquiring%20\(Card%20Topups\)/getAcqAuth){target="\_self"} Retrieve a card topup authorization | `read_only` | | [`/v1/topups/cards/authorizations/{authorizationId}`](/api-reference/api-endpoints.html#tag/Acquiring%20\(Card%20Topups\)/deleteAcqAuth){target="\_self"} Delete a card topup authorization | `read_write` | | [`/v1/topups/cards/authorizations/{authorizationId}/payins`](/api-reference/api-endpoints.html#tag/Acquiring%20\(Card%20Topups\)/postAcqAuthPayin){target="\_self"} Create payin from an authorization | `read_write` | | [`/v1/topups/cards/authorizations/{authorizationId}/payins`](/api-reference/api-endpoints.html#tag/Acquiring%20\(Card%20Topups\)/getAcqAuthPayins){target="\_self"} List all payins from an authorization | `read_only` | | [`/v1/topups/cards/refunds/{refundId}`](/api-reference/api-endpoints.html#tag/Acquiring%20\(Card%20Topups\)/acquiringv2-topup-cards-refunds-get){target="\_self"} Retrieve a card topup payin refund | `read_only` | | [`/v1/topups/cards/refunds`](/api-reference/api-endpoints.html#tag/Acquiring%20\(Card%20Topups\)/acquiringv2-topup-cards-refunds-post){target="\_self"} Create a card topup payin refund | `read_write` | | [`/v1/topups/cards/chargebacks/{chargebackId}`](/api-reference/api-endpoints.html#tag/Acquiring%20\(Card%20Topups\)/acquiringv2-topup-cards-chargebacks-get){target="\_self"} Retrieve a card topup payin chargeback | `read_only` | **Reading – Learn more about Acquiring** * [HiPay official API](https://developer.hipay.com/online-payments/overview) * [HiPay best practices](https://treezor.zendesk.com/hc/en-us/articles/360015946959-HiPay-Best-practices) * [Recurring Payins](https://treezor.zendesk.com/hc/en-us/articles/360017100639-HiPay-PayIn) * [Sentinel profile](https://treezor.zendesk.com/hc/en-us/articles/360017474380-What-is-Sentinel-Hipay) * [3DS Strong authentication](https://treezor.zendesk.com/hc/en-us/articles/360017648859-DSP2-Strong-customer-authentication-and-3DSv2) --- --- url: /guide/cards/introduction.md description: >- Get a foundational understanding of the Treezor API card issuing, your card program and customization. Includes the card object key attributes, JSON structure, and related endpoints list. --- # Introduction Treezor allows you to issue both Physical and Virtual Cards. This section focuses on Card creation and management. Before starting to issue Cards, you must have a [Card Program](#card-program) set up with Treezor. **Information – Card Top-up feature also available** If you're looking to receive card payments to credit a Wallet, see the [Card Acquiring](/guide/acquiring/introduction) section of the documentation. ## Card Program Your Card Program defines the design and configuration of the issued Cards. Your *Welcome Pack* provided by Treezor contains all the forms to fill in. Card Programs require assistance from Treezor teams. Contact your Treezor: * **Account Manager** to [define the design your cards](#card-design). * **Implementation Manager** to [define configuration and customization options](#card-product-customization-options). Once your Card Program is set up, Treezor will give you your `cardPrint`. This value is the unique identifier of you Card Program and is required to [create Cards](creation). ### Card Design You can design both your cards and their shipping packaging. Your *Welcome Pack* contains forms and templates for [Physical Cards](creation#physical-card-creation) and [Virtual Cards](creation#virtual-card-creation) design, along with resources to design your cards while abiding by: * The guidelines provided by the schemes (e.g., Mastercard, Visa, etc.). * The predefined formats from the card printing third-party. ### Card Product & Customization options Your Card Product defines options such as [Permissions Group](/guide/cards/restrictions-limits#permission-groups-permsgroup) and default limits for the Cards you issue. You can also add logos, customized text, and specify packaging and card design on a per-Card basis. See the [Customization](/guide/cards/creation#customization) article for more information. ## Key attributes Below are some of the most important Card attributes. | Attribute | Type | Description | |--- |--- |--- | | `isLive` | integer | The activation status of the Card. Cards are issued as inactive and are activated using the [dedicated request](./creation#activation). `0` – Not activated yet`1` – Activated | | `statusCode` | integer | The [current Card status](#card-status-statuscode) such as active, stolen, temporarily or permanently blocked. | | `pinTryExceeds` | integer | Indicates if the PIN try limit has been exceeded (when set to `1`, the PIN is blocked). | | `cardDesign` | string | The Card Print Id, the design that is/will be printed on the Card. | | `optionAtm` | integer | The ability to make [withdrawals at ATM](/guide/cards/restrictions-limits#payment-withdrawal-limits). | | `optionForeign` | integer | The ability to use the Card [outside the user's country](/guide/cards/restrictions-limits#options-permission-groups). | | `optionOnline` | integer | The ability to use the Card for [online Payments](/guide/cards/restrictions-limits#options-permission-groups). | | `optionNfc` | integer | The ability to use the Card for [contactless payment](/guide/cards/restrictions-limits#options-permission-groups). | | `embossedName` | string | The cardholder's name, as embossed or etched on the Card. | | `maskedPan`| string | The [PAN](/guide/overview/glossary#primary-account-number-pan) with the middle numbers redacted for safety. | | `publicToken` | string | 9-character long string printed on the Card. It can be used to [activate a card](./creation#activation). | **API – API Reference available** For a complete list of Card attributes, check the [Cards](/api-reference/api-endpoints.html#tag/Cards){target="\_self"} section of the API Reference. ### Card Status (`statusCode`) Statuses are defined in the `statusCode` attribute of a Card. ## Card object ::: code-group ```json [JSON] { "cardId": 0, "userId": 0, "walletId": 0, "walletCardtransactionId": 0, "mccRestrictionGroupId": 0, "merchantRestrictionGroupId": 0, "countryRestrictionGroupId": 0, "publicToken": "string", "cardTag": "string", "statusCode": "UNLOCK", "isLive": 0, "pinTryExceeds": 0, "maskedPan": "string", "embossedName": "string", "expiryDate": "string", "CVV": "string", "startDate": "string", "endDate": "string", "countryCode": "string", // Inherited from the User's country "currencyCode": "string", // Always EUR "lang": "string", // Inherited from the User's language "deliveryTitle": "string", "deliveryLastname": "string", "deliveryFirstname": "string", "deliveryAddress1": "string", "deliveryAddress2": "string", "deliveryAddress3": "string", "deliveryCity": "string", "deliveryPostcode": "string", "deliveryCountry": "string", "mobileSent": "string", // Inherited from the User's phone "limitsGroup": "string", "permsGroup": "string", "cardDesign": "string", "virtualConverted": 0, "optionAtm": 0, "optionForeign": 0, "optionOnline": 0, "optionNfc": 0, "limitAtmYear": 0, "limitAtmMonth": 0, "limitAtmWeek": 0, "limitAtmDay": 0, "limitAtmAll": 0, "limitPaymentYear": 0, "limitPaymentMonth": 0, "limitPaymentWeek": 0, "limitPaymentDay": 0, "limitPaymentAll": 0, "paymentDailyLimit": 0, "totalAtmYear": 0, "totalAtmMonth": 0, "totalAtmWeek": 0, "totalAtmDay": 0, "totalAtmAll": 0, "totalPaymentYear": 0, "totalPaymentMonth": 0, "totalPaymentWeek": 0, "totalPaymentDay": 0, "totalPaymentAll": 0, "createdBy": 0, "createdDate": "string", "modifiedBy": 0, "modifiedDate": "string", "renewalType": "string", "renewalDate": "string", "originalCardId": 0, "totalRows": 0, "designCode": "string", "cardLanguages": "string", "eventName": "string", // Inherited from the Wallet the card is attached to "eventAlias": "string", // Inherited from the Wallet the card is attached to "restrictionGroupLimits": [ { "paymentDailyLimit": 0, "mccRestrictionGroups": 0, "countryRestrictionGroups": 0, "merchantIdRestrictionGroups": 0 } ], "cancellationNumber": "string", "metadata": "string", "renewalDate": "string", "renewalType": "string", "originalCardId": 0, "logoId": "string", "logoBackId": "string", "packageId": "string", "customizeInfo": "string", "letterCustomizedInfo": "string", "freeCustomizedInfo": "string", "deliveryMethod": 0, "pinMailer": 0, "batchDeliveryId": 0, "sendToParent": 0 } ``` ::: ## Endpoints | Endpoint |[Scope](/guide/api-basics/authentication#available-scopes) | | --- | --- | | [`/v1/cards/CreateVirtual`](/api-reference/api-endpoints.html#tag/Cards/postCardVirtual){target="\_self"} Create a new Virtual Card | `read_write` | | [`/v1/cards/RequestPhysical`](/api-reference/api-endpoints.html#tag/Cards/postCardPhysical){target="\_self"} Request a new Physical Card | `read_write` | | [`/v1/cards/Register3DS`](/api-reference/api-endpoints.html#tag/Cards/post3ds){target="\_self"} Register a Card for 3D Secure | `read_write` | | [`/v1/cardimages`](/api-reference/api-endpoints.html#tag/Cards/getCardImage){target="\_self"} Retrieve a Virtual (or Virtual converted) Card image | `read_write` | | [`/v1/cards`](/api-reference/api-endpoints.html#tag/Cards/getCards){target="\_self"} Search Cards | `read_only` | | [`/v1/cards/{cardId}`](/api-reference/api-endpoints.html#tag/Cards/getCard){target="\_self"} Retrieve a Card using its `id` | `read_only` | | [`/v1/cards/{cardId}`](/api-reference/api-endpoints.html#tag/Cards/putCard){target="\_self"} Update a Card information | `read_write` | | [`/v1/cards/{cardId}/Activate`](/api-reference/api-endpoints.html#tag/Cards/activateCard){target="\_self"} Activate a Card initially | `read_write` | | [`/v1/cards/{cardId}/Assign`](/api-reference/api-endpoints.html#tag/Cards/reassignCard){target="\_self"} Assign or Reassign a Card to a User | `read_write` | | [`/v1/cards/{cardId}/ChangePIN`](/api-reference/api-endpoints.html#tag/Cards/changePin){target="\_self"} Change a PIN (requires to know the previous one) | `read_write` | | [`/v1/cards/{cardId}/setPIN`](/api-reference/api-endpoints.html#tag/Cards/setPin){target="\_self"} Define a PIN code | `read_write` | | [`/v1/cards/{cardId}/UnblockPIN`](/api-reference/api-endpoints.html#tag/Cards/unblockPin){target="\_self"} Unblock a PIN code | `read_write` | | [`/v1/cards/{cardId}/ConvertVirtual`](/api-reference/api-endpoints.html#tag/Cards/convertVirtual){target="\_self"} Convert a Virtual Card to a Physical one | `read_write` | | [`/v1/cards/{cardId}/Limits`](/api-reference/api-endpoints.html#tag/Cards/putLimits){target="\_self"} Change a Card limits | `read_write` | | [`/v1/cards/{cardId}/Options`](/api-reference/api-endpoints.html#tag/Cards/cardOptions){target="\_self"} Change a Card options | `read_write` | | [`/v1/cards/{cardId}/LockUnlock`](/api-reference/api-endpoints.html#tag/Cards/updateBlockStatus){target="\_self"} Toggle the locking status of a Card | `read_write` | | [`/v1/cards/{cardId}/Regenerate`](/api-reference/api-endpoints.html#tag/Cards/regenerateCard){target="\_self"} Regenerate a Virtual Card image | `read_write` | If you have migrated to the [PCI DSS services](./pci-dss), please note some endpoints have been replaced. See the list of [PCI DSS-specific endpoints](./pci-dss#pci-dss-endpoints) for more information. ## Object relations diagram --- --- url: /guide/cheques/introduction.md description: >- Get a foundational understanding of Treezor check cash-in feature. Includes key attributes, JSON structure, and related endpoints list. --- # Introduction Treezor allows your end users to [cash checks](cashing). Checks are a traditional means of physical payment, mapped to `Payin` objects, with a `paymentMethodId` attribute set to `26`. **Configuration – Checks are not enabled by default** You can request access to this feature by contacting your *Treezor Account Manager*. **Important – Limitations** * Recipient name on the check must match the Wallet owner name. * Maximum amount set by Treezor. Contact your *Treezor Account Manager* to define your limit. ## Process Check cashing into a Wallet implies the creation of the relevant object in Treezor API and the physical handling of checks so that they can be processed. ```mermaid sequenceDiagram autonumber participant app as You participant trz as Treezor app->>trz: Create a Payin for the check trz->>app: Sends a payin.create webhook (status 160001)
While waiting for aknowledgement trz->>app: Sends a payin.create webhook (status 160003)
Once the check can be mailed app->>trz: Send the physical check within 14 days trz->>trz: Check processing trz->>app: Sends a payin.update webhook (status 140005 for VALIDATED) ``` The steps are the following: 1. You create a Payin (`paymentMethodId` `26`) 2. Treezor sends a [`payin.create`](/guide/cheques/events) webhook (status `160001`) confirming the creation 3. Treezor sends a [`payin.create`](/guide/cheques/events) webhook (status `160003`) allowing you to mail the check in 4. You mail in the physical check to the indicated postal address 5. The check is processed by Treezor's partner and is either: * **Accepted** – The [`payinStatus`](/guide/cheques/introduction#status-payinstatus) is set to `VALIDATED` * **Refused** – The [`payinStatus`](/guide/cheques/introduction#status-payinstatus) is set to `CANCELED` and the check is mailed back to you. The processing of a check follows strict delays: * Delay between the check Payin creation and physical check reception can't exceed **14 days** * Delay between the physical check reception and the validation can't be lower than **11 days** **Tip – Check life cycles examples are available** Refer to the [Life cycle](./cashing#life-cycle) section for more information. ## Anatomy of a check The physical check contains information that you have to include in the corresponding Payin object. | Section | Description | | --- | --- | | **CMC7 line** | The unique identifier of the physical check printed in magnetic ink at the bottom of the check. Made up of: **CMC7A** – The first part of the CMC7 line**CMC7B** – The second part of the CMC7 line**CMC7C** – The third part of the CMC7 line | | **RLMC key** | The 2-character key, enclosed by `<>` or `()` used to check the integrity of the CMC7 line (%97.) | | **Drawer** | Information about the user who emitted the check. | | **Beneficiary** | The user who receives the check and cashes it. | ## Key attributes Checks rely on the Payin object. Below are some of the relevant Payin attributes when it comes to cashing checks. | Attribute | Type | Description | |--- |--- |--- | | `paymentMethodId` | integer | The payment method. For checks, this value is always `26`. | | `payinStatus` | string | The status of the check cashing process. May be one of the following: `PENDING` – Waiting for payment`VALIDATED` – Payment is validated`CANCELED` – Payment is canceled | | `amount` | number | The [amount](/guide/api-basics/data-format#amounts) of the check. | | `currency` | string | The [currency](/guide/api-basics/data-format#currencies) of the check. | | `additionalData` | object | Contains the cmc7 line, the drawer data and the RLMC key of the check. | **API – API Reference available** Refer to the [Payins](/api-reference/api-endpoints.html#tag/payins){target="\_self"} section in the API Reference for a complete list of Checks attributes. ### Additional Data (`additionalData`) The `additionalData` object allows you to provide information that is available on the physical check. ::: code-group ```json [JSON] "additionalData": { "cheque":{ "cmc7" : { "a":"000036", // required, 1st section of CMC7 line "b":"0230021566985", // required, 2nd section of CMC7 line "c":"00700065456" // required, 3rd section of CMC7 line }, "RLMCKey":"22", // required, RMLC key "drawerData":{ // required object "isNaturalPerson" : true, // required, boolean, true: physical / false: legal entity "email":"aoak@example.com", // drawer's email "firstName" : "Alex", // drawer's firstname "lastName" : "Oak", // drawer's lastname "address" : "22 Rosewood Lane", // drawer's address "address2" : "App. 12", // drawer's address continued "zipCode" : "75001", // drawer's postcode "city" : "Paris" // drawer's city } } } ``` ::: ### Status Codes (`codeStatus`) | Code | Description | |- |- | | 140004 | The cheque Payin has been cancelled before the reception at the treatment center. | | 140005 | Funds received by Treezor. Payin is validated and funds are usable on the wallet. | | 160001 | Waiting for treatement center aknowledgement | | 160002 | The treatement center aknowledgement failed| | 160003 | The cheque can now be sent to the treatement center | | 151125 | The controls of the cheque have failed. | | 151129 | Cheque has been successfully treated. Waiting for bank settlement | | 151130 | Payment is in the 11 working days delay period, to prevent bounced cheques. | | 151132 | The check has been received by the treatment center of our partner. | | 151134 | The check has not been received by the treatement center in the allowed delay of 14 calendar days | | 151136 | Check rejected | | 170001 | Refund request | | 170005 | Refund validated |  ## Check payin object ::: code-group ```json [JSON] { "payinId": "2xxxxx1", "payinTag": "", "walletId": "3xxxx4", "userId": "1xxxx2", "payinStatus": "CANCELED", "paymentMethodId": "26", "messageToUser": "", "subtotalItems": "0.00", "subtotalServices": "0.00", "subtotalTax": "0.00", "amount": "195.00", "currency": "EUR", "createdDate": "2020-09-22 12:43:14", "walletEventName": "Name Test", "walletAlias": "Alias Test", "userFirstname": "TEST Chèque", "userLastname": "", "codeStatus": "151128", "informationStatus": "Cheque cannot be treated amount is too low comparing to original demand", "refundAmount": null, "DbtrIBAN": null, "forwardUrl": null, "paymentAcceptedUrl": null, "paymentRefusedUrl": null, "paymentWaitingUrl": null, "paymentExceptionUrl": null, "paymentCanceledUrl": null, "payinDate": "0000-00-00", "mandateId": "0", "creditorName": null, "creditorAddressLine": null, "creditorCountry": null, "creditorIban": null, "creditorBIC": null, "virtualIbanId": null, "virtualIbanReference": null, "additionalData": { "cheque":{ "cmc7":{ "a":"5xxxxx1", "b":"0xxxxxxxxxx8", "c":"1xxxxxxxxxx4" } "RLMCKey": "xx", "drawerData":{"isNaturalPerson":false} } } } ``` ::: ## Endpoints | Endpoint | [Scope](/guide/api-basics/authentication#available-scopes) | | --- | --- | | [`/v1/payins`](/api-reference/api-endpoints.html#tag/Payins/postPayin){target="\_self"} Create a check payin | `read_write` | | [`/v1/payins`](/api-reference/api-endpoints.html#tag/Payins/getPayins){target="\_self"} Search for check payins | `read_only` | | [`/v1/payins/{payinId}`](/api-reference/api-endpoints.html#tag/Payins/getPayin){target="\_self"} Retrieve a check payin using its `id` | `read_only` | | [`/v1/payins/{payinId}`](/api-reference/api-endpoints.html#tag/Payins/deletePayin){target="\_self"} Delete a check payin | `read_write` | --- --- url: /guide/strong-customer-authentication/introduction.md description: >- Learn about Strong Customer Authentication (SCA), a European regulatory requirement, and its implementation with Treezor services for secure payments. --- # Introduction [Strong Customer Authentication (SCA)](https://en.wikipedia.org/wiki/Multi-factor_authentication) is a European regulatory requirement aiming at reducing fraud and making payments more secure. Because you're using Treezor ACPR agreement, you must implement SCA into your user flow by declaring SCA either: * [With Treezor services](/guide/strong-customer-authentication/securing-endpoints#applying-sca-with-treezor-services) for Treezor endpoints falling into SCA functional context and/or * [Outside Treezor services](/guide/strong-customer-authentication/securing-endpoints#declaring-sca-external-operations) for any sensitive operation made from your back end. ## Key concepts A defined set of user actions requires Strong Customer Authentication, either by session or by operation. | Context | Description | |---|---| | [**Per session**](#per-session-authentication-main-steps) | When logging-in, the User is required to authenticate with SCA. This allows for some follow-up actions without an additional SCA. | | [**Per operation**](#per-operation-authentication-main-steps) | When doing a sensitive operation, the User is required to use SCA to confirm it, even if they already went through strong authentication when logging-in. | To ensure a Strong Customer Authentication, we use at least 2 of the following 3 elements: * Something the User **has** (smartphone, hardware token) * Something the User **is** (fingerprint, facial identification) * Something the User **knows** (password, PIN) In a nutshell, SCA aims to prove that the operation effectively originates from the User by: 1. **Generating a cryptographic signature** known as SCA Proof (JWS) of the requested operation on the User's device. 2. **Sending this SCA proof** to the Treezor API along with the usual operation request (e.g., creating a Beneficiary). 3. **Checking the received SCA proof** by the Treezor API and only allowing operation if legitimate. Treezor relies on a digital safe containing a private key necessary for Strong Customer Authentication: the [SCA Wallet object](#sca-wallet-object). ### SCA authentication flow The following diagram illustrates what is required of your app and back end to enforce Strong Customer Authentication. **Information – The diagram is not exhaustive, it doesn't cover:** * The notion of [session expiration](#sessions) * The necessity of a [strong authentication every 180 days](#per-session) ```mermaid sequenceDiagram participant app as Your app participant agent as Your back end participant trz as Treezor Note over app: Generate an SCA Proof (JWS) using the SDK
(either of type None, Biometry or Passcode)
or using WebAuthn app->>agent: End User logs in to your API Note over app, agent: Forward the SCA proof (JWS) agent->>trz: Authentication using delegated_end_user Note over agent, trz: Forward the SCA proof (JWS) trz->>agent: Returns a JWT Note over agent: Store this JWT and associate it to the User
as it can only be used on behalf of this User loop For each call to Per-Session endpoints app->>agent: End User wants to do some Per-Session requests Note over agent: Retrieve the User's JWT from your database
Do not request a new JWT from Treezor if yours hasn't expired agent->>trz: Call the relevant endpoint Note over agent, trz: Place the JWT in the "Authorization:" header trz->>agent: Response agent->>app: Response end loop For each call to Per-Operation endpoints app->>agent: End User wants to do some Per-Operation requests Note over app: Generate an SCA Proof (JWS)
using the SDK or
using WebAuthn
The proof must sign the relevant parameters (payload) of the request Note over app, agent: Forward the SCA proof (JWS) Note over agent: Retrieve the User's JWT from your database
Do not request a new JWT from Treezor if yours hasn't expired agent->>trz: Call the relevant endpoint Note over agent, trz: Place the JWT in the "Authorization:" header %Note over agent, trz: Place the JWS in the "X-SCA-Authorization:" header Note over agent, trz: Forward the SCA proof (JWS) trz->>agent: Response agent->>app: Response end ``` #### Per Session authentication main steps For other requests to the Treezor API. ::: details 1. You request an SCA proof. This can be done using the [SDK](sdk) or [Web Native](#web-native) solution. ::: ::: details 2. You provide the SCA proof when authenticating against the Treezor API. The SCA proof is passed as a header parameter of your authentication request. ::: ::: details 3. Treezor checks the signature. | Signature | SCA type | Treezor returns | | --- | --- | --- | | **Valid** | Other than `None` | Treezor returns a JWT (`trz:sca` valued to `true`) | | **Valid** | `None` | Treezor returns a JWT (`trz:sca` valued to `false`). | | **Invalid** | N/A | N/A, no JWT is delivered | ::: ::: details 4. You authenticate all future requests using the obtained JWT. * [Per Session requests](/guide/strong-customer-authentication/securing-endpoints#active-session-actions) will be accepted if the JWT: * Contains `trz:sca` = `true` and * Has been obtained less than 5 minutes ago * Has been used to make any type of valid request * [Per Session requests **with 180 days exemption**](/guide/strong-customer-authentication/securing-endpoints#passive-session-actions) regardless of the `trz:sca` value and inactivity (as long as the JWT itself hasn't expired). ::: #### Per Operation authentication main steps When a request to the Treezor API [mandates a per-operation SCA](/guide/strong-customer-authentication/securing-endpoints#individual-actions): ::: details 1. You prepare the necessary API payload for the desired endpoint. This step is the same as for any endpoint. ::: ::: details 2. You sign the payload using the User's private key. This produces a unique signature (using [the SDK](sdk#mobile-sdk) or [Web Native](#web-native)). ::: ::: details 3. You send the payload along with the signature to the Treezor API. * For requests using `GET`, `DELETE` you add the signature as a `sca` query parameter * For requests using `PUT`, `POST` you add the signature as a `sca` body parameter ::: ::: details 4. Treezor checks the payload against the provided signature and the User's public key. * If the signature is **valid**, the request is handled by Treezor * If the signature is **invalid or missing**, the request is rejected by Treezor with a `400` Status Code ::: ## SCA solutions Treezor offers mobile and web native solutions for you to produce the cryptographic signatures necessary for Strong Customer Authentication: | Solution | Description | | --- | --- | | **[Mobile Abstraction Layer](sdk-abstraction)** | React abstraction layer wrapping the Mobile SDK. | | **[Mobile Flutter Bridge](#mobile-flutter-bridge)** | Bridge exposing the same methods and interfaces as the Mobile SDK, in Flutter. | | **[Mobile SDK](sdk)** | SDK providing SCA wallet functionality, device eligibility checks, and cryptographic signature generation for strong authentication. | | **[Web Native](#web-native)** | Solution to generate SCA proofs within a web browser for use cases without a mobile app. | ### Mobile Abstraction Layer Treezor provides a React abstraction layer that lives above the [Mobile SDK](sdk). This wrapper allows you to implement SCA features more easily than via the SDK directly. **Prerequisites:** * Import `react-native-treezor-sca` using credentials provided by Treezor. * Import `bridge-reactNative-{version}` provided to you encrypted using GPG. * Using `npm install -S {package}` or `yarn add {package}`. Learn more in the dedicated [Mobile Abstraction Layer](sdk-abstraction) article. ### Mobile Flutter Bridge Treezor provides a Flutter bridge which exposes the same methods and interfaces as the [Mobile SDK](sdk), in Flutter. To use it you have to specify the following dependency in your `pubspec.yaml`. ::: code-group ```yaml[YAML] dependencies: endtrust_bridge_flutter: path: path_to_the_bridge_folder ``` ::: The bridge will be provided to you as a ZIP archive. #### Android Bridge Configuration Add the following to `android/app/build.gradle` ::: code-group ```json [JSON] android { [...] defaultConfig { [...] minSdkVersion 21 } packagingOptions { jniLibs { keepDebugSymbols += "*/*/libscm.so" useLegacyPackaging = true } } } ``` ::: ##### Metadata Add the following metadata to `android/app/src/main/AndroidManifest.xml` ::: code-group ```xml [XML] ``` ::: ##### Permissions Add the following permissions to `android/app/src/main/AndroidManifest.xml` ::: code-group ```xml [XML] ``` ::: ### Mobile SDK All the SDK features are provided through an SCA Wallet object implemented in the SDK itself. It can be seen as a base layer, gathering configuration and security settings on which Strong Customer Authentication relies. SCA Wallets are synchronized between the mobile device and Treezor back end. The main property of the SCA wallet is its state, evolving from actions triggered on the back end or on hosting app side, and defining how an SCA Wallet is accessible to the hosting app. ::: details Requirements for mobile compatibility on your end users side **Android** * Minimum supported version – Android 5.0 Lollipop (API level 21) * Target version – Tested with Android versions until Android 13 (API level 33) **iOS** * Minimum supported version – iOS 11 * Minimum supported version for pushing a Card to Apple Pay – iOS 13.4 * Swift 5 ::: Learn more in the dedicated [Mobile SDK](sdk) article. ::: details Download SDK #### Sandbox #### Production ::: ### Web Native Web-only banking scenarios can't rely on mobile app SDK for cryptography and signing. Instead, you can use the web native solution to generate SCA proofs within a web browser. It leverages public key cryptography for user authentication, achieving a security level comparable to native apps. ::: details [Copyright](https://www.w3.org/policies/) © 2023 [World Wide Web Consortium](https://www.w3.org/). All Rights Reserved. Treezor technology is built relying on [WebAuthn](https://webauthn.io/). This solution and related documentation includes materials copied or derived from the [W3C Web Authentication recommendation](https://www.w3.org/TR/webauthn/). This work is distributed under the [W3C® Software and Document License](https://www.w3.org/copyright/software-license-2023/) in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ::: #### Web Native & SCA Elements WebAuthn addresses the [SCA elements](/guide/strong-customer-authentication/introduction#key-concepts) as follows. | Element | Description | | --- | --- | | **Passkey** | Represents “something the user **has**”. | | **Passcode** | Represents “something the user **knows**”. The passcode is unique by user for all their devices, and is [encrypted](#passcode-encryption) on the user's device before transmission to Treezor. | ::: details Why is the passcode necessary? You might wonder why Treezor requires the passcode, when a smartphone might already mandate biometry to unlock the passkeys, satisfying both “something the user **has**” and “something the user **is**”. Although the conditions *may* be satisfied in this very situation, due to the multiplicity of authenticators supported by WebAuthn the passkeys may be accessed with or without biometry. **Therefore, to be SCA-compliant with every WebAuthn authenticator, Treezor requires the [encrypted passcode](/guide/strong-customer-authentication/user-enrollment#passcode-encryption) in addition to the WebAuthn generated signature**. ::: **Note – Authentication type `= None` only applies to the [SDK](sdk).** When using Web Native, the authentication is always stronger than `None` as we use “something the user **has**” (trusted browser/device) and require “something the user **knows**” (passcode). #### Requirements Web Authentication API usage requires hardware capabilities to handle cryptographic operations and keys. Unauthorized access protection can be ensured using either: * A [Trusted Execution Environment (TEE)](https://en.wikipedia.org/wiki/Trusted_execution_environment) or * A [Trusted Platform Module (TPM)](https://en.wikipedia.org/wiki/Trusted_Platform_Module) TEEs and TPMs are available on modern computers and smartphones. They can also be found in dedicated roaming hardware authenticators. When first generating their passkey, the browser prompts the User to select a storage location. The passkey storage location depends on the device capabilities and how the WebAuthn API is called. They can be one of the following: ::: details The device itself Requires the device to possess necessary cryptographic capabilities (TEE, TPM, or other hardware-based security features). ::: ::: details Roaming hardware authenticators Such as YubiKey, SoloKey, or Google Titan for instance. ::: ::: details Smartphones Utilizing a QR code displayed during the Web Native enrollment process, a smartphone can scan the code to assist in the key pair generation and storage process. This last method leverages the smartphone security features to extend Web Native reach beyond the first two options. The smartphone can either store the key pair or assist in the authentication process by verifying the user's identity before the key pair is generated, stored, or accessed securely. Both the computer and the smartphone must have Bluetooth enabled and be connected to the internet (although they do not necessarily need to be on the same network). ::: **Reading – Matrix of device support** A comprehensive matrix detailing device support and key pair synchronization features is available at , offering developers insight into the wide array of compatible devices and their specific capabilities. ## SCA Wallet object An SCA Wallet is the secure enclave locally present on a device. Please note that this is an example of SCA Wallet object, and that some attributes such as the `activationCode` are only valorized when relevant. ::: code-group ```json [JSON] { "id": "1a73b1eca9a64cf19a448b61dd494d15", "status": "CREATED", "subStatus": "CREATED_READY", "passcodeStatus": "NOT_SET", "locked": false, "lockReasons": [], "lockMessage": null, "settingsProfile": "default", "mobileWallet": { "pushMessagingId": "c9wB0BakTaakW9vwtDIyl_:APA91bH-0-ArJEbYdV9s8m-6332wXfvO1DLYeoZzkkqasU3s-1893KdLarFdM7dJBHsb22H4lOFI4Xr_PzE9bFS2w", "productModel": "SM-A415F", "os": "ANDROID", "deviceIdType": "ANDROID_ID", "secretFingerprint": "0x83ec6a38e8cd9f12bc1ed89e771ca402048959e738943dAAAAAAAA", "lastEligibilityCheck": "2023-11-15T10:04:50Z", "nfc": true, "deviceId": "c2032a73ac90de11", "appBuildNumber": "v04-04-06-06-02-02", "productFingerprint": "samsung/a41eea/a41:12/SP1A.210812.016/A415FXX123456:user/release-keys", "mobileUpdateDate": "2023-11-15T10:04:50Z", "appleTeamId": null, "emulator": false, "pushMessagingProvider": "FIREBASE", "osVersion": "12", "root": "0", "sdkVersion": "2.4.11", "brand": "samsung" }, "activationCode": null, "creationDate": "2023-07-13T15:29:05+02:00", "deletionDate": null, "activationCodeExpiryDate": "2023-07-13T15:49:05+02:00", "authenticationMethods": [ { "type": "DEVICE_BIOMETRIC", "usages": [ "STRONG_CUSTOMER_AUTHENTICATION" ], "parameters": { "validityDuration": 60 } }, { "type": "HYBRID_PIN", "usages": [ "WALLET_MANAGEMENT", "STRONG_CUSTOMER_AUTHENTICATION" ], "parameters": { "maxAttempts": 3, "validityDuration": 60 } }, { "type": "NONE", "usages": [ "STRONG_CUSTOMER_AUTHENTICATION" ], "parameters": [] }, { "type": "CLOUD_PIN", "usages": [ "WALLET_MANAGEMENT", "STRONG_CUSTOMER_AUTHENTICATION" ], "parameters": { "maxAttempts": 3, "validityDuration": 60 } } ], "invalidActivationAttempts": null, "userId": "3400118", "scaWalletTag": "Iphone 13 mini", "clientId": "string", "activationDate": "2023-07-15T15:29:05+02:00", "lockDate":null, "unlockDate":null, "resetPinDate":null } ``` ::: ### Key attributes #### Status (`status`) | Status | Description | | --- | --- | | `CREATING` | SCA Wallet is being created | | `CREATED` | SCA Wallet has been created, but has not yet been initialized | | `INITIALIZING` | SCA Wallet is being initialized | | `ACTIVE` | SCA Wallet has been initialized and is not locked or deleted | | `DELETED` | SCA Wallet has been deleted by issuer | #### Sub Status (`subStatus`) | Sub Status | Description | | --- | --- | | `CREATING_IN_PROGRESS` | SCA Wallet is being created | | `CREATED_BLOCKED` | SCA Wallet created but may not be used yet | | `CREATED_READY` | SCA Wallet created that can be used | | `INITIALIZING_MOBILE` | SCA Wallet is being initializing by the mobile | | `ACTIVATED_LOGGED_IN` | User is logged in | | `ACTIVATED_LOGGED_OUT` | User is logged out | | `DELETED_BY_ISSUER` | SCA Wallet has been deleted by the issuer | | `DELETED_UNINSTALLED` | SCA Wallet has been deleted because the SCA wallet has been uninstalled | #### Passcode Status (`passcodeStatus`) | Passcode Status | Description | | --- | --- | | `SET` | Passcode was set by the customer | | `NOT_SET` | Passcode was not set by the customer | | `TO_BE_CHANGED` | Passcode has to be changed | | `NONE` | None | #### Locking Reasons (`lockReason`) | Lock Reason | Description | | --- | --- | | `ISSUER` | You locked the SCA Wallet (generic lock reason) | | `LOST_DEVICE` | End user declared a lost device | | `STOLEN_DEVICE` | End user declared a stolen device | | `FRAUDULENT_USE_SUSPECTED_BY_ISSUER` | You suspected a fraudulent use of the SCA Wallet | | `FRAUDULENT_USE_SUSPECTED_BY_CLIENT` | End user suspected a fraudulent use of the SCA Wallet | | `TERMINATE_SERVICE` | Your business relation with the end user was terminated | **Note – You may encounter locking reasons that can't be set manually** * `DELETED` – The SCA Wallet [was deleted](sca-wallet-lifecycle#deletion) * `PASSCODE` – The end user entered too many wrong PIN codes * `PAYMENT` – The end user entered too many wrong PIN codes during a payment SCA ## Endpoints | Endpoint | [Scope](/guide/api-basics/authentication#available-scopes) | | --- | --- | | [`/core-connect/sca/scawallets`](/api-reference/api-endpoints.html#tag/SCA/postScaWallet){target="\_self"} | `legal`, `read_write` | | [`/core-connect/sca/scawallets/swap`](/api-reference/api-endpoints.html#tag/SCA/swapSCAWallets){target="\_self"} | `read_write` | | [`/core-connect/sca/scawallets?userId={userId}`](/api-reference/api-endpoints.html#tag/SCA/getSCAWallets){target="\_self"} | `read_only` | | [`/core-connect/sca/scawallets/{scaWalletId}`](/api-reference/api-endpoints.html#tag/SCA/getScaWallet){target="\_self"} | `read_only` | | [`/core-connect/sca/scawallets/{scaWalletId}/lock`](/api-reference/api-endpoints.html#tag/SCA/putScaWallet){target="\_self"} | `legal` | | [`/core-connect/sca/scawallets/{scaWalletId}/resetPin`](/api-reference/api-endpoints.html#tag/SCA/resetScaWalletPin){target="\_self"} | `legal` | | [`/core-connect/sca/scawallets/{scaWalletId}/unlock`](/api-reference/api-endpoints.html#tag/SCA/unlockScaWallet){target="\_self"} | `legal` | | [`/core-connect/sca/setPasscode`](/api-reference/api-endpoints.html#tag/SCA/setPasscode){target="\_self"} | `read_write` | | [`/core-connect/sca/scawallets/{scaWalletId}`](/api-reference/api-endpoints.html#tag/SCA/deleteScaWallet){target="\_self"} | `legal` | --- --- url: /guide/dashboard/introduction.md description: >- Configure your Treezor experience and let your team of operators provide support to your end users through the ready-to-use Treezor Dashboard web application. --- # Introduction The Dashboard is a ready-to-use web application for your teams to use as a back office. From there, your Dashboard Users can manage your end users, hence providing support without having to develop an application or going through complex, technical-driven processes. Here is what the Dashboard can do for you: * **End users support** – Manage users, wallets, cards, and operations from the interface. * **Technical configuration** – Make subscribing to webhooks or configuring templates easier. * **Testing** – Control the results of your integration directly from your Sandbox Dashboard. * **Company account management** – Manage your own accounts in the Treezor ecosystem (keep track of operations, initiate transfers to your bank accounts, etc.). The complete list of actions you can do from the Dashboard is available in the [Dashboard User Roles](./dashboard-users#dashboard-user-roles) article. ## Accessing your Dashboard If you’ve opted for this option when starting to work with Treezor services, you have a Dashboard for each of your [environments](/guide/api-basics/environments) shared with you by your *Treezor Implementation Manager*: * **Sandbox** – `https://dashboard-{yourCompanyName}.sandbox.treezor.co` * **Production** – `https://dashboard.{yourCompanyName}.api.treezor.co` There are two ways to log in to the Dashboard for you and your teams: | Method | Description | |---|---| | [**Standard with 2FA**](#standard-login-with-2fa) | You and your team log in with a username and password. Once this done, the user also goes through 2-factor authentication (2FA). | | [**SSO Identity Provider**](#company-sso-login) | If your company has a single authentication solution for multiple applications, you can configure your Dashboard to authenticate your users with it. | **Best practice – Always use your individual account** Treezor has provided you with a technical account in the early steps of your journey. This account is to be used as a backup account only. ### Standard login with 2FA When logging in with Treezor, 2-Factor Authentication (2FA) is mandatory for security reasons. With 2FA, Dashboard Users enter: * Their username and password * A second authentication factor (biometric or PIN/password). This technology relies on a pair of cryptographic keys: a private key stored on a trusted device and a public key registered on our servers. It makes sharing accounts impossible, and only one device for a given account can hold the passkey for the second factor. #### Configuring Dashboard 2FA Available options for 2FA depend on the configuration, device, and browser, and can be: * Internal device (the one the Dashboard User uses to access the Dashboard) * External device (phone, tablet, security key) * All types of devices If needed, your *Treezor Implementation Manager* will help you configure the authentication to fit your work environment. #### Logging in with 2FA When prompted, Dashboard Users set up and provide a second authentication factor, which can be biometric (fingerprint, facial recognition) or a personal PIN/password. After entering their username and password for the first time, they must click on “Enable 2-Factor Authentication” to set up their passkey. From there, they follow the browser prompts to select their authenticator of choice based on your Dashboard configuration. Once the relevant option is selected, they can name their passkey for convenience purposes, and get back to log in. After this initial setup, the passkey is required every time the user logs in (or if the session exceeds 12 hours). If your have a Manager User Role, you can reset your users 2FA in the [Dashboard Users view](./dashboard-users). ### Company SSO login You can also use your company Single Sign-On (SSO) solution to log in to the Dashboard seamlessly. #### Configuring your SSO You need to contact Treezor to configure your SSO. Your *Treezor Implementation Manager* will ask for your SAML app configuration file (see [Google documentation](https://support.google.com/a/answer/6087519?hl=en) for example). Then, you can define a SAML key when creating your [Dashboard Users](/guide/dashboard/dashboard-users#dashboard-users). The SAML key links automatically a Dashboard User to a Dashboard OAuth2 client. #### Logging in with SSO Once the setup done, this is a straightforward experience for your Dashboard Users. ## Get to know the Dashboard Interface Let’s take a quick guided tour of the key components of the Dashboard interface. **Note – Your Dashboard is customizable** The views may differ from the screenshots displayed depending on: * Where you’re at in your integration process, if you’re customizing the design * The User Role of the logged-in user, if you’re not using all of Treezor features * Your localization and language selection --- --- url: /guide/transfers/introduction.md description: >- Get a foundational understanding of Treezor payins and payouts, whether they are wallet transfers, SEPA Direct Debits, SEPA Credit Transfers, or International Transfers. --- # Introduction A bank transfer is the movement of funds from one account to another. Therefore, for a given Treezor environment, any funds movement listed below is considered a transfer: | From | To | Object | | --- | --- | --- | | Wallet | External account | Payout | | External account | Wallet | Payin | | Wallet | Wallet (same environment) | Transfer | ## Type of transfers Treezor provides a variety of transfer options to meet different needs: * [SEPA Credit Transfers](/guide/transfers/credit-transfer) * [SEPA Instant Payments](/guide/transfers/credit-transfer-inst) * [SEPA Direct Debit](/guide/transfers/direct-debit) * [Wallet-to-Wallet](/guide/transfers/wallet-to-wallet) The prerequisites and processing differ for each type of transfer depending on the direction of the funds, the service used, and the initiator. Contact Treezor to learn which types of transfers best fit your needs among the following: | Transfer | Type | Initiator | Coverage | |------------------------------|--------|----------------------------|-----------------------| | [Emitted SEPA Direct Debit](/guide/transfers/direct-debit#emitted-direct-debits-sdde) | Payin | Treezor User (recipient) | SEPA | | [Received SEPA Direct Debit](/guide/transfers/direct-debit#received-direct-debits-sddr) | Payout | External account owner | SEPA | | [Emitted SEPA Credit Transfer](/guide/transfers/credit-transfer#emitted-credit-transfers-scte) | Payout | Treezor User (sender) | SEPA | | [Received SEPA Credit Transfer](/guide/transfers/credit-transfer#received-credit-transfers-sctr) | Payin | External account owner | SEPA | | [Emitted Instant Credit Transfers](/guide/transfers/credit-transfer-inst#emitted-instant-credit-transfers-scte-inst) | Payout | Treezor User (sender) | SEPA | | [Received Instant Credit Transfers](/guide/transfers/credit-transfer-inst#received-instant-credit-transfers-sctr-inst) | Payin | External account owner | SEPA | Additional services such as [Scheduled payments](scheduled-payments) may be of interest as well. ## Statuses ### Payin statuses (`codeStatus`) | `codeStatus` | | `payinStatus` | Description | |:---: | :---: | --- |--- | | `140001` | | `PENDING` | Pending payment (during SDDE/SCTR payin creation) | | `140004` | | `CANCELED` | For SDDE, this status indicates either that the [ARA](/guide/overview/glossary#ara) is rejected or that you have canceled the payin. For SCTR, this status indicates the payin cannot be validated. | | `140005` | | `VALIDATED` | For SDDE, this status indicates the [ARA](/guide/overview/glossary#ara) is accepted. For SCTR, indicates the transaction is processed. | | `140006` | | `PENDING` | Pending non-repudiation | | `140007` | | `PENDING` | Fraud suspicion (AML/CFT). Don't communicate this information with your end users. | | `140010` | | `CANCELED` | SEPA Transfer refused | ### Payout statuses (`codeStatus`) | `codeStatus` | | `payoutStatus` | Description | |:---: |:---: | --- |--- | | `160001` | | `PENDING` | Refund request populated | | `160002` | | `PENDING` | Refund request received by mail | | `160003` | | `VALIDATED` | Internaly validated | | `160004` | | `VALIDATED` | Transfer request sent to bank | | `160005` | | `VALIDATED` | Refund transfer validated | | `160006` | | `CANCELED` | Canceled by the User | | `160007` | | `PENDING` | Bank account in error during the first transfert or debit | | `160008` | | `PENDING` | Fraud suspicion or AML/CFT | | `160009` | | `CANCELED` | Canceled by operator | | `160010` | | `CANCELED` | Insufficient Authorized Balance when the operation was presented | | `160011` | | `PENDING` | Outgoing funds pending validation due to Beneficiary being in a non-[FATF](https://www.fatf-gafi.org) country | | `160012` | | `PENDING` | Outgoing funds pending validation due to amount exceeding €10,000 | | `160013` | | `PENDING` | Outgoing funds pending validation due poor scoring of the operation | | `160014` | | `PENDING` | Outgoing funds sent to recipient's institution, pending acknowledgment | | `160015` | | `PENDING` | Outgoing funds suspended by operator | ### Payout Refund statuses (`codeStatus`) | `codeStatus` | | `payoutStatus` | Description | |:---: |:---: | --- |--- | | `790001` | | `PENDING` | Message of refund has been sent to Scheme. Wait for confirmation. | | `790002` | | `CANCELED` | Canceled by the Scheme (Treezor received a negative answer) | | `790003` | | `VALIDATED` | Validated | | `790004` | | `PENDING_NO_RESPONSE` | No response received in legal delay | ### Transfer statuses (`codeStatus`) | `codeStatus` | | `transferStatus` | Description | |:---: |:---: | --- |--- | | `150001` | | `PENDING` | Transfer has been initiated. | | `150002` | | `PENDING` | Fraud suspicion, you can't expose this information to your end users. | | `150003` | | `CANCELED` | Canceled by the end user. | | `150004` | | `CANCELED` | Canceled by the operator. | | `150005` | | `VALIDATED` | Validated | | `150006` | | `CANCELED` | Transfer canceled due to lack of funds from the debited Wallet Authorized Balance. | ## Endpoints ### Payins | Endpoint |[Scope](/guide/api-basics/authentication#available-scopes) | | --- | --- | | [`/v1/payins`](/api-reference/api-endpoints.html#tag/Payins/postPayin){target="\_self"} Create a Payin | `read_write` | | [`/v1/payins`](/api-reference/api-endpoints.html#tag/Payins/getPayins){target="\_self"} Search Payins | `read_only` | | [`/v1/payins/{payinId}`](/api-reference/api-endpoints.html#tag/Payins/getPayin){target="\_self"} Retrieve a Payin using its `id` | `read_only` | | [`/v1/payinrefunds`](/api-reference/api-endpoints.html#tag/Payin%20Refunds/getPayinrefunds){target="\_self"} Search Payin Refunds | `read_only` | | [`/v1/payinrefunds/{id}`](/api-reference/api-endpoints.html#tag/Payin%20Refunds/getPayinrefund){target="\_self"} Retrieve a Payin Refund using its `id` | `read_only` | ### Payouts | Endpoint |[Scope](/guide/api-basics/authentication#available-scopes) | | --- | --- | | [`/v1/payouts`](/api-reference/api-endpoints.html#tag/Payouts/postPayout){target="\_self"} Create a Payout | `read_write` | | [`/v1/payouts`](/api-reference/api-endpoints.html#tag/Payouts/getPayouts){target="\_self"} Search Payouts | `read_only` | | [`/v1/payouts/{payoutId}`](/api-reference/api-endpoints.html#tag/Payouts/getPayout){target="\_self"} Retrieve a Payout using its `id` | `read_only` | | [`/v1/payouts/{payoutId}`](/api-reference/api-endpoints.html#tag/Payouts/deletePayout){target="\_self"} Cancel a Payout| `read_write` | | [`/core-connect/payouts/{payoutId}/proof`](/api-reference/api-endpoints.html#tag/Payouts/getProofPayout){target="\_self"} Create a Payout Proof| `read_only` | | [`/v1/payoutRefunds`](/api-reference/api-endpoints.html#tag/Payout%20Refunds/postPayoutRefund){target="\_self"} Create a Payout Refund | `read_write` | | [`/v1/payoutRefunds/{payoutRefundId}`](/api-reference/api-endpoints.html#tag/Payout%20Refunds/getPayoutRefund){target="\_self"} Retrieve a Payout Refund based on its `id` | `read_only` | ### Recalls & RROs | Endpoint |[Scope](/guide/api-basics/authentication#available-scopes) | | --- | --- | | [`/v1/recallR`](/api-reference/api-endpoints.html#tag/Recalls/getRecalls){target="\_self"} Search for SCT Recalls | `read_only` | | [`/v1/recallRs/{recallRId}`](/api-reference/api-endpoints.html#tag/Recalls/getRecallR){target="\_self"} Retrieve an SCT Recall or RRO by its `id` | `read_only` | | [`/v1/recallRs/{recallRId}/response/`](/api-reference/api-endpoints.html#tag/Recalls/putRecallR){target="\_self"} Provide your decision following an SCT Recall request | `read_write` | | [`/v1/recall-sct-inst/{sctInstId}/{recallId}`](/api-reference/api-endpoints.html#tag/Recalls/getRecallSctInst){target="\_self"} Retrieve an SCT Inst Recall | | | [`/v1/recall-sct-inst/{sctinstId}/{recallId}/response`](/api-reference/api-endpoints.html#tag/Recalls/putRecallSctInst){target="\_self"} Provide your decision following an SCT Inst Recall | | | [`/v1/payinrefunds/{recallId}`](/api-reference/api-endpoints.html#/) Retrieve a payinrefund following a Recall | | | [`/v1/payoutRefund`](/api-reference/api-endpoints.html#tag/Payout%20Refunds/postPayoutRefund){target="\_self"} Create a Recall (SCTE Inst only) | `read_write` | | [`/v1/payoutRefund/{payoutRefundId}`](/api-reference/api-endpoints.html#tag/Payout%20Refunds/getPayoutRefund){target="\_self"} Create a Recall (SCTE Inst only) | `read_only` | | [`/simulation/sct-inst/payin`](/api-reference/api-endpoints.html#tag/Simulation/simulateSctInstReception){target="\_self"} Emulate an SCTR, to test the procedure | | | [`/simulation/sct-inst/recall`](/api-reference/api-endpoints.html#tag/Simulation/simulateSctInstRecall){target="\_self"} Emulate a reception of a SCTR inst recall, to test the procedure | | | [`/simulation/recall-r`](/api-reference/api-endpoints.html#/) Emulate a Recallr, to test the procedure | | ### Transfers | Endpoint |[Scope](/guide/api-basics/authentication#available-scopes) | | --- | --- | | [`/v1/transfer`](/api-reference/api-endpoints.html#tag/Transfers/postTransfers){target="\_self"} Create a Transfers | `read_write` | | [`/v1/transfers`](/api-reference/api-endpoints.html#tag/Transfers/getTransfers){target="\_self"} Search Transfers | `read_only` | | [`/v1/transfers/{transferId}`](/api-reference/api-endpoints.html#tag/Transfers/getTransfer){target="\_self"} Retrieve a Transfer using its `id` | `read_only` | | [`/v1/transfers/{transferId}`](/api-reference/api-endpoints.html#tag/Transfers/deleteTransfer){target="\_self"} Delete a Transfer using its `id`| `read_write` | ### Beneficiaries | Endpoint | [Scope](/guide/api-basics/authentication#available-scopes) | | --- | --- | | [`/v1/beneficiaries`](/api-reference/api-endpoints.html#tag/Beneficiaries/postBeneficiary){target="\_self"} Create a Beneficiary | `read_write` | | [`/v1/beneficiaries`](/api-reference/api-endpoints.html#tag/Beneficiaries/getBeneficiaries){target="\_self"} Search for Beneficiaries | `read_only` | | [`/v1/beneficiaries/{beneficiaryId}`](/api-reference/api-endpoints.html#tag/Beneficiaries/getBeneficiary){target="\_self"} Retrieve a Beneficiary | `read_only` | | [`/v1/beneficiaries/{beneficiaryId}`](/api-reference/api-endpoints.html#tag/Beneficiaries/putBeneficiary){target="\_self"} Update a Beneficiary | `read_write` | ### Mandates | Endpoint | [Scope](/guide/api-basics/authentication#available-scopes) | | --- | --- | | [`/v1/mandates`](/api-reference/api-endpoints.html#tag/Mandates/postMandates){target="\_self"}  Create a mandate | `read_write` | | [`/v1/mandates`](/api-reference/api-endpoints.html#tag/Mandates/getMandates){target="\_self"}  Search for mandates | `read_only` | | [`/v1/mandates/{mandateId}`](/api-reference/api-endpoints.html#tag/Mandates/getMandate){target="\_self"}  Retrieve a mandate | `read_only` | | [`/v1/mandates/{mandateId}`](/api-reference/api-endpoints.html#tag/Mandates/deleteMandate){target="\_self"}  Revoke a mandate | `read_write` | --- --- url: /use-cases/prerequisites/introduction.md description: >- Explore Treezor's Use Cases section. This introduction sets the context for integrating common business models via step by step (API and no-code) guides, outlining key requirements such as KYC and Strong Customer Authentication (SCA). --- # Introduction The Use Cases section of the documentation provides implementation step-by-step guides (either no-code or API) to help users through the integration of common use cases without in-depth support from you *Treezor Implementation Manager*. Nevertheless, you are still required to abide by the following: * **KYC Form** – Treezor provided you a KYC Form listing the documents and declarative data you must provide for each type of user. * **Implementation best practices** – Treezor will validate your implementation to make sure you abide by regulations and requirements. You should only go through those guides if you've been oriented to them by Treezor. ## About Strong Customer Authentication Usually, Treezor won't request your implement strong customer authentication for use cases. However, your local regulator (e.g., la Banque de France for French companies) may require you declare sensitive end users' actions. In the use case articles, actions to declare are flagged with the badges. You may use either Treezor SCA endpoints or your own solution to implement SCA. Learn more in the [Strong Customer Authentication (SCA)](/guide/strong-customer-authentication/introduction) documentation. --- --- url: /guide/user-verification/introduction.md description: >- Get a foundational understanding of your legal obligation to verify your end users identity to present the misuse of the financial system for illegitimate purposes. Includes an overview of the KYC / KYB process and life cycle. --- # Introduction Treezor is legally obligated to verify the identity of the users using its services, whether it's you as a company or your end users. The obligations placed on banking services providers aim to prevent the misuse of the financial system for illegitimate purposes, as stated by the [anti-money laundering and countering the financing of terrorism (AML/CFT)](/guide/overview/glossary#anti-money-laundering-and-countering-the-financing-of-terrorism-aml-cft) rules. In this context, Treezor collaborates closely with regulating institutions through reporting and monitoring, and any other measure that aims to provide a compliant and secure banking ecosystem. Once your project is approved and you start using your `Production` environment, you must abide by the same rules and regulations. ## KYC / KYB The terms Know Your Customer (KYC) and Know Your Business (KYB) refer to the verification of a user, whether they are a legal entity or an individual. For Treezor to make sure users are who they say they are, you need to provide: * **Declarative data** – Regarding the user, such as their name, address, etc. * **Documents** – Proving the user or entity identity (IDs, company registration, proof of address, etc.) The KYC / KYB of a user is not a one-time check. In addition to the initial check done during the end user onboarding, multiple reviews are made along the user life cycle. The requirements to verify a user identity vary depending on factors such as: * The type of services you provide * The country you’re operating in * The type of users to be verified Some additional vigilance measures are required, such as a SEPA Transfer to a Wallet from the user to be verified or a certified video process. Treezor provides you with a *KYC Form* upon starting your project. It indicates everything you need to provide for user verification. ## Process Below is a high-level example of the KYC process for end user onboarding: The key steps are the following: 1. You collect the necessary data based on your *KYC Form* (declarative data, [documents](./documents), [tax residence](./tax-residence)). 2. You pre-review the documents to ensure proper quality before [requesting a KYC review](./kyc-request). 3. Treezor [manually verifies the user's identity](https://treezor.zendesk.com/hc/en-us/articles/360010167539-KYC) and decides whether they are eligible to use Treezor services. **Best practice – Make sure you provide data of quality** Bad data quality may result in unnecessary back-and-forth with Treezor. The more accurate and vigilant you are when providing the necessary data when requesting a KYC / KYB review, the smoother the end user experience. ### Provide user declarative data User key information to provide (based on your KYC Form) is to be populated through the following objects: * [Users](/guide/users/introduction) – Create or update your user with the relevant attributes * [Tax Residence](./tax-residence) – Declare the country of tax residency with a specific object (and add it to the corresponding User object) ### Provide documents Treezor offers 2 ways for end users to upload documents: * [To the Treezor API (with pre-review)](./documents-prereview) * [From your application to the Treezor API](./documents) The processes differ depending on the option you implement. Only once all the documents are properly updated can the KYC review by Treezor be requested. Learn more in the [Documents](./documents) section. ### Verification solutions Treezor relies on several verification solutions to ease the physical user verification process. The solutions available to you depend on the type of user and the [distribution country](/guide/users/introduction#distribution-country-distributioncountry). | Verification solution | Description | | --- | --- | | [Liveness](/guide/user-verification/live-verification) | Live verification which requires a video of the end user, their identity proof, and a SEPA transfer into their Treezor Wallet as an extra validation step. | | [Certified video (PVID)](/guide/user-verification/live-verification) | Live verification which requires a video of the end user and their identity proof, with challenges for the user to complete. PVID is ANSSI-certified. | | [Qualified eSignature (QES)](/guide/user-verification/qes) | Electronic signature verified with a selfie. It ensures the signer identification, protects the signature, and provides a certificate from a certified provider. | | [Video conference](/guide/user-verification/videoconf) | Feature that verifies the user through an online video call with an expert who reviews the ID and asks questions to ensure the user is who they claim to be. | Using a verification solution may still require you to collect documents and implement additional vigilance measures. Make sure you rely on the information provided by Treezor Compliance. #### Solution availability by `distributionCountry` ::: tabs key:abc \== France (FR) | | End user | Children (-18) | Legal Rep. | Shareholder | | --- | :---: | :---: | :---: | :---: | | **Liveness** [+ SEPA Transfer](#additional-vigilance-measures) | | | | | | **PVID** | | | | | | **QES** | | | | | | **Video conf.** | | | | | | **Documents** | | | | | \== Germany (DE) | | End user | Children (-18) | Legal Rep. | Shareholder | | --- | :---: | :---: | :---: | :---: | | **Liveness** | | | | | | **PVID** | | | | | | **QES** [+ SEPA Transfer](#additional-vigilance-measures) | | | | | | **Video conf.** | | | | | | **Documents** | | | | | \== Other EU countries | | End user | Children (-18) | Legal Rep. | Shareholder | | --- | :---: | :---: | :---: | :---: | | **Liveness** [+ SEPA Transfer](#additional-vigilance-measures) | | | | | | **PVID** | | | | | | **QES** | | | | | | **Video conf.** | | | | | | **Documents** | | | | | ::: ### Additional vigilance measures Your *KYC Form* may indicate a [SEPA Transfer](/guide/transfers/introduction#key-words) as an additional vigilance measure, allowing Treezor to know that the User has already passed a verification process with a credit institution located in the European Economic Area (EEA). This step consists of Users wiring money from their existing bank account to their new Treezor Wallet, and takes place between the upload of all the Documents and the request for a KYC review. The User can wire money to their [Wallet](/guide/wallets/introduction) via its [IBAN](/guide/wallets/iban) using one of the following methods: * [SCTR](/guide/transfers/credit-transfer#received-credit-transfers-sctr) * [SCTR Inst](/guide/transfers/credit-transfer-inst#received-instant-credit-transfers-sctr-inst) **Prerequisites – In order to make the initial transfer, the User must be created and** * Must have [Wallet](/guide/wallets/introduction) * Must have uploaded all their [Documents](/guide/user-verification/documents) This money wiring will send you a [`payin.create`](/guide/transfers/events#payin-create) webhook. You must then wait for this Payin status (`payinStatus`) to be `VALIDATED` before [requesting a KYC review](/guide/user-verification/kyc-request). **The validation of the Payin confirms that this measure was passed.** Depending on the type of transfer, the validation of the Payin may be provided immediately upon creation of the Payin, or via the [`payin.update`](/guide/transfers/events#payin-update) webhook within a few days. **Information – Transfer must be refunded if the User is not KYC-validated** You will need to get in touch with your *Treezor Account Manager* before being able to send a [payinrefund](/guide/transfers/events#payinrefund-create). ## User KYC Levels (`kycLevel`) The `kycLevel` represents our confidence in the assigned KYC Review status. | Value | Plaintext | Description | | :---: | --- | --- | | `0` | `NONE` | **No review** occurred yet for this User. | | `1` | `LIGHT` | User has been accepted or refused for light reasons (invalidating this status is possible with new documents). | | `2` | `REGULAR` | The User is KYC-validated. | | `3` | `STRONG` | The User is KYC-validated. | | `4` | `REFUSED` | **Permanent refusal**, further reviews will be denied. | Services availability for the User differ depending on their KYC Level. | Service | `NONE` | `LIGHT` | `REGULAR` | `REFUSED` | | --- | :---: | :---: | :---: | :---: | | [Create Cards](/guide/cards/creation) | | | | | | [Pay by Card](/guide/cards/transactions) | | | | | | [Send funds](/guide/transfers/introduction) | | | | | | [Receive funds](/guide/wallets/introduction#how-to-credit-wallets-top-up) | | | | | | [Request another KYC review](/guide/user-verification/kyc-request) | | | | | Services may also be unavailable due to Wallet specificities (i.e., [Electronic Money Limits](/guide/wallets/introduction#electronic-money-limits)). **Caution – When the User KYC level is `LIGHT`:** * It is your responsibility to [lock the User's Cards](/guide/cards/modification#block-a-card) * Payouts are enabled only to allow the User to retrieve their funds before definitely closing their Wallet. ## User KYC Review status (`kycReview`) The `kycReview` represent the current status of the user review by Treezor. It's for information purposes only, this value doesn't impact the services available to the User. | Value | Plaintext | Additional information| | :---: | --- | --- | | `0` | `NONE` | No review yet. | | `1` | `PENDING` | Review in progress. | | `2` | `VALIDATED` | Review is done and the user is KYC-validated. | | `3` | `REFUSED` | Review is done and the user is refused. | | `4` | `INVESTIGATING` |  | | `5` | `CLOSED` |  | | `6` | `REVIEW_OPEN` |  | | `7` | `REVIEW_PENDING` |  | **Note – [Each document receives its own review status](/guide/user-verification/documents#status-documentstatus)** The User's review status is automatically deduced from all the documents individual review status. ## KYC Life cycle All Users start their KYC journey with [kycLevel](#user-s-kyc-levels-kyclevel) `0` (`NONE`) and [kycReview](#user-s-kyc-review-status-kycreview) `0` (`NONE`). The most common scenario and life cycles are described below. ### Straightforward validation In this ideal process, the user produces decent quality and valid documents right away and doesn't exhibit counter indications to having a wallet. | # | Description | `user.kycLevel` | `user.kycReview` | |- |- |- |- | | 0 | Initial state | `0` None | `0` None | | 1 | User uploads all documents | `0` None | `0` None | | 2 | You request a KYC Review | `0` None | `1` **Pending** | | 3 | Treezor approves all documents | `2` **Regular** | `2` **Validated** | **Note – A validated Document cannot be replaced** If the user wishes to replace it, a new [Document](documents) object has to be created, and a new [KYC Review request](./kyc-request) has to be sent. ### Non-compliant documents The user uploads all documents (1) but one is expired or non-acceptable (3). The user loops back to the upload step (4) and provides an acceptable document that is validated by Treezor (5). | # | Description | `user.kycLevel` | `user.kycReview` | |- |- |- |- | | 0 | Initial state | `0` None | `0` None | | 1 | User uploads all documents | `0` None | `0` None | | 2 | You request a KYC Review | `0` None | `1` **Pending** | | 3 | Treezor rejects at least one document | `1`, `2` or `3` **Light**, **Regular** or **Strong** | `3` **Refused** | | 4 | User uploads new documents | `1`, `2` or `3` Light, Regular or Strong | `3` Refused | | 5 | You request a KYC Review | `0` **None** | `1` **Pending** | | 6 | Treezor approves all documents | `2` **Regular** | `2` **Validated** | **Note – A refused Document cannot be replaced** If the user wishes to replace it, a new [Document](documents) object has to be created, and a new [KYC Review request](./kyc-request) has to be sent. ### Permanent refusal The user uploads all documents (1), but analysis of the provided documents concluded that this user is not permitted to use Treezor's services (3). This is a **definitive refusal**, all subsequent document uploads will be refused. | # | Description | `user.kycLevel` | `user.kycReview` | |- |- |- |- | | 0 | Initial state | `0` None | `0` None | | 1 | User uploads all documents | `0` None | `0` None | | 2 | You request a KYC Review | `0` None | `1` **Pending** | | 3 | Treezor refuses the User | `4` **Refused** | `3` **Refused** | ### Modifying a non-validated user The user has uploaded documents but is not yet validated. | # | Description | `user.kycLevel` | `user.kycReview` | |- |- |- |- | | 0 | Initial state | `0` None | `0` None | | 1 | User uploads all documents | `0` None | `0` None | | 2 | User cancels a document | `0` None | `0` None | | 3 | User uploads a new document | `0` None | `0` None | | 4 | You request a KYC Review | `0` None | `1` **Pending** | | 5 | Treezor approves all documents | `2` **Regular** | `2` **Validated** | ### Modifying an already validated user The user has been validated previously, and decides to upload new documents. During the upload of new documents, the user can still access his/her account. | # | Description | `user.kycLevel` | `user.kycReview` | |- |- |- |- | | 0 | Already validated user | `2` **Regular** | `2` **Validated** | | 1 | User uploads new documents | `2` Regular | `2` Validated | | 2 | You request a KYC Review | `2` Regular | `1` **Pending** | | 3 | Treezor approves the new documents | `2` Regular | `2` **Validated** | ### Straightforward (live verification) In this ideal process, the user goes into Live verification, and produces acceptable documents right away. | # | Description | `user.kycLevel` | `user.kycReview` | `kycliveness.kyc-status` | |- |- |- |- |- | | 0 | Initial state | `0` None | `0` None | | | 1 | You request a live verification | `0` None | `0` None | **`initiated`** | | 2 | Treezor provides the verification URL | `0` None | `0` None | `initiated` | | 3 | You redirect the end user to the verification URL | `0` None | `0` None | `initiated` | | 4 | The end user is guided into uploading the documents | `0` None | `0` None | `initiated` | | 5 | Treezor sends a `kycliveness.create` webhook | `0` None | `0` None | **`processing`** | | 6 | Treezor sends a `kycliveness.update` webhook | `0` None | `0` None | **`processed`** | | 7 | You request a KYC Review | `0` None | `1` **Pending** | `processed` | | 8 | Treezor sends `document.create` webhooks | `0` None | `1` Pending | `processed` | | 9 | Treezor approves the documents | `2` **Regular** | `2` **Validated** | `processed` | ### Non-compliant documents (live verification) The user completes the Live verification process, but some documents are non-compliant. The user is refused by Treezor live verification provider. | # | Description | `user.kycLevel` | `user.kycReview` | `kycliveness.kyc-status` | |- |- |- |- |- | | 0 | Initial state | `0` None | `0` None | | | 1 | You request a live verification | `0` None | `0` None | **`initiated`** | | 2 | Treezor provides the verification URL | `0` None | `0` None | `initiated` | | 3 | You redirect the end user to the verification URL | `0` None | `0` None | `initiated` | | 4 | The end user is guided into uploading the documents | `0` None | `0` None | `initiated` | | 5 | Treezor sends a `kycliveness.create` webhook | `0` None | `0` None | **`processing`** | | 6 | Treezor sends a `kycliveness.update` webhook | `0` None | `0` None | **`processed`** | ### Compliant documents but refused User (live verification) The user completes the Live verification process and provides compliant documents. Nonetheless, Treezor refuses the User. | # | Description | `user.kycLevel` | `user.kycReview` | `kycliveness.kyc-status` | |- |- |- |- |- | | 0 | Initial state | `0` None | `0` None | | | 1 | You request a live verification | `0` None | `0` None | **`initiated`** | | 2 | Treezor provides the verification URL | `0` None | `0` None | `initiated` | | 3 | You redirect the end user to the verification URL | `0` None | `0` None | `initiated` | | 4 | The end user is guided into uploading the documents | `0` None | `0` None | `initiated` | | 5 | Treezor sends a `kycliveness.create` webhook | `0` None | `0` None | **`processing`** | | 6 | Treezor sends a `kycliveness.update` webhook | `0` None | `0` None | **`processed`** | | 7 | You request a KYC Review | `0` None | `1` **Pending** | `processed` | | 8 | Treezor sends `document.create` webhooks | `0` None | `1` **Pending** | `processed` | | 9 | Treezor refuses the documents | `1` **Light** | `3` **Refused** | `processed` | ## Endpoints | Endpoint | [Scope](/guide/api-basics/authentication#available-scopes) | | --- | --- | | [`/v1/documents`](/api-reference/api-endpoints.html#tag/User%20Documents/createDocuments){target="\_self"} Create a document | `read_write` | | [`/v1/taxResidences`](/api-reference/api-endpoints.html#tag/User%20Tax%20Residences/postTaxresidence){target="\_self"} Create a Tax Residence | `read_write` | | [`/v1/users/{userId}/kycliveness`](/api-reference/api-endpoints.html#tag/User%20Live%20Verification/postKycliveness){target="\_self"} Initiate the user [Live verification](/guide/user-verification/introduction) process | `read_write` | | [`/v1/documents`](/api-reference/api-endpoints.html#tag/User%20Documents/getDocuments){target="\_self"} Search for documents | `read_only` | | [`/v1/documents/{documentId}`](/api-reference/api-endpoints.html#tag/User%20Documents/getDocument){target="\_self"} Retrieve a specific document based on its `id` | `read_only` | | [`/v1/documents/{documentId}/download`](/api-reference/api-endpoints.html#tag/User%20Documents/getDocumentDownloadUrl){target="\_self"} Retrieve a document download URL | `read_only` | | [`/v1/taxResidences`](/api-reference/api-endpoints.html#tag/User%20Tax%20Residences/getTaxresidences){target="\_self"} Search for Tax Residences | `read_only` | | [`/v1/taxResidences/{taxResidenceId}`](/api-reference/api-endpoints.html#tag/User%20Tax%20Residences/getTaxresidence){target="\_self"} Retrieve a Tax Residence based on its `id` | `read_only` | | [`/v1/users/{userId}/Kycreview`](/api-reference/api-endpoints.html#tag/User%20KYC%20Review/putKycreview){target="\_self"} Initiate the user [KYC review](/guide/user-verification/introduction) process | `read_write` | | [`/v1/documents/{documentId}`](/api-reference/api-endpoints.html#tag/User%20Documents/putDocument){target="\_self"} Update a document `name` | `read_write` | | [`/v1/users/{userId}/kycliveness`](/api-reference/api-endpoints.html#tag/User%20Live%20Verification/put-kyc-liveness){target="\_self"} Upload the documents once the Live verification is completed. | `read_write` | | [`/v1/taxResidences/{taxResidenceId}`](/api-reference/api-endpoints.html#tag/User%Tax%20Residences/putTaxresidence){target="\_self"} Update a Tax Residence | `read_write` | | [`/v1/documents/{documentId}`](/api-reference/api-endpoints.html#tag/User%20Documents/deleteDocument){target="\_self"} Delete a document | `read_write` | | [`/v1/taxResidences/{taxResidenceId}`](/api-reference/api-endpoints.html#tag/User%Tax%20Residences/deleteTaxresidence){target="\_self"} Delete a Tax Residence | `read_write` | --- --- url: /guide/users/introduction.md description: >- Get a foundational understanding of Treezor physical users and legal entities, and their compatible functionalities. Includes key attributes, JSON structure, and related endpoints list. --- # Introduction Users typically refer to your customers, also known as end users. They can be: * [Physical Users](/guide/users/physical), representing an actual human being. * [Legal Entities](/guide/users/legal-entity), representing a company, association, etc. * [Anonymous](/guide/users/physical#anonymous-users), which are users with close to no declarative data, intended for specific and limited use cases. Users can also have hierarchical [parent-children relations](/guide/users/parent-children) between them. ## Key attributes Below are some of the most important User attributes. | Attribute | Type | Description | |--- |--- |--- | | `email` | string | [Unique and valid email address](#using-unique-and-valid-email-addresses). | | `specifiedUSPerson` | integer | Indicates if the user is a [US Person](/guide/user-verification/tax-residence#the-specific-case-of-us-taxpayers). | | `userTypeId` | integer | The type of user. **See [list of types](#types-usertypeid)**. | | `kycLevel` | integer | The current level of KYC validation. **See [list of levels](/guide/user-verification/introduction#user-kyc-levels-kyclevel)**. | | `kycReview` | integer | The current status of the KYC validation. **See [list of statuses](/guide/user-verification/introduction#user-kyc-review-status-kycreview)**. | | `kycComment` | string | A comment set by Treezor upon [KYC review](/guide/user-verification/introduction). It concatenates information for each KYC Review update, with the date, the `kycReview` and `kycLevel` values, and the comment from Treezor. | | `userStatus` | string | The user status as set by Treezor. Can be one of the following values:`PENDING` – User has just been created.`VALIDATED` – User is validated.`CANCELED` – User is [deleted](/guide/users/modifications#deletion). | | `employeeType` | integer | Used in the context of [parent-children relations](./parent-children) | | `controllingPersonType` | integer | Used in the context of [parent-children relations](./parent-children) | | `parentType` | string | Used in the context of [parent-children relations](./parent-children) | | `parentUserId` | integer | Used in the context of [parent-children relations](./parent-children) | | `title` | string | The title of the user, [used when sending physical cards](/guide/cards/creation#physical-card-creation). Can be one of the following: `M` – Stands for mister (Mr.)`MME` – Stands for misses (Mrs.)`MLLE` – Stands for miss`MX` – Gender-neutral title | | `firstname` | string | The first name of the user, [used when sending physical cards](/guide/cards/creation#physical-card-creation). | | `lastname` | string | The last name of the user, [used when sending physical cards](/guide/cards/creation#physical-card-creation). | | `middleNames` | string | The middle names of the user, if any. | | `address{1-3}` | string | Postal address of the user, also [used when sending physical cards](/guide/cards/creation#physical-card-creation). **See [limitations regarding address fields length](/guide/api-basics/data-format#addresses)** | | `postcode` | string | Postcode of the user, [used when sending physical cards](/guide/cards/creation#physical-card-creation). | | `city` | string | The user's address city, [used when sending physical cards](/guide/cards/creation#physical-card-creation). | | `state` | string | The user's address state, if any. May be [used when sending physical cards](/guide/cards/creation#physical-card-creation). | | `country` | string | The residence country of the user in the ISO 3166-1 alpha-2 format. [Used when sending physical cards](/guide/cards/creation#physical-card-creation). | | `position` | string | Only for NGOs, indicating their geographic activity coverage. | | `legal{Name/Form/...}` | string | Used to describe [Legal Entities](/guide/users/legal-entity) | | `birthday` | string | The birthday of the user in the `YYYY-MM-DD` format. |\ | `occupationCategory` | string | Type of occupation of the physical user. See [occupation category](./physical#occupation-category-occupationcategory) for the list of values.| | `timezone` | string | The local timezone of the user [in tz database format `Area/Location`](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) (e.g., `America/New_York`, `Europe/Paris`) | | `language` | string | The preferred language of the user (ISO 639-1). Conditions the language of the SMS sent for the [X-Pay](/guide/cards/x-pay-google-apple) feature. | | `isOnStockExchange` | integer | The [Legal Entity](/guide/users/legal-entity) presence on Stock Exchange: `0` – No ([Physical Users](/guide/users/physical) must use this value) `1` – Yes | | `distributionCountry` | string | The country in which the end user is using your services. This field is only required when you operate in multiple countries. Otherwise, it either defaults to your country or is set to `null`. Please contact Treezor to configure this feature. Format: ISO 3166-1 alpha-2 format. | **API – API Reference available** For a complete list of User attributes, check the [Users](/api-reference/api-endpoints.html#tag/Users){target="\_self"} section of the API Reference. ### Types (`userTypeId`) | `userTypeId` | User types | | :---: | --- | | `1` | [Physical User](/guide/users/physical) and [Anonymous User](/guide/users/physical#anonymous-users) | | `2` | [Business User](/guide/users/legal-entity) | | `3` | [Non-governmental organization](/guide/users/legal-entity) | | `4` | [Governmental organization](/guide/users/legal-entity) | ### User Status (`codeStatus`) Most user `codeStatus` values are deprecated, here are the ones you may encounter. | | `codeStatus` | `userStatus` | Description | | :---: | :---: | --- | --- | | | `110012` | PENDING | Internal checks in progress. | | | `110005` | CANCELED | User canceled by an operator. | | | `110006` | CANCELED | User canceled by the end user. | | | `110009` | VALIDATED | User is validated. | ### Using unique and valid email addresses Email addresses must be unique, except for `CANCELED` users, which are not taken into account for email address checks. During your [Sandbox](/guide/api-basics/environments) development phase, however, if you don't cancel users, we recommend that stakeholders (e.g., developers, QA testers) use their own email address with a random `+tag` suffixed to it. For example, if your email address is `firstname.lastname@example.com`, you can use: * `firstname.lastname+test1@example.com` * `firstname.lastname+test2@example.com` * `firstname.lastname+testn@example.com` All of which are unique and valid addresses that automatically redirect emails to `firstname.lastname@example.com`. Please note the use of disposable email addresses or services is strongly discouraged and can be rejected by the Treezor API. **Note – 50-character limit for X-Pay provisioning OTP method** If you're using the [X-Pay](/guide/cards/x-pay-google-apple) feature, consider enforcing a < 50-character limit to user's email. Only emails complying with this limit are used for the X-Pay provisioning OTP method. ### Distribution country (`distributionCountry`) The [KYC](/guide/user-verification/introduction) requirements and regulations may depend on the country your end user is located. Therefore, if you operate in multiple countries, your Treezor configuration includes the list of countries in which you operate. You must then associate the countries available in your configuration to your Users with the `distributionCountry` parameter. Doing so help you tailor the onboarding process of your users, requesting the relevant declarative data and going through the appropriate [verification solution](/guide/user-verification/introduction#verification-solutions). Treezor currently supports the following distribution countries. | Country | `distributionCountry` value | | --- | --- | | Belgium | `BE` | | France | `FR` | | Germany | `DE` | | Italy | `IT` | | Luxembourg | `LU` | | Spain | `ES` | | The Netherlands | `NL` | ## User object ::: code-group ```json [JSON] { "userId": 0, "userStatus": "PENDING", "userTag": "string", "parentUserId": 0, "parentType": "shareholder", "controllingPersonType": 0, "employeeType": 0, "specifiedUSPerson": 0, "title": "M", "firstname": "string", "lastname": "string", "middleNames": "string", "birthday": "string", "email": "string", "address1": "string", "address2": "string", "address3": "string", "postcode": "string", "city": "string", "state": "string", "country": "string", "countryName": "string", "distributionCountry": "FR", "secondaryAddress1": "string", "secondaryAddress2": "string", "secondaryAddress3": "string", "secondaryPostcode": "string", "secondaryCity": "string", "secondaryState": "string", "secondaryCountry": "string", "phone": "string", "mobile": "string", "nationality": "string", "nationalityOther": "string", "placeOfBirth": "string", "birthCountry": "string", "legalName": "string", "legalNameEmbossed": "string", "legalRegistrationNumber": "string", "legalTvaNumber": "string", "legalRegistrationDate": "string", "legalForm": "string", "legalShareCapital": 0, "legalSector": "string", "legalAnnualTurnOver": "string", "legalNetIncomeRange": "string", "legalNumberOfEmployeeRange": "string", "effectiveBeneficiary": 0, "kycLevel": 0, "kycReview": 0, "kycReviewComment": "string", "isFrozen": 0, "language": "string", "optInMailing": 0, "sepaCreditorIdentifier": "string", "position": "string", "activityOutsideEu": 0, "economicSanctions": 0, "residentCountriesSanctions": 0, "involvedSanctions": 0, "entitySanctionsQuestionnaire": 0, "sanctionsQuestionnaireDate": "string", "timezone": "string", "sourceOfFunds": "donation", "legalSectorType": "NAF", "isOnStockExchange": 0, "codeStatus": "string", "informationStatus": "string", "createdDate": "string", "modifiedDate": "string", "walletCount": 0, "payinCount": 0, "totalRows": 0, "occupationCategory": 1, "personalAssetsRange": 0, "monthlyIncomeRange": 1 } ``` ::: ## Endpoints | Endpoint | [Scope](/guide/api-basics/authentication#available-scopes) | | --- | --- | | [`/v1/users`](/api-reference/api-endpoints.html#tag/Users/postUsers){target="\_self"} Create a User | `legal`, `admin` | | [`/v1/users`](/api-reference/api-endpoints.html#tag/Users/getUsers){target="\_self"} Search for Users | `read_only` | | [`/v1/users/{userId}`](/api-reference/api-endpoints.html#tag/Users/getUser){target="\_self"} Retrieve a User based on its `id` | `read_only` | | [`/v1/users/{userId}`](/api-reference/api-endpoints.html#tag/Users/putUser){target="\_self"} Update a User | `read_write` | | [`/v1/users/{userId}/FreezeAssets`](/guide/users/restricted-users#freeze) Freeze/Unfreeze a User | `admin` | | [`/v1/users/{userId}`](/api-reference/api-endpoints.html#tag/user/deleteUser){target="\_self"} Delete a User | `read_write`, `admin` | ## Diagram ```mermaid flowchart LR User(User) AnonymousUser(Anonymous) PhysicalUser(Physical) BusinessUser(Business) NGOUser(Non-Governmental Organization) GovernmentalUser(Governmental Organization) Documents(Documents) KYCValidation("KYC Validation by Treezor") User -- userTypeId=1,2 --> AnonymousUser User -- userTypeId=1 --> PhysicalUser User -- userTypeId=2 --> BusinessUser User -- userTypeId=3 --> NGOUser User -- userTypeId=4 --> GovernmentalUser AnonymousUser -. optional .- Documents PhysicalUser --- Documents BusinessUser --- Documents NGOUser --- Documents GovernmentalUser --- Documents Documents -- Submission to Treezor --> KYCValidation class User MermaidUser class AnonymousUser MermaidNeutral class PhysicalUser MermaidNeutral class BusinessUser MermaidNeutral class NGOUser MermaidNeutral class GovernmentalUser MermaidNeutral class Documents MermaidNeutralAlternate class KYCValidation MermaidCard click AnonymousUser "/guide/users/physical.html#anonymous-users" click PhysicalUser "/guide/users/physical.html" click BusinessUser "/guide/users/legal-entity.html" click NGOUser "/guide/users/legal-entity.html" click GovernmentalUser "/guide/users/legal-entity.html" click Documents "/guide/user-verification/documents.html" click KYCValidation "/guide/user-verification/introduction.html" ``` --- --- url: /guide/wallets/introduction.md description: >- Get a foundational understanding of Treezor wallet and account types, and their compatible functionalities. Includes key attributes, JSON structure, and related endpoints list. --- # Introduction Wallets are accounts used to store funds. They are necessary for any type of transaction in the Treezor environment. In most cases, Wallets are attached to your end users (Wallets (n) → User (1)), allowing for the setup of their means of payment (cards, transfers, etc.). You can check their [Balance](balances), and they come with a dedicated [IBAN](iban). Treezor offers various types of wallets to adapt to multiple use cases and technical architectures while remaining compliant in a highly regulated context. Here are the wallet types you might encounter: * [Electronic Money Wallet](#electronic-money-wallet-type-9) * [Payment Account Wallet](#payment-account-wallet-type-10) * [Master Wallet](#master-wallet-type-15) * [Card Transaction Wallet](#card-transaction-wallet-type-14-18) ## Electronic Money Wallet (type `9`) Electronic Money Wallets are accounts specifically designed to hold funds in the form of [e-money](/guide/overview/glossary#electronic-money-e-money) and are compatible with a specific set of features. They are mostly used for prepaid services and online transactions, as the account balance represents prepaid monetary value. Such accounts are governed by the E-money regulation (EU’s E-Money Directive), so you require an [**EM approval**](https://treezor.zendesk.com/hc/en-us/articles/360014672580-Note-EM-5th-Directive) of your project to create this type of Wallets. Electronic wallets can store either: * **Nominative e-money** – The owner is KYC-validated. * **Anonymous e-money** – The owner is not KYC-validated. Depending on the type of [e-money](/guide/overview/glossary#electronic-money-e-money), different limits and restrictions may apply. ### Electronic Money Limits [E-money](/guide/overview/glossary#electronic-money-e-money) is governed by national and international rules that Electronic Money institutions must comply with. Following these rules, Treezor applies different types of restrictions and limits for anonymous and nominative e-money. The limits and restrictions are currently enforced in Belgium, France, Germany, and Spain. In addition, anonymous electronic money isn't allowed in Italy. #### Features Below the compatibility of Electronic Wallets with Treezor features. | Feature | Anonymous | Nominative | |-------------------|:----------------------------:|:----------------------:| | Check cashing (payin) | | | | Emitted SEPA Credit Transfer (payout) | | | | Received SEPA Direct Debit (payout) | | | | Received SEPA Credit Transfer (payin) | | | | Instantaneous Received SEPA Credit Transfer (payin) | | | | Emitted SEPA Direct Debit (payin) | | | | Card Acquiring (payin) | | | | Card payment | | | | Wallet-to-Wallet transfers with `type=10` | | | | Wallet-to-Wallet transfers with `type=9` (Anonymous) | | | | Wallet-to-Wallet transfers with `type=9` (Nominative) | | | | Wallet-to-Wallet transfers with `type=9` with parent-children relationship between users | | | | Wallet-to-Wallet transfers with `type=9` of the same user | | | #### Limits & restrictions Below are the e-money limits and restrictions. Limits are calculated on a rolling 30-day period per user (regardless of the number of `type=9` wallets they own). | Feature | Anonymous | Nominative | |------------------------------------------------|------------------------------------------------------------|------------------------------------------------| | Balance | Max. €150/user | Max. €10.000/user (with physical card) | | Crediting Wallets | Max. €150/user | Max. €10.000/user (with physical card) | | Debiting Wallets | Max. €150/user | Max. €10.000/user (with physical card) | | Cash withdrawals | | Max. €1.000/user | | Cash top-ups | | Max. €1.000/user | | Card top-ups | | Max. €1.000/user | | Cash refunds | | Max. €1.000/user | | Card Transaction MCC | Prohibited MCCs: 4829, 6050, 6051, 6536, 6537, 6538, 6540, 7800, 7801, 7995, 9406 | No restriction | | Card transactions | Max. €50/transaction (online) Max. €150/transaction ([POS](/guide/overview/glossary#terminal)) | Max. €3.000/transaction | | Receiving funds from an anonymous e-money account | | Max. €1.000/user | | Country | Anonymous e-money cannot be used outside of the country where the e-money was issued. | No restriction | **Information – The €150 limit does not apply when the wallet is:** * Used for special payment vouchers (i.e., restricted to certain categories of goods or services) **and** * [Associated](/guide/users/parent-children) to a parent [Legal entity](/guide/users/legal-entity) that is KYC validated. ## Payment Account Wallet (type `10`) Payment Account Wallets are accounts that facilitate payment transactions. They support a wider range of operations, including check cashing, emitted SEPA Credit Transfers, and received SEPA Direct Debit. Payment accounts are governed by payment services regulations, such as the EU's Payment Services Directive 2 (PSD2). Therefore, you require the [**ACPR approval**](https://acpr.banque-france.fr/) of your project to create this type of Wallets. Only [KYC-validated](/guide/user-verification/introduction) users can use Payment Account Wallets. ## Master Wallet (type `15`) Master Wallets are only created by Treezor, mostly to process payment titles with specific and regulated usage (e.g., employee benefits, lunch vouchers). This is what is called in French *“Titres Spéciaux de Paiement (TSPs)“*. They are only available to certain projects, as per agreement with Treezor. ## Card Transaction Wallet (type `14` & `18`) Treezor automatically creates additional Wallets to process card transactions properly. They can be of type: * `14` for the Mastercard scheme * `18` for the Visa scheme These wallets are exclusively for Treezor’s internal usage, and you shouldn't have to interact with them at any point. You may however encounter such Wallets in the `walletCardtransactionId` attribute in the Card object. ## How To Credit Wallets (Top-up) To credit a Wallet, multiple options are available to you. | Feature | Description | | --- | --- | | **Card Top-up** | [Card Topups](/guide/acquiring/introduction) allow you to display a Card acquisition form in your application, in a similar way to a payment form on a web shop. The user can use their existing Card to credit the wallet instantly. | | **SEPA Credit Transfer** | [SEPA Credit Transfers (SCTR)](/guide/transfers/credit-transfer#received-credit-transfers-sctr) are a type of inter-bank transfers, initiated by the debtor who needs to know the IBAN of the Wallet to credit. It usually takes a few days to appear on the Wallet. [Instantaneous SEPA Credit Transfers (SCTR Inst)](/guide/transfers/credit-transfer-inst#received-instant-credit-transfers-sctr-inst) are a quicker variant of the aforementioned SCTR. It usually takes a few seconds to appear on the Wallet. | | **SEPA Direct Debit** | [SEPA Direct Debit (SDDE)](/guide/transfers/direct-debit#emitted-direct-debits-sdde) are a type of inter-bank debit, initiated by the creditor who needs to know the IBAN of the account to debit and have a [Mandate](/guide/transfers/mandates) signed by the debtor. | | **Checks cashing** | Traditional check cashing remains a reliable way of receiving money on a Wallet. Treezor offers the ability to first register a check via the API, then mail in that check for cashing on a Wallet. See the [Checks](/guide/cheques/introduction) section of the documentation for more information. | | **Wallet-to-Wallet transfers** | Within Treezor, you can use inter-wallet [Transfers](/guide/transfers/wallet-to-wallet) that take effect immediately. | ## Key attributes Below are some of the most important Wallet attributes. | Attribute | Type | Description | |--- |--- |--- | | `walletTypeId` | integer | The type of wallet. The Wallet type is editable up to the first operation. Once the first transaction occurred, the `walletTypeId` can no longer be updated | | `eventName` | string | The name of the Wallet. | | `solde` | number | The current [**Balance**](/guide/overview/glossary#balance) of the Wallet. Prefer the [Balance endpoints](/guide/wallets/balances) for more accurate values. | | `authorizedBalance` | number | The balance of the Wallet, [including **currently pending operations**](/guide/overview/glossary#balance). Prefer the [Balance endpoints](/guide/wallets/balances) for more accurate values. | | `userId` | integer | The unique identifier of the [User](/guide/users/introduction) owning the Wallet. | | `walletTag` | string | Custom attribute that you can use as you see fit. Learn more in the [Object tags](/guide/api-basics/objects-tags) article. | | `tariffId` | integer | The fees applied to the Wallet, as defined by your contract with Treezor. | | `walletStatus` | string | The [status of the Wallet](#wallet-status), which can be one of the following: `PENDING`, `VALIDATED`, or `CANCELED`. | | `bic` | string | The [Bank Unique Identifier](/guide/overview/glossary#bank-identifier-code-bic) of the bank hosting the Wallet. All Wallets at Treezor have the same BIC unless you are a Payment Institution or more broadly a [Regulated Institution](/guide/overview/glossary#regulated-institution). | | `iban` | string | The automatically assigned [IBAN](./iban) of the Wallet. | | `currency`| string | The currency of the Wallet, in the [ISO 4217 3-letter code](/guide/api-basics/data-format#currencies) format. As of today, Treezor only supports `EUR`. | **API – API Reference available** For a complete list of Wallet attributes, check the [Wallets](/api-reference/api-endpoints.html#tag/Wallets){target="\_self"} section of the API Reference. ### Wallet Status | | `codeStatus` | `walletStatus` | Description | | :---: | :---: | --- | --- | | | `120001` | PENDING | Some checks are in progress. | | | `120002` | PENDING | KYC process in progress. | | | `120003` | CANCELED | Wallet closed by an operator. | | | `120004` | CANCELED | Wallet closed by the end user. | | | `120005` | VALIDATED | Wallet is ready for use. | ## Wallet object ::: code-group ```json [JSON] { "walletId": 0, "walletTypeId": 0, "walletStatus": "PENDING", "codeStatus": 0, "informationStatus": "string", "walletTag": "string", "userId": 0, "userLastname": "string", "userFirstname": "string", "jointUserId": 0, // Legacy attribute, do not use "tariffId": 0, "eventName": "string", "eventAlias": "string", // Legacy attribute, do not use "eventDate": "string", // Legacy attribute, do not use "eventMessage": "string", "eventPayinStartDate": "string",// Legacy attribute, do not use "eventPayinEndDate": "string", // Legacy attribute, do not use "contractSigned": 0, "bic": "string", "iban": "string", "urlImage": "string", "currency": "string", "createdDate": "string", "modifiedDate": "string", "payinCount": 0, "payoutCount": 0, "transferCount": 0, "solde": 0, "authorizedBalance": 0, "totalRows": 0 } ``` ::: **Best practice – Use the endpoints dedicated to Balances** You may experience some latency with the Wallet `solde` and `authorizedBalance` fields. Use the [`/v1/balances/{walletId}`](/api-reference/api-endpoints.html#tag/Balances/getBalances){target="\_self"} endpoint for a more performant usage. See the [Balances](/guide/wallets/balances) article. ## Endpoints | Endpoint |[Scope](/guide/api-basics/authentication#available-scopes) | | --- | --- | | [`/v1/wallets`](/api-reference/api-endpoints.html#tag/Wallets/postWallets){target="\_self"} Create a Wallet | `read_write` | | [`/v1/wallets`](/api-reference/api-endpoints.html#tag/Wallets/getWallets){target="\_self"} Search for Wallets | `read_only` | | [`/v1/wallets/{walletId}`](/api-reference/api-endpoints.html#tag/Wallets/getWallet){target="\_self"} Retrieve a Wallet based on its `id` | `read_only` | | [`/v1/wallets/{walletId}`](/api-reference/api-endpoints.html#tag/Wallets/putWallet){target="\_self"} Update a Wallet | `read_write` | | [`/v1/wallets/{walletId}`](/api-reference/api-endpoints.html#tag/Wallets/deleteWallet){target="\_self"} Set the Wallet status to `CANCELED` | `read_write` | | [`/v1/balances/{walletId}`](/api-reference/api-endpoints.html#tag/Balances/getBalances){target="\_self"} Retrieve the Balance of Wallets based on the `walletId` or `userId` | `read_only` | | [`/core-connect/balance/{walletId}/balance`](/api-reference/api-endpoints.html#tag/Balances/getWalletBalanceHistory){target="\_self"} Retrieve the Balance History of a Wallet | `read_only` | --- --- url: /guide/webhooks/introduction.md description: >- Get started with Treezor API webhooks. Learn what webhooks are, their core structure (payload, signature), and why to use them for real-time event notifications and handling unpredictable banking events. --- # Introduction When a specific event occurs, an HTTP request is sent from our infrastructure to a URL of your choice and provides you with relevant information regarding that event. A webhook is characterized by: * The unique identifier of the webhook * The callback URL – The URL receiving the event notification * The [event](/guide/webhooks/events-descriptions) – The event triggering a webhook request * The payload – The data passed along with the event * The signature – A means of [checking authenticity](/guide/webhooks/integrity-checks) ## Why use Webhooks? Although optional, using webhooks is strongly recommended. They provide much quicker event notifications (no need to periodically check the API for changes). As a result, webhooks allow you to better handle: * The intrinsic unpredictability of some banking events such as: * Receiving a [card payment](/guide/acquiring/introduction) or [money transfer](/guide/transfers/introduction), * Blocked transfers due to [AML/CFT suspicion](/guide/overview/glossary#aml-cft-anti-money-laundering-combating-the-financing-of-terrorism) * [Check cashing](/guide/cheques/cashing) * [Card](/guide/cards/introduction) activation by a [User](/guide/users/introduction) * The inherent delay of some actions such as requesting a [KYC](/guide/user-verification/introduction) or [Document](/guide/user-verification/documents) review. **Information – Not all Webhooks are available in Sandbox** [Read more about those limitations](/guide/api-basics/environments#sandbox) ## What does a Webhook look like? It looks like a standard HTTP POST request. Details regarding the event are embedded as a JSON array (`object_payload`). A hash (`object_payload_signature`) of the body allows you to [assert the authenticity](/guide/webhooks/integrity-checks) of the received information. **Information – Webhooks may not be received in chronological order** While Treezor sends webhooks chronologically, there is [no guarantee your servers receives them in the same order](./race-conditions). Compare the `webhook_created_at` values against your locally stored values to know which is most recent. ## Structure of a webhook | Attribute | Description | |--- |--- | | `webhook` | Name of the webhook | | `webhook_id` | Unique identifier of the webhook (UUID v4, 36-character long string) | | `webhook_created_at` | Date at which the webhook was created, as [Unix epoch (timestamp)](https://en.wikipedia.org/wiki/Unix_time) in the form `10^-4` seconds | | `object` | Name of the Treezor object | | `object_id` | ID of the Treezor object | | `object_payload` | **Standard Treezor objects** (Payin, Payout, CardTransaction, User, Wallet, etc.), generally in an array | | `object_payload_signature` | Hash of \[payload + `webhook_secret`]. This field allows you to [ensure the payload originates from Treezor](/guide/webhooks/integrity-checks) and has not been tempered with. | **Tip – Webhooks content matches the API's** Objects contained in the payload are identical to any other object retrieved from *Treezor Connect* API. They are simply embedded in an event object. ## Example Below is an example of a Webhook request. It was triggered by the creation of a transaction ([`transaction.create`](/guide/cards/events-tx#cardtransaction-create) event). ::: code-group ```json [JSON] { "webhook":"transaction.create", "webhook_id":"54350b79-9250-4e4e-bc0e-c2c01f6c43c6", "object":"transaction", "object_id":"16700", "object_payload":{ "transactions":[ { "transactionId":"16700", [...] // some attributes are hidden for clarity } ] }, "object_payload_signature":"XWvC\/4wAhkqIOgHAccHTkZQ73zp7QMBZC5APTU5oZww=" } ``` ::: While webhooks return JSON, **they are provided with the `text/plain` mime type** . --- --- url: /guide/user-verification/faking-operations.md description: >- Learn how to update the user KYC status within the Sandbox environment for development and API integration testing. --- # Emulation Emulation features are only available in `Sandbox` [environment](/guide/api-basics/environments). **Tip – You can also rely on webhooks** For operations that cannot be emulated in the Sandbox, [webhook examples](events) are provided. ## KYC validation Emulate the KYC validation of a single user by adding a suffix to the User's `lastname` using the following requests: * [`/v1/users`](/api-reference/api-endpoints.html#tag/Users/postUser){target="\_self"} * [`/v1/users/{userId}`](/api-reference/api-endpoints.html#tag/Users/putUser){target="\_self"} | Suffix | `kycLevel` | `kycReview` | Description | | --- | :---: | :---: | --- | | `.validated` | `2` | `2` | The User is `REGULAR` / `VALIDATED` | | `.refused` | `4` | `3` | The User is `REFUSED` / `REFUSED` | **Tip – Compatible with User status emulation** You can cumulate the suffixes to achieve both KYC and [status emulation](/guide/users/faking-operations) at once. For instance: `lastname.refused.userStatusValidated`. Wait a few minutes and make a [`/v1/users/{userId}`](/api-reference/api-endpoints.html#tag/Users/getUser){target="\_self"} request for the User you've just updated. The API returns the User with the emulated `kycLevel` and `kycReview`. **Information – Incompatibility with Parent-Children hierarchical relations** As opposed to the API behavior when requesting a KYC Review, emulating the validation of a parent user won't have any consequence on its children. ### Example Let's take an example in which we'd like to simulate a KYC refusal of a User. ::: code-group ```bash [CURL] curl -X PUT '{baseUrl}/v1/users' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: With a `{payload}` containing the suffixed `lastname`: ::: code-group ```json [JSON] { "lastname": "Oak.refused" } ``` ::: You need to retrieve the User a few moments after the update with the following request: ::: code-group ```bash [CURL] curl -X GET '{baseUrl}/v1/users/{userId}' \ --header 'Authorization: Bearer {accessToken}' ``` ::: The User object returned with the updated `kycLevel` and `kycReview`. ::: code-group ```json [JSON] {47-49} { "users": [ { "userId": 100135695, "userTypeId": 1, "userStatus": "VALIDATED", "userTag": "emulationTestr36748", "parentUserId": 0, "parentType": "", "controllingPersonType": 0, "employeeType": 0, "specifiedUSPerson": 0, "title": "", "firstname": "Alex", "lastname": "Oak.refused", "middleNames": "", "birthday": "1982-05-31", "email": "aOak533@example.com", "address1": "12 rosewood lane", "address2": "", "postcode": "75000", "city": "Paris", "state": "", "country": "FR", "countryName": "France", "phone": "+33121212121", "mobile": "", "nationality": "FR", "nationalityOther": "", "placeOfBirth": "Montreuil", "birthCountry": "FR", "occupation": "", "incomeRange": "0-18", "legalName": "", "legalNameEmbossed": "", "legalRegistrationNumber": "", "legalTvaNumber": "", "legalRegistrationDate": "0000-00-00", "legalForm": "", "legalShareCapital": 0, "entityType": null, "legalSector": "", "legalAnnualTurnOver": "", "legalNetIncomeRange": "", "legalNumberOfEmployeeRange": "", "effectiveBeneficiary": 0, "kycLevel": 4, "kycReview": 3, "kycReviewComment": "Refused automatic simulation", "isFreezed": 0, "isFrozen": null, "language": "", "optInMailing": null, "sepaCreditorIdentifier": "", "taxNumber": "", "taxResidence": "", "position": "", "personalAssets": "465-", "createdDate": "2024-02-14 07:24:21", "modifiedDate": "2024-02-14 08:25:12", "walletCount": 0, "payinCount": 0, "totalRows": "1", "activityOutsideEu": 0, "economicSanctions": 0, "residentCountriesSanctions": 0, "involvedSanctions": 0, "entitySanctionsQuestionnaire": 0, "address3": null, "timezone": null, "occupationType": "", "isOnStockExchange": 0, "secondaryAddress1": "", "secondaryAddress2": "", "secondaryAddress3": "", "secondaryPostcode": "", "secondaryCity": "", "secondaryState": "", "secondaryCountry": "", "clientId": "929252", "sanctionsQuestionnaireDate": null, "codeStatus": "110009", "informationStatus": "", "legalSectorType": "", "sourceOfFunds": "" } ] } ``` ::: ## KYC Liveness ### Refused Liveness To emulate a refused Liveness process, create a User under one name and provide documents (ID Card, driving license, etc.) under a different name during the Liveness. ### Accepted Liveness To emulate an accepted Liveness process, create a User under one name and provide documents (ID Card, driving license, etc.) in the same name during the liveness. --- --- url: /guide/dashboard/kyc.md description: >- Let your team provide support regarding your end users onboarding using the Treezor Dashboard. Includes the upload of documents and pre-review. --- # KYC / KYB Know Your Customer (KYC) or Know Your Business (KYB) refers to the verification of your users' identity. Part of this process consists in submitting documents to Treezor for validation, which can be done from the Dashboard. **Reading – Know Your Customer** Learn more about the user verification process with the dedicated [KYC](/guide/user-verification/introduction) section. ## Accessing user KYC/KYB information You may access KYC information for a specific user in the *Profiles Board* view, *KYC* tab once a user is selected (learn more about [accessing user information](/guide/dashboard/users#accessing-your-users)). The tab appears only for users who can go through verification. **Information – The tab changes depending on the type of user** The name of the tab and the details depend on the user type. For the sake of convenience, this article uses mostly the term KYC rather than KYB. The *KYC* / *KYB* tab is made up of the following sections: * [**Global KYC Status**](#global-kyc-status) – Information about the KYC Status of the selected user, including [additional vigilance measures](#additional-vigilance-measure). * **User information** – Main declarative data about the user. * **Verification details** – Declarative data necessary for user verification, such as nationality, situation, or tax residence for instance. * [**Documents section**](#documents-section) – List of documents uploaded for the user, for you to review. In the upper right corner, the "Submit KYC to Treezor" button allows you to [request a KYC review by Treezor](#request-a-kyc-review-by-treezor). This button is only enabled once the required data is provided. ## Global KYC Status The *Global KYC Status* section provides information about the KYC Status of the selected user. ### KYC Status On the left-hand side, the KYC Status indicates the overall status of the user verification. The status can be one of the following values: | Status | Description | | --- | --- | | **Not required** | The user is not subject to verification. | | **Optional** | The user doesn't need to go through verification unless they reach [Electronic Money Limits](/guide/wallets/introduction#electronic-money-limits). | | **To submit to Treezor** | The necessary declarative data is filled in; you can now request verification from Treezor. Ensure all documents have been uploaded and pre-reviewed before submitting. | | **Pending Treezor** | Treezor Compliance team is reviewing the user. | | **To review** | Treezor rejected the user (e.g., missing data). Complete user data and documents before resubmitting. | | **To check** | Treezor triggered a periodical or exceptional review. Update user data and documents before requesting a new review. | | **Validated** | Treezor has verified the user and deemed them fit to use the financial services. | | **Refused** | Treezor has verified the user and deemed them unfit to use the financial services. This status is definitive. | Clicking on the "See details" button opens the *KYC History* popup which contains: * Date and time at which Treezor Compliance team reviewed the user * Comments and note from Treezor compliance team * [KYC Level](/guide/user-verification/introduction#user-kyc-levels-kyclevel) set during the verification. * [KYC Review status](/guide/user-verification/introduction#user-kyc-review-status-kycreview) set during the verification. #### KYC life cycle ### Additional vigilance measure Additional vigilance measures might be necessary to complete the user verification process. It consists of a received SEPA Credit Transfer to the user wallet. Status can be: * **None** – No SCTR has been initiated yet. * **Pending** – An SCTR has been initiated, but not validated yet. * **Settled** – The SCTR is validated, completing the additional vigilance measure. Once the transfer "Settled", the vigilance measure is complete and the user will be able to use Treezor financial services when verified. When clicking on the "See details" button, the *Additional vigilance measure* popup is displayed, providing the list of SCT payins made with the following key attributes: Operation date, status, amount, emitter, IBAN, and BIC. ## User information sections You can view user main information which are necessary for the KYC/KYB review in the *User information* and *Verification details* sections. If you have the relevant rights, you can update existing user data. Make sure the provided data is in accordance with the Compliance rules in terms of KYC. ### Manage user tax residence When declaring the tax residence, you need to provide the country and Tax Identification Number (TIN) of the user (optional for all the countries except for [US taxpayers](#the-specific-case-of-us-taxpayers)). It is possible to add or edit the user Tax Residence in the *Verification details* section, by clicking on the dedicated "Edit" button. Click on the "Add Tax Residence" button to declare a new tax residence. Fill in the displayed fields with the relevant country and Tax Identification Number. "Save Changes" to complete your new declaration. ## Documents section Documents are evidence required by Treezor to ensure Users are who they claim to be. During the KYC/B review, Treezor compares documents to the user’s declarative data. The user is verified if the documents are in order (as well as any other verification requirement). This section lists documents uploaded for the KYC Review. You must pre-review the documents before requesting the KYC review from Treezor. ### Documents list Documents are displayed if: * The end user uploaded documents from your application * Your Dashboard Users uploaded a document for your end users Each document has a menu icon that provides access to the following commands (depending on the status of the document): | Action | Description | | --- | --- | | **Review document** | Opens the [*Review document*](#review-document-popup) popup, allowing you to validate or refuse the document. | | **See document details** | Opens the read-only version of the [*Review document*](#review-document-popup) popup, allowing you to validate or refuse the document. | | **Delete document** | Deletes the document. | Also, clicking on the arrow displays the document in a new browser tab or downloads it (depending on the format). ### Document statuses Documents can have one of the following statuses. Please note every time "you" is indicated, the name of your company will be displayed instead. | Status | Description | | --- | --- | | **To review (you)** | Waiting for pre-review from your teams. | | **Reviewed (you)** | The document has been pre-reviewed (validated) by your teams, but at least another document from this use is still to be pre-reviewed. | | **Reviewed, to submit** | All the documents have been pre-reviewed by your teams. They will be sent to Treezor for validation when requesting the KYC review. | | **Pending validation** | The documents are waiting for Treezor team's validation. | | **Validated (Treezor)** | The document has been validated by Treezor as part of the KYC/KYB review process. | | **Refused (you)** | Your team refused the document during the pre-review process. | | **Refused (Treezor)** | The document was rejected by Treezor as part of the KYC/KYB review process. | | **Canceled** | The document was deleted by the end user or your teams, or was subject to a technical issue. | #### Document life cycle ### Review document popup The *Review document* popup displays a preview of the uploaded document on the left-hand side, and details of the document on the right. In order to review a document: 1. Select the relevant status in the picklist. 2. Add a comment explaining your choice. 3. Click on the enabled "Submit" button. ### Uploading KYC Documents Usually, end users are the ones uploading their KYC documents through your application. In some cases, however, your [Dashboard Users](/guide/dashboard/dashboard-users) might upload documents for the end users. They can do so by clicking on the "Add KYC Document" button to open the *Upload KYC document* popup. From there, you can select a document type, then upload the file while abiding by the requested format and weight. If the upload is successful, the document appears in the *Documents* section. ## Requesting a KYC review by Treezor When all the necessary documents have been uploaded and properly pre-reviewed, you can request a review from Treezor. To do so, click on the "Submit KYC to Treezor" button located in the upper right corner of the *Profiles Board* view, *KYC tab*. **Information – In Production, verification is done by Treezor Compliance team** Verification usually takes about 24h, but may take up to 48h or more (working days only). --- --- url: /guide/api-basics/mutual-tls.md description: >- Understand Mutual TLS (mTLS) for the Treezor API. This guide explains two-way authentication, how to implement client certificates, and enhance API security for robust and trusted connections. --- # Mutual Transport Layer Security (mTLS) The Mutual Transport Layer Security (mTLS) protocol guarantees mutual authentication and encrypted communication, preventing interception and identity theft between systems. **Configuration – Mutual Transport Layer Security (mTLS) availability** If you've been working with Treezor prior to the mTLS authentication availability, you will have to migrate to the new services. ## Introduction Mutual TLS ensures that the parties at each end of the network connection are who they claim to be by verifying they both have the correct private key. This protocol relies on the exchange of Transport Layer Security (TLS) certificates. TLS certificates contain the necessary information for verifying the server or device identity, such as the public key, a statement of who issued the certificate, and the expiration date. ## Setting up your certificates To use mTLS, you need to send 2 Certificate Signing Requests (CSRs) to Treezor. It will allow you to set up, with your private key, the TLS negotiation. In return, Treezor provides the signed certificates for you to configure your client and authenticate your requests. You need to provide a different set of certificates for each of your Treezor environments (Sandbox and Production). If you're using PCI DSS services, you'll need yet another set of CSR files (see [PCI DSS integration](/guide/cards/pci-dss)). ### 1. Create your RSA keys You need a private key to create your Certificate Signing Request (CSR). This key must have the following attributes: * **Type**: RSA * **Format**: PKCS1 * **Size**: 2048 **Configuration – Use a different RSA key for each CSR** Your mTLS certificate and your signature certificate for [signing PCI DSS requests](/guide/cards/pci-dss#sign-your-requests) must have different private keys. Here is the command to run for your Sandbox, please keep in mind you'll have to do the same for your Production environment. ::: code-group ```[Linux / macOS] openssl genrsa -out _privatekey_mtls.pem 2048 ``` ::: **Security – Protect your private key** Don’t share your private key with anyone and make sure they are securely stored (e.g., secure vault, key management system). ### 2. Create your CSR files The Certificate Signing Request (CSR) is a request you send to a Certificate Authority (or CA, in this case, Treezor) to apply for a digital identity certificate. The CSR includes the public key and additional information such as the entity requesting the certificate common name (CN). Here is the command to run: ::: code-group ```[Linux / macOS] openssl req -new -key _privatekey_mtls.pem -out _csr_mtls.pem ``` ::: Then use the information in the table below to complete the CSR information. | Information | Description | |---------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Country | The two-letter country code representing the country where the organization is located. | | State / Province | The state or province where the organization is located (e.g., Brittany, IdF). | | Locality | The locality or city where the organization is located. | | Organization Name | The legal name of the organization to which the entity belongs. This could be the company, department, or other organizational unit. | | Organizational Unit | (optional) The specific unit within the organization. For example, “IT Department” or “Marketing”. | | Common Name | Usually, the fully qualified domain name (FQDN) for which the certificate is being requested. For example, if the certificate is for a website, the CN might be the domain name (e.g., https://yourcompany.com). | | Email | The email address of the organization. | ### 3. Ask Treezor to generate your certificates CSR files and certificates are not considered sensitive data. This is why you can exchange them by email. 1. Send your CSR files to your *Treezor Technical Account Manager*. 2. Treezor will send you back the signed certificates. **Security – Don't send your private keys, only the CSR files** If you were to send us your private key, you'll have to generate new ones and start the process from scratch. ## Renewing your certificates Your certificates have a specific validity period. You need to contact Treezor about a month before their expiration date to set up new ones. Here is the command to run to check the start and end dates of a certificate: ::: code-group ```[Linux / macOS] openssl x509 -startdate -enddate -noout -in _csr_.pem ``` ::: Outputs the following: ::: code-group ```[Linux / macOS] notBefore=Jan 22 12:25:04 2024 GMT notAfter=Jan 22 13:25:04 2025 GMT ``` ::: ## Revoking your certificates If you suspect your private key has been compromised, you must contact Treezor immediately to revoke your certificate. You can then go through the process described in this article to set up new certificates. --- --- url: /guide/api-basics/objects-tags.md description: >- Understand Object Tags in the Treezor API. This guide explains how to use custom tags to categorize and manage your API objects for enhanced organization and filtering of your data. --- # Object tags Tag attributes allow you to match Treezor objects with objects stored in your databases. These attributes have the following characteristics: * Strings (max 250 characters) * Always in the API's responses * Named as a concatenation of the object's class and the word "Tag" (camelCase) Here are a few examples of tag attributes: `userTag`, `cardTag`, `payinTag`, `walletTag`. **Best practice – Tags must:** * **Be unique**. Tagging convention must avoid tag collisions. * **Use alphanumeric characters** plus `/` `!` `-` `_` `.` `*` `'` `(` `)`. Using other characters can have unexpected consequences. ## Tag examples ### User Tag When creating a User object, the associated tag is the `userTag`. Consider the following request to create a user: ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/users' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: You can include the corresponding `userTag` in the `{payload}`: ::: code-group ```json [JSON] {3} { "userTypeId": 1, "userTag": "6050c342b8e240.82964", "specifiedUSPerson": 0, "firstname": "Alex", "lastname": "Oak", "birthday": "1982-05-31", "placeOfBirth": "Edgewood", "birthCountry": "FR", "nationality": "FR", "email": "alex.oak@example.com" } ``` ::: The `userTag` is then included in the returned User object. ### Wallet Tag When creating a Wallet object, the associated tag is the `walletTag`. Consider the following request to create a wallet: ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/wallets' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: You can include the corresponding `walletTag` in the `{payload}`: ::: code-group ```json [JSON] {3} { "walletTypeId":10, "walletTag": "6050c342b8e240.82964", "tariffId": 1234, "userId": 123456, "currency": "EUR", "eventName": "My Wallet Name" } ``` ::: The `walletTag` is then included in the returned Wallet object. --- --- url: /guide/api-basics/pagination.md description: >- Master API pagination in the Treezor API. This guide explains how to retrieve large datasets, detailing both offset-based and cursor-based pagination types for efficient data handling. --- # Pagination Pagination involves breaking down the list of returned objects into subsets that you can then navigate. Treezor offers 2 methods to paginate API responses, depending on the endpoints. | Method | Description | | --- | --- | | **[Offset-based](#offset-based-pagination)** | Divides the results into pages by indicating the number of items per page. | | **[Cursor-based](#cursor-based-pagination)** | Uses a cursor to mark the last item in each page. | ## Offset-based pagination ### Parameters [Endpoints that support offset pagination](#supported-endpoints) rely on the following query parameters. | Attribute | Description | | --- | --- | | `pageNumber` | The number of the page to retrieve. | | `pageCount` | The number of objects per page. | | `sortBy` | The object attribute to sort the list with (e.g., `creationDate`, `modifiedDate`, etc.). Differs for each endpoint. | | `sortOrder` | The order you want to sort the list. Either: `DESC` (default) for a descending order`ASC` for an ascending order | ### Examples Let's retrieve the list of transfers for a specific wallet with the following pagination parameters: * **1st page** (`pageNumber=1`) * **30 objects** (`pageCount=30`) * **Sorted by creation date** (`sortBy=creationDate`) * **In chronological order**, so that the most recently created is displayed last (`sortOrder=ASC`) You need to make the following request: ::: code-group ```bash [CURL] curl -X GET '{baseUrl}/v1/transfers?pageNumber=1&pageCount=30&sortBy=creationDate&sortOrder=ASC&walletId={{walletId}}' \ --header 'Authorization: Bearer {accessToken}' ``` ::: Returns an array of `30` objects (or less, in the last page). ::: code-group ```json [JSON] [ { "walletId": 28749, "createdDate": "2019-03-10T08:05:10-00:00", [...] }, { "walletId": 92758, "createdDate": "2020-08-25T07:08:20-00:00", [...] }, { "walletId": 57820, "createdDate": "2021-02-03T07:09:33-00:00", [...] }, [...] // 27 more objects hidden ] ``` ::: Now, let's retrieve the same list of transfers for the wallet, but with different pagination parameters: * **5th page** (`pageNumber=5`) * **50 objects** (`pageCount=50`) * **Sorted by amount** (`sortBy=amount`) * **In descending order**, so that the highest amount is displayed first (`sortOrder=DESC`) You need to make the following request: ::: code-group ```bash [CURL] curl -X GET '{baseUrl}/v1/transfers?pageNumber=5&pageCount=50&sortBy=amount&sortOrder=DESC&walletId={{walletId}}' \ --header 'Authorization: Bearer {accessToken}' ``` ::: Returns an array of `50` objects (or less, in the last page). ::: code-group ```json [JSON] [ { "walletId": 82749, "amount": 4298, [...] }, { "walletId": 10855, "amount": 2310, [...] }, { "walletId": 42187, "amount": 150, [...] }, [...] // 47 more objects hidden ] ``` ::: ### Supported endpoints Usually, endpoints with a `v1` prefix in their path and used to retrieve a list of objects support offset pagination. ::: details List of endpoints supporting offset pagination * [`/v1/beneficiaries`](/api-reference/api-endpoints.html#tag/Beneficiaries/getBeneficiaries){target="\_self"} * [`/v1/cards`](/api-reference/api-endpoints.html#tag/Cards/getCards){target="\_self"} * [`/v1/cardtransactions`](/api-reference/api-endpoints.html#tag/Card%20Transactions/readCardTransaction){target="\_self"} * [`/v1/countryRestrictionGroups`](/api-reference/api-endpoints.html#tag/Country%20Restriction%20Groups/getCountryRestrictionGroups){target="\_self"} * [`/v1/documents`](/api-reference/api-endpoints.html#tag/User%20Documents/getDocuments){target="\_self"} * [`/issuerInitiatedDigitizationDatas`](/api-reference/api-endpoints.html#tag/issuerInitiatedDigitizationData/tavrequestget){target="\_self"} * [`/v1/mccRestrictionGroups`](/api-reference/api-endpoints.html#tag/MCC%20Restriction%20Groups/getMccRestrictionGroups){target="\_self"} * [`/v1/merchantIdRestrictionGroups`](/api-reference/api-endpoints.html#tag/Merchant%20ID%20Restriction%20Groups/getMerchantIdRestrictionGroup){target="\_self"} * [`/v1/recallRs`](/api-reference/api-endpoints.html#tag/Recalls/getRecallRs){target="\_self"} * [`/v1/taxResidences`](/api-reference/api-endpoints.html#tag/User%20Tax%20Residences){target="\_self"} * [`/v1/transactions`](/api-reference/api-endpoints.html#tag/Transactions/getTransactions){target="\_self"} * [`/v1/transfers`](/api-reference/api-endpoints.html#tag/Transfers/getTransfers){target="\_self"} * [`/v1/users`](/api-reference/api-endpoints.html#tag/Users/getUsers){target="\_self"} * [`/v1/virtualIbans`](/api-reference/api-endpoints.html#tag/Virtual%20IBANs/getvirtualibans){target="\_self"} * [`/v1/wallets`](/api-reference/api-endpoints.html#tag/Wallets/getWallets){target="\_self"} ::: ## Cursor-based pagination Cursor-based pagination works by returning a pointer to a specific item in the dataset. Then, you specify one of the returned cursors in your next request to navigate the datasets. Unlike offset pagination, cursor-based pagination is not optional. As soon as you make your request to retrieve your list of objects, the results will be paginated and the first page will be displayed by default. The number of objects returned varies depending on each endpoint. Most endpoints returns `50` objects. ### Cursor object API Responses for endpoints that support cursors include the `cursor` object. ::: code-group ```json [JSON] "cursor": { "prev": null, "current": "356a192b7913b04c54574d18c28d46e6395428ab", "next": "da4b9237bacccdf19c0760cab7aec4a8359010b0" } ``` ::: | Attribute | string | Description | --- | --- | --- | | `prev` | string | Pointer for the previous page. `null` if on the first page. | | `current` | string | Pointer for the current page. | | `next` | string | Pointer for the next page. `null` if on the last page. | If there is no adjacent operation, the `next` attribute will be valued to `null`. The `current` attribute can be cached and used later to only retrieve new operations. ### Parameters [Endpoints supporting cursor-based pagination](#supported-endpoints-1) rely on the `cursor` query parameters for pagination. The size of the subset (number of objects returned) varies depending on each endpoint. Most endpoints returns `50` objects. | Attribute | Description | | --- | --- | | `cursor` | The desired starting position for your next subset of objects. | ### Example When initially using [`{baseUrl}/core-connect/operations`](/api-reference/api-endpoints.html#tag/Operations/getOperations){target="\_self"}, the response returned 50 operations and included the `cursor` object. ::: code-group ```json [JSON] "cursor": { "prev": null, "current": "356a192b7913b04c54574d18c28d46e6395428ab", "next": "da4b9237bacccdf19c0760cab7aec4a8359010b0" } ``` ::: Since there is no `prev` value, we know we are on the first subset of responses. To navigate to the next subset, the `next` value must be used for the `cursor` query parameter, as in the following request: ::: code-group ```bash [CURL] curl -X GET '{baseUrl}/core-connect/operations?walletId={walletId}&dateFrom={dateFrom}&dateTo={dateTo}&cursor=da4b9237bacccdf19c0760cab7aec4a8359010b0' \ --header 'Authorization: Bearer {accessToken}' ``` ::: This returns the next subset of Operations objects, which will include the `cursor` object again: ::: code-group ```json [JSON] "cursor": { "prev": "e99a18c428cb38d5f260853678922e03abd83395", "current": "da4b9237bacccdf19c0760cab7aec4a8359010b0", "next": null } ``` ::: In this example, the `next` value is `null`, indicating that we are on the last subset. ### Supported endpoints Usually, endpoints with a `core-connect` prefix in their path and used to retrieve a list of objects support cursor-based pagination. Some `v1` endpoints have been migrated to this pagination system too. ::: details List of endpoints supporting cursor pagination * [`/core-connect/cardtransactions`](/api-reference/api-endpoints.html#tag/Card%20Transactions/getCoCardTransactions){target="\_self"} * [`/core-connect/cardtransactions/{cardId}`](/api-reference/api-endpoints.html#tag/Card%20Transactions/getCoCardTransaction){target="\_self"} * [`/core-connect/merchantIdRestrictionGroups/{groupId}/mid/metadata`](/api-reference/api-endpoints.html#tag/Merchant%20ID%20Metadata/getAllMidMetadata){target="\_self"} * [`/core-connect/operations`](/api-reference/api-endpoints.html#tag/Operations/getOperations){target="\_self"} * [`/v1/payins`](/api-reference/api-endpoints.html#tag/Payins/getPayins){target="\_self"} * [`/v1/payinrefunds`](/api-reference/api-endpoints.html#tag/Payin%20Refunds/getPayinrefunds){target="\_self"} * [`/v1/payouts`](/api-reference/api-endpoints.html#tag/Payouts){target="\_self"} * [`/core-connect/scheduledPayment`](/api-reference/api-endpoints.html#tag/Scheduled%20Payments/getScheduledPayment){target="\_self"} * [`/core-connect/sca/scawallets`](/api-reference/api-endpoints.html#tag/SCA/getSCAWallets){target="\_self"} ::: --- --- url: /guide/user-verification/documents-prereview.md description: >- Technical guide for pre-reviewing KYC documents via the Treezor API. Includes required parameters, request structure, and response examples. --- # Document pre-review The Documents pre-review process offers another way to upload documents to Treezor. It includes a built-in pre-validation process. Users upload files through pre-signed forms. These files are stored on dedicated servers while your teams review them. The actual Document objects are created in the Treezor API once the files are validated. This is the same method as the one used by the [Dashboard](/guide/dashboard/introduction). **Caution – The Document object is created after pre-validation** While their structure is similar, [objects](#structure) created during the pre-review process aren't [Document](./documents) object. ## Process 1. The end user requests the necessary form to upload the document with the dedicated request: [`/core-connect/users/{userId}/kyc/document`](/api-reference/api-endpoints.html#tag/User%20Document%20Pre-review/getPreSignedKycForm){target="\_self"} 2. The Treezor API answers with the pre-signed form dedicated endpoint. 3. The end user uploads the document using the pre-signed form. 4. You request the download URL of the uploaded document with the dedicated request:[`/core-connect/kyc/documents/{documentId}/preview`](/api-reference/api-endpoints.html#tag/User%20Document%20Pre-review/getPresignedUrlDocument){target="\_self"} 5. The Treezor API answers with the download URL to use in the allocated time frame. 6. You download the document and expose it to your teams for pre-review. 7. Your team members update the document with the dedicated request:[`/core-connect/kyc/documents/{documentId}/status`](/api-reference/api-endpoints.html#tag/User%20Document%20Pre-review/updateDocument){target="\_self"}When doing so, the corresponding [Document](./documents) object is created in the Treezor API. 8. Once all the documents for a given user are uploaded and pre-validated, you request a review process using the [`/v1/users/{userId}/Kycreview`](/api-reference/api-endpoints.html#tag/User%20KYC%20Review/putKycreview){target="\_self"} endpoint. **Tip – You can use pre-signed forms without pre-review** To do so, automate the `PUT /core-connect/kyc/documents/{documentId}/status` request to set the pre-review status to `VALIDATED` and hence creating the Document object in the Treezor API. ## Request the upload form Make the following request to generate the pre-signed form to upload the document. ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/core-connect/users/{userId}/kyc/document' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is `{payload}` example for an ID card (`documentTypeId=9`). ::: code-group ```json [JSON] { "documentType":9, "metadata":[] } ``` ::: Returns the necessary information to upload the document to through the form. ::: code-group ```json [JSON] { "documentId":"900f0614-78ff-49e6-90ec-adaa53de7f43", "form":{ "action":"https:\/\/connect-kyc-files.s3.eu-west-3.amazonaws.com", "method":"POST", "enctype":"multipart\/form-data" }, "formFields":{ "acl":"private", "key":"1625063017_1370854_9_900f0614-78ff-49e6-90ec-adaa53de7f43_0", "Content-Type":"", "X-Amz-Security-Token":"IQo...7x4j", // Truncated for clarity "X-Amz-Credential":"ASI...est", // Truncated for clarity "X-Amz-Algorithm":"AWS4-HMAC-SHA256", "X-Amz-Date":"20210630T142337Z", "Policy":"eyJ...V19", // Truncated for clarity "X-Amz-Signature":"5ae...4f7" // Truncated for clarity }, "expireIn":300 } ``` ::: **Information – The newly exposed endpoint expires after 300 seconds.** The file must therefore be uploaded within 5 minutes of this request. ## Upload documents to the form All the values returned in the previous response are to be used for your request to upload the document: * The `form` object contains your URL (`action`), `method` and `enctype` for your request. * The `formFields` object contains the form inputs. You must provide the document in the `file` input. **Configuration – Documents must:** * Abide by size restrictions (file < 4.5Mo) * Be in mime type: `application/pdf`, `image/jpg`, `image/png`, `image/tiff`, or `image/svg+xml` ::: code-group ```bash [CURL] curl -X POST 'https://connect-kyc-files.s3.eu-west-3.amazonaws.com/' \ -H 'Content-Type: multipart/form-data' \ --form 'acl="{useValueProvidedInThePreviousResponse}"' \ --form 'key="{useValueProvidedInThePreviousResponse}"' \ --form 'Content-Type="{useValueProvidedInThePreviousResponse}"' \ --form 'X-Amz-Security-Token="{useValueProvidedInThePreviousResponse}"' \ --form 'X-Amz-Credential="{useValueProvidedInThePreviousResponse}"' \ --form 'X-Amz-Algorithm="{useValueProvidedInThePreviousResponse}"' \ --form 'X-Amz-Date="{useValueProvidedInThePreviousResponse}"' \ --form 'Policy="{useValueProvidedInThePreviousResponse}"' \ --form 'X-Amz-Signature="{useValueProvidedInThePreviousResponse}"' \ file=@{theDocumentsPath} ``` ::: Answers with a `204 No Content` [HTTP Status Code](/guide/api-basics/response-codes), signaling that the file was succesfully uploaded. You may use the [`/core-connect/users/{userId}/kyc/document`](/api-reference/api-endpoints.html#tag/User%20Document%20Pre-review/getKYCDocuments){target="\_self"} request to retrieve the `documentId` necessary for the next step. ## View the document You must download the file to expose it to your teams for validation. Documents can only be downloaded with the following method during the **pre-review** phase. **Tip – Files are automatically deleted** Validated documents are deleted once the user is validated (i.e., you've received a [`user.kycreview`](/guide/user-verification/events#user-kycreview) webhook with the `kycReview` set to `2`). Use the following request to obtain the URL to view the document. ::: code-group ```bash [CURL] curl -X GET '{baseUrl}/core-connect/kyc/documents/{documentId}/preview' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' ``` ::: Returns the following object containing a `url`. ::: code-group ```json [JSON] { "url":"https:\/\/dev-connect-kyc-files.s3.eu-west-3.amazonaws.com\/161...4_2?X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Security-Token=IQo...Nce&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ASI...est&X-Amz-Date=20210708T092227Z&X-Amz-SignedHeaders=host&X-Amz-Expires=300&X-Amz-Signature=33b...400", "contentType":"image\/jpeg", "duration":300 } ``` ::: You can now download the file using the `url`. **Information – The preview URL expires after 300 seconds.** The file can be viewed for 5 minutes after this request. ## Pre-validate documents Your teams may either validate of refuse a document by updating its pre-review `status`. | Value | Status | Description | | :---: | --- | --- | | `0` | PENDING | The document hasn't been pre-reviewed yet. | | `1` | REFUSED | The document was refused during the pre-review. | | `2` | VALIDATED | The document was validated during the pre-review. As a result, a Document object is created in the Treezor API. | In addition, the `comment` mandatory attribute allows you to specify why the document is accepted or refused. ### Validation of the document Here is an example of request to pre-validate the document. ::: code-group ```bash [CURL] curl -X PUT '{baseUrl}/core-connect/kyc/documents/{documentId}/status' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{ "status": 2, "comment": "This document is fine" #Avoid special characters }' ``` ::: Returns the updated object. ::: code-group ```json [JSON] { "documentId":"1ca27e96-0cf1-45ba-82ea-404f850c2264", "documentType":9, "status":2, "userId":1370854, "createdAt":"2021-03-08T14:13:00+00:00", "metadata":{ "creationdate":"2021-03-08T14:13:00.438Z", "treezor_document_id":"383597" // Created Document object id }, "comment":"This document is fine", "updatedAt":"2021-05-14T11:19:46+00:00" } ``` ::: Once validated, the corresponding Document object is created in the Treezor API and Treezor sends the corresponding [`document.create`](/guide/user-verification/events#document-create) webhook. Since the `metadata` may take a few seconds to be populated, you might not receive it with the API response right away. However, the webhook for document creation contains all the information you need. ::: details Webhook example ::: code-group ```json [JSON] { "webhook":"document.create", "object_payload":{ "documents":[ { "documentId":"383597", // treezor_document_id "documentTag":"", "clientId":"929252", "userId":"1370854", "userFirstname":"Alex", "userLastname":"Oak", "name":"1ca27e96-0cf1-45ba-82ea-404f850c2264", // pre-review document uuid "documentStatus":"PENDING", "documentTypeId":"9", "documentType":"ID", "fileName":"1012512.png", "thumbFileName":"", "createdDate":"2024-07-17 14:34:47", "modifiedDate":"0000-00-00 00:00:00", "codeStatus":"600003", "informationStatus":"", "residenceId":"0", "totalRows":1 } ] }, "object_id":"1012512", "object":"document", "webhook_created_at":17212196888641, "webhook_id":"ca1a6f2f-7d2f-46b8-a1dc-b76e5e656ee6", "object_payload_signature":"IuXf8vyqvswwPKwadf/Encpwe/RiW8ixxxxlLLLM3QY=" } ``` ::: ### Refusal of the document Here is an example of request to refuse the document. ::: code-group ```bash [CURL] curl -X PUT {baseUrl}/core-connect/kyc/documents/{documentId}/status \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{ "status": 1, "comment": "This document is not suitable" #Avoid special characters }' ``` ::: Returns the updated object. ::: code-group ```json [JSON] { "documentId":"1ca27e96-0cf1-45ba-82ea-404f850c2264", "documentType":9, "status":1, "userId":1370854, "createdAt":"2021-03-08T14:13:00+00:00", "metadata":{ "creationdate":"2021-03-08T14:13:00.438Z" }, "comment":"This document is not suitable", "updatedAt":"2021-07-08T09:31:03+00:00" } ``` ::: ## Structure The file for pre-review is slightly different from the actual [Document object](./documents), starting with the fact that the `documentId` is an UUID and the `status` indicates the pre-validation status. ::: code-group ```json [JSON] [ { "documentId": "bb18a003-050c-4acb-b33e-e44f26534b87", "documentType": 9, "status": 0, "userId": 100554428, "createdAt": "2024-07-15T13:45:48+00:00", "metadata": [], "comment": "", "updatedAt": "2024-07-15T15:48:23+02:00" } ] ``` ::: ## Endpoints | Endpoint |[Scope](/guide/api-basics/authentication#available-scopes) | | --- | --- | | [`/core-connect/users/{userId}/kyc/document`](/api-reference/api-endpoints.html#tag/User%20Document%20Pre-review/getPreSignedKycForm){target="\_self"} Create a pre-signed form to upload document | `read_write` | | [`/core-connect/users/{userId}/kyc/document`](/api-reference/api-endpoints.html#tag/User%20Document%20Pre-review/getKYCDocuments){target="\_self"} Retrieve the pre-review documents for a user | `legal` | | [`/core-connect/kyc/documents/{documentId}/preview`](/api-reference/api-endpoints.html#tag/User%20Document%20Pre-review/getPresignedUrlDocument){target="\_self"} Retrieve a pre-signed URL to download the document | `legal` | | [`/core-connect/kyc/documents/{documentId}/status`](/api-reference/api-endpoints.html#tag/User%20Document%20Pre-review/updateDocument){target="\_self"} Update the pre-review document status | `legal` | | [`/v1/users/{userId}/Kycreview`](/api-reference/api-endpoints.html#tag/User%20KYC%20Review/putKycreview){target="\_self"} Initiate the user [KYC review](/guide/user-verification/introduction) process | `read_write` | | [`/core-connect/kyc/documents/{documentId}`](/api-reference/api-endpoints.html#tag/User%20Document%20Pre-review/deleteKYCDocumentcument){target="\_self"} Delete a pre-review document | `legal` | --- --- url: /guide/transfers/proof-of-payout.md description: >- Technical guide for generating proof of payout documents via the Treezor API. Includes required parameters, request structure, and response examples. --- # Proof of Payout Proof of Payout are PDF documents that can be generated to prove the creation of a Payout. ## Templates Proof of Payouts can be templated using Treezor [template feature](/guide/api-basics/templates). ## Retrieval To retrieve a proof of payout, use the following request. ::: code-group ```bash [CURL] curl -X GET '{baseUrl}/core-connect/payouts/{payoutId}/proof' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ ``` ::: Returns an object containing a download URL (`link`) which **expires after 5 minutes**: ::: code-group ```json [JSON] { "link": "https://xxxxxx.s3.eu-west-3.amazonaws.com/tmp/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxx.pdf", "expireIn": 300 } ``` ::: --- --- url: /guide/overview/tinker.md description: >- Get a first taste of the Treezor API by following these simple testing steps. Explore various functionnalities with request and examples, from authentication to the first payment. --- # Quickstart Not sure where to start? Find below the testing steps for you to start exploring the Treezor API capabilities in Sandbox. **Tip – Rely on Treezor [Webhooks](/guide/webhooks/introduction) and [Dashboard](/guide/dashboard/introduction)** These tools will allow you to better visualize the results of your testing. ## Authenticate to your Sandbox **Reading – Related documentation in API Basics** [Environments](/guide/api-basics/environments) | [Credentials](/guide/api-basics/authentication#credentials) | [Authentication](/guide/api-basics/authentication) | [Scope & Permissions](/guide/api-basics/authentication) Once you have your `client_id` and `client_secret` for your Sandbox environment, you can generate your JSON Web Token (JWT) that you will use to authenticate your API requests. ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/oauth/token' \ --form 'grant_type="client_credentials"' \ # required --form 'client_id=""' \ # required --form 'client_secret=""' \ # required # --form 'scope=""' # optional ``` ::: Returns the `access_token` for you to use in the `Authorization` header of all your subsequent requests. ::: code-group ```json [JSON] { "token_type": "Bearer", "expires_in": 3600, "access_token": "eyJ0eX[...]PcOIkQ" } ``` ::: **Note – The access token expires after 1 hour** Read how to extend its lifetime in the [Authentication](/guide/api-basics/authentication) article. ## Create a User **Reading – Related documentation** [Users](/guide/users/introduction) | [Physical Users](/guide/users/physical) In this example, your end user is a physical person to whom you will offer banking services thanks to Treezor. You can use the following request to create a [physical user](/guide/users/physical). Endpoint: [`/v1/users`](/api-reference/api-endpoints.html#tag/Users/postUsers){target="\_self"} ::: code-group <<< @/guide/users/snippets/create\_user.bash \[CURL] ::: Here is a `{payload}` example: ::: code-group ```json [JSON] { "userTypeId":1, // required, 1 is for Physical User "specifiedUSPerson":0, // required "title": "MX", "firstname":"Alex", "lastname": "Oak.userStatusValidated", // Suffix to emulate VALIDATED status "email":"aoak@example.com", // required, must be unique "address1":"101 Willow lane", // required to create a Card later on "phone":"+33102030405" // required to create a Card later on } ``` ::: Returns the new [User](/guide/users/introduction) with its `id` (1545392) that you will use for the next steps. ::: code-group ```json [JSON] {4} { "users": [ { "userId": 8327278, "userTypeId": 1, "userStatus": "VALIDATED", "userTag": "", "parentUserId": 0, "parentType": "", "controllingPersonType": 0, "employeeType": 0, "specifiedUSPerson": 0, "title": "MX", "firstname": "Alex", "lastname": "Oak", "middleNames": "", "birthday": "", "email": "alex.oak@example.com", "address1": "101 Willow lane", "address2": "", "postcode": "", "city": "", "state": "", "country": "", "countryName": "", "distributionCountry": null, "phone": "+33102030405", "mobile": "", "nationality": "", "nationalityOther": "", "placeOfBirth": "", "birthCountry": "", "occupation": "", "incomeRange": "", "legalName": "", "legalNameEmbossed": "", "legalRegistrationNumber": "", "legalTvaNumber": "", "legalRegistrationDate": "0000-00-00", "legalForm": "", "legalShareCapital": 0, "entityType": 0, "legalSector": "", "legalAnnualTurnOver": "", "legalNetIncomeRange": "", "legalNumberOfEmployeeRange": "", "effectiveBeneficiary": 0, "kycLevel": 0, "kycReview": 0, "kycReviewComment": "", "isFreezed": 0, "isFrozen": null, "language": "", "optInMailing": null, "sepaCreditorIdentifier": "", "taxNumber": "", "taxResidence": "", "position": "", "personalAssets": "", "personalAssetsRange": 2, "createdDate": "2024-11-13 07:40:10", "modifiedDate": "0000-00-00 00:00:00", "walletCount": 0, "payinCount": 0, "totalRows": "1", "activityOutsideEu": 0, "economicSanctions": 0, "residentCountriesSanctions": 0, "involvedSanctions": 0, "address3": null, "timezone": null, "occupationType": "", "isOnStockExchange": 0, "secondaryAddress1": "", "secondaryAddress2": "", "secondaryAddress3": "", "secondaryPostcode": "", "secondaryCity": "", "secondaryState": "", "secondaryCountry": "", "clientId": "929252", "sanctionsQuestionnaireDate": null, "codeStatus": "110009", "informationStatus": "", "legalSectorType": "", "sourceOfFunds": "", "distributionCountry": null, "entitySanctionsQuestionnaire": 0, "occupationCategory": 5, "monthlyIncomeRange": 2 } ] } ``` ::: **Note – Treezor API offers a variety of Users to fit your use cases** You could also create other types of users, such as [Legal Entities](/guide/users/legal-entity) and [Anonymous Users](/guide/users/physical#anonymous-users). Users can also be linked by hierarchical relations referred to as [parent-children relations](/guide/users/parent-children). ## Simulate User KYC validation **Reading – Related documentation** [User verification (KYC)](/guide/user-verification/introduction) | [KYC Simulation](/guide/user-verification/faking-operations) In real life, Users must be verified to use Treezor services. This process includes sending documents and declarative data for Treezor to manually approve the User. In Sandbox, you can use the following request to [force the KYC validation](/guide/user-verification/faking-operations), allowing you to proceed with the next steps. Endpoint: [`/v1/users/{userId}`](/api-reference/api-endpoints.html#tag/Users/putUser){target="\_self"} ::: code-group <<< @/guide/users/snippets/update\_user.bash \[CURL] ::: Here is a `{payload}` example with the `.validated` suffix to approve the KYC in Sandbox: ::: code-group ```json [JSON] { "lastname":"Oak.validated" } ``` ::: Returns the new [User](/guide/users/introduction), but you might not see they are verified right away. You need to make a [`/v1/users/{userId}`](/api-reference/api-endpoints.html#tag/Users/getUser){target="\_self"} call to see the User object with the updated [`kycLevel` and `kycReview`](/guide/user-verification/introduction#user-kyc-levels-kyclevel). ::: code-group ```json [JSON] {3,4} { "userId":1545392, "kycLevel":"2", "kycReview":"2" // [...] some attributes are hidden } ``` ::: ## Create a Wallet **Reading – Related documentation** [Wallets](/guide/wallets/introduction) | [Wallet Creation](/guide/wallets/creation) Let's create a payment account, which is represented by the [Wallet](/guide/wallets/introduction) object in the API. We will define the previously created [User](/guide/users/introduction) as its owner. Endpoint : [`/v1/wallets`](/api-reference/api-endpoints.html#tag/Wallets/postWallets){target="\_self"} ::: code-group <<< @/guide/wallets/snippets/create\_wallet.bash \[CURL] ::: Here is a `{payload}` example: ::: code-group ```json [JSON] { "walletTypeId":10, // required, 10 = Payment Account Wallet "tariffId": 123, // usually required, fees applied to the Wallet, as defined by your contract with Treezor "userId":1545392, // required, attach this wallet to the previously created user "currency":"EUR", // required "eventName":"AO's Account" // required, name the wallet } ``` ::: Returns a [Wallet](/guide/wallets/introduction) object, with its `id` (826210) and its ready-to-use [IBAN](/guide/wallets/iban): ::: code-group ```json [JSON] {4,23} { "wallets": [ { "walletId": 2702198, "walletTypeId": 10, "walletStatus": "VALIDATED", "codeStatus": 120005, "informationStatus": "", "walletTag": "", "userId": 1545392, "userLastname": "Oak.validated", "userFirstname": "Alex", "jointUserId": 0, "tariffId": 136, "eventName": "AO's Account", "eventAlias": "ao-s-account-65df2ab48f029", "eventDate": "2024-03-06", "eventMessage": "", "eventPayinStartDate": "2024-02-28", "eventPayinEndDate": "0000-00-00", "contractSigned": 0, "bic": "TRZOFR21XXX", "iban": "FR7616798000010000270219811", "urlImage": "", "currency": "EUR", "createdDate": "2024-02-28 13:44:36", "modifiedDate": "0000-00-00 00:00:00", "payinCount": 0, "payoutCount": 0, "transferCount": 0, "solde": 0, "authorizedBalance": 0, "totalRows": 1, "country": "FR" } ] } ``` ::: **Note – Treezor API offers a variety of Wallets to fit your use cases** There are [different types of wallets](/guide/wallets/introduction), some requiring [KYC validation](/guide/user-verification/introduction), some that don't. ## Credit the Wallet **Reading – Related documentation** [Wallets](/guide/wallets/introduction) | [SEPA Transfers](/guide/transfers/introduction) | [SCTR Simulation](/guide/transfers/faking-operations#sctr) Let's simulate a payin into a [Wallet](/guide/wallets/introduction) by emulating an [incoming SEPA Transfer](/guide/transfers/credit-transfer#received-credit-transfers-sctrs). These fictitious funds will then be useful to further test Treezor abilities, such as payouts to external accounts, or Wallet-to-Wallet transfers. Here is the simulation request, in which you must pass the IBAN of the wallet to credit and the amount (integer) to credit. ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/simulation/payin-sct' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}` ::: code-group ```json [JSON] { "iban":"FR7616798000010001726649397", "amount": 20 } ``` ::: Returns the `id` of the SCTR, its `txId` (transaction `Id`) and its `payinId`. ::: code-group ```json [JSON] { "sctrs": [ { "id": 10116, "txId": "1zS0fKXhAuzDnNBL", "payinId": 1287763, "returnReasonCode": null } ] } ``` ::: **Note – Discover all the ways to credit a Wallet** Treezor offers a large range of payins for you to credit wallets. Learn more in the [How to credit wallets](/guide/wallets/introduction#how-to-credit-wallets-top-up) article. ## Check the Wallet Balance **Reading – Related documentation** [Wallets](/guide/wallets/introduction) | [Balances](/guide/wallets/balances) Let's make sure the Wallet was properly credited by checking its [Balance](/guide/overview/glossary#balance). Use the following request to retrieve a given Wallet Balance, with the corresponding `walletId` expected as a query parameter. Endpoint: [`/v1/balances/{walletId}`](/api-reference/api-endpoints.html#tag/Balances/getBalances){target="\_self"} ::: code-group ```bash [CURL] curl -X GET '{baseUrl}/v1/balances?walletId=826210' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ ``` ::: Returns the Balance object, with both the [Authorized Balance](/guide/overview/glossary#balance) (`authorizedBalance`) and [Balance](/guide/overview/glossary#balance) (`currentBalance`). ::: code-group ```json [JSON] { "balances": [ { "walletId": 826210, "currentBalance": 50, // Actual Balance, as credited in the previous step "authorizations": 0, // Currently pending authorizations "authorizedBalance": 50, // Balance, minus pending authorizations "currency": "EUR", // Currency of the balance "calculationDate": "2024-02-01 15:52:40" // When the Balance was last actualized } ] } ``` ::: **Tip – Balance History is available** The dedicated [Balance History endpoint](/guide/wallets/balances#check-the-balance-history) gives the Balance evolution over time. ## Create a Beneficiary **Reading – Related documentation** [Beneficiaries](/guide/transfers/beneficiaries) | [SEPA Transfers](/guide/transfers/introduction) To send money to bank accounts outside your Treezor environment, you must create a [Beneficiary](/guide/transfers/beneficiaries) beforehand. Endpoint: [`/v1/beneficiaries`](/api-reference/api-endpoints.html#tag/Beneficiaries/postBeneficiary){target="\_self"} ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/v1/beneficiaries' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "userId":123456, // required, user ID allowed to use the beneficiary "name":"Chris Oak", // Name of the Beneficiary "tag":"oak-1982", // Custom field you're free to populate "nickName":"C. Oak checking", // Alias of the Beneficiary "address":"Woods Bank", "iban":"FR7616798000010000012345678", // required, IBAN of the Beneficiary "bic":"TRZOFR21XXX", // required, BIC of the Beneficiary "usableForSct":true // required, if the Beneficiary can be used for SCT } ``` ::: Returns the [Beneficiary](/guide/transfers/beneficiaries) object, with its `id` allowing you to send funds to it using a Payout. ::: code-group ```json [JSON] { "id": 11XXXX8, "tag": "oak-1982", "userId": 22XXXX6, "nickName": "C. Oak checking", "name": "Chris Oak", "address": "Woods Bank", "iban": "2XXXXXXXX X X 7XXXXXXXXX5 X X 75XXXXXXXX6 X X 1XXXXX4", "bic": "BNPAFRPP", "sepaCreditorIdentifier": "", "sddB2bWhitelist": [], "sddCoreBlacklist": [], "usableForSct": true, "sddCoreKnownUniqueMandateReference": [], "isActive": true } ``` ::: ## Send funds to an external account **Reading – Related documentation** [Wallets](/guide/wallets/introduction) | [SEPA Transfers](/guide/transfers/introduction) This sends funds from the created [Wallet](/guide/wallets/introduction), to the created [Beneficiary](/guide/transfers/beneficiaries) using a [SEPA transfer](/guide/transfers/introduction). ::: code-group <<< @/guide/transfers/snippets/create\_payout.bash \[CURL] ::: Here is an example of `{payload}` with an amount ending in `1.25` to emulate the `VALIDATED` status of the payout. Endpoint: [`/v1/payouts`](/api-reference/api-endpoints.html#tag/Payouts/postPayout){target="\_self"} ::: code-group ```json [JSON] { "walletId":826210, // required, the wallet to debit "beneficiaryId":{beneficiaryId}, // required, id of the beneficiary created in the previous step "amount":11.25, // required, must end with 1.25 for VALIDATED "currency":"EUR" // required } ``` ::: Returns a Payout object with its `id`. ::: code-group ```json [JSON] { "payoutId": "", "payoutTag": "", "payoutStatus": "", "payoutTypeId": , "payoutType": "", "walletId": , "payoutDate": "", "walletEventName": "", "userId": , "beneficiaryId": , "amount": "", "currency": "" // [...] some attributes are hidden } ``` ::: **Tip – SEPA Direct Debit also available** You could also use [Direct Debit](/guide/transfers/direct-debit#received-direct-debits-sddr) to debit funds from the Wallet to an external account. ## Send funds to another Wallet **Reading – Related documentation** [Wallets](/guide/wallets/introduction) | [Wallet-to-Wallet Transfers](/guide/transfers/wallet-to-wallet) You can also transfer funds from one [Wallet](/guide/wallets/introduction) to another in your Treezor environment. Endpoint: [`/v1/transfer`](/api-reference/api-endpoints.html#tag/Transfers/postTransfers){target="\_self"} ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/v1/transfers' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is a `{payload}` example: ::: code-group ```json [JSON] { "walletId":826210, // required, source wallet for the transfer "beneficiaryWalletId":123456, // required, destination wallet for the transfer "amount":21.25, // required "currency":"EUR" // required } ``` ::: Returns a Transfer object. ::: code-group ```json [JSON] { "transfers": [ { "transferId": 4269222, "transferStatus": "VALIDATED", "transferTag": "", "walletId": 826210, "walletTypeId": 10, "beneficiaryWalletId": 2301937, "beneficiaryWalletTypeId": 10, "walletEventName": "Account A", "walletAlias": "account-63346a643a7fa", "beneficiaryWalletEventName": "Main account", "beneficiaryWalletAlias": "main-account-64ad18c128f29", "amount": "21.25", "currency": "EUR", "label": "", "transferTypeId": 1, "createdDate": "2024-02-07 14:17:51", "modifiedDate": "2024-02-07 14:17:51", "totalRows": null, "foreignId": null, "partnerFee": null, "codeStatus": "150005", "informationStatus": null, "metadata": null } ] } ``` ::: You can now [recheck the balance](#check-the-balance-of-the-wallet) of the Wallet. ## Create a Card to make payments **Reading – Related documentation** [Cards](/guide/cards/introduction) | [Card Program](/guide/cards/introduction#card-program) | [Card Creation](/guide/cards/creation) If you already have a `cardPrint` provided once your [Card Program](/guide/cards/introduction#card-program) is set up, you can test the creation of [Virtual Card](/guide/cards/introduction) and/or [Physical Cards](/guide/cards/introduction). Let's take the example of the [Virtual Card](/guide/cards/introduction) creation. Endpoint: [`/v1/cards/CreateVirtual`](/api-reference/api-endpoints.html#tag/Cards/postCardVirtual){target="\_self"} ::: code-group <<< @/guide/cards/snippets/create-card-virtual.bash \[CURL] ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "userId":1545392, // required, card owner "walletId":826210, // required, wallet to which the card will be associated "permsGroup":"TRZ-CU-016", // required, defines a set of permissions for the card "cardPrint":"{cardPrint}" // required, as a string, defines your card program and card design } ``` ::: Returns a Card object with its `id`, expiration date, [CVV](/guide/overview/glossary#card-verification-number-cvc), etc. ::: code-group ```json [JSON] { "cardId": "10xxxx4", "userId": "22xxxx7", "walletId": "2xxxxx1", "walletCardtransactionId": "2xxxxx1", "expiryDate": "2023-06-30", "CVV": "757", "physical": "0" // [...] some attributes are hidden } ``` ::: **Note – A lot of options come with your Card Product** You can set [withdrawals and payments limits](/guide/cards/restrictions-limits#payment-withdrawal-limits), [options for payments](/guide/cards/restrictions-limits#options-permission-groups), restrictions based on [countries](/guide/cards/restrictions-limits#country-restrictions), [business categories](/guide/cards/restrictions-limits#mcc-restrictions), and [merchants](/guide/cards/restrictions-limits#mid-restrictions). You can also [digitize cards](/guide/cards/x-pay-google-apple) with Apple Pay, Google Pay and Samsung Pay. ## Simulate a Card Transaction **Reading – Related documentation** [Cards](/guide/cards/introduction) | [Card Transactions](/guide/cards/transactions#card-program) | [Card Transaction simulation](/guide/cards/faking-operations) Now that you've created a Virtual Card, you may simulate a Card Transaction. ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/simulation/cardtransactions' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ --data-raw '{payload}' ``` ::: Here is a `{payload}` example: ::: code-group ```json [JSON] { "publicToken": "103020378", "date": "2022-02-12 13:00:00", "amount": 15.90, "mcc": "8574", "merchantId": "3256", "merchantName": "Merchant Name", "paymentStatus": "A", "paymentCode": "100000000000004" } ``` ::: The request returns a `201` HTTP Status Code without any content. **Note – Disclaimers about simulating card transactions** * No Wallet balance update: sends a [`balance.update`](/guide/wallets/events#balance-update) webhook with `0` values. * No refunds and negative amount settlements support yet. --- --- url: /guide/user-verification/kyc-request.md description: >- Technical guide for making a KYC request via the Treezor API. Includes required parameters, request structure, and response examples. --- # KYC Request Prior to requesting a KYC Review for a user, make sure that: * All the necessary declarative data has been provided in the [User](/guide/users/introduction) object * All the necessary [Documents](/guide/user-verification/documents) have been uploaded and checked * The country of [tax residency](/guide/user-verification/tax-residence) has been properly declared **Best practice – Submitting a KYB must be done for all users at once** The legal entity, its legal representative and shareholders are reviewed as a whole. You can submit the legal entity KYB request only once you have provided all the required documents for all the corresponding users. The more you abide by the rules of verification, the more efficient Treezor teams will be in verifying your users, allowing for a much smoother experience. ## Request a review of the user Endpoint: [`/v1/users/{userId}/Kycreview`](/api-reference/api-endpoints.html#tag/User%20KYC%20Review/putKycreview){target="\_self"} ::: code-group ```bash [CURL] curl -X PUT '{baseUrl}/v1/users/{userId}/Kycreview' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' ``` ::: It returns the User object, with its `kycLevel` set to `0` **(NONE)** and `kycReview` set to `1` **(PENDING)**. ::: code-group ```json [JSON] { "users": [ { "userId": "1611975", "userTypeId": "1", "kycLevel": "0", // <--- 0 means NONE "kycReview": "1", // <--- 1 means PENDING "kycReviewComment": "", // <--- No comment has been set by Treezor yet [...] // some attributes are hidden } ] } ``` ::: Treezor also sends a [`user.kycrequest`](./events#user-kycrequest) webhook. Once the user refused or validated, you receive a [`user.kycreview`](./events#user-kycreview) webhook. **Information – Treezor's Compliance team verifies your company in Production** Verification usually takes about 24h, but may take up to 48h or more (working days only). --- --- url: /guide/users/restricted-users.md description: >- Understand the restrictions that may be placed upon end users as part of your obligations to prevent the misuse of the financial system for illegitimate purposes. Includes required parameters, request structure, and response examples. --- # Restricted Users ## Introduction The obligations placed on banking services providers aim to prevent the misuse of the financial system for illegitimate purposes, as stated by the [anti-money laundering and countering the financing of terrorism (AML/CFT)](/guide/overview/glossary#anti-money-laundering-and-countering-the-financing-of-terrorism-aml-cft) rules. In this context, Treezor may restrict the usage of the API to some Users to provide a compliant and secure banking ecosystem. ### Types of User restrictions There are 2 ways a user may be under restrictions: | Restriction type | Field | Usage | | ---- | --- | --- | | [Freeze](#freeze) | `isFrozen` | Allows operational teams to block the user’s assets, preventing most payout operations from their wallets. This feature may be open for as an operational tool. | | [Legal Freeze](#legal-freeze) | Not exposed | Freezes the user’s assets, preventing funds from being debited from their Wallets. Treezor freezes assets when the user is deemed unfit to use banking services based on AML/CFT regulations. This feature is only open to Treezor. | **Important – Don’t share their blocked status with end users** Due to legal implications, you mustn’t let your users know if their assets are frozen. ### Blocked operations When a User is blocked, some operations on their Wallets are no longer possible while others are still permitted. Below is the list of available operations by user restriction status. | Operation | Type | `isFrozen` | `IsLegalFrozen` | | --- | --- | :---: | :---: | | Card transactions | Payout | | | | Emitted wallet-to-wallet transfers | Payout | | | | Received wallet-to-wallet transfers | Payin | | | | Emitted SEPA Credit Transfers (including SCTE Inst) | Payout | | | | Received SEPA Credit Transfers (including SCTR Inst) | Payin | | | | Emitted SEPA Direct Debit | Payin | | | | Received SEPA Direct Debit | Payout | | | | Card acquiring | Payin | | | | Check cashing | Payin | | | Operations such as SEPA Recalls & RROs, as well as Refunds may be enabled or not depending on the situation, and may be manually checked by Treezor teams prior to blocking. ## Freeze When a User is blocked with the `isFrozen` status, all payout operations **except** SDDR are forbidden while it’s still possible to credit their Wallet with payins. Also, Treezor notifies you through a `user.update` webhook with the `isFreezed` field valued to `1` when a user is blocked. ### Block a User This endpoint is only available if you’re a [Regulated Institution](/guide/overview/glossary#regulated-institution). If you’re not, you may contact Treezor for any action relative to blocking/unblocking users. #### Parameters | Attribute | Type | Description | | --- | --- | --- | | `isFrozen` | integer | Indicates whether to freeze or unfreeze the user. `0` – The User isn’t frozen `1` – The User is frozen| | `comment` | string | Explanation for the blocked status of the user. You can’t retrieve this value afterward. | #### Request You can use the following request with the `admin` scope to freeze/unfreeze a user. ::: code-group ```bash [CURL] curl -X PUT '{baseUrl}/v1/users/{userId}/FreezeAssets' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "isFrozen":1, "comment":"Mandatory comment explaining the reason for freezing" } ``` ::: Returns the User object, with the corresponding `isFrozen` attribute updated accordingly. ## Legal Freeze This endpoint is only available if you’re a [Regulated Institution](/guide/overview/glossary#regulated-institution). If you’re not, you may contact Treezor for any action relative freeze and unfreeze a user's assets. When a User has the `IsLegalFrozen` status, all payout operations **including** SDDR are forbidden while it’s still possible to credit their Wallet with payins. Treezor notifies you through a `user.update` webhook with the `IsLegalFrozen` field valued to `1`. --- --- url: /guide/strong-customer-authentication/authenticating.md description: >- Technical guide for authenticating in the name of your end user for SCA. Learn how to obtain your SCA proof (JWS) and use it to request a JWT to authenticate. Includes required parameters, request structure, and response examples. --- # SCA Authentication ## Key principles Before the SCA mechanism, all your requests to the Treezor API were made using the same [authentication token](/guide/api-basics/authentication). To leverage the SCA mechanism, your requests to the Treezor API will have to be made ***in the name of*** each end user, using a distinct authentication token. ```mermaid flowchart LR A("End User A") B("End User B") C("End User C") D("Your back end") F("Treezor API") A --> D B --> D C --> D D -- User A's JWT --> F D -- User B's JWT --> F D -- User C's JWT --> F class D dark; class F neutral; ``` To make requests in the name of the end user, you: 1. [Obtain an SCA Proof](#obtain-an-sca-proof) in the form of a JSON Web Signature (JWS) using the [Mobile SDK](sdk) or [Web Native](introduction#web-native) on the end user's device. 2. Provide this SCA Proof and a different [grant type](#parameters) when [requesting a JWT](#request-the-end-user-s-jwt). 3. Use this JWT to authenticate all future requests to the Treezor API made in the name of that end user. Depending on the type of SCA Proof provided, the JWT will contain a `trz:sca` attribute valued to: * `false` if the provided SCA was of type `None`. * `true` if any stronger type of authentication was used (Biometry, Passcode, etc.). **Information – SCA type other than `None` required every 180 days** The end user is required to authenticate using a stronger SCA type (Biometry, Passcode, etc.) if no authentication using an SCA type other than `None` occurred in the last 180 days. ## Obtain an SCA Proof **Prerequisites – Users must be enrolled first** For both the mobile and web native solutions, the user must have an active SCA Wallet. See [Enrolling users](user-enrollment) for more information. ### Mobile signature ::: tabs \== Mobile SDK SCA proof capabilities are provided by the SDK via `CustomerAuthenticatedSignature`, it produces a signature once the user has performed the required authentication. This signature is generated locally within Entrust SDK and is returned to the hosting app. `CustomerAuthenticatedSignature` must first be instantiated with the following parameters. | Parameter | Description | | --- | --- | | `patternName` | The name of the authentication pattern to use for this authentication. Can be:`patterns.NONE.name` for none authentication`patterns.PIN.name` for PIN authentication`patterns.BIOMETRY.name` for Biometric authentication | | `message` | The message to display to the customer. Must be set if the SDK is used to display the UI. In any case, this information is part of the signed data. | | `signatureType` | Type of signature result to generate. You must use the `CustomerAuthenticatedSignatureType.LocalJws` option. | | `signatureInputData` | Custom, context-related information that is part of [the signed data](sdk#payload). | Once instantiated, you must call `CustomerAuthenticatedSignature#sign()` to start the signature process. When the `CustomerAuthenticatedSignature` is successfully completed, you're notified by the `CustomCustomerAuthenticatedProcessCallback#onProcessSuccess()` callback. The generated signature result can be fetched by calling `CustomerAuthenticatedSignature#getResult()`. See the SDK [Signature](/guide/strong-customer-authentication/sdk#signature) article for more information. \== Mobile Abstraction Layer After [connecting to an SCA Wallet](sdk-abstraction#connect-to-an-sca-wallet), you can generate an SCA proof with or without user action. ::: code-group ```js [JavaScript - Without user action] // Generate a JWS to make session calls const signature = await sign(); const decoded = jwtDecode(signature); console.info(decoded); ``` ```js [JavaScript – With user action] // Generate a JWS to make session calls const signature = await sign({ type: 'authenticate' }); const decoded = jwtDecode(signature); console.info(decoded); ``` ::: ### Web Native signature Once the browser has undergone the [enrollment](user-enrollment#web-native-enrollment), it is able to produce SCA signatures. SCA enforcement requires that all request to the Treezor API be made [in the name of the User](#key-principles). Therefore, when obtaining a JWT, you must now provide an SCA proof. The following code snippet shows how to generate an SCA proof that can then be used to obtain a JWT. ::: code-group ```js [JavaScript] const publicKeyCredentialRequestOptions = { challenge: convertToArrayBuffer(JSON.stringify({ iat: Date.now() })), // for the login step, you must strictly provide the challenge above allowCredentials: [ { id: base64URLStringToBuffer(publicKeyCredentialId), // publicKeyCredentialId from "authenticationMethods" on the scawallets of the user type: type, // type from "authenticationMethods" on the scawallets of the user transports: transports // transports [] from "authenticationMethods" on the scawallets of the user } ], // the list of active scawallets of the user with "settingsProfile": "webauthn" timeout: 60000, // time in milliseconds for the end user to complete the WebAuthn flow rpId: 'www.example.com', // the current FQDN, must be the same used during enrollment flow }; const assertion = await navigator.credentials.get({ publicKey: publicKeyCredentialRequestOptions }); const response = assertion.response; const rawId = arrayBufferToBase64Url(assertion.rawId).toString(); const clientDataJSON = arrayBufferToBase64Url( assertion.response.clientDataJSON ).toString(); const authenticatorData = arrayBufferToBase64Url( response.authenticatorData ).toString(); const signature = arrayBufferToBase64Url(response.signature).toString(); const userHandle = arrayBufferToBase64Url(response.userHandle).toString(); let encodedResponse = btoa( JSON.stringify({ response: { authenticatorData, clientDataJSON, signature, userHandle, }, id: assertion.id, rawId, type: "public-key", }) ); ``` ::: Details of `base64URLStringToBuffer` method. ::: code-group ```js [JavaScript] export function base64URLStringToBuffer(base64URLString: string): ArrayBuffer { // Convert from Base64URL to Base64 const base64 = base64URLString.replace(/-/g, "+").replace(/_/g, "/"); /** * Pad with '=' until it's a multiple of four * (4 - (85 % 4 = 1) = 3) % 4 = 3 padding * (4 - (86 % 4 = 2) = 2) % 4 = 2 padding * (4 - (87 % 4 = 3) = 1) % 4 = 1 padding * (4 - (88 % 4 = 0) = 4) % 4 = 0 padding */ const padLength = (4 - (base64.length % 4)) % 4; const padded = base64.padEnd(base64.length + padLength, "="); // Convert to a binary string const binary = atob(padded); // Convert binary string to buffer const buffer = new ArrayBuffer(binary.length); const bytes = new Uint8Array(buffer); for (let i = 0; i < binary.length; i++) { bytes[i] = binary.charCodeAt(i); } return buffer; } ``` ::: Request the User to enter their passcode and encrypt it. ::: code-group ```js [JavaScript] const encryptedPassCode = encryptPasscode(passCode) // see Passcode encryption section below regarding how to encrypt the passcode ``` ::: The two strings from the previous steps should now be concatenated with a dot as follows: ::: code-group ```js [JavaScript] const sca = `${encryptedPassCode}.${encodedResponse}` // concatenate these values with a dot ``` ::: ## Request the end user's JWT ### Parameters | Parameter | Description | | --- | --- | | `client_id` | The `client_id` as per your [usual authentication flow](/guide/api-basics/authentication). | | `client_secret` | The `client_secret` as per your [usual authentication flow](/guide/api-basics/authentication). | | `username` | The `userId` or the end user's email, as used in [User](/guide/users/introduction) objects | | `password` | A hash to be generated by concatenating `userId` with `client_secret` and hashing the string using `sha256` i.e., `sha256(userIdclient_secret)`. | | `grant_type` | Must be set to `delegated_end_user`. | | `sca` | The SCA proof (which can be generated using a type [`None`](sdk#methods) if a stronger type was used in the last 180 days). | In return, Treezor provides you with a JWT for all subsequent requests to the Treezor API made in the name of that User. It must be placed in the `Authorization: Bearer` header as described in the [Authentication](/guide/api-basics/authentication#using-the-token) article. ### Request example ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/oauth/token' \ --form 'grant_type="delegated_end_user"' \ --form 'client_id="{clientId}"' \ --form 'client_secret="{clientSecret}"' \ --form 'scope="read_write"' \ --form 'username="101109094"' \ --form 'password="bc6ead2bbcd9cc409ba53d9cfbf145a667647414eae496xxxx75636b15384a8"' \ --form 'sca="eyJh_NDN9.WQBp_Xg7w"' ``` ::: Returns the Bearer token: ::: code-group ```json [JSON] { "token_type": "Bearer", "expires_in": 3600, "access_token": "eyJ0_XXX_q44Q" } ``` ::: ## Make requests in the name of the end user Here is an example for creating a Beneficiary (per-operation SCA, so you need another SCA proof prior to this action). ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/v1/beneficiaries' \ --header 'Authorization: Bearer eyJ0_XXX_q44Q' \ --header 'Content-Type: application/json'\ --data '{payload}' ``` ::: With the following `{payload}`: ::: code-group ```json [JSON] { "userId": "101109094", "name": "Alex Oak", "adress": "33 av de Wagram Paris", "iban": "FR1130003000305928344XXXXX", "bic": "SOGEFRPPXXX", "usableForSct": true, "sca":"eyJh_UxfQ.nNIH_n9kA" // SCA proof that you need as a prerequisite } ``` ::: Returns the Beneficiary object: ::: code-group ```json [JSON] { "beneficiaries": [ { "id": 527977, "tag": "", "userId": 101109094, "nickName": "", "name": "Alex Oak", "address": "", "iban": "3537524356444355504255444055564B574C405157455041XXXX", "bic": "SOGEFRPPXXX", "sepaCreditorIdentifier": "", "sddB2bWhitelist": [], "sddCoreBlacklist": [], "usableForSct": true, "sddCoreKnownUniqueMandateReference": [], "isActive": true, "createdDate": "2024-11-21 08:05:56", "modifiedDate": "2024-11-21 08:05:56", "metadata": { "iban": "FR1130003000305928344XXXXX" } } ] } ``` ::: --- --- url: /guide/strong-customer-authentication/errors.md description: >- Troubleshoot and handle strong customer authentication-related issues using the Treezor API's complete list of error messages and codes, and their corresponding meanings. --- # Errors Find below the codes and messages for SCA-related errors. ## Authentication errors | HTTP | `code` | `message`| Description | | :---: | --- | --- | --- | | 400 | `authentication_error` | The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. | The SCA proof is missing | | 403 | `sca_forbidden` | The authentication requires a valid ScaProof. | The SCA proof is older than 180 days. | | 400 | `authentication_error` | The user credentials were incorrect. | No SCA proof recorded during the last 180 days. | ## SCA Proof errors | HTTP | `code` | `message`| Description | | :---: | --- | --- | --- | | 500 | `sca_error` | The SCA wallet does not belong to the user. | | | 403 | `sca_forbidden` | Delay between SCA proof and JWT creation is over. | SCA proof has expired. | | 400 | `sca_bad_request` | The sca proof is already used. | SCA proofs must be unique. | | 401 | `sca_unauthorized` | The SCA proof must come from the same ScaWallet used to generate your JWT. | Mismatch between the SCA wallet and the SCA proof. | | 403 | `sca_forbidden` | The ScaWallet must be active and not locked. | | | 500 | `sca_error` | The ScaProof is invalid. | Mobile SDK only. The SCA proof is either not properly formatted or not readable. | | 500 | `sca_error` | The certificate from sca proof cannot be parsed. | Mobile SDK only. | | 500 | `sca_error` | The certificate of the ScaProof is expired. | Mobile SDK only. | | 500 | `sca_error` | The identifier of the ScaProof is invalid.| Mobile SDK only. | | 500 | `sca_error` | The amr of the ScaProof is invalid. | Mobile SDK only. | | 500 | `sca_error` | The sub value of the ScaProof is invalid | Mobile SDK only. | | 500 | `sca_error` | The ScaProof signature is invalid | Mobile SDK only. | | 500 | `sca_error` | The ScaProof is expired or iat is in the future | Mobile SDK only. | | 500 | `sca_error` | No Entrust public keys were retrieved. | Mobile SDK only. | | 500 | `sca_error` | The ScaProof certificate cannot be verified. | Mobile SDK only. | | 500 | `sca_error` | The ScaProof is invalid. | Web Native only. | | 500 | `sca_error` | An error occurred while decrypting the passcode. | Web Native only. | | 500 | `sca_error` | The user has no passcode registered. | Web Native only. | | 500 | `sca_error` | The passcode is not valid. | Web Native only. | | 500 | `sca_error` | The data are not valid. | Web Native only. | | 500 | `sca_error` | Unable to load the data | Web Native only. | | 500 | `sca_error` | The SCA Wallet is not found | Web Native only. | | 500 | `sca_error` | The SCA wallet has no authenticator to validate the SCA proof. | Web Native only. | | 500 | `sca_error` | The SCA proof is invalid. | Web Native only. | ## Per-operation SCA errors | HTTP | `code` | `message`| Description | | :---: | --- | --- | --- | | 400 | `sca_bad_request` | The sca field is required. | | | 401 | `sca_unauthorized` | The sca proof is invalid. | | | 400 | `sca_bad_request` | The sca proof amr is invalid. | | | 400 | `sca_bad_request` | The sca proof is invalid. | The SCA proof message URL is missing. | | 400 | `sca_bad_request` | The message in the sca proof is invalid. | The SCA proof message body is missing or not readable. | | 400 | `sca_bad_request` | The message in the sca proof is invalid. | The SCA proof message is not valid. | ## Per-session SCA errors | HTTP | `code` | `message` | | :---: | --- | --- | | 403 | `sca_forbidden` | The ScaWallet must be active and not locked. | | 401 | `sca_session_expired` | Your session has expired. | ## SCA Wallet errors | HTTP | `code` | `message` | Description | | :---: | --- | --- | --- | | 400 | `input_validation_error` | webauthn is invalid. | Web Native only. | | 400 | `input_validation_error` | passcode is invalid. | Web Native only. | | 400 | `input_validation_error` | The password must be at least 6 characters | Web Native only. | | 400 | `functional_error` | The maximum number of scaWallets is reached | | | 400 | `input_validation_error` | The passcode is already defined. | Web Native only. | | 400 | `input_validation_error` | The maximum number of scaWallets is reached for userId `{userId}`. | | | 400 | `functional_error` | The sca field is required. | | | 400 | `functional_error` | The ScaWallet is deleted. | When attempting to lock the SCA Wallet. | | 400 | `input_validation_error` | The ScaWallet is already locked. | | | 403 | `functional_error` | The user `{userId}` is not authorized. | | | 403 | `authorization_error` | Forbidden access for the current scope | | | 404 | `resource_not_found_error` | The resource was not found | The SCA Wallet not found | | 400 | `input_validation_error` | The ScaWallet is already unlocked. | | | 400 | `input_validation_error` | The ScaWallet is deleted. | When attempting to unlock or delete the SCA Wallet. | | 400 | `unexpected_error` | The wallet with identifier `{walletId}` is not active. | | | 400 | `input_validation_error` | The new passcode and confirm passcode do not match. | | | 400 | `input_validation_error` | The user has no passcode defined. | | | 400 | `input_validation_error` | The ScaWallet is already deleted. | When attempting to swap SCA Wallets. | ## External Operation errors | HTTP | `code` | `message` | | :---: | --- | --- | | 400 | `functional_error` | ResourceIds is required | | 400 | `input_validation_error` | The resource ids field is required when action name is externalGetStatement. | | 400 | `functional_error` | Update of `{actionName}` is not allowed | | 400 | `input_validation_error` | The following resource are already saved : `{resource_id}` | --- --- url: /guide/strong-customer-authentication/sdk-abstraction.md description: >- Technical guide for configuration and usage of React abstraction layer of the Mobile SDK. Includes JavaScript code examples. --- # Mobile Abstraction Layer Treezor provides a React abstraction layer that lives above the [Mobile SDK](sdk). This wrapper allows you to implement SCA features more easily than via the SDK directly. **Alert – The abstraction layer is provided “as is”** Contrary to the [SDK](sdk), this abstraction layer is provided “as is” without any warranty. To use it, you have to: * Import `react-native-treezor-sca` using credentials provided by Treezor. * Import `bridge-reactNative-{version}` provided to you encrypted using GPG. Using `npm install -S {package}` or `yarn add {package}`. ## iOS SDK Configuration **Reading – iOS SDK configuration guide is available** This section is to be read along with the iOS SDK full documentation. Contact Treezor if you don't have access to the partner's integration guides yet. **Prerequisites – Requires Apple Developer Account** You need a valid Apple Developer Account to achieve a valid configuration, as well as an up-to-date membership in Apple Developer Program (see [Apple Membership](https://developer.apple.com/support/compare-memberships/)). You need the following Apple Capabilities to work with the SDK: * **Push Notifications** – Required for SCA Wallet activation (silent push) and for authentication request (classic push) * **App Groups** – Required to decrypt an authentication request and present decrypted content to iOS Push System. If you're unfamiliar with how to configure these capabilities, you can either refer to the 2.3 section of the SDK documentation or go through the configuration steps listed below. ::: details Configuration steps In your Apple [Developer Portal](https://developer.apple.com/account/resources/profiles/list), you'll need to: 1. Create your identifier (if it's not already the case) 2. Configure App Groups 3. Configure Apple Push Notifications **To create your identifier**, go to *Identifiers* and select or create your application identifier (for a creation, check your identifier has an "Explicit" Bundle ID). **To configure App Groups**: * Select *Identifiers* in the left menu of the Developer, then select *App Groups* from the upper right dropdown * Click on the "+" button and follow the instructions from the creation assistant * Open your Application Identifier and click "Configure" from the "App Groups" feature. Then, select your previously created App Groups Identifier. **To Configure Push Notifications**: * Select *Keys* in the left menu of the Developer Portal. * Click on the "+" button and: * Provide a "Key name" * Check "Apple Push Notifications service (APNs)" * Click on "Continue", then "Register" * Click on the "Download" button to retrieve the generated key and the "APNS Key ID" value. Also keep the "Team ID" value. * Open your Application Identifier and click "Configure" from the "Push Notification" feature. You can also: * Follow the [Apple's documentation](https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/establishing_a_certificate-based_connection_to_apns) to add an Apple Push Notification Production SSL certificate. * Send Push information to the SDK ::: ### AntelopRelease.plist Using XCode, create `AntelopRelease.plist` file in iOS → AppName → `AntelopRelease.plist` and add it to your TargetAppName. Your file should look like this: ::: code-group ```xml [XML] fr.antelop.alertLoggingEnabled The Antelop SDK is logging. fr.antelop.applicationGroupIdentifier group.com.treezor.scaintegration fr.antelop.initialConnectionTimeout 60 fr.antelop.application_id {yourApplicationId} fr.antelop.issuer_id {yourIssuerId} fr.antelop.teamIdentifier {yourTeamIdentifier} ``` ::: ### Configure XCode If you are using the last architecture of React Native which uses Obj-c++, you will need to add the following flag: Target → BuildSettings → Other C++ flags: `-fmodules` and `-fcxx-modules` If you get the "C++ modules are disabled" error, please set the following settings to true. Target → BuildSettings → Enable Modules(C and Objective-C) ### Configure AppDelegate In `AppDelegate.mm`, add `@import react_native_antelop;` at the top of the document. ```c @import react_native_antelop; ``` Override the [AppDelegate.didFinishLaunchingWithOptions](https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622921-application) and use this code. ```c - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // [...] Your application code // Add these lines at end of the method [AntelopBridgeAppDelegate.shared didFinishLaunchingWithOptionsWithApplication:application launchOptions:launchOptions]; return YES; } ``` **Note – Do not replace your complete `didFinishLaunchingWithOptions` method** Just add the provided code at the end of the method. Override the [AppDelegate.applicationDidBecomeActive](https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622956-applicationdidbecomeactive) and use this code : ```c - (void)applicationDidBecomeActive:(UIApplication *)application { [AntelopBridgeAppDelegate.shared applicationDidBecomeActiveWithApplication:application]; } ``` Override the [AppDelegate.didRegisterForRemoteNotificationsWithDeviceToken](https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622958-application) and use this code: ```c - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { // You can retreive the deviceToken for you own Server side push // Link to Antelop Bridge [AntelopBridgeAppDelegate.shared didRegisterForRemoteNotificationsWithDeviceTokenWithApplication:application data:deviceToken]; } ``` Override the [AppDelegate.didReceiveRemoteNotification](https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623013-application) and use this code: ```c -(void) application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler { typedef void (^FetchCompletionHandler)(UIBackgroundFetchResult); typedef void (^ClientNotificationHandler)(NSDictionary * _Nonnull, FetchCompletionHandler); ClientNotificationHandler clientNotificationHandler = ^void(NSDictionary * _Nonnull userInfo, FetchCompletionHandler handler) { // To be implemented if the default behaviour is not desired }; [AntelopBridgeAppDelegate.shared didReceiveRemoteNotificationWithUserInfo:userInfo completionHandler:completionHandler clientNotificationHandler:clientNotificationHandler]; } ``` Override the [AppDelegate.performFetchWithCompletionHandler](https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623125-application) and use this code: ```c -(void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler { [AntelopBridgeAppDelegate.shared performFetchWithCompletionHandlerWithApplication:application completion:completionHandler]; } ``` ### Push notifications Adding the Notification Service is required to decrypt the encrypted content of the Push Notifications. To add the necessary files for iOS, run the command `yarn installNotificationIOS` **Note – `installNotificationIOS` script depends on `npm xcode` package** Therefore, you should make sure that your `package.json` specifies this package (`yarn add xcode` or `npm i xcode`). This will add a new target "PushExtension" to your project. Verify the settings below for the newly added target: * In XCode navigate to section "General" * Verify your Bundle identifier, Version and Build * Navigate to section "Signing & Capabilities" * Add "App Groups" by clicking "+ Capability" and check the group identifier embed in your provisioning profile * Verify your Bundle identifier * Navigate to section "Build Settings": * Search for "SWIFT\_VERSION" in the filter and ensure that it is valued to "SWIFT 5" In order to share data with the main app, the Extension must have access to the [App Group](https://developer.apple.com/documentation/xcode/configuring-app-groups) declared in the `AntelopRelease.plist` at `fr.antelop.applicationGroupIdentifier`. In your Podfile, add these lines to the target of your application: ```c pod 'react-native-antelop', :path => '../node_modules/react-native-antelop' pod 'AntelopSDK', :path => '../node_modules/react-native-antelop/ios/Frameworks/' pod 'SecureCModule', :path => '../node_modules/react-native-antelop/ios/Frameworks/' ``` In your Podfile, add these lines at the end of the file: ```c target 'PushExtension' do config = use_native_modules! use_react_native!(:path => config["reactNativePath"]) inherit! :search_paths post_install do |installer| installer.pods_project.targets.each do |target| target.build_configurations.each do |config| config.build_settings['APPLICATION_EXTENSION_API_ONLY'] = 'NO' end end flipper_post_install(installer) end end ``` Make sure to add the `AntelopRelease.plist` to the Extension Target: File Inspector → Target Membership, check the box for the Extension Target if necessary. ## Android SDK Configuration **Reading – Android SDK configuration guide is available** This section is to be read along with the Android SDK full documentation. Contact Treezor if you don't have access to the partner's integration guides yet. ### Metadata Add the following metadata to `android/app/src/main/AndroidManifest.xml` ::: code-group ```xml [XML] ``` ::: ### Permissions Add the following permissions to `android/app/src/main/AndroidManifest.xml` ::: code-group ```xml [XML] ``` ::: ### Libraries Add the following libraries to `android/build.gradle` ::: code-group ```json [JSON] allprojects { // ... repositories { // ... flatDir { dirs project(':react-native-antelop').file('libs') dirs project(':react-native-antelop').file('google-libs') } } // ... } ``` ::: Add the following to `android/app/build.gradle` (if not already present) ::: code-group ```json [JSON] dependencies { // ... implementation 'androidx.work:work-runtime-ktx:2.7.0' } ``` ::: ## Usage Declare a custom prompt `YourCustomPrompt.tsx` using: ::: code-group ```js [JavaScript] import { StrongCustomerAuthenticationProvider, CustomPromptProps, CustomPromptAction, CustomPromptError, } from 'react-native-treezor-sca'; const YourCustomPrompt = ({ onPasscodeEntered, onClose, action, error, }: CustomPromptProps) => { const title: Record = { auth: 'Enter your passcode', check: 'Enter your current passcode', setup: isConfirmation ? 'Repeat your passcode' : 'Set your passcode', update: isConfirmation ? 'Repeat your new passcode' : 'Enter your new passcode', unlock: 'Enter your passcode to unlock your account', activateBiometric: 'Enter your passcode to activate biometric', deactivateBiometric: 'Enter your passcode to deactivate biometric', }; const scaErrors: Record = { wrongPasscode: remainingPasscodeAttempts ? `Invalid passcode.\n You have ${remainingPasscodeAttempts} attempt(s) left` : 'Invalid passcode.\n Please try again ', wrongBiometrics: "Many incorrect attempts to verify biometrics; use passcode until it's reactivated again", }; return ( {title[action]} {error && {errors[error]}} {/* Rest of your prompt design & logic */} ); }; ``` ::: When a passcode error in the prompt occurs, the set `remainingPasscodeAttempts` value depends on the context. | Passcode error context | Value | Description | | --- | --- | --- | | **SCA** | numerical | The number of remaining attempts before the authentication passcode is blocked. Applies to both per-session and per-operation SCA. | | **SCA Wallet action** | `undefined` | Specifically for biometry activation/deactivation or unlocking of the SCA Wallet. If there are too many erroneous attempts, the SCA Wallet will be blocked. | Wrap your application in `App.tsx` using the following. ::: code-group ```js [JavaScript] import { StrongCustomerAuthenticationProvider } from 'react-native-treezor-sca'; return ( {/* Your application */} ); ``` ::: Then initialize the abstraction layer using: ::: code-group ```js [JavaScript] import { useStrongCustomerAuthentication } from 'react-native-treezor-sca'; const { isConnected, biometricStatus, destroy, connect, disconnect, provision, sign, changePasscode, activateBiometric, deactivateBiometric, } = useStrongCustomerAuthentication({ rootedDeviceForbidden: false, onError: (code, details) => console.error(code, details), onProvisioningRequired: async () => { const scaWallet = await MyApiService.createScaWallet({ userId }); provision(scaWallet.activationCode); }, onChangeCredentialsSuccess: () => console.info('Passcode has been updated'), onCheckCredentialsSuccess: () => console.info('Passcode has been checked'), onActivateBiometricSuccess: () => console.info('Biometric Authentication has been activated'), onDeactivateBiometricSuccess: () => console.info('Biometric Authentication has been deactivated'), }); ``` ::: ### Connect to an SCA Wallet ::: code-group ```js [JavaScript] // by calling the connect() method : // if no wallet exists, onProvisioningRequired() will be called // if a wallet is already provisionned, a simple connexion to it is established connect(); ``` ::: You should only connect to an SCA Wallet once the end user has authenticated on your app. ### Generate an SCA Proof (without user action) ::: code-group ```js [JavaScript] // Generate a JWS to make session calls const signature = await sign(); const decoded = jwtDecode(signature); console.info(decoded); ``` ::: ### Generate an SCA Proof (with user action) Generate an SCA proof with a user passcode or user biometrics request. ::: code-group ```js [JavaScript] // Generate a JWS to make session calls const signature = await sign({ type: 'authenticate' }); const decoded = jwtDecode(signature); console.info(decoded); ``` ::: ### Customize prompt biometric ::: code-group ```js [JavaScript] // Customizing biometric prompt with android title, android subtitle or ios subtitle const signature = await sign({ type: 'authenticate', biometryMessage: { androidTitle: 'Android title to custom', androidSubTitle: 'Android subtitle to custom', iosSubTitle: "iOS subtitle to custom }, }); ``` ::: ### Sign parameters interface ::: code-group ```js [JavaScript (v2.6.6 & higher)] // Sign params interface type ISignMethod = 'passcode' | 'biometric'; export interface ISignOptions { type: ISignType; data?: unknown; signMethod?: ISignMethod; biometryMessage?: IBiometryMessage; passcodeFallback?: boolean; // If true, if biometry cancelation, the passcode prompt will be displayed. If false or undefined the biometry cancelation will close the biometry prompt } ``` ```js [JavaScript (up to v2.6.5.1)] // Sign params interface const sign = async (options: ISignOptions = { type: 'none' }) interface ISignOptions { type: ISignType; data?: unknown; biometryMessage?: IBiometryMessage; } interface IBiometryMessage { title?: string; subTitle?: string; } ``` ::: Find below the details for `isSignOptions`: | Property | Type | Description | |-----------------|------------------|--------| | type | ISignType | The authentication type, either `none` or `authenticate`. | | data | unknown | Data to be displayed as part of the authentication or null. | | signMethod | ISignMethod | The user specified sign method, either `biometry` or `passcode`. If no value is specified, the current signMethod is used. | | biometryMessage | IBiometryMessage | Custom biometric prompt message. | | passcodeFallback | boolean | Whether to fall back to passcode authentication when canceling biometry authentication. If false or undefined, canceling the biometry closes the biometry prompt. | ### Sign act parameters interface ::: code-group ```js [JavaScript (v2.6.6 & higher)] // Sign act params interface type OperationSignature = { url: string; body: unknown; }; type TSignActOptions = { signMethod?: ISignMethod; biometryMessage?: IBiometryMessage; passcodeFallback?: boolean; } const signAct = ( operation: OperationSignature, options?: TSignActOptions ) ``` ```js [JavaScript (up to v2.6.5.1)] // Sign act params interface const signAct = ( operation: OperationSignature, biometryMessage?: IBiometryMessage // you can also customize biometric prompt message for signAct ) export type OperationSignature = { url: string; body: unknown; }; ``` ::: Find below the details for `signAct`: | Property | Type | Description | |----------|----------------------|------------------------------------------------------------------------------------------------| | operation  | OperationSignature | The url and body of the sign act. | | options | TSignActOptions | Options included the sign method, custom prompt message, and fallback to passcode in case of biometry cancellation. | Find below the details for `TSignActOptions`: | Property | Type | Description | |------------------|------------------|------------------------------------------------------------------------------------------------| | signMethod | ISignMethod | The user specified sign method, either `biometry` or `passcode`. If no value is specified, the current signMethod is used. | | biometryMessage | IBiometryMessage | Custom biometric prompt message. | | passcodeFallback | boolean | Whether to fall back to passcode authentication when canceling biometry authentication. If false or undefined, canceling the biometry closes the biometry prompt. | ### Activate biometric ::: code-group ```js [JavaScript] // Activate biometric activateBiometric(); ``` ::: ### Deactivate biometric ::: code-group ```js [JavaScript] // Deactivate biometric deactivateBiometric(); ``` ::: ### Generate a per-operation SCA Proof ::: code-group ```js [JavaScript] // Generate a JWS to update a Card's limits, with a user passcode request const signature = await signAct({ url: '{baseUrl}/v1/cards/{cardId}/Limits', body: { limitAtmMonth: 1000, limitPaymentMonth: 800, }, }); const decoded = jwtDecode(signature); console.info(decoded); ``` ::: You can check out [the format of the payload](./sdk#payload) to sign. ### Change the passcode ::: code-group ```js [JavaScript] // change passcode requested by end user changePasscode(); ``` ::: ### Disconnect from an SCA Wallet ::: code-group ```js [JavaScript] // disconnect from an SCA Wallet disconnect(); ``` ::: A disconnect should occur when your app is put to the background, or when the end user disconnects from your app. ### Delete an SCA Wallet ::: code-group ```js [JavaScript] // irreversibly destroy the SCA Wallet from mobile device destroy(); ``` ::: ## Listeners Subscribing for "WalletEventListener" and "PushAuthenticationRequestListener" enables the application to capture events from remote notifications, thereby ensuring correct wallet and authentication statuses. For subscription, a set of callback functions for each event have to be provided. Find below two examples of listening to notifications, with display or actions triggered afterwards. ### Example 1 – Listen and display log or toaster outside the application ::: code-group ```js [JavaScript] import {AppRegistry} from 'react-native'; import {Toast} from 'react-native-toast-message/lib/src/Toast'; import { WalletEventListener, PushAuthenticationRequestListener, } from 'react-native-antelop'; import {name as appName} from './app.json'; import App from './src/App'; const walletEventListenerProtocole = { onWalletLoaded: () => { Toast.show({ type: 'info', text1: 'Wallet has been loaded', }); console.log('Event', '@WalletEventListener/onWalletLoaded'); }, onWalletLocked: reason => { Toast.show({ type: 'info', text1: 'Wallet has been locked', }); console.log('Event', '@WalletEventListener/onWalletLocked', reason); }, onWalletUnlocked: () => { Toast.show({ type: 'info', text1: 'Wallet has been unlocked', }); console.log('Event', '@WalletEventListener/onWalletUnlocked'); }, onWalletDeleted: () => { Toast.show({ type: 'info', text1: 'Wallet has been deleted', }); console.log('Event', '@WalletEventListener/onWalletDeleted'); }, onLogout: () => { console.log('Event', '@WalletEventListener/onLogout'); }, onSettingsUpdated: () => { console.log('Event', '@WalletEventListener/onSettingsUpdated'); }, onCountersUpdated: () => { console.log('Event', '@WalletEventListener/onCountersUpdated'); }, onCustomerCredentialsReset: () => { console.log('Event', '@WalletEventListener/onCustomerCredentialsReset'); }, onLostEligibility: () => { console.log('Event', '@WalletEventListener/onLostEligibility'); }, onCardsUpdated: () => { console.log('Event', '@WalletEventListener/onCardsUpdated'); }, }; const pushAuthProtocole = { onRequestReceived(pushAuthenticationRequestId) { console.log( 'PushAuthenticationRequestFetcher', 'onRequestReceived', pushAuthenticationRequestId, ); }, onRequestCancelled(requestId, reason) { console.log( 'PushAuthenticationRequestFetcher', 'onRequestCancelled', requestId, reason, ); }, }; PushAuthenticationRequestListener().setBackgroundListener(pushAuthProtocole); PushAuthenticationRequestListener().setForegroundListener(pushAuthProtocole); WalletEventListener().setBackgroundListener(walletEventListenerProtocole); WalletEventListener().setForegroundListener(walletEventListenerProtocole); AppRegistry.registerComponent(appName, () => App); ``` ::: ### Example 2 – Listen and trigger appropriate actions inside the application In this example, we listen for notification events relating to the SCA Wallet status (e.g., `onWalletLocked`, `onCredentialsReset`, and `onWalletDelete`) to dispatch an event from the `index.js` (other notifications are handled as the same way as the first example). Inside the application logic (`MobileActions.tsx`), on capturing the event, we display a modal with explanation and a CTA button to disconnect the SCA Wallet. #### index.js ::: code-group ```js [JavaScript] import {AppRegistry, NativeEventEmitter, NativeModules} from 'react-native'; import {Toast} from 'react-native-toast-message/lib/src/Toast'; import { WalletEventListener, PushAuthenticationRequestListener, } from 'react-native-antelop'; import {name as appName} from './app.json'; import App from './src/App'; // For ios, the EmitterModule must be declared beforehand as describled in: https://reactnative.dev/docs/native-modules-ios // As example, Add RCTEmitterModule.h and RCTEmitterModule.m inside the ios folder to to register the emitter module const {EmitterModule} = NativeModules; const eventEmitter = new NativeEventEmitter(EmitterModule); const walletEventListenerProtocole = { onWalletLoaded: () => { Toast.show({ type: 'info', text1: 'Wallet has been loaded', }); console.log('Event', '@WalletEventListener/onWalletLoaded'); }, onWalletLocked: reason => { console.log('Event', '@WalletEventListener/onWalletLocked', reason); // dispatch an event in case of WalletLocked eventEmitter.emit('onWalletUpdated', {type: 'Wallet locked', reason}); }, onWalletUnlocked: () => { Toast.show({ type: 'info', text1: 'Wallet has been unlocked', }); console.log('Event', '@WalletEventListener/onWalletUnlocked'); }, onWalletDeleted: () => { console.log('Event', '@WalletEventListener/onWalletDeleted'); // dispatch an event in case of WalletDeleted eventEmitter.emit('onWalletUpdated', {type: 'Wallet deleted'}); }, onLogout: () => { console.log('Event', '@WalletEventListener/onLogout'); }, onSettingsUpdated: () => { console.log('Event', '@WalletEventListener/onSettingsUpdated'); }, onCountersUpdated: () => { console.log('Event', '@WalletEventListener/onCountersUpdated'); }, onCustomerCredentialsReset: () => { console.log('Event', '@WalletEventListener/onCustomerCredentialsReset'); // dispatch an event in case of CustomerCredentialsReset eventEmitter.emit('onWalletUpdated', {type: 'Credentials reset'}); }, onLostEligibility: () => { console.log('Event', '@WalletEventListener/onLostEligibility'); }, onCardsUpdated: () => { console.log('Event', '@WalletEventListener/onCardsUpdated'); }, }; const pushAuthProtocole = { onRequestReceived(pushAuthenticationRequestId) { console.log( 'PushAuthenticationRequestFetcher', 'onRequestReceived', pushAuthenticationRequestId, ); }, onRequestCancelled(requestId, reason) { console.log( 'PushAuthenticationRequestFetcher', 'onRequestCancelled', requestId, reason, ); }, }; PushAuthenticationRequestListener().setBackgroundListener(pushAuthProtocole); PushAuthenticationRequestListener().setForegroundListener(pushAuthProtocole); WalletEventListener().setBackgroundListener(walletEventListenerProtocole); WalletEventListener().setForegroundListener(walletEventListenerProtocole); AppRegistry.registerComponent(appName, () => App); ``` ::: #### MobileActions.tsx ::: code-group ```js [JavaScript] ... const [walletStatus, setWalletStatus] = useState(); ... // Listening to onWalletUpdated to display the modal on received // Remove listener on unmount useEffect(() => { eventEmitter.addListener('onWalletUpdated', data => { console.log(data); isConnected && setWalletStatus(data?.type); }); return () => { eventEmitter.removeAllListeners('onWalletUpdated'); }; }, [isConnected]); ... // Display the modal with explanation and CTA button to disconnect the sca wallet <> {!!walletStatus && ( setWalletStatus(undefined)} onSubmit={() => { setWalletStatus(undefined); disconnect(); }} /> )} ``` ::: ## Errors Treezor abstraction layer returns error objects in the following format: ::: code-group ```json [JSON] { "code": 449, "error": "Canceled" } ``` ::: Here is the list of errors you may encounter: | HTTP Status code | SDK error | Description | | --- | --- | --- | | 401 | Invalid Credentials | Occurs when the passcode of the end user are invalid or provided in an invalid format. | | 404 | Wallet Not Found | Occurs when the SCA Wallet doesn't exist (deleted, wrong Id). | | 405 | Passcode Authentication Impossible | Occurs when the number of authentication attempts with a passcode is reached. To unblock this situation, you may activate the biometry or reset the passcode (via the app, dashboard, or your own back office with a PIN reset). | | 406 | Device Not Eligible | Occurs when the device is not supported (due to the OS version for instance). | | 407 | Authentication Error | Occurs when there is an issue with the strong customer authentication (timeout, duplicate, etc.). | | 416 | Wallet Not Activated | Occurs when the SCA Wallet is not active. | | 423 | Wallet Locked | Occurs when the SCA Wallet is locked. You may unlock the SCA Wallet per your end user's request in the Dashboard or in your own back office. | | 428 | Activation Required | Occurs when the end user is active on their device and an action is made from the back office or Dashboard (unlock or reset PIN). The end user must log out and log back in order to reactivate their account or reinitialize their passwords. | | 451 | Other Error | Contact Treezor for more information. | | 498 | Invalid Activation Code | Occurs when the activation code is invalid, already used, expired or locked during the SCA Wallet initialization or provisioning. | | 499 | Canceled | Occurs when the end user cancels the SCA. | | 500 | Internal Error | Occurs in case of an unexpected server error. Contact Treezor if the error persists. | | 511 | Network Not Available | Occurs when there is a network issue. | --- --- url: /guide/strong-customer-authentication/sdk.md description: >- Technical guide for using the Mobile SDK for Strong Customer Authentication (SCA). Includes the links to download the SDK in multiple languages, for both sandbox and production. --- # Mobile SDK **Information – SDK *Wallet* or *SCA Wallet* do not refer to Treezor Wallets** The SDK uses the terms *Wallet* or *SCA Wallet* to describe a secure enclave present locally on a mobile device where the private key is stored. Not to be mixed up with [Treezor Wallets](/guide/wallets/introduction) feature. All the SDK features are provided through an SCA wallet object implemented in the SDK itself. It can be seen as a base layer, gathering configuration and security settings on which Strong Customer Authentication relies. SCA Wallets are synchronized between the mobile device and Treezor back end. The main property of the SCA Wallet is its state, evolving from actions triggered on the back end or on hosting app side, and defining how an SCA wallet is accessible to the hosting app. ::: details Requirements for mobile compatibility on your end users side **Android** * Minimum supported version – Android 5.0 Lollipop (API level 21) * Target version – Tested with Android versions until Android 13 (API level 33) **iOS** * Minimum supported version – iOS 11 * Minimum supported version for pushing a Card to Apple Pay – iOS 13.4 * Swift 5 ::: ## Access To request SCA proofs, the hosting app must first build a `WalletManager` object with a custom implementation of `WalletManagerCallback`. The callback functions will be called by the SDK upon the completion of asynchronous actions requested on the `WalletManager` instance. Once a `WalletManager` object is built, SCA Wallet access is requested by calling the `WalletManager#connect()` method. `connect()` calls are asynchronous and trigger one of the following method of the `WalletManager` upon completion. | Callback | Description | | --- | --- | | `WalletManagerCallback#onConnectionSuccess()` | The **wallet is ready** and any of its services can be used. | | `WalletManagerCallback#onProvisioningRequired()` | The **wallet access is refused because there is no initialized wallet** in the app. The hosting app [must first initialize a wallet](#provisionning) and then attempt to access it again. | | `WalletManagerCallback#onCredentialsRequired()` | The **wallet access is refused because credentials must be provided**. It can be either: New credentials to define when the wallet is accessed for the first time after provisioning.Current credentials when the wallet is accessed after log out. The hosting App must request and acquire credentials from the customer, then forward them to the SDK as method arguments through a new call to `WalletManager#connect(currentCredentials,newCredentials)`. If the Wallet is configured to not enforce access protection, this callback is never called. | | `WalletManagerCallback#onConnectionError()` | The **wallet access cannot be established**, for a specific reason provided as method argument. | Calls to the `connect()` method happen mostly locally, but can require online connectivity in some specific cases (for example when credentials are provided or when critical security checks must be carried out). **Best practice – Ensure the SCA Wallet handled by the app is up-to-date** Don't handle the SCA Wallet instance returned by the SDK statically or in a singleton on the hosting app side. Each time a new context on the App needs to interact with an SCA Wallet, it must connect to a `WalletManager` and wait for `onConnectionSuccess` callback function. ## Device Eligibility SCA features can be forbidden if the device is rooted or if the device model is explicitly blacklisted. Checking device eligibility is done by calling the `WalletProvisioning#checkEligibility()` method. This starts a light operation and executes the following callbacks. | Callback | Description | | --- | --- | | `WalletProvisioningCallback#onDeviceEligible()` | If the **device is considered eligible** for SCA services. Features available on the SCA wallet are provided as method argument. After this callback, the hosting app can proceed with wallet provisioning. | | `WalletProvisioningCallback#onDeviceNotEligible()` | If the **device is considered not eligible** for SCA services (wallet provisioning isn't possible). The eligibility denial reason is provided as method argument with the eligibility denial reference (i.e., the identifier used to record this specific eligibility denial on the back end). | | `WalletProvisioningCallback#onCheckEligibilityError()` | If the **eligibility check has failed** for a specific reason provided as method argument. | ### Provisioning flow The following diagram illustrates the provisioning procedure. This applies to **one** User and **one** mobile device. ```mermaid sequenceDiagram participant sdk as Mobile SDK participant app as Mobile App participant agent as Agent back end participant trz as Treezor % participant entrust as Entrust app->>sdk: Attempt to connect to the SCA Wallet using
WalletManager.connect() Note over app: Wait for onProvisioningRequired async event % alt onProvisioningRequired % sdk-->>app: WalletManagerCallback.onProvisioningRequired() % else onCredentialsRequired % sdk-->>app: WalletManagerCallback.onCredentialsRequired() % else onConnectionError % sdk-->>app: WalletManagerCallback.onConnectionError() % end sdk-->>app: WalletManagerCallback.onProvisioningRequired() app->>agent: Request creation of SCA Wallet agent->>trz: Create an SCA Wallet trz->>agent: Response (with activationCode) %Note over trz,agent: Containing the SCA Wallet activationCode trz-->>agent: Send an SCA.wallet.create webhook Note over trz,agent: Containing the SCA Wallet activationCode agent->>app: Response (with activationCode) %% agent-->>app: Send a push notification %% Note over agent,app: Containing the SCA Wallet activation code app->>sdk: Intialize the provisionning instance using
WalletProvisioning.initialize() Note over app: Wait for onInitializationSuccess async event % alt onInitializationSuccess sdk-->>app: WalletProvisioningCallback.onInitializationSuccess() % else onInitializationError % sdk-->>app: WalletProvisioningCallback.onInitializationError() % else onPermissionNotGranted % sdk-->>app: WalletProvisioningCallback.onPermissionNotGranted() % end app->>sdk: Check device elligibility using
WalletProvisioning.checkEligibility() Note over app: Wait for onDeviceEligible async event % alt onDeviceEligible sdk-->>app: WalletProvisioningCallback.onDeviceEligible() % else onDeviceNotEligible % sdk-->>app: WalletProvisioningCallback.onDeviceNotEligible() % else onCheckEligibilityError % sdk-->>app: WalletProvisioningCallback.onCheckEligibilityError() % end app->>sdk: Provision the SCA Wallet using
WalletProvisioning.launch(activationCode) Note over app: Wait for onProvisioningSuccess async event % alt onProvisioningSuccess sdk-->>app: WalletProvisioningCallback.onProvisioningSuccess() % else onProvisioningError % sdk-->>app: WalletProvisioningCallback.onProvisioningError() % end app->>sdk: Attempt to connect to the SCA Wallet using
WalletManager.connect() Note over app: Wait for onCredentialsRequired async event sdk-->>app: WalletManagerCallback.onCredentialsRequired() Note over app: Prompt the user to define a PIN Code (4 to 8 digits) app->>sdk: Attempt to connect to the SCA Wallet using
WalletManager.connect(null,pinCode) Note over app,sdk: This defines the pinCode of the SCA Wallet Note over app: Wait for onConnectionSuccess async event % alt onConnectionSuccess sdk-->>app: WalletManagerCallback.onConnectionSuccess() % else onCredentialsRequired % sdk-->>app: WalletManagerCallback.onCredentialsRequired() % else onConnectionError % sdk-->>app: WalletManagerCallback.onConnectionError() % end Note over app: The SCA Wallet is ready % provisionner % creer credentials ``` **Best practice – Your code must be event-based** Although this diagram is fairly procedural for clarity, your code must be event-based to handle all possibilities. ## Signature SCA proof capabilities are provided by the SDK via `CustomerAuthenticatedSignature`, it produces a signature once the user has performed the required authentication. This signature is generated locally within Entrust SDK and is returned to the hosting app. `CustomerAuthenticatedSignature` must first be instantiated with the following parameters. | Parameter | Description | | --- | --- | | `patternName` | The name of the authentication pattern to use for this authentication. Can be:`patterns.NONE.name` for none authentication`patterns.PIN.name` for PIN authentication`patterns.BIOMETRY.name` for Biometric authentication | | `message` | The message to display to the customer. Must be set if the SDK is used to display the UI. In any case, this information is part of the signed data. | | `signatureType` | Type of signature result to generate. You must use the `CustomerAuthenticatedSignatureType.LocalJws` option. | | `signatureInputData` | Custom, context-related information that is part of [the signed data](#payload). | Once instantiated, you must call `CustomerAuthenticatedSignature#sign()` to start the signature process. When the `CustomerAuthenticatedSignature` is successfully completed, you're notified by the `CustomCustomerAuthenticatedProcessCallback#onProcessSuccess()` callback. The generated signature result can be fetched by calling `CustomerAuthenticatedSignature#getResult()`. ### SCA Proof flow The following diagram illustrates the generation of SCA Proofs using type PIN. It assumes the [provisioning is completed](#provisioning-flow). ```mermaid sequenceDiagram participant sdk as Mobile SDK participant app as Mobile App participant agent as Agent API participant trz as Treezor % participant entrust as Entrust app->>sdk: Attempt to connect to the SCA Wallet using
WalletManager.connect() Note over app: Wait for onConnectionSuccess async event sdk-->>app: WalletManagerCallback.onConnectionSuccess() Note over app: Prepare the payload that needs to be signed app->>sdk: Instanciate the CustomerAuthenticatedSignature(pattern, message, type, input) Note over app,sdk: The following parameters are expected :
pattern: patterns.PIN.name
message: "A description of the signature action"
type: CustomerAuthenticatedSignatureType.LocalJws
input: Buffer.from(JSON.stringify(payload), 'utf8') app->>sdk: Call the sign(callback, callback, ...) method on the CustomerAuthenticatedSignature instance Note over app,sdk: The following callbacks are expected :
onCustomerCredentialsRequired()
onCustomerCredentialsInvalid()
onAuthenticatedDeclined()
onError()
onProcessStart()
onProcessSuccess() Note over app: Wait for onCustomerCredentialsRequired async event sdk-->>app: CustomCustomerAuthenticatedProcessCallback.onCustomerCredentialsRequired() Note over app: Prompt the user for their PIN Code %app->>sdk: Set their PIN Code using
CustomerAuthenticatedProcess.setCustomerCredentials(
new CustomerAuthenticationPasscode(pinCode)
) app->>sdk: Set their PIN Code using
CustomerAuthenticatedProcess.setCustomerCredentials(pinCode) Note over app: Wait for onProcessSuccess async event app->>sdk: Retrieve the SCA Proof using CustomerAuthenticatedSignature.getResult() Note over sdk,app: This is the SCA Proof JWS app->>agent: Send the Per-Operation request Note over app, agent: Forward the SCA proof (JWS) Note over agent: Retrieve the User's JWT from your database
Do not request a new JWT from Treezor if yours hasn't expired agent->>trz: Call the relevant endpoint Note over agent, trz: Place the JWT in the "Authorization:" header %Note over agent, trz: Place the JWS in the "X-SCA-Authorization:" header Note over agent, trz: Forward the SCA proof (JWS) trz->>agent: Response agent->>app: Response ``` **Best practice – Your code must be event-based** Although this diagram is fairly procedural for clarity, your code must be event-based to handle all possibilities. #### SCA Wallet states SCA Wallets may have the following states. | State | Description | | --- | --- | | **Not provisioned** | The app has not initialized the SDK yet, so no SCA wallet exists on it. | | **Ready** | The SDK was initialized by the app, an SCA wallet was provisioned into it, and its properties and features can be accessed by the app (after [establishing a connection](#access) to the SCA wallet). | | **Locked** | The SCA wallet provisioned into the app is locked. Its properties and features aren't accessible to the app until the SCA wallet is unlocked from the back end. | | **Logout** | Access to properties and features of the SCA wallet provisioned into the app requires first a customer authentication. | ## Authentication ### Methods The user is prompted to authenticate differently depending on the method: * **Pin** – Using a 6 to 8 digits PIN code. * **Biometric** – Using the local biometric authentication system of the device. * **None** – No input required, the operation is transparent. You may use indistinctly **Pin** or **Biometric**, depending on the capabilities of the device. Regardless of the method, basic checks are carried out to ensure the mobile device is legitimate and has not been altered or cloned. ## Events The following functions can be called by the SDK upon SCA Wallet updates. | Event | Description | | --- | --- | | `WalletEventListener#onWalletSettingUpdated()` | The SCA wallet settings are updated. | | `WalletEventListener#onWalletProductsUpdated()` | The SCA wallet products are updated. | | `WalletEventListener#onWalletCountersUpdated()` | The SCA wallet passcode (PIN Code) attempt counter is updated. | | `WalletEventListener#onCustomerCredentialsReset()` | The SCA wallet passcode (PIN Code) has been reset. | | `WalletEventListener#onWalletLocked()` | The SCA wallet has been locked. | | `WalletEventListener#onWalletUnlocked()` | The SCA wallet has been unlocked. | | `WalletEventListener#onDeviceEligibilityLost()` | The current device is no longer eligible to SCA service. | | `WalletEventListener#onWalletDeleted()` | The SCA wallet has been deleted. | | `WalletEventListener#onWalletLoaded()` | The SCA wallet has completed its initialization. | | `WalletEventListener#onAppSunsetScheduled()` | The current version of the mobile application has been deprecated. | ## Payload When providing a payload to the SDK for signature, it should be in the following format, with: * The `url` (string) – Always populated with the endpoint that requires the SCA. * The `body` (object) – Populated with parameters to sign, and left as an empty array when [no parameters have to be signed](securing-endpoints#per-session). ### No parameters to be signed ```json [JSON] { "url": "string", "body": {} } ``` ### With parameters to be signed ```json [JSON] { "url": "string", "body": { "foo0": "bar0", "foo1": "bar1" } } ``` ### Payload examples Find below a series of examples that illustrate different payloads. #### GET /v1/cardimages Request example: ::: code-group ```bash [CURL] GET {baseURL}/v1/cardimages?cardId=123456&encryptionMethod=2 ``` ::: Signed data: ::: code-group ```json [JSON] { "url": "{baseURL}/v1/cardimages", "body": { "cardId":"123456" } } ``` ::: #### PUT /v1/cards​/{id}​/Activate Request example: ::: code-group ```bash [CURL] PUT {baseURL}​/v1/cards​/{id}​/Activate​?accessTag=12345 ``` ::: Signed data: ::: code-group ```json [JSON] { "url": "{baseURL}/v1/cards​/{id}​/Activate", "body": {} } ``` ::: #### POST /v1/beneficiaries Request example: ::: code-group ```bash [CURL] POST {baseURL}/v1/beneficiaries?accessTag=12345 { "userId": "12345", "name": "Alex Oak" "address": "15 Magnolia road", "iban": "FR113000300030592123456789", "bic": "SOGEFRPPXXX", "usableForSct": true } ``` ::: Signed data: ::: code-group ```json [JSON] { "url": "{baseURL}/v1/beneficiaries", "body": { "userId": "12345", "name": "Alex Oak", "address": "15 Magnolia road", "iban": "FR113000300030592123456789", "bic": "SOGEFRPPXXX", "usableForSct": true } } ``` ::: #### PUT /v1/users/{userId} Request example: ::: code-group ```bash [CURL] PUT {baseURL}/v1/users/{userId}?accessTag=12345 { "phone": “0702030405”, "middleNames": "Chris" } ``` ::: Signed data: ::: code-group ```json [JSON] { "url": "{baseURL}/v1/users/{userId}", "body": { "phone": “0765432190” } } ``` ::: #### PUT /v1/cards/{cardId}/Limits Request example: ::: code-group ```bash [CURL] PUT {baseURL}/v1/cards/{cardId}/Limits { "limitPaymentDay":25, "limitAtmDay":100 } ``` ::: Signed data: ::: code-group ```json [JSON] { "url": "{baseURL}/v1/cards/{cardId}/Limits", "body": { "limitPaymentDay":25, "limitAtmDay": 100 } } ``` ::: ## PIN Change To change the PIN of an SCA Wallet, you have to follow these steps. ### Check the current PIN Call the `WalletManager#checkCredentials(currentCredentials)` method. As the operation is async: * Subscribe to the `WalletManager#onAsyncRequestSuccess` callback for the **success** response * Subscribe to the `WalletManager#onAsyncRequestError` callback for the **error** response ### Change the PIN Use the `WalletManager#changeCredentials(currentCredentials,newCredentials)` method. As the operation is async: * Subscribe to the `WalletManager#onAsyncRequestSuccess` callback for the **success** response * Subscribe to the `WalletManager#onAsyncRequestError` callback for the **error** response ## Disconnection When disconnecting from an SCA Wallet, you have to follow these steps: ```c WalletManager#disconnect() WalletManager#clean() ``` ## Compatibility chart | Language | SDK Availability | iOS | Android | |--- |:---: |:---: |:---: | | [React Native](https://doc.antelop-solutions.com/latest/common/sdk-reactdoc/index.html) | | | | | [Java](https://doc.antelop-solutions.com/latest/common/sdk-javadoc/index.html) | | | | | [Swift](https://doc.antelop-solutions.com/latest/common/sdk-swiftdoc/index.html) | | | | | Cordova | | | | | Flutter | | | | | Dart | | | | | Kotlin | | | | | Objective C | | | | | Web | | N/A | N/A | **Information – The SDK is not compatible with pure Web applications** If your mobile stack is not available yet, get in touch with your *Implementation Manager*. *** **Reading – Full SDK Documentation available** Contact Treezor to request access to the SDK full documentation. ## Download SDK ### Sandbox ### Production --- --- url: /guide/strong-customer-authentication/events.md description: >- Reference a comprehensive list of SCA wallets events for Treezor API webhooks, detailing each event's structure and payload for integration. --- # Events ## SCA Wallets ### `sca.wallet.create` ::: code-group ```json [JSON] { "webhook": "sca.wallet.create", "object": "scaWallet", "object_id": "aef88f9c07b54056a5db807c4c3131b5", "object_payload": { "scaWallets": [ { "id": "aef88f9c07b54056a5db807c4c3131b5", "status": "CREATED", "subStatus": "CREATED_READY", "passcodeStatus": "NOT_SET", "locked": false, "lockReasons": [], "lockMessage": null, "settingsProfile": "default", "mobileWallet": null, "activationCode": "0x8a6074281ac911e04623cb2ba915bea6", "creationDate": "2025-06-26T16:29:36+02:00", "deletionDate": null, "activationCodeExpiryDate": "2025-06-26T16:49:36+02:00", "authenticationMethods": [ { "type": "DEVICE_BIOMETRIC", "usages": [ "STRONG_CUSTOMER_AUTHENTICATION" ], "parameters": { "validityDuration": 60 } }, { "type": "NONE", "usages": [ "STRONG_CUSTOMER_AUTHENTICATION" ], "parameters": [] }, { "type": "HYBRID_PIN", "usages": [ "WALLET_MANAGEMENT", "STRONG_CUSTOMER_AUTHENTICATION" ], "parameters": { "maxAttempts": 3, "validityDuration": 60 } } ], "invalidActivationAttempts": null, "userId": "102267425", "scaWalletTag": null, "clientId": "12345", "activationDate": null, "lockDate": null, "unlockDate": null, "resetPinDate": null } ] }, "webhook_created_at": 17509481770133, "webhook_id": "7e2c1954-5149-45f8-9fc9-b5e01beafb5a", "object_payload_signature": "gzeErSE8a8A7taIImbTXRY5pFdpSrxxffx4Y246Onic=" } ``` ::: ### `sca.wallet.update` Treezor sends this webhook when the SCA Wallet is activated (Mobile SDK). At this step, the `activationDate` and `status` are updated. ::: code-group ```json [JSON] {9,73} { "webhook": "sca.wallet.update", "object": "scaWallet", "object_id": "ed4e1329628443bf84113a9231ed34cb", "object_payload": { "scaWallets": [ { "id": "ed4e1329628443bf84083a9231ed34cb", "status": "ACTIVE", "subStatus": "ACTIVATED_LOGGED_IN", "passcodeStatus": "SET", "locked": false, "lockReasons": null, "lockMessage": null, "settingsProfile": "default", "mobileWallet": { "appBuildNumber": "v04-04-06-06-02-02", "sdkVersion": "2.4.11", "os": "ANDROID", "osVersion": "14", "brand": "Google", "productModel": "sdk_gphone64_arm64", "deviceId": "749676e2ci91c8fd", "deviceIdType": "ANDROID_ID", "productFingerprint": "google/sdk_gphone64_arm64/emu64a:14/[...]", "secretFingerprint": "0xbc311dfcef97f93fe3611722d[...]", "root": "0", "pushMessagingId": "feT82iyLTFqZi6SXG3l8Qd:APA91bHIhquMcd359oKGbdFKX5jTuTYpfw1XU9n1ohAglN8dLpVLMrI-[...]", "pushMessagingProvider": "FIREBASE", "mobileUpdateDate": "2025-04-22T12:22:31Z", "lastEligibilityCheck": "2025-04-22T12:22:31Z", "nfc": false, "emulator": true, "appleTeamId": null }, "activationCode": null, "creationDate": "2025-04-22T14:17:31+02:00", "deletionDate": null, "activationCodeExpiryDate": "2025-04-22T14:37:32+02:00", "authenticationMethods": [ { "type": "DEVICE_BIOMETRIC", "usages": [ "STRONG_CUSTOMER_AUTHENTICATION" ], "parameters": { "validityDuration": 60 } }, { "type": "NONE", "usages": [ "STRONG_CUSTOMER_AUTHENTICATION" ], "parameters": [] }, { "type": "HYBRID_PIN", "usages": [ "WALLET_MANAGEMENT", "STRONG_CUSTOMER_AUTHENTICATION" ], "parameters": { "maxAttempts": 3, "validityDuration": 60 } } ], "invalidActivationAttempts": null, "userId": "101887833", "scaWalletTag": "test", "clientId": "12345", "activationDate": "2025-04-22T14:22:31+02:00", "lockDate": null, "unlockDate": null, "resetPinDate": null } ] }, "webhook_created_at": 17453245629317, "webhook_id": "41338a50-daec-4191-a531-e7b02dcc50d3", "object_payload_signature": "rKilCnGC0EngkPF+7McW02L/NevQlk3kY3sHc6M7OJg=" } ``` ::: ### `sca.wallet.delete` ::: code-group ```json [JSON] { "webhook":"sca.wallet.delete", "object":"sca.wallet", "object_id":"a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6", "object_payload":{ "scaWallets":[ { "id":1234567890123456789, "issuerWalletId":"a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6", "issuerClientId":"123456", "preparationType":"default", "msisdn":null, "status":"DELETED", "subStatus":"DELETED_BY_ISSUER", "passcodeStatus":"NOT_SET", "eligibleProducts":[ ], "locked":true, "lockReasons":[ "ISSUER" ], "lockMessage":"USER_REQUEST", "incidentCounter":0, "settingsProfile":"default", "settings":null, "userSettings":null, "applicableSettings":{ "limits":{ "maxTransactionAmount":100000000, "mobileConnectionTimeout":60, "activationCodeLifetime":1200, "checkTransactionOutcomeTimeout":4000, "checkTransactionOutcomePolling":2000, "pingAckDelay":500, "pingPeriod":604799, "checkEligibilityPeriod":30 }, "security":{ "rootAllowed":true, "geolocateMessages":false, "userGeolocatePayments":false, "settingsProtection":true, "accelerometerProtection":false, "paymentCondition":"NO", "scaOfflineAuthenticationReuseDuration":0 }, "credentials":{ "sessionLifetime":10 } }, "issuerData":null, "mobileWallet":{ "appBuildNumber":null, "sdkVersion":null, "os":null, "osVersion":null, "brand":null, "productModel":null, "deviceId":null, "deviceIdType":null, "productFingerprint":null, "secretFingerprint":null, "root":null, "pushMessagingId":null, "pushMessagingProvider":null, "mobileUpdateDate":null, "lastEligibilityCheck":null, "nfc":null, "emulator":false, "appleTeamId":null }, "activationCode":null, "activationCodeB32":null, "creationDate":"2025-03-24T10:34:41+01:00", "deletionDate":"2025-03-24T11:06:22+01:00", "activationCodeExpiryDate":"2025-03-24T10:54:41+01:00", "cards":[ ], "currencyCode":"EUR", "authenticationMethods":[ { "type":"DEVICE_BIOMETRIC", "usages":[ "STRONG_CUSTOMER_AUTHENTICATION" ], "parameters":{ "validityDuration":60 } }, { "type":"NONE", "usages":[ "STRONG_CUSTOMER_AUTHENTICATION" ], "parameters":[ ] }, { "type":"HYBRID_PIN", "usages":[ "WALLET_MANAGEMENT", "STRONG_CUSTOMER_AUTHENTICATION" ], "parameters":{ "maxAttempts":3, "validityDuration":60 } } ], "lastPasscodeSyncDate":null, "issuerActivationId":null, "invalidActivationAttempts":null, "userId":"100000001", "scaWalletTag":"test", "activationDate":null, "lockDate":null, "unlockDate":null, "resetPinDate":null } ] }, "webhook_created_at":17428108419449, "webhook_id":"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee", "object_payload_signature":"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX=" } ``` ::: ### `sca.wallet.lock` ::: code-group ```json [JSON] { "webhook":"sca.wallet.lock", "object":"sca.wallet", "object_id":"a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6", "object_payload":{ "scaWallets":[ { "id":1234567890123456789, "issuerWalletId":"a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6", "issuerClientId":"123456", "preparationType":"default", "msisdn":null, "status":"CREATED", "subStatus":"CREATED_READY", "passcodeStatus":"NOT_SET", "eligibleProducts":[ ], "locked":true, "lockReasons":[ "ISSUER" ], "lockMessage":"USER_REQUEST", "incidentCounter":0, "settingsProfile":"default", "settings":null, "userSettings":null, "applicableSettings":{ "limits":{ "maxTransactionAmount":100000000, "mobileConnectionTimeout":60, "activationCodeLifetime":1200, "checkTransactionOutcomeTimeout":4000, "checkTransactionOutcomePolling":2000, "pingAckDelay":500, "pingPeriod":604799, "checkEligibilityPeriod":30 }, "security":{ "rootAllowed":true, "geolocateMessages":false, "userGeolocatePayments":false, "settingsProtection":true, "accelerometerProtection":false, "paymentCondition":"NO", "scaOfflineAuthenticationReuseDuration":0 }, "credentials":{ "sessionLifetime":10 } }, "issuerData":null, "mobileWallet":{ "appBuildNumber":null, "sdkVersion":null, "os":null, "osVersion":null, "brand":null, "productModel":null, "deviceId":null, "deviceIdType":null, "productFingerprint":null, "secretFingerprint":null, "root":null, "pushMessagingId":null, "pushMessagingProvider":null, "mobileUpdateDate":null, "lastEligibilityCheck":null, "nfc":null, "emulator":false, "appleTeamId":null }, "activationCode":null, "activationCodeB32":null, "creationDate":"2025-03-24T10:34:41+01:00", "deletionDate":null, "activationCodeExpiryDate":"2025-03-24T10:54:41+01:00", "cards":[ ], "currencyCode":"EUR", "authenticationMethods":[ { "type":"DEVICE_BIOMETRIC", "usages":[ "STRONG_CUSTOMER_AUTHENTICATION" ], "parameters":{ "validityDuration":60 } }, { "type":"NONE", "usages":[ "STRONG_CUSTOMER_AUTHENTICATION" ], "parameters":[ ] }, { "type":"HYBRID_PIN", "usages":[ "WALLET_MANAGEMENT", "STRONG_CUSTOMER_AUTHENTICATION" ], "parameters":{ "maxAttempts":3, "validityDuration":60 } } ], "lastPasscodeSyncDate":null, "issuerActivationId":null, "invalidActivationAttempts":null, "userId":"100000001", "scaWalletTag":"test", "activationDate":null, "lockDate":"2025-03-24T09:34:41+00:00", "unlockDate":null, "resetPinDate":null } ] }, "webhook_created_at":17428089074303, "webhook_id":"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee", "object_payload_signature":"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX=" } ``` ::: ### `sca.wallet.unlock` ::: code-group ```json [JSON] { "webhook":"sca.wallet.unlock", "object":"sca.wallet", "object_id":"a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6", "object_payload":{ "scaWallets":[ { "id":1234567890123456789, "issuerWalletId":"a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6", "issuerClientId":"123456", "preparationType":"default", "msisdn":null, "status":"CREATED", "subStatus":"CREATED_READY", "passcodeStatus":"NOT_SET", "eligibleProducts":[ ], "locked":false, "lockReasons":[ ], "lockMessage":null, "incidentCounter":0, "settingsProfile":"default", "settings":null, "userSettings":null, "applicableSettings":{ "limits":{ "maxTransactionAmount":100000000, "mobileConnectionTimeout":60, "activationCodeLifetime":1200, "checkTransactionOutcomeTimeout":4000, "checkTransactionOutcomePolling":2000, "pingAckDelay":500, "pingPeriod":604799, "checkEligibilityPeriod":30 }, "security":{ "rootAllowed":true, "geolocateMessages":false, "userGeolocatePayments":false, "settingsProtection":true, "accelerometerProtection":false, "paymentCondition":"NO", "scaOfflineAuthenticationReuseDuration":0 }, "credentials":{ "sessionLifetime":10 } }, "issuerData":null, "mobileWallet":{ "appBuildNumber":null, "sdkVersion":null, "os":null, "osVersion":null, "brand":null, "productModel":null, "deviceId":null, "deviceIdType":null, "productFingerprint":null, "secretFingerprint":null, "root":null, "pushMessagingId":null, "pushMessagingProvider":null, "mobileUpdateDate":null, "lastEligibilityCheck":null, "nfc":null, "emulator":false, "appleTeamId":null }, "activationCode":null, "activationCodeB32":null, "creationDate":"2025-03-24T10:35:09+01:00", "deletionDate":null, "activationCodeExpiryDate":"2025-03-24T10:55:09+01:00", "cards":[ ], "currencyCode":"EUR", "authenticationMethods":[ { "type":"DEVICE_BIOMETRIC", "usages":[ "STRONG_CUSTOMER_AUTHENTICATION" ], "parameters":{ "validityDuration":60 } }, { "type":"NONE", "usages":[ "STRONG_CUSTOMER_AUTHENTICATION" ], "parameters":[ ] }, { "type":"HYBRID_PIN", "usages":[ "WALLET_MANAGEMENT", "STRONG_CUSTOMER_AUTHENTICATION" ], "parameters":{ "maxAttempts":3, "validityDuration":60 } } ], "lastPasscodeSyncDate":null, "issuerActivationId":null, "invalidActivationAttempts":null, "userId":"100000001", "scaWalletTag":"test", "activationDate":null, "lockDate":"2025-03-24T10:35:10+01:00", "unlockDate":"2025-03-24T09:35:10+00:00", "resetPinDate":null } ] }, "webhook_created_at":17428089747334, "webhook_id":"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee", "object_payload_signature":"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX=" } ``` ::: ### `sca.wallet.resetPin` ::: code-group ```json [JSON] { "webhook":"sca.wallet.resetPin", "object":"sca.wallet", "object_id":"a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6", "object_payload":{ "scaWallets":[ { "id":"a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6", "status":"ACTIVE", "subStatus":"ACTIVATED_LOGGED_OUT", "passcodeStatus":"NOT_SET", "locked":false, "lockReasons":[ ], "lockMessage":null, "settingsProfile":"default", "mobileWallet":{ "appBuildNumber":"v04-04-06-06-02-02", "sdkVersion":"2.4.11", "os":"ANDROID", "osVersion":"14", "brand":"Google", "productModel":"sdk_gphone64_arm64", "deviceId":"abcdef1234567890", "deviceIdType":"ANDROID_ID", "productFingerprint":"google/sdk_gphone64_arm64/emu64a:14/UE1A.230829.036.A1/11228894:user/release-keys", "secretFingerprint":"0xbc311dfcef97f93fe3611722d81cd4061ee3711ea9148d7ee0ef88fe97f4fddb", "secretFingerprint":"0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890", "pushMessagingId":"abcdefghijklmnopqrstuvwx:APA91bABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890", "pushMessagingProvider":"FIREBASE", "pushMessagingId":"abcdefghijklmnopqrstuvwx:APA91bABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890", "lastEligibilityCheck":"2025-03-21T09:09:21Z", "nfc":false, "emulator":true, "appleTeamId":null }, "activationCode":null, "creationDate":"2025-03-21T10:07:29+01:00", "deletionDate":null, "activationCodeExpiryDate":"2025-03-21T10:27:29+01:00", "authenticationMethods":[ { "type":"DEVICE_BIOMETRIC", "usages":[ "STRONG_CUSTOMER_AUTHENTICATION" ], "parameters":{ "validityDuration":60 } }, { "type":"NONE", "usages":[ "STRONG_CUSTOMER_AUTHENTICATION" ], "parameters":[ ] }, { "type":"HYBRID_PIN", "usages":[ "WALLET_MANAGEMENT", "STRONG_CUSTOMER_AUTHENTICATION" ], "parameters":{ "maxAttempts":3, "validityDuration":60 } } ], "invalidActivationAttempts":null, "userId":"100000001", "scaWalletTag":"test", "clientId":"123456", "activationDate":"2025-03-21T10:09:21+01:00", "lockDate":"2025-03-21T11:46:00+01:00", "unlockDate":null, "resetPinDate":"2025-03-24T10:35:05+01:00" } ] }, "webhook_created_at":17428089054820, "webhook_id":"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee", "object_payload_signature":"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX=" } ``` ::: ### `sca.wallet.swap` ::: code-group ```json [JSON] { "webhook": "sca.wallet.swap", "object": "scaWallet", "object_id": "23cbf5648a234c4fb4624036f988b0d1", "object_payload": { "scaWallets": [ { "id": "23cbf5648a234c4fb4624036f988b0d1", "status": "CREATED", "subStatus": "CREATED_READY", "passcodeStatus": "NOT_SET", "locked": false, "lockReasons": [], "lockMessage": null, "settingsProfile": "default", "mobileWallet": null, "activationCode": "0x9a63a75dfc9f78dbef298ea0635b8d21", "creationDate": "2025-06-26T15:22:45+02:00", "deletionDate": null, "activationCodeExpiryDate": "2025-06-26T15:42:45+02:00", "authenticationMethods": [ { "type": "DEVICE_BIOMETRIC", "usages": [ "STRONG_CUSTOMER_AUTHENTICATION" ], "parameters": { "validityDuration": 60 } }, { "type": "NONE", "usages": [ "STRONG_CUSTOMER_AUTHENTICATION" ], "parameters": [] }, { "type": "HYBRID_PIN", "usages": [ "WALLET_MANAGEMENT", "STRONG_CUSTOMER_AUTHENTICATION" ], "parameters": { "maxAttempts": 3, "validityDuration": 60 } } ], "invalidActivationAttempts": null, "userId": "102267265", "scaWalletTag": "", "clientId": "92912345252", "activationDate": null, "lockDate": null, "unlockDate": null, "resetPinDate": null } ] }, "webhook_created_at": 17509441656229, "webhook_id": "f6d4bf56-0e0f-4136-b210-e5ba5c8d3b36", "object_payload_signature": "8sCloQ+CVXvLk1EJu8/mHTmxxxffrUKAeJLJHd4sKqWo=" } ``` ::: --- --- url: /guide/strong-customer-authentication/sca-wallet-lifecycle.md description: >- Technical guide for managing the SCA Wallets life cycle, such as locking, unlocking, and changing passcodes or PINs. Includes required parameters, request structure, and response examples. --- # SCA Wallet life cycle ## Locking When you suspect that an SCA Wallet or device may have been compromised, you should lock the SCA Wallet and provide a [reason](/guide/strong-customer-authentication/introduction#locking-reasons-lockreason) for doing so. Locking is a sensitive action, so users must be strongly authenticated before proceeding. ::: code-group ```bash [CURL] curl -X PUT '{baseUrl}/core-connect/sca/scawallets/{scaWalletId}/lock' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "lockReason":"LOST_DEVICE", // see list below "lockMessage":"string" // optional, max 256 characters } ``` ::: Returns a `200` HTTP Status Code and the updated SCA Wallet object. Treezor also sends the [`sca.wallet.lock`](/guide/strong-customer-authentication/events#sca-wallet-lock) webhook. On the SDK, this triggers the [`WalletEventListener#onWalletLocked()`](sdk#events) event. ## Unlocking If an SCA Wallet has been [locked](#locking) by one of your [Dashboard Users](/guide/dashboard/dashboard-users) **and after the legitimacy of the device has been reestablished**, you may unlock it using the following request. This is a sensitive action that can be done by: * **Your Dashboard Users**, with two-factor authentication, or * **The end user**, if they provide a per-operation SCA proof. ::: code-group ```bash [CURL] curl -X PUT '{baseUrl}/core-connect/sca/scawallets/{scaWalletId}/unlock' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' ``` ::: Answers with a `200` HTTP Status Code and the updated SCA Wallet object. Treezor also sends the [`sca.wallet.unlock`](/guide/strong-customer-authentication/events#sca-wallet-unlock) webhook. Unlocking the SCA Wallet also triggers the [`WalletEventListener#onWalletUnlocked()`](sdk#events) event on the SDK. ## Deletion A user using a single device should have a single SCA Wallet. The SCA Wallets of your users should be monitored as to avoid multiple or inactive SCA Wallets for a unique end user. SCA Wallets should be deleted when: * They haven't been used in a long time and probably can't be trusted anymore, * The user declared their device stolen/lost, * The user gets a new device that replaces the old one, * Your commercial relationship with the user ends. **Alert – Automatic deletion** Treezor automatically deletes SCA Wallets that have been inactive for 6 months. An SCA Wallet is considered inactive if the last SCA Proof is older than 6 months. The following request can be used to delete an SCA Wallet, including by the end user if they provide a per-operation SCA proof. ::: code-group ```bash [CURL] curl -X DELETE '{baseUrl}/core-connect/sca/scawallets/{scaWalletId}' \ --header 'Authorization: Bearer {accessToken}' ``` ::: Answers with a `200` HTTP Status Code and the updated SCA Wallet object. Treezor also sends the [`sca.wallet.delete`](/guide/strong-customer-authentication/events#sca-wallet-delete) webhook. Deleting an SCA Wallet triggers the [`WalletEventListener#onWalletDeleted()`](sdk#events) event on the SDK. ## Reset PIN (Mobile) SCA Wallets are protected by PIN codes on end user devices. Resetting PIN codes is only available to you and your team, this is not an action that can be exposed to your end users. This only applies to mobile SCA Wallets (i.e., SCA Wallets whose `settingsProfile` attribute is `default`). To reset a PIN code, you can use the following request. ::: code-group ```bash [CURL] curl -X PUT '{baseUrl}/core-connect/sca/scawallets/{scaWalletId}/resetPin' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' ``` ::: Returns a `200` HTTP Status Code and the updated SCA Wallet object. Treezor also sends the [`sca.wallet.resetPin`](/guide/strong-customer-authentication/events#sca-wallet-resetpin) webhook. On the SDK, this triggers the [`WalletEventListener#onCustomerCredentialsReset()`](sdk#events) event. The end user is now able to define a new PIN from their device. ## Passcode change (Web Native) This is considered a sensitive action, so users must be strongly authenticated before setting a new passcode (at least 6 characters). There are two use cases depending on whether the user knows their current passcode: * **[With SCA proof](#with-sca-proof)** – If the user knows their current passcode. * **[With 2-factor authentication](#with-2-factor-authentication)** – If the user doesn't know their current passcode. This only applies to mobile SCA Wallets (i.e., SCA Wallets whose `settingsProfile` attribute is `webauthn`). **Tip – Passcode is shared between devices** Contrary to device-specific [SDK passcodes](/guide/strong-customer-authentication/sdk#pin-change), the passcode used with Web Native is not tied to the device passkeys and technically not used to access the passkeys. Therefore, the passcode is not device-specific; if a User has multiple Web Native devices enrolled, a single and unique passcode is used for all of them. ### With SCA proof If your user already knows their passcodes, use the following request with a `delegated_end_user` JWT. ::: code-group ```bash [CURL] curl -X PUT '{baseUrl}/core-connect/sca/setPasscode' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "userId": "123456", "newPasscode": "", "confirmPasscode": "", "sca": "{scaProof}" } ``` ::: Answers with `204 Accepted` HTTP status code. ### With 2-factor authentication If your user don't know their passcodes, use the following request with a `client_credentials` JWT while ensuring the user is who they claim to be with relevant information as necessary, such as: * Their birthdate, email address, mobile phone number * A one-time-password that you sent to their email address * A one-time-password that you sent to their mobile phone If enough conditions are met, you may contact Treezor endpoint for the user to set their new passcode with the following request. ::: code-group ```bash [CURL] curl -X PUT '{baseUrl}/core-connect/sca/setPasscode' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "userId": "123456", "newPasscode": "", "confirmPasscode": "", "authMethod":["OTP SMS", "OTP EMAIL", "ID", "OTHER"], // List methods used to ensure the user's identity } ``` ::: Answers with `204 Accepted` HTTP status code. ## Endpoints | Endpoint | [Scope](/guide/api-basics/authentication#available-scopes) | | --- | --- | | [`/core-connect/sca/scawallets/swap`](/api-reference/api-endpoints.html#tag/SCA/swapSCAWallets){target="\_self"} | `read_write` | | [`/core-connect/sca/scawallets/{scaWalletId}/lock`](/api-reference/api-endpoints.html#tag/SCA/putScaWallet){target="\_self"} | `legal` | | [`/core-connect/sca/scawallets/{scaWalletId}/resetPin`](/api-reference/api-endpoints.html#tag/SCA/resetScaWalletPin){target="\_self"} | `legal` | | [`/core-connect/sca/scawallets/{scaWalletId}/unlock`](/api-reference/api-endpoints.html#tag/SCA/unlockScaWallet){target="\_self"} | `legal` | | [`/core-connect/sca/setPasscode`](/api-reference/api-endpoints.html#tag/SCA/setPasscode){target="\_self"} | `read_write` | --- --- url: /guide/strong-customer-authentication/securing-endpoints.md description: >- Guide for declaring your end users actions (passive session, active session, or invididual), whether they are made with Treezor endpoints or not. Includes request and examples for the external operation declaration. --- # Securing endpoints ## Functional context If you're eligible to SCA, you're legally required to declare the end users actions, regardless of whether they are done with [Treezor endpoints](#applying-sca-with-treezor-services) or with [your own back end](#declaring-sca-external-operations). The actions requiring SCA can be broken down into 3 categories: * [Passive session actions](#passive-session-actions) * [Active session actions](#active-session-actions) * [Individual actions](#individual-actions) A session means that the requests of the end user to the Treezor API are [authenticated](authenticating) using a [JWT](/guide/overview/glossary#json-web-token-jwt) which: * Was obtained with an SCA of type != [`None`](sdk#methods) (JWT with a `trz:sca` valued to `true`). * Is not expired (i.e., obtained in the last 60 minutes as JWT have a 60-minute lifetime) * Was used in the last 5 minutes to make any valid call to the Treezor API. **Note – Session expiration after 5 minutes** Even if the JWT itself hasn't expired yet, if it has not been used in the last 5 minutes to call Treezor API **the SCA session is considered expired**. If the session has expired, the following error will be returned by the API with a `401` HTTP Status Code. ::: code-group ```json [JSON] { "errors": [ { "type": "invalid_request", "code": "sca_session_expired", "message": "Your session has expired.", "docUrl": "string" } ] } ``` ::: ### Passive session actions Per-session operations with 180 days exemption. The following actions can be done if a [session](introduction#session) with an SCA (`!= None`) was used in the last 180 days: * Logging into the customer space * Checking the Balance of Wallets * Checking the Operations history of the last 90 days ### Active session actions Per-session operations The following actions can be done if this very session was opened using an SCA (`!= None`), and if the session is still active. * Ordering a [new Card](/guide/cards/creation) * [Transferring funds](/guide/transfers/wallet-to-wallet) between Wallets belonging to the same User * Searching for [operations](/guide/wallets/operations) * Checking or downloading [Account Statements](/guide/wallets/account-documents) or [certificates](/guide/wallets/account-documents) * Displaying bank account details * Self-certifications (such as defining a tax residence, etc.) If the session is no longer active or if this is the first time the user is authenticating, then a new session must be open with an SCA (`!= None`). ### Individual actions For all the following operations, a per-operation SCA is required (regardless of the use of an SCA during initial authentication and session opening). * [Activating a Card](/guide/cards/creation#activation) * [Approving an online payment](/guide/cards/transactions-authentication) with a Card (e-commerce) * Displaying a Card information (PAN, CVV, etc.) * Enrolling a Card into [X-Pay](/guide/cards/x-pay-google-apple) * Changing a [Card payment or withdrawal limits](/guide/cards/restrictions-limits#payment-withdrawal-limits) * Changing a [Card restrictions or options](/guide/cards/restrictions-limits#options-permission-groups) * [Modifying, displaying, and unlocking a PIN](/guide/cards/modification#change-pin) * [Unlocking the CVV](/guide/cards/modification#unlock-cvv) * [Updating personal information](/guide/users/introduction) (mobile phone, email, address) * [Transferring funds between Wallets](/guide/transfers/wallet-to-wallet) belonging to distinct Users * Adding or changing a [Beneficiary](/guide/transfers/beneficiaries) * Creating a [SEPA transfer](/guide/transfers/credit-transfer#emitted-credit-transfers-scte) * Initiating recurring payments or mass payment ## Applying SCA with Treezor services You must provide an SCA proof anytime you use a Treezor API request that falls into the functional context of Strong Customer Authentication. This proof of SCA is to be presented in a specific way (i.e., data to sign in the path and [payload](/guide/strong-customer-authentication/sdk#payload)), as listed in the endpoints requiring SCA in the table below. You may also: * Find badges across the documentation, indicating the need for an SCA. * Check out the [Regulatory Technical Standards](https://eur-lex.europa.eu/legal-content/EN/TXT/HTML/?uri=CELEX:32018R0389\&from=EN) for an exhaustive and authoritative list of operations requiring SCA. ### Per Session | Endpoint | Note | |--- |--- | | [`/v1/cards/CreateVirtual`](/api-reference/api-endpoints.html#tag/Cards/postCardVirtual){target="\_self"} | | | [`/v1/cards/RequestPhysical`](/api-reference/api-endpoints.html#tag/Cards/postCardPhysical){target="\_self"} | | | [`/core-connect/card/bulk`](/api-reference/api-endpoints.html#tag/Cards%20Bulk%20Creation/postBulkCard){target="\_self"} | | | [`/v1/taxResidences`](/api-reference/api-endpoints.html#tag/User%20Tax%20Residences/postTaxresidence){target="\_self"} | | | [`/v1/taxResidences/{taxResidenceId}`](/api-reference/api-endpoints.html#tag/User%20Tax%20Residences/putTaxresidence){target="\_self"} | | | [`/v1/wallets`](/api-reference/api-endpoints.html#tag/Wallets/postWallets){target="\_self"} | | | [`/core-connect/account-details/{walletId}/raw`](/api-reference/api-endpoints.html#tag/Account%20Documents/getRawWalletAccountDetail){target="\_self"} | | | [`/core-connect/account-details/{walletId}/computed`](/api-reference/api-endpoints.html#tag/Account%20Documents/getComputedWalletAccountDetail){target="\_self"} | | | [`/core-connect/statements/{walletId}/raw`](/api-reference/api-endpoints.html#tag/Account%20Statements/getRawStatement){target="\_self"} | | | [`/core-connect/statements/{walletId}/computed`](/api-reference/api-endpoints.html#tag/Account%20Statements/getPdfAccountStatement){target="\_self"} | | | [`/core-connect/operations`](/api-reference/api-endpoints.html#tag/Operations/getOperations){target="\_self"} | Only for operations that are more than 90 days old | | [`/v1/transfers`](/api-reference/api-endpoints.html#tag/Transfers/postTransfers){target="\_self"} | Only if `beneficiaryWalletId` belongs to the current User | | [`/core-connect/certificates/walletBalance/{walletId}/computed`](/api-reference/api-endpoints.html#tag/Account%20Documents/getWalletBalanceComputed){target="\_self"} |  | | [`/core-connect/certificates/walletBalance/{walletId}/raw`](/api-reference/api-endpoints.html#tag/Account%20Documents/getWalletBalanceRaw){target="\_self"} |  | | [`/core-connect/certificates/walletClosure/{walletId}/computed`](/api-reference/api-endpoints.html#tag/Account%20Documents/getWalletClosureComputed){target="\_self"} |  | | [`/core-connect/certificates/walletClosure/{walletId}/raw`](/api-reference/api-endpoints.html#tag/Account%20Documents/getWalletClosureRaw){target="\_self"} |  | | [`/core-connect/certificates/walletDomiciliation/{walletId}/computed`](/api-reference/api-endpoints.html#tag/Account%20Documents/getWalletDomiciliationComputed){target="\_self"} |  | | [`/core-connect/certificates/walletDomiciliation/{walletId}/raw`](/api-reference/api-endpoints.html#tag/Account%20Documents/getPdfAccountStatement){target="\_self"} |  | ### Per Operation | Endpoint | Data to sign in the SCA proof `body`(only if present in the [payload](/guide/strong-customer-authentication/sdk#payload)) | Note | |--- |--- |--- | | `/v1/auth-requests/{authRequestId}/result` | | | | `/v1/bankaccounts` | `userId`, `bankaccountOwnerName`, `bankaccountOwnerAddress`, `bankaccountIBAN`, `bankaccountBIC`, `bankaccountType` | | | [`/v1/beneficiaries`](/api-reference/api-endpoints.html#tag/Beneficiaries/postBeneficiary){target="\_self"} | `userId`, `name`, `nickname`, `iban`, `bic`, `usableForSct` | [*Payload example*](/guide/strong-customer-authentication/sdk#post-v1-beneficiaries) | | [`/v1/beneficiaries/{beneficiaryId}`](/api-reference/api-endpoints.html#tag/Beneficiaries/putBeneficiary){target="\_self"} | `nickName`, `name`, `iban`, `bic`, `usableForSct`, `isActive` | | | [`/v1/cardimages`](/api-reference/api-endpoints.html#tag/Cards/getCardImage){target="\_self"} | `cardId` | [*Payload example*](/guide/strong-customer-authentication/sdk#get-v1-cardimages) | | [`/v1/cards/{cardId}/Activate`](/api-reference/api-endpoints.html#tag/Cards/activateCard){target="\_self"} | | [*Payload example*](/guide/strong-customer-authentication/sdk#put-v1-cards%E2%80%8B-id-%E2%80%8B-activate) | | [`/v1/cards/{publicToken}/public-token-activation`](/api-reference/api-endpoints.html#tag/Cards/activateCardToken){target="\_self"} | | | | [`/v1/cards/{cardId}/ChangePIN`](/api-reference/api-endpoints.html#tag/Cards/changePin){target="\_self"} | | | | [`/v1/cards/{cardId}/setPIN`](/api-reference/api-endpoints.html#tag/Cards/setPin){target="\_self"} | | | | [`/v1/cards/{cardId}/UnblockPIN`](/api-reference/api-endpoints.html#tag/Cards/unblockPin){target="\_self"} | | | | [`/v1/cards/{cardId}/LockUnlock`](/api-reference/api-endpoints.html#tag/Cards/updateBlockStatus){target="\_self"} | `lockStatus` | Only when unlocking (`lockStatus` is `0`) | | [`/v1/cards/{cardId}/Limits`](/api-reference/api-endpoints.html#tag/Cards/putLimits){target="\_self"} | `limitAtmYear`, `limitAtmMonth`, `limitAtmWeek`, `limitAtmDay`, `limitAtmAll`, `limitPaymentYear`, `limitPaymentMonth`, `limitPaymentWeek`, `limitPaymentDay`, `limitPaymentAll`, `paymentDailyLimit`, `restrictionGroupLimits` | [*Payload example*](/guide/strong-customer-authentication/sdk#put-v1-cards-cardid-limits) | | [`/v1/cards/{cardId}/Options`](/api-reference/api-endpoints.html#tag/Cards/cardOptions){target="\_self"} | `foreign`, `online`, `atm`, `nfc` | | | [`/v1/cards/{cardId}/unblockcvc2`](/api-reference/api-endpoints.html#tag/Cards/unblockCvcs){target="\_self"} | | | | [`/v1/issuerInitiatedDigitizationDatas`](/api-reference/api-endpoints.html#tag/Issuer%20Initiated%20Digitization%20Data/tavRequestPOST){target="\_self"} | `cardId`, `tokenRequestor`, `additionnalData` | | | [`/v1/cardDigitalizations/{cardDigitalizationId}`](/api-reference/api-endpoints.html#tag/Cards%20Digitalization/putcardDigitalizationsId){target="\_self"} | `status`, `reasonCode` | Only if the `status` is `unsuspend` | | [`/v1/payout`](/api-reference/api-endpoints.html#tag/Payouts/postPayout){target="\_self"} | `walletId`, `amount`, `currency`, `beneficiaryId` | | | [`/core-connect/sca/scawallets/{scaWalletId}/setPasscode`](/api-reference/api-endpoints.html#tag/SCA/setPasscode){target="\_self"} | | For web native wallets only, when using a `delegated_end_user` JWT. | | [`/core-connect/sca/scawallets/{scaWalletId}/resetPin`](/api-reference/api-endpoints.html#tag/SCA/resetScaWalletPin){target="\_self"} | | For mobile wallets only. | | [`/core-connect/sca/scawallets/{scaWalletId}/unlock`](/api-reference/api-endpoints.html#tag/SCA/unlockScaWallet){target="\_self"} | | | | [`/core-connect/scheduledPayment`](/api-reference/api-endpoints.html#tag/Scheduled%20Payments/postScheduledPayment){target="\_self"} | `walletId`, `beneficiaryType`, `beneficiary`, `beneficiaryLabel`, `amount`, `type`, `execAt`, `startAt`, `endAt`, `period`, `currency`, `scheduledPaymentName`, `endToEndId` | | | [`/v1/transfers`](/api-reference/api-endpoints.html#tag/Transfers/postTransfers){target="\_self"} | `walletId`, `beneficiaryWalletId`, `amount`, `currency`, `transferTypeId` | Only if `beneficiaryWalletId` doesn't belong to the current User | | [`/v1/users/{userId}`](/api-reference/api-endpoints.html#tag/Users/putUser){target="\_self"} | `phone`, `mobile`, `email`, `address1`, `address2`, `address3`, `postcode`, `city`, `state`, `country`, `countryName` | Only if `phone`, `mobile`, `email`, or any of the `address` attributes are modified. [*Payload example*](/guide/strong-customer-authentication/sdk#put-v1-users-userid) | **Best practice – Optimize user experience by avoiding subsequent calls on per-operation SCA endpoints** When an action on your application requires several calls to per-operation SCA endpoints, the user goes through multiple SCA in a row. Split your sensitive actions on your mobile app for a better experience. ::: details Example In your application, changing both the Card limits (`PUT /v1/cards/{cardId}/Limits`) and options (`PUT /v1/cards/{cardId}/Options`) at the same time and on the same screen requires 2 sequential SCA operations. This means your end user has to go through SCA twice. To avoid this, you could offer to change Options and Limits on different screens of your application. ::: ## SCA for Card Transactions When eligible to SCA, most card transactions must be authenticated. Therefore, the steps of a card transaction are the following: 1. **Authentication** – Ensuring the legitimate cardholder is initiating the transaction. 2. **Authorization** – Checking the balance, limits, restrictions, etc. to accept the transaction. 3. **Transaction** – Moving the funds from the cardholders' account. For the authentication step to be properly SCA-compliant, you must: * [Enroll the user card for OOB authentication](#card-authentication-methods-enrollment) * [Ensure your handle card transaction authentication properly](#card-transactions-authentication) Please note that the [3D Secure (3DS)](/guide/overview/glossary#_3d-secure-3ds) protocol on its own is not SCA-compliant. It is used as a fallback option only. ### Card authentication methods enrollment Cards must be registered with the 2 following methods to accept secure online payments: | Method | Endpoint | | --- | --- | | **[Out of Band (OOB)](#enrolling-to-out-of-band-authentication)** | [`/v1/cards/{cardId}/authentication-methods`](/api-reference/api-endpoints.html#tag/Card%203DSecure%20Enrollment%20\(SCA\)/postAuthMethods){target="\_self"} A strong customer authentication of the cardholder through their payment application.| | **[SMS method](#enrolling-to-fallback-sms-authentication)** | [`/v1/cards/Register3DS`](/api-reference/api-endpoints.html#tag/Cards/post3ds){target="\_self"} Fallback with a one-time password (OTP) sent by SMS. | **Tip – Cards are enrolled with both methods at the same time** This allows you to request a FALLBACK to the SMS method if the Out of Band authentication is not possible during a card transaction. #### Enrolling to Out of Band Authentication When a User has an active (provisioned) SCA Wallet, you must enable the SCA for a Card using the following request. ::: code-group ```bash [CURL] curl -X POST '{baseURL}/v1/cards/{cardId}/authentication-methods' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content: application/json' \ -d '{ "method": "OOB" }' ``` ::: Returns an HTTP 201 response. ::: code-group ```json [JSON] { "publicToken": "103685666", "id": "b7478da6-4165-4c8c-xxx0-8e9200f5162a", "method": "OOB", "system": "GPS" } ``` ::: #### Retrieving a Card authentication methods ::: code-group ```bash [CURL] curl -X GET '{baseURL}/v1/cards/{cardId}/authentication-methods' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content: application/json' \ ``` ::: Returns the Card enrollments list. ::: code-group ```json [JSON] [ { "publicToken": "103685965", "id": "2739879", "method": "OTPSMS", "system": "GPS" }, { "publicToken": "103685965", "id": "b7478da6-4165-4c8c-aaa0-8e9200f5162a", "method": "OOB", "system": "GPS" } ] ``` ::: #### Enrolling to fallback SMS Authentication #### 3DSecure enrollment endpoints Find below the list of 3DSecure endpoints (SCA Mode). | Endpoint | Description | | --- | --- | | [`/v1/cards/{cardId}/authentication-methods`](/api-reference/api-endpoints.html#tag/Card%203DSecure%20Enrollment%20\(SCA\)/postAuthMethods){target="\_self"} | Define the authentication methods of a Card | | [`/v1/cards/{cardId}/authentication-methods`](/api-reference/api-endpoints.html#tag/Card%203DSecure%20Enrollment%20\(SCA\)/getAuthMethods){target="\_self"} | Retrieve the authentication methods of a Card | | [`/v1/cards/{cardId}/authentication-methods/{authMethodId}`](/api-reference/api-endpoints.html#tag/Card%203DSecure%20Enrollment%20\(SCA\)/getAuthMethodsDetails){target="\_self"} | Retrieve details regarding the authentication method of a Card | | [`/v1/cards/{cardId}/authentication-methods/{authMethodId}`](/api-reference/api-endpoints.html#tag/Card%203DSecure%20Enrollment%20\(SCA\)/deleteAuthMethods){target="\_self"} | Delete the authentication method of a Card. Only available for OOB method. | ### Card transactions authentication **Reading – Article dedicated to Card transaction SCA** Learn more in the [Transactions authentication (SCA)](/guide/cards/transactions-authentication) article. ## Declaring SCA External Operations When applying SCA outside of Treezor services, you are legally required to declare the [listed end user actions](#functional-context) to Treezor. Treezor uses these declarations for reporting to the regulator. The External Operations endpoint allows you to declare any sensitive action that: * Required a Strong Customer Authentication (SCA) and, * Was made from your back end (rather than Treezor's) ### Key attributes Below are the most important External Operation attributes: | Attribute | Type | Description | | --- | --- | --- | | `externalOperationId` | string | 32-character long identifier of the External Operation the database (UUIDv4). |  | `actionName` | string | The end user action that was secured by an SCA. See [list of actions](#action-names-actionname). |  | `scaProof` | string | The valid proof that authenticated the end user's action. |  | `actionDate` | string | The date on which the declared action took place. |  | `resourceIds` | array | The list of unique identifiers (strings) of the objects, conditioned by the type of action: **walletId** for `externalGetStatement`, `externalGetBalance`, `externalOperationView`, `externalOperationView90Days`, and `externalDisplayAccountDetails`**payoutId** for **transferId** in case of a payout or transfer**cardId** for `externalUpdateLimitsCard`|  | `createdAt` | string | The date and time at which the External Operation was created. |  | `scaDate` | string | The `iat` timestamp of the `scaProof` for per-operation SCA. |  | `amr` | string | The type of SCA for per-operation SCA (e.g., `CLOUD_PIN`, `HYBRID_PIN`, `DEVICE_BIOMETRIC`) |  | `externalOperationNote` | string | Comment left by Treezor after scoring, indicating a potential issue. See [List of notes](#notes-externaloperationnote). |  #### Action names (`actionName`) The `actionName` parameter is required to declare an SCA External Operation. It can be one of the following: | `actionName` | Description | Session | | --- | --- | --- | | `externalGetBalance` | Retrieve the wallet balance | [Per-session (180 days exempt.)](#passive-session-actions) | | `externalOperationView90Days` | Retrieve the operations history for the last 90 days | [Per-session (180 days exempt.)](#passive-session-actions) | | | `externalOperationView` | Retrieve the operations history for operations older than 90 days | [Per-session](#active-session-actions) | | `externalDisplayAccountDetails` | Retrieve information about the Wallet (i.e., account details) | [Per-session](#active-session-actions) | | `externalGetStatement` | Retrieve the Account Statement (i.e., operations for a given month) | [Per-session](#active-session-actions) | | `externalMassPayoutOrderCreation` | Creation of a transfer order for a mass payout | [Per-operation](#individual-actions) | | `externalMassTransferOrderCreation` | Creation of a transfer order for a mass transfer | [Per-operation](#individual-actions) | | `externalScheduledPayoutOrder` | Creation of a transfer order for a scheduled or recurring payout | [Per-operation](#individual-actions) | | `externalScheduledTransferOrder` |  Creation of a transfer order for a scheduled or recurring transfer | [Per-operation](#individual-actions) | | `externalUpdateLimitsCard` | Update of the card limits externally. | [Per-operation](#individual-actions) | | `internalCheck` | Declare a sensitive action that is not part of Treezor's Regulatory Technical Standard but that you want to secure with strong authentication. | [Per-operation](#individual-actions) | ### Notes (`externalOperationNote`) The `externalOperationNote` parameter displays information when there is an issue with your External Operation Declaration. | `externalOperationNote` | Description | | --- | --- | | `Wrong sca value` | The JWT `trz:sca` is not to `true` | | `Wrong JWT. Grant type must be delegated end user` | The JWT `userType` is not `user` | | `Parse error` | The SCA proof is not readable | | `Wrong certificate` | The SCA proof certificate is not valid | | `Signature error` | The SCA proof is not signed | | `AMR not allowed` | The SCA proof `amr` is not allowed | | `Declaration delay is too long` | The time elapsed between SCA proof and the `actionDate` is over 300 seconds | ### Declare an External Operation In order to declare an SCA External Operation, you must use a JWT `accessToken` with a `delegated_end_user` grant type and the `read_write` scope. See the [SCA Authentication](authenticating) article for more information. You can then use the following request to declare an external operation. ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/core-connect/sca/externalOperations' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is a `{payload}` example: ::: code-group ```json [JSON] { "actionName": "string", // Required "scaProof": "string", // Conditional "actionDate": "date", // Required - RFC 3339 "resourceIds":[""] // Conditional depending on the actionName } ``` ::: Returns the External Operation object if successful. ::: code-group ```json [JSON] { "externalOperationId":"7a5740ed-b1ae-4afd-940b-1193275728ab", "actionName":"externalScheduledTransferOrder", "scaProof":"[...]MJsrki4orRnqQ", "actionDate":"2024-02-16T14:37:04+01:00", "resourceIds":[ "12345", "67890" ], "createdAt":"2024-02-16T14:37:05+01:00", "scaDate":"2024-02-16T14:37:04+01:00", "amr":"HYBRID_PIN", "externalOperationNote":"", "externalOperationResponseCode":0 // For Treezor purposes only } ``` ::: ### Update an External Operation You must update per-operation payment external operations in order to link all subsequent payments to the initial declaration. For instance, for recurring or mass payments, the steps are the following: 1. Declare your External Operation with [`/core-connect/sca/externalOperations`](/api-reference/api-endpoints.html#tag/SCA%20External%20Operations/postExtOperation){target="\_self"} 2. When the corresponding payments are created, update your external Operation by adding the `id` with [`/core-connect/sca/externalOperations/{externalOperationId}`](/api-reference/api-endpoints.html#tag/SCA%20External%20Operations/putExtOperation){target="\_self"} Each recurring payment must be declared and linked to the original External Operation declaration. In the case of mass payments, all the payment ids must be declared when updating the External Operation. Use the following request to update an External Operation declaration. ::: code-group ```bash [CURL] curl -X PUT '{baseUrl}/core-connect/sca/externalOperations/{externalOperationId}' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is a `{payload}` example: ::: code-group ```json [JSON] { "resourcesIds":["54321", "12345"] // Required } ``` ::: Returns the External Operation object if successful, with the updated list of `resourceIds`. ::: code-group ```json [JSON] { "externalOperationId":"7a5740ed-b1ae-4afd-940b-1193275728ab", "actionName":"externalScheduledPayoutOrder", "scaProof":"[...]MJsrki4orRnqQ", "actionDate":"2024-02-16T14:37:04+01:00", "resourceIds":[ "54321", "12345" ], "createdAt":"2024-02-16T14:37:05+01:00", "scaDate":"2024-02-16T14:37:04+01:00", "amr":"HYBRID_PIN", "externalOperationNote":"", "externalOperationResponseCode":0 // For Treezor purposes only } ``` ::: ### External Operation object ::: code-group ```json [JSON] { "externalOperationId":"7a5740ed-b1ae-4afd-940b-1193275728ab", "actionName":"externalScheduledPayoutOrder", "scaProof":"[...]MJsrki4orRnqQ", "actionDate":"2024-02-16T14:37:04+01:00", "resourceIds":[ "12345", "67890" ], "createdAt":"2024-02-16T14:37:05+01:00", "scaDate":"2024-02-16T14:37:04+01:00", "amr":"HYBRID_PIN", "externalOperationNote":"", "externalOperationResponseCode":0 // For Treezor purposes only } ``` ::: ### External Operation endpoints | Endpoint | [Scope](/guide/api-basics/authentication#available-scopes) | | --- | --- | | [`/core-connect/sca/externalOperations`](/api-reference/api-endpoints.html#tag/SCA%20External%20Operations/postExtOperation){target="\_self"} Create an SCA External Operation Declaration | `read_write` | | [`/core-connect/sca/externalOperation/{externalOperationId}`](/api-reference/api-endpoints.html#tag/SCA%20External%20Operations/putExtOperation){target="\_self"} Update an SCA External Operation Declaration | `read_write` | --- --- url: /guide/transfers/credit-transfer.md description: >- Technical guide for emitting and receiving SEPA Credit Transfers (SCT). Includes required parameters, request structure, and response examples. --- # SEPA Credit Transfers (SCT) [SEPA Credit Transfers (SCT)](/guide/overview/glossary#sepa-credit-transfer-sct) allow the initiator of the transfer (sender) to make Euro-denominated payments to [SEPA](/guide/overview/glossary#single-euro-payments-aera-sepa) countries accounts. At Treezor, SCT can be used in two directions: * [`SCTR`](#received-credit-transfers-sctr) are Received into a Wallet and mapped to **Payin** objects * [`SCTE`](#emitted-credit-transfers-scte) are Emitted from a Wallet and mapped to **Payout** objects ## Received Credit Transfers (SCTR) When an SCTR is received, a Payin object is created, along with a [`payin.create`](/guide/transfers/events#payin-create-1) webhook. Treezor receives batches of SCTR from other banks every worked day between 6:30 and 19:00 Paris local time. They are handled and Wallets are credited as they are received. **Tip – You can also provide [Virtual IBANs](/guide/wallets/iban) to receive SCTR** Virtual IBANs have many benefits over your main IBAN (restriction in the direction they can be used, restriction in validity period, easier funds movements categorization, etc.). ### The SCTR Payin object ::: code-group ```json [JSON] { "payins": [ { "payinId": "12345", "payinTag": null, "walletId": "34567", "userId": "852741", // Valued to 3 initially in Production. DO NOT USE. "payinStatus": "VALIDATED", // Funds are available to the Wallet owner "paymentMethodId": "20", "messageToUser": "Transfer to my Wallet", "subtotalItems": "100.00", "subtotalServices": "0.00", "subtotalTax": "0.00", "amount": "100.00", "currency": "EUR", "createdDate": "2018-01-01 17:00:00", "walletEventName": "Wallet Test", "walletAlias": "test-wallet-abcd", "userFirstname": "CMA", "userLastname": "", "codeStatus": "140005", "informationStatus": "", "refundAmount": null, "ibanFullname": "ALEX OAK", "DbtrIBAN": "FR763000401544999999999123", "ibanBic": "BNPAFRPP", "ibanTxEndToEndId": "XXXXXXXXX", "ibanTxId": "180799999990123", "forwardUrl": null, "paymentAcceptedUrl": null, "paymentRefusedUrl": null, "paymentWaitingUrl": null, "paymentExceptionUrl": null, "paymentCanceledUrl": null, "payinDate": null, "mandateId": null, "creditorName": "WILL OAK", "creditorAddressLine": null, "creditorCountry": null, "creditorIban": "FR761679999999999999011456", "creditorBIC": "TRZOFR21XXX", "virtualIbanId": null, "virtualIbanReference": null, "ibanId": "995d69d1839999999999a6935979ea8110d3" } ] } ``` ::: **Caution – `UserId` initial value in Production** In [Production environment](/guide/api-basics/environments), all SCTR are initially received with `userId` attribute valued to `3`. **It is strictly forbidden to use this value, this is a technical user for Treezor use only**. ### Rejection of an SCTR #### Immediate rejection An SCTR can be immediately rejected for [multiple reasons](error-codes#sctr-errors). In this case, a [`sepa.return_sctr`](/guide/transfers/events#sepa-return-sctr) webhook is sent with the [reason code](error-codes#sct-errors) provided in the [`return_reason_code`](events#sepa-return-sctr) attribute. #### Delayed rejection Treezor enforces [AML/CFT](/guide/overview/glossary#anti-money-laundering-and-countering-the-financing-of-terrorism-aml-cft) checks before validating an SCTR. When a suspicious SCTR is encountered, the SCTR funds are frozen and Treezor sends you: * A [`payinrefund.create`](events#payinrefund-create-1) webhook with `reasonTms` attribute set to `null` and `payinrefundStatus` attribute set to `PENDING` (which freezes the funds). * A [`payinrefund.update`](events#payinrefund-update-1) webhook with `reasonTms` attribute populated by an explanation. Upon further inspection by Treezor, the following occurs depending on whether the anomaly is confirmed: * **No anomaly** – A [`payinrefund.cancel`](events#payinrefund-cancel) webhook is sent (the wallet can be credited by the SCTR). * **Anomaly confirmed** – A [`payinrefund.update`](events#payinrefund-update-1) webhook is sent, with a `VALIDATED` `payinrefundStatus` (which refunds the SCTR). **Information – [AML/CFT](/guide/overview/glossary#anti-money-laundering-and-countering-the-financing-of-terrorism-aml-cft) inspection by Treezor can last up to 48h** Therefore, an SCTR can be delayed by up to 48 hours. ## Emitted Credit Transfers (SCTE) Treezor allows you to send funds from wallets to external accounts using SCTE. ### Requirements * The sender's Wallet must be valid and not [frozen](/guide/users/introduction#freezing) * The sender's User must be valid * You have the IBAN of the recipient * You have created an active [Beneficiary](beneficiaries) using this IBAN Although SCTE can be created an any time, they will only take place on a [SEPA Open Banking Day](/guide/overview/glossary#sepa-open-banking-days). ### Parameters | Attribute | Type | Description | | --- | --- | --- | | `walletId` | integer | The unique identifier of the debited Wallet. | | `beneficiaryId` | integer | The unique identifier of the Beneficiary of the Transfer. You must have created the [Beneficiary](./beneficiaries) object beforehand. | | `amount` | number | The amount of the credit transfer. | | `currency` | string | The currency of the credit transfer. Must be `EUR`. | | `supportFileLink` | string | Mandatory if the payout exceeds €10,000 (B2C) or €50,000 (B2B) for supporting documents. See [processing](#processing) for more information. | ### Request ::: code-group <<< @/guide/transfers/snippets/create\_payout.bash \[CURL] ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "walletId":{walletId}, "beneficiaryId":{beneficiaryId}, "amount":1000, "currency":"EUR" } ``` ::: Returns the Payout object, with its `payoutStatus` set to `PENDING` at first. You will then receive sequentially the following webhooks. | Webhook | When | Specific attributes | | --- | --- | --- | | [`payout.update`](/guide/transfers/events#pending) | When the SCTE is sent to the SEPA network. | `PENDING` status and `160014` codeStatus |  | [`payout.update`](/guide/transfers/events#validated) | When the SCTE sender's wallet is debited. | `VALIDATED` status | ::: code-group ```json [JSON] { "payouts":[ { "payoutId":"2XX40", "payoutTag":"25XXXXXXXXXXXXXXXX86f5cb", "payoutStatus":"VALIDATED", "payoutTypeId":1, "payoutType":"Credit Transfer", "walletId":"85090", "label":"Remboursement", "payoutDate":"2017-10-04", "amount":"1000.00", "currency":"EUR", "partnerFee":"0", "createdDate":"2017-10-04 09:37:34", "modifiedDate":"2017-10-04 09:55:57", "walletEventName":"XXXXXXXAB", "walletAlias":"XXXXXXXXXX", "userLastname":"", "userFirstname":"", "userId":"636338", "bankaccountIBAN":"XXXXXXXXXXXXXXXXXXXXXXXX", "codeStatus":"160004", "informationStatus":"", "supportingFileLink":"" } ] } ``` ::: Please note that to retrieve the beneficiary IBAN, you can fetch the Beneficiary object using the `beneficiaryId`. ### Processing Emitted SEPA Credit Transfers (SCTE) are **executed the next worked day** when requested before the cutoff point (10AM). When the SCTE exceeds €10,000 (B2C) or €50,000 (B2B), you must provide support documents in the `supportFileLink` parameter: * An invoice, bill, contract, or similar document. * A RIB of the creditor, edited by the creditor's bank. Support documents may be required for additional controls if Treezor deems the transaction of interest. Treezor is entitled to refuse an SCTE when the aforementioned requirements are not met, or upon suspicion of fraudulent activity. ### Rejection of an SCTE A beneficiary's bank can reject an SCTE for [multiple reasons](error-codes#sctr-errors). In this situation a [`payoutrefund.create`](/guide/transfers/events#payoutrefund-create-1) webhook is sent, with the [`reasonCode`](error-codes#sct-errors) for the rejection provided. ### Recalling an SCTE To recall an SCTE, please [check out the dedicated article](sepa-recalls#scte-recalls). --- --- url: /guide/transfers/direct-debit.md description: >- Technical guide for emitting and receiving SEPA Direct Debits (SDD). Includes required parameters, request structure, and response examples. --- # SEPA Direct Debits (SDD) [SEPA Direct Debit (SDD)](/guide/overview/glossary#sepa-direct-debit-sdd) allows the recipient of the transfer to collect Euro-denominated payments from [SEPA](/guide/overview/glossary#single-euro-payments-aera-sepa) countries accounts. This type of transfer is initiated by the creditor, hence requiring an IBAN and a debtor-approved [Mandate](/guide/transfers/mandates). At Treezor, SDD can be used in two directions: * [`SDDR`](#received-direct-debits-sddr) are Received into a Wallet and mapped to **Payout** objects * [`SDDE`](#emitted-direct-debits-sdde) are Emitted from a Wallet and mapped to **Payin** objects ## Received Direct Debits (SDDR) Treezor allows for the Wallets to be debited using SEPA Direct Debit (SDDR). They can be received by Treezor between 24h and 14 days before the desired SDD [effective date](/guide/overview/glossary#effective-date). While the creditor of the SDDR is always a business, there are 2 types of SDDR depending on the nature of the debtor: | Type | Debtor | Specific policies | | --- | --- | --- | | **SDDR Core** | Business or private individual | Refund is possible Accepted by default, can be blocked by blacklisting [UMRs](/guide/overview/glossary#unique-mandate-reference-umr) on the [Beneficiary](/guide/transfers/beneficiaries) | | **SDDR B2B** | Legal entity or individual acting for professional purposes | Refund is not possible Denied by default, can be authorized by whitelisting [UMRs](/guide/overview/glossary#unique-mandate-reference-umr) on the [Beneficiary](/guide/transfers/beneficiaries) | **Tip – [Virtual IBAN](/guide/wallets/iban) SDD reception is also supported** You may provide a Virtual IBAN to receive a SEPA Direct Debit into a Wallet. Virtual IBANs have many benefits over your main IBAN (direction and validity period restrictions, easier funds movements categorization, etc.). ### Receiving an SDDR When an SDD is received, Treezor sends a [`sepa_sddr.reception`](events#sepa-sddr-reception) webhook, so you can inform the end user about the Direct Debit and its amount. Treezor also controls the validity of the operation (e.g., the wallet is active, the Beneficiary not blacklisted, etc.). If the controls: * **Succeed**: The [Balance](/guide/overview/glossary#balance) and [Authorized Balance](/guide/overview/glossary#balance) of the Wallet remain unaffected until the SDD [effective date](/guide/overview/glossary#effective-date). * **Fail**: Treezor sends a [`sepa.reject_sddr_core`](events#sepa-reject-sddr-core) or a [`sepa.reject_sddr_b2b`](events#sepa-reject-sddr-b2b) webhook. **Best practice – Inform your end users of the SDD reception** They need to provision their Wallet to cover the corresponding amount. On the [effective date](/guide/overview/glossary#effective-date) of the SDD, Treezor: * Re-runs the controls made when the SDD was initially received. * Checks if the Wallet is sufficiently provisioned. * Checks if the [Beneficiary](/guide/transfers/beneficiaries) was created (SDDR B2B) or automatically creates the [Beneficiary](/guide/transfers/beneficiaries) (SDDR Core), which sends a [`beneficiary.create`](events#beneficiary-create) webhook. Then, if the controls: * **Succeed**: Treezor creates the Payout and sends a [`payout.create`](events#payout-create) webhook (`VALIDATED` status). * **Fail**: Treezor sends a [`sepa.return_sddr`](events#sepa-return-sddr) or a [`sepa.refund_sddr`](/guide/transfers/events#sepa-refund-sddr) webhook (no payout is created). **Reading – SDDR Rejection** Learn more about received SEPA Direct Debit rejection in the [SDDR Rejection](#rejection-of-an-sddr) section. ### The SDDR Payout object The SDDR takes the form of a payout object, structured and valued as follows. Please note that to retrieve the beneficiary IBAN, you can fetch the Beneficiary object using the `beneficiaryId`. ::: code-group ```json [JSON] { "payouts":[ { "payoutId":"12345", "payoutTag":"some-tag", "payoutStatus":"PENDING", "payoutTypeId":2, "payoutType":"Direct Debit", "walletId":"258024", "beneficiaryId":"33587", "uniqueMandateReference":null, "label":"Direct Debit SEAP ALEX OAK", "payoutDate":"2018-01-10", "amount":"100.00", "currency":"EUR", "partnerFee":"0", "createdDate":"2018-01-01 11:00:00", "modifiedDate":"0000-00-00 00:00:00", "walletEventName":"Wallet-Client", "walletAlias":"test-wallet", "userLastname":"", "userFirstname":"", "userId":"98765", "bankaccountIBAN":"ENCRYPTED IBAN", "codeStatus":"160001", "informationStatus":"", "supportingFileLink":"" } ] } ``` ::: You can check the [list of SDDR Errors Codes](error-codes#sddr-errors). ### Rejection of an SDDR #### Rejection upon reception by Treezor If the SDD is not valid, you receive a [`sepa.reject_sddr_core`](/guide/transfers/events#sepa-reject-sddr-core) or a [`sepa.reject_sddr_b2b`](/guide/transfers/events#sepa-reject-sddr-b2b) webhook. The [Wallet](/guide/wallets/introduction) [Balance](/guide/overview/glossary#balance) is not affected. #### Rejection on the effective date If the SDD operation can't take place on (or after) the effective date, Treezor sends you: * A [`sepa.return_sddr`](/guide/transfers/events#sepa-return-sddr) webhook (e.g., insufficient funds) **or** * A [`sepa.refund_sddr`](/guide/transfers/events#sepa-refund_sddr) webhook (unexpected delays in the controls or transmission of the SDD). ### Refund management To oppose an SDDR, the [User](/guide/users/introduction) first contacts you. You then [open a ticket](https://treezor.zendesk.com/hc/en-us/articles/4403978479634-How-to-create-a-Zendesk-ticket) with Treezor Support. Treezor sends you a [`payoutrefund.create`](/guide/transfers/events#payoutrefund-create) webhook with its status set to `PENDING`. Then, the refund can be either accepted or declined by the debiting bank: * **Accepted** – You receive a [`payoutrefund.update`](/guide/transfers/events#payoutrefund-update) webhook (`VALIDATED` status) which concludes the refund. * **Declined** – You receive a [`payoutrefund.update`](/guide/transfers/events#payoutrefund-update) webhook (`CANCELED` status) and the refund doesn't take place. Declines may occur if the SDDR is more than 8-week old or if the refund reason was improperly set for instance. ## Emitted Direct Debits (SDDE) Treezor allows [Users](/guide/users/introduction) to debit funds from somebody else's account using SEPA Direct Debit (SDDE). ### Creating an SDDE **Prerequisites – Prior to making an SDDE, you must have a:** * **SEPA Creditor Identifier (SCI)** – Contact Treezor to obtain one. * **[Mandate](/guide/transfers/mandates) signed by the debtor** – With the correct [`sddType`](mandates#mandatory-parameters), explicitly allowing you to initiate a transfer. Also, the debit date (`payinDate`) must be on a [SEPA Open Banking Day](/guide/overview/glossary#sepa-open-banking-days). #### Parameters Below are the main parameters of a SEPA Direct Debit Payin. | Attribute | Type | Description | | --- | --- | --- | | `paymentMethodId` | integer | Must be `21` for SDDE Core, or `22` for SDDE B2B. | | `walletId` | integer | The unique identifier of the credited Wallet. | | `mandateId` | integer | The unique identifier of the associated [Mandate](/guide/transfers/mandates) | | `amount` | number | The amount of the Payin. | | `currency` | string | The currency of the Payin. Must be `EUR`. | | `payinDate` | string | The [desired date](/guide/overview/glossary#effective-date) of the Payin, which must be a [SEPA Open Banking Day](/guide/overview/glossary#sepa-open-banking-days). Format: YYYY-MM-DD The earliest date you can define depends on when the payin is made compared to cut-off time (7:55PM UTC+1): **Before** – On the next SEPA Open Banking Day**After** – On the second next SEPA Open Banking DayDefaults to the third SEPA Open Banking Day following the payin creation if left empty. | | `messageToUser` | string | Message to send to Wallet of the user. For SEPA Direct Debit Core payment method, this parameter reconciles information transmitted to the Debtor (i.e., Invoice number). In this case, it can't exceed 140 characters. | #### Request ::: code-group <<< @/guide/transfers/snippets/create\_payin.bash \[CURL] ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "walletId":{walletId}, "paymentMethodId":21, // Or 22 for SDDE B2B "messageToUser":"Invoice number 089063", "mandateId":{mandateId}, "amount":1.25, "currency":"EUR" } ``` ::: Returns the Payin object, with its status set to `PENDING`. You will receive the corresponding [webhook](/guide/transfers/events) on the [desired Payin date](/guide/overview/glossary#effective-date) (`payinDate`). ::: code-group ```json [JSON] { "payins": [ { "payinId": "", "payinTag": "", "payinStatus": "", // is set to PENDING until the payinDate "codeStatus": , "informationStatus": "", "walletId": , // the wallet to credit "userId": "", // valued to 3 initially in Production. DO NOT USE. "cartId": , "walletEventName": "", "walletAlias": "", "userFirstname": "", "userLastname": "", "messageToUser": "", // commentary "paymentMethodId": , "amount": "", "currency": "", "distributorFee": "", "createdDate": "", "createdIp": "", "ibanFullname": "", "ibanId": "", "ibanBic": "", "ibanTxEndToEndId": "", "ibanTxId": "", "refundAmount": "", "totalRows": "", "forwardUrl": "", "payinDate": "", // desired date of effect, or "effective date" "mandateId": "", // is ID of the associated Mandate "creditorName": "", "creditorAddressLine": "", "creditorCountry": "", "creditorIban": "", "creditorBIC": "", "virtualIbanId": , "virtualIbanReference": "" [...] // some attributes are hidden } ] } ``` ::: **Caution – `userId` value in Production initially set to `3`.** It is strictly forbidden to use this value, this is a technical user for Treezor use only. #### Processing flow Depending on the evolution of the refund or return, you might receive the following webhooks for the payin refund. | Event | | Status | Description | | --- | :---: | --- | --- | | `payin.create` | | `PENDING` | Treezor issues an SDDE Payin. | | `payin.update` | | `VALIDATED` | The SDDE is accepted. | | `payin.cancel` | | `CANCELED` | The SDDE is rejected **before the effective date**. | Here is the diagram for an SDDE processing. ```mermaid flowchart TD A("Treezor issues an SDDE") B("Sends a payin.create webhook
payinStatus: PENDING") C("Sends a payin.update webhook
payinStatus: VALIDATED") D("Sends a payin.cancel webhook
payinStatus: CANCELED") E("Sends a transaction.create webhook") F("Sends a balance.update webhook") A --> B -- Accepted --> C B -- Rejected --> D C --> E --> F class A MermaidNeutral; class B neutral; class C neutral; class D neutral; class E neutral; class F neutral; ``` ### Cancelling an SDDE You can cancel an SDDE before Treezor processes it. SDDE processing at Treezor occurs daily at 8AM UTC+1. ::: details Example | Payin creation time | Deletable until | | --- | --- | | 2PM UTC+1 | 8:OOAM UTC+1 on the next day. | | 7AM UTC+1 | 8:OOAM UTC+1 on the same day. | ::: #### Request ::: code-group ```bash [CURL] curl -X DELETE '{baseUrl}/v1/payins/{payinId}' \ --header 'Authorization: Bearer {accessToken}' ``` ::: Returns the Payin object, with its status set to `CANCELED`. Treezor also sends a `payin.cancel` webhook. ::: code-group ```json [JSON] { "payins": [ { "payinId": "", "payinTag": "", "payinStatus": "CANCELED", // is set to CANCELED "codeStatus": 140004, "informationStatus": "", "walletId": , "userId": "", "cartId": , "walletEventName": "", "walletAlias": "", "userFirstname": "", "userLastname": "", "messageToUser": "", "paymentMethodId": , "amount": "", "currency": "", "distributorFee": "", "createdDate": "", "createdIp": "", "ibanFullname": "", "ibanId": "", "ibanBic": "", "ibanTxEndToEndId": "", "ibanTxId": "", "refundAmount": "", "totalRows": "", "forwardUrl": "", "payinDate": "", "mandateId": "", "creditorName": "", "creditorAddressLine": "", "creditorCountry": "", "creditorIban": "", "creditorBIC": "", "virtualIbanId": , "virtualIbanReference": "" [...] // some attributes are hidden } ] } ``` ::: If it is too late for you to cancel the SDDE, you receive the following HTTP 400 error: ::: code-group ```json [JSON] { "errors": [ { "type": "invalid_request", "code": "input_validation_error", "message": "The payin has already been sent to the scheme", "docUrl": "https://docs.treezor.com/guide/api-basics/response-codes.html" } ] } ``` ::: ### Rejection of an SDDE SDDE can be rejected either before or after the [effective date](/guide/overview/glossary#effective-date). ::: tabs \== Core \== B2B ::: ::: details Definitions * **Reject** – Refusal of the direct debit by the debited PSP before the effective date. * **Return** – Refusal of the direct debit by the debited PSP up to 5 (core) or 3 (B2B) days banking days after the effective date. * **Refund** (Core only) – Request of reimbursement from the debtor and initiated by their PSP after the effective date. This refund can be sent up to 13 months after the settlement date in case of a claim for unauthorized operation. ::: #### Rejection before effective date If the debtor bank rejects the SDDE, Treezor sends you a [`payin.cancel`](/guide/transfers/events#payin-cancel) webhook with: * The status set to `CANCELED` * The [reason code](/guide/transfers/error-codes#sdd-reason-codes) for rejection (e.g., closed account) in the `informationStatus` field. #### Rejection after effective date Although SDDE Returns and Refunds are 2 distinct R-transactions, Treezor handles them the same way. When receiving a return/refund for an SDDE, Treezor will try to refund the transaction and sends the corresponding webhooks. Those webhooks contain the reason for the return/refund in the `informationStatus` field. | Event | | Status | Description | | --- | :---: | --- | --- | | `payinrefund.create` | | `PENDING` | Treezor received an SDDE refund or return request. | | `payinrefund.update` | | `VALIDATED` | The SDDE refund or return is accepted. | | `payinrefund.cancel` | | `CANCELED` | The SDDE refund or return is refused. | If the refund is validated, then Treezor also sends a `transaction.create` webhook with a `transactionType` valued to "Payin Refund". #### Processing flow Here is the processing flow of a refund or return of an SDDE. ```mermaid flowchart TD A("Treezor receives an SDDE
return or refund request") B("Sends a payinrefund.create webhook
payinrenfundStatus: PENDING") C("Sends a payinrefund.update webhook
payinrenfundStatus: VALIDATED") D("Sends a payinrefund.cancel webhook
payinrenfundStatus: CANCELED") E("Sends a transaction.create webhook
transactionType: Payin Refund") F("Sends a balance.update webhook") A --> B -- Accepted --> C B -- Rejected --> D C --> E --> F class A MermaidNeutral; class B neutral; class C neutral; class D neutral; class E neutral; class F neutral; ``` --- --- url: /guide/transfers/credit-transfer-inst.md description: >- Technical guide for emitting and receiving SEPA Instant Credit Transfers (SCT Inst). Includes required parameters, request structure, and response examples. --- # SEPA Instant Payments The [SEPA Instant Credit Transfer](/guide/overview/glossary#sepa-instant-payments) is a real-time electronic payment method allowing for rapid and secure fund transfers between bank accounts within the SEPA region. The rapid processing offers a settlement within a matter of seconds, providing users with immediate access to transferred funds. Key benefits: * **Real-time transfers** – Allows for almost instant availability of funds to the recipient. * **SEPA region coverage** – Operates within the [SEPA](/guide/overview/glossary#single-euro-payments-aera-sepa), ensuring cross-border transfers in multiple European countries. * **24/7 availability** – Processes transfers 7 days a week, including weekends and holidays. * **Secure and efficient** – Enforces security measures to safeguard transfers while keeping an efficient process. **Configuration – SCT Inst are not enabled by default** You can request access to the SCT Inst feature by contacting Treezor. At Treezor, instant payments can be used in two directions: * [`SCTR Inst`](#received-instant-credit-transfers-sctr-inst) are Received into a Wallet and mapped to [**Payin**](#key-payin-attributes) objects * [`SCTE Inst`](#emitted-instant-credit-transfers-scte-inst) are Emitted from a Wallet, mapped to [**Payout**](#key-payout-attributes) objects ## Received Instant Credit Transfers (SCTR Inst) An SCTR Inst is a variant of an SCTR, that is received and makes funds available within 10 seconds of its emission. Therefore, an SCTR Inst can be received any day, any time. When receiving an SCTR Inst, Treezor might either [accept](#accepting-an-sctr-inst) or [refuse](#rejecting-an-sctr-inst) the transaction. You may also receive Recalls for SCTR Inst. See the [Emitting SCTR Inst Recalls](/guide/transfers/sepa-recalls#receiving-sctr-inst-recalls) article for details and how to answer. **Information – SCTR Inst amount is limited to:** * €10,000 in B2C context * €50,000 in B2B context Upon mutual agreement with Treezor, these limits may be lowered. ### Accepting an SCTR Inst When successfully receiving an SCTR Inst, Treezor: * Sends a [`payin.create`](events#payin-create-2) webhook (with a `paymentMethodId` valued to `27` and a `VALIDATED` status). * Creates a [Transaction](/guide/wallets/transactions) ([`transactionType`](/guide/wallets/transactions#transaction-types-transactiontype) valued to `Payin`). You can retrieve an SCTR Inst using the [`/v1/payins/{payinId}`](/api-reference/api-endpoints.html#tag/Payins/getPayin){target="\_self"} request. ### Rejecting an SCTR Inst Treezor may reject an SCTR Inst, if the [Wallet is closed](/guide/wallets/modification#delete) or if the amount exceeds the limits for instance. In such cases, Treezor sends a [`sepaSctrInst.reject_sctr_inst`](events#sepasctrinst-reject-sctr-inst) webhook. It contains a [`return_reason_code`](error-codes#sct-inst-errors) indicating the reason for the rejection. ### Processing flow Here is a diagram for an SCTR Inst processing. ```mermaid flowchart TD A("Originator PSP") B("Treezor") C("Sends a payin.create webhook (VALIDATED)") D("Sends a sepaSctrInst.reject_sctr_inst webhook") E("Sends a transaction.create webhook") F("Sends a balance.update webhook") A -- Sends SCTR Inst. --> B -- Accepted --> C B -- Refused --> D C --> E --> F class A MermaidNeutral; class C neutral; class D neutral; class E neutral; class F neutral; ``` ### The SCTR Inst Payin object ::: code-group ```json [JSON] {9} { "payins": [ { "payinId": "xxxxxx-xxxx-5xxx-9xxx-xxxxxxxxxxxx", // uuid for SCTR Inst "payinTag": null, "walletId": "34567", "userId": "852741", // Valued to 3 initially in Production. DO NOT USE. "payinStatus": "VALIDATED", // Means that the funds are available to the Wallet owner "paymentMethodId": "27", "messageToUser": "Transfer to my Wallet", "subtotalItems": "100.00", "subtotalServices": "0.00", "subtotalTax": "0.00", "amount": "100.00", "currency": "EUR", "createdDate": "2018-01-01 17:00:00", "walletEventName": "Wallet Test", "walletAlias": "test-wallet-abcd", "userFirstname": "CMA", "userLastname": "", "codeStatus": "140005", "informationStatus": "", "refundAmount": null, "ibanFullname": "ALEX OAK", "DbtrIBAN": "FR763000401544999999999173", "ibanBic": "BNPAFRPP", "ibanTxEndToEndId": "XXXXXXXXX", "ibanTxId": "180799999990292", "forwardUrl": null, "paymentAcceptedUrl": null, "paymentRefusedUrl": null, "paymentWaitingUrl": null, "paymentExceptionUrl": null, "paymentCanceledUrl": null, "payinDate": null, "mandateId": null, "creditorName": "WILL OAK", "creditorAddressLine": null, "creditorCountry": null, "creditorIban": "FR761679999999999999011987", "creditorBIC": "TRZOFR21XXX", "virtualIbanId": null, "virtualIbanReference": null, "ibanId": "995d69d1839999999999a6935979ea8220d8" } ] } ``` ::: **Caution – `UserId` initial value in Production** In [Production environment](/guide/api-basics/environments), all SCTR Inst are initially received with `userId` attribute valued to `3`. **It is strictly forbidden to use this value, this is a technical user for Treezor use only**. ## Emitted Instant Credit Transfers (SCTE Inst) An SCTE Inst is a variant of an SCTE, that makes funds available for the beneficiary within about 10 seconds of its emission. Therefore, contrary to the classic SCTE, an SCTE Inst can be sent any day, any time. When an SCTE Inst is emitted, Treezor updates the [Balance authorizations](/guide/overview/glossary#balance) accordingly (`balance.update` webhook) while making a series of checks to determine if the beneficiary account is eligible to instant payout. Then: * The payout is created ([`payout.create`](events#payout-create-2)) with a temporary `PENDING` status. * Once the payout confirmed, Treezor sends a series of webhooks ([`payout.update`](events#payout-update-1), `balance.update`, [`transaction.create`](events#transaction-create-3)) while the account is debited. ::: details Accepted SCTE Inst webhooks diagram ```mermaid sequenceDiagram autonumber participant app as You participant trz as Treezor app->>trz: Create an instant payout trz->>app: balance.update webhook (blocks) trz->>app: payout.create webhook (PENDING) trz->>app: payout.update webhook (VALIDATED) trz->>app: balance.update webhook (unblocks the funds) trz->>app: transaction.create webhook trz->>app: balance.updated webhook (debited funds) ``` ::: Please bear in mind that Treezor cannot guarantee you will receive the webhooks in the relevant order. See the [Race conditions](/guide/webhooks/race-conditions) article for more information. You may request a Recall for the SCTE Inst. For more information, please refer to the [Emitting SCTE Inst Recalls](/guide/transfers/sepa-recalls#emitting-scte-inst-recalls) article. **Information – SCTE Inst can't be canceled** The [`/v1/payouts/{payoutId}`](/api-reference/api-endpoints.html#tag/Payouts/deletePayout){target="\_self"} endpoint is not available for SCTE Inst. ### The SCTE Inst Payout object ::: code-group ```json [JSON] { "payouts":[ { "payoutId":"2dbb81b2-6db9-4db3-b530-988b4189xxx7", "payoutTag":"", "payoutStatus":"VALIDATED", "payoutTypeId":3, "payoutType":"Instant Credit Transfer", "walletId":1902786, "payoutDate":"2024-03-05 17:01:43", "walletEventName":"Main Account", "walletAlias":"mainaccount-65e741xxx62e6", "userFirstname":"Alex", "userLastname":"Oak", "userId":100026123, "beneficiaryId":321123, "uniqueMandateReference":"", "bankaccountIBAN":"FR76174180000100001234567", "label":"", "amount":"10.00", "currency":"EUR", "partnerFee":"0", "createdDate":"2024-03-05 17:01:43", "modifiedDate":"", "virtualIbanId":null, "virtualIbanReference":null, "codeStatus":"160001", "informationStatus":"VALIDATED", "supportingFileLink":"", "endToEndId":"2dbb81b26db94db3b530988b418xxxd7", "reasonCode":null, "reasonDescription":null, "metadata":null, "totalRows":null } ] } ``` ::: Please note the payout object doesn't contain the beneficiary IBAN, you need to fetch the Beneficiary object using the `beneficiaryId` instead. ### Parameters Below are the main attributes to create a SEPA Credit Transfer Payout. | Attribute | Type | Description | | --- | --- | --- | | `payoutTypeId` | integer | Value must be `3` for Instant Payment. | | `walletId` | integer | The unique identifier of the debited Wallet. | | `beneficiaryId` | integer | The unique identifier of the Beneficiary of the Transfer. You must have created the [Beneficiary](./beneficiaries) object beforehand. | | `amount` | number | The amount of the credit transfer. | | `currency` | string | The currency of the credit transfer. Must be `EUR`. | For the transfer to be successful, make sure the information of the User associated to the Beneficiary is accurate: * The name must be at least 2-character long (`firstname` + `lastname` or `legalName`) . * The address must be at least 4-character long (`addressLine{1|2|3}` + `postcode` + `city`) ### Request Use the following request: ::: code-group <<< @/guide/transfers/snippets/create\_payout.bash \[CURL] ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] {4} { "accessTag": "", // max. 250 characters "payoutTag": "", // max. 250 characters "payoutTypeId": 3, "walletId":{walletId}, "beneficiaryId":{beneficiaryId}, "label": "", // max. 140 characters "amount":10.00, // max. amount depends on your implementation and contract "currency":"EUR", "supportingFileLink": "", "endToEndId": "testdu15fevrier12h15" // max. 35 characters } ``` ::: Returns a `VALIDATED` Payout object with the `payoutTypeId` value to `3`. ::: code-group ```json [JSON] {6,7} { "payouts":[ { "payoutId":"2dbb81b2-6db9-4db3-b530-988b4189aad7", "payoutTag":"", "payoutStatus":"VALIDATED", "payoutTypeId":3, "payoutType":"Instant Credit Transfer", "walletId":1902786, "payoutDate":"2024-03-05 17:01:43", "walletEventName":"Main Account", "walletAlias":"mainaccount-65e741b1a62e6", "userFirstname":"Alex", "userLastname":"Oak", "userId":100026123, "beneficiaryId":321123, "uniqueMandateReference":"", "bankaccountIBAN":"FR76174180000100001234567", "label":"", "amount":"10.00", "currency":"EUR", "partnerFee":"0", "createdDate":"2024-03-05 17:01:43", "modifiedDate":"", "virtualIbanId":null, "virtualIbanReference":null, "codeStatus":"160001", "informationStatus":"VALIDATED", "supportingFileLink":"", "endToEndId":"2dbb81b26db94db3b530988b4189aad7", "reasonCode":null, "reasonDescription":null, "metadata":null, "totalRows":null } ] } ``` ::: Treezor also sends a [`payout.create`](events##payout-create-2) webhook. You can retrieve an SCTE Inst using the [`/v1/payouts/{payoutId}`](/api-reference/api-endpoints.html#tag/Payouts/getPayout){target="\_self"} request. **Tip – See `reasonCode` and `reasonDescription` for rejection information** You can refer to the list of reason codes in the [corresponding section](/guide/transfers/error-codes#sct-reason-codes). As opposed to regular SCT, the SCTE Inst can't have R-trans of type "Return". --- --- url: /guide/transfers/sepa-recalls.md description: >- Technical guide for requesting and handling SEPA R Transactions (recalls and RROs). Includes required parameters, request structure, and response examples. --- # SEPA Recalls & RROs In some situations (technical errors, fraud, human errors, etc.) the originator of a [SEPA Credit Transfer (SCT)](/guide/overview/glossary#sepa-credit-transfer-sct) can ask to reverse the transfer. Requests have different names depending on the requesting entity: * **RROs** (initiated by the end user) – Must be requested [**within 13 months**](/guide/overview/glossary#sepa-open-banking-days) after the [SCT](/guide/transfers/credit-transfer). * **Recalls** (initiated by the banking institution) – Must be requested [**within 10 open banking days**](/guide/overview/glossary#sepa-open-banking-days) after the [SCT](/guide/transfers/credit-transfer) (or 13 months in case of [`FRAD`](#types-of-recalls-reasoncode)). Treezor allows you to: * **Receive** recalls when you unduly received funds. * **Emit** recalls when you unduly sent funds. ### Types of Recalls (`reasonCode`) When receiving or emitting a Recall, it can be any of the following types. | `reasonCode` | For | Description | Reception delay | | :---: | --- | --- | --- | | `DUPL` | Recalls | Duplicate payment | 10 days | | `TECH` | Recalls | Technical problem | 10 days |  | `FRAD` | Recalls | Fraudulent origin (these don't send webhooks, only Treezor analyzes them) |  13 months | | `CUST` | RROs | Customer's reason | 13 months | | `AM09` | RROs | Wrong amount | 13 months | | `AC03` | RROs | Invalid creditor account number | 13 months | Once the delay for reception passed, recalls and RROs are automatically rejected. ### Types of Recall Rejection (`negativeResponseReasonCode`) When rejecting a Recall, the reason may be any of the following. | `negativeResponseReasonCode` | Description | | :---: | --- | | `NOOR` | The associated transaction (SCTR/SCTR Inst) was **not received** | | `ARDT` | The associated transaction has **already been returned** | | `AC04` | The associated **account is closed** |   | `NOAS` | The beneficiary **didn't answer** (neither accepted nor declined) | | `CUST` | The beneficiary **rejected the recall** | | `AM04` | The beneficiary has **insufficient funds** | | `LEGL` | Legal decision (regulatory rules) | **Information – Beneficiary obligation to return the funds** Article 1376 of the French Civil Code states that in case of an error, the beneficiary is obligated to return the funds (i.e., [accept the recall request](#accept-a-recall)). If the beneficiary [rejects the Recall](#reject-a-recall), they engage their own legal responsibility. ## Receiving SCTR Recalls SCTR Recalls are first analyzed by Treezor upon reception, to decide whether it is legitimate or not. Treezor may: * Reject the recall directly (e.g., the account is closed). * Handle the decision-making process for recalls of type `FRAD`, `TECH`, and `DUPL`. * Pass on the decision-making to you for recalls of type `CUST`, `AM09`, and `AC03`. If an SCTR recall is passed on to you, then the following occurs: 1. **Treezor informs you** of the Recall request sending a [`recallR.need_response`](events#recallr-need-response) webhook. 2. **Treezor blocks immediately** the funds on the involved Wallet and sends a [`payinrefund.create`](events#payinrefund-create-1) webhook. 3. **You decide** if you want to accept or reject the recall (within 15 working days). To do so, use the [dedicated request](#responding-to-an-sctr-recall) after receiving the [`recallR.need_response`](events#recallr-need-response) webhook. **Tip – A `statusId` of `1` or `3` indicates that you haven't responded** The [`statusId`](#status-statusid) is available in the [`recallR.need_response`](events#recallr-need-response) webhook or in the SCTR Recall object. ### Status (`statusId`) | | `statusId` | Status | Notes | | :---: | :---: | --- | --- | | | `1` | `PENDING` | Pending analysis by you (or by Treezor for recalls of type `FRAD`, `TECH`, and `DUPL`) | | | `2` | `PENDING_PAYIN_REFUND_CREATED` | For simulation purposes. | | | `3` | `PENDING_ANSWER_REQUESTED` | Treezor is awaiting an answer. | | | `7` | `IN_ERROR` | | | | `6` | `CANCELED` | | | | `5` | `REJECTED` | | | | `4` | `ACCEPTED` | | **Caution – When receiving `FRAD`, `TECH`, and `DUPL` recalls** * You **can't respond** to these recalls. Only Treezor is accountable (unless for ). * You **must not** inform the end users of the reception of `FRAD` recalls. ### The SCTR Recall object The structure of an SCTR Recall is as follows. While the `recallR.need_response` webhooks only contain a subset of the following attributes, you may retrieve the Recall object by using the [`/recallRs/{recallId}`](/api-reference/api-endpoints.html#tag/Recalls/getRecallR){target="\_self"} endpoint. ::: code-group ```json [JSON] { "id": 10, "recallRSepaMessageId": 351170, "cxlId": "401", "txId": "401", // transaction id of the initial SCT. "statusId": 3, "statusLabel": "PENDING ANSWER REQUESTED", "reasonCode": "TECH", // see available reasons list above "additionalInformation": "", "clientId": 878950, "clientName": "trois_soc", "userId": 1321404, "userTypeId": 1, "userName": "Alex Oak", "userStatusId": 9, "walletId": 714744, // related wallet id "walletStatusId": 5, "walletActivationDate": "2020-10-30 00:00:00", "walletDesactivationDate": null, "sctrId": 401, // related SCTR id "sctrTxId": 0, "sctrAmount": "1451.00", // related SCTR amount "sctrSettlementDate": "2020-12-30 00:00:00", "sctrDbtrIBAN": "FR7612548029981234567123456", "sctrDbtrBIC": "AXABFRPP", "sctrDbtrName": "Test name debitor", "responseSepaMessageId": 0, "receivedDate": null, "payinId": 0, "payinRefundId": 3566, // related Payin created to block the Authorized Balance "responseType": false, "negativeResponseReasonCode": "", "negativeResponseAdditionalInformation": "", "responseComment": "", "boResponse": false, "frozenWalletFollowingRecallR": false, "automaticResponse": "", "comment": "", "fraudConfirmed": false, // is set to true if Treezor confirms a case of fraud "partialRefund": false, // is set to true if the refunds was done outside of the Recall protocol "inError": false, "createdDate": "2020-12-30 15:01:12", "updatedDate": "2020-12-30 15:01:12" } ``` ::: ### Responding to an SCTR Recall Your response must be sent to the dedicated [`/v1/recallRs/{recallId}/response`](/api-reference/api-endpoints.html#tag/Recalls/putRecallSctInst){target="\_self"} endpoint. ### Accept a Recall Here is a payload example to accept a recall. ::: code-group ```json [JSON] { "responseType": 1, // mandatory, 1 for accepted "negativeResponseAdditionalInformation": "",// must be kept empty "negativeResponseReasonCode": "", // must be kept empty "responseComment": "" // optional } ``` ::: Treezor sends a [`payinrefund.update`](events#payinrefund-update-1) with a `VALIDATED` status after receiving your acceptance of the SCTR Recall. This webhook indicates that the blocked funds will be debited. ### Reject a Recall Here is a payload example to reject a recall. ::: code-group ```json [JSON] { "responseType": 0, // mandatory, 0 for declined "negativeResponseAdditionalInformation": "",// optional "negativeResponseReasonCode": "", // mandatory, see "Types of Recall Rejection (negativeResponseReasonCode)" at the top of this page "responseComment": "" // optional } ``` ::: Treezor sends a [`payinrefund.update`](events#payinrefund-update-1) with a status `CANCELED` and the [Authorized Balance](/guide/overview/glossary#balance) is freed up. You may encounter the following errors while answering to a Recall: * `115000` – This recall request does not exist * `115001` – Unable to answer because status is not `PENDING` nor `ANSWER REQUESTED` * `74001` – Input validation failed. The Recall does not belong to you ### Processing flow Here is a diagram for an SCTR Recall processing. ```mermaid flowchart TD A("Reception of an SCTR Recall") B("Treezor assesses the Recall") C("Treezor sends a `recallr.need_response` webhook") D("Treezor sends a `payinrefund.create` webhook") F("You assess the Recall") I("You PUT your refusal decision
using `responseType=0`") J("You PUT your approval decision
using `responseType=1`") K("Treezor sends a `payinrefund.update` webhook
with `payinStatus=VALIDATED`") L("Treezor sends you a `payinrefund.cancel` webhook
with `payinStatus=CANCELED`") G("Recall rejected by Treezor") A --> B -- Accepted --> C --> D --> F B -- Rejected --> G F -- Rejected --> I F -- Accepted --> J J --> K I --> L class A dark; class B neutral; class F neutral; ``` ## Receiving SCTR Inst Recalls When a Recall regarding an [SCTR Inst](/guide/transfers/credit-transfer-inst) is received, Treezor sends: * A [`separecallsctrinst.reception`](events#separecallsctrinst-reception) webhook. * A [`payinrefund.create`](events#payinrefund-create-2) webhook with a `PENDING` status, hence blocking the funds on the involved Wallet. If the recall reason allows you to answer, you have 15 working days to accept or reject the recall. If you don't answer within 15 days, Treezor sends a negative answer on your behalf, and you receive a [`payinrefund.cancel`](events#payinefund-cancel) webhook with a `REJECTED` status. **Information – Treezor rejects duplicates** When receiving several recall requests for the same SCT Inst, the duplicates are rejected (negative response and the `CUST` reason code). Treezor still sends you the [`separecallsctrinst.reception`](events#separecallsctrinst-reception) webhook. ### Status (`statusLabel`) | | `statusLabel` | Description | | :---: | --- | --- | | | `PENDING` | **Received** recall, it is being analyzed by you (or by Treezor for recalls of type `FRAD`, `TECH`, and `DUPL`) | | | `PENDING_REJECTED_WAITING_ACK` | **Rejected** recall, waiting for interbanking system confirmation | | | `PENDING_ACCEPTED_WAITING_ACK` | **Accepted** recall, waiting for interbanking system confirmation | | | `REJECTED` | **Rejected** recall (final state) | | | `ACCEPTED` | **Accepted** recall (final state) | **Caution – When receiving `FRAD`, `TECH`, and `DUPL` recalls, you:** * **Can't respond**, only Treezor is accountable, except for . * **Must not** inform the end users of the reception of `FRAD` recalls. ### The SCTR Inst Recall object The structure of an SCTR Recall is as follows. You may retrieve the Recall object by using the [`/v1/recall-sct-inst/{sctInstId}/{recallId}`](/api-reference/api-endpoints.html#tag/Recalls/getRecallR){target="\_self"} endpoint. ::: code-group ```json [JSON] { "recallId": "string", // uuid "creationDateTime": "string", "statusLabel": "PENDING", "cxlId": "string", "reasonCode": "CUST", "additionalInformation": "", "sctrDbtrIBAN": "string", "sctrDbtrBIC": "string", "sctrDbtrName": "string", "sctrDbtrAddress": "string", "sctrDbtrCountry": "string", "sctrCdtrIBAN": "string", "sctrCdtrBIC": "srting", "sctrCdtrName": "string", "sctrCdtrAddress": "string", "sctrCdtrCountry": "FR", "sctrMsgId": "string", "sctrInstrId": "string", "sctrTxId": "string", "sctrE2EID": "string", "sctrAmount": "string", "sctrSettlementDate": "string", "sctrRemittanceInformation": "string", "sctrTrzId": "string", "sctrExternalId": "string", "clientId": 0, "userId": 0, "walletId": 0, "receivedDate": "string", "payinRefundId": 0, "payinRefundUid": "string", "responseType": -1, "negativeResponseReasonCode": "string", "negativeResponseAdditionalInformation": "string", "responseComment": "string", "automaticResponse": "string", "createdDate": "string", "updatedDate": "string" } ``` ::: ### Responding to an SCTR Inst Recall Your response must be sent to the dedicated [`/v1/recall-sct-inst/{sctinstId}/{recallId}/response`](/api-reference/api-endpoints.html#tag/Recalls/putRecallSctInst){target="\_self"} endpoint within 15 working days, to which Treezor answers with an HTTP Status Code `201`. ### Accept a Recall Here is an example of payload to accept a recall. ::: code-group ```json [JSON] { "responseType": 1, // mandatory, 1 for accepted "negativeResponseAdditionalInformation": "",// must be kept empty "negativeResponseReasonCode": "", // must be kept empty } ``` ::: Treezor sends a [`payinrefund.update`](events#payinrefund-update-2) webhook with an `ACCEPTED` status and the Wallet is debited a few seconds later. ### Reject a Recall Here is an example of payload to reject a recall. ::: code-group ```json [JSON] { "responseType": 0, // mandatory, 0 for declined "negativeResponseAdditionalInformation": "",// mandatory, optional or not expected depending on the situation, see details below "negativeResponseReasonCode": "", // mandatory, see "Types of Recall Rejection (negativeResponseReasonCode)" at the top of this page } ``` ::: The `negativeResponseAdditionalInformation` attribute is limited to 202 alphanumeric characters and is: * **Mandatory** when the recall `reasonCode` was `FRAD` or `DUPL` or `TECH` and `negativeResponseReasonCode` is `LEGL` * **Optional** when * The recall `reasonCode` was `FRAD` and `negativeResponseReasonCode` is **not** `LEGL` or * The recall `reasonCode` was `AC03` * **Not expected** (must be left empty) in any other situations. Treezor sends a [`payinrefund.cancel`](events#payinefund-cancel-1) with a status `REJECTED` and the [Authorized Balance](/guide/overview/glossary#balance) is freed up. ### Processing flow Here is a diagram for an SCTR Inst Recall processing. ```mermaid flowchart TD A("Reception of an SCTR Inst Recall") B("Treezor assesses the Recall") C("Treezor sends a `separecallsctrinst.reception` webhook
with a `statusLabel=PENDING`") D("Treezor sends a `payinrefund.create` webhook") E("Treezor sends a `separecallsctrinst.reception` webhook
with a `statusLabel=REJECTED`") F("You assess the Recall") G("You PUT your refusal decision
using `responseType=0`") H("You PUT your approval decision
using `responseType=1`") I("Treezor sends a `payinrefund.cancel` webhook
with a `payinStatus=REJECTED`") J("Treezor sends a `payinrefund.update` webhook
with a `payinStatus=ACCEPTED`") class A dark; class B neutral; class F neutral; A --> B -- Accepted --> C --> D --> F B -- Rejected --> E F -- Rejected --> G F -- Accepted --> H G --> I H --> J ``` ## Emitting SCTE Recalls When requesting a recall, you are not guaranteed to receive the funds back. The decision regarding the recall request is up to the corresponding bank and depends on various factors, including funds availability and compliance with delays. * You have up to [10 open banking days](/guide/overview/glossary#sepa-open-banking-days) for `TECH` or `DUPL` recalls and 13 months for RRO and `FRAD` recalls. * The corresponding bank has up to [15 open banking days](/guide/overview/glossary#sepa-open-banking-days) from the reception of your recall request to respond. ### Process to recall an SCTE * You [open a ticket](https://treezor.zendesk.com/hc/en-us/articles/4403978479634-How-to-create-a-Zendesk-ticket) containing the details of the SCTE and the [appropriate recall reason](/guide/transfers/sepa-recalls#types-of-recalls-reasoncode). * Treezor initiates the request on the interbanking system and sends you a [`payoutrefund.create`](events#payoutrefund-create-1) webhook. * Treezor receives the response from the corresponding bank: * If it is **accepted**, Treezor credits the Wallet with the recalled amount and sends you: * A [`payoutrefund.update`](events#payoutrefund-update-1) webhook with the status `VALIDATED`. * A `transaction.create` webhook. * A [`balance.update`](/guide/wallets/events#balance-update) webhook. * If it is **declined**, Treezor sends a [`payoutrefund.cancel`](events#payoutrefund-cancel) webhook. ### Processing flow Here is a diagram for an SCTE Recall processing. ```mermaid flowchart TD A("You open a ticket for a Recall") B("Treezor makes a request the corresponding bank") C("Treezor receives the response") D("Treezor sends a `payoutrefund.update` webhook
with `informationStatus=VALIDATED`") E("Treezor sends a `transaction.create` webhook") F("Treezor sends a `balance.update` webhook") G("Treezor sends a `payoutrefund.cancel` webhook") H("Treezor sends a `payoutrefund.create` webhook") A --> B --> C D --> E --> F B --> H C -- Rejected --> G C -- Accepted --> D class A dark; class B neutral; class C neutral; ``` ## Emitting SCTE Inst Recalls When requesting a recall, you are not guaranteed to receive the funds back. The decision regarding the recall request is up to the corresponding bank and depends on various factors, including funds availability and compliance with delays. You can directly request for SCTE Inst recalls for all [reasons](/guide/transfers/sepa-recalls#types-of-recalls-reasoncode), using the [`/v1/payoutRefund`](/api-reference/api-endpoints.html#tag/Payout%20Refunds/postPayoutRefund){target="\_self"} endpoint. Delays to abide by are the same as for SCTE Recalls: * You have up to [10 open banking days](/guide/overview/glossary#sepa-open-banking-days) for `TECH` or `DUPL` recalls and 13 months for RRO and `FRAD` recalls. * The corresponding bank has up to [15 open banking days](/guide/overview/glossary#sepa-open-banking-days) from the reception of your recall request to respond. ### Create a Recall Recalls for SCTE Inst payouts are created with the payoutRefunds request. #### Parameters Below some of the key attributes for SCTE. | Attribute | Type | Description | | --- | --- | --- | | `payoutId` | string | The unique identifier of the payout (SCTE Inst) for which the recall is to be made. | | `reasonCode` | string | The [reasons](/guide/transfers/sepa-recalls#types-of-recalls-reasoncode) of the Recall. | | `requestAmount` | number | The amount of the recall request. Defaults to the initial payout amount. | | `requestCurrency` | number | The currency of the recall request. Defaults to the initial payout currency. | #### Request example ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/v1/payoutRefunds' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "payoutId": "bf9367cb-22be-4a86-ad68-8f30fxxxx15", "accessTag": "test {{timestampMs}}", // max. 250 characters "payoutRefundTag": "test", // max. 250 characters "requestAmount": 1000.10, "requestCurrency": "EUR", "reasonCode": "DUPL" } ``` ::: Returns a payoutRefund object. ::: code-group ```json [JSON] { "payoutRefunds": [ { "id": "f0eb0186-1592-4fb8-84a1-a65db6901234", "payoutRefundTag": "test", "codeStatus": "790001", "informationStatus": "PENDING", "payoutId": "bf9367cb-22be-4a86-ad68-8f30fxxxx15", "requestAmount": 1000.1, "requestCurrency": "EUR", "requestComment": "", "reasonCode": "DUPL", "refundAmount": 1000.1, "refundCurrency": "EUR", "refundDate": "", "refundComment": "", "negativeResponseReasonCode": "", "createdDate": "2024-03-14 17:09:19", "modifiedDate": "" } ] } ``` ::: Treezor also sends a [`payoutRefund.create`](events#payoutrefund-create-2) webhook with a `payoutStatus` attribute set to `PENDING`. You can retrieve a SCTE Inst Recall by suing the [`/v1/payoutRefunds/{payoutRefundId}`](/api-reference/api-endpoints.html#tag/Payout%20Refunds/getPayoutRefund){target="\_self"} endpoint. ### Processing flow Here is a diagram for an SCTE Inst Recall processing. ```mermaid flowchart TD A("You create an SCTE Inst Recall") B("The corresponding bank receives the request") C("Treezor receives the response") D("Treezor sends a `payoutrefund.update` webhook
with `informationStatus=VALIDATED`") E("Treezor sends a `transaction.create` webhook") F("Treezor sends a `balance.update` webhook") G("Treezor sends a `payoutrefund.cancel` webhook") H("Treezor sends a `payoutrefund.create` webhook") A --> B --> C D --> E --> F B --> H C -- Rejected --> G C -- Accepted --> D class A dark; class B neutral; class C neutral; ``` ## Endpoints | Endpoint |[Scope](/guide/api-basics/authentication#available-scopes) | | --- | --- | | [`/v1/recallR`](/api-reference/api-endpoints.html#tag/Recalls/getRecalls){target="\_self"} Search for SCT Recalls | `read_only` | | [`/v1/recallRs/{recallRId}`](/api-reference/api-endpoints.html#tag/Recalls/getRecallR){target="\_self"} Retrieve an SCT Recall or RRO by its `id` | `read_only` | | [`/v1/recallRs/{recallRId}/response/`](/api-reference/api-endpoints.html#tag/Recalls/putRecallR){target="\_self"} Provide your decision following an SCT Recall request | `read_write` | | [`/v1/recall-sct-inst/{sctInstId}/{recallId}`](/api-reference/api-endpoints.html#tag/Recalls/getRecallSctInst){target="\_self"} Retrieve an SCT Inst Recall | | | [`/v1/recall-sct-inst/{sctinstId}/{recallId}/response`](/api-reference/api-endpoints.html#tag/Recalls/putRecallSctInst){target="\_self"} Provide your decision following an SCT Inst Recall | | | [`/v1/payinrefunds/{recallId}`](/api-reference/api-endpoints.html#/) Retrieve a payinrefund following a Recall | | | [`/v1/payoutRefund`](/api-reference/api-endpoints.html#tag/Payout%20Refunds/postPayoutRefund){target="\_self"} Create a Recall (SCTE Inst only) | `read_write` | | [`/v1/payoutRefund/{payoutRefundId}`](/api-reference/api-endpoints.html#tag/Payout%20Refunds/getPayoutRefund){target="\_self"} Create a Recall (SCTE Inst only) | `read_only` | | [`/simulation/sct-inst/payin`](/api-reference/api-endpoints.html#tag/Simulation/simulateSctInstReception){target="\_self"} Emulate an SCTR, to test the procedure | | | [`/simulation/sct-inst/recall`](/api-reference/api-endpoints.html#tag/Simulation/simulateSctInstRecall){target="\_self"} Emulate a reception of a SCTR inst recall, to test the procedure | | | [`/simulation/recall-r`](/api-reference/api-endpoints.html#tag/Recalls/simulateSctInstRecall){target="\_self"} Emulate a Recallr, to test the procedure | | --- --- url: /guide/strong-customer-authentication/faking-operations.md description: Technical guide for generating an SCA Proof to test the SCA flow in Sandbox. --- # Emulation Emulation features are only available in `Sandbox` [environment](/guide/api-basics/environments). ## Simulate SCA Proof The [`/simulation/scaProof`](/api-reference/api-endpoints.html#tag/SCA%20Proof%20Simulation/postScaProof){target="\_self"} endpoint allows you to simulate an SCA proof. ### Parameters | Attribute | Type | Description | | --- | --- | --- | | `scaWalletId` | string | The unique identifier of the SCA Wallet from which the `scaProof` is to be created. | | `url` | string | The URL of the endpoint for which the sensitive action is to be secured with strong customer authentication. | | `body` | string | Data to sign in the SCA proof body. See the [Per Operation](securing-endpoints#per-operation) table to know which data to sign for each endpoint. | ### Request In order to generate an SCA Proof in Sandbox, you must use a JWT `accessToken` with a `client_credentials` grant type and the `admin` scope. See the [SCA Authentication](authenticating) article for more information. ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/simulation/scaProof' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' ``` ::: Here is a `{payload}` example: ::: code-group ```json [JSON] { "scaWalletId": "string", // required "url": "string", // optional "body": {"string"} // optional } ``` ::: Returns the SCA proof. ::: code-group ```json [JSON] { "scaProof": "string" } ``` ::: ### Worked example Let's take an example where you want to test in Sandbox the creation of a new Beneficiary, an action which requires strong customer authentication. The steps are the following: 1. [Use the simulator as the App](#_1-use-the-simulator-as-the-app) 2. [Simulate an SCA proof as the App](#_2-simulate-an-sca-proof-as-the-app) 3. [Authenticate as end user](#_3-authenticate-as-end-user) 4. [Simulate SCA Proof as App](#_4-simulate-sca-proof-as-app) 5. [Create the beneficiary as end user](#_5-create-the-beneficiary-as-end-user) **Prerequisites** A User must be already created, with an active [SCA Wallet](introduction#sca-wallet-object). #### 1. Use the simulator as the App Authenticate as the application to use the simulator. Here is the authentication request: ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/oauth/token' \ --form 'grant_type="client_credentials"' \ --form 'client_id="{clientId}"' \ --form 'client_secret="{clientSecret}"' \ --form 'scope="admin"' ``` ::: Returns the Bearer token: ::: code-group ```json [JSON] { "token_type": "Bearer", "expires_in": 3600, "access_token": "eyJ0_XXX_DSnw" } ``` ::: #### 2. Simulate an SCA proof as the App Use the simulator to create an SCA proof that you'll be able to use to authenticate as the end user in the next step. ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/simulation/scaProof' \ --header 'Authorization: Bearer eyJ0_XXX_DSnw' \ --header 'Content-Type: application/json' \ --data '{payload}' ``` ::: With the user's `scaWalletId` in the `{payload}`: ::: code-group ```json [JSON] { "scaWalletId": "e59b5fadd69f4d2693a60492b0334464" } ``` ::: Returns the SCA Proof: ::: code-group ```json [JSON] { "scaProof": "eyJh_NDN9.WQBp_Xg7w" } ``` ::: #### 3. Authenticate as end user Authenticate as the end user to create the beneficiary. Here is the authentication request: ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/oauth/token' \ --form 'grant_type="delegated_end_user"' \ --form 'client_id="{clientId}"' \ --form 'client_secret="{clientSecret}"' \ --form 'scope="read_write"' \ --form 'username="101109094"' \ --form 'password="bc6ead2bbcd9cc409ba53d9cfbf145a667647414eae496xxxx75636b15384a8"' \ --form 'sca="eyJh_NDN9.WQBp_Xg7w"' ``` ::: Returns the Bearer token: ::: code-group ```json [JSON] { "token_type": "Bearer", "expires_in": 3600, "access_token": "eyJ0_XXX_q44Q" } ``` ::: #### 4. Simulate SCA Proof as App ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/simulation/scaProof' \ --header 'Authorization: Bearer eyJ0_XXX_DSnw' \ --header 'Content-Type: application/json' \ --data '{payload}' ``` ::: With the following `{payload}` which contains the data to sign: ::: code-group ```json [JSON] { "scaWalletId": "e59b5fadd69f4d2693a60492b0334464", "url": "https://yourcompanyname.sandbox.treezor.co/v1/beneficiaries", "body": { "userId": "101109094", "name": "Alex Oak", "adress": "33 av de Wagram Paris", "iban": "FR1130003000305928344XXXXX", "bic": "SOGEFRPPXXX", "usableForSct": true } } ``` ::: Returns the SCA Proof: ::: code-group ```json [JSON] { "scaProof": "eyJh_UxfQ.nNIH_n9kA" } ``` ::: #### 5. Create the beneficiary as end user ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/v1/beneficiaries' \ --header 'Authorization: Bearer eyJ0_XXX_q44Q' \ --header 'Content-Type: application/json'\ --data '{payload}' ``` ::: With the following `{payload}`: ::: code-group ```json [JSON] { "userId": "101109094", "name": "Alex Oak", "adress": "33 av de Wagram Paris", "iban": "FR1130003000305928344XXXXX", "bic": "SOGEFRPPXXX", "usableForSct": true, "sca":"eyJh_UxfQ.nNIH_n9kA" } ``` ::: Returns the Beneficiary object: ::: code-group ```json [JSON] { "beneficiaries": [ { "id": 527977, "tag": "", "userId": 101109094, "nickName": "", "name": "Alex Oak", "address": "", "iban": "3537524356444355504255444055564B574C405157455041XXXX", "bic": "SOGEFRPPXXX", "sepaCreditorIdentifier": "", "sddB2bWhitelist": [], "sddCoreBlacklist": [], "usableForSct": true, "sddCoreKnownUniqueMandateReference": [], "isActive": true, "createdDate": "2024-11-21 08:05:56", "modifiedDate": "2024-11-21 08:05:56", "metadata": { "iban": "FR1130003000305928344XXXXX" } } ] } ``` ::: --- --- url: /guide/dashboard/templates.md description: >- Customize your templates directly with the Dashboard code editor. Preview the final rendering of your PDF account documents and email templates on the interface. --- # Templates Templates allow you to customize some of the API-generated documents, that you provide to your end users on request. **Reading – Templates are powered by Twig 3.x templating engine** Learn more in the [Templates](/guide/api-basics/templates) article. ## Accessing templates In the *Administration section*, select the *Templating management* section to view the templates. In the drop-down list, the following templates are available: | Template | Type | Description | |--- |--- |--- | | Onboarding confirmation (html) | Email | Customizes the email sent to users to confirm their onboarding. Linked to [Delegated authentication](/guide/api-basics/using-treezor-as-oauth-identity-provider). | | Onboarding confirmation (text) | Email | Customizes the message sent to confirm their onboarding (preferred format if a mobile phone number is provided). Linked to [Delegated authentication](/guide/api-basics/using-treezor-as-oauth-identity-provider). |  | Forgot password (html) | Email | Customizes the email sent to reset their password. Linked to [Delegated authentication](/guide/api-basics/using-treezor-as-oauth-identity-provider). | | Forgot password (text) | Email | Customizes the message sent to users to reset their password (preferred format if a mobile phone number is provided). Linked to [Delegated authentication](/guide/api-basics/using-treezor-as-oauth-identity-provider). | | Wallet details (pdf) | Document | Customizes the [Account details](/guide/wallets/account-documents). This document can be download from the *Wallets* tab, [*Wallets list*](/guide/dashboard/wallets#navigating-the-wallet-s-information) section, when clicking on the "More" button and selecting the "Account details" option. | | Wallet statement (pdf) | Document | Customizes the [Account statement](/guide/wallets/account-documents) document. This document can be download from the *Wallets* tab, [*Wallets list*](/guide/dashboard/wallets#navigating-the-wallet-s-information) section, when clicking on the "More" button and selecting the "Statement" option. | | Proof of payout (pdf) | Document | Customizes the [Proof of payout](/guide/transfers/proof-of-payout) document. | | Wallet closure certificate (pdf) | Document | Customizes the [Closure certificate](/guide/wallets/account-documents) document. | | Wallet balance certificate (pdf) | Document | Customizes the [Balance certificate](/guide/wallets/account-documents) document. | | Wallet domiciliation certificate (pdf) | Document | Customizes the [Domiciliation](/guide/wallets/account-documents) document. | ## Managing templates The Dashboard allows you to: * [Render templates in real-time](#rendering-templates-in-real-time) * [Make the most out of the template variables](#making-the-most-out-of-template-variables) ### Rendering templates in real-time Templates are rendered in real time in the Dashboard while you edit them. You can use the left-hand side of the view to edit, and see the results directly in the right-hand side. Once all your modifications are done, you can click on the "Save Changes" button in the upper right corner of the view. ### Making the most out of template variables A list of available variables is provided for each template. These variables can be used in compliance with [the Twig templating language](/guide/api-basics/templates). To access the variables, click on the "Variables" button located next to the picklist. As a result, a dialog box is prompted, providing information about the variables you can use. --- --- url: /guide/webhooks/testing-in-sandbox.md description: >- Test Treezor API webhooks in your Sandbox environment. This guide provides methods for receiving and processing webhooks during development, including using port forwarding services (Ngrok, RequestCatcher) and manual setup, to validate your integration. --- # Testing webhooks During the [development phase](https://treezor.zendesk.com/hc/en-us/sections/360002673359-Validating-your-implementation) in [Sandbox](/guide/api-basics/environments#sandbox), you need to receive and process webhooks, just like you would in [Production](/guide/api-basics/environments#production). Receiving and processing webhooks is essential to validating that your code will behave as expected once pushed into production. **Security – Development exposure** You should consider the security implications of exposing your development environment to the internet. There are two main ways of achieving this: * [Using a port forwarding service](#using-a-port-forwarding-service) * [Manually setting-up port forwarding](#manually-setting-up-port-forwarding) ## Using a port forwarding service Some commercial services can offer you a customized domain name, and redirect requests sent to this domain, towards your development machine or server, allowing for the reception of webhooks. These have the advantage of **being able to run behind a firewall, and do not require any changes to your router configuration or DNS zone**. **Security – Webhook exposure** You should consider the security implications of having webhooks transit through a third party's infrastructure. Careful reading of their TCU is recommended. ### [NGRok](https://ngrok.com/) Ngrok exposes your development machine or server to the public internet over a secure tunnel, using a locally installed helper program. **Webhooks are forwared to your development machine or server.** * [Download and run a program](https://ngrok.com/download) on your development machine or server and [provide it the port](https://ngrok.com/docs) of your web application (`./ngrok http {portOfYourApplication}`). * The application automatically configures and provides you with a domain name that redirects to your development machine. * Traffic is relayed through to the ngrok process running on your machine and then on to your web application. ### [RequestCatcher](https://requestcatcher.com/) RequestCatcher exposes requests sent to a subdomain directly in your browser. It doesn't require the creation of an account or the installation of a helper program. **Webhooks are visible to you, but are not forwarded to your development machine or server.** * Go to [the webpage](https://requestcatcher.com/) and enter a subdomain of your choice * The webpage automatically updates to display all requests sent to this subdomain ### [Mocklab](https://get.mocklab.io/) Mocklab allows you to graphically program an API (such as accepting POST requests and [answering with `200` HTTP Status Code](./integrity-checks#what-should-my-application-return)), and display any request sent to it in your Mocklab dashboard. **Webhooks are visible to you, but are not forwarded to your development machine or server.** ### Subscribe to webhooks You can follow the [normal subscription procedure](./subscription-management) using the domain name provided by one of these services as the webhook endpoint. The [AWS certificate verifications steps](./subscription-management#manually-check-the-confirmation-request-signature) of the subscription procedure are a nice to have but can be skipped. ## Manually setting up port forwarding This is a manual process, whereby, somebody with access to your router configuration, exposes your development machine or server to internet, allowing for the reception of webhooks. **Prerequisites – To manually set up port forwarding** * Your internet link must have a [static IP](https://en.wikipedia.org/wiki/IP_address) address (often provided with pro-grade links). If you don't have a static IP, you may resort to a [Dynamic DNS](https://en.wikipedia.org/wiki/Dynamic_DNS) service such as [No-IP](https://www.noip.com/). * You must have administrator access to your router * You must have access to your domain's DNS zone ### Configure a domain name #### Using your own domain (static IP)  You need to connect to your domain name customer interface, go to the DNS zone, and add an `A` type entry (such as `sandbox.{my-domain-name.io} => 12.345.6.789`), pointing to your internet access' IP. Your domain name provider likely has a detailed documentation regarding this step. #### Using a Dynamic DNS service (dynamic IP) If you use a Dynamic DNS service, you need to connect to your Dynamic DNS customer interface, where you will be asked to choose or customize a domain name. The second step is to install a helper program on your development machine or server. This program will notify the Dynamic DNS service of any IP address change. The Dynamic DNS service will then automatically update the DNS zone to point the domain to your new IP address. ### Configure port forwarding You need to connect to your router, go to the NAT rules, and add an inbound NAT forwarding rule * from the port `443` * to the port `443` * to the IP of your development machine or server. Your router manufacturer likely has a detailed documentation regarding this step. ### Subscribe to webhooks You can follow the [normal subscription procedure](./subscription-management) using your newly created domain name as the webhook endpoint. The [AWS certificate verifications steps](./subscription-management#manually-check-the-confirmation-request-signature) of the subscription procedure are a nice to have but can be skipped. --- --- url: /guide/transfers/error-codes.md description: >- Troubleshoot and handle transfer-related issues using the Treezor API's complete list of error codes, messages, reason codes and their corresponding meanings. --- # Errors This page lists both common error codes from the Treezor API and the reason codes for SEPA R-transactions as defined by the European Payment Council. **Caution – Only the legacy API sends the error code in HTTP errors** When handling errors with Connect, only the `message` attribute is returned. ## SCT reason codes Find below the list of reason codes to handle SCT R-transactions (i.e., rejects, returns, and recalls). This list is regularly updated on the [EPC website](https://www.europeanpaymentscouncil.eu/document-library/clarification-paper/guidance-reason-codes-sepa-credit-transfer-r-transactions). | Code | Definition | Reason | |:---: |--- |--- | | `AC01` | Incorrect Account Number | Account identifier invalid or incorrect (i.e., invalid IBAN or account number does not exist) *Type of R-trans: Reject, Return* | | `AC03` | Invalid Creditor Account Number | Wrong unique identifier of the Beneficiary account *Type of R-trans: RFRO* | | `AC04` | Closed Account Number | Account closed *Type of R-trans: Return, Negative answer to a Recall or to a RFRO* | | `AC06` | Blocked Account | Account blocked *Type of R-trans: Return* | | `ACNR` | Accepted Claim No Receipt | Inter-PSP positive response to Claim Non-Receipt *Type of R-trans: Positive answer to SCT Inquiry “Claim Non- Receipt”* | | `ACVA` | Accepted Value Date Adjustment | Inter-PSP positive response to Claim for Value Date Correction *Type of R-trans: Positive answer to SCT Inquiry “Claim for Value Date Correction”* | | `AG01` | Transaction Forbidden | Credit transfer forbidden on this account (e.g., savings account) *Type of R-trans: Return* | | `AG02` | Invalid Bank Operation Code | Operation code/transaction code incorrect, invalid file format *Type of R-trans: Reject, Return* | | `AM04` | Insufficient funds on the account | Insufficient funds on the account *Type of R-trans: Negative answer to a Recall or to a RFRO* | | `AM05` | Duplication | Duplicate payment *Type of R-trans: Reject, Return* | | `AM09` | Wrong amount | Wrong amount *Type of R-trans: RFRO* | | `ARDT` | The Transaction Has Already Been Returned | Already returned transaction *Type of R-trans: Negative answer to a Recall or to a RFRO; Negative answer to SCT Inquiry “Claim Non- Receipt”* | | `ARJT` | Already Rejected Transaction | Already rejected transaction *Type of R-trans: Negative answer to SCT Inquiry “Claim Non- Receipt”* | | `BE04` | Missing Creditor Address | Account address invalid. The address is required if the beneficiary bank is based in a non-EEA SEPA country. *Type of R-trans: Return* | | `CERI` | Check ERI | The credit transfer is not tagged as an Extended Remittance Information (ERI) transaction but contains ERI *Type of R-trans: Reject* | | `CNOR` | Creditor Bank is Not Registered | Beneficiary PSP is not registered under this BIC in the CSM *Type of R-trans: Reject, Return* | | `CUST` | Requested By Customer | a. By request of Customer the Originator without any reason specified. b. Refusal by the Beneficiary *Type of R-trans: a. RFRO. b. Negative answer to a Recall or to a RFRO* | | `CVAA` | Correct value date already applied | Inter-PSP negative response to Claim for Value Date Correction *Type of R-trans: Negative answer to SCT Inquiry “Claim for Value Date Correction”* | | `DNOR` | Debtor bank is not registered | Originator PSP is not registered *Type of R-trans: Reject* | | `DUPL` | Duplicate payment | Duplicate sending *Type of R-trans: Recall* | | `ED05` | Settlement failed | Settlement of the SEPA Credit Transfer failed *Type of R-trans: Reject* | | `ERIN` | ERI Option Not Supported | The Extended Remittance Information (ERI) option is not supported *Type of R-trans: Reject, Return* | | `FF01` | Invalid File Format | Operation/ transaction code incorrect, invalid file format *Type of R-trans: Reject* | | `FOCR` | Following Cancellation Request | Positive answer to the Recall *Type of R-trans: Positive answer to a recall or to a RGRO* | | `FRAD` | Fraudulent Origin | Fraudulent originated credit transfer *Type of R-trans: Recall* | | `LEGL` | Legal Decision | Legal reasons *Type of R-trans: Negative answer to a Recall or to a RFRO* | | `MD07` | End Customer Deceased | Beneficiary deceased *Type of R-trans: Return* | | `MODI` | Modified As Per Request | Inter-PSP confirmed positive response to Claim for Value Date Correction *Type of R-trans: Confirmed positive answer to SCT Inquiry “Claim for Value Date Correction”* | | `MS02` | Not Specified Reason Customer Generated | By order of the Beneficiary *Type of R-trans: Return* | | `MS03` | Not Specified Reason | Reason not specified *Type of R-trans: Reject, Return* | | `NERI` | No ERI | The SEPA Credit Transfer is tagged as an Extended Remittance Information (ERI) transaction but does not contain ERI *Type of R-trans: Reject* | | `NOAS` | No Answer From Customer | No response from Beneficiary *Type of R-trans: Negative answer to a Recall or to a RFRO* | | `NOOR` | No Original Transaction Received | Original Credit Transfer never received *Type of R-trans: Negative answer to a Recall or to a RFRO; Negative answer to SCT Inquiry “Claim Non- Receipt”* | | `RC01` | Bank Identifier Incorrect | PSP identifier incorrect (i.e., invalid BIC) *Type of R-trans: Reject, Return* | | `RJNR` | Rejected Claim Non- Receipt | Inter-PSP negative response to Claim Non-Receipt *Type of R-trans: Negative answer to SCT Inquiry “Claim Non- Receipt”* | | `RJVA` | Rejected Value Date Adjustment | Inter-PSP negative response to Claim for Value Date Correction *Type of R-trans: Negative answer to SCT Inquiry “Claim for Value Date Correction”* | | `RNPR` | Original Transaction Received but not processable | Original Transaction Received but Not Processable *Type of R-trans: Negative answer to SCT Inquiry “Claim Non- Receipt”* | | `RR01` | Missing Debtor Account Or Identification | Regulatory Reason *Type of R-trans: Reject, Return* | | `RR02` | Missing Debtor’s Name Or Address | Regulatory Reason *Type of R-trans: Reject, Return* | | `RR03` | Missing Creditor’s Name Or Address | Regulatory Reason *Type of R-trans: Reject, Return* | | `RR04` | Regulatory Reason | Regulatory Reason *Type of R-trans: Reject, Return; Negative answer to SCT Inquiry “Claim Non- Receipt”* | | `TECH` | Technical Problem | Technical problems Recall. resulting in erroneous SCTs *Type of R-trans: Recall* | | `TM01` | Cut Off Time | File received after Cut-off Time *Type of R-trans: Reject* | ## SCT Inst reason codes Find below the list of reason codes to handle SCT Inst R-transactions (i.e., rejects, returns, and recalls). This list is regularly updated on the [EPC website](https://www.europeanpaymentscouncil.eu/document-library/guidance-documents/guidance-reason-codes-sepa-instant-credit-transfer-r-0). | Code | Definition | Reason | |:---: |--- |--- | | `AB05` | Timeout Creditor Agent | Transaction stopped due to timeout at the Creditor Agent. *Type of R-trans: Reject* | | `AB06` | Timeout Instructed Agent | Transaction stopped due to timeout at the Instructed Agent. *Type of R-trans: Reject* | | `AB07` | Offline Agent | Agent of message is not online. Generic usage if it cannot be determined who exactly is not online. *Type of R-trans: Reject* | | `AB08` | Offline Creditor Agent | Creditor Agent is not online *Type of R-trans: Reject* | | `AB09` | Error Creditor Agent | Transaction stopped due to error at the Creditor Agent *Type of R-trans: Reject* | | `AB10` | Error Instructed Agent | Transaction stopped due to error at the Instructed Agent *Type of R-trans: Reject* | | `AC01` | Incorrect Account Number | Account identifier invalid or incorrect (i.e., invalid IBAN or account number does not exist). *Type of R-trans: Reject* | | `AC03` | Invalid Creditor Account Number | Wrong unique identifier of the Beneficiary account. *Type of R-trans: RFRO* | | `AC04` | Closed Account Number | Account closed. *Type of R-trans: Reject, Negative answer to a Recall or to a RFRO* | | `AC06` | Blocked account | Account blocked *Type of R-trans: Reject* | | `AG01` | Trnsaction Forbidden | Credit transfer forbidden on this account. *Type of R-trans: Reject* | | `AG02` | Invalid Bank Operation Code | Operation code/transaction code incorrect, invalid file format *Type of R-trans: Reject* | | `AG09` | Payment Not Received | Original payment never received *Type of R-trans: Reject* | | `AG10` | Agent Suspended | Agent of message is suspended from the Real Time Payment system. *Type of R-trans: Reject* | | `AG11` | Creditor Agent Suspended | Creditor Agent of message is suspended from the Real Time Payment system. *Type of R-trans: Reject* | | `AM02` | Not Allowed Amount | Amount exceeds the maximum authorized amount for SCT Inst. *Type of R-trans: Reject* | | `AM04` | Insufficient Funds | Insufficient funds on the account. *Type of R-trans: Negative answer to a Recall or to a RFRO.* | | `AM05` | Duplication | Duplicate payment. *Type of R-trans: Reject* | | `AM09` | Wrong Amount | Wrong amount. *Type of R-trans: RFRO* | | `AM23` | Aount Exceeds Settlement Limit | Transaction amount exceeds settlement limit. *Type of R-trans: Reject* | | `ARDT` | The Transaction Has Already Been Returned | Already returned transaction. *Type of R-trans: Negative answer to a Recall or to a RFRO.* | | `BE04` | Missing Creditor Address | Account address invalid. The address is required if the beneficiary bank is based in a non-EEA SEPA country. *Type of R-trans: Reject* | | `CNOR` | Creditor Bank Is Not Registered. | Beneficiary PSP is not registered under this BIC in the CSM. *Type of R-trans: Reject* | | `CUST` | Request By Customer | a. By request of Customer the Originator without any reason specified. b. Refusal by the Beneficiary *Type of R-trans: a. RFRO. b. Negative answer to a Recall or to a RFRO* | | `DNOR` | Debtor Bank Is Not Registered | Originator PSP is not registered under this BIC in the CSM. *Type of R-trans: Reject* | | `DUPL` | Duplicate Payment | Duplicate Sending *Type of R-trans: Recall* | | `FF01` | Invalid File Format | Operation/ transaction code incorrect, invalid file format. *Type of R-trans: Reject* | | `FOCR` | Following Cancellation Request | Positive answer to the Recall. *Type of R-trans: Positive answer to a Recall or to a RFRO* | | `FRAD` | Fraudulent Origin | *Type of R-trans: Recall* | | `LEGL` | Legal Decision | Legal reasons. *Type of R-trans: Negative answer to a Recall or to a RFRO* | | `MD07` | End Customer Deceased | Beneficiary deceased. *Type of R-trans: Reject* | | `MS02` | Not Specified Reason Customer Generated | By order of the Beneficiary. *Type of R-trans: Reject* | | `MS03` | Not Specificed Reason Agent Generated | Reason not specified. *Type of R-trans: Reject* | | `NOAS` | No Answer From Customer | No response from Beneficiary. *Type of R-trans: Negative answer to a Recall or to RFRO* | | `NOOR` | No Original Transaction Received | Original SEPA Instant Credit Transfer never received. *Type of R-trans: Negative answer to a Recall or to RFRO* | | `RC01` | Bank Identifier Incorrect | PSP identifier incorrect (i.e., invalid BIC). *Type of R-trans: Reject* | | `RR01` | Missing Debtor Account Or Identification | Regulatory Reason. *Type of R-trans: Reject* | | `RR02` | Missing Debtor's Name Or Address | Regulatory Reason. *Type of R-trans: Reject* | | `RR03` | Missing Creditor's Name Or Address | Regulatory Reason. *Type of R-trans: Reject* | | `RR04` | Regulatory Reason | Regulatory Reason. *Type of R-trans: Reject* | | `TECH` | Technical Problem | Technical problems resulting in erroneous SCT Inst transactions *Type of R-trans: Recall* | | `TM01` | Invalid Cut Off Time | Time-out – maximum execution time has been exceeded *Type of R-trans: Reject* | ## SDD reason codes Find below the list of reason codes to handle SDD R-transactions (i.e., rejects, returns, and recalls). This list is regularly updated on the [EPC website](https://www.europeanpaymentscouncil.eu/document-library/guidance-documents/guidance-reason-codes-sepa-direct-debit-r-transactions). | Code | Definition | Reason | |:---: |--- |--- | | `AC01` | Incorrect Account Number | Account Identifier incorrect (i.e., invalid IBAN of the Debtor) *Type of R-trans: Reject, Return* | | `AC04` | Closed Account Number | Account closed *Type of R-trans: Reject, Return* | | `AC06` | Blocked Account | Account blocked *Type of R-trans: Reject, Return* | | `AC13` | Invalid Debtor Account Type | Debtor account is a consumer account **(For SDD B2B collections only)** *Type of R-trans:Reject, Return* | | `AG01` | Transaction Forbidden | Direct Debit forbidden on this account for regulatory reasons *Type of R-trans: Reject, Return* | | `AG02` | Invalid Bank Operation Code | Operation code/ transaction code/ sequence type incorrect, invalid file format *Type of R-trans:Reject, Return* | | `AM04` | Insufficient Funds | Insufficient funds *Type of R-trans: Reject, Return* | | `AM05` | Duplication | Duplicate collection *Type of R-trans: Reject, Return, Revers* | | `BE05` | Unrecognised initiating party | Identifier of the Creditor Incorrect *Type of R-trans: Reject, Return* | | `CNOR` | Debtor Bank is not registered | Creditor PSP is not registered under this BIC in the CSM *Type of R-trans: Reject* | | `DNOR` | Debtor Bank is not registered | Debtor PSP is not registered under this BIC in the CSM *Type of R-trans: Reject* | | `ED05` | Settlement Failed | Settlement of the collection failed *Type of R-trans: Reject* | | `FF01` | Invalid File Format | Invalid file format *Type of R-trans: Reject* | | `MD01` | No Mandate | No valid mandate **(For SDD Core collections only)** No mandate or unable to obtain mandate confirmation from the Debtor; **(For SDD B2B collections only)** Unauthorised transaction. **(For Refunds of SDD Core collections only)** *Type of R-trans: Reject, Return, Refund* | | `MD02` | Missing Mandatory Mandate Information in Mandate | Mandate data missing or incorrect *Type of R-trans: Reject* | | `MD06` | Refund Request By End Customer | Disputed authorized transaction. **(For SDD Core collections only)** *Type of R-trans: Refund* | | `MD07` | End Customer Deceased | Debtor Deceased *Type of R-trans: Reject, Return* | | `MS02` | Not Specified Reason Customer Generated | Refusal by the Debtor *Type of R-trans: Reject, Return, Reversal* | | `MS03` | Not Specified Reason Agent Generated | Reason not specified *Type of R-trans: Reject, Return, Reversal* | | `RC01` | Bank Identifier Incorrect | PSP identifier incorrect (i.e., invalid BIC) *Type of R-trans: Reject, Return* | | `RR01` | Missing Debtor Account Or Identification | Regulatory Reason *Type of R-trans: Reject, Return* | | `RR02` | Missing Debtor Name Or Address | Regulatory Reason *Type of R-trans: Reject, Return* | | `RR03` | Missing Creditor Name Or Address | Regulatory Reason *Type of R-trans: Reject, Return* | | `RR04` | Regulatory Reason | Regulatory Reason *Type of R-trans: Reject, Return* | | `SL01` | Specific Service Offered By Debtor Agent | Due to specific service offered by the Debtor PSP *Type of R-trans: Reject, Return* | ## Transfer errors The following API errors can be encountered regarding [Eletronic Money Wallets](/guide/wallets/introduction#electronic-money-wallet-type-9). | Code | Message | Description | |:---: |--- |--- | | `120018` | Impossible to create the payout SCTE | SCTE payouts are not allowed (e.g., anonymous electronic money) | | `120020` | Impossible to create the operation, the authorization amount exceed the max amount limit | Amount of the operation exceeds the limit | | `120021` | Impossible to create the operation, the authorization amount added to the account limit exceed the max account amount limit | Balance of the account exceeds the limit | | `120019` | Impossible to create the operation, the total debit exceed the max total debit limit on sliding period | Sum of the debit operations in the past 30 days exceeds the limit | | `120026` | Impossible to create the operation, the total credit exceed the max total credit limit on sliding period | Sum of the credit operations in the past 30 days exceeds the limit | | `120022` | Impossible to create the operation, the transfer creditor user is invalid | User of the wallet receiving the credit is an anonymous user and doesn’t have a relationship parent/child with the creditor’s user | | `120023` | Impossible to create the operation, the transfer debitor user is invalid | User crediting the wallet is an anonymous user and doesn’t have a relationship parent/child with the wallet’s user | | `15016` | Impossible to create the transfer, the BICs of the provided wallets are not the same | The Wallet-to-Wallet transfers is not compatible with [Local IBAN](/guide/wallets/iban), a SEPA Transfer can be initiated instead. | ## Beneficiary errors The following API errors can be encountered with beneficiaries. | Code | Message | Additional information | |:---: |--- |--- | | `75001` | IBAN Validation failed | | | `75002` | sddB2bWhitelist validation failed | | | `75003` | userId validation failed | | | `75004` | sepaCreditorIdentifier is missing | | | `75005` | sddB2bWhitelist is missing | | | `75006` | sddCoreBlacklist validation failed | | | `75007` | Beneficiary ID does not exist | | | `75008` | Another beneficiary has already used this userId or sepa\_creditor\_identifier | | | `75009` | userId is empty or missing | | | `75010` | sepaCreditorIdentifier is empty or missing | | | `75011` | BIC IBAN - Invalid country code | See [Accepted countries](/guide/transfers/beneficiaries#accepted-countries) for more information. | ## Payout errors The following API errors can be encountered with payouts. | Code | Message |:---: |--- | | `16010` | Impossible to cancel Payout, this Payout is already CANCELED | | `16011` | Impossible to cancel Payout, this Payout does not exist | | `16012` | Impossible to cancel Payout, Database Error. | | `16045` | Unable to cancel the Payout. | | `16046` | The label type is not correct, it must be a string | | `16047` | Label contains invalid chars. Only allowed : 'a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 / - ? : ( ) . , ' + Space | | `16048` | Label contains invalid chars. Must not start or end with / | | `16049` | Label contains invalid chars. Must not contain // | ## Mandate errors | Code | Message | |:---------:|--------------------------------------------------------------------------------------------------------------| | `22002` | Unable to create the mandate. The name of the debtor is not valid. | | `22003` | Unable to create the mandate. The address of the debtor is mandatory. | | `22004` | Unable to create the mandate. The city of the debtor is mandatory. | | `22005` | Unable to create the mandate. The zip code of the debtor is mandatory. | | `22006` | Unable to create the mandate. The country of the debtor is mandatory. | | `22007` | Unable to create the mandate. The sequence type is mandatory. | | `22008` | Unable to create the mandate. The IBAN of the debtor is mandatory. | | `22009` | Unable to create the mandate. The payment type value must be 'OOFF' (one-off) or 'RCUR' (recurrent). | | `22010` | Unable to create the mandate. The IBAN is not valid. | | `22011` | Unable to create Mandate. Database Error during the creation of the One-time password. | | `22012` | Mandate does not exist or is already signed up. | | `22013` | Unable to sign up the mandate. Wrong OTP. It has been sent again via SMS. | | `22014` | Unable to update the mandate. Database error during the signing up. | | `22015` | The mandate you want to cancel does not exist. | | `22017` | Unable to sign up the mandate. Database error during the signature. | | `22018` | Unable to create the mandate. The userId is required. | | `22019` | Unable to create the mandate. The mobile of the debtor is mandatory. | | `22020` | Unable to create the mandate. An error occurred during the One-time password sending. | | `22021` | An error occurred during the One-time password sending. | | `22022` | Error during OTP checking. | | `22023` | Error during OTP checking. | | `22024` | mandateId is mandatory. | | `22025` | Unable to create the mandate. debtorBic is mandatory. | | `22026` | Unable to create the mandate. User does not have a SEPA creditor identifier. | | `22028` | Database Error | | `22029` | Error. The SMS has not been sent to the user. | | `22030` | Unable to create the mandate. The user does not have an SCI number yet. | | `22031` | The mandate is already revoked. | | `22032` | Origin is mandatory. | | `22033` | Origin can be 'CREDITOR' or 'DEBITOR'. | | `22034` | Unable to create the mandate. The last name of the debtor is mandatory.| | `22035` | Unable to create the mandate. The creditor userId does not have a title.| | `22036` | Unable to create the mandate. The creditor userId does not have a first name.| | `22037` | Unable to create the mandate. The creditor userId does not have a last name. | | `22038` | Unable to create the mandate. The creditor userId does not have an address1. | | `22039` | Unable to create the mandate. The creditor userId does not have a post code. | | `22040` | Unable to create the mandate. The creditor userId does not have a city. | | `22041` | Unable to create the mandate. The creditor userId does not have a country. | | `22042` | Unable to create the mandate. The creditor userId does not have a legal name. | | `22043` | Unable to create the mandate. The mobile of the debtor must begin by + or 00 followed by the phone country code (e.g., 0033 for France). | | `22044` | Currently, we only allow paper mandates. | | `22045` | This type of SDD is not authorized yet. | | `22046` | OTP is mandatory. | | `22047` | signatureDate is mandatory. | | `22048` | The PUT method is not available. | | `22049` | The signature date is malformatted. | | `22050` | The userId provided in the request does not exist. | | `22050` | The userIdUltimateCreditor provided in the request does not exist. | | `22051` | The Third Party Creditor mode is not activated for your account. Please contact the Treezor Team to ask for activation. | | `22052` | In third-party creditor mode, the userId of the wallet credited must be equal to the property userIdUltimateCreditor of the mandate. | --- --- url: /guide/transfers/events.md description: >- Reference a comprehensive list of transfer, beneficiaries, and mandates events for Treezor API webhooks, detailing each event's structure and payload for integration. --- # Events This article lists the [Webhooks](/guide/webhooks/introduction) you may receive when regarding transfers. ## Beneficiaries To initiate a fund transfer to external accounts, a beneficiary must be created first. When receiving [SDDR](/guide/transfers/direct-debit#received-direct-debits-sddr), a [Beneficiary](beneficiaries) is automatically created, representing the originator. ### `beneficiary.create` ::: code-group ```json [JSON] { "webhook":"beneficiary.create", "webhook_id":"21410028", "object":"beneficiary", "object_id":"131680", "object_payload":{ "beneficiaries":[ { "id":131680, "tag":"", "userId":854084, "nickName":"", "name":"XXXX", "address":"XXXX", "iban":"", "bic":"", "sepaCreditorIdentifier":"XXXX", "sddB2bWhitelist":[ { "uniqueMandateReference":"adc2e1ac4024457baf844064ebed4166", "isRecurrent":false, "walletId":334886 } ], "sddCoreBlacklist":[ ], "usableForSct":false, "sddCoreKnownUniqueMandateReference":[ ], "isActive":true, "createdDate":"2021-04-22 10:03:35", "modifiedDate":"2021-04-22 10:03:35" } ] }, "object_payload_signature":"5rG4Xs3vi64p\/r65mcREY0fB0ZDhaYvOA7aQ6bVNhqw=" } ``` ::: ### `beneficiary.update` ::: code-group ```json [JSON] { "webhook":"beneficiary.update", "webhook_id":"21410027", "object":"beneficiary", "object_id":"120757", "object_payload":{ "beneficiaries":[ { "id":120757, "tag":"", "userId":854084, "nickName":"", "name":"creditorName", "address":"XXXX", "iban":"", "bic":"", "sepaCreditorIdentifier":"XXXX", "sddB2bWhitelist":[ ], "sddCoreBlacklist":[ "*", "EDEA7D89D8A34726A02BB09A4F1C3AA1" ], "usableForSct":false, "sddCoreKnownUniqueMandateReference":[ ], "isActive":true, "createdDate":"2021-02-24 13:48:35", "modifiedDate":"2021-04-22 10:03:35" } ] }, "object_payload_signature":"whE26wjEpLekI5PFf+QvlPtD8mPXT8zraMd49LZY0T8=" } ``` ::: ## Mandates Mandates allow for [SDDE](/guide/transfers/direct-debit#emitted-direct-debits-sdde) payins. ### `mandate.create` ::: code-group ```json [JSON] { "messageId": "4d33xxxx-6xxc-5xx4-806a-33fxxxxx7c01", "webhookId": "bfxxxx02-axxa-4xx0-8xx9-272xxxxx0fe2", "webhook": { "webhook": "mandate.create", "object": "mandate", "object_id": "7004", "object_payload": { "mandates": [ { "mandateId": 7004, "title": "M", "legalInformations": "Compagnie", "uniqueMandateReference": "39FF[...]E64C1F423", "mandateStatus": "PENDING", "userId": 35xxxx3, "debtorName": "Nom du Debiteur", "debtorAddress": "33 avenue Wagram", "debtorCity": "Paris", "debtorZipCode": "75017", "debtorCountry": "FR", "debtorIban": "FR7616[...]xx20", "debtorBic": "TRZOFR21XXX", "sequenceType": "one-off", "creditorName": "Compagnie", "sepaCreditorIdentifier": "FR123TEST456", "creditorAddress": "99 rue de test ", "creditorCity": "Paris", "creditorZipCode": "75001", "creditorCountry": "FR", "signatureDate": "2022-10-22", "debtorSignatureIp": "", "signed": 0, "revocationSignatureDate": null, "debtorIdentificationCode": "", "debtorReferencePartyName": "", "debtorReferenceIdentificationCode": "", "creditorReferencePartyName": "", "creditorReferenceIdentificationCode": "", "contractIdentificationNumber": "", "contractDescription": "", "createdDate": null, "codeStatus": 220001, "informationStatus": "Mandat complété", "isPaper": true, "sddType": "core", "createdIp": "10.xx.x.37", "userIdUltimateCreditor": 0 } ] }, "webhook_created_at": 16661913868587, "webhook_id": "bfxxxx02-axxa-4xx0-8xx9-xx2dxx2xxfe2", "object_payload_signature": "8Hv4[...]PnE=" }, "clientId": "878950" } ``` ::: ## Transfers [Transfers](/guide/transfers/wallet-to-wallet) are internal, they are from [Wallet](/guide/wallets/introduction) to Wallet. ### `transfer.create` ::: code-group ```json [JSON] { "webhook": "transfer.create", "webhook_id": "10XXXXXX", "object": "transfer", "object_id": "3XXXXX", "object_payload": { "transfers": [ { "transferId": "3XXXXX", "transferTypeId": "3", "transferTag": "\"=DZm&_h+iT%4\"sS[ABC", "transferStatus": "PENDING", "walletId": "5XXXXX", "foreignId": "0", "walletTypeId": "10", "beneficiaryWalletId": "5XXXXX", "beneficiaryWalletTypeId": "10", "amount": "21600.00", "currency": "EUR", "label": "", "partnerFee": "0", "createdDate": "2020-05-19 10:44:20", "modifiedDate": "0000-00-00 00:00:00", "walletEventName": "Main", "walletAlias": "c6ade708-3dfc-48ba-92ac-35b48bbfdb46-5ec24ae1bXOXO", "beneficiaryWalletEventName": "Main", "beneficiaryWalletAlias": "33b98677-3487-431b-8b2b-00981ba174d0-5ebe86655XAXA", "codeStatus": "150001", "informationStatus": "" } ] }, "object_payload_signature": "tUq1WPaRdlapmUl6/ObZGXR1a757XUWeB2erJNUSASAS" } ``` ::: ### `transfer.update` ::: code-group ```json [JSON] { "webhook": "transfer.update", "webhook_id": "10XXXXXX", "object": "transfer", "object_id": "32XXXX", "object_payload": { "transfers": [ { "transferId": "32XXXX", "transferTypeId": "3", "transferTag": "m_^./![+d8J2NaHiXXXX", "transferStatus": "VALIDATED", "walletId": "5XXXXX", "foreignId": "0", "walletTypeId": "10", "beneficiaryWalletId": "5XXXXX", "beneficiaryWalletTypeId": "10", "amount": "21600.00", "currency": "EUR", "label": "", "partnerFee": "0", "createdDate": "2020-05-19 10:16:37", "modifiedDate": "2020-05-19 10:16:37", "walletEventName": "Main", "walletAlias": "eef8bc9d-15d9-42c8-8a3d-e74da26097cc-5ec2428XXXXXX", "beneficiaryWalletEventName": "Main", "beneficiaryWalletAlias": "33b98677-3487-431b-8b2b-00981ba174d0-5ebe866XXXXXX", "codeStatus": "150005", "informationStatus": "" } ] }, "object_payload_signature": "uPTyXZHnG0YyL0CTe3OoWMup7qLU6I5UFJtjHfmXXXXX" } ``` ::: ### `transfer.cancel` ::: code-group ```json [JSON] { "webhook": "transfer.cancel", "webhook_id": "1xxxxxxxx", "object": "transfer", "object_id": "3xxxxx", "object_payload": { "transfers": [ { "transferId": "3xxxxx", "transferTypeId": "1", "transferTag": "", "transferStatus": "CANCELED", "walletId": "4xxxxx", "foreignId": "0", "walletTypeId": "10", "beneficiaryWalletId": "4xxxxx", "beneficiaryWalletTypeId": "10", "amount": "1xxx.00", "currency": "EUR", "label": "label", "partnerFee": "0", "createdDate": "2020-05-05 23:45:30", "modifiedDate": "2020-05-05 23:45:38", "walletEventName": "wallet of second ", "walletAlias": "aaaaa-5e99cc3161a61", "beneficiaryWalletEventName": "aaaaa ", "beneficiaryWalletAlias": "aaaaa-5e99cc88d0000", "codeStatus": "150003", "informationStatus": "" } ] }, "object_payload_signature": "XNYa62cf3z8RIL2NTATK3yNqQ4l6sXSzsaJRBxWz0000" } ``` ::: ## SDDR webhooks Find below the series of webhooks you may receive during the processing of a received SEPA Direct Debit. ### `sepa_sddr.reception` #### SDDR Core ::: code-group ```json [JSON] { "messageId": "efab78b5-d90f-5fcb-9111-2xxxxxxxxxx", "webhookId": "36a6ab15-62ca-4f98-bxx3-8xxxxxxxxxx", "webhook": { "webhook": "sepa_sddr.reception", "object_payload": { "sepaSddr": { "wallet_id": 123456789, "virtual_iban_id": null, "beneficiary_id": 445566, "transaction_id": "00950N2202482123456796", "interbank_settlement_amount": "98.77", "requested_collection_date": { "date": "2024-11-21 00:00:00", "timesone_type": 3, "timezone": "UTC" }, "local_instrument": "CORE", "mandate_id": "XXXXXX", "creditor_scheme_id": "FR11ZZZ12346", "debitor_name": "TREE CIE", "debitor_address": "", "debitor_country": "", "creditor_name": "CREDITOR NAME", "creditor_address": "CREDITOR ADDRESS 75006 PARIS FR", "creditor_country": "FR", "creditor_bic": "SOGEFRPPXXX", "creditor_iban": "FR7630003009500006711111111", "unstructured_field": "XXXX", "created_date": { "date": "2024-11-20 15:15:27", "timesone_type": 3, "timezone": "UTC" } } }, "object_id": "8311386", "object": "sepa_sddr", "webhook_created_at": 17321555274116, "webhook_id": "36a6ab15-62ca-4f98-b783-8656ee555556", "object_payload_signature": "ecIAA53k4nWGVtG97g4hDBEOxxxVUUx9cKUQDNejl5M=" }, "clientId": "12345" } ``` ::: #### SDDR B2B ::: code-group ```json [JSON] { "messageId": "9e8c9d92-86fe-528f-9f8a-c22xxxxxxbf", "webhookId": "c602365b-03fd-495d-a6ea-1xxxxxa92b6", "webhook": { "webhook": "sepa_sddr.reception", "object_payload": { "sepaSddr": { "wallet_id": 123456, "virtual_iban_id": null, "beneficiary_id": 0, "transaction_id": "COMD981234595294XXX", "interbank_settlement_amount": "90.00", "requested_collection_date": { "date": "2024-11-21 00:00:00", "timesone_type": 3, "timezone": "UTC" }, "local_instrument": "B2B", "mandate_id": "nn844244566DGFIP2023684XXXX", "creditor_scheme_id": "FR11ZZZ12345", "debitor_name": "DEBITOR NAME", "debitor_address": "adresse inconnue adresse inconnue", "debitor_country": "FR", "creditor_name": "CREDITOR NAME", "creditor_address": "", "creditor_country": "", "creditor_bic": "BDXXXXX", "creditor_iban": "FR6930001007034520X12345640", "unstructured_field": "", "created_date": { "date": "2024-11-19 18:18:05", "timesone_type": 3, "timezone": "UTC" } } }, "object_id": "8312389", "object": "sepa_sddr", "webhook_created_at": 17320402855364, "webhook_id": "c602365b-03fd-495d-a6ea-12e22512345", "object_payload_signature": "VDW+mMThl4azQ5FXixxxxVX80Bts+bl3Cpor0g53Rnw=" }, "clientId": "191294" } ``` ::: ### `sepa.reject_sddr_core` ::: code-group ```json [JSON] { "webhook":"sepa.reject_sddr_core", "webhook_id":"35XXXX370", "object":"sepaSddr", "object_id":"2xxxxx7", "object_payload":{ "sepaSddrs":[ { "wallet_id":123456, "virtual_iban_id":null, "transaction_id":"20155xxxxxx00434", "sequence_type":"RCUR", "reject_reason_code":"MS02", "interbank_settlement_amount":"33.97", "requested_collection_date":"2020-06-08", "mandate_id":"700xxxxxxxxxx66", "sepa_creditor_identifier":"FRXXXXXXX3", "date_of_signature":"2020-02-06", "debitor_name":"XXXX", "debitor_address":null, "debitor_country":null, "creditor_name":"XXXX", "creditor_address":"XXXX", "creditor_country":"FR", "unstructured_field":"XXXX", "bankaccount_id":null, "beneficiary_id":1000089 } ] }, "object_payload_signature":"6ZEv505Swg5QsAnGBcuEOs2CvXHmUMF2ObzXkgudyl8=" } ``` ::: ### `sepa.reject_sddr_b2b` ::: code-group ```json [JSON] { "webhook":"sepa.reject_sddr_b2b", "webhook_id":"35XXXX29", "object":"sepaSddr", "object_id":"21XXXX0", "object_payload":{ "sepaSddrs":[ { "wallet_id":123456, "virtual_iban_id":null, "transaction_id":"20155XXXXXX50", "sequence_type":"RCUR", "reject_reason_code":"AM04", "interbank_settlement_amount":"2495", "requested_collection_date":"2020-06-05", "mandate_id":"nnABCDEFGHIJKLMOXXXXXXYTJ5", "sepa_creditor_identifier":"FR46XXXXXX02", "date_of_signature":"2019-02-05", "debitor_name":"TREE CIE", "debitor_address":" ", "debitor_country":null, "creditor_name":"CREDITOR NAME", "creditor_address":" ", "creditor_country":null, "unstructured_field":"IS-052020-2572", "bankaccount_id":null, "beneficiary_id":null } ] }, "object_payload_signature":"amXZewtaB2KcFTX15xnOxxxxx/980HZvgBfo3jSIKo=" } ``` ::: ### `beneficiary.create` #### SDDR Core ::: code-group ```json [JSON] { "messageId": "0937c153-38e2-5b25-ad62-9exxxxxe96", "webhookId": "cfe12dbe-ede6-43de-953d-0ebxxxxd8a95", "webhook": { "webhook": "beneficiary.create", "object_payload": { "beneficiaries": [ { "id": 123456789, "tag": "", "userId": 11111144, "nickName": "", "name": "TREE S.A.", "address": "FR", "iban": "FR76177890000119999999737", "bic": "DEUXXXXPXXX", "sepaCreditorIdentifier": "FR03SXXX02381", "sddB2bWhitelist": [], "sddCoreBlacklist": null, "usableForSct": false, "sddCoreKnownUniqueMandateReference": null, "isActive": true, "createdDate": "2024-11-06 08:15:43", "modifiedDate": "2024-11-06 08:15:43" } ] }, "object_id": "1234567", "object": "beneficiary", "webhook_created_at": 17308809434537, "webhook_id": "cfe12dbe-ede6-43de-953d-xxxx49d8a95", "object_payload_signature": "gHOGPMeuWQr9m/Dwlx9J111xxxoXILE7nc4QBCigwHg=" }, "clientId": "12345" } ``` ::: #### SDDR B2B ::: code-group ```json [JSON] { "messageId": "683f5597-92f3-539f-80a2-0a9xxxxx2d0b", "webhookId": "1431c1f1-dddd-4bbe-a2f9-1184xxxxx6", "webhook": { "webhook": "beneficiary.create", "object": "beneficiary", "object_id": "3974948", "object_payload": { "beneficiaries": [ { "id": 123456, "tag": "", "userId": 123456789, "nickName": "", "name": "TREE CIE", "address": "15 ROSEWOOD LANE", "iban": "", "bic": "", "sepaCreditorIdentifier": "FR44ZZZ123456", "sddB2bWhitelist": [ { "uniqueMandateReference": "nn539565911DGFIP2111111347LY454WW7", "isRecurrent": true } ], "sddCoreBlacklist": [], "usableForSct": false, "sddCoreKnownUniqueMandateReference": [], "isActive": true, "createdDate": "2024-07-08 14:03:41", "modifiedDate": "2024-07-08 14:03:41" } ] }, "webhook_created_at": 17204474219169, "webhook_id": "1431c1f1-xxxx-xxxx-xxxx-1184b5c2b076", "object_payload_signature": "Yvd4c8X3H/WeL7eCBRKWX/hW/anZhnXTLXXXXX2DeQ=" }, "clientId": "12345" } ``` ::: ### `sepa.return_sddr` #### SDDR Core ::: code-group ```json [JSON] { "messageId": "a76cbdb5-xxxx-xxxx-xxxx-e203bf6f144a", "webhookId": "b2b23d28-xxxx-xxxx-xxxx-d5c649955ea0", "webhook": { "webhook": "sepa.return_sddr", "object_payload": { "sepaSddrs": [ { "wallet_id": 123456, "virtual_iban_id": null, "transaction_id": "REPSDD241XXXX1FR45549720562", "sequence_type": "RCUR", "reject_reason_code": null, "reason_code": "AM04", "interbank_settlement_amount": "46.72", "requested_collection_date": "2024-11-19 00:00:00", "mandate_id": "00S017745232", "sepa_creditor_identifier": "FRXXXXXX", "date_of_signature": "2022-05-31 00:00:00", "debitor_name": "Debitor Name", "debitor_address": "14 ROSEWOOD LANE", "debitor_country": "FR", "creditor_name": "BLUE TREE S.A.", "creditor_address": "FR", "creditor_country": "FR", "unstructured_field": "", "bankaccount_id": null, "beneficiary_id": 123456 } ] }, "object_id": "123", "object": "sepa_sddr", "webhook_created_at": 17320365151141, "webhook_id": "b2b23d28-1111-xxxx-11111-d5c649955ea0", "object_payload_signature": "JVCCqpKBps/6atnn0o2Rsdv/2b+xxxxc/qOuNjSlu8o=" }, "clientId": "12345" } ``` ::: #### SDDR B2B ::: code-group ```json [JSON] { "messageId": "0da13ff4-xxxx-1111-xxxx-60436e0a2b48", "webhookId": "79aad3d5-1111-xxxx-1111-5fbbad0b1a00", "webhook": { "webhook": "sepa.return_sddr", "object_payload": { "sepaSddrs": [ { "wallet_id": 12345, "virtual_iban_id": null, "transaction_id": "COMD98G90112345XXX", "sequence_type": "RCUR", "reject_reason_code": null, "reason_code": "AM04", "interbank_settlement_amount": "278", "requested_collection_date": "2024-11-20 00:00:00", "mandate_id": "nn482136264DGFIP20212345LO6WTI8C", "sepa_creditor_identifier": "FR46ZZZ005002", "date_of_signature": "2023-10-26 00:00:00", "debitor_name": "TREE COMPANY", "debitor_address": "ROSEWOOD LANE 75012 PARIS", "debitor_country": "FR", "creditor_name": "CREDITOR NAME", "creditor_address": "", "creditor_country": "", "unstructured_field": "", "bankaccount_id": null, "beneficiary_id": 123456 } ] }, "object_id": "8384450", "object": "sepa_sddr", "webhook_created_at": 17321121144920, "webhook_id": "79aad3d5-xxxx-xxxx-xxxx-5fbbad0b1a00", "object_payload_signature": "WigBc/JUKTYnk/8PsAv123654/b1Z+3FaBbkZQ3X4=" }, "clientId": "12345" } ``` ::: ### `sepa.refund_sddr` ::: code-group ```json [JSON] { "webhook": "sepa.refund_sddr", "webhook_id": "4XXXXXX5", "object": "sepaSddr", "object_id": "21XXXX0", "object_payload": { "sepaSddrs": [ { "wallet_id": 600007, "virtual_iban_id": null, "transaction_id": "20155XXXXXX50", "sequence_type": "RCUR", "reject_reason_code": null, "reason_code": "MD06", "interbank_settlement_amount": "2495", "requested_collection_date": "2020-06-05", "mandate_id": "nnABCDEFGHIJKLMONPJRRWYTJ5", "sepa_creditor_identifier": "FR46XXXXXX02", "date_of_signature": "2019-02-05", "debitor_name": "MA SOCIETE", "debitor_address": " ", "debitor_country": null, "creditor_name": "DGFIP", "creditor_address": " ", "creditor_country": null, "unstructured_field": "IS-052020-2572", "bankaccount_id": null, "beneficiary_id": null } ] }, "object_payload_signature": "123xyztaB2KcFTX15xnOVQ86ek/980HZvfgto3jSIKo=" } ``` ::: ### `payout.create` #### SDDR Core ::: code-group ```json [JSON] { "messageId": "41897072-44444-55555-66666-2fc474aee947", "webhookId": "9676e0cb-7777-99999-88888-7c87e9780c16", "webhook": { "webhook": "payout.create", "object_payload": { "payouts": [ { "payoutId": "123456789", "payoutTag": "", "payoutStatus": "VALIDATED", "payoutTypeId": "2", "payoutType": "Direct Debit", "walletId": "123456", "payoutDate": "2024-11-19", "walletEventName": "WALLET NAME", "walletAlias": "wallet-name-5bbb97ed9f75d", "userLastname": "OAK", "userFirstname": "ALEX", "userId": "123456789", "bankaccountId": "123654", "beneficiaryId": "789654", "uniqueMandateReference": "5MAXXX54W2FUU", "bankaccountIBAN": "", "label": "XXXX/ADD TO BALANCE", "amount": "30.00", "currency": "EUR", "partnerFee": "", "createdDate": "2024-11-19 08:00:38", "modifiedDate": "", "virtualIbanId": null, "virtualIbanReference": null, "codeStatus": "160005", "informationStatus": "Validated", "supportingFileLink": "", "endToEndId": "12345678963", "reasonCode": null, "reasonDescription": null, "metadata": null, "totalRows": 1 } ] }, "object_id": "20440330", "object": "payout", "webhook_created_at": 17320032389643, "webhook_id": "9676e0cb-xxxx-eeee-rrrr-7c87e9780c16", "object_payload_signature": "8Zf6k5tVfxGwZeUP7iagDdjsffffEwHO7kppSBagMS/M=" }, "clientId": "123456" } ``` ::: #### SDDR B2B ::: code-group ```json [JSON] { "messageId": "3eeb07b1-aaaa-zzzz-rrrr-5806a3c01443", "webhookId": "754f2204-vvvv-nnnn-ssss-f4d58a6c5688", "webhook": { "webhook": "payout.create", "object_payload": { "payouts": [ { "payoutId": "123456789", "payoutTag": "", "payoutStatus": "VALIDATED", "payoutTypeId": "2", "payoutType": "Direct Debit", "walletId": "123456", "payoutDate": "2024-11-20", "walletEventName": "Wallet Name", "walletAlias": "wallet-name-61dffb46b1fae", "userLastname": "", "userFirstname": "", "userId": "123654", "bankaccountId": "987456", "beneficiaryId": "258963", "uniqueMandateReference": "nn909003626DGFIP2022906XXXXXK8S8F", "bankaccountIBAN": "", "label": "TVA-XXXXX-3310CA3", "amount": "4514.00", "currency": "EUR", "partnerFee": "", "createdDate": "2024-11-20 08:01:44", "modifiedDate": "", "virtualIbanId": null, "virtualIbanReference": null, "codeStatus": "160005", "informationStatus": "Validated", "supportingFileLink": "", "endToEndId": "22075712999999333457", "reasonCode": null, "reasonDescription": null, "metadata": null, "totalRows": 1 } ] }, "object_id": "20151121926", "object": "payout", "webhook_created_at": 17320897049707, "webhook_id": "754f2204-xxx-xxxx-xxxx-f4d58a6c5688", "object_payload_signature": "xYgn0KTD/iL+mfP74/AP9Udbe125ffffffffYGBDPlQ=" }, "clientId": "123456" } ``` ::: ### `transaction.create` #### SDDR Core ::: code-group ```json [JSON] { "messageId": "1f34be62-aaaa-aaaa-aaaa-e1d48d4b1265", "webhookId": "608e6ceb-cccc-cccc-cccc-aea3afc9e446", "webhook": { "webhook": "transaction.create", "object_payload": { "transactions": [ { "transactionId": "12345", "walletDebitId": "32165", "walletCreditId": "9", "transactionType": "Payout", "foreignId": "123654", "name": "111111", "description": "Prélèvement 123654", "valueDate": "2024-11-19", "executionDate": "2024-11-19", "amount": "30.00", "walletDebitBalance": "1368.21", "walletCreditBalance": "0.00", "currency": "EUR", "createdDate": "2024-11-19 09:00:38" } ] }, "object_id": "99999999", "object": "transaction", "webhook_created_at": 17320032389078, "webhook_id": "608e6ceb-xxxx-xxxx-xxxx-aea3afc9e446", "object_payload_signature": "5YDh3HrB8IM7eMaOE4f9cl7jI/e1d48d4b1265=" }, "clientId": "123456" } ``` ::: #### SDDR B2B ::: code-group ```json [JSON] { "messageId": "672f7914-xxxx-xxxx-xxxx-26a35280b07c", "webhookId": "1ad05bba-xxxx-xxxx-xxxx-1429c9182b39", "webhook": { "webhook": "transaction.create", "object_payload": { "transactions": [ { "transactionId": "123456", "walletDebitId": "654789", "walletCreditId": "9", "transactionType": "Payout", "foreignId": "654789", "name": "XXXX", "description": "Prélèvement XXXX", "valueDate": "2024-11-20", "executionDate": "2024-11-20", "amount": "4514.00", "walletDebitBalance": "109673.64", "walletCreditBalance": "0.00", "currency": "EUR", "createdDate": "2024-11-20 09:01:44" } ] }, "object_id": "870584566", "object": "transaction", "webhook_created_at": 17320897048636, "webhook_id": "1ad05bba-eeee-eeee-eeee-1429c9182b39", "object_payload_signature": "MAJr6N1YxFPg9Nn+DFFFE+TWdQZl4ep5kQCk=" }, "clientId": "12345" } ``` ::: ### `payoutRefund.create` ::: code-group ```json [JSON] { "messageId": "a1b2c3d4-e5f6-54g7-8h9i-j0k1l2m3n4o5", "webhookId": "b2c3d4e5-f6g7-4h8i-9j0k-l1m2n3o4p5q6", "webhook": { "webhook": "payoutRefund.create", "object": "payoutRefund", "object_id": "59760", "object_payload": { "payoutRefunds": [ { "id": "59760", "payoutRefundTag": "", "codeStatus": 790001, "informationStatus": "PENDING", "payoutId": "19686689", "requestAmount": "20.00", "requestCurrency": "EUR", "requestComment": "", "reasonCode": "MD06", "refundAmount": "", "refundCurrency": "", "refundDate": null, "refundComment": "", "negativeResponseReasonCode": "", "createdDate": "2024-10-01 13:17:47", "modifiedDate": null } ] }, "webhook_created_at": 17277886676171, "webhook_id": "b2c3d4e5-f6g7-4h8i-9j0k-l1m2n3o4p5q6", "object_payload_signature": "WUySz+2mVHTIyzyp3XNP5i2NSu3y8fhowxuv+K4Vx00=" }, "clientId": "12345" } ``` ::: ### `payoutRefund.update` ::: code-group ```json [JSON] { "messageId": "a1b2c3d4-e5f6-5g7h-8i9j-k0l1m2n3o4p5", "webhookId": "b2c3d4e5-f6g7-4h8i-9j0k-l1m2n3o4p5q6", "webhook": { "webhook": "payoutRefund.update", "object": "payoutRefund", "object_id": "59760", "object_payload": { "payoutRefunds": [ { "id": "59760", "payoutRefundTag": "", "codeStatus": 790003, "informationStatus": "VALIDATED", "payoutId": "19686689", "requestAmount": "20.00", "requestCurrency": "EUR", "requestComment": "", "reasonCode": "MD06", "refundAmount": "20", "refundCurrency": "EUR", "refundDate": "2024-10-01", "refundComment": "", "negativeResponseReasonCode": "", "createdDate": "2024-10-01 13:17:47", "modifiedDate": "2024-10-01 17:15:16" } ] }, "webhook_created_at": 17278029168100, "webhook_id": "c3d4e5f6-g7h8-4i9j-0k1l-m2n3o4p5q6r7", "object_payload_signature": "nDESXRVXi9VuUXqF9+FsPbDXcs5ND322ODtAN54D/04=" }, "clientId": "12345" } ``` ::: ## SDDE webhooks Find below the series of webhooks you may receive during the processing of an emitted SEPA Direct Debit. ### `payin.create` ::: code-group ```json [JSON] { "messageId": "aca2ac41-xxxx-xxxx-xxxx-f3dfba7c57f9", "webhookId": "7a65a4da-xxxx-xxxx-xxxx-d6ff82919991", "webhook": { "webhook": "payin.create", "object": "payin", "object_id": "12369999", "object_payload": { "payins": [ { "payinId": "12365478", "payinTag": "540afcb0-xxxx-xxxx-xxxx-95717e8ffaf8", "walletId": "123456", "userId": "3", "payinStatus": "PENDING", "paymentMethodId": "21", "messageToUser": "", "subtotalItems": "0.00", "subtotalServices": "0.00", "subtotalTax": "0.00", "amount": "424.51", "currency": "EUR", "createdDate": "2024-11-01 01:00:02", "walletEventName": "Wallet Name", "walletAlias": "wallet-name-2-6406c12315bef", "userFirstname": "Alex", "userLastname": "Oak", "codeStatus": "140001", "informationStatus": "", "refundAmount": null, "DbtrIBAN": null, "forwardUrl": null, "paymentAcceptedUrl": null, "paymentRefusedUrl": null, "paymentWaitingUrl": null, "paymentExceptionUrl": null, "paymentCanceledUrl": null, "payinDate": "2024-11-07", "mandateId": "52850", "creditorName": null, "creditorAddressLine": null, "creditorCountry": null, "creditorIban": null, "creditorBIC": null, "virtualIbanId": null, "virtualIbanReference": null, "additionalData": "", "totalRows": 1, "paymentHtml": null } ] }, "webhook_created_at": 17304192026804, "webhook_id": "7a65a4da-xxx-xxxx-xxxx-d6ff82919991", "object_payload_signature": "LYSu34X59tE9EukD+KS/fwxxxxxyAmwamYBQjZu8Kds=" }, "clientId": "908165" } ``` ::: ### `payin.update` ::: code-group ```json [JSON] { "messageId": "3a5e1eb4-xxxx-xxxx-xxxx-4113b64e094b", "webhookId": "0e7495ac-xxxx-xxxx-xxxx-805f5dc745bf", "webhook": { "webhook": "payin.update", "object_payload": { "payins": [ { "payinId": "123456", "payinTag": "540afcb0-xxxx-xxxx-xxxx-95717e8ffaf8", "walletId": "123456789", "userId": "3", "paymentMethodId": "21", "messageToUser": "A", "subtotalItems": "", "subtotalServices": "", "subtotalTax": "", "amount": "424.51", "currency": "", "createdDate": "2024-11-01 01:00:02", "walletEventName": "Wallet Name", "walletAlias": "wallet-name-6406c123456bef", "userFirstname": "", "userLastname": "", "payinStatus": "VALIDATED", "codeStatus": "140005", "informationStatus": "VALIDATED", "refundAmount": null, "ibanFullname": "", "DbtrIBAN": "FR761027806013000XXXX30225", "ibanBic": "", "ibanTxEndToEndId": "", "ibanTxId": "", "forwardUrl": null, "paymentAcceptedUrl": null, "paymentRefusedUrl": null, "paymentWaitingUrl": null, "paymentExceptionUrl": null, "paymentCanceledUrl": null, "payinDate": "2024-11-07", "mandateId": "52850", "creditorName": "Creditor Name", "creditorAddressLine": "15 ROSEWOOD ROAD", "creditorCountry": "FR", "creditorIban": "FR761679800001000XXXX15604", "creditorBIC": "TRZOFR21XXX", "virtualIbanId": null, "virtualIbanReference": null, "additionalData": "", "ibanId": "", "totalRows": 0, "paymentHtml": null } ] }, "object_id": "123456987", "object": "payin", "webhook_created_at": 17310062402680, "webhook_id": "0e7495ac-xxxx-xxxx-xxxx-805f5dc745bf", "object_payload_signature": "0cu82+3JNuYpZx5QPpqqNeV123654Cgz5ekBPvGmfZ1k=" }, "clientId": "12345" } ``` ::: ### `payin.cancel` ::: code-group ```json [JSON] { "messageId": "8ee5e015-xxxx-xxxx-xxxx-bfb30697058d", "webhookId": "edce11f7-xxxx-xxxx-xxxx-6267d3b17992", "webhook": { "webhook": "payin.cancel", "object_payload": { "payins": [ { "payinId": "123456", "payinTag": "987654", "walletId": "654789", "userId": "456123", "paymentMethodId": "21", "messageToUser": "", "subtotalItems": "", "subtotalServices": "", "subtotalTax": "", "amount": "9688.72", "currency": "EUR", "createdDate": "2024-11-04 19:01:52", "walletEventName": "Wallet Name", "walletAlias": "wallet-Name-6296165c10f1d", "userFirstname": "Tree Cie", "userLastname": "Tree Cie", "payinStatus": "CANCELED", "codeStatus": "150115", "informationStatus": "MS02", "refundAmount": null, "ibanFullname": "", "DbtrIBAN": "FR7613335000400412345692550", "ibanBic": "", "ibanTxEndToEndId": "", "ibanTxId": "", "forwardUrl": null, "paymentAcceptedUrl": null, "paymentRefusedUrl": null, "paymentWaitingUrl": null, "paymentExceptionUrl": null, "paymentCanceledUrl": null, "payinDate": "2024-11-04 19:01:52 +0000 UTC", "mandateId": "38217", "creditorName": "Creditor name", "creditorAddressLine": "10 WILLOW LANE 75008 Paris", "creditorCountry": "FR", "creditorIban": "FR761679800001098745610308", "creditorBIC": "TRZOFR21XXX", "virtualIbanId": null, "virtualIbanReference": null, "additionalData": "", "ibanId": "", "totalRows": 0, "paymentHtml": null } ] }, "object_id": "31771605", "object": "payin", "webhook_created_at": 17309826676945, "webhook_id": "edce11f7-xxxx-xxxx-xxxx-6267d3b17992", "object_payload_signature": "LYbuxxxxxlQnZTgD1lCfFrFMJBpuxzSS2M/hiA5EIM=" }, "clientId": "12345" } ``` ::: ### `transaction.create` ::: code-group ```json [JSON] { "messageId": "213bdfe8-ffff-ffff-ffff-804f8892b101", "webhookId": "39dc5126-ffff-ffff-ffff-f0cea7aaae6d", "webhook": { "webhook": "transaction.create", "object_payload": { "transactions": [ { "transactionId": "10232569", "walletDebitId": "9", "walletCreditId": "321654", "transactionType": "Payin", "foreignId": "852369741", "name": "222222", "description": "sdde payin_id 12345669", "valueDate": "2024-11-07", "executionDate": "2024-11-07", "amount": "424.51", "walletDebitBalance": "0.00", "walletCreditBalance": "539.92", "currency": "EUR", "createdDate": "2024-11-07 20:01:00" } ] }, "object_id": "863333120", "object": "transaction", "webhook_created_at": 17310060608928, "webhook_id": "39dc5126-xxxx-xxxx-xxxx-f0cea7aaae6d", "object_payload_signature": "ATCVsw0AVyUWcuIlj/gATPIrKvDsFU123456vpddutAY=" }, "clientId": "12345" } ``` ::: ### `payinrefund.create` ::: code-group ```json [JSON] { "messageId": "c23a16e7-hhhh-hhhh-hhhh-4992bdf70c2e", "webhookId": "6ef4154d-hhhh-hhhh-hhhh-ff1796e2a69e", "webhook": { "webhook": "payinrefund.create", "object_payload": { "payinrefunds": [ { "payinrefundId": "123654", "payinrefundTag": null, "payinrefundStatus": "PENDING", "walletId": "10203040", "payinId": "30201040", "payinrefundDate": "0000-00-00", "amount": "18.42", "currency": "EUR", "createdDate": "2024-10-01 10:30:59", "modifiedDate": "0000-00-00 00:00:00", "codeStatus": "170001", "informationStatus": "AM04", "reasonTms": null } ] }, "object_id": "32145", "object": "payinrefund", "webhook_created_at": 17277669259687, "webhook_id": "6ef4154d-xxxx-xxxx-xxxx-ff1796e2a69e", "object_payload_signature": "9Dsct7JSBvbDco1236547nm44icy5DbKUq/7y1GnQnaU0=" }, "clientId": "12345" } ``` ::: ### `payinrefund.update` ::: code-group ```json [JSON] { "messageId": "e0f6134e-xxxx-xxxx-xxxx-4c3b6ef7b243", "webhookId": "cfbe862d-xxxx-xxxx-xxxx-1bc11f2c8284", "webhook": { "webhook": "payinrefund.update", "object_payload": { "payinrefunds": [ { "payinrefundId": "123654", "payinrefundTag": null, "payinrefundStatus": "VALIDATED", // or ACCEPTED "walletId": "3214569", "payinId": "6547896", "payinrefundDate": "2024-10-01", "amount": "18.42", "currency": "EUR", "createdDate": "2024-10-01 10:30:59", "modifiedDate": "2024-10-01 10:30:59", "codeStatus": "170005", "informationStatus": "AM04", "reasonTms": null } ] }, "object_id": "33333", "object": "payinrefund", "webhook_created_at": 17277669260404, "webhook_id": "cfbe862d-ffff-ffff-ffff-1bc11f2c8284", "object_payload_signature": "nYL4fstR7jl5llllll1H04P+rp4+D69rqLWNyjWSb7Hc=" }, "clientId": "206135" } ``` ::: ## SCTE webhooks Find below the series of webhooks you may receive during the processing of an emitted SEPA Credit Transfer. ### `payout.create` ::: code-group ```json [JSON] { "messageId": "b73e9f12-c8d4-5a1b-9e3f-d2c7b8a9f0e1", "webhookId": "f5e6d7c8-b9a0-4d2e-a1b2-c3d4e5f6a7b8", "webhook": { "webhook": "payout.create", "object": "payout", "object_id": "20356891", "object_payload": { "payouts": [ { "payoutId": "123456", "payoutTag": "", "payoutStatus": "PENDING", "payoutTypeId": "1", "payoutType": "Credit Transfer", "walletId": "7654321", "bankaccountId": "0", "beneficiaryId": "987650", "endToEndId": null, "uniqueMandateReference": null, "label": "", "payoutDate": "0000-00-00", "amount": "1000.00", "currency": "EUR", "partnerFee": "0", "createdDate": "2024-12-06 23:58:33", "modifiedDate": "0000-00-00 00:00:00", "walletEventName": "Main", "walletAlias": "a1b2c3d4-e5f6-47g8-9h0i-j1k2l3m4n5o6", "userLastname": "", "userFirstname": "", "userId": "5432176", "bankaccountIBAN": null, "virtualIbanId": null, "virtualIbanReference": null, "codeStatus": "160001", "informationStatus": "Demande de remboursement saisie", "supportingFileLink": "", "reasonCode": "", "reasonDescription": "", "totalRows": 1 } ] }, "webhook_created_at": 17335259137789, "webhook_id": "f5e6d7c8-b9a0-4d2e-a1b2-c3d4e5f6a7b8", "object_payload_signature": "G1MiRO4x1ZVcCrXLMxNraacj6g9lWvWXpvK0foZY22I=" } } ``` ::: ### `payout.update` #### Pending ::: code-group ```json [JSON] { "messageId": "c13754fd-xxxx-xxxx-xxxx-0b63abaac0e4", "webhookId": "9cd4163f-xxxx-xxxx-xxxx-61206810c8ce", "webhook": { "webhook": "payout.update", "object_payload": { "payouts": [ { "payoutId": "1234567", "payoutTag": "", "payoutStatus": "PENDING", "payoutTypeId": "1", "payoutType": "Credit Transfer", "walletId": "54321", "payoutDate": "2024-09-30", "walletEventName": "Wallet 319158", "walletAlias": "wallet-319158-59f0d43680747", "userLastname": "", "userFirstname": "", "userId": "987654", "bankaccountId": "0", "beneficiaryId": "456789", "uniqueMandateReference": "", "bankaccountIBAN": "FR3140031000010000393123456", "label": "", "amount": "10.69", "currency": "EUR", "partnerFee": "0", "createdDate": "2024-09-30 10:36:57", "modifiedDate": "2024-11-01 10:34:12", "virtualIbanId": null, "virtualIbanReference": null, "codeStatus": "160014", "informationStatus": "Virement sortant envoyé en compensation, en attente de l'accusé de réception", "supportingFileLink": "", "endToEndId": null, "reasonCode": null, "reasonDescription": null, "metadata": null, "totalRows": 1 } ] }, "object_id": "19673123", "object": "payout", "webhook_created_at": 17304536521193, "webhook_id": "9cd4163f-xxxx-xxxx-xxxx-61206810c8ce", "object_payload_signature": "9/LLDq1yrJCvjm4QyP0F4vA6XXBKFT9QSvoAUoA1IBs=" }, "clientId": "12345" } ``` ::: #### Validated ::: code-group ```json [JSON] { "messageId": "17f6cb9a-xxxx-xxxx-xxxx-9404a161b12c", "webhookId": "42b2183a-xxxx-xxxx-xxxx-38ed1949c7f9", "webhook": { "webhook": "payout.update", "object": "payout", "object_id": "19673327", "object_payload": { "payouts": [ { "payoutId": "123456", "payoutTag": "", "payoutStatus": "VALIDATED", "payoutTypeId": "1", "payoutType": "Credit Transfer", "walletId": "12345", "bankaccountId": "0", "beneficiaryId": "98765", "endToEndId": null, "uniqueMandateReference": null, "label": "", "payoutDate": "2024-11-01", "amount": "10.69", "currency": "EUR", "partnerFee": "0", "createdDate": "2024-09-30 10:36:57", "modifiedDate": "2024-11-01 12:29:31", "walletEventName": "Wallet 319158", "walletAlias": "wallet-319158-59f0d43680747", "userLastname": "", "userFirstname": "", "userId": "708922", "bankaccountIBAN": null, "virtualIbanId": null, "virtualIbanReference": null, "codeStatus": "160004", "informationStatus": "Envoyé en banque", "supportingFileLink": "", "reasonCode": "", "reasonDescription": "", "totalRows": 1 } ] }, "webhook_created_at": 17304605714246, "webhook_id": "42b2183a-xxxx-xxxx-xxxx-38ed1949c7f9", "object_payload_signature": "IveNdWaxRQEk9hvQCfwTguAXXXXs1F3knlTm+ohwXx8=" }, "clientId": "12345" } ``` ::: ### `payout.cancel` ::: code-group ```json [JSON] { "messageId": "b34b2bd9-xxxx-xxxx-xxxx-744643027cc7", "webhookId": "859077ee-xxxx-xxxx-xxxx-66de5bf7c8ba", "webhook": { "webhook": "payout.cancel", "object": "payout", "object_id": "99975645", "object_payload": { "payouts": [ { "payoutId": "123456", "payoutTag": "", "payoutStatus": "CANCELED", "payoutTypeId": "1", "payoutType": "Credit Transfer", "walletId": "987654", "bankaccountId": "0", "beneficiaryId": "456789", "endToEndId": null, "uniqueMandateReference": null, "label": "", "payoutDate": "0000-00-00", "amount": "1000.00", "currency": "EUR", "partnerFee": "0", "createdDate": "2024-11-01 23:54:30", "modifiedDate": "2024-11-01 23:58:03", "walletEventName": "Wallet", "walletAlias": "wallet-66cd835xxe4be", "userLastname": "", "userFirstname": "", "userId": "87652436", "bankaccountIBAN": null, "virtualIbanId": null, "virtualIbanReference": null, "codeStatus": "160006", "informationStatus": "Annulé par le User", "supportingFileLink": "", "reasonCode": "", "reasonDescription": "", "totalRows": 1 } ] }, "webhook_created_at": 17305018831485, "webhook_id": "859077ee-xxxx-xxxx-xxxx-66de5bf7c8ba", "object_payload_signature": "fmxqIvroNav1gly0SWomkKxxxDRWQ8y+WVke30EOzA=" }, "clientId": "12345" } ``` ::: ### `transaction.create` ::: code-group ```json [JSON] { "messageId": "3aab4601-xxxx-xxxx-xxxx-199f0d1379e0", "webhookId": "aace45a4-xxxx-xxxx-xxxx-6c00c3213e2d", "webhook": { "webhook": "transaction.create", "object": "transaction", "object_id": "858804036", "object_payload": { "transactions": [ { "transactionId": "12345", "walletDebitId": "654321", "walletCreditId": "9", "transactionType": "Payout", "foreignId": "098765", "name": "name", "description": "Virement 19673327", "valueDate": "2024-11-01", "executionDate": "2024-11-01", "amount": "10.69", "walletDebitBalance": "0.00", "walletCreditBalance": "0.00", "currency": "EUR", "createdDate": "2024-11-01 12:29:31" } ] }, "webhook_created_at": 17304605712375, "webhook_id": "aace45a4-xxxx-xxxx-xxxx-6c00c3213e2d", "object_payload_signature": "IV15tQ5GG6FyMRF5tgNbt0Lsssss0eV+1YCu+u3TZv08=" }, "clientId": "12345" } ``` ::: ### `payoutRefund.create` ::: code-group ```json [JSON] { "messageId": "6913bf25-xxxx-xxxx-xxxx-e0505cd8d363", "webhookId": "b212c94d-xxxx-xxxx-xxxx-4c503f28c9ca", "webhook": { "webhook": "payoutRefund.create", "object_payload": { "payoutRefunds": [ { "id": "12345", "codeStatus": 790001, "informationStatus": "PENDING", "payoutId": "987654", "payoutRefundTag": "", "requestAmount": "43.20", "requestCurrency": "EUR", "requestComment": "", "reasonCode": "AC01", "refundAmount": "", "refundCurrency": "", "refundDate": "", "refundComment": "", "createdDate": "2024-10-01 10:30:23", "modifiedDate": "", "negativeResponseReasonCode": "" } ] }, "object_id": "9876", "object": "payoutRefund", "webhook_created_at": 17277669265064, "webhook_id": "b212c94d-xxxx-xxxx-xxxx-4c503f28c9ca", "object_payload_signature": "XCKBNNMlLK/UY+XMd39xxxEQpTZ7UKwQHXo5E5Sz1ks=" }, "clientId": "12345" } ``` ::: ### `payoutRefund.update` ::: code-group ```json [JSON] { "messageId": "02e2fd0c-xxxx-xxxx-xxxx-a2792b5c87de", "webhookId": "31f0e3bf-xxxx-xxxx-xxxx-ea7324c67545", "webhook": { "webhook": "payoutRefund.update", "object_payload": { "payoutRefunds": [ { "id": "12345", "codeStatus": 790003, "informationStatus": "VALIDATED", "payoutId": "987664", "payoutRefundTag": "", "requestAmount": "43.20", "requestCurrency": "EUR", "requestComment": "", "reasonCode": "AC01", "refundAmount": "43.20", "refundCurrency": "EUR", "refundDate": "2024-10-01", "refundComment": "", "createdDate": "2024-10-01 10:30:23", "modifiedDate": "2024-10-01 10:30:23", "negativeResponseReasonCode": "" } ] }, "object_id": "7654", "object": "payoutRefund", "webhook_created_at": 17277669265803, "webhook_id": "31f0e3bf-xxxx-xxxx-xxxx-ea7324c67545", "object_payload_signature": "kw90uW6/raDwMRrBIwiD9F7qY9xxx8O8eiLgZsqLQxQ=" }, "clientId": "12345" } ``` ::: ### `payoutRefund.cancel` ::: code-group ```json [JSON] { "messageId": "a5f6f11e-xxxx-xxxx-xxxx-aea9ca60e864", "webhookId": "7337ec42-xxxx-xxxx-xxxx-731227c91cd6", "webhook": { "webhook": "payoutRefund.cancel", "object_payload": { "payoutRefunds": [ { "id": "12345", "codeStatus": 790002, "informationStatus": "CANCELED", "payoutId": "987654", "payoutRefundTag": "", "requestAmount": "20.00", "requestCurrency": "EUR", "requestComment": "", "reasonCode": "FRAD", "refundAmount": "0.00", "refundCurrency": "EUR", "refundDate": "2024-11-20 09:15:29", "refundComment": "LEGL - ATR053/RECALLSCT-1111111", "createdDate": "2024-10-28 16:36:59", "modifiedDate": "2024-11-20 09:15:29", "negativeResponseReasonCode": "LEGL" } ] }, "object_id": "68833", "object": "payoutRefund", "webhook_created_at": 17320905292189, "webhook_id": "7337ec42-xxxx-xxxx-xxxx-731227c91cd6", "object_payload_signature": "Uo9ogL6r5CSiLTy5iUsm0xxx5DqY0JSLZoo6oqj1BA=" }, "clientId": "12345" } ``` ::: ## SCTE Inst. webhooks Find below the series of webhooks you may receive during the processing of an emitted instant SEPA Credit Transfer. ### `payout.create` ::: code-group ```json [JSON] { "messageId": "b4d2f1a8-7c39-5bd6-9e84-af0521d8c6e2", "webhookId": "fc28eba5-3a67-489d-b1f5-7c9a4e2d8f3b", "webhook": { "webhook": "payout.create", "object_payload": { "payouts": [ { "payoutId": "23bcd9f1-8e5a-4d7c-96b3-45f2a1c8d7e9", "payoutTag": "", "payoutStatus": "PENDING", "payoutTypeId": "3", "payoutType": "Instant Credit Transfer", "walletId": "3600677", "payoutDate": "2024-11-21 10:37:01", "walletEventName": "Event_test", "walletAlias": "event-test-673efef123318", "userLastname": "Oak", "userFirstname": "Alex", "userId": "101121231", "bankaccountId": "", "beneficiaryId": "12345", "uniqueMandateReference": "", "bankaccountIBAN": "FR7616798000010000360055555", "label": "", "amount": "20.00", "currency": "EUR", "partnerFee": "0", "createdDate": "2024-11-21 10:37:01", "modifiedDate": "", "virtualIbanId": null, "virtualIbanReference": null, "codeStatus": "160001", "informationStatus": "PENDING", "supportingFileLink": "", "endToEndId": "23bcd9f18e5a4d7c96b345f2123457e9", "reasonCode": "", "reasonDescription": "", "metadata": null, "totalRows": 0 } ] }, "object_id": "23bcd9f1-8e5a-4d7c-96b3-45f2a1c8d7e9", "object": "payout", "webhook_created_at": 17321818239625, "webhook_id": "fc28eba5-3a67-489d-b1f5-7c9a4e2d8f3b", "object_payload_signature": "7KuqFc+ZTYxZz7BufoYkN1nrG3kP/qGoekmFaV/1dFE=" }, "clientId": "12345" } ``` ::: ### `payout.update` ::: code-group ```json [JSON] { "messageId": "a1b2c3d4-e5f6-50g7-8h9i-j0k1l2m3n4o5", "webhookId": "b2c3d4e5-f6g7-4h8i-9j0k-l1m2n3o4p5q6", "webhook": { "webhook": "payout.update", "object_payload": { "payouts": [ { "payoutId": "c3d4e5f6-g7h8-4i9j-0k1l-m2n3o4p5q6r7", "payoutTag": "", "payoutStatus": "VALIDATED", "payoutTypeId": "3", "payoutType": "Instant Credit Transfer", "walletId": "7654321", "payoutDate": "2024-11-21 10:37:01", "walletEventName": "Event_test", "walletAlias": "event-test-123abcdef4567", "userLastname": "Oak", "userFirstname": "Alex", "userId": "987654321", "bankaccountId": "", "beneficiaryId": "246810", "uniqueMandateReference": "", "bankaccountIBAN": "FR7612345678901234567890123", "label": "", "amount": "20.00", "currency": "EUR", "partnerFee": "0", "createdDate": "2024-11-21 10:37:01", "modifiedDate": "2024-11-21 10:37:05", "virtualIbanId": null, "virtualIbanReference": null, "codeStatus": "160004", "informationStatus": "VALIDATED", "supportingFileLink": "", "endToEndId": "d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9", "reasonCode": "", "reasonDescription": "", "metadata": null, "totalRows": 0 } ] }, "object_id": "e5f6g7h8-i9j0-4k1l-m2n3-o4p5q6r7s8t9", "object": "payout", "webhook_created_at": 17321818259045, "webhook_id": "f6g7h8i9-j0k1-4l2m-n3o4-p5q6r7s8t9u0", "object_payload_signature": "9ezRxcdRKT3KwqfJNDNBXHoeUacVWbaHa8VWwPABM7k=" }, "clientId": "123456" } ``` ::: ### `transaction.create` ::: code-group ```json [JSON] { "messageId": "a1b2c3d4-e5f6-5g7h-8i9j-k0l1m2n3o4p5", "webhookId": "b2c3d4e5-f6g7-4h8i-9j0k-l1m2n3o4p5q6", "webhook": { "webhook": "transaction.create", "object_payload": { "transactions": [ { "transactionId": "7891234", "walletDebitId": "4500789", "walletCreditId": "9", "transactionType": "payout SCTE instant", "foreignId": "8765", "name": "c3d4e5f6-g7h8-4i9j-0k1l-m2n3o4p5q6r7", "description": "ip c3d4e5f6-g7h8-4i9j-0k1l-m2n3o4p5q6r7", "valueDate": "2024-11-21", "executionDate": "2024-11-21", "amount": "20.00", "walletDebitBalance": "181.25", "walletCreditBalance": "0.00", "currency": "EUR", "createdDate": "2024-11-21 10:37:05" } ] }, "object_id": "7891234", "object": "transaction", "webhook_created_at": 17321818258386, "webhook_id": "d4e5f6g7-h8i9-4j0k-l1m2-n3o4p5q6r7s8", "object_payload_signature": "R7bXmPq9Yz2AxCvNwDfEhGjKlMnOpQrStUvWxYz1234=" }, "clientId": "12345" } ``` ::: ### `payoutRefund.create` ::: code-group ```json [JSON] { "messageId": "a1b2c3d4-e5f6-5g7h-8i9j-k0l1m2n3o4p5", "webhookId": "b2c3d4e5-f6g7-4h8i-9j0k-l1m2n3o4p5q6", "webhook": { "webhook": "payoutRefund.create", "object_payload": { "payoutRefunds": [ { "id": "c3d4e5f6-g7h8-4i9j-0k1l-m2n3o4p5q6r7", "codeStatus": 790001, "informationStatus": "PENDING", "payoutId": "d4e5f6g7-h8i9-4j0k-l1m2-n3o4p5q6r7s8", "payoutRefundTag": "test", "requestAmount": "20.00", "requestCurrency": "EUR", "requestComment": "", "reasonCode": "DUPL", "refundAmount": "20.00", "refundCurrency": "EUR", "refundDate": "", "refundComment": "", "createdDate": "2024-11-21 10:44:21", "modifiedDate": "", "negativeResponseReasonCode": "" } ] }, "object_id": "e5f6g7h8-i9j0-4k1l-m2n3-o4p5q6r7s8t9", "object": "payoutRefund", "webhook_created_at": 17321822620807, "webhook_id": "f6g7h8i9-j0k1-4l2m-n3o4-p5q6r7s8t9u0", "object_payload_signature": "aBcDeFgHiJkLmNoPqRsTuVwXyZ1234567890AbCdEf=" }, "clientId": "123456" } ``` ::: ### `payoutRefund.update` ::: code-group ```json [JSON] { "messageId": "a1b2c3d4-e5f6-5g7h-8i9j-k0l1m2n3o4p5", "webhookId": "b2c3d4e5-f6g7-4h8i-9j0k-l1m2n3o4p5q6", "webhook": { "webhook": "payoutRefund.update", "object_payload": { "payoutRefunds": [ { "id": "c3d4e5f6-g7h8-4i9j-0k1l-m2n3o4p5q6r7", "codeStatus": 790003, "informationStatus": "VALIDATED", "payoutId": "d4e5f6g7-h8i9-4j0k-l1m2-n3o4p5q6r7s8", "payoutRefundTag": "test", "requestAmount": "20.00", "requestCurrency": "EUR", "requestComment": "", "reasonCode": "DUPL", "refundAmount": "20.00", "refundCurrency": "EUR", "refundDate": "", "refundComment": "", "createdDate": "2024-11-21 10:44:21", "modifiedDate": "", "negativeResponseReasonCode": "" } ] }, "object_id": "e5f6g7h8-i9j0-4k1l-m2n3-o4p5q6r7s8t9", "object": "payoutRefund", "webhook_created_at": 17321822644721, "webhook_id": "f6g7h8i9-j0k1-4l2m-n3o4-p5q6r7s8t9u0", "object_payload_signature": "aBcDeFgHiJkLmNoPqRsTuVwXyZ1234567890AbCdEf=" }, "clientId": "123456" } ``` ::: ### `payoutRefund.cancel` ::: code-group ```json [JSON] { "messageId": "a7b3c9d1-e2f4-5g6h-8i9j-k0l1m2n3o4p5", "webhookId": "b8c9d0e1-f2g3-4h5i-6j7k-l8m9n0p1q2r3", "webhook": { "webhook": "payoutRefund.cancel", "object_payload": { "payoutRefunds": [ { "id": "c1d2e3f4-g5h6-7i8j-9k0l-m1n2o3p4q5r6", "codeStatus": 790002, "informationStatus": "CANCELED", "payoutId": "d2e3f4g5-h6i7-8j9k-0l1m-n2o3p4q5r6s7", "payoutRefundTag": "", "requestAmount": "10.00", "requestCurrency": "EUR", "requestComment": "", "reasonCode": "TECH", "refundAmount": "10.00", "refundCurrency": "EUR", "refundDate": "", "refundComment": "", "createdDate": "2024-10-21 19:02:12", "modifiedDate": "", "negativeResponseReasonCode": "AC06" } ] }, "object_id": "e3f4g5h6-i7j8-9k0l-1m2n-o3p4q5r6s7t8", "object": "payoutRefund", "webhook_created_at": 17295301355064, "webhook_id": "f4g5h6i7-j8k9-0l1m-2n3o-p4q5r6s7t8u9", "object_payload_signature": "G7YQwz3Xn1mF9bV5cR8tL6pK2jH4dS0aE6uI7yO3fA8=" }, "clientId": "12345" } ``` ::: ## SCTR webhooks Find below the series of webhooks you may receive during the processing of a received SEPA Credit Transfer. ### `payin.create` ::: code-group ```json [JSON] { "messageId": "02e3c6b4-xxxx-xxxx-xxxx-99025662153a", "webhookId": "3ae934ad-xxxx-xxxx-xxxx-c26e1a545415", "webhook": { "webhook": "payin.create", "object_payload": { "payins": [ { "payinId": "123456", "payinTag": "", "walletId": "11530716", "userId": "8103200", "paymentMethodId": "20", "messageToUser": "", "subtotalItems": "13.00", "subtotalServices": "0.00", "subtotalTax": "0.00", "amount": "13.00", "currency": "EUR", "createdDate": "2024-11-19 10:01:13", "walletEventName": "Main wallet", "walletAlias": "main-wallet-63b33xxee1061", "userFirstname": "Alex", "userLastname": "Oak", "payinStatus": "PENDING", "codeStatus": "140001", "informationStatus": "", "refundAmount": null, "ibanFullname": "Tree Cie", "DbtrIBAN": "FR52219440000XXXXXX", "ibanBic": "MPAYFRP1XXX", "ibanTxEndToEndId": "8d03d882fc744ae69420cxcvb1f7f94d", "ibanTxId": "2432360481234511", "forwardUrl": null, "paymentAcceptedUrl": null, "paymentRefusedUrl": null, "paymentWaitingUrl": null, "paymentExceptionUrl": null, "paymentCanceledUrl": null, "payinDate": "0000-00-00", "mandateId": "0", "creditorName": "Alex Oak", "creditorAddressLine": "116 Willow road", "creditorCountry": "FR", "creditorIban": "FR7616798000010002222271616", "creditorBIC": "TRZOFR21XXX", "virtualIbanId": null, "virtualIbanReference": null, "additionalData": "", "ibanId": "be667e072f2b7112490560c0e1236544e51d93db", "totalRows": 1, "paymentHtml": null } ] }, "object_id": "31964985", "object": "payin", "webhook_created_at": 17320068736433, "webhook_id": "3ae934ad-xxxx-xxxx-xxxx-c26e1a545415", "object_payload_signature": "yRo0000000000000000000000000000000000" }, "clientId": "12345" } ``` ::: ### `payin.update` ::: code-group ```json [JSON] { "messageId": "25df01f7-xxxx-xxxx-xxxx-5e4f4af4216c", "webhookId": "39e99ce0-xxxx-xxxx-xxxx-29a43039bb84", "webhook": { "webhook": "payin.update", "object_payload": { "payins": [ { "payinId": "123456", "payinTag": "", "walletId": "321654", "userId": "987456", "paymentMethodId": "20", "messageToUser": "", "subtotalItems": "36.72", "subtotalServices": "0.00", "subtotalTax": "0.00", "amount": "36.72", "currency": "EUR", "createdDate": "2024-11-21 09:20:55", "walletEventName": "Main Wallet", "walletAlias": "main-wallet-64123ffd0a7e7", "userFirstname": "Alex ", "userLastname": "Oak", "payinStatus": "VALIDATED", "codeStatus": "140005", "informationStatus": "", "refundAmount": null, "ibanFullname": "ALEX OAK", "DbtrIBAN": "ES96123456123456686249", "ibanBic": "CAIXESBBXXX", "ibanTxEndToEndId": "NOTPROVIDED", "ibanTxId": "A2141TI999999999", "forwardUrl": null, "paymentAcceptedUrl": null, "paymentRefusedUrl": null, "paymentWaitingUrl": null, "paymentExceptionUrl": null, "paymentCanceledUrl": null, "payinDate": "0000-00-00", "mandateId": "0", "creditorName": "ALEX OAK", "creditorAddressLine": "3 CALLE DES LOS ARBOLES", "creditorCountry": "ES", "creditorIban": "FR761679800001000123655555", "creditorBIC": "TRZOFR21XXX", "virtualIbanId": null, "virtualIbanReference": null, "additionalData": "", "ibanId": "b47dc58116105724f666d70c7777777b5b3dc510", "totalRows": 1, "paymentHtml": null } ] }, "object_id": "31989128", "object": "payin", "webhook_created_at": 17321772560387, "webhook_id": "39e99ce0-xxxx-xxxx-xxxx-29a43039bb84", "object_payload_signature": "yRo0000000000000000000000000000000000" }, "clientId": "12345" } ``` ::: ### `payin.cancel` ::: code-group ```json [JSON] { "webhook": "payin.cancel", "object": "payin", "object_id": "12345", "object_payload": { "payins": [ { "payinId": "12345", "payinTag": "", "walletId": "8766543", "userId": "09876123", "payinStatus": "CANCELED", "paymentMethodId": "20", "messageToUser": "", "subtotalItems": "0.00", "subtotalServices": "0.00", "subtotalTax": "0.00", "amount": "101.25", "currency": "EUR", "createdDate": "2025-03-06 09:48:46", "walletEventName": "Main account", "walletAlias": "main-account-67c9616de90b8", "userFirstname": "Alex", "userLastname": "Oak", "codeStatus": "140004", "informationStatus": "", "refundAmount": null, "ibanFullname": null, "DbtrIBAN": null, "ibanBic": null, "ibanTxEndToEndId": null, "ibanTxId": null, "forwardUrl": null, "paymentAcceptedUrl": null, "paymentRefusedUrl": null, "paymentWaitingUrl": null, "paymentExceptionUrl": null, "paymentCanceledUrl": null, "payinDate": "0000-00-00", "mandateId": "0", "creditorName": null, "creditorAddressLine": null, "creditorCountry": null, "creditorIban": null, "creditorBIC": null, "virtualIbanId": null, "virtualIbanReference": null, "additionalData": "", "ibanId": "8e5522e9ccd084d54ef7b897af495xxx333ca617c", "totalRows": 1 } ] }, "webhook_created_at": 17412509271748, "webhook_id": "47186faa-xxxx-xxxx-xxxx-fb7a1d5e62a1", "object_payload_signature": "y+ZUmlX2OxPBVf2lkuQgjDnxo/LVIpZNgMx1zG0sPlQ=" } ``` ::: ### `transaction.create` ::: code-group ```json [JSON] { "messageId": "b3b8b5d1-xxxx-xxxx-xxxx-ea6759eb35ff", "webhookId": "095a10c0-xxxx-xxxx-xxxx-a1e224e5065e", "webhook": { "webhook": "transaction.create", "object_payload": { "transactions": [ { "transactionId": "123456789", "walletDebitId": "9", "walletCreditId": "654123", "transactionType": "Payin", "foreignId": "987456321", "name": "5555555", "description": "sctr id 55555", "valueDate": "2024-11-19", "executionDate": "2024-11-19", "amount": "13.00", "walletDebitBalance": "0.00", "walletCreditBalance": "16.84", "currency": "EUR", "createdDate": "2024-11-19 10:01:13" } ] }, "object_id": "869988392", "object": "transaction", "webhook_created_at": 17320068737656, "webhook_id": "095a10c0-xxxx-xxxx-xxxx-a1e224e5065e", "object_payload_signature": "yRo0000000000000000000000000000000000" }, "clientId": "12345" } ``` ::: ### `sepa.return_sctr ` ::: code-group ```json [JSON] { "webhook": "sepa.return_sctr", "webhook_id": "4XXXXX", "object": "sepaSctr", "object_id": "5XXXXX", "object_payload": { "sepaSctrs": [ { "wallet_id": "2XXXX", "virtual_iban_id": null, "transaction_id": "010XXXXX", "interbank_settlement_amount": "48.10", "debitor_name": "SXXXXX", "debitor_address": "XXXXXXXXX ", "debitor_country": null, "creditor_name": "XXXX XXXX", "creditor_address": "XXXXXXXX ", "creditor_country": null, "unstructured_field": "XXXXXXX", "return_reason_code": "AC04" } ] }, "object_payload_signature": "yRo0000000000000000000000000000000000" } ``` ::: ### `recallR.need_response` ::: code-group ```json [JSON] { "webhook": "recallR.need_response", "webhook_id": "15000700", "object": "recallR", "object_id": "9", "object_payload": { "recallrs": [ { "id": 9, "cxl_id": "987", "status_id": 3, "status_label": "PENDING ANSWER REQUESTED", "reason_code": "TECH", // see available reasons in the Recall article "additional_information": null, "user_id": 1321404, "user_name": "XXXX", "user_status_id": 9, "wallet_id": 714744, // related wallet id "wallet_status_id": 5, "wallet_activation_date": "2020-10-30 00:00:00", "wallet_desactivation_date": null, "sctr_id": 397, // related SCTR id "sctr_tx_id": "pPgx9rB0RJFkJt5A", "sctr_amount": "3011.00", // related SCTR amount "sctr_currency": "EUR", "sctr_settelment_date": "2020-11-30 00:00:00", "sctr_dbtr_name": "Test name debitor", "received_date": null, "payinrefund_id": 3521 // related Payin created to block the Authorized Balance } ] } } ``` ::: ### `payinrefund.create` ::: code-group ```json [JSON] { "messageId": "4e3c1b82-xxxx-xxxx-xxxx-4435158fce0e", "webhookId": "a94927ca-xxxx-xxxx-xxxx-db6470df39c9", "webhook": { "webhook": "payinrefund.create", "object": "payinrefund", "object_id": "49338", "object_payload": { "payinrefunds": [ { "payinrefundId": "123456", "payinrefundTag": null, "payinrefundStatus": "PENDING", "walletId": "321654", "payinId": "897456", "payinrefundDate": "0000-00-00", "amount": "375.00", "currency": "EUR", "createdDate": "2024-11-20 13:20:40", "modifiedDate": "0000-00-00 00:00:00", "codeStatus": "170001", "informationStatus": "", "reasonTms": null, "totalRows": 1 } ] }, "webhook_created_at": 17321052400640, "webhook_id": "a94927ca-xxxx-xxxx-xxxx-db6470df39c9", "object_payload_signature": "yRo0000000000000000000000000000000000" }, "clientId": "12345" } ``` ::: ### `payinrefund.update` ::: code-group ```json [JSON] { "messageId": "a352c3dd-xxxx-xxxx-xxxx-9c6afd8e1e93", "webhookId": "fee81a6d-xxxx-xxxx-xxxx-30164466efcd", "webhook": { "webhook": "payinrefund.update", "object": "payinrefund", "object_id": "49334", "object_payload": { "payinrefunds": [ { "payinrefundId": "654789", "payinrefundTag": null, "payinrefundStatus": "VALIDATED", // or ACCEPTED "walletId": "123456", "payinId": "987456", "payinrefundDate": "0000-00-00", "amount": "4998.00", "currency": "EUR", "createdDate": "2024-11-19 16:20:40", "modifiedDate": "2024-11-20 05:15:21", "codeStatus": "170005", "informationStatus": "", "reasonTms": null, "totalRows": 1 } ] }, "webhook_created_at": 17320797217512, "webhook_id": "fee81a6d-xxxx-xxxx-xxxx-30164466efcd", "object_payload_signature": "yRo0000000000000000000000000000000000" }, "clientId": "12345" } ``` ::: ### `payinrefund.cancel` ::: code-group ```json [JSON] { "messageId": "ca8cc285-xxxx-xxxx-xxxx-9d306c98f20c", "webhookId": "a55090df-xxxx-xxxx-xxxx-ceb1f1db34dc", "webhook": { "webhook": "payinrefund.cancel", "object": "payinrefund", "object_id": "49261", "object_payload": { "payinrefunds": [ { "payinrefundId": "1234556", "payinrefundTag": null, "payinrefundStatus": "CANCELED", "walletId": "654321", "payinId": "987654", "payinrefundDate": "0000-00-00", "amount": "2900.00", "currency": "EUR", "createdDate": "2024-11-18 11:22:09", "modifiedDate": "2024-11-18 17:11:26", "codeStatus": "170003", "informationStatus": "", "reasonTms": null, "totalRows": 1 } ] }, "webhook_created_at": 17319462865000, "webhook_id": "a55090df-xxxx-xxxx-xxxx-ceb1f1db34dc", "object_payload_signature": "yRo0000000000000000000000000000000000" }, "clientId": "12345" } ``` ::: ## SCTR Inst. webhooks Find below the series of webhooks you may receive during the processing of a received instant SEPA Credit Transfer. ### `payin.create` ::: code-group ```json [JSON] { "messageId": "a7b8c9d0-e1f2-53g4-h5i6-j7k8l9m0n1o2", "webhookId": "b8c9d0e1-f2g3-4h5i-6j7k-l8m9n0p1q2r3", "webhook": { "webhook": "payin.create", "object_payload": { "payins": [ { "payinId": "c9d0e1f2-g3h4-556i-j7k8-l9m0n1o2p3q4", "payinTag": "DEUTDEFF24112100009683400000001|DEUTDEFF211124108223410000001", "walletId": "15678901", "userId": "3", "payinStatus": "VALIDATED", "paymentMethodId": "27", "messageToUser": "BLG-PRDLE12PYFZZ", "subtotalItems": "", "subtotalServices": "", "subtotalTax": "", "amount": "50.00", "currency": "EUR", "createdDate": "2024-11-21 09:59:18", "walletEventName": "MAIN", "walletAlias": "main-670c0f8f3b968", "userFirstname": "Alex", "userLastname": "Oak", "codeStatus": "140005", "informationStatus": "", "refundAmount": "", "ibanFullname": "ALEX OAK", "DbtrIBAN": "DE39350400380605802800", "ibanBic": "DEUTDEFFXXX", "ibanTxEndToEndId": "d1e2f3g4h5i6j7k8l9m0n1o2p3q4r5s6", "ibanTxId": "DEUTDEFF211124108223410000001", "forwardUrl": "", "paymentAcceptedUrl": "", "paymentRefusedUrl": "", "paymentWaitingUrl": "", "paymentExceptionUrl": "", "paymentCanceledUrl": "", "payinDate": "", "mandateId": "0", "creditorName": "ALEX OAK", "creditorAddressLine": "", "creditorCountry": "", "creditorIban": "FR7616798000010001567890167", "creditorBIC": "TRZOFR21XXX", "virtualIbanId": "", "virtualIbanReference": "", "additionalData": "", "ibanId": "e1f2g3h4i5j6k7l8m9n0o1p2q3r4s5t6u7v8w9x0" } ] }, "object_id": "c9d0e1f2-g3h4-556i-j7k8-l9m0n1o2p3q4", "object": "payin", "webhook_created_at": 17321795586841, "webhook_id": "b8c9d0e1-f2g3-4h5i-6j7k-l8m9n0p1q2r3", "object_payload_signature": "GjGCKYuskU/RqEHjohfK/CXa9GIzz6zbOduaf3fIJeI=" }, "clientId": "373826" } ``` ::: ### `transaction.create` ::: code-group ```json [JSON] { "messageId": "a7b8c9d0-e1f2-53g4-h5i6-j7k8l9m0n1o2", "webhookId": "b8c9d0e1-f2g3-4h5i-6j7k-l8m9n0p1q2r3", "webhook": { "webhook": "transaction.create", "object_payload": { "transactions": [ { "transactionId": "871387155", "walletDebitId": "9", "walletCreditId": "16423670", "transactionType": "Payin", "foreignId": "7156118", "name": "c9d0e1f2-g3h4-5i6j-k7l8-m9n0p1q2r3s4", "description": "Payment SCTr inst c9d0e1f2-g3h4-5i6j-k7l8-m9n0p1q2r3s4", "valueDate": "2024-11-21", "executionDate": "2024-11-21", "amount": "50.00", "walletDebitBalance": "0.00", "walletCreditBalance": "50.00", "currency": "EUR", "createdDate": "2024-11-21 09:59:18" } ] }, "object_id": "871387155", "object": "transaction", "webhook_created_at": 17321795585276, "webhook_id": "d0e1f2g3-h4i5-6j7k-8l9m-n0p1q2r3s4t5", "object_payload_signature": "AbCdEfGhIjKlMnOpQrStUvWxYz1234567890aBcDeF=" }, "clientId": "12345" } ``` ::: ### `sepaSctrInst.reject_sctr_inst` ::: code-group ```json [JSON] { "webhook":"sepaSctrInst.reject_sctr_inst", "webhook_id":"15000700", "object":"sepaSctrInst", "object_id":"f51d656c-1919-57ae-8416-760165f4c2c6", "object_payload": { "sepaSctrInsts": [ { "walletId":"379601", "messageId":"aad9cfef-575e-11ec-b2f5-9a8693508ae7", // "transactionEndToEndId":"032021153210009999999999", // "transactionId":"04322NA202169999999999", // "settlementAmount":3225.55, // "settlementDate":"2021-06-02", "debtorIban":"FR7630003043220008888888888", // "debtorBic":"SOGEFRPP", // "debitorName":"DEBTOR NAME", "debitorAddressLine":"DEBTOR ADDRESS", "debitorCountry":"", "creditorIban":"FR7616798000010009999999999", // "creditorBIC":"TRZOFR21", // "creditorName":"REDACTED", // "creditorAddressLine":null, // "creditorCountry":null, // "remittanceInformation":"", "return_reason_code":"AC04", // specifies the rejection reason "virtualIbanId":null, "virtualIbanReference":null, } ] } } ``` ::: ### `separecallsctrinst.reception` ::: code-group ```json [JSON] { "webhook": "separecallsctrinst.reception", "object_payload": { "recallId": "dea754f8-f8bd-4b80-a3f6-42f72d1234681", // Unique identifier (UUID) "creationDateTime": "2024-07-24T08:48:35.426Z", // Date and time of recall request by the originator "statusLabel": "PENDING", // Status of the recall request. "cxlId": "BIPT242060212345772", // Unique and unambiguous identifier of a cancellation request, defined by the assigner "reasonCode": "FRAD", // Can be: FRAD, TECH, DUPL, AM09, CUST, AC03 "additionalInformation": "", "sctrDbtrIBAN": "FR7613485008000416151234543", // IBAN of the debtor "sctrDbtrBIC": "CEPAFRXXXX", // BIC of the debtor "sctrDbtrName": "ALEX OAK", // Name of the debtor "sctrDbtrAddress": "15 Rosewood road", // Postal address of the debtor "sctrDbtrCountry": "FR", "sctrCdtrIBAN": "FR7616798000010001571234573", // IBAN of the creditor "sctrCdtrBIC": "TRZOFR21XXX", // BIC of the creditor "sctrCdtrName": "CHRIS PINE", // Name of the creditor "sctrCdtrAddress": "23 Willow lane", // Postal address of the debtor "sctrCdtrCountry": "", "sctrMsgId": "1720396248916-7-1481234", // MsgId of the original transaction "sctrInstrId": "2000000028fe81000712345404d5347", // Instruction Id of the original transaction "sctrTxId": "BIPT241900200XXXXX6", // Transaction Id of the original transaction "sctrE2EID": "Bankwire of A OAK", // End To end id of the original transaction "sctrAmount": "500.00", // Amount of the original transaction "sctrSettlementDate": "2024-07-08T00:00:00Z", // Settlement date of the original transaction "sctrRemittanceInformation": "", // Remittance information of the original transaction "sctrTrzId": "80adc46a-3367-5c35-b53c-ef7b852345e6", // Unique identifier of the original transaction "sctrExternalId": "SG24190IP0ZDFP7324190IP0ZDF345000", // ttis payment id of the original transaction "clientId": 12345, "userId": 1234567, "walletId": 123456789, // Wallet that received the of the original transaction "receivedDate": "2024-07-24T08:48:36Z", // Date and time of the recall request reception "payinRefundId": 0, "responseType": -1, // Response to the recall request. Can be: 1 (positive) or 0 (negative) "negativeResponseReasonCode": "", // Reason code of the response to the pending recall request received. Can be: AC04, AM04, ARDT, CUST, LEGL, NOAS, NOOR "negativeResponseAdditionalInformation": "", // Available for reason code LEGL, FRAD and AC03 "responseComment": "", // To be used by your teams or Treezor's "automaticResponse": "pendingRecall", // Yes or No. To flag when a response was given automatically "createdDate": "2024-07-24T08:48:36Z", // Date and time at which the recall was created in Treezor database "updatedDate": null }, "object_id": "dea754f8-f8bd-4b80-a3f6-42f7xxxx2681", "object": "separecallsctrinst", "webhook_created_at": 17218109179396, "webhook_id": "5adf9788-3521-43aa-a954-abxxxxeb84c2", "object_payload_signature": "rKf2lk5vZ5bHmEx9Ix/wtrDosvpi8Gdxxxxay2hq4Ds=" } ``` ::: ### `payinrefund.create` ::: code-group ```json [JSON] { "messageId": "a7b8c9d0-e1f2-53g4-h5i6-j7k8l9m0n1o2", "webhookId": "b8c9d0e1-f2g3-4h5i-6j7k-l8m9n0p1q2r3", "webhook": { "webhook": "payinrefund.create", "object_payload": { "payinrefunds": [ { "payinrefundId": "c9d0e1f2-g3h4-5i6j-k7l8-m9n0p1q2r3s4", "payinrefundTag": null, "payinrefundStatus": "PENDING", "walletId": "15678901", "payinId": "d1e2f3g4-h5i6-7j8k-9l0m-n1o2p3q4r5s6", "payinrefundDate": "2024-11-18 09:07:11", "amount": "11000.00", "currency": "EUR", "createdDate": "2024-11-18 09:07:09", "modifiedDate": "", "codeStatus": "170001", "informationStatus": "Demande de remboursement de participation", "reasonTms": null } ] }, "object_id": "e3f4g5h6-i7j8-9k0l-1m2n-o3p4q5r6s7t8", "object": "payinrefund", "webhook_created_at": 17319208317442, "webhook_id": "f5g6h7i8-j9k0-1l2m-3n4o-p5q6r7s8t9u0", "object_payload_signature": "AbCdEfGhIjKlMnOpQrStUvWxYz1234567890aBcDeF=" }, "clientId": "12345" } ``` ::: ### `payinrefund.update` ::: code-group ```json [JSON] { "messageId": "a7b8c9d0-e1f2-53g4-h5i6-j7k8l9m0n1o2", "webhookId": "b8c9d0e1-f2g3-4h5i-6j7k-l8m9n0p1q2r3", "webhook": { "webhook": "payinrefund.update", "webhook_created_at": 17316611944485, "object_id": "c9d0e1f2-g3h4-5i6j-k7l8-m9n0p1q2r3s4", "object": "payinrefund", "object_payload": { "payinrefunds": [ { "payinrefundId": "c9d0e1f2-g3h4-5i6j-k7l8-m9n0p1q2r3s4", "payinrefundTag": null, "payinrefundStatus": "VALIDATED", // or ACCEPTED "payinrefundDate": "2024-11-15 09:59:53", "walletId": "16732256", "payinId": "d1e2f3g4-h5i6-7j8k-9l0m-n1o2p3q4r5s6", "amount": "10", "currency": "EUR", "createdDate": "2024-11-15 09:59:53", "modifiedDate": "2024-11-15 09:59:53", "profile": "00001344879", "userId": "101923629", "codeStatus": "150125", "informationStatus": "Refunded", "reasonTms": null } ] }, "webhook_id": "b8c9d0e1-f2g3-4h5i-6j7k-l8m9n0p1q2r3", "object_payload_signature": "AbCdEfGhIjKlMnOpQrStUvWxYz1234567890aBcDeF=" }, "clientId": "12345" } ``` ::: ### `payinrefund.cancel` ::: code-group ```json [JSON] { "messageId": "a7b8c9d0-e1f2-53g4-h5i6-j7k8l9m0n1o2", "webhookId": "b8c9d0e1-f2g3-4h5i-6j7k-l8m9n0p1q2r3", "webhook": { "webhook": "payinrefund.cancel", "object_payload": { "payinrefunds": [ { "payinrefundId": "c9d0e1f2-g3h4-5i6j-k7l8-m9n0p1q2r3s4", "payinrefundTag": "", "payinrefundStatus": "REJECTED", "walletId": "15678901", "payinId": "d1e2f3g4-h5i6-7j8k-9l0m-n1o2p3q4r5s6", "payinrefundDate": "2024-09-23 11:23:37", "amount": "128.45", "currency": "EUR", "createdDate": "2024-09-23 11:23:35", "modifiedDate": "", "codeStatus": "170004", "informationStatus": "Annulé par un opérateur", "reasonTms": "" } ] }, "object_id": "e3f4g5h6-i7j8-9k0l-1m2n-o3p4q5r6s7t8", "object": "payinrefund", "webhook_created_at": 17271728589428, "webhook_id": "f5g6h7i8-j9k0-1l2m-3n4o-p5q6r7s8t9u0", "object_payload_signature": "AbCdEfGhIjKlMnOpQrStUvWxYz1234567890aBcDeF=" }, "clientId": "12345" } ``` ::: --- --- url: /guide/transfers/faking-operations.md description: >- Learn how to simulate payins and payouts within the Sandbox environment for development and API integration testing. --- # Emulation Emulation features are only available in `Sandbox` [environment](/guide/api-basics/environments). **Tip – You can also rely on webhooks** For operations that cannot be emulated in the Sandbox, [webhook examples](events) are provided. ## SEPA Direct Debit reception (SDDR) SDDR Core can be emulated by using the dedicated [`/simulation/payout-sddr`](/api-reference/api-endpoints.html#tag/Payouts/SimulateSDDR){target="\_self"} endpoint. This is a Payout operation; simulating an SDDR debits the Treezor Wallet. ### Parameters | Attribute | Type | Description | | --- | --- | --- | | `debitorIban` | string | IBAN or Virtual IBAN of the debited Wallet. | | `amount` | integer | Amount of the SDD (will be divided by the `nbTxs`). **Decimal amounts are not supported.** | | `typeSDD` | string | Either `CORE` (default) or `B2B`. | | `typeReject` | string | The type of error returned if the SDDR fails. Can be: `rejected` (default), `returned`, `refunded`, or `today` (specifies that we want the SDDR to be executed today). | | `sci` | string | The SEPA Credit Identifier of the user. In the case of simulation, this defaults to a random string. | | `nbTxs` | integer | The number of transactions for the SDD. Defaults to `1`. | | `mandateId` | integer | The Beneficiary Mandate unique identifier. This field is optional. | | `executeAfterParse` | integer | When set to `1`, launch the job to execute pending SDDRs on the due date (must be used in combination with `typeReject` = `today`). | ### Request ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/simulation/payout-sddr' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "amount": "26", "debitorIban": "FR7616798000010000071474474", "sci": "FR44ZZZ332801", "typeSDD":"CORE", "typeReject":"today", "executeAfterParse":1 } ``` ::: Response example (if `executeAfterParse` is set to `1`): ::: code-group ```json [JSON] { "messages":[ "[Simulation] [POST /payoutSddr] CORE SDDR created", "[Simulation] batchExecuteSddr() launched" ] } ``` ::: ## SEPA Direct Debit emission (SDDE) SDDE can be emulated by using the [`/v1/payins`](/api-reference/api-endpoints.html#tag/Payins/postPayin){target="\_self"} endpoint. This is a Payin operation; simulating an SDDE credits the Treezor Wallet. **Prerequisites – SDDE emulation requires a KYC-validated legal entity with:** * **A signed [Mandate](/guide/transfers/mandates)** – Must be the correct [`sddType`](mandates#mandatory-parameters). * **A SEPA Creditor Identifier (SCI)** – To enable a SCI, please contact your *Treezor Account Manager*. ### Mandatory parameters | Attribute | Type | Description | | --- | --- | --- | | `walletId` | integer | The unique identifier of the Wallet to credit. | | `paymentMethodId` | integer | Set this value to `21` for crediting funds in Sandbox only. | | `amount` | number | The amount to credit. Must end with `1.25` to emulate a `VALIDATED` result. | | `currency` | string | The currency of the transfer. Must be `EUR`. | | `mandateId` | integer | The unique identifier of the [Mandate](/guide/transfers/mandates). | ### Request ::: code-group <<< @/guide/transfers/snippets/create\_payin.bash \[CURL] ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "walletId":"{walletId}", "userId":"{userId}", "paymentMethodId":21, "amount":1.25, "currency":"EUR", "mandateId":"{mandateId}" } ``` ::: Returns the Payin object. ::: code-group ```json [JSON] { "payins": [ { "payinId": "", "payinTag": "", "payinStatus": "", "codeStatus": "", "informationStatus": "", "walletId": "", // id of the wallet to credit "userId": "", "amount": "", "currency": "", [...] // some attributes are hidden } ] } ``` ::: **Note – Funds availability latency** Funds are usually available in the Wallet within 5 minutes following the request. ## SEPA Credit Transfer reception (SCTR) SCTR can be emulated by using the dedicated [`/simulation/payin-sct`](/api-reference/api-endpoints.html#tag/Payins/simulateSctReception){target="\_self"} endpoint. This is a Payin operation; simulating an SCTR credits the Treezor Wallet. ### Parameters The following parameters are required. | Attribute | Type | Description | | --- | --- | --- | | `iban` | string | The IBAN of the Wallet to credit. | | `amount` | integer | The amount to credit. Decimal amounts are not supported. | ### Request Endpoint: [`/simulation/payin-sct`](/api-reference/api-endpoints.html#tag/Payins/simulateSctReception){target="\_self"} ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/simulation/payin-sct' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}` ::: code-group ```json [JSON] { "iban":"FR7616798000010001726649397", "amount": 20 } ``` ::: Returns the id of the SCTR, its `txId` (transaction id) and its `payinId`. ::: code-group ```json [JSON] { "sctrs": [ { "id": 10022, "txId": "xxCN7gLRpqmjS6p5", "payinId": 1234567, "returnReasonCode": null } ] } ``` ::: **Tip – The `returnReasonCode` provides more information** The `returnReasonCode` can inform you of [the reason](/guide/transfers/error-codes#sct-reason-codes) for a rejection, in which case the `payinId` will be `null`. ### Accepted SCTR * The IBAN must be valid **and**, * The [Wallet](/guide/wallets/introduction) must be validated **and**, * The [User](/guide/users/introduction) must have its [KYC validated](/guide/user-verification/introduction) **except** when the [SCTR is used as an additional vigilance measure](/guide/user-verification/introduction#additional-vigilance-measures). ### Refused SCTR * The IBAN can be erroneous (you can for example use `FR76169999999999999999999`) **or**, * The User [KYC status](/guide/user-verification/introduction) can be `NONE`/`PENDING` **or**, * The [Wallet](/guide/wallets/modification#delete) status can be `PENDING` or `CANCELED` ### Legacy SCTR Emulation can also be achieved using the same procedure as for [SDDE](#sepa-direct-debit-emission-sdde), by changing the `paymentMethodId` to `20`. ## Instant SEPA Credit Transfer reception [SCTR Inst](/guide/transfers/credit-transfer-inst#emitted-instant-credit-transfers-sctr-inst) can be emulated by using the dedicated [`/simulation/sct-inst/payin`](/api-reference/api-endpoints.html#tag/Payins/simulateSctInstReception){target="\_self"} endpoint. ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/simulation/sct-inst/payin' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "name":"M. Firstname LASTNAME", // Name of the recipient (User) "bic":"TRZOFR21XXX", // BIC of the recipient (User) "iban":"FR76167980019999999999999", // IBAN of the recipient (Wallet) "currency":"EUR", "amount":10.0 } ``` ::: Returns the `paymentID` and `sctInstID`. ::: code-group ```json [JSON] { "sctInstID": "2333c7a8-25c5-54ff-a06e-7ed2bd8c2f66", "paymentID": "RECEPTION_6cde3d9f-58d2-11ec-8593-86285561c46d" } ``` ::: The `sctInstID` can be used to retrieve the payin using the [`/v1/payins/{sctInstId}`](/api-reference/api-endpoints.html#tag/payin/getPayins){target="\_self"} endpoint. ### Accepted SCTR Inst For an emulated SCTR Inst to be **accepted**: * The IBAN must be valid **and**, * The [Wallet](/guide/wallets/introduction) must be validated. ### Refused SCTR Inst The emulated SCTR Inst may be **refused** if: * The IBAN is erroneous (e.g., you can use `FR76169999999999999999999`), or * The [Wallet](/guide/wallets/modification#delete) status can be `PENDING` or `CANCELED` * The SCTR Inst amount can be greater that €10,000 in a B2C context or greater than €50,000 in a B2B context In which case, you receive a [`sepaSctrInst.reject_sctr_inst`](events#sepa-reject-sctr-inst) webhook. ## SCTR Recalls To initiate an SCTR Recall, you can use the following request. **Prerequisites – You need an SCTR first** Use the [`/simulation/payin-sct`](/api-reference/api-endpoints.html#tag/Payins/simulateSctReception){target="\_self"} endpoint to create a valid [SCTR emulation](#sepa-credit-transfer-reception-sctr) beforehand. ### Parameters | Attribute | Type | Description | | --- | --- | --- | | `cxlId` | string | The unique identifier of the Recall. We recommend that you use the SCTR's id. | | `statusId` | integer | The status of the recall resource. For simulation purposes, you must set this to `2` (PENDING\_PAYIN\_REFUND\_CREATED). | | `sctrId` | integer | The SCTR's id as provided by the [SCTR simulation endpoint](/guide/transfers/faking-operations#sctr). | | `txId` | string | The `txId` value returned by the [SCTR simulation endpoint](/guide/transfers/faking-operations#sctr). | | `reasonCode` | string | Reason code of the recall request [see available values](/guide/transfers/sepa-recalls#types-of-recalls-reasoncode). | | `createPayinRefund` | boolean | Creates a payinrefund resource and receives the corresponding webhooks if set to `true`. | ### Request ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/simulation/recall-r' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "cxlId": "401", "statusId": 2, "sctrId": 401, "txId": "401", "reasonCode": "TECH", "createPayinRefund": true } ``` ::: Returns the `id` of the Recall. ::: code-group ```json [JSON] { "recalls": { "id": 10 } } ``` ::: ## SCTR Inst Recalls To initiate an SCTR Inst Recall, you can use the following request. **Prerequisites – You need an SCTR Inst first** A valid SCTR Inst must [have been emulated](#instant-sepa-credit-transfer-reception) beforehand. ### Parameters | Attribute | Type | Description | | --- | --- | --- | | `sctInstId` | string | The SCTR Inst's id as provided by the [SCTR Inst simulation endpoint](/guide/transfers/faking-operations#sctr-inst). | | `demandDate` | string | The date of the recall request. | | `reasonCode` | string | The reason code of the recall request [see available values](/guide/transfers/sepa-recalls#types-of-recalls-reasoncode). | | `additionalInformation` | string | Information on top of the recall reason code you want to receive (can only be used with `reasonCode` of type `FRAD`). | ### Request ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/simulation/sct-inst/recall' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is a `{payload}` example: ::: code-group ```json [JSON] { "sctInstId": "1380aeca-963b-5497-aef4-a9532086653c", "demandDate": "2022-11-24", "reasonCode": "FRAD", "additionalInformation": "" } ``` ::: Returns the `id` for the Recall: ::: code-group ```json [JSON] { "sctInstId": "c8457258-b18c-5647-9950-9ba3c99a9543", "recallrId": "f3f6a9c8-2f4b-5906-9ac7-2d908d04b681" } ``` ::: ## SEPA Credit Transfer emission (SCTE) Emulating SCTE in Sandbox only requires you use your regular payout endpoint. Any amount will return a `PENDING` status (and the Wallet Balance will be updated the day after around 10:30AM Paris time), except for amounts ending in `1.25`. For the later, retrieving the Payout shortly after will return a `VALIDATED` result, and the debited Wallet Balance is updated at the same time. ### Mandatory parameters | Attribute | Type | Description | | --- | --- | --- | | `walletId` | integer | The unique identifier of the debited Wallet. | | `beneficiaryId` | integer | The unique identifier of the Beneficiary of the Transfer. You must have created the [Beneficiary](./beneficiaries) object beforehand. | | `amount` | number | The amount of the credit transfer. Must end with `1.25` for a `VALIDATED` result. | | `currency` | string | The currency of the credit transfer. Must be `EUR`. | ### Request ::: code-group <<< @/guide/transfers/snippets/create\_payout.bash\[CURL] ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "walletId":{walletId}, "beneficiaryId":{beneficiaryId}, "amount":11.25, "currency":"EUR" } ``` ::: Returns a Payout object. ::: code-group ```json [JSON] { "payouts": [ { "payoutId": 191317, "payoutTag": "", "payoutStatus": "PENDING", "payoutTypeId": 1, "payoutType": "Credit Transfer", "walletId": 2548369, "payoutDate": "0000-00-00", "walletEventName": "wallet transfer", "walletAlias": "wallet-transfer-65844f47b3766", "userFirstname": "Alex", "userLastname": "Oak", "userId": 4248201, "beneficiaryId": 411981, "uniqueMandateReference": "", "bankaccountIBAN": "", "label": "payout_test", "amount": "11.25", "currency": "EUR", "partnerFee": "0", "createdDate": "2024-04-03 12:06:48", "modifiedDate": "0000-00-00 00:00:00", "virtualIbanId": null, "virtualIbanReference": null, "codeStatus": "160001", "informationStatus": "Demande de remboursement saisie", "supportingFileLink": "", "endToEndId": null, "reasonCode": null, "reasonDescription": null, "metadata": null, "totalRows": 1 } ] } ``` ::: You can use the [`/v1/payouts/{payoutId}`](/api-reference/api-endpoints.html#tag/Payouts/getPayout){target="\_self"} endpoint to view the updated payout with its `VALIDATED` status. ::: code-group ```json [JSON] {6,28} { "payouts": [ { "payoutId": 191317, "payoutTag": "", "payoutStatus": "VALIDATED", "payoutTypeId": 1, "payoutType": "Credit Transfer", "walletId": 2548369, "payoutDate": "2024-04-03", "walletEventName": "wallet transfer", "walletAlias": "wallet-transfer-65844f47b3766", "userFirstname": "Alex", "userLastname": "Oak", "userId": 4248201, "beneficiaryId": 411981, "uniqueMandateReference": "", "bankaccountIBAN": "", "label": "payout_test", "amount": "11.25", "currency": "EUR", "partnerFee": "0", "createdDate": "2024-04-03 12:06:48", "modifiedDate": "2024-04-03 12:07:06", "virtualIbanId": null, "virtualIbanReference": null, "codeStatus": "160005", "informationStatus": "Remboursement par virement Validé", "supportingFileLink": "", "endToEndId": null, "reasonCode": null, "reasonDescription": null, "metadata": null, "totalRows": 1 } ] } ``` ::: ## Instant SEPA Credit Transfer emission (SCTE Inst) Emulating SCTE in Sandbox only requires you use your regular payout endpoint. Prerequisites: * User must be KYC validated. * Beneficiary `userId` and Wallet owner must be the same User. * Necessary funds must be available on the debited Wallet. ### Mandatory parameters | Attribute | Type | Description | | --- | --- | --- | | `payoutTypeId` | integer | Must be `3` for an SCTE Inst. | | `walletId` | integer | The unique identifier of the debited Wallet. | | `beneficiaryId` | integer | The unique identifier of the Beneficiary of the transfer. You must have created the [Beneficiary](./beneficiaries) object beforehand. | | `amount` | number | The amount of the credit transfer, which value defines the result of the emulation: `VALIDATED` – Provide an amount stricly **below** `1000.00``CANCELED` – Provide an amount stricly **above** `1000.00` | | `currency` | string | The currency of the credit transfer. Must be `EUR`. | ### Request ::: code-group <<< @/guide/transfers/snippets/create\_payout.bash\[CURL] ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "payoutTypeId":3, "walletId":{walletId}, "beneficiaryId":{beneficiaryId}, "amount":800.00, "currency":"EUR" } ``` ::: Returns a Payout object. ::: code-group ```json [JSON] { "payouts": [ { "payoutId": "8929329c-b4a5-4bb9-b792-0e9e9d98xxxa", "payoutTag": "", "payoutStatus": "PENDING", "payoutTypeId": 3, "payoutType": "Instant Credit Transfer", "walletId": 3059736, "payoutDate": "2024-06-26 10:15:17", "walletEventName": "Name of the Wallet", "walletAlias": "name-of-the-wallet-667bcd66d546b", "userFirstname": "Alex", "userLastname": "Oak.validated", "userId": 965725, "beneficiaryId": 40963, "uniqueMandateReference": "", "bankaccountIBAN": "FR761679800001000030XXXXXX3", "label": "", "amount": "800.00", "currency": "EUR", "partnerFee": "0", "createdDate": "2024-06-26 10:15:17", "modifiedDate": "", "virtualIbanId": null, "virtualIbanReference": null, "codeStatus": "160001", "informationStatus": "PENDING", "supportingFileLink": "", "endToEndId": "8929329cb4a54bb9b7920e9xxx8891a", "reasonCode": null, "reasonDescription": null, "metadata": null, "totalRows": null } ] } ``` ::: You can use the [`/v1/payouts/{payoutId}`](/api-reference/api-endpoints.html#tag/Payouts/getPayout){target="\_self"} endpoint to view the updated payout with its `VALIDATED` status. ::: code-group ```json [JSON] {6,28} { "payouts": [ { "payoutId": "8929329c-b4a5-4bb9-b792-0e9e9d98xxxa", "payoutTag": "", "payoutStatus": "VALIDATED", "payoutTypeId": 3, "payoutType": "Instant Credit Transfer", "walletId": 3059736, "payoutDate": "2024-06-26 10:15:17", "walletEventName": "Name of the Wallet", "walletAlias": "name-of-the-wallet-667bcd66d546b", "userFirstname": "Alex", "userLastname": "Oak.validated", "userId": 965725, "beneficiaryId": 40963, "uniqueMandateReference": "", "bankaccountIBAN": "FR761679800001000030XXXXXX3", "label": "", "amount": "800.00", "currency": "EUR", "partnerFee": "0", "createdDate": "2024-06-26 10:15:17", "modifiedDate": "", "virtualIbanId": null, "virtualIbanReference": null, "codeStatus": "160004", "informationStatus": "VALIDATED", "supportingFileLink": "", "endToEndId": "8929329cb4a54bb9b7920e9xxx8891a", "reasonCode": null, "reasonDescription": null, "metadata": null, "totalRows": null } ] } ``` ::: --- --- url: /guide/dashboard/transfers.md description: >- Let your team provide support regarding your end users operations (payouts, wallet-to-wallet) using the Treezor Dashboard. --- # Transfers In the Dashboard, funds can be moved from a Wallet in the following ways: * [**Payouts**](#transfers-from-wallet-to-external-bank-account) – Transfers money from the Wallet to an external bank account (i.e., [Beneficiary](beneficiaries)) * [**Wallet-to-Wallet**](#transfers-from-wallet-to-wallet) – Transfers money from one [Wallet](wallets) to another in your Treezor ecosystem ## Transfers from Wallet to external Bank Account From the [*Wallets*](./wallets) tab, you can transfer funds from one wallet to an external bank account through the SEPA network. You must create a [Beneficiary](beneficiaries) prior to making this type of transfer. In the *Profile Boards* view, once the user is selected, select the *Wallets* tab and click the "Make a payment" button to select the "Create payout" option. The *Payout* popup is displayed for you to: * Select the source wallet (belongs to the currently selected user) * Select the target external bank account (Beneficiary) * Define the payout type, amount, and reason * Add a supporting file if needed. **Information – Instant Payments are not available by default** Please contact Treezor if you're interested in this feature. Once done, you may click on the "Preview Payout" button. Make sure all the information is relevant before confirming. **Tip – Internal reasons picklist available on request** A custom picklist can be configured, for categorizing the transfers, or identifying they've been emitted from the Dashboard, for instance. This picklist relies on the `payoutTag` field. Contact Treezor for more information. ## Transfers from Wallet to Wallet From the *Wallets* tab, you can transfer funds from one wallet to another. This operation is instantaneous. In the *Profile Boards* view, once the user is selected, select the *Wallets* tab and click the "Make a payment" button to select the "Wallet-to-Wallet Transfer" option. The *Wallet to Wallet Transfer* popup is displayed for you to: * Select the source wallet (belongs to the currently selected user) * Select the target wallet (either from favorites, currently selected user, or by search) * Define the transfer amount and reason * Make sure all the information is relevant prior to confirming the transfer When all the steps are completed, a popup indicates the operation is successful and the corresponding operation is displayed in the *Operations* section of both Wallets. --- --- url: /api-reference/postman.md description: >- Quickly get started with the Treezor API using our Postman Collection, to explore common API use cases for rapid integration understanding. This guide explains how to set up and use the collection, providing step-by-step instructions and the official link. --- # Documentation Postman Collection Treezor Documentation has its own [Postman Collection](https://learning.postman.com/docs/collections/collections-overview/) to help you understand how to use the Treezor API. This collection is: * **Connect-oriented** – It doesn’t take into account legacy API services. * **Sandbox-oriented** – It doesn’t provide production-only features. * **Non-exhaustive** – It’s only meant to get you started, with key endpoints and attributes. Before using the collection, ensure you already have the credentials for your Sandbox from Treezor. If you’re new to Postman, the sections below may help you get started: * [Fork the collection](#fork-the-collection) * [Set up your environment](#set-up-your-environment) * [Pull the collection changes](#pull-collection-changes) **Reading – Postman Documentation** The [Postman Documentation](https://learning.postman.com/docs/introduction/overview/) may provide more information on how to take advantage of the collection! ## Fork the collection By clicking on the Run with Postman button, you’ll be invited to fork the collection. It consists of duplicating the collection to play with it without impacting the source collection and other users. **Tip – Watch collection** Make sure you tick the “Watch original collection” checkbox. You’ll be notified when the collection is updated so you can pull the changes into your collection. Once the copy of the collection is available in your Postman workspace, you may set up your environment. ## Set up your environment You need to create an environment to start using your collection. In the Postman Environment section, you can either: * Create a new environment, in which you will add the relevant variables listed below, or * Import [this environment](https://www.postman.com/restless-crater-540300/workspace/treezor-doc-public/environment/35140470-eec9e7d5-c109-4d8e-97c7-d399260a7561?action=share\&creator=35140470) that you can download. It contains empty variables for you to fill in. Then enter your environment URL and your credentials sent to you by Treezor in the variables: | Variable | Description | | --- | --- | | `baseUrl` | Your Sandbox environment URL. | | `client_id` | Your API authentication credentials provided to you by Treezor. | | `client_secret` | Your API authentication credentials provided to you by Treezor. | In addition, the following variables are necessary for some features: | Variable | Description | | --- | --- | | `cardPrint` | If you plan on issuing cards, you will need this value provided upon setting up your Card Program. | | `tariffId` | The fees applied to the Wallet, as defined by your contract with Treezor. This field is usually required to create Wallets but may have a default value set by Treezor. | As you use the collection, the environment variables will automatically be defined by the scripts included in each request. ## Structure of the collection The collection is organized for you to navigate through the various illustrated uses. | Folder | Description | | --- | --- | | **Authentication** | Contains the `POST /oauth/token` endpoint for you to generate the access token necessary to authenticate all the Treezor API requests. We made it easily accessible as your token expires after 1 hour. | | **Starter endpoints** | Contains some of the essential endpoints to get started with the Treezor API. For more advanced features, please contact Treezor or refer to the API Documentation. | | **Quickstart** | Contains the endpoints for the [Quickstart](/guide/overview/tinker.html) article, guiding you through your first testing of the Treezor API. | | **Use cases** | Contains the endpoints to run the step-by-step guides available in the [Use Cases](/use-cases/prerequisites/introduction) section of the documentation. | ## Pull collection changes The collection is constantly updated as the Treezor API and the documentation evolve. If you’re watching the collection, you may have received a notification in Postman or an email indicating that the collection has been modified. To retrieve the modification, you may use the pull changes command for your collection. A tab opens in your forked collection to import all the changes made to your collection. More information is available in the [Postman Documentation](https://learning.postman.com/docs/collaborating-in-postman/using-version-control/forking-elements/#pull-updates-from-a-parent-element). --- --- url: /api-reference/api-endpoints.md description: >- The complete Treezor API Reference. Explore all endpoints with detailed specifications, request/response examples, and schema definitions in an interactive OpenAPI 3.0.1 powered interface. --- --- --- url: /api-reference/pci-dss-dev.md description: >- The PCI DSS Treezor API Reference. Explore PCI DSS-specific endpoints with detailed specifications, request/response examples, and schema definitions in an interactive OpenAPI 3.0.1 powered interface. --- --- --- url: /guide/cards/modification.md description: >- Technical guide for updating cards via the Treezor API, including blocking, PIN & CVV management, and dynamic card account selection. Includes required parameters, request structure, and response examples. --- # Modification In addition to the card life cycle and [options](./restrictions-limits), Treezor offers a series of features to manage your cards on the day-to-day basis. | Feature | Description | | --- | --- | | **Lock/Unlock** | Ability to update the card status, hence unlocking and locking the card temporarily or permanently. | | **PIN code** | Ability to change the PIN code, or unlock a card which has been blocked due to erroneous PIN code entries. | | **CVV unlock** | Ability to unblock a card which has been blocked due to erroneous CVV entries. | | **Regeneration** | Ability to recreate the virtual card image if your branding changes for instance. | ## Block a card If you suspect fraud or misuse, the API allows you to temporarily or permanently block a card, effective immediately. This feature can also be used with special cards that must expire at a specific date (such as a one-year valid gift card). You will have to lock the card on the expiration day. **Best practice – Allowing your end users to block their cards** While blocking a card temporarily is no issue, you should not allow end users to permanently block their cards without thorough confirmation steps (as fees may apply to issue a replacement card). ### Lock status parameter The `lockStatus` integer allows you to update `statusCode` attribute of a Card. They are mapped as follows. **Caution – A lost or stolen card can't be reactivated** If the cardholder wants a replacement card, a new card will have to be ordered. ### Request example You can use the following request to change the card lock status, with the `cardId` as a path parameter and the `lockStatus` in the body. ::: code-group ```bash [CURL] curl -X PUT '{baseUrl}/v1/cards/{cardId}/LockUnlock' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' ``` ::: Here is an example of `{payload}` which specifies a `lockStatus` of `2`, declaring the Card as `LOST` and locking it permanently. ::: code-group ```json [JSON] { "lockStatus":2 } ``` ::: Returns a Card object, with a `statusCode` attribute set to either `UNLOCK`, `LOCK`, `LOST`, `STOLEN`, `DESTROYED`, `CUSTOM_LOCK`. ::: code-group ```json [JSON] {7,9} { "cardId": 999894949, "userId": 100198207, "walletId": 2728965, "publicToken": "105603415", "cardTag": "string", "statusCode": "LOST", "isLive": 1, "cancellationNumber": "19532590" // Generated for LOST & STOLEN Cards only // [...] some attributes are hidden } ``` ::: Although you provide the `lockStatus` as an integer, it is returned as a plaintext value. Treezor also sends a [`card.lockunlock`](./events#cardlockunlock) webhook. ## Card account selection For a given card, you can use a different Wallet for each transaction. This may prove particularly useful to centralize various services on a unique card. For instance, the same card could be used for employee benefits and food vouchers. **Configuration – Feature not enabled by default** Please contact Treezor to activate the Card account selection feature. Assigning the card to a Wallet can be done as often as you wish to, and either: * **[Manually](#manual-selection)** – The user chooses the Wallet to debit prior to the transaction. * **[Dynamically](#dynamic-selection)** – The [MDC](/guide/cards/transactions-rules-engine) or [external validation](/guide/cards/transactions-external-validation) feature selects the Wallet when the transaction is initiated. This feature is only compatible with the following [types of Wallet](/guide/wallets/introduction): `9`, `10`, `15`. **Information – The behavior is transparent in the transaction life cycle** Even if the wallet assigned to the card changes, the wallet of a given card transaction remains the same during the whole transaction life cycle. The debited wallet value is available in the `card.transaction` webhook. ### Manual selection In this case, the cardholder manually selects the Wallet to be debited before initiating the transaction. #### Parameters | Attribute | Type | Description | | --- | --- | --- | | `cardId` | query | The unique identifier of the card to assign. | | `walletId` | integer | The unique identifier of the wallet to which the card is to be assigned. The wallet must have the same `userId` value as the card if the `walletTypeId` is `9` or `10`. | #### Request example ::: code-group ```bash [CURL] curl -X PUT '{baseUrl}/v1/cards/{cardId}/assignWallet' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "walletId":123456 } ``` ::: Returns the Card object with the updated `walletId` value, and sends the [`card.assignwallet`](./events#card-assignwallet) webhook. ::: code-group ```json [JSON] {4} { "cardId": 999894949, "userId": 100198207, "walletId":123456, "publicToken": "105603415", "cardTag": "string", "statusCode": "UNLOCK", "isLive": 1, // [...] some attributes are hidden } ``` ::: ### Dynamic selection You can take advantage of the [Multi-Criteria Dynamic Card (MDC)](/guide/cards/transactions-rules-engine) or the [external validation](/guide/cards/transactions-external-validation) feature to automatically debit the relevant Wallet when a transaction is initiated. The steps are the following: 1. The User initiates a payment with their card. 2. The [Multi-Criteria Dynamic Card (MDC)](/guide/cards/transactions-rules-engine) rules engine or your [external validation](/guide/cards/transactions-external-validation) system determines the wallet to use. 3. The Wallet is debited by the card transaction. ### Specific cases #### Offline transactions When a transaction occurs offline, there is no information regarding the assigned Wallet yet. In that case, the last assigned Wallet is debited when using manual selection. When relying on MDC or external authorization for dynamic selection though, you can create rules for the relevant wallet to be selected for offline transactions. #### Recurring transactions For recurring transactions, the same Wallet is debited as the initial transaction. ## Change PIN If a Card is in the `UNLOCK` [status](#card-/guide/cards/introduction#card-status-statuscode) and not [PIN-locked](#unlock-pin), you can define its PIN code. There are 2 ways to proceed: | Context | Endpoint | Usage | | --- | --- | --- | | **[Without the previous PIN](#without-the-previous-pin)** | [`/v1/cards/{cardId}/setPIN`](/api-reference/api-endpoints.html#tag/Cards/setPin){target="\_self"}| Machine-oriented | | **[Requiring the previous PIN](#with-the-previous-pin)** | [`/v1/cards/{cardId}/changePIN`](/api-reference/api-endpoints.html#tag/Cards/changePin){target="\_self"} | End user-oriented | | Context | Endpoint | Usage | | --- | --- | --- | | **[Without the previous PIN](#without-the-previous-pin)** | [`/cards/{cardId}/setPIN`](/api-reference/pci-dss-dev.html#tag/Cards/putSetPin){target="\_self"}| Machine-oriented | | **[Requiring the previous PIN](#with-the-previous-pin)** | [`/cards/{cardId}/changePIN`](/api-reference/pci-dss-dev.html#tag/Cards/putChangePin){target="\_self"} | End user-oriented | Once set, you mustn't store the PIN code on your infrastructure. You cannot retrieve a PIN code using the Treezor API unless you have migrated to our [PCI DSS services](./pci-dss). In such case, you can use the [`/cards/{cardId}/pin`](/api-reference/pci-dss-dev.html#tag/Cards/getPIN){target="\_self"} endpoint. We recommend you let your end users choose their PIN code when ordering a new card. ### End user ATM action required When changing the PIN code via the API, there is no immediate way to relay the information to the physical card. **The cardholder must make a withdrawal or balance inquiry at an ATM** for the change to take effect. This method works even if the Card program doesn't include withdrawals. Indeed, a rejected withdrawal updates the card too. ### Without the previous PIN This is the initial situation upon Card creation. #### Parameters In addition to the `cardId` passed as a path parameter, the following parameters are required. | Attribute | Type | Description | | --- | --- | --- | | `newPIN` | string | The new PIN code of the card. Must be a string to allow for leading zeroes. | | `confirmPIN` | string | Confirmation of the new PIN code of the card. Must be a string to allow for leading zeroes. | #### Request example ::: code-group ```bash [CURL] curl -X PUT '{baseUrl}/v1/cards/{cardId}/setPIN' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "newPIN":"1234", "confirmPIN":"1234" } ``` ::: Returns a Card object and sends the [`card.setpin`](./events#card-setpin) webhook. ::: code-group ```json [JSON] { "cards": [ { "cardId": 999994169, "userId": 100642533, "walletId": 3151814, "walletCardtransactionId": 3159200, "mccRestrictionGroupId": 0, "merchantRestrictionGroupId": 0, "countryRestrictionGroupId": 0, "publicToken": "105501272", "cardTag": "black", "statusCode": "UNLOCK", "isLive": 0, "pinTryExceeds": 0, "maskedPan": "548821******6605", "embossedName": "ALEX OAK", "expiryDate": "2027-07-31", "CVV": "370", "startDate": "2024-07-24", "endDate": "0000-00-00", "countryCode": "FR", "currencyCode": "EUR", "lang": null, "deliveryTitle": "M", "deliveryLastname": "OAK", "deliveryFirstname": "ALEX", "deliveryAddress1": "07323 WOODLANE", "deliveryAddress2": "", "deliveryAddress3": "", "deliveryCity": "PARIS", "deliveryPostcode": "75017", "deliveryCountry": "FR", "mobileSent": "+336XXXXXXXX", "limitsGroup": "TRZ-VL-001", "permsGroup": "TRZ-CU-012", "cardDesign": "1234", "virtualConverted": 0, "physical": 0, "optionAtm": 0, "optionForeign": 1, "optionOnline": 1, "optionNfc": 1, "limitAtmYear": 0, "limitAtmMonth": 0, "limitAtmWeek": 2000, "limitAtmDay": 1000, "limitAtmAll": 0, "limitPaymentYear": 0, "limitPaymentMonth": 0, "limitPaymentWeek": 3000, "limitPaymentDay": 2000, "limitPaymentAll": 0, "paymentDailyLimit": 500.0, "totalAtmYear": 0, "totalAtmMonth": 0, "totalAtmWeek": null, "totalAtmDay": null, "totalAtmAll": 0, "totalPaymentYear": 0, "totalPaymentMonth": 0, "totalPaymentWeek": null, "totalPaymentDay": null, "totalPaymentAll": 0, "createdBy": 929252, "createdDate": "2024-07-24 11:13:15", "modifiedBy": 929252, "modifiedDate": "2024-09-13 15:13:26", "totalRows": null, "designCode": null, "cardLanguages": "", "eventName": "Name of the Wallet", "eventAlias": "name-of-the-wallet-669f4218dfbff", "restrictionGroupLimits": null, "cancellationNumber": "", "metadata": null, "renewalDate": null, "renewalType": null, "originalCardId": null, "logoId": "", "logoBackId": "", "packageId": "", "customizeInfo": "", "letterCustomizedInfo": "", "freeCustomizedInfo": "", "deliveryMethod": null, "pinMailer": null, "batchDeliveryId": null, "sendToParent": 0 } ] } ``` ::: #### Parameters In addition to the `cardId` passed as a path parameter, the following parameters are required. | Attribute | Type | Description | | --- | --- | --- | | `userId` | string | The unique identifier of the cardholder. | | `newPIN` | string | The new PIN code of the card. Must be a string to allow for leading zeroes. | | `confirmPIN` | string | Confirmation of the new PIN code of the card. Must be a string to allow for leading zeroes. | | `sca` | string | The `scaProof` (required if not in delegated mode). | #### Request example ::: code-group ```bash [CURL] curl -X PUT '{pciBaseUrl}/cards/{cardId}/setPIN' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "userId": "100642533", "newPIN":"1234", "confirmPIN":"1234", "sca": "eyJh_UxfQ.nNIH_n9kA" } ``` ::: Returns an HTTP 204 No Content and sends the [`card.setpin`](./events#card-setpin) webhook. #### Locked PIN error If the card is [PIN-locked](#unlock-pin) (`pinTryExceeds` value set to `1`), the request fails with a 400 HTTP status code and the following error. ::: code-group ```json [JSON] { "errors": [ { "type": "invalid_request", "code": "input_validation_error", "message": "Card blocked.", "docUrl": "https://docs.treezor.com/guide/api-basics/response-codes.html#error-attributes", "requestId": "20ba6d1c-f903-4ab8-918b-341ee13b59b8" } ] } ``` ::: You must [PIN Unlock](#unlock-pin) before setting the PIN code. ### With the previous PIN #### Parameters In addition to the `cardId` passed as a path parameter, the following parameters are required. | Attribute | Type | Description | | --- | --- | --- | | `currentPIN` | string | The current PIN code of the card. Must be a string to allow for leading zeroes. | | `newPIN` | string | The new PIN code of the card. Must be a string to allow for leading zeroes. | | `confirmPIN` | string | Confirmation of the new PIN code of the card. Must be a string to allow for leading zeroes. | #### Request example ::: code-group ```bash [CURL] curl -X PUT '{baseUrl}/v1/cards/{cardId}/ChangePIN' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "currentPIN": "4321", "newPIN":"1234", "confirmPIN":"1234" } ``` ::: Returns a Card object and sends the [`card.changepin`](./events#card-changepin) webhook. ::: code-group ```json [JSON] { "cards": [ { "cardId": 999994169, "userId": 100642533, "walletId": 3151814, "walletCardtransactionId": 3159200, "mccRestrictionGroupId": 0, "merchantRestrictionGroupId": 0, "countryRestrictionGroupId": 0, "publicToken": "105501272", "cardTag": "black", "statusCode": "UNLOCK", "isLive": 0, "pinTryExceeds": 0, "maskedPan": "548821******6605", "embossedName": "ALEX OAK", "expiryDate": "2027-07-31", "CVV": "370", "startDate": "2024-07-24", "endDate": "0000-00-00", "countryCode": "FR", "currencyCode": "EUR", "lang": null, "deliveryTitle": "M", "deliveryLastname": "OAK", "deliveryFirstname": "ALEX", "deliveryAddress1": "07323 WOODLANE", "deliveryAddress2": "", "deliveryAddress3": "", "deliveryCity": "PARIS", "deliveryPostcode": "75017", "deliveryCountry": "FR", "mobileSent": "+336XXXXXXXX", "limitsGroup": "TRZ-VL-001", "permsGroup": "TRZ-CU-012", "cardDesign": "1234", "virtualConverted": 0, "physical": 0, "optionAtm": 0, "optionForeign": 1, "optionOnline": 1, "optionNfc": 1, "limitAtmYear": 0, "limitAtmMonth": 0, "limitAtmWeek": 2000, "limitAtmDay": 1000, "limitAtmAll": 0, "limitPaymentYear": 0, "limitPaymentMonth": 0, "limitPaymentWeek": 3000, "limitPaymentDay": 2000, "limitPaymentAll": 0, "paymentDailyLimit": 500.0, "totalAtmYear": 0, "totalAtmMonth": 0, "totalAtmWeek": null, "totalAtmDay": null, "totalAtmAll": 0, "totalPaymentYear": 0, "totalPaymentMonth": 0, "totalPaymentWeek": null, "totalPaymentDay": null, "totalPaymentAll": 0, "createdBy": 929252, "createdDate": "2024-07-24 11:13:15", "modifiedBy": 929252, "modifiedDate": "2024-09-13 15:13:26", "totalRows": null, "designCode": null, "cardLanguages": "", "eventName": "Name of the Wallet", "eventAlias": "name-of-the-wallet-669f4218dfbff", "restrictionGroupLimits": null, "cancellationNumber": "", "metadata": null, "renewalDate": null, "renewalType": null, "originalCardId": null, "logoId": "", "logoBackId": "", "packageId": "", "customizeInfo": "", "letterCustomizedInfo": "", "freeCustomizedInfo": "", "deliveryMethod": null, "pinMailer": null, "batchDeliveryId": null, "sendToParent": 0 } ] } ``` ::: #### Parameters In addition to the `cardId` passed as a path parameter, the following parameters are required. | Attribute | Type | Description | | --- | --- | --- | | `userId` | string | The unique identifier of the cardholder. | | `currentPIN` | string | The current PIN code of the card. Must be a string to allow for leading zeroes. | | `newPIN` | string | The new PIN code of the card. Must be a string to allow for leading zeroes. | | `confirmPIN` | string | Confirmation of the new PIN code of the card. Must be a string to allow for leading zeroes. | | `sca` | string | The `scaProof` (required if not in delegated mode). | #### Request example ::: code-group ```bash [CURL] curl -X PUT '{pciBaseUrl}/cards/{cardId}/ChangePIN' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "userId": "100642533", "currentPIN": "4321", "newPIN":"1234", "confirmPIN":"1234", "sca": "eyJh_UxfQ.nNIH_n9kA" } ``` ::: Returns an HTTP 204 No Content and sends the [`card.changepin`](./events#card-changepin) webhook. #### Locked PIN error If the card is [PIN-locked](#unlock-pin) (`pinTryExceeds` value set to `1`), the request fails with a 400 HTTP status code and the following error. ::: code-group ```json [JSON] { "errors": [ { "type": "invalid_request", "code": "input_validation_error", "message": "Card blocked.", "docUrl": "https://docs.treezor.com/guide/api-basics/response-codes.html#error-attributes", "requestId": "20ba6d1c-f903-4ab8-918b-341ee13b59b8" } ] } ``` ::: You must [PIN Unlock](#unlock-pin) the card before changing the PIN code. ## Unlock PIN Entering 3 erroneous PIN codes in a row blocks the PIN and sets the `pinTryExceeds` to `1`. As the card is blocked on the server side, you can unblock it instantaneously using a dedicated endpoint. When unlocking a PIN, the PIN code remains unchanged. **Note – You can't change a locked PIN** If the PIN is blocked you **must** unlock the PIN before being able to [change it](#change-pin). ### Request example Only the `cardId` passed as a path parameter is required to use the following request. ::: code-group ```bash [CURL] curl -X PUT '{baseUrl}/v1/cards/{cardId}/UnblockPIN' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' ``` ::: Returns a Card object and sends a [`card.unblockpin`](./events#cardunblockpin) webhook with the `pinTryExceeds` parameter set to `0`. ::: code-group ```json [JSON] {15} { "cards": [ { "cardId": 999994169, "userId": 100642533, "walletId": 3151814, "walletCardtransactionId": 3159200, "mccRestrictionGroupId": 0, "merchantRestrictionGroupId": 0, "countryRestrictionGroupId": 0, "publicToken": "105501272", "cardTag": "black", "statusCode": "UNLOCK", "isLive": 0, "pinTryExceeds": 0, "maskedPan": "548821******6605", "embossedName": "ALEX OAK", "expiryDate": "2027-07-31", "CVV": "370", "startDate": "2024-07-24", "endDate": "0000-00-00", "countryCode": "FR", "currencyCode": "EUR", "lang": null, "deliveryTitle": "M", "deliveryLastname": "OAK", "deliveryFirstname": "ALEX", "deliveryAddress1": "07323 WOODLANE", "deliveryAddress2": "", "deliveryAddress3": "", "deliveryCity": "PARIS", "deliveryPostcode": "75017", "deliveryCountry": "FR", "mobileSent": "+336XXXXXXXX", "limitsGroup": "TRZ-VL-001", "permsGroup": "TRZ-CU-012", "cardDesign": "1234", "virtualConverted": 0, "physical": 0, "optionAtm": 0, "optionForeign": 1, "optionOnline": 1, "optionNfc": 1, "limitAtmYear": 0, "limitAtmMonth": 0, "limitAtmWeek": 2000, "limitAtmDay": 1000, "limitAtmAll": 0, "limitPaymentYear": 0, "limitPaymentMonth": 0, "limitPaymentWeek": 3000, "limitPaymentDay": 2000, "limitPaymentAll": 0, "paymentDailyLimit": 500.0, "totalAtmYear": 0, "totalAtmMonth": 0, "totalAtmWeek": null, "totalAtmDay": null, "totalAtmAll": 0, "totalPaymentYear": 0, "totalPaymentMonth": 0, "totalPaymentWeek": null, "totalPaymentDay": null, "totalPaymentAll": 0, "createdBy": 929252, "createdDate": "2024-07-24 11:13:15", "modifiedBy": 929252, "modifiedDate": "2024-09-13 15:13:26", "totalRows": null, "designCode": null, "cardLanguages": "", "eventName": "Name of the Wallet", "eventAlias": "name-of-the-wallet-669f4218dfbff", "restrictionGroupLimits": null, "cancellationNumber": "", "metadata": null, "renewalDate": null, "renewalType": null, "originalCardId": null, "logoId": "", "logoBackId": "", "packageId": "", "customizeInfo": "", "letterCustomizedInfo": "", "freeCustomizedInfo": "", "deliveryMethod": null, "pinMailer": null, "batchDeliveryId": null, "sendToParent": 0 } ] } ``` ::: ## Unlock CVV The Card [CVV](/guide/overview/glossary#card-verification-code-cvc) can get locked if the cardholder enters multiple times in a row an erroneous CVV while attempting an e-commerce payment. The number of attempts is configurable, and is usually set to 3 or 5. When this happens, the [`cardtransaction.create`](/guide/cards/events#declined-insufficient-funds) webhook contains an [`authorizationNote`](/guide/cards/authorization-notes) valued to `DR: CVC2 tries exceeded`. As the card is blocked on the server side, you can unblock it instantaneously using a dedicated endpoint. ::: code-group ```bash [CURL] curl -X PUT '{baseUrl}/v1/cards/{cardId}/unblockcvc2' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' ``` ::: It returns a 204 HTTP response with the following description: `successfully unblocked`. Also sends a [`card.unblockcvc2`](./events#card-unblockcvc2) webhook. **Tip – Unlocking only available on Connect** If you haven't migrated to [Connect](/guide/overview/getting-started#treezor-api), or if the feature is not yet available to you, you must [open a ticket](https://treezor.zendesk.com/hc/en-us/articles/4403978479634-How-to-create-a-Zendesk-ticket) to unlock a CVV. ## Unlock 3DS The [3DS](/guide/overview/glossary#_3d-secure-3ds) feature of a Card can get locked if the cardholder fails 3 times the 3DS authentication using One Time Password while attempting an e-commerce payment. When using the [Strong Customer Authentication](/guide/strong-customer-authentication/introduction) instead of One Time Password, a failure to authenticate doesn't increment the 3DS failure count and will not lock the 3DS feature. If the SCA feature [cannot be used](/guide/cards/transactions-authentication#payload) and the fallback to One Time Password via SMS is used, then a locking can still occur. To unlock the 3DS feature, you must [open a ticket](https://treezor.zendesk.com/hc/en-us/articles/4403978479634-How-to-create-a-Zendesk-ticket) as no API endpoint currently allows you to unlock the 3DS feature. ## Regenerate If your brand changes its graphical identity (e.g., new logo, colors, layout, etc.), you can ask Treezor to set up a new card design, and then re-generate Virtual Card images without altering their actual PAN, CVC, or expiration date. Endpoint: [`/v1/cards/{cardId}/Regenerate`](/api-reference/api-endpoints.html#tag/Cards/regenerateCard){target="\_self"} ::: code-group ```bash [CURL] curl -X PUT '{baseUrl}/v1/cards/{cardId}/Regenerate' \ --header 'Authorization: Bearer {accessToken}' ``` ::: Returns the Card object and sends a [`card.regenerate`](./events#cardregenerate) webhook. ::: code-group ```json [JSON] { "cards": [ { "cardId": 999994169, "userId": 100642533, "walletId": 3151814, "walletCardtransactionId": 3159200, "mccRestrictionGroupId": 0, "merchantRestrictionGroupId": 0, "countryRestrictionGroupId": 0, "publicToken": "105501272", "cardTag": "black", "statusCode": "UNLOCK", "isLive": 0, "pinTryExceeds": 0, "maskedPan": "548821******6605", "embossedName": "ALEX OAK", "expiryDate": "2027-07-31", "CVV": "370", "startDate": "2024-07-24", "endDate": "0000-00-00", "countryCode": "FR", "currencyCode": "EUR", "lang": null, "deliveryTitle": "M", "deliveryLastname": "OAK", "deliveryFirstname": "ALEX", "deliveryAddress1": "07323 WOODLANE", "deliveryAddress2": "", "deliveryAddress3": "", "deliveryCity": "PARIS", "deliveryPostcode": "75017", "deliveryCountry": "FR", "mobileSent": "+336XXXXXXXX", "limitsGroup": "TRZ-VL-001", "permsGroup": "TRZ-CU-012", "cardDesign": "1234", "virtualConverted": 0, "physical": 0, "optionAtm": 0, "optionForeign": 1, "optionOnline": 1, "optionNfc": 1, "limitAtmYear": 0, "limitAtmMonth": 0, "limitAtmWeek": 2000, "limitAtmDay": 1000, "limitAtmAll": 0, "limitPaymentYear": 0, "limitPaymentMonth": 0, "limitPaymentWeek": 3000, "limitPaymentDay": 2000, "limitPaymentAll": 0, "paymentDailyLimit": 500.0, "totalAtmYear": 0, "totalAtmMonth": 0, "totalAtmWeek": null, "totalAtmDay": null, "totalAtmAll": 0, "totalPaymentYear": 0, "totalPaymentMonth": 0, "totalPaymentWeek": null, "totalPaymentDay": null, "totalPaymentAll": 0, "createdBy": 929252, "createdDate": "2024-07-24 11:13:15", "modifiedBy": 929252, "modifiedDate": "2024-09-13 15:13:26", "totalRows": null, "designCode": null, "cardLanguages": "", "eventName": "Name of the Wallet", "eventAlias": "name-of-the-wallet-669f4218dfbff", "restrictionGroupLimits": null, "cancellationNumber": "", "metadata": null, "renewalDate": null, "renewalType": null, "originalCardId": null, "logoId": "", "logoBackId": "", "packageId": "", "customizeInfo": "", "letterCustomizedInfo": "", "freeCustomizedInfo": "", "deliveryMethod": null, "pinMailer": null, "batchDeliveryId": null, "sendToParent": 0 } ] } ``` ::: Endpoint: [`/cards/{cardId}/cardImage`](/api-reference/pci-dss-dev.html#tag/Cards/postCardImage){target="\_self"} ::: code-group ```bash [CURL] curl -X POST '{pciBaseUrl}/cards/{cardId}/cardImage' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "userId": "100642533" } ``` ::: Returns an HTTP 204 No Content if successful. --- --- url: /guide/users/modifications.md description: >- Technical guide for updating and deleting users via the Treezor API. Includes required parameters, request structure, and response examples. --- # Modification Users' declarative data evolve as they use your services. It's not uncommon to have to update the user's address or contact information for instance. **For [KYC-validated](/guide/user-verification/introduction) Users, most modifications trigger a new KYC review.** **Tip – Attribute updates that don't result in KYC review** `address3`, `phone`, `mobile`, `activityOutsideEu`, `economicSanctions`, `residentCountriesSanctions`, `involvedSanctions`, `timezone`. ## Updating Endpoint: [`/v1/users/{userId}`](/api-reference/api-endpoints.html#tag/Users/putUser){target="\_self"} ::: code-group <<< @/guide/users/snippets/update\_user.bash \[CURL] ::: Here is a `{payload}` example: ::: code-group ```json [JSON] { "address1":"new address", "address2":"new address continuated", "postcode":"75001", "city":"Paris" } ``` ::: Returns the updated User object with the modified fields. ::: code-group ```json [JSON] {19-22} { "users": [ { "userId": 100147235, "userTypeId": 1, "userStatus": "VALIDATED", "userTag": "user test Treezor", "parentUserId": 0, "parentType": "", "controllingPersonType": 0, "employeeType": 0, "specifiedUSPerson": 0, "title": "MX", "firstname": "Alex", "lastname": "Oak", "middleNames": "", "birthday": "1982-05-31", "email": "190john.smith725@test.com", "address1":"new address", "address2":"new address continuated", "postcode":"75001", "city":"Paris", // [...] some attributes are hidden } ] } ``` ::: Treezor also sends a [`user.update`](./events#user-update) webhook, and a [`card.update`](/guide/cards/events#card-update) webhook if the cardholder's information was modified. ## Deletion For legal reasons, Users cannot be deleted. They are permanently “Canceled” instead. **Prerequisites – To Deactivate a User** * The Balance of all of their Wallets must be `0` * No card transaction authorization can be pending To cancel a User you can use the following request, and provide an `origin` which can either be: * `OPERATOR`– When you are at the origin of the deactivation. * `USER` – When the end user is at the origin of the deactivation. Endpoint: [`/v1/users/{userId}`](/api-reference/api-endpoints.html#tag/user/deleteUser){target="\_self"} ::: code-group <<< @/guide/users/snippets/delete\_user.bash \[CURL] ::: Here is an example of `{payload}`: ::: code-group <<< @/guide/users/snippets/origin\_operator.json \[JSON] ::: Returns a User object if successful, with the `userStatus` set to `CANCELED`: ::: code-group <<< @/./guide/users/snippets/deleted\_user.json {6} \[JSON] ::: Treezor also sends a [`user.cancel`](./events#user-cancel) webhook. Once deleted, no action can be made on the user. You can re-create the user, using the same email if needed, as the rule for [unique emails](./introduction#using-unique-and-valid-email-addresses) doesn't apply to canceled user. --- --- url: /guide/wallets/modification.md description: >- Technical guide for updating wallets via the Treezor API. Includes required parameters, request structure, and response examples. --- # Modification ## Update Wallet ### Parameters Below are the specific set of information that can be updated. | Attribute | Type | Description | |--- |--- |--- | | `tariffId` | integer | The fees applied to the Wallet, as defined by your contract with Treezor. Usually required, but may have a default value set by Treezor. | | `walletTypeId` | integer | Either `9` or `10`. Available [types](/guide/wallets/introduction#types-of-wallets) depend on your agreement with Treezor. | | `walletTag` | integer | Custom attribute to use as you see fit. Learn more in the [Object tags](/guide/api-basics/objects-tags#objects-tags) article. Max length: 250 characters Format: hc characters and `/` `!` `-` `_` `.` `*` `'` `(` `)` | | `eventName` | string | The name of the Wallet. | | `eventMessage` | string | Can be used to describe the Wallet. | **API – API Reference available** For a complete list of Wallet attributes, check the [Wallets](/api-reference/api-endpoints.html#tag/Wallets){target="\_self"} section of the API Reference. ### Request Endpoint: [`/v1/wallets/{walletId}`](/api-reference/api-endpoints.html#tag/Wallets/putWallet){target="\_self"} ::: code-group ```bash [CURL] curl -X PUT '{baseUrl}/v1/wallets/{walletId}' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ ``` ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "walletTag":"Updated Tag", "tariffId":{tariffId}, "eventName": "Main Account", "eventMessage":"My Payment Account Wallet" } ``` ::: Returns the Wallet object with the updated information. ::: code-group ```json [JSON] {6} { "wallets": [ { "walletId": 2585102, "walletTypeId": 10, "walletStatus": "VALIDATED", "codeStatus": 120005, "informationStatus": "", "walletTag": "Updated Tag", "userId": 100060463, "userLastname": "Alex", "userFirstname": "Oak", "jointUserId": 0, "tariffId": 136, "eventName": "Main Account", "eventAlias": "main-account-659d1cdd12c892024-01-09 11:16:59", "eventDate": "2024-01-16", "eventMessage": "My Payment Account Wallet", "eventPayinStartDate": "2024-01-09", "eventPayinEndDate": "0000-00-00", "contractSigned": 0, "bic": "TRZOFR21XXX", "iban": "FR7616798000010000XXXXXXXXX", "urlImage": "", "currency": "EUR", "createdDate": "2024-01-09 11:15:57", "modifiedDate": "2024-10-09 11:16:59", "payinCount": 0, "payoutCount": 0, "transferCount": 0, "solde": 0, "authorizedBalance": 0, "totalRows": 1, "country": "FR" } ] } ``` ::: Treezor also sends the [`wallet.update`](/guide/wallets/events#wallet-update) webhook. ## Delete Wallet For safety and legal reasons Wallets cannot be deleted, they are **permanently deactivated** instead. Once deactivated, no operations can be made to or from the Wallet. **Prerequisites – To Deactivate a Wallet** * The Balance must be equal to `0` * No operations can be pending ### Parameters | Attribute | Type | Description | |--- |--- |--- | | `id` | integer | The unique identifier of the Wallet to deactivate. | | `origin` | string | The origin of the request for cancelling the Wallet, which can be one of the following: `OPERATOR` – When **you** are at the origin of the deactivation.`USER` – When the **end user** is at the origin of the deactivation.| ### Request Endpoint: [`/v1/wallets/{walletId}`](/api-reference/api-endpoints.html#tag/Wallets/deleteWallet){target="\_self"} ::: code-group ```bash [CURL] curl -X DELETE '{baseUrl}/v1/wallets/{walletId}?origin={origin}' \ --header 'Authorization: Bearer {accessToken}' ``` ::: Returns the Wallet object with the `walletStatus` attribute set to `CANCELED`. ::: code-group ```json [JSON] {6} { "wallets": [ { "walletId": 2585102, "walletTypeId": 10, "walletStatus": "CANCELED", "codeStatus": 120003, "informationStatus": "", "walletTag": "", "userId": 100060463, "userLastname": "Alex", "userFirstname": "Oak", "jointUserId": 0, "tariffId": 136, "eventName": "Account 1", "eventAlias": "test-delete-659d1cdd12c892024-01-09 11:16:59", "eventDate": "2024-01-16", "eventMessage": "", "eventPayinStartDate": "2024-01-09", "eventPayinEndDate": "0000-00-00", "contractSigned": 0, "bic": "TRZOFR21XXX", "iban": "FR7616798000010000XXXXXXXXX", "urlImage": "", "currency": "EUR", "createdDate": "2024-01-09 11:15:57", "modifiedDate": "2024-01-09 11:16:59", "payinCount": 0, "payoutCount": 0, "transferCount": 0, "solde": 0, "authorizedBalance": 0, "totalRows": 1, "country": "FR" } ] } ``` ::: Treezor also sends the [`wallet.cancel`](/guide/wallets/events#wallet-cancel) webhook. --- --- url: /guide/users/error-codes.md description: >- Troubleshoot and handle user-related issues using the Treezor API's complete list of error codes, messages, and their corresponding meanings. --- # Errors **Caution – Only the legacy API sends the error code in HTTP errors** When handling errors with Connect, only the `message` attribute is returned. ## Users The following API errors can be encountered when dealing with users. | Code | Message | |:---:|---| | `28` | User's assets are freezed | | `10012` | User Canceled | | `10023` | UserId is in pending state | | `10025` | UserId is in invalid state | | `11002` | Unable to update the user. User does not exist | | `11008` | The email is required. | | `11009` | The email is not valid. | | `11014` | Impossible to cancel, the user does not exist. | | `11015` | Impossible to cancel, the origin not specified or incorrect. | | `11016` | Impossible to cancel user, he is already in canceled status. | | `11017` | Impossible to cancel user. Wrong userId. | | `11018` | Impossible to cancel user. Database error | | `11019` | The email is already used | | `11020` | Impossible to create user. The parent type must be provided | | `11021` | Impossible to create user. Value available for Parent Type : shareholder, employee, leader | | `11022` | Impossible to create user. Parent User does not exist | | `11023` | Impossible to update the kyc review. User does not exist. | | `11038` | userTypeId is required. | | `11041` | user does not exist. | | `11042` | kycReview is required. | | `11043` | kycReview value is incorrect. | | `11044` | kycReviewComment is required. | | `11046` | userIdKyc is required. | | `11047` | user does not exist. | | `11048` | kycLevel is required. | | `11049` | kycLevel value is incorrect. | | `11053` | legalForm does not exist | | `11054` | legalNumberOfEmployeeRange is not correct. Values authorized : | | `11055` | legalNetIncomeRange is not correct. Values authorized : | | `11056` | legalAnnualTurnOver is not correct. Values authorized : | | `11057` | title is not correct. Values authorized | | `11059` | birthCountry is not in the right format. Format ISO 3166-1 alpha-2 | | `11061` | nationalityOther is not in the right format. Format ISO 3166-1 alpha-2 | | `11062` | Impossible to update the kyc review. KYC entity is not created | | `11063` | Impossible to update the kyc review. Phone number can not contains a space character. It can begin by the | | `11077` | sci must be between 17 and 35 characters | | `11078` | The language provided does not comply with ISO 639 (alpha-2) norm. | | `11080` | The field 'personalAssets' must have a value compliant with the documentation | | `11081` | The format must follow the norm : ISO-3166-1 alpha-2 | | `11085` | The field 'personalAssets' is provided but the value does not comply with provided enum values | | `11086` | User is not found in the database | | `11087` | Wrong format for phone number. | | `11088` | Wrong format for mobile number. | | `11089` | User's address1 has a line breaker | | `11090` | User's address2 has a line breaker | | `11092` | User's address3 has a line breaker | | `11093` | User is not found in the database | | `11094` | User is not found in the database | | `11096` | employeeType is invalid | | `11097` | controllingPersonType is invalid | | `11100` | specifiedUSPerson is provided but are not between 0 and 1 | | `11101` | entityType is invalid | | `11102` | activityOutsideEu is provided but are not between 0 and 1 | | `11103` | economicSanctions is provided but are not between 0 and 1 | | `11104` | residentCountriesSanctions is provided but are not between 0 and 1 | | `11105` | involvedSanctions is provided but are not between 0 and 1 | | `11109` | timezone is not in the right format. Format type tz database. Ex : Europe/Paris | | `11110` | User's city has a line breaker | | `11111` | User's country has a line breaker | | `11112` | Error during the user's cards update, please try again later | | `11113` | Wrong value of legalForm for user type NATURAL PERSON, legalForm can only be 1000. | | `11114` | BirthDepartementCode is not in the right format. Format type : 5 digits. Ex : 75008 | | `11115` | legalRegistrationDate Year is too old (before 1800) | | `11116` | legalForm is not valid. | | `11117` | User's email is too long, it must not exceed 50 characters | | `11118` | User's secondary address1 has a line breaker | | `11119` | User's secondary address2 has a line breaker | | `11120` | occupation field must be a string | | `11121` | The format must follow the norm : ISO-3166-1 alpha-2 | | `11126` | User's secondary address3 has a line breaker | | `11127` | isOnStockExchange is provided but are not between 0 and 1 | | `11128` | occupationType is not correct. Values authorized : self\_employed, public\_sector\_employees, private\_sector\_employees, retired\_people\_and\_students, without\_any\_professional\_activity | | `11129` | sourceOfFunds is not correct. Values authorized : donation, inheritance, loan, lottery, pension, proceeds\_from\_investment, proceeds\_from\_sale, salary, saving | | `11133` | Impossible to update Legal Freeze field. | | `11134` | legalSectorType is not correct. Values authorized : NAF, NACE | | `11135` | legalSector is not in the correct format for a legalSectorType code : NAF => \[0-9]\[0-9]\[0-9]\[0-9]\[A-Z] or NACE => \[0-9]\[0-9]\[0-9]\[0-9] | | `11141` | Impossible to cancel user, pending card authorization. | | `11141` | not a valid French city | | `11142` | An error occurred while processing cancel request, aborting. | | `11142` | incoherent French city and postcode | | `11143` | not a valid French postcode | | `11144` | A legal user can't give the firstname | | `11145` | A legal user can't give the lastname | | `11146` | A legal user can't give the middleNames | | `11148` | firstname is too long | | `11149` | lastname is too long | | `11177` | Impossible to submit KYC request due to user status | | `101209` | The distributionCountry must follow the ISO-3166-1 alpha-2 format | | `101210` | The distributionCountry is required | | `101211` | The DistributionCountry needs to be listed on the client side | | `101212` | Client DistributionCountry is missing | | `101302` | not an acceptable value for personalAssetsRange | ## User restrictions The following API errors can be encountered when dealing with [Restricted Users](/guide/users/restricted-users). | Code | Message | |:---:|---| | `11064` | Impossible to Freeze Assets. userId is mandatory. | | `11065` | Impossible to Freeze Assets. userIdFreezed does not exist. | | `11066` | Impossible to Freeze Assets. isFrozen is mandatory. | | `11067` | User's assets already freezed | | `11068` | User's assets already not freezed | | `11069` | Impossible to Freeze Assets. comment is mandatory. | | `11130` | User's assets already legally frozen | | `11131` | User's assets already not legally frozen | | `11132` | IsLegalFrozen is provided but are not between 0 and 1 | | `11133` | Impossible to update Legal Freeze field. | --- --- url: /guide/users/events.md description: >- Reference a comprehensive list of user events for Treezor API webhooks, detailing each event's structure and payload for integration. --- # Events This article lists the [Webhooks](/guide/webhooks/introduction) you may receive when regarding Users. ## Users ### `user.create` ::: code-group ```json [JSON] { "webhook": "user.create", "object_payload": { "users": [ { "userId": "123456789", "userTypeId": "1", "userStatus": "VALIDATED", "clientId": "222222", "userTag": "97a25cae-8027-4cec-b6db-97b48b12345", "parentUserId": "987654321", "parentType": "leader", "title": "", "firstname": "Alex", "lastname": "Oak", "middleNames": "", "birthday": "1970-01-06", "email": "a.oak@texample.com", "address1": "1600 Willow road", "address2": "", "address3": null, "postcode": "75000", "city": "Paris", "state": "", "country": "FR", "countryName": "France", "distributionCountry": "FR", "phone": "+33606060606", "mobile": "", "nationality": "FR", "nationalityOther": "", "placeOfBirth": "Paris", "birthCountry": "FR", "secondaryAddress1": null, "secondaryAddress2": null, "secondaryAddress3": null, "secondaryPostcode": null, "secondaryCity": null, "secondaryState": null, "secondaryCountry": null, "occupation": "director", "incomeRange": "36-56", // Deprecated "legalName": "", "legalNameEmbossed": "", "legalRegistrationNumber": "", "legalTvaNumber": "", "legalRegistrationDate": "0000-00-00", "legalForm": "", "legalShareCapital": "0", "legalSector": "", "legalAnnualTurnOver": "", "legalNetIncomeRange": "", "legalNumberOfEmployeeRange": "", "effectiveBeneficiary": "0.00", "position": "", "personalAssets": "0-2", // Deprecated "personalAssetsRange": "3", "taxResidence": "", // Deprecated "taxNumber": "", // Deprecated "kycLevel": "0", "kycReview": "0", "kycReviewComment": "", "isFreezed": "0", "language": null, "specifiedUSPerson": "0", "employeeType": "0", "entityType": "0", "controllingPersonType": "3", "activityOutsideEu": null, "economicSanctions": null, "residentCountriesSanctions": null, "involvedSanctions": null, "entitySanctionsQuestionnaire": null, "sanctionsQuestionnaireDate": null, "timezone": null, "occupationType": null, // Deprecated "isOnStockExchange": null, "IsLegalFrozen": "0", "sourceOfFunds": null, "legalSectorType": null, "createdDate": "2024-01-08 11:00:42", "modifiedDate": "0000-00-00 00:00:00", "codeStatus": "110009", "informationStatus": "", "sepaCreditorIdentifier": null, "walletCount": "0", "payinCount": "0", "occupationCategory": "5", "totalRows": "1", "monthlyIncomeRange": "2" } ] }, "object_id": "100060123", "object": "user", "webhook_created_at": 17047116429943, "webhook_id": "9a430c8b-1165-4ddf-a479-7a436f4d1234", "object_payload_signature": "r+V/RP/0QkeH56QXfaRz5/QpcifrgnXrfZhHXXXXXXM=" } ``` ::: ### `user.update` ::: code-group ```json [JSON] { "webhook": "user.update", "object_payload": { "users": [ { "userId": "123456789", "userTypeId": "1", "userStatus": "VALIDATED", "clientId": "929253", "userTag": "", "parentUserId": null, "parentType": null, "title": "", "firstname": "Sam", "lastname": "Willow", "middleNames": "", "birthday": "0000-00-00", "email": "swillow@example.com", "address1": "", "address2": "", "address3": null, "postcode": "", "city": "", "state": "", "country": "", "countryName": null, "distributionCountry": null, "phone": "", "mobile": "", "nationality": "FR", "nationalityOther": "", "placeOfBirth": "", "birthCountry": "", "secondaryAddress1": null, "secondaryAddress2": null, "secondaryAddress3": null, "secondaryPostcode": null, "secondaryCity": null, "secondaryState": null, "secondaryCountry": null, "occupation": "director", "incomeRange": "36-56", // Deprecated "legalName": "", "legalNameEmbossed": "", "legalRegistrationNumber": "", "legalTvaNumber": "", "legalRegistrationDate": "0000-00-00", "legalForm": "", "legalShareCapital": "0", "legalSector": "", "legalAnnualTurnOver": "", "legalNetIncomeRange": "", "legalNumberOfEmployeeRange": "", "effectiveBeneficiary": "0.00", "position": "", "personalAssets": "0-2", // Deprecated "personalAssetsRange": "3", "taxResidence": "", // Deprecated "taxNumber": "", // Deprecated "kycLevel": "0", "kycReview": "0", "kycReviewComment": "", "isFreezed": "0", "language": null, "specifiedUSPerson": "0", "employeeType": "0", "entityType": "0", "controllingPersonType": "3", "activityOutsideEu": null, "economicSanctions": null, "residentCountriesSanctions": null, "involvedSanctions": null, "entitySanctionsQuestionnaire": null, "sanctionsQuestionnaireDate": null, "timezone": null, "occupationType": null, // Deprecated "isOnStockExchange": null, "IsLegalFrozen": "0", "sourceOfFunds": null, "legalSectorType": null, "createdDate": "2024-01-08 11:00:42", "modifiedDate": "2024-02-08 11:00:42", "codeStatus": "110009", "informationStatus": "", "sepaCreditorIdentifier": null, "walletCount": "0", "payinCount": "0", "occupationCategory": "5", "totalRows": "1", "monthlyIncomeRange": "2" } ] }, "object_id": "100060789", "object": "user", "webhook_created_at": 17047224279950, "webhook_id": "e77663b0-0c4f-49c3-be53-96f39001234", "object_payload_signature": "abcDZ6MeUFRIjNoRDMN4KFjNJ0yR2Eok+MFrEq1k2/ho=" } ``` ::: ### `user.cancel` ::: code-group ```json [JSON] { "webhook": "user.cancel", "object": "user", "object_id": "100060789", "object_payload": { "users": [ { "userId": "100060789", "userTypeId": "1", "userStatus": "CANCELED", "clientId": "929252", "userTag": "", "parentUserId": null, "parentType": null, "title": "", "firstname": "Sam", "lastname": "Willow", "middleNames": "", "birthday": "0000-00-00", "email": "swillow@example.com", "address1": "", "address2": "", "address3": null, "postcode": "", "city": "", "state": "", "country": "", "countryName": null, "distributionCountry": null, "phone": "", "mobile": "", "nationality": "FR", "nationalityOther": "", "placeOfBirth": "", "birthCountry": "", "secondaryAddress1": null, "secondaryAddress2": null, "secondaryAddress3": null, "secondaryPostcode": null, "secondaryCity": null, "secondaryState": null, "secondaryCountry": null, "occupation": "director", "incomeRange": "36-56", // Deprecated "legalName": "", "legalNameEmbossed": "", "legalRegistrationNumber": "", "legalTvaNumber": "", "legalRegistrationDate": "0000-00-00", "legalForm": "", "legalShareCapital": "0", "legalSector": "", "legalAnnualTurnOver": "", "legalNetIncomeRange": "", "legalNumberOfEmployeeRange": "", "effectiveBeneficiary": "0.00", "position": "", "personalAssets": "0-2", // Deprecated "personalAssetsRange": "3", "taxResidence": "", // Deprecated "taxNumber": "", // Deprecated "kycLevel": "0", "kycReview": "0", "kycReviewComment": "", "isFreezed": "0", "language": null, "specifiedUSPerson": "0", "employeeType": "0", "entityType": "0", "controllingPersonType": "3", "activityOutsideEu": null, "economicSanctions": null, "residentCountriesSanctions": null, "involvedSanctions": null, "entitySanctionsQuestionnaire": null, "sanctionsQuestionnaireDate": null, "timezone": null, "occupationType": null, // Deprecated "isOnStockExchange": null, "IsLegalFrozen": "0", "sourceOfFunds": null, "legalSectorType": null, "createdDate": "2024-01-08 11:00:42", "modifiedDate": "2024-02-08 11:00:42", "codeStatus": "110006", "informationStatus": "", "sepaCreditorIdentifier": null, "walletCount": "0", "payinCount": "0", "occupationCategory": "5", "totalRows": "1", "monthlyIncomeRange": "2" } ] }, "webhook_created_at": 17047241698952, "webhook_id": "e4b40b36-db07-4af0-9c57-a4429fc01234", "object_payload_signature": "1ABCDmDZMqv/pZ5gA9E1xq9CvivJp+K7ngW2hh7mvF0=" } ``` ::: --- --- url: /guide/users/parent-children.md description: >- Technical guide for creating hierarchical relations between users, such as family relationships and company structures (e.g., employer/employee, company/shareholders). Includes required parameters, request structure, and response examples. --- # Parent-Children relations Hierarchical relations can exist between *Users* (with a maximum depth of 2). Parent-children relations can be used in [multiple scenarios](#use-cases). It is mandatory for: * Family relations between [Physical Users](physical) (actual **parent** and **children**) * Hierarchical relations between [Legal Entities](legal-entity) (*employer*, **parent**) and [Physical Users](physical) (*employee*, **children**) * Ownership relations between [Legal Entities](legal-entity) (*company*, **parent**) and [Physical Users](physical) (*shareholders/legal representatives*, **children**) It can optionally be used for other types of hierarchical relations related to your own business activity. **Best practice – Make sure you create relevant hierarchical relations** Always abide by the rules Treezor sets out for you. Otherwise, you may have technical or legal issues. ## Key attributes The hierarchical relation to a parent User is defined by the following attributes: | Attribute | Type | Description | | --- | --- | --- | | `parentUserId` | integer | The unique identifier of the User who is the parent of the current one. |  | `controllingPersonType` | integer | The type of relation with the parent, used with Shareholders and Legal representatives. See [list of values](#controlling-person-types-controllingpersontype) |  | `parentType` | string | The type of relationship between the parent and the current user. See [list of values](#parent-types-parenttype) |  | `effectiveBeneficiary` | integer | Percentage of ownership for an Effective Beneficiary, if applicable (`25` for 25%, `100` for 100%, etc.) |  | `employeeType` | integer | The type of employee. See [list of values](#employee-types-employeetype). |  ### Parent Types (`parentType`) The following parent types are available. They may take different meanings depending on [your implementation](#use-cases). * `shareholder` * `leader` * `employee` **Information – `parentType` can't be updated** Once this value is set upon creating a user, it cannot be changed later on. ### Controlling Person Types (`controllingPersonType`) * `0` **None** * `1` **Shareholder** of a [Legal Entity](/guide/users/legal-entity) * `2` **Other\_relationship** * `3` **Legal representative** of a [Legal Entity](/guide/users/legal-entity) ### Employee Types (`employeeType`) * `0` **None** (not an employee) * `1` **Leader** (legal representative) * `2` **Employee** (employee) ## How to use parent relations It is recommended that you **create your users from the top** of the hierarchical tree (starting with the top-most parent) and take a look at [use cases](#use-cases). The following example illustrates the creation of a company and one of its employees. We first create **"Example Company"**, a [Legal Entity](/guide/users/legal-entity) that will act as the parent. ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/v1/users' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{ "userTypeId":2, "specifiedUSPerson":0, "legalName":"An Awesome Company" # [...] }' ``` ::: Returns a User, with its `id` (111222333). ::: code-group ```json [JSON] { "userId": 111222333, "userTypeId": 2, // 2 corresponds to Business Users "parentUserId": null, // this User does not have a parent "parentType": null, // as it does not have a parent, it cannot have a parent type either "legalName": "Example Company", // [...] some attributes are hidden for clarity } ``` ::: We then create **"Alex"**, a Physical User, * associate it to the parent company (`parentUserId`), * define the relation as an *employee* relation (`parentType`). All in one step. ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/v1/users' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{ "userTypeId":1, # 1 = physical user (human being) "specifiedUSPerson":0, # 0 = Non-US citizen "firstname":"Alex", "parentUserId":111222333, # <--- associate to the parent companys ID created above "parentType":"employee" # <--- define the type of relation # [...] }' ``` ::: Returns a *User*, with `parentUserId` and `parentType` populated as specified above. ::: code-group ```json [JSON] { "userId": 444555666, "userTypeId": 1, "parentUserId": 111222333, "parentType": "employee", "firstname": "Alex" // [...] some attributes are hidden for clarity } ``` ::: ## Use Cases The most reliable way to identify how to implement your parent-children relation is to find a suitable Use Case below. ### Company and Employee This use case describes a parent company ([Legal Entity](legal-entity)) and an employee ([Physical User](physical)) of the parent company. #### Parent ```json [JSON] { "userTypeId":2, "parentType":null, "parentUserId":null } ``` #### Children ```json [JSON] { "userTypeId":1, "parentType":"employee", "parentUserId":{idOfTheParentUser}, } ``` *** ### Company and Legal Representative This use case describes a parent company ([Legal Entity](legal-entity)) and a legal representative ([Physical User](physical)) of the parent company. #### Parent ```json [JSON] { "userTypeId":2, "controllingPersonType":null, "parentUserId":null } ``` #### Children ```json [JSON] { "userTypeId":1, "controllingPersonType":3, "parentType": "leader", "parentUserId":{idOfTheParentUser} } ``` *** ### Company and Shareholder This use case describes a parent company ([Legal Entity](legal-entity)) and a shareholder ([Physical User](physical)) of the parent company. #### Parent ```json [JSON] { "userTypeId":2, "controllingPersonType":null, "parentUserId":null } ``` #### Children ```json [JSON] { "userTypeId":1, "controllingPersonType":1, "parentType": "shareholder", "parentUserId":{idOfTheParentUser}, "effectiveBeneficiary": 30 // shares (%) } ``` *** ### Company and Legal Representative who is also a Shareholder This use case describes a parent company ([Legal Entity](legal-entity)) and a [Physical User](physical) who is both the legal representative and a shareholder of the parent company. In such cases: * The Physical User is created as a Legal Representative and, * The `effectiveBeneficiary` field must include the shares of the company. #### Parent ```json [JSON] { "userTypeId":2, "controllingPersonType":null, "parentUserId":null } ``` #### Children ```json [JSON] { "userTypeId":1, "controllingPersonType":3, "parentType": "leader", "parentUserId":{idOfTheParentUser}, "effectiveBeneficiary": 30 // shares (%) } ``` *** ### Natural Parent and Minor (using Electronic Money) This use case describes a natural parent ([Physical User](physical)) and their natural minor children ([Physical User](physical)). #### Key aspects of this Use Case * It is used with [Electronic Money](/guide/wallets/introduction#electronic-money-wallet-type-9) Wallets. * The Wallets are associated (`Wallet.userId`) to the natural parents. * When the [Electronic Money](/guide/wallets/introduction#electronic-money-wallet-type-9) threshold of €150 is reached, a [KYC](/guide/user-verification/introduction) is required on the natural parent exclusively. #### Parent ```json [JSON] { "userTypeId":1, "parentType":null, "parentUserId":null } ``` #### Children ```json [JSON] { "userTypeId":1, "parentType":"leader", "parentUserId":{idOfTheParentUser} } ``` *** ### Natural Parent and Minor (using Payment Account) This use case describes a natural parent ([Physical User](physical)) and their natural minor children ([Physical User](physical)). #### Key aspects of this Use Case * It is used with [Payment Account](/guide/wallets/introduction#payment-account-wallet-type-10) Wallets. * The Wallets are associated (`Wallet.userId`) to the minor children. * A [KYC](/guide/user-verification/introduction) is required on both the natural parent and the minor children. #### Parent ```json [JSON] { "userTypeId":1, "parentType":null, "parentUserId":null } ``` #### Children ```json [JSON] { "userTypeId":1, "parentType":"shareholder", "parentUserId":{idOfTheParentUser} } ``` *** ### Individual and Assisted Individual This use case describes a parent individual ([Physical User](physical)) and an assisted individual ([Physical User](physical)) under their legal responsibility (such as under guardianship). #### Key aspects of this Use Case * It is used with [Payment Account](/guide/wallets/introduction#payment-account-wallet-type-10) Wallets. * The Wallets are associated (`Wallet.userId`) to the assisted individuals. * A [KYC](/guide/user-verification/introduction) is required on both the parent individual and the assisted individual. * The parent is required to produce an additional [KYC Document](/guide/user-verification/documents) (form of proxy) allowing them access to the children's Wallet. #### Parent ```json [JSON] { "userTypeId":1, "parentType":null, "parentUserId":null } ``` #### Children ```json [JSON] { "userTypeId":1, "parentType":"leader", "parentUserId":{idOfTheParentUser} } ``` --- --- url: /guide/user-verification/live-verification.md description: >- Technical guide for verifying users (KYC) with live verification via the Treezor API. Includes required parameters, request structure, and response examples. --- # Live verification Live verification consists of verifying the user’s identity remotely through a live video. This feature contributes to mitigating fraud risk while optimizing the user experience. **Configuration – Environment configuration by Treezor** Contact Treezor to use one of the live verification features. Treezor relies on a live verification provider which offers two ways to verify user identity. You can use only one of these two methods. | Method | Description | | --- | --- | | **Liveness** | Requires a video of the end user, their identity proof, and a SEPA transfer into their Treezor Wallet as an [extra validation step](/guide/user-verification/introduction#additional-vigilance-measures). | | **Certified video ([PVID](/guide/overview/glossary#remote-identity-verification-providers-pvid))** | Requires a video of the end users and their identity proof. It contains challenges for the user to complete, so no extra validation step is necessary. PVID is [ANSSI-certified](/guide/overview/glossary#french-cybersecurity-agency-anssi). Both features use the same endpoint with a transparent behavior. **Tip – The KYC live verification interface is customizable** Contact Treezor to change the colors, logo, redirection URL once the process ends, etc. ## Process 1. You initiate a live verification for the User – [`/v1/users/{userId}/kycliveness`](/api-reference/api-endpoints.html#tag/Verification%20Solutions%20\(KYC\)/postKycliveness){target="\_self"} 2. Treezor answers with the live verification URL (`identification-url`). 3. You redirect the User to the `identification-url`. 4. The User follows the step-by-step live verification process, hence uploading the document. 5. Treezor keeps you informed of the documents processing with the [KYC Liveness](/guide/users/events#kyc-liveness) webhooks. 6. Once the [`kycliveness.update`](events#kyc-liveness) webhook returns a `kyc-status` set to `processed`, you may request a KYC review: a. [Retrieve the documents](#retrieve-the-documents) – [`/v1/users/{userId}/kycliveness`](/api-reference/api-endpoints.html#tag/Verification%20Solutions%20\(KYC\)/put-kyc-liveness){target="\_self"} b. [Request a KYC review](#request-a-review-of-the-user) – [`/v1/users/{userId}/Kycreview`](/api-reference/api-endpoints.html#tag/User%20KYC%20Review/putKycreview){target="\_self"} 7. Treezor sends you the [`user.kycreview`](events#user-kycreview) webhook upon validation or refusal. Note that the live verification process may take some time. Please don't call the [`/v1/users/{userId}/kycliveness`](/api-reference/api-endpoints.html#tag/Users/postKycliveness){target="\_self"} endpoint for a given user before the previous live verification is completed. When this situation occurs: * The newer request replaces the previous one. * Trying to upload documents for the first live verification results in an HTTP error. ## Key attributes (webhooks) Live verification relies exclusively on webhooks to provide you with information regarding the process: * [`kycliveness.create`](/guide/user-verification/events#kycliveness-create) – Received when the end user completes (or abandons) the live verification process. * [`kycliveness.update`](/guide/user-verification/events#kycliveness-update) – Received when Treezor identity verification partner completes the verification. Below are some of the key attributes you may find in these webhooks. | Attribute | Type | Description | | --- | --- | --- | | `kyc-status` | string | The status of the live verification process. See the `redirectURL` [query parameters](#parameters). | | `comment` | string | Comment from Treezor providing additional information regarding the live verification process. | | `reasons` | array | List of reason codes and messages indicating why the user has been refused. See the list of [reason codes](#reason-codes-reason-code) below. | ### Reason codes (reason-code) When using the live verification feature (either Liveness or Certified video), the [`kycliveness.update`](/guide/user-verification/events#kyc-liveness) webhook returns the `reason-code` and the corresponding `reason-message`, providing insights on the refusal. Some of these errors are sensitive regarding [AML/CFT](/guide/overview/glossary#anti-money-laundering-and-countering-the-financing-of-terrorism-aml-cft), please remember not to share the reasons for refusal with your end users when that’s the case. | Code | Message | | :---: | --- | | 1201 | Applicant did not have a sufficient connexion | | 1301 | Applicant’s document video is too blurry (mostly due to too much movement but if this error persists the camera quality might be at fault) | | 1302 | Applicant has not presented the front of the document | | 1303 | Applicant has not presented the back of the document | | 1304 | Applicant hides part of the document | | 1305 | Applicant did not present a dynamic view of the document | | 1310 | Applicant’s video of their face is too blurry (mostly due to too much movement but if this error persists the camera quality might be at fault) | | 1311 | Applicant has not presented a face | | 1312 | Applicant did not show the full front view of their face | | 1313 | Applicant did not move to prove the liveness | | 1320 | Applicant performed their id verification under poor lighting conditions | | 1901 | Internal non-categorizable error | | 1911 | The received videos cannot be played | | 2101 | Applicant presented an expired document | | 2102 | Applicant presented a document which is not accepted | | 2103 | Applicant has submitted a damaged document | | 2201 | Applicant presented a photocopy of the document | | 2202 | Applicant presented the document on a screen | | 2301 | Applicant has submitted a counterfeit or falsification | | 2302 | Applicant presented a document declared as stolen or lost | | 2303 | Applicant presented the front and back of two different documents | | 2304 | Applicant is not the rightful owner of the document | | 2305 | Applicant presented another person's face | | 2306 | Applicant has altered his/her appearance | | 2307 | Applicant has digitally altered the videos | | 2399 | Generic code when a fraud has been detected within a certified identity verification | | 2401 | Applicant’s identity does not match with the expected one | | 2402 | Applicant used a device that has been technically altered | | 2403 | Applicant seems to have performed the check against his will | ## Initiate a live verification Before initiating the live verification process, the User must be created with the relevant attributes (as required by Treezor Compliance). At least the `firstname`, `lastname`, and `birthday` of the user must be populated, otherwise, the API call returns an HTTP 428 error. ### Parameters You can optionally override the default URL to which the user will be redirected after the live verification. | Attribute | Type | Description | | --- | --- | --- | | `redirectUrl` | string | The URL to which the User will be redirected after the live verification. | Additional information is added to the defined redirect URL in the form of query parameters. This can help the end user understand why a live verification process has been aborted. The query parameters provided with the `redirectUrl` are the following: | Parameter | Description | | --- | --- | | `identification_id` | The unique identifier of the live verification process. | | `status` | The status of the live verification, which in this case can be either `processing` in case of success or `aborted` for failures. | | `return_reason` | The reason for the live verification process abortion. | | `error_type` | Indicates the type of error that led to the live verification process abortion. | ::: details More about the Redirect URL query parameters If you take the following URL: `redirect_url?identification_id=123&status=aborted&return_reason=error&error_type=device_not_found` You can deduce that the identification process `123` was aborted due to an error; the device was not found (i.e., the device did not have any camera). Here is the list of values for the query parameters: | status | return\_reason | error\_type | description | |:------------:|---------------|--------------------|---------------------------------------------------| | `processing` | none | none | The user completed their verification. | | `aborted` | refusal | none | The user refused to perform the verification now. | | `aborted` | no\_document | none | The user did not have their document available to them. | | `aborted` | verify\_later | none | The user refused to start the verification process. | | `aborted` | focus-lost | none | The user switched tabs/application while performing the id verification. | | `aborted` | connections\_issue | bad\_connexion | The connection was not good enough. | | `aborted` | doc\_instructions\_not\_followed | challenge\_timeout | The user did not follow the instruction for the document challenge. | | `aborted` | face\_instructions\_not\_followed | challenge\_timeout | The user did not follow the instruction for the face challenge. | | `aborted` | error | bad\_connexion | The connection was not good enough. | | `aborted` | error | no\_SMS | The user did not receive the SMS. | | `aborted` | error | publish | Error during video connection. | | `aborted` | error | device\_not\_allowed | The user refused to give access to their camera. | | `aborted` | error | browser-not-supported | The browser was not supported. | | `aborted` | error | device\_not\_found | The user’s device did not have any camera. | | `aborted` | error | wrong\_phone\_number | The user wanted to change their phone number and were not allowed to for security reasons. | ::: ### Request You can use the following request to initiate the live verification process. ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/v1/users/{userId}/kycliveness' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{"redirectUrl": "https://www.my-domain.tld"}' ``` ::: Answers with a 201 HTTP Status Code and returns the identifier of the verification process and the `identification-url`. The latter is where the end user is to be redirected to go through the live verification process. ::: code-group ```json [JSON] { "identification": { "identification-id": "f8048bee-3182-48dc-93e5-7eef9db77050", "identification-url": "https://id.ubble.ai/f8048bee-3182-48dc-93e5-7eef9db77050", "type": "video_certified" } } ``` ::: Once redirected, end users have **15 minutes** to complete the steps for the relevant live verification feature. After this delay, the `identification-url` expires. **Information – The redirection link may not be supported by the end user's device** See the `redirectURL` [query parameters](#parameters) to know which error is returned when this occurs. ### End user live verification Once redirected, end users are guided through the live verification steps: * Which differ depending on the live verification type. * Which documents vary depending on the country of the end user. ::: details Click to see the KYC Liveness steps for your end users (mobile) ::: ::: details Click to see the Certified video steps for your end users (mobile) ::: After the last step: * The user is redirected to the `redirectUrl` or the URL configured with Treezor. * Treezor sends you a [`kycliveness.create`](./events) webhook with a `kyc-status` set to `processing`. ## Retrieve the live verification document Once you have received the [`kycliveness.update`](./events) webhook with a `kyc-status` set to `processed`, you must retrieve the documents from the live verification provider for them to be uploaded to Treezor. These documents include documents uploaded by the end user during the process and the live verification process synthesis document, which is either: * **Liveness result** for the liveness process (`documentTypeId` = `26`). * **Certified Liveness Result** for the certified video process (`documentTypeId` = `34`). To retrieve the documents, use the following request. ::: code-group ```bash [CURL] curl -X PUT '{baseUrl}/v1/users/{userId}/kycliveness' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' ``` ::: Answers with an HTTP 200 status code and makes the documents available for download. Treezor sends you as many `document.create` webhooks as there are documents for the user’s live verification. You can make your [KYC Review request](#request-a-kyc-review-for-the-user) only once you've received all the document creation webhooks. ## Download the live verification documents If you're eligible, you may be able to collect some of the uploaded documents whose `documentTypeId` allows for it. **Configuration – Download is not enabled by default** Please contact Treezor to request access to this feature. Downloading a document is a 2-step process, in which you: 1. [Request the download URL](#request-the-download-url) 2. [Download the document within 30 seconds](#download-the-document) ### Request the download URL To request the download URL, you need the corresponding `documentId` (available in the `document.create` webhook for instance). ::: code-group ```bash [CURL] curl -X GET '{baseUrl}/v1/documents/{documentId}/download' \ --header 'Authorization: Bearer {accessToken}' \ ``` ::: Returns the URL to download the document, with all the necessary query parameters for the next step. ::: code-group ```json [JSON] { "url": "{documentDownloadUrl}" } ``` ::: ### Download the document You have 30 seconds to download the document from the moment the URL has been generated in the previous step. ::: code-group ```bash [CURL] curl -X GET '{documentDownloadUrl}' ``` ::: The document is returned in its initial format. ## Request a KYC Review for the User Before requesting a KYC review from Treezor, please make sure all the information and documents are properly updated for the user. You can use the dedicated endpoint: * [`/v1/users/{userId}/Kycreview`](/api-reference/api-endpoints.html#tag/User%20KYC%20Review/putKycreview){target="\_self"} **Alert – Documents must be uploaded for children users too** When there are [parent-children hierarchical relationship](/guide/users/parent-children), in most cases, the KYC Review must only be requested for the parent user. But you may need to upload [Documents](./documents) for the children before that. Please abide by the Treezor Compliance team recommendation for a smooth experience. Learn more in the [KYC Request](./kyc-request) article. ## Endpoints | Endpoint |[Scope](/guide/api-basics/authentication#available-scopes) | | --- | --- | | [`/v1/users/{userId}/kycliveness`](/api-reference/api-endpoints.html#tag/Verification%20Solutions%20\(KYC\)/postKycliveness){target="\_self"} Initiate the user [Live verification](/guide/user-verification/introduction) process | `read_write` | | [`/v1/documents/{documentId}/download`](/api-reference/api-endpoints.html#tag/User%20Documents/getDocumentDownloadUrl){target="\_self"} Retrieve a document download URL | `read_only` | | [`/v1/users/{userId}/kycliveness`](/api-reference/api-endpoints.html#tag/Verification%20Solutions%20\(KYC\)/put-kyc-liveness){target="\_self"} Upload the documents once the Live verification is completed. | `read_write` | | [`/v1/users/{userId}/Kycreview`](/api-reference/api-endpoints.html#tag/User%20KYC%20Review/putKycreview){target="\_self"} Initiate the user [KYC review](/guide/user-verification/introduction) process | `read_write` | --- --- url: /guide/users/faking-operations.md description: >- Learn how to simulate Treezor User validation within the Sandbox environment for development and API integration testing. --- # Emulation Emulation features are only available in `Sandbox` [environment](/guide/api-basics/environments). ## Simulate user validation Some actions, like creating specific types of Wallets, require the user to be in a `VALIDATED` status. In Sandbox, you can validate the user for testing purposes by adding the `.userStatusValidated` suffix to the User's `lastname`. You can do so with the following requests: * [`/v1/users`](/api-reference/api-endpoints.html#tag/Users/postUser){target="\_self"} * [`/v1/users/{userId}`](/api-reference/api-endpoints.html#tag/Users/putUser){target="\_self"} **Tip – Compatible with KYC emulation** You can cumulate the suffixes to achieve both status and [KYC emulation](/guide/user-verification/faking-operations) at once. For instance: `lastname.refused.userStatusValidated`. ### Example Let's update a User's `lastname` to set the status to `VALIDATED`. ::: code-group ```bash [CURL] curl -X PUT '{baseUrl}/v1/users' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: With a `{payload}` containing the suffixed `lastname`: ::: code-group ```json [JSON] { "lastname": "Oak.userStatusValidated" } ``` ::: Returns the updated user with the new `userStatus`: ::: code-group ```json {6} [JSON] { "users": [ { "userId": 101391362, "userTypeId": 1, "userStatus": "VALIDATED", "userTag": "", "parentUserId": 0, "parentType": "", "controllingPersonType": 0, "employeeType": 0, "specifiedUSPerson": 0, "title": "M", "firstname": "Alex", "lastname": "Oak.userStatusValidated", "middleNames": "", "birthday": "1982-05-30", "email": "Waino.Cole@gmail.com", "address1": "8214 Kris Turnpike", "address2": "", "postcode": "75017", "city": "Paris", "state": "", "country": "FR", "countryName": "France", "phone": "+33141358530", "mobile": "", "nationality": "FR", "nationalityOther": "", "placeOfBirth": "Paris", "birthCountry": "FR", "occupation": "", "incomeRange": "0-18", "legalName": "", "legalNameEmbossed": "", "legalRegistrationNumber": "", "legalTvaNumber": "", "legalRegistrationDate": "0000-00-00", "legalForm": "", "legalShareCapital": 0, "entityType": 0, "legalSector": "", "legalAnnualTurnOver": "", "legalNetIncomeRange": "", "legalNumberOfEmployeeRange": "", "effectiveBeneficiary": 0, "kycLevel": 2, "kycReview": 0, "kycReviewComment": "", "isFreezed": 0, "isFrozen": null, "language": "", "optInMailing": null, "sepaCreditorIdentifier": "", "taxNumber": "", "taxResidence": "", "position": "", "personalAssets": "", "createdDate": "2025-01-17 09:39:21", "modifiedDate": "2025-01-17 10:39:45", "walletCount": 0, "payinCount": 0, "totalRows": "1", "activityOutsideEu": null, "economicSanctions": null, "residentCountriesSanctions": null, "involvedSanctions": null, "address3": null, "timezone": null, "occupationType": "", "isOnStockExchange": 0, "secondaryAddress1": "", "secondaryAddress2": "", "secondaryAddress3": "", "secondaryPostcode": "", "secondaryCity": "", "secondaryState": "", "secondaryCountry": "", "clientId": "929252", "sanctionsQuestionnaireDate": null, "codeStatus": "110009", "informationStatus": "", "legalSectorType": "", "sourceOfFunds": "", "distributionCountry": null, "entitySanctionsQuestionnaire": 0, "monthlyIncomeRange": null, "personalAssetsRange": null, "occupationCategory": null, "birthCityCode": null } ] } ``` ::: --- --- url: /guide/user-verification/errors.md description: >- Troubleshoot and handle KYC, Documents, and verification solution issues using the Treezor API's complete list of error codes, messages, and their corresponding meanings. --- # Errors The following API errors can be encountered when dealing with user verification. **Caution – Only the legacy API sends the error code in HTTP errors** When handling errors with Connect, only the `message` attribute is returned. ## KYC request errors | Code | Message | |:-------:|---------------------| | `1` | Generic Error | | `3` | A database error has occured | | `6` | An Exception has been raised | | `11` | One filter given in the request is empty, you should provide a filter value at least | | `31` | The same request is already running | | `55` | The request accessTag is too long | | `1029` | Non-existent client for the given user | | `10009` | Request UserId does not belong to Oauth2 ClientId | | `10029` | Non-existent client for the given document | | `10030` | SCI must be between 8 and 35 characters | | `10034` | SCI must start with a valid ISO country code | | `10035` | Invalid SCI checksum | | `11004` | Title is required | | `11005` | Civility value must be either 'M' or 'MME' or 'MLLE' | | `11006` | Firstname is required. | | `11007` | The lastname is required. | | `11011` | The post code is required. | | `11012` | The city is required. | | `11013` | The country is required. Format ISO 3166-1 alpha-2 | | `11019` | The email is already used | | `11025` | legalRegistrationNumber is required. | | `11026` | legalRegistrationDate is required (format : YYYY-MM-DD) | | `11027` | legalName is required. | | `11028` | legalForm is required. | | `11029` | legalShareCapital is required | | `11030` | phone is required. | | `11031` | legalSector is required. | | `11032` | legalNumberOfEmployeeRange is required. | | `11033` | legalNetIncomeRange is required. | | `11034` | legalAnnualTurnOver is required. | | `11035` | placeOfBirth is required. | | `11036` | birthCountry is required. Format ISO 3166-1 alpha-2 | | `11037` | nationality is required. | | `11039` | birthday is required (format : YYYY-MM-DD) | | `11040` | userIdKyc is required. | | `11041` | user does not exist. | | `11042` | kycReview is required. | | `11043` | kycReview value is incorrect. | | `11044` | kycReviewComment is required. | | `11046` | userIdKyc is required. | | `11047` | user does not exist. | | `11048` | kycLevel is required. | | `11049` | kycLevel value is incorrect. | | `11051` | nationalityOther is not in the right format. Format ISO 3166-1 alpha-2 | | `11058` | birthday is not in the right format. Format YYYY-MM-DD | | `11060` | nationality is not in the right format. Format ISO 3166-1 alpha-2 | | `11073` | incomeRange is required. | | `11074` | userId is missing. | | `11075` | userId does not exist for the client. | | `11076` | sci is empty | | `11095` | employeeType is missing | | `11098` | controllingPersonType is missing | | `11099` | specifiedUSPerson is missing | | `11113` | Wrong value of legalForm for user type NATURAL PERSON, legalForm can only be 1000. | | `11115` | legalRegistrationDate Year is too old (before 1800) | | `11122` | The secondary address is required | | `11123` | The secondary country is required | | `11124` | The secondary postcode is required | | `11125` | The secondary city is required | | `11177` | Impossible to submit KYC request due to user status | | `11179` | one of the associated user is invalid | | `101300` | the business user and each effective beneficiary attached to it need to have at least one tax residence declared | | `101301` | the business user and each effective beneficiary attached to it need to have at least one valid tax residence declared | | `101208` | specifiedUSPerson must be 0 or 1 | ## Document errors | Code | Message | |:------:|------------------------------------------------------------------------------------------------------------------| | `60000` | The user does not exist or he is in canceled status | | `60001` | File not uploaded. The file is empty | | `60002` | The file type is not permitted | | `60003` | This document type is not permitted | | `60004` | Impossible to save the document | | `60005` | Impossible to connect to the file server | | `60006` | Impossible to upload the document into the container | | `60007` | Impossible to read the file into the container | | `60008` | Impossible to update the document into database | | `60009` | Error when reading document | | `60010` | Impossible to cancel this Document, already in CANCELED status | | `60011` | Impossible to update this Document, not exists | | `60012` | statusId incorrect. | | `60013` | Impossible to verify canceled status | | `60014` | Impossible to update this document | | `60017` | Image is empty | | `60019` | documentId is mandatory. | | `60020` | documentStatusId is mandatory. | | `60021` | The document must be in a PENDING status | | `60024` | The documentTypeId is empty or you provide a wrong documentTypeId value | | `60025` | Wrong value for documentStatusId | | `60026` | documentId not valid | | `60027` | statusId is mandatory. | | `60028` | When the document is a taxStatement or an exemptionStatement, the field residenceId is mandatory | | `60029` | When the document is not a taxStatement nor an exemptionStatement, the field residenceId should not be provided | | `60030` | The residenceId you provided does not match a valid entry in the taxResidence database | | `60031` | The residenceId you provided has been deleted | | `60032` | userId is missing | | `60033` | Impossible to create the document, The number of objects is exceeded or the quota of your space is saturated | | `60034` | Impossible to update the status, this document is canceled | | `60035` | Impossible to get URL, this document does not exist | | `60036` | The document source is not valid or not in the list | | `60038` | name is mandatory. | | `60039` | Document not found in database. | | `60040` | Update document status with error | | `60041` | fileExtension is missing | | `60042` | FileExtension is not valid or not in the list | | `60043` | The request must contain documentHash when documentId is in params . | | `60044` | Document already cancel or validate, this document, this document is not pending status | | `60045` | The documentHash is invalid | | `60046` | fileExtension is not correct | | `60049` | fileSize is too large | | `60050` | fileSize is missing | | `60051` | fileHash is missing | | `60052` | document already created | | `60052` | invalid hex-encoded hash | ## Tax Residence errors | Code | Message | |:---------:|------------------------------------------------------------------------------------------------------------| | `101001` | taxPayerId and liabilityWaiver are both present | | `101002` | taxResidence doesn't exist | | `101003` | Country is not in the following format: ISO 3166-1 alpha 2 | | `101004` | taxPayerId is invalid | | `101005` | taxResidence is deleted, impossible to update this taxResidence | | `101006` | taxPayerId and liabilityWaiwer at least one must be present | | `101200` | liabilityWaiver cannot be false if taxPayerId is null or empty | | `101201` | liabilityWaiver cannot be true if taxPayerId is not null or not empty | | `101202` | a taxPayerId is required if country is US or a US territory | | `101203` | the country must have a ISO 3166-1 alpha 2 format\ | `101204` | a tax residence in the US or a US teritory must be declared for the user if specifiedUSPerson = 1 | | `101205` | specifiedUSPerson must be 1 if at least one of the following fields is the US or a US territory: nationality, nationalityOther, birthCountry, country, secondaryCountry | | `101206` | specifiedUSPerson must be 1 if a tax residence was declared in the US or a US territory | | `101207` | a user must have at least one tax residence declared | | `101213` | The user can't waive liability, taxPayerId is required. | | `101214` | An Italian taxPayerId already exists for this user. | | `101215` | Updating the userId is not allowed. | | `101216` | Updating the country is not allowed. | | `101217` | Tax Residence can't be deleted, the taxPayerId is required for the associated User. | | `101218` | The taxPayerId from the Tax Residence object is mandatory for Italian users. | | `101303` | A tax residence already exists for this user in this country | --- --- url: /guide/user-verification/events.md description: >- Reference a comprehensive list of KYC, documents, and verification solution events for Treezor API webhooks, detailing each event's structure and payload for integration. --- # Events This article lists the [Webhooks](/guide/webhooks/introduction) you may receive when regarding user verification. ## KYC ### `user.kycrequest` ::: code-group ```json [JSON] { "messageId": "04b61286-2cb1-555c-a62e-49836482c5b8", "webhookId": "fd895029-22e5-49ed-a2c8-093c07dc053c", "webhook": { "webhook": "user.kycrequest", "object": "user", "object_id": "6461762", "object_payload": { "users": [ { "userId": "6461762", "userTypeId": "1", "userStatus": "VALIDATED", "clientId": "516899", "userTag": "", "parentUserId": null, "parentType": null, "title": "M", "firstname": "Alex", "lastname": "Oak", "middleNames": "", "birthday": "1989-00-00", "email": "a.oak@example.com", "address1": "12 Willow Lane", "address2": "", "address3": "", "postcode": "75000", "city": "Paris", "state": "Paris", "country": "FR", "countryName": "France", "phone": "+xxxxxxxxxxxxx", "mobile": "+xxxxxxxxxxxxx", "nationality": "FR", "nationalityOther": "", "placeOfBirth": "Caen", "birthCountry": "FR", "occupation": "", "incomeRange": "28-35", "legalName": "", "legalNameEmbossed": "", "legalRegistrationNumber": "", "legalTvaNumber": "", "legalRegistrationDate": "0000-00-00", "legalForm": "", "legalShareCapital": "0", "legalSector": "", "legalAnnualTurnOver": "", "legalNetIncomeRange": "", "legalNumberOfEmployeeRange": "", "effectiveBeneficiary": "0.00", "position": "", "personalAssets": "0-2", "taxResidence": "FR", "taxNumber": "", "kycLevel": "0", "kycReview": "1", "kycReviewComment": "", "isFreezed": "0", "language": null, "specifiedUSPerson": "0", "employeeType": "0", "entityType": "0", "controllingPersonType": "0", "activityOutsideEu": null, "economicSanctions": null, "residentCountriesSanctions": null, "involvedSanctions": null, "entitySanctionsQuestionnaire": null, "sanctionsQuestionnaireDate": null, "timezone": null, "createdDate": "2022-05-18 12:21:04", "modifiedDate": "2022-05-18 12:21:12", "codeStatus": "110009", "informationStatus": "", "sepaCreditorIdentifier": null, "walletCount": "1", "payinCount": "0", "totalRows": "1" } ] }, "webhook_created_at": 16532945786168, "webhook_id": "fd895029-22e5-49ed-a2c8-093c07dc053c", "object_payload_signature": "pVzBUAM2mgVtCNxw6u4fdaZqktAlStk\/yGlfA1v2JQs=" }, "clientId": "516899" } ``` ::: ### `user.kycreview` This event is sent when Treezor validates or refuses a User. ::: code-group ```json [JSON] { "messageId": "db99d40f-0840-5945-bfab-8f01daf65ac1", "webhookId": "8f3577ec-c126-4e94-a3df-1bdccfb0b89f", "webhook": { "webhook": "user.kycreview", "object": "user", "object_id": "6461762", "object_payload": { "users": [ { "userId": "6461762", "userTypeId": "1", "userStatus": "VALIDATED", "clientId": "516899", "userTag": "", "parentUserId": null, "parentType": null, "title": "M", "firstname": "Alex", "lastname": "Oak", "middleNames": "", "birthday": "1989-00-00", "email": "a.oak@example.com", "address1": "xxxxxxxxxxx", "address2": "", "address3": "", "postcode": "75000", "city": "Paris", "state": "Paris", "country": "FR", "countryName": "France", "phone": "+00000000000", "mobile": "+00000000000", "nationality": "FR", "nationalityOther": "", "placeOfBirth": "Caen", "birthCountry": "FR", "occupation": "", "incomeRange": "28-35", "legalName": "", "legalNameEmbossed": "", "legalRegistrationNumber": "", "legalTvaNumber": "", "legalRegistrationDate": "0000-00-00", "legalForm": "", "legalShareCapital": "0", "legalSector": "", "legalAnnualTurnOver": "", "legalNetIncomeRange": "", "legalNumberOfEmployeeRange": "", "effectiveBeneficiary": "0.00", "position": "", "personalAssets": "0-2", "taxResidence": "FR", "taxNumber": "", "kycLevel": "2", "kycReview": "2", "kycReviewComment": "30-05-2022 - 16:11:02Level : REGULAR et Review : VALIDATED", "isFreezed": "0", "language": null, "specifiedUSPerson": "0", "employeeType": "0", "entityType": "0", "controllingPersonType": "0", "activityOutsideEu": null, "economicSanctions": null, "residentCountriesSanctions": null, "involvedSanctions": null, "entitySanctionsQuestionnaire": null, "sanctionsQuestionnaireDate": null, "timezone": null, "createdDate": "2022-05-18 12:21:04", "modifiedDate": "2022-05-18 12:21:12", "codeStatus": "110009", "informationStatus": "", "sepaCreditorIdentifier": null, "walletCount": "1", "payinCount": "0", "totalRows": "1" } ] }, "webhook_created_at": 16539198620721, "webhook_id": "8f3577ec-c126-4e94-a3df-1bdccfb0b89f", "object_payload_signature": "Kg\/+Np3zU7vW9f6HbMCU0ueIIACCRfGKCiWa+PiLvzM=" }, "clientId": "516899" } ``` ::: ## Documents ### `document.create` ::: code-group ```json [JSON] { "webhook": "document.create", "webhook_id": "10XXXXXX", "object": "document", "object_id": "8XXXX", "object_payload": { "documents": [ { "documentId": "8XXXX", "documentTag": "LP'6C7`VGnREXXXXXXXX", "clientId": "4XXXX", "userId": "1XXXXXX", "userFirstname": "Victoria", "userLastname": "Perin", "name": "Merged_Passport.pdf", "documentStatus": "PENDING", "documentTypeId": "17", "documentType": "PASSPORT", "fileName": "8XXXX.pdf", "thumbFileName": "", "createdDate": "2020-05-19 10:34:21", "modifiedDate": "0000-00-00 00:00:00", "codeStatus": "600003", "informationStatus": "", "residenceId": "0" } ] }, "object_payload_signature": "bJaKKq6y4Ah5RhlZMIgHwClWMxGIxpBB4xdMJXddXXXX" } ``` ::: ### `document.update` ::: code-group ```json [JSON] { "webhook": "document.update", "webhook_id": "1XXXXXXX", "object": "document", "object_id": "8XXXX", "object_payload": { "documents": [ { "documentId": "8XXXX", "documentTag": "draftedstatutes", "clientId": "9XXXX", "userId": "1XXXXXX", "userFirstname": "MICHELE", "userLastname": "CRESSIN", "name": "draftedstatutes_2192.pdf", "documentStatus": "PENDING", "documentTypeId": "23", "documentType": "LEGAL_STATUS", "fileName": "80009.pdf", "thumbFileName": "", "createdDate": "2020-05-13 16:22:03", "modifiedDate": "2020-05-13 18:28:43", "codeStatus": "600003", "informationStatus": "", "residenceId": "0" } ] }, "object_payload_signature": "q53Gk3QsSuOurHDECo9CZZ4cs9GRMg8I81L21M6+XOXO" } ``` ::: You can check the list of `codeStatus` in the [Documents](/guide/user-verification/documents#status-documentstatus) article. ### `document.cancel` ::: code-group ```json [JSON] { "webhook": "document.cancel", "webhook_id": "1XXXXXX", "object": "document", "object_id": "8XXXX", "object_payload": { "documents": [ { "documentId": "8XXXX", "documentTag": "0000000", "clientId": "1XXXXX", "userId": "0000000", "userFirstname": "Marie", "userLastname": "bela", "name": "XXXXXX_doc", "documentStatus": "CANCELED", "documentTypeId": "21", "documentType": "PAYSLIP", "fileName": "AAAAA.jpg", "thumbFileName": "", "createdDate": "2020-05-18 22:55:13", "modifiedDate": "2020-05-18 20:55:24", "codeStatus": "600004", "informationStatus": "", "residenceId": "0" } ] }, "object_payload_signature": "OfyL8/fpm1FX33ubIWdPqG+bNsQlhCFm4yN0Zl8XXXXX" } ``` ::: ## KYC Liveness The following webhooks are sent for Live Verification (whether it is Liveness or Certified video). ### `kycliveness.create` ::: code-group ```json [JSON] { "webhook":"kycliveness.create", "webhook_id":"42424224-442z5-42ce9-8242-513d80c15142", "object":"identification", "object_id":"9dac1414-6733-46ae-b5a9-1b3aa39ea4bd", "object_payload":{ "kyc-status": "processing", "comment": "Some additional elements need to be verified. You will be notified by webhook when the final answer is ready.", "user_id":"2440234", "started-at": "2020-06-30T07:10:47.824723Z", "updated-at": "2020-06-30T07:15:18.856843Z", "score": 1, "identity": { "last-name": "OAK", "first-name": "ALEX", "birth-date": "1942-11-19", "gender": "M", "issuing-place": "", "birthplace": "PARIS" }, }, "object_payload_signature":"5Hfi\/ywu2fjtw0Exm22rJJwyZEej4Qp4BfPsamXAP\/42" } ``` ::: ### `kycliveness.update` ::: code-group ```json [JSON] { "webhook":"kycliveness.update", "webhook_id":"42424224-442z5-42ce9-8242-513d80c11111", "object":"identification", "object_id":"9dac1414-6733-46ae-b5a9-1b3aa39ea4xx", "object_payload":{ "updated-at": "2024-03-08T05:37:26.076003Z", "started-at": "2024-03-08T05:32:37.100594Z", "identity": { "last-name": "OAK", "first-name": "ALEX", "birth-date": "1990-07-18", "gender": "M", "issuing-place": "", "birthplace": "PARIS" }, "kyc-status": "processed", "comment": "Applicant did not show the full front view of their face, Applicant performed their id verification under poor lighting conditions, Applicant's identity does not match with the expected one", "refusal-details": { "meta": { "count": 3 }, "reasons": [ { "reason-code": "1312", "reason-message": "Applicant did not show the full front view of their face" }, { "reason-code": "1320", "reason-message": "Applicant performed their id verification under poor lighting conditions" }, { "reason-code": "2401", "reason-message": "Applicant's identity does not match with the expected one" } ] }, "user_id": "100196123", "score": 0 }, "object_payload_signature":"5Hfi\/ywu2fjtw0Exm22rJJwyZEej4Qp4BfPxxxXXX\/42" } ``` ::: ## Qualified eSignature The following webhooks are sent for qualified electronic signature (QES) verification. ### `qes.created` ::: code-group ```json [JSON] { "webhook": "qes.created", "object_payload": { "userId": "4137216", "result": "STARTED", "identificationTime": "", "identId": "TST-TWLYB", "transactionNumber": "b00ecdec-b721-55c4-8e20-ef3625616926", "type": "APP" }, "object_id": "b00ecdec-b721-55c4-8e20-ef3625616926", "object": "identification", "webhook_created_at": 17194724399022, "webhook_id": "af5a6c9e-4dc8-4d58-a245-e26dc27xx9aa", "object_payload_signature": "WUuvXuGyAL4dw9C12K3HxxRmUi3hMxxy8+4kMaRhLDo=" } ``` ::: ### `qes.processing` ::: code-group ```json [JSON] { "webhook": "qes.processing", "object_payload": { "userId": "4137216", "result": "CHECK_PENDING", "identificationTime": "2024-06-27T09:16:23+02:00", "identId": "TST-TWLYB", "transactionNumber": "b00ecdec-b721-55c4-8e20-ef3625616926", "type": "APP" }, "object_id": "b00ecdec-b721-55c4-8e20-ef3625616926", "object": "identification", "webhook_created_at": 17194725841286, "webhook_id": "5fa78cf6-c85b-46c2-b950-a7ad7e974291", "object_payload_signature": "WDeMRi95hkJhllJZBwfhc2xxRdF1aymVcDhybMzDsig=" } ``` ::: ### `qes.aborted` ::: code-group ```json [JSON] { "webhook": "qes.aborted", "object_payload": { "userId": "100438239", "result": "ABORTED", "identificationTime": "2024-06-15T10:58:02+02:00", "identId": "TST-ARJBA", "transactionNumber": "3606323f-345e-5105-bfb6-7ca324a69945", "type": "APP", "reason": { "reasonDetails": { "reasonCode": "3002", "reasonMessage": "USER_CANCELLATION_DOCUMENT_EXPIRED" } } }, "object_id": "3606323f-345e-5105-bfb6-7ca324a69945", "object": "identification", "webhook_created_at": 17184418842212, "webhook_id": "696b7f9e-020b-4b60-b91a-c7fab0a4940f", "object_payload_signature": "yNd+4XWx6bIeJn1/lzWliCb//Vwl8BkxxJ4y3+qwL4E=" } ``` ::: ### `qes.finalized` The structure of the webhook differs depending on its `result`. ::: code-group ```json [JSON (success)] { "webhook": "qes.finalized", "object_payload": { "userId": "4137216", "result": "SUCCESS_DATA_CHANGED", "identificationTime": "2024-06-27T09:16:23+02:00", "identId": "TST-TWLYB", "transactionNumber": "b00ecdec-b721-55c4-8e20-ef3625616926", "type": "APP", "identity": { "firstname": "ALEX", "lastname": "OAK", "birthday": "1983-08-12", "gender": "OTHER", "issuingPlace": "STADT KÖLN", "birthplace": "BERLIN" } }, "object_id": "b00ecdec-b721-55c4-8e20-ef3625616926", "object": "identification", "webhook_created_at": 17194726044907, "webhook_id": "8a7dfe6b-d44a-4b54-92a7-cc02c3d43eb8", "object_payload_signature": "svoHId/5xu940i24cJV82+nCYnzUDv4a9cxxAj9GvJo=" } ``` ```json [JSON (canceled)] { "webhook": "qes.finalized", "object_payload": { "userId": "4137216", "result": "CANCELED", "identificationTime": "2024-06-27T09:16:23+02:00", "identId": "TST-TWLYB", "transactionNumber": "b00ecdec-b721-55c4-8e20-ef3625616926", "type": "APP", "identity": { "firstname": "ALEX", "lastname": "OAK", "birthday": "1983-08-12", "gender": "OTHER", "issuingPlace": "STADT KÖLN", "birthplace": "BERLIN" }, "reason": { "reasonDetails": { "reasonCode": "3201", "reasonMessage": "WARNING_SELFIE_REAL_PERSON" } } }, "object_id": "b00ecdec-b721-55c4-8e20-ef3625616926", "object": "identification", "webhook_created_at": 17194726044907, "webhook_id": "8a7dfe6b-d44a-4b54-92a7-cc02c3d43eb8", "object_payload_signature": "svoHId/5xu940ixxcJV82+nCYnzUDv4a9cmYAj9GvJo=" } ``` ::: ## Video Conference The following webhooks are sent for video conference verification. ### `videoConference.created` ::: code-group ```json [JSON] { "webhook": "videoConference.created", "object_payload": { "userId": "4137216", "result": "STARTED", "identificationTime": "", "identId": "TST-TWLYB", "transactionNumber": "b00ecdec-b721-55c4-8e20-ef3625616926", "type": "APP" }, "object_id": "b00ecdec-b721-55c4-8e20-ef3625616926", "object": "identification", "webhook_created_at": 17194724399022, "webhook_id": "af5a6c9e-4dc8-4d58-a245-e26dc27xx9aa", "object_payload_signature": "WUuvXuGyAL4dw9C12K3HxxRmUi3hMxxy8+4kMaRhLDo=" } ``` ::: ### `videoConference.processing` ::: code-group ```json [JSON] { "webhook": "videoConference.processing", "object_payload": { "userId": "100764422", "result": "REVIEW_PENDING", "identificationTime": "2024-08-27T15:23:03+02:00", "identId": "TS2-FEJYN", "transactionNumber": "bd17f3e1-05fe-5b12-929c-0d4b9b27c4a2", "type": "WEB" }, "object_id": "bd17f3e1-05fe-5b12-929c-0d4bxxxc4a", "object": "identification", "webhook_created_at": 1724061955000, "webhook_id": "8a7dfe6b-d44a-4b54-92a7-cc02cxxx3eb8", "object_payload_signature": "svoHId/5xu940i24cJV82+nCYnzUDxxx9cxxAj9GvJo=" } ``` ::: ### `videoConference.aborted` ::: code-group ```json [JSON] { "webhook": "videoConference.aborted", "object_payload": { "userId": "4137216", "result": "ABORTED", "identificationTime": "2024-08-01T01:33:00+02:00", "identId": "TS2-KWYGX", "transactionNumber": "26dd014c-33f2-56f6-9ebc-bec12caxx2bf", "type": "WEB", "reason": { "reasonDetails": { "reasonCode": "", "reasonMessage": "STALLED_TIMEOUT" } } }, "object_id": "26dd014c-33f2-56f6-9ebc-bec1xxa162bf", "object": "identification", "webhook_created_at": 1724061955000, "webhook_id": "8a7dfe6b-d44a-4b54-92a7-cc02c3xx3eb8", "object_payload_signature": "svoHId/5xu940i24cJV82+nCYnzxx4a9cxxAj9GvJo=" } ``` ::: ### `videoConference.finalized` The structure of the webhook differs depending on its `result`. ::: code-group ```json [JSON (success)] { "webhook": "videoConference.finalized", "object_payload": { "userId": "100689821", "result": "SUCCESS_DATA_CHANGED", "identificationTime": "2024-08-19T10:05:55+02:00", "identId": "TS2-HGWTV", "transactionNumber": "11a08a9a-b05a-5127-b727-b32fa01616bc", "type": "WEB", "identity": { "firstname": "ALEX", "lastname": "OAK", "birthday": "1983-10-30", "gender": "F", "issuingPlace": "ISSUER", "birthplace": "BIRTHPLACE" } }, "object_id": "11a08a9a-b05a-5127-b727-b32fxxx16bc", "object": "identification", "webhook_created_at": 1724061955000, "webhook_id": "8a7dfe6b-d44a-4b54-92a7-cc02cxx3eb8", "object_payload_signature": "svoHId/5xu940i24cJV82+nCYnzUDv4a9cxxx9GvJo=" } ``` ```json [JSON (canceled)] { "webhook": "videoConference.finalized", "object_payload": { "userId": "4137216", "result": "CANCELED", "identificationTime": "2024-06-27T09:16:23+02:00", "identId": "TST-TWLYB", "transactionNumber": "b00ecdec-b721-55c4-8e20-ef3625616926", "type": "APP", "identity": { "firstname": "ALEX", "lastname": "OAK", "birthday": "1983-08-12", "gender": "OTHER", "birthplace": "BERLIN" }, "reason": { "reasonDetails": { "reasonCode": "3201", "reasonMessage": "WARNING_SELFIE_REAL_PERSON" } } }, "object_id": "b00ecdec-b721-55c4-8e20-ef3625616926", "object": "identification", "webhook_created_at": 17194726044907, "webhook_id": "8a7dfe6b-d44a-4b54-92a7-cc02c3d43eb8", "object_payload_signature": "svoHId/5xu940ixxcJV82+nCYnzUDv4a9cmYAj9GvJo=" } ``` ::: --- --- url: /guide/dashboard/users.md description: >- Let your team provide support regarding your end users using the Treezor Dashboard. --- # Users Users refer to your end users, whether they represent legal entities or physical persons. They can be directly created and managed from your Dashboard. ## Accessing your users You may access your user information by: * Taking advantage of the main *Search toolbar* * Navigating the *All Users* view ### Search toolbar The Dashboard main toolbar provides a series of user attributes-based search fields. You may take advantage of the search fields available in the main toolbar to find a specific user based on its: * **User Id** – The `userId` automatically generated by Treezor when creating a user. * **User Tag** – The [`userTag`](/guide/api-basics/objects-tags), a field you can populate to suit your needs. * **Email** – The `email` provided during the user creation. * **Name** – Takes into account the `firstName`, `lastName`, `legalName` and `email` provided during the user creation. Once one of the fields is populated, click on the "Search" button to launch the search. **Tip – Additional search fields** * **Card** – Use the `cardId` or the `publicToken` of the [Card](/guide/cards/introduction). * **Wallet** – Use the `walletId` generated by Treezor upon creating a [Wallet](/guide/wallets/introduction). ### All Users view The *All Users* view provides a table listing all your users with some key information. Upon clicking on a user, it opens the corresponding profile in the *Profiles Board* view. To help you navigate through the list, you have the following filters available: * **User type** – Allows you to display only one type of user (physical user, business user, non-governmental organization or governmental organization). * **Date range** – Allows you to display only users within a specific time frame. * **User status** – Allows you to display only users with the selected status (Pending, Validated, Canceled). Click on the “Clear” button on the rightmost side of the filters section to reset all the filters. ## Navigating the user’s profile ### Profile boards view The *Profile Boards* view is empty until you’ve performed a search or selected a user-related object. The view then displays as many tabs as there are selected users, with exhaustive information to navigate through. ### User information Once a user is selected, all the information is broken down into tabs for you to easily manage. |       | Tab | Description | | --- | --- | --- | | | **Overview** | All the key information about the user, summarized. If the KYC tab isn't displayed, you can also access the *Edit user* popup by clicking on the Edit button in the upper right corner. | | | **KYC / KYB** | For you to update user information, manage documents, and go through the user KYC/KYB process. |  | | **Children Users** /**Company members** | The list of [Children Users](#children-users) attached to the currently selected user. When clicking on the "Add Child" button, the [*Create User*](/guide/dashboard/users#creating-users) view is displayed and set up with the child creation path, with the currently selected user already defined as a parent. |  | | **Wallets** | All the user Wallets for you to manage. Find out more in the [Wallets](/guide/wallets/introduction) article. | | | **Cards** | All the user Cards for you to manage. Find out more in the [Cards](/guide/cards/introduction) article. |  | | **Beneficiaries** | All the user external accounts, sorted by usage. Find out more in the [Beneficiaries](/guide/transfers/beneficiaries) article. |  ### User Overview The user *Overview* tab displays information that depends on your activated features and the selected user type. You can see the main information at a glance and then use the links to dive into the details of the user's wallets and cards for instance. #### Wallets section The overview *Wallets* section displays the first few wallets, but also the overall [Balances](/guide/overview/glossary#balance), that is to say the sum of balances of all the user's wallets. For each displayed wallet, the following commands are available: |       | Action | Description | | --- | --- | --- | | | **Star** | Adds wallet as favorite. | | | **Unstar** | Remove from favorites. | | | **More** | Provide access to the **Download document** command, which allows you to select a PDF document to download. Learn more in the [Wallet commands](./wallets#wallet-commands) section. | | | **Details** | Switches the view to the [*Wallets*](./wallets#navigating-the-wallet-s-information) tab, with the corresponding wallet details displayed. | The "See all wallets" button is displayed in the bottom right corner if there are more wallets than the ones displayed in the overview. It indicates the total number of wallets and switches the view to the [*Wallets*](./wallets#navigating-the-wallet-s-information) tab when clicking on it. #### Cards section The overview *Cards* section displays the first few cards, with all their key information. Clicking on the details arrow switches the view to the [*Cards*](./cards#profiles-board-view-cards-tab) tab with the selected card details displayed. The "See all cards" button is displayed in the bottom right corner if there are more cards than the ones displayed in the overview. It indicates the total number of cards and switches the view to the [*Cards*](./cards#profiles-board-view-cards-tab) tab when clicking on it. ### Children users Hierarchical relations can exist between users, such as: * Family relations (a parent and actual children, usually minor). * Ownership relations between a company and its shareholders and representative. * Company relations with their employees. Because declarative data changes depending on the use case, the Dashboard offers as much context as possible, with specific tab names ("Children users" for physical users, "Company members" for legal entities), and the relevant [user creation path](/guide/dashboard/users#creating-users) when clicking on the "Add Child" button. ::: tabs \== Children Users tab \== Company Members tab ::: A few [use case examples](/guide/users/parent-children#use-cases) are available in the API Guides. ## Creating users There are multiple ways to access the *Create User* view, whether it is directly from the Navigation menu or the buttons located in the various views. This offers a series of creation paths tailored to the context. The creation paths are exhaustive so you can fill in all the information at once, including: * Fill declarative data * Upload documents * Declare tax residence * Create children users (company numbers, employees, parent-children relations, etc.) Information to fill in may differ depending on the creation path and your own model. Please note that non-required information and documents may be updated after the user creation (but before requesting a KYC Review). ### Specific options Here are a few specific features that may be available depending on your path. | Options | Physical | Business | Self-Employed | | --- | :---: | :---: | :---: | | **Select parent** Enter the parent user ID to create hierarchical relation. | | | | | **Prefill data** Use legal registration number to prefill data. | | | | | **Add company members** Create hierarchical relations and declare shareholders and legal representatives. | | | | ## Deleting a User When a User is not in business with you anymore, you may [delete](/guide/users/introduction#deletion) them. **Prerequisites – To delete a User** * The Balance of all of their Wallets must be `0` * No card transaction authorization can be pending To delete a user, you can use the "Delete user" button accessible from their profile. This action is irreversible. A success message is then displayed in the top of the view and the user status becomes "Deleted". **Note – Users can't be removed** For regulatory reasons, users can't be removed. Once deleted, they will still be displayed in the user list, with a "Deleted" status. ## Managing SCA devices The Dashboard allows you to manage the devices used by the end user for [Strong Customer Authentication (SCA)](/guide/strong-customer-authentication/introduction). You may find information about SCA devices in the *Profile Boards* view, *Profile* tab, if enabled in the Configuration. Each device corresponds to a created [SCA Wallet](/guide/strong-customer-authentication/introduction#sca-wallet-object) for the selected user on either: * A mobile device ([SDK implementation](/guide/strong-customer-authentication/sdk)) * A web browser ([Web Native implementation](/guide/strong-customer-authentication/introduction#web-native)) The following information is available regarding the SCA devices: status, creation date, device information (web or mobile), and the tag (custom information). The following device statuses can be displayed: * **Passcode missing** – User has to set their PIN (initially or after reset request). * **Active** – User has set their PIN. The device may be used for SCA. * **Locked** – The device has been locked. Available commands depend on the device status and your [User Role](/guide/dashboard/dashboard-users): | | Command | Description | | :---: | --- | --- | | | **Reset PIN** | Allows you to send a request to the end user to reset their SCA PIN code. For mobile devices only.  Should only be done if you're sure of the user identity. | | | **Secure SCA** | Allows you to [lock the device](#securing-sca-on-a-device), hence not allowing the user go through strong customer authentication. | | | **Unlock SCA** | Allows you to unlock the device. Should only be done if you're sure of the user identity. | | | **Delete SCA** | Allows you to delete the device. | You can use the status filter to access the list of all the devices that used to be enrolled. This may prove useful for customer services and fraud analysis for instance. ### Securing SCA on a device You may lock the device used for Strong Customer Authentication by using the "Secure SCA on this device" command. When doing so, you are prompted to select a reason for securing the device, and you can add a securing message. As a result, the device is "Blocked" and the entered information is displayed in the "Lock reason" and "Message" fields. **Security – End user information must be verified prior to unlocking** The "Unlock SCA for this device" and "Reset PIN" commands are available, but should be used with caution. It is your responsibility to make sure the user information is accurate to avoid any kind of fraudulent behavior. --- --- url: /guide/user-verification/qes.md description: >- Technical guide for verifying users (KYC) with qualified eSignature (QES) via the Treezor API. Includes required parameters, request structure, and response examples. --- # Qualified eSignature (QES) Some countries (such as Germany) enforce stricter standards on user verification. One way to follow such standards is by using a [Qualified Electronic Signature (QES)](/guide/overview/glossary#qualified-electronic-signature-qes). For Germany, this option requires a SEPA transfer into the user's Wallet as an extra validation step. Treezor relies on a user verification provider for QES services. In this process, you redirect end users to a URL where they follow the verification steps. The identity document uploaded during these steps is digitally signed according to QES standards. **Configuration – Environment configuration by Treezor** Contact Treezor to use the qualified eSignature feature. ## Process 1. You initiate QES verification for the User: [`/v1/users/{userId}/qes`](/api-reference/api-endpoints.html#tag/Verification%20Solutions%20\(KYC\)/postKycqes){target="\_self"} 2. Treezor answers with the QES URL (`identificationURL`). 3. You redirect the User to the `identificationURL` 4. The User follows the step-by-step QES verification process, hence uploading the document. 5. Treezor informs you of the documents processing with the [QES](/guide/user-verification/events#qualified-esignature) webhooks. 6. Once the [`qes.finalized`](/guide/user-verification/events#qes-finalized) webhook returns a success `Result`, you may request a [KYC review](#request-a-review-of-the-user): [`/v1/users/{userId}/Kycreview`](/api-reference/api-endpoints.html#tag/User%20KYC%20Review/putKycreview){target="\_self"} 7. Treezor sends you the [`user.kycreview`](events#user-kycreview) webhook upon validation or refusal. ## Key attributes (webhooks) QES verification relies on webhooks to provide you with information regarding the process: * [`qes.created`](/guide/user-verification/events#qes-created) – Received when the user completes the QES verification process. * [`qes.processing`](/guide/user-verification/events#qes-processing) – Received when the QES verification process is under review on the verification provider side. * [`qes.aborted `](/guide/user-verification/events#qes-aborted) – Received when the user abandons the QES process (see [Aborted reasons](#aborted-reasons) list for more details). * [`qes.finalized`](/guide/user-verification/events#qes-finalized) – Received when the verification process is done on the verification provider side, either successful or canceled (see [Canceled reasons](#canceled-reasons) list for more details). Below some of the key attributes you may find in these webhooks. | Attribute | Type | Description | | --- | --- | --- | | `result` | string | Indicates whether the user was successfully verified on the provider side. Can be: `START` – The verification process has started.`CHECK_PENDING` – The user is currently being verified.`FRAUD_SUSPICION_PENDING` – Further verifications are made due to fraud suspicions.`ABORTED` – The end user abandoned the QES verification process.`SUCCESS` – The end user's identity is verified.`SUCCESS_DATA_CHANGE` – The end user's identity is verified with data adjustments from provider.`FRAUD_SUSPICION_CONFIRMED` – The user identity is verified and is suspected of committing fraud.`CANCELED` – The verification couldn't be carried out by the provider. | | `reason` | object | Details about the result when necessary. See [Reasons list](#reasons) below. | ### Reasons The reason object of the webhook contains a `reasonCode` and a `reasonMessage` for you to better understand the result of the QES verification. #### Aborted reasons Here are the reasons you may find for aborted QES. | Code | Message | Description | |-------------|----------------|-------------| | `3001` | `USER_CANCELLATION_DOCUMENT_NOT_ACCEPTED` | User's ID document is not accepted for the verification process | | `3002` | `USER_CANCELLATION_DOCUMENT_EXPIRED` | User cannot continue the verification process due to an expired ID document | | `3003` | `USER_CANCELLATION_UNDERAGE` | User is underage and is not allowed to continue the verification process | | `3004` | `USER_CANCELLATION_CAMERA_ACCESS_DENIED` | User does not allow camera permission in the app | | `3005` | `USER_CANCELLATION_TERMS_DENIED` | User does not accept the terms and conditions | | `3006` | `USER_CANCELLATION_SELFIE_NOT_READY` | User is not ready for a selfie | | `3007` | `USER_CANCELLATION_APP_NOT_SCANNING` | User aborts as the app is not scanning the document | | `3008` | `USER_CANCELLATION_ESIGNING_REJECTED` | User does not accept the esigning request | | `3009` | `USER_CANCELLATION_ESIGNING_NAME_CONFIRMATION_REJECTED` | User's name is specified incorrectly (This applies only to the QES/Signing flow) | | `3010` | `USER_CANCELLATION_INCORRECT_PHONE_NUMBER` | User cancels as the phone number is specified incorrectly | | `3011` | `USER_CANCELLATION_IDENTIFY_LATER` | User wants to identify later | | `3012` | `USER_CANCELLATION_USER_NOT_INTERESTED` | User is not interested in performing the identity verification | | `3013` | `USER_CANCELLATION_APP_NOT_RESPONDING` | User aborts because the app is not responding | | `3014` | `USER_CANCELLATION_PRIVACY_CONCERNS` | User aborts due to privacy concerns | | `3015` | `USER_CANCELLATION_DOCUMENT_NOT_AVAILABLE` | User does not have the ID document available and aborts | | `3016` | `USER_CANCELLATION_OTHER` | User aborts the identification process in app for any other unspecified reason | | `3017` | `APP_CANCELLATION_APPROVAL_PHRASE_RETRY_LIMIT_REACHED` | This is used in the QES/esign flow when the app is unable to retrieve the approval phrases from the back end after multiple retries | | `3018` | `APP_CANCELLATION_APPROVAL_PHRASE_NO_CONTRACT` | App encounters a technical error in the Approval Phrases step in QES/esign | | `3019` | `APP_CANCELLATION_APPROVAL_PHRASE_INSUFFICIENT_DOCUMENT_COUNT` | In the Approval Phrases step for QES/esign, the required number of documents to be signed are not received from back end | | `3020` | `APP_CANCELLATION_OTP_MATCH_LIMIT_REACHED` | In the OTP Authentication step, the user has reached the allowed limit for number of OTP entries and cannot try again | | `3021` | `APP_CANCELLATION_TSP_TECHNICAL_EXCEPTION` | App encounters a technical error from the TSP side. If this error state does not resolve after multiple automatic retries, the user cannot proceed further and the ident is aborted with this reason | #### Canceled reasons Here are the reasons you may find for canceled QES. | Code | Message | Description | |-------------|----------------|-------------| | `3101` | `ID_BLURRY` | Document is blurry and mandatory data cannot be read due to the blur. | | `3102` | `ID_GLARE` | Document has glare and mandatory data cannot be read due to the glare. | | `3103` | `ID_DARKNESS` | Pictures of the document are dark and it is not possible to read the mandatory data or verify the authenticity of the document. | | `3104` | `ID_DATA_COVERED` | Mandatory data is covered by the user while taking the picture | | `3105` | `ID_PERSPECTIVE` | Document is positioned at such an angle that mandatory data cannot be read or document cannot be verified | | `3106` | `ID_DATA` | Mandatory data cannot be read on the document | | `3107` | `ID_DATA_OTHER` | Any other reason due to which mandatory data cannot be read | | `3108` | `ID_NOT_SUPPORTED` | Document used during the identification is not supported for the customer's use case | | `3109` | `ID_EXPIRED` | Document used during the identification is expired. | | `3110` | `ID_WRONG_SIDE` | Wrong side of the document is scanned during the process. | | `3111` | `ID_OUTWORN` | Document is worn out. Either data cannot be read out or the document cannot be verified. | | `3112` | `ID_HAS_STICKER` | Document has such stickers which are not acceptable and the document used is considered as damaged document. | | `3113` | `ID_WRITTEN_ON` | Document has text written over it which makes the document not readable or not verifiable. If the sticker is legit one and added by the authorities while issuing the document then the document will be acceptable and not cancelled due to this reason. | | `3114` | `ID_BROKEN` | Document used during the identification is broken. | | `3115` | `ID_DAMAGED` | Document used during identification is a damaged document. | | `3116` | `ID_DAMAGED_OTHER` | Any other reason for a damaged document. | | `3117` | `ID_SECURITY_FEATURE_NOT_VISIBLE_NOT_FRAUD` | Security features of the document are not visible because user did not move the document correctly. | | `3118` | `ID_SECURITY_FEATURE_VIDEO_SHORT` | Security feature video is too short to detect if there are holograms in the document. | | `3119` | `ID_SECURITY_FEATURE_VIDEO_CANNOT_BE_PLAYED` | Security feature video cannot be played for the agent to review holograms. | | `3120` | `ID_SECURITY_FEATURE_OTHER` | Any other issues with the security feature video. | | `3121` | `ID_SECOND_DOCUMENT` | If two documents are required for the identification process, the user needs to photograph two different documents (i.e. ID + Driver's license) - If the second required ID document is not available, the ident will be cancelled. | | `3122` | `ID_SECOND_DOCUMENT_BAD_PHOTO_QUALITY` | Photo quality of the additional document in the process is not acceptable. | | `3123` | `ID_SECOND_DOCUMENT_DAMAGED` | Additional document used in the identification process is severely outworn, written or drawn on, ripped or broken. | | `3124` | `ID_SECOND_DOCUMENT_EXPIRED` | Additional document used in the identification process is an expired document. | | `3125` | `ID_SECOND_DOCUMENT_OTHER` | Any other issues with the additional document used in the identification process. | | `3126` | `ID_NEED_ADDITIONAL_DOCUMENT` | Additional document like Driver's License is missing in the identification process but it was required. | | `3127` | `ID_OTHER` | Any other issues with the document used in the identification process. | | `3128` | `USER_INVOICE_MISSING` | Customer needs proof of address from the user as the additional document but user did not provide it in the identification process. | | `3129` | `USER_OBSCURED` | User has covered the face during the face comparison process unintentionally like wearing the face mask. | | `3130` | `SELFIE_BLURRY` | Selfie taken by the user is blurry and cannot be used to compare the face with the identification document. | | `3131` | `SELFIE_GLARE` | Photo of the user on the ID document has glares and selfie cannot be compared with it. | | `3132` | `SELFIE_DARKNESS` | Selfie taken by the user is too dark to compare the face of the person with the photo on the identification document. | | `3133` | `SELFIE_PERSPECTIVE` | Selfie taken by the user is on such an angle that it is not possible to compare it with the photo on the identification document. | | `3134` | `SELFIE_OTHER` | Any other issues with the selfie which restrict ident specialist to compare the selfie of the user with the photo on the identification document. | | `3135` | `IDENT_CANNOT_BE_COMPLETED` | Due to a technical reason, ident specialist cannot finish the identity verification process. | | `3136` | `IDENT_DISPLAY_ERROR` | Due to a technical reason, ident specialist cannot see the data submitted by the user in the identification process. | | `3137` | `IDENT_OTHER` | Any other reason due to which the identification process cannot be completed by the ident specialist. | | `3138` | `TSP_WRONG_CONFIRMATION_TOKEN` | A wrong signing code was entered by the user during the signing step. | | `3139` | `TSP_SIGNING_FAILED` | The signing process failed due to any technical error. | | `3140` | `TSP_CERTIFICATE_EXPIRED` | Signing certificates are valid for an hour. The final signing step took more than an hour from the time of certificate generation. | | `3141` | `ID_SECURITY_FEATURE_VIDEO_FILE_MISSING` | If enabled, the system automatically cancels an ident when the 'Security Features' (Hologram) video is not saved due to any technical error, and is hence missing from the final result (zip) file. | #### Fraud suspicion reasons **Important – Don't communicate fraud suspicion to end users** For legal reasons, you mustn't indicate to end users that they are suspected of fraud. Here are the reasons you may find for fraud suspicions. | Code | Message | Description | |-------------|----------------|-------------| | `3201` | `WARNING_SELFIE_REAL_PERSON` | User that performed the identification is a real person but the selfie does not match with the face on the document. | | `3202` | `WARNING_SELFIE_NO_REAL_PERSON` | Selfie taken in the identification person is not of a real person. For example, the selfie taken is a photo of a picture. | | `3203` | `WARNING_SELFIE_DISGUISED` | User intentionally disguised the face by wearing a mask or in some other way. | | `3204` | `WARNING_MANIPULATED_DATA` | Data is manipulated on the Identification document. | | `3205` | `WARNING_MANIPULATED_PHOTO` | Photo of the person is manipulated on the Identification document. | | `3206` | `WARNING_FAKED_SECURITY_FEATURES` | Security features like holograms on the Identification document are not real. | | `3207` | `WARNING_PAPER_PRINT` | The Identification document is not real but a printout taken on a paper. | | `3208` | `WARNING_DIGITAL_DOCUMENT` | Identification document image is taken from a digital screen (from laptop, from mobile or from any other screen). | | `3209` | `WARNING_FAKED_SPECIMEN` | Identification document is a specimen document and not real document. | | `3210` | `WARNING_USER_UNDERAGE` | User is below the age required to access the customer's service. | | `3211` | `WARNING_DIGITAL_SELFIE` | Selfie is taken from a digital screen (from laptop, from mobile or from any other screen). | | `3212` | `WARNING_MONEY_MULE` | User is duped by fraudster to perform identification on fraudster's behalf. | | `3213` | `WARNING_NAME_COMPARISON` | Considerable inconsistency between user's name and document. | | `3214` | `WARNING_SCAN` | Identification document is a facsimile. | | `3215` | `WARNING_FRAUD_OTHER` | Any other type of fraud identified during the verification process by Ident specialist. | ## Initiate QES verification Before initiating the QES verification process, the User must be created with the relevant attributes (as required by Treezor Compliance). At least the `firstname`, `lastname`, `email`, `country`, and `phone` fields of the user must be populated, otherwise, the API call returns an HTTP 428 error. ### Parameters You can optionally override the default URL to which the user will be redirected after the QES verification. | Attribute | Type | Description | | --- | --- | --- | | `redirectUrl` | string | The URL to which the User will be redirected after the QES verification. | ### Request You can use the following request to initiate the QES verification process. ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/v1/users/{userId}/qes' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{"redirectUrl": "https://www.my-domain.tld"}' ``` ::: Answers with a 201 HTTP Status Code and returns the identifier of the verification process and the `identificationURL`. The latter is where the end user is to be redirected to go through the qualified electronic signature process. ::: code-group ```json [JSON] { "identification": { "identificationId": {{identification-id}}, "identificationURL": "https://go.idnow.de/app/treezoramlauto/identifications/{{identification-id}}/identification/routing/start", } } ``` ::: Once redirected, end users are guided through the QES verification steps, in which they present a verification document. ### End user QES verification Once redirected, end users are guided through the QES steps. ::: details Click to see the Qualified eSignature steps for your end users (mobile) ::: After the last step: * The user is redirected to the `redirectUrl` or the URL configured with Treezor. * Treezor sends you a `qes.created` webhook. * The verification documents are automatically created once the `qes.finalized` webhook is received. ## Download the QES documents If you're eligible, you may be able to collect some of the uploaded documents whose `documentTypeId` allows for it. **Configuration – Download is not enabled by default** Please contact Treezor to request access to this feature. Downloading a document is a 2-step process, in which you: 1. [Request the download URL](#request-the-download-url) 2. [Download the document within 30 seconds](#download-the-document) ### Request the download URL To request the download URL, you need the corresponding `documentId` (available in the `document.create` webhook for instance). ::: code-group ```bash [CURL] curl -X GET '{baseUrl}/v1/documents/{documentId}/download' \ --header 'Authorization: Bearer {accessToken}' ``` ::: Returns the URL to download the document, with all the necessary query parameters for the next step. ::: code-group ```json [JSON] { "url": "{documentDownloadUrl}" } ``` ::: ### Download the document You have 30 seconds to download the document from the moment the presigned URL has been generated in the previous step. ::: code-group ```bash [CURL] curl -X GET '{documentDownloadUrl}' ``` ::: The document is returned in its initial format. ## Request a KYC Review for the User Before requesting a KYC review from Treezor, please make sure all the information and documents are properly updated for the user. You can use the dedicated endpoint: * [`/v1/users/{userId}/Kycreview`](/api-reference/api-endpoints.html#tag/User%20KYC%20Review/putKycreview){target="\_self"} **Alert – Documents must be uploaded for children users too** When there are [parent-children hierarchical relationship](/guide/users/parent-children), in most cases, the KYC Review must only be requested for the parent user. But you may need to upload [Documents](./documents) for the children before that. Please abide by the Treezor Compliance team recommendation for a smooth experience. Learn more in the [KYC Request](./kyc-request) article. ## Endpoints | Endpoint |[Scope](/guide/api-basics/authentication#available-scopes) | | --- | --- | | [`/v1/users/{userId}/qes`](/api-reference/api-endpoints.html#tag/Verification%20Solutions%20\(KYC\)/postKycqes){target="\_self"} Initiate the user [QES verification](/guide/user-verification/introduction) process | `read_write` | | [`/v1/documents/{documentId}/download`](/api-reference/api-endpoints.html#tag/User%20Documents/getDocumentDownloadUrl){target="\_self"} Retrieve a document download URL | `read_only` | | [`/v1/users/{userId}/Kycreview`](/api-reference/api-endpoints.html#tag/User%20KYC%20Review/putKycreview){target="\_self"} Initiate the user [KYC review](/guide/user-verification/introduction) process | `read_write` | --- --- url: /guide/user-verification/videoconf.md description: >- Technical guide for verifying users (KYC) with Video Conference via the Treezor API. Includes required parameters, request structure, and response examples. --- # Video Conference The Video Conference feature verifies the user through an online video call with an expert. The expert reviews the ID card and asks key questions to the end user to ensure they are who they claim to be. Treezor relies on a user verification provider for Video Conference services. In this process, you redirect end users to a URL where they follow verification steps, including a video conference with an agent. **Configuration – Environment configuration by Treezor** Contact Treezor to use the video conference feature. ## Process 1. You initiate video conference verification for the User: [`/v1/users/{userId}/videoconference`](/api-reference/api-endpoints.html#tag/Verification%20Solutions%20\(KYC\)/postKycVconf){target="\_self"} 2. Treezor answers with the video conference URL (`identificationURL`). 3. You redirect the User to the `identificationURL` 4. The User follows the step-by-step process, hence uploading the document (ID) while online with the expert. 5. Treezor informs you of the documents processing with the [Video Conference](/guide/user-verification/events#video-conference) webhooks. 6. Once the [`videoConference.finalized`](/guide/user-verification/events#video-conference) webhook returns a success `Result`, you may request a [KYC review](#request-a-review-of-the-user): [`/v1/users/{userId}/Kycreview`](/api-reference/api-endpoints.html#tag/User%20KYC%20Review/putKycreview){target="\_self"} 7. Treezor sends you the [`user.kycreview`](events#user-kycreview) webhook upon validation or refusal. ## Key attributes (webhooks) Video conference relies on webhooks to provide you with information regarding the process: * [`videoConference.created`](/guide/user-verification/events#videoconference-created) – Received when the user completes the video conference verification process. * [`videoConference.processing`](/guide/user-verification/events#videoconference-processing) – Received when the video conference verification process is under review on the verification provider side. * [`videoConference.aborted`](/guide/user-verification/events#videoconference-aborted) – Received when the user abandons the video conference process (see [Aborted reasons](#aborted-reasons) list for more details). * [`videoConference.finalized`](/guide/user-verification/events#videoconference-finalized) – Received when the verification process is done on the verification provider side, either successful or canceled (see [Canceled reasons](#canceled-reasons) list for more details). | Attribute | Type | Description | | --- | --- | --- | | `result` | string | Indicates whether or not the user was successfully verified on the provider side. Can be: `START` – The verification process has started.`REVIEW_PENDING` – The user is currently being verified.`FRAUD_SUSPICION_PENDING` – Further verifications are made due to fraud suspicions.`ABORTED` – The end user abandoned the verification process.`SUCCESS` – The end user's identity is verified.`SUCCESS_DATA_CHANGE` – The end user's identity is verified with data adjustments from provider.`FRAUD_SUSPICION_CONFIRMED` – The user identity is verified and is suspected of committing fraud.`CANCELED` – The verification couldn't be carried out by the provider. | | `reason` | object | Details about the result when necessary. See [Reasons list](#reasons) below. | ### Reasons The reason object of the webhook contains a `reasonCode` and a `reasonMessage` for you to better understand the result of the Video Conference verification. #### Aborted reasons Here are the reasons you may find for aborted video conference. | Code | Message | Description | |-------|------------|------------------| | `4001`| `USER_CANCELLATION_DOCUMENT_NOT_ACCEPTED`| User's ID document is not accepted for the verification process. | | `4002`| `USER_CANCELLATION_DOCUMENT_EXPIRED` | User cannot continue the verification process due to an expired ID document.| | `4003`| `USER_CANCELLATION_UNDERAGE` | User is underage and is not allowed to continue the verification process. | | `4004`| `USER_CANCELLATION_CAMERA_ACCESS_DENIED` | User does not allow camera permission in the app. | | `4005`| `USER_CANCELLATION_TERMS_DENIED` | User does not accept the terms and conditions. | | `4006`| `USER_CANCELLATION_SELFIE_NOT_READY` | User is not ready for a selfie. | | `4007`| `USER_CANCELLATION_APP_NOT_SCANNING` | User aborts as the app is not scanning the document. | | `4008`| `USER_CANCELLATION_INCORRECT_PHONE_NUMBER` | User cancels as the phone number is specified incorrectly. | | `4009`| `USER_CANCELLATION_IDENTIFY_LATER` | User wants to identify later. | | `4010`| `USER_CANCELLATION_USER_NOT_INTERESTED` | User is not interested in performing the identity verification. | | `4011`| `USER_CANCELLATION_APP_NOT_RESPONDING` | User aborts because the app is not responding. | | `4012`| `USER_CANCELLATION_PRIVACY_CONCERNS` | User aborts due to privacy concerns. | | `4013`| `USER_CANCELLATION_DOCUMENT_NOT_AVAILABLE` | User does not have the ID document available and aborts. | | `4014`| `APP_CANCELLATION_OTP_MATCH_LIMIT_REACHED` | User has reached the allowed limit for number of OTP entries and cannot try again. | | `4015`| `USER_CANCELLATION_AGENT_BEHAVIOUR` | User does not feel comfortable to continue identification due to the agent's behaviour. | #### Canceled reasons Here are the reasons you may find for canceled video conference. | Code | Message | Description | |-------|---------------|---------------| | `4101`| `ID_BLURRY` | Document is blurry and mandatory data cannot be read due to the blur. | | `4102`| `ID_GLARE` | Document has glare and mandatory data cannot be read due to the glare. | | `4103`| `ID_DARKNESS` | Pictures of the document are dark and it is not possible to read the mandatory data or verify the authenticity of the document. | | `4104`| `ID_DATA_COVERED` | Mandatory data is covered by the user while taking the picture. | | `4105`| `ID_PERSPECTIVE` | Document is positioned at such an angle that mandatory data cannot be read or document cannot be verified. | | `4106`| `ID_DATA_OTHER` | Any other reason due to which mandatory data cannot be read. | | `4107`| `ID_NOT_SUPPORTED` | Document used during the identification is not supported for the customer's use case. | | `4108`| `ID_EXPIRED` | Document used during the identification is expired. | | `4109`| `ID_WRONG_SIDE` | Wrong side of the document is scanned during the process. | | `4110`| `ID_OUTWORN` | Document is worn out. Either data cannot be read out or the document cannot be verified. | | `4111`| `ID_HAS_STICKER` | Document has such stickers which are not acceptable and the document used is considered as damaged document. | | `4112`| `ID_WRITTEN_ON` | Document has text written over it which makes the document not readable or not verifiable. If the sticker is legit one and added by the authorities while issuing the document then the document will be acceptable and not cancelled due to this reason. | | `4113`| `ID_BROKEN` | Document used during the identification is broken. | | `4114`| `ID_DAMAGED_OTHER` | Any other reason for a damaged document. | | `4115`| `ID_SECURITY_FEATURE_NOT_VISIBLE_NOT_FRAUD` | Security features of the document are not visible because user did not move the document correctly. | | `4116`| `ID_SECURITY_FEATURE_VIDEO_SHORT` | Security feature video is too short to detect if there are holograms in the document. | | `4117`| `ID_SECURITY_FEATURE_VIDEO_CANNOT_BE_PLAYED` | Security feature video cannot be played for the agent to review holograms. | | `4118`| `ID_SECURITY_FEATURE_OTHER` | Any other issues with the security feature video. | | `4119`| `ID_SECOND_DOCUMENT_BAD_PHOTO_QUALITY` | Photo quality of the additional document in the process is not acceptable. | | `4120`| `ID_SECOND_DOCUMENT_DAMAGED` | Additional document used in the identification process is severely outworn, written or drawn on, ripped or broken. | | `4121`| `ID_SECOND_DOCUMENT_EXPIRED` | Additional document used in the identification process is an expired document. | | `4122`| `ID_NEED_ADDITIONAL_DOCUMENT` | Additional document like Driver's License is missing in the identification process but it was required. | | `4123`| `ID_SECOND_DOCUMENT_OTHER` | Any other issues with the additional document used in the identification process. | | `4124`| `ID_OTHER` | Any other issues with the document used in the identification process. | | `4125`| `USER_INVOICE_MISSING`| Customer needs proof of address from the user as the additional document but user did not provide it in the identification process. | | `4126`| `USER_OBSCURED` | User has covered the face during the face comparison process unintentionally like wearing the face mask. | | `4127`| `SELFIE_BLURRY` | Selfie taken by the user is blurry and cannot be used to compare the face with the identification document. | | `4128`| `SELFIE_GLARE` | Photo of the user on the ID document has glares and selfie cannot be compared with it. | | `4129`| `SELFIE_DARKNESS` | Selfie taken by the user is too dark to compare the face of the person with the photo on the identification document. | | `4130`| `SELFIE_PERSPECTIVE` | Selfie taken by the user is on such an angle that it is not possible to compare it #### Final reasons Here are the reasons you may find for finalized video conference. | Code | Message | Description | |-------|------------------------------------|-------------------------------------------------------------------------------------------------| | `4201`| `WARNING_SELFIE_REAL_PERSON` | User that performed the identification is a real person but the selfie does not match with the face on the document. | | `4202`| `WARNING_SELFIE_NO_REAL_PERSON` | Selfie taken in the identification process is not of a real person. For example, the selfie taken is a photo of a picture. | | `4203`| `WARNING_SELFIE_DISGUISED` | User intentionally disguised the face by wearing a mask or in some other way. | | `4204`| `WARNING_MANIPULATED_DATA` | Data is manipulated on the Identification document. | | `4205`| `WARNING_MANIPULATED_PHOTO` | Photo of the person is manipulated on the Identification document. | | `4206`| `WARNING_FAKED_SECURITY_FEATURES` | Security features like holograms on the Identification document are not real. | | `4207`| `WARNING_PAPER_PRINT` | The Identification document is not real but a printout taken on a paper. | | `4208`| `WARNING_DIGITAL_DOCUMENT` | Identification document image is taken from a digital screen (from laptop, from mobile or from any other screen). | | `4209`| `WARNING_FAKED_SPECIMEN` | Identification document is a specimen document and not a real document. | | `4210`| `WARNING_USER_UNDERAGE` | User is below the age required to access the customer's service. | | `4211`| `WARNING_DIGITAL_SELFIE` | Selfie is taken from a digital screen (from laptop, from mobile or from any other screen). | | `4212`| `WARNING_MONEY_MULE` | User is duped by fraudster to perform identification on fraudster's behalf. | | `4213`| `WARNING_NAME_COMPARISON` | Considerable inconsistency between user's name and document. | | `4214`| `WARNING_SCAN` | Identification document is a facsimile. | | `4215`| `WARNING_FRAUD_OTHER` | Any other type of fraud identified during the verification process by Ident specialist. | ## Initiate Video conference verification Before initiating the video conference verification process, the User must be created with the relevant attributes (as required by Treezor Compliance). At least the `firstname`, `lastname`, `email`, `country`, and `phone` fields of the user must be populated, otherwise, the API call returns an HTTP 428 error. ### Parameters You can optionally override the default URL to which the user will be redirected after the video conference verification. | Attribute | Type | Description | | --- | --- | --- | | `redirectUrl` | string | The URL to which the User will be redirected after the video conference verification. | ### Request You can use the following request to initiate the video conference verification process. ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/v1/users/{userId}/videoconference' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{"redirectUrl": "https://www.my-domain.tld"}' ``` ::: Answers with a 201 HTTP Status Code and returns the identifier of the verification process and the `identificationURL`. The latter is where the end user is to be redirected to go through the video conference verification process. ::: code-group ```json [JSON] { "identification": { "identificationId": {{identification-id}}, "identificationURL": "https://go.idnow.de/app/treezoramlauto/identifications/{{identification-id}}/identification/routing/start", } } ``` ::: ### End user verification Once redirected, end users are guided through the video conference verification steps, in which they present a verification document while talking online with the expert. ## Download the documents If you're eligible, you may be able to collect some of the uploaded documents whose `documentTypeId` allows for it. **Configuration – Download is not enabled by default** Please contact Treezor to request access to this feature. Downloading a document is a 2-step process, in which you: 1. [Request the download URL](#request-the-download-url) 2. [Download the document within 30 seconds](#download-the-document) ### Request the download URL To request the download URL, you need the corresponding `documentId` (available in the `document.create` webhook for instance). ::: code-group ```bash [CURL] curl -X GET '{baseUrl}/v1/documents/{documentId}/download' \ --header 'Authorization: Bearer {accessToken}' ``` ::: Returns the URL to download the document, with all the necessary query parameters for the next step. ::: code-group ```json [JSON] { "url": "{documentDownloadUrl}" } ``` ::: ### Download the document You have 30 seconds to download the document from the moment the presigned URL has been generated in the previous step. ::: code-group ```bash [CURL] curl -X GET '{documentDownloadUrl}' ``` ::: The document is returned in its initial format. ## Request a KYC Review for the User Before requesting a KYC review from Treezor, please make sure all the information and documents are properly updated for the user. You can use the dedicated endpoint: * [`/v1/users/{userId}/Kycreview`](/api-reference/api-endpoints.html#tag/User%20KYC%20Review/putKycreview){target="\_self"} **Alert – Documents must be uploaded for children users too** When there are [parent-children hierarchical relationship](/guide/users/parent-children), in most cases, the KYC Review must only be requested for the parent user. But you may need to upload [Documents](./documents) for the children before that. Please abide by the Treezor Compliance team recommendation for a smooth experience. Learn more in the [KYC Request](./kyc-request) article. ## Endpoints | Endpoint |[Scope](/guide/api-basics/authentication#available-scopes) | | --- | --- | | [`/v1/users/{userId}/videoconference`](/api-reference/api-endpoints.html#tag/Verification%20Solutions%20\(KYC\)/postKycVconf){target="\_self"} Initiate the user Video Conference verification process | `read_write` | | [`/v1/documents/{documentId}/download`](/api-reference/api-endpoints.html#tag/User%20Documents/getDocumentDownloadUrl){target="\_self"} Retrieve a document download URL | `read_only` | | [`/v1/users/{userId}/Kycreview`](/api-reference/api-endpoints.html#tag/User%20KYC%20Review/putKycreview){target="\_self"} Initiate the user [KYC review](/guide/user-verification/introduction) process | `read_write` | --- --- url: /guide/wallets/error-codes.md description: >- Troubleshoot and handle wallet-related issues using the Treezor API's complete list of error codes, messages, and their corresponding meanings. --- # Errors **Caution – Only the legacy API sends the error code in HTTP errors** When handling errors with Connect, only the `message` attribute is returned. ## Wallets The following API errors can be encountered when dealing with wallets. | Code | Message | Additional information | |:---: |--- |--- | | `12001` | Impossible to read Wallet | | | `12002` | Impossible to create Wallet | | | `12010` | Impossible to update Wallet | | | `12011` | Impossible to update Wallet, the wallet is already canceled | | | `12012` | eventPayinStartDate format is not valid | | | `12013` | eventPayinEndDate format is not valid | | | `12014` | eventPayinStartDate cannot be earlier than the creation date of the wallet | | | `12015` | eventPayinStartDate can't succeed eventPayinEndDate | | | `12016` | eventPayinEndDate cannot be earlier than eventPayinStartDate | | | `12018` | Impossible to change eventPayinStartDate when a gift is already offered | | | `12020` | Impossible to Cancel Wallet. The wallet does not exist | | | `12021` | Impossible to create Wallet image repository | | | `12022` | Impossible to create Wallet image file | | | `12023` | Impossible to create Wallet, Tarif is not comform | | | `12024` | Impossible to create Wallet, Tarif does not exist | | | `12025` | Impossible to create Wallet, Alias is not unique | | | `12026` | Unable to create Wallet. The unicity of the alias can't be checked. | | | `12027` | Impossible to update Wallet, eventPayinEndDate can't be lower than today | | | `12028` | Impossible to update Wallet, WalletId is not valid | | | `12029` | Impossible to Cancel Wallet, WalletId is not valid | | | `12030` | Impossible to Cancel Wallet, The wallet is already in status CANCELLED | | | `12031` | Impossible to create Wallet, User Id required | | | `12032` | Impossible to create Wallet, User Id not permitted | | | `12033` | Impossible to create Wallet, Joint User Id not valid | | | `12034` | Impossible to create Wallet, Currency must be EUR | | | `12035` | Unable to create the wallet. eventPayinEndDate cannot be earlier than eventPayinStartDate | | | `12036` | Impossible to create Wallet, Name is required | | | `12037` | Unable to create wallet. The event Payin Start Date is mandatory. | | | `12038` | Unable to create wallet. The event Payin End Date is mandatory. | | | `12039` | Unable to create wallet. The origin is not correct | | | `12040` | Unable to Cancel wallet. The origin is not correct | | | `12041` | Unable to Cancel wallet. Balance is not null. | | | `12042` | Unable to retrieve a wallet in the Database | | | `12043` | No status retrieved for wallet in Database | | | `12044` | The status linked to the wallet has no name | | | `12045` | The wallet has no user linked impossible to continue | | | `12046` | The wallet has no Tariff | | | `12047` | The wallet has no Tariff specified for an incoming SCTR | | | `12048` | The wallet has no Tariff specified for an incoming SDDR | | | `12049` | The walletTypeId is missing | | | `12050` | The walletTypeId must be 9 (Electronic Money Wallet), or 10 (Payment Account Wallet), or 13 (Mirror Account) | | | `12051` | Impossible to change the type of the wallet due to presence of transactions for this wallet | | | `12052` | The walletId is missing | | | `12053` | The beneficiaryName is missing | | | `12054` | The beneficiaryAddress is missing | | | `12055` | The beneficiaryIban is missing | | | `12056` | The beneficiaryBic is missing | | | `12057` | No status retrieved for wallet in Database | | | `12058` | The beneficiaryName is not valid | | | `12059` | The beneficiaryAddress is not valid | | | `12060` | The beneficiaryIban is not valid | | | `12061` | The wallet cannot be closed yet | | | `12062` | The wallet is already closed | | | `12063` | The wallet have not cards which linked to | | | `12064` | Error during block card linked to the wallet | | | `12065` | The request must contains at least one of those inputs : walletId, eventAlias, userId, walletTypeId | | | `12066` | Impossible to Cancel Wallet, The wallet has pending payin refunds | | | `12067` | No wallet retrieved | | | `12068` | Impossible to create Wallet, the user is freezed | Blocked users can't have new wallets. | | `12069` | Impossible to create Wallet, the user is legal frozen | Users whose assets are frozen can't have new wallets. | | `12070` | Impossible to cancel the wallet, technical card wallets cannot be canceled | | | `12071` | Impossible to create the wallet, field bic should not be empty when provided | | | `12072` | Impossible to create the wallet, the provided bic is not correct | | | `12073` | Impossible to create the wallet, the provided bic met too much possible candidate | | | `12074` | Impossible to create the wallet, please provide a valid bic | | | `12075` | Impossible to create the wallet, invalid payment institution bic | | | `12076` | Impossible to create the wallet, the bic provided is not authorized | | | `12077` | Impossible to create the wallet, the iban could not be generated | | | `12078` | Impossible to create wallet due to user status | Users must be validated to own a wallet. You need to wait until the status is no longer `PENDING`. | | `12079` | Impossible to create the wallet. A legal representative need to be declared | Create a physical user hierarchically attached to the legal entity owning the wallet to declare the legal representative. | ## Anonymous Electronic Money Wallets Exceeding *Electronic Money Wallets* limitations or restrictions will produce the following errors. ### In Requests | Context | Endpoint | Code | Message | |--- |--- |--- |--- | | SDDE | `/payins` | `14058` | You attempt to create a payin of type SDD Core, The wallet is not of type compte de paiement, impossible to continue | | Payouts | `/payouts` | `16027` | Impossible to create Payout due to incoherent KYC level | | Transfers | `/transfers` | `120019` | Impossible to create the operation, the total debit exceed the max total debit limit on sliding period | | Transfers, Payins | `/transfers`, `/payins` | `120020` | Impossible to create the operation, the authorization amount exceed the max amount limit | | Transfers, Payins | `/transfers`, `/payins` | `120021` | Impossible to create the operation, the authorization amount added to the account limit exceed the max account amount limit | | Transfers | `/transfers` | `120022` | Impossible to create the operation, the transfer creditor user is invalid | | Transfers | `/transfers` | `120023` | Impossible to create the operation, the transfer debitor user is invalid | | Transfers, Payins | `/transfers`, `/payins` | `120026` | Impossible to create the operation, the total credit exceed the max total credit limit on sliding period | ### In Webhooks | Context | Webhook | Error | Message (if any) | |--- |--- |--- |--- | | SDDR | `sepa.reject_sddr_core` | `reject_reason_code`=`AG01` | | | SDDR | `sepa.reject_sddr_b2b` | `reject_reason_code`=`AG01` | | | SDDR | `sepa.return_sddr` | `reject_reason_code`=`AG01` | | | SCTR | `sepa.return_sctr` | `return_reason_code`=`AG01` | | | SCTR | `sepa.return_sctr` | `return_reason_code`=`RR04` | | | SCTR Inst | `sepaSctrInst.reject_sctr_inst` | `return_reason_code`=`RR04` | | | Card Payment | `cardtransaction.create` | `authorizationResponseCode`=`57` | Electronic Money : transaction not permitted to cardholder | | Card Payment | `cardtransaction.create` | `authorizationResponseCode`=`57` | Electronic Money : cumulative amount authorized exceeded | | Card Payment | `cardtransaction.create` | `authorizationResponseCode`=`57` | Electronic Money : amount exceeds the authorized amount | | Card Payment | `cardtransaction.create` | `authorizationResponseCode`=`57` | Electronic Money : payment is not permitted in this country | | Card Payment | `cardtransaction.create` | `authorizationResponseCode`=`57` | Electronic Money : refused due to error | ## Balances | Code | Message | |:---------:|-------------------------------------------------------------------------------------------------------------| | `24000` | No balance corresponds to your search. | | `24001` | Exception while attempting to update authorizations | | `24002` | Impossible to continue operation. Balance data on wallet were not retrieved | | `24003` | walletId is mandatory | | `24004` | You must provide at least one argument: walletId or userId | ## Virtual IBANs The following API errors can be encountered when dealing with [virtual IBANs](/guide/wallets/iban##virtual-iban). | Code | Message | |:------:|------------------------------------------------------------------------------------------------------------------| | `71001` | No Wallet Linked to the Virtual IBAN | | `71002` | The wallet linked to the IBAN has no status | | `71003` | Wallet linked to the Virtual Iban has a not permitted Status | | `71004` | Currency of operation does not match the currency of wallet linked to the virtualIban | | `71005` | This transaction type is not supported by the virtual IBAN System | | `71006` | Transaction type not specified in virtual Iban Object impossible to check validity of virtual Iban regarding operation | | `71007` | Transaction type of operation is not supported by the virtual Iban | | `71008` | Impossible to add a new transaction for this virtualIban, number of transactions will be exceeded | | `71009` | Impossible to add a new transaction for this virtualIban, max amount will be exceeded | | `71010` | Validity date of this virtual Iban is KO | | `71011` | The virtual iban with the id provided does not exist | | `71012` | Impossible to create an iban | | `71013` | The field walletId must be provided | | `71014` | The field validFrom is lower than current date | | `71015` | The field validTo is lower than date validFrom | | `71016` | The field reference has a limit of 255 characters | | `71017` | The field tag has a limit of 255 characters | | `71018` | The field maxUsage must be higher than 1 | | `71019` | The field maxUsage must be higher than the number of transactions made by the virtualIban | | `71020` | The field maxAmount must be higher than 1 | | `71021` | The field maxAmount must be higher than the cumulated amount | | `71022` | The field maxAmount must follow this format: '2.15' | | `71023` | The field virtualibanId must be provided | | `71024` | The typeId is required | | `71025` | The typeId is invalid | | `71026` | Unable to create virtual IBAN. Database Error. | | `71027` | Wallet linked to the Virtual Iban has a not permitted type | ## Transactions The following API errors can be encountered when dealing with [transactions](/guide/wallets/transactions). | Code | Message | |:---------:|--------------------------------------------------------------------------------------------------------------------------------------------------------| | `23000` | Impossible to read Transaction. Database Error. | | `23001` | Card transaction already in transaction. | | `23003` | The request must contain at least one of these inputs: walletId, transactionId, executionDate, valueDate. | | `23004` | createdDateFrom must be a valid YYYY-MM-DD HH:MM:SS date. | | `23005` | createdDateTo must be a valid YYYY-MM-DD HH:MM:SS date. | | `23006` | createdDateTo cannot be lower than createdDateFrom. | | `23007` | transactionTypeId and transactionType do not refer to the same TransactionType. | | `23008` | transactionType should be a string. | | `23009` | transactionTypeId should be numeric (string or integer). | --- --- url: /guide/wallets/events.md description: >- Reference a comprehensive list of wallet events for Treezor API webhooks, detailing each event's structure and payload for integration. --- # Events This article lists the [Webhooks](/guide/webhooks/introduction) you may receive when regarding Wallets. ## Wallets ### `wallet.create` ::: code-group ```json [JSON] { "webhook":"wallet.create", "webhook_id":"648614636", "object":"wallet", "object_id":"4330619", "object_payload":{ "wallets":[ { "walletId":"4330619", "walletTypeId":"9", "walletStatus":"VALIDATED", "userId":"3691057", "jointUserId":"0", "walletTag":"62090", "currency":"EUR", "eventDate":"2021-04-29", "eventMessage":"", "eventAlias":"XXXX", "eventPayinStartDate":"2021-04-22", "eventPayinEndDate":"0000-00-00", "contractSigned":"0", "urlImage":"", "createdDate":"2021-04-22 14:54:14", "modifiedDate":"0000-00-00 00:00:00", "tariffId":"59", "eventName":"XXXX", "userFirstname":"XXXX", "userLastname":"XXXX", "codeStatus":"120005", "informationStatus":"", "payinCount":"0", "payoutCount":"0", "transferCount":"0", "solde":null, "authorizedBalance":null, "bic":"TRZOFR21XXX", "iban":"XXXX", "totalRows":1 } ] }, "object_payload_signature":"eYIDFtDa3Ai9T+0vRgIFwU0oDYZ2WkcILLRDOBWLAY8=" } ``` ::: ### `wallet.update` ::: code-group ```json [JSON] { "webhook":"wallet.update", "webhook_id":"644808221", "object":"wallet", "object_id":"3858134", "object_payload":{ "wallets":[ { "walletId":"3858134", "walletTypeId":"9", "walletStatus":"VALIDATED", "userId":"3384099", "jointUserId":"0", "walletTag":"", "currency":"EUR", "eventDate":"2021-03-02", "eventMessage":"", "eventAlias":"XXXX", "eventPayinStartDate":"2021-02-23", "eventPayinEndDate":"0000-00-00", "contractSigned":"0", "urlImage":"", "createdDate":"2021-02-23 02:05:24", "modifiedDate":"2021-04-19 19:16:46", "tariffId":"25", "eventName":"XXXX", "userFirstname":"XXXX", "userLastname":"SAS", "codeStatus":"120005", "informationStatus":"", "payinCount":"0", "payoutCount":"0", "transferCount":"0", "solde":"0.00", "authorizedBalance":"0.00", "bic":"TRZOFR21XXX", "iban":"XXXX" } ] }, "object_payload_signature":"h+0FXlKloXIrFHpY\/PMMIoIQbUBTp5W1HlXZnqCNHx4=" } ``` ::: ### `wallet.cancel` ::: code-group ```json [JSON] { "webhook":"wallet.cancel", "webhook_id":"21419123", "object":"wallet", "object_id":"860377", "object_payload":{ "wallets":[ { "walletId":"860377", "walletTypeId":"10", "walletStatus":"CANCELED", "userId":"1622006", "jointUserId":"0", "walletTag":"", "currency":"EUR", "eventDate":"2021-04-29", "eventMessage":"", "eventAlias":"XXXX", "eventPayinStartDate":"2021-04-22", "eventPayinEndDate":"0000-00-00", "contractSigned":"0", "urlImage":"", "createdDate":"2021-04-22 14:55:33", "modifiedDate":"2021-04-22 14:55:33", "tariffId":"83", "eventName":"XXXX", "userFirstname":"", "userLastname":"", "codeStatus":"120003", "informationStatus":"", "payinCount":"0", "payoutCount":"0", "transferCount":"0", "solde":"0.00", "authorizedBalance":"0.00", "bic":"TRZOFR21XXX", "iban":"XXXX" } ] }, "object_payload_signature":"UhRUkiWyKTptpF\/mbeiN20+XRBM2igEXM8JoUSrQZMs=" } ``` ::: ## Balances * [`balance.update`](#balance-update) is sent to you any time **the balance of a Wallet changes** ### `balance.update` ::: code-group ```json [JSON] { "webhook": "balance.update", "webhook_id": "382069610", "object": "balance", "object_id": "2xxxxx7", "object_payload": { "balances": [ { "walletId": "2xxxxx7", "currentBalance": "4819188.18", // updated Current Balance "authorizations": "407973.44", "authorizedBalance": "4411214.74", // updated Authorized Balance "currency": "EUR", "calculationDate": "2020-07-03 11:14:38" } ] }, "object_payload_signature": "Rd8sLKMet9oPVYiEMLR5p5idGcOTBLhbZ7xnKvTOr3o=" } ``` ::: --- --- url: /guide/wallets/iban.md description: >- Learn to create and manage Treezor Wallet IBANs via the API, including support for local IBANs and virtual IBANs, to optimize account functionalities. --- # IBAN The International Bank Account Number (IBAN) is the unique identifier of a bank account as agreed upon by international standards. An IBAN and a [BIC](/guide/overview/glossary#bank-identifier-code-bic) code are automatically assigned to every newly created Wallet. They are either Treezor BIC or your own BIC if you are a [Regulated Institution](/guide/overview/glossary#regulated-institution). Treezor offers 2 IBAN-related services: * [Virtual IBAN](#virtual-iban) - Add additional IBANs to a Wallet. * [Local IBAN](#local-iban) - Create Wallets for specific countries. IBAN features are compatible with transfers as follows: | Transfer | Virtual IBAN | Local IBAN | |---------|:--------------:|:-------------:| | [Received SEPA Direct Debit (SDDR)](/guide/transfers/direct-debit#received-direct-debits-sddr) | | | | [Emitted SEPA Direct Debit (SDDE)](/guide/transfers/direct-debit#emitted-direct-debits-sdde) | | | | [Received SEPA Credit Transfer (SCTR)](/guide/transfers/credit-transfer#received-credit-transfers-sctr) | | | | [Emitted SEPA Credit Transfer (SCTE)](/guide/transfers/credit-transfer#emitted-credit-transfers-scte) | | | | [Received SEPA Instant Credit Transfer](/guide/transfers/credit-transfer-inst#received-instant-credit-transfers-sctr-inst) | | | | [Emitted SEPA Instant Credit Transfer](/guide/transfers/credit-transfer-inst#emitted-instant-credit-transfers-scte-inst) | | | | [Wallet-to-Wallet](/guide/transfers/wallet-to-wallet) | | | ## Virtual IBAN You can add Virtual IBANs to a Wallet besides the automatically assigned IBAN. There is no limitation on the number of Virtual IBANs per Wallet. **Feature Activation – Virtual IBANs are not available by default** Please reach out to your *Treezor Account Manager* to learn more about the conditions for using this service. ### Use cases Virtual IBAN offers capabilities and restrictions that are not available with the Wallet main IBAN. Therefore, they allow for a more granular handling of operations. | Capability | Benefits | |----------|---------| | **Usage restriction** | Restricting the usage of a Virtual IBAN to specific users or usage allows you to better categorize funds movements. | | **Virtual IBAN deactivation** | Deactivating the Virtual IBAN without closing the Wallet facilitates of litigation handling, for instance. | Virtual IBANs include operation limitations to prevent abuses: * **Single direction** – Support either outgoing ([SDDR](/guide/transfers/direct-debit)) or incoming ([SCTR](/guide/transfers/credit-transfer)) funds. * **Time frame** – Limit a Virtual IBAN usage between two specified dates. * **Number of transaction** – Set a maximum number of transactions for a Virtual IBAN. * **Maximum amount** – Set a maximum cumulated amount for a Virtual IBAN. **Note – Declined transfers don't impact limits** A declined [SCT](/guide/transfers/credit-transfer) or [SDD](/guide/transfers/direct-debit) is ignored by Virtual IBAN limits (its doesn't count towards `maxUsage` or `maxAmount` restrictions). ### Creating a Virtual IBAN #### Parameters | Attribute | Type | Description | | --- | --- | ---- | | `walletId`  | integer | The unique identifier of the Wallet to which the Virtual IBAN is associated. Must be a `walletType` of `9` or `10`. |  | `typeId` | integer | The type of IBAN, allowing for a specific transfer direction. Can be: `1` for `SDDR` [SEPA Direct Debit](/guide/transfers/direct-debit)`2` for `SCTR` [SEPA Credit Transfer](/guide/transfers/credit-transfer) |  | `validFrom` | string | The date from which the Virtual IBAN validity starts. Defaults to today's date and must be set in the future. Format: YYYY-MM-DD |  | `validTo` | string | The date from which the Virtual IBAN validity ends. Must be set after the `validFrom` date. Format: YYYY-MM-DD |  | `maxUsage` | integer | The maximum number of transactions allowed (`0` = unlimited). |  | `maxAmount` | string (number) | The maximum cumulated [amount](/guide/api-basics/data-format#amounts) of all transactions (`"0.00"` = unlimited). |  | `reference` | string | Custom field for your internal reference of the Virtual IBAN. Max. length: 255 characters. | | `tag` | string | Custom attribute that you can use as you see fit. Learn more in the [Object tags](/guide/api-basics/objects-tags) article. |  #### Request example Endpoint: [`/v1/virtualibans`](/api-reference/api-endpoints.html#tag/Virtual%20IBANs/postVirtualIban){target="\_self"} ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/v1/virtualibans' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "walletId":{walletId}, "typeId":2 } ``` ::: Returns a Virtual IBAN object, containing its `id`, the IBAN itself and additional information. ::: code-group ```json [JSON] { "virtualibans": [ { "virtualibanId": 123456, "walletId": 0123456, "typeId": 2, "tag": "Test vIBAN", "reference": "", "validFrom": "2024-01-31", "validTo": null, "maxUsage": 10, // 0 means there is no limit "maxAmount": "0.00", // "0.00" means there is no limit "iban": "FR761679800001100000123455678", "createdDate": "2024-01-31 09:28:06", "numberOfTransactions": 0, "cumulatedAmount": "0.00", "updatedDate": null } ] } ``` ::: **Tip – All your Virtual IBANs have the same BIC** All IBANs emitted by Treezor have the following BIC `TRZOFR21XXX` unless you are a Payment Institution or more broadly a , in which case, you have your own BIC. ### Retrieving a Virtual IBAN You can use the following request with the `virtualIbanId` as a path parameter to retrieve a Virtual IBAN. ::: code-group ```bash [CURL] curl -X GET '{baseUrl}/v1/virtualibans/{virtualIbanId}' \ --header 'Authorization: Bearer {accessToken}' \ ``` ::: Returns the corresponding Virtual IBAN object. ::: code-group ```json [JSON] { "virtualibans": [ { "virtualibanId": 123456, "walletId": 0123456, "typeId": 2, "tag": "Test vIBAN", "reference": "", "validFrom": "2024-01-31", "validTo": null, "maxUsage": 10, "maxAmount": "0.00", "iban": "FR761679800001100000123455678", "createdDate": "2024-01-31 09:28:06", "numberOfTransactions": 0, "cumulatedAmount": "0.00", "updatedDate": null } ] } ``` ::: ### Deleting a Virtual IBAN For legal reasons, Virtual IBANs cannot be deleted. The only way to do so is for the Virtual IBAN to go past its `validTo` date. Although the `validTo` date can't be set in the past, you can update it to be in the near-future by using the [`/v1/virtualibans/{virtualIbanId}`](/api-reference/api-endpoints.html#tag/Virtual%20IBANs/putVirtualIban){target="\_self"} request. ::: code-group ```bash [CURL] curl -X PUT '{baseUrl}/v1/virtualibans/{virtualIbanId}' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{ "validTo":"" # The expiration date (YYYY-MM-DD) }' ``` ::: Returns the updated Virtual IBAN object. ::: code-group ```json [JSON] { "virtualibans": [ { "virtualibanId": 123456, "walletId": 0123456, "typeId": 2, "tag": "Test vIBAN", "reference": "", "validFrom": "2024-01-31", "validTo": null, "maxUsage": 10, "maxAmount": "0.00", "iban": "FR761679800001100000123455678", "createdDate": "2024-01-31 09:28:06", "numberOfTransactions": 0, "cumulatedAmount": "0.00", "updatedDate": null } ] } ``` ::: ### Endpoints | Endpoint |[Scope](/guide/api-basics/authentication#available-scopes) | | --- | --- | | [`/v1/virtualibans`](/api-reference/api-endpoints.html#tag/Virtual%20IBANs/postVirtualIban){target="\_self"}  Create a Virtual IBAN | `read_write` | | [`/v1/virtualibans`](/api-reference/api-endpoints.html#tag/Virtual%20IBANs/getvirtualibans){target="\_self"}  Search Virtual IBANs | `read_only` | | [`/v1/virtualibans/{virtualIbanId}`](/api-reference/api-endpoints.html#tag/Virtual%20IBANs/getvirtualiban){target="\_self"}  Retrieve a specific Virtual IBAN | `read_only` | | [`/v1/virtualibans/{virtualIbanId}`](/api-reference/api-endpoints.html#tag/Virtual%20IBANs/putVirtualIban){target="\_self"} Update a Virtual IBAN | `read_write` | ## Local IBAN Bank accounts are country-specific, which is reflected by the first 2 characters of the IBAN (country code). You can create accounts with a BIC and IBAN based in the user’s [`distributionCountry`](/guide/users/introduction#distribution-country-distributioncountry). **Configuration – Environment configuration by Treezor** Please contact Treezor to set up your [distribution countries](/guide/users/introduction#distribution-country-distributioncountry) and available IBANs per country. Required fields upon creating a Wallet change depending on your setup. Local IBANs are compatible with all Treezor transaction flows. In the specific case of [Wallet-to-Wallet transfers](/guide/transfers/wallet-to-wallet), transfers are only possible when the wallets have IBANs of the same country. Otherwise, you need to make a SEPA Credit Transfer instead. ### Available countries (`bic`) While by default, Treezor provides French IBAN, the following countries are available: Germany, Italy, and Spain. Find below the available `bic` values structure per country. These [BICs](/guide/overview/glossary#bank-identifier-code-bic) are to be adapted depending on the value Treezor provided you. | Country code | `bic` structure | | --- | --- | | FR | TRZOFR21XXX | | DE | TRZODEB2XXX | | IT | TRZOITM2XXX | | ES | TRZOESM2XXX | ### Creating a Local IBAN Treezor generates the IBAN when creating a Wallet. Depending on your configuration, you may specify the location of the IBAN by either: * Relying on the `distributionCountry` of the wallet owner * Specifying the `bic` value In most cases, however, the `bic` country must be aligned with wallet owner's `distributionCountry`. #### Parameters Below are the main parameters to create a wallet with a local IBAN. | Attribute | Type | Description | |--- |--- |--- | | `tariffId` | integer | The fees applied to the Wallet, as defined by your contract with Treezor. Usually required, but may have a default value set by Treezor. | | `walletTypeId` | integer | The type of Wallet. Allowed values are: `9` – Electronic Money Wallet`10`– Payment Account Wallet| | `bic` | string | The country in which the wallet is domiciled. The BIC is required depending on your configuration; it can default to the configured value only if there is only one allowed `bic` value authorized for a given `distributionCountry`. Contact Treezor for more information about your configuration. | | `userId` | integer | The unique identifier of the User who owns the Wallet. | | `currency` | string | The currency of the Wallet. Can only be `EUR`. | | `eventName` | string | The name of the Wallet. | **API – API Reference available** For a complete list of Wallet attributes, check the [Wallets](/api-reference/api-endpoints.html#tag/Wallets){target="\_self"} section of the API Reference. #### Request example Endpoint: [`/v1/wallets`](/api-reference/api-endpoints.html#tag/Wallets/postWallets){target="\_self"} ::: code-group <<< @/guide/wallets/snippets/create\_wallet.bash \[CURL] ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "walletTypeId":10, "bic":"TRZODEB2XXX", "tariffId":{tariffId}, "userId":123456, "currency":"EUR", "eventName":"Wallet DE" } ``` ::: Returns the Wallet object with the BIC and IBAN localized in the desired country. ::: code-group ```json [JSON] {22,23} { "wallets": [ { "walletId": 3445765, "walletTypeId": 10, "walletStatus": "VALIDATED", "codeStatus": 120005, "informationStatus": "", "walletTag": "", "userId": 100962903, "userLastname": "Oak", "userFirstname": "Alex", "jointUserId": 0, "tariffId": 136, "eventName": "Wallet DE", "eventAlias": "wallet-de-67093a222d23a", "eventDate": "2024-10-18", "eventMessage": "", "eventPayinStartDate": "2024-10-11", "eventPayinEndDate": "0000-00-00", "contractSigned": 0, "bic": "TRZODEB2XXX", "iban": "DE72100102000003445765", "urlImage": "", "currency": "EUR", "createdDate": "2024-10-11 16:45:54", "modifiedDate": "0000-00-00 00:00:00", "payinCount": 0, "payoutCount": 0, "transferCount": 0, "solde": 0, "authorizedBalance": 0, "totalRows": 1, "country": "FR" } ] } ``` ::: --- --- url: /guide/wallets/operations.md description: >- Get a foundational understanding of Treezor operations (card, payins, payouts, and transfers). Includes key attributes, JSON structure, and related endpoints list. --- # Operations Operations stand for banking operations originating from or targeting a [Wallet](/guide/wallets/introduction) (i.e., Card Transactions, Payins, Payouts, and Transfers) and their refunds. Each Operation summarizes the initial transaction with read-only information such as the nature, status, amount, origin, and destination. Therefore, you may use Operations as a single source of information. They are what end users generally expect to see as a table or timeline when they log into their bank website/app. **Tip – Operations are available in CSV format** You can also export the information using the [Reports](/guide/wallets/operations#generate-operations-reports) feature. ## Available operations (`operationType`) The `operationType` attribute allows you to identify what kind of banking operation is concerned. The following operation types are available: | `operationType` | Initial operation | | --- | --- | | `bankDirectDebit` | [SEPA Direct Debit (SDD)](/guide/transfers/direct-debit) | | `bankTransfer` | [SEPA Transfer](/guide/transfers/credit-transfer) | | `cardTopup` | [Incoming funds from Card](/guide/acquiring/introduction) | | `cardTransaction` | [Outgoing Card payment](/guide/cards/transactions) | | `check` | [Check](/guide/cheques/introduction) | | `creditNote` | [Wallet-to-wallet Transfers](/guide/transfers/introduction#from-wallet-to-wallet) with a `transferTypeId` value of `4`. Such transfers allow you to handle reimbursement of charges. | | `fees` | [Wallet-to-wallet Transfers](/guide/transfers/introduction#from-wallet-to-wallet) with a `transferTypeId` value of `3`. Such transfers allow you to debit fees from end users wallets. They are identified as such in Account Statements. | | `instantBankTransfer` | [Instant SEPA Transfer](/guide/transfers/credit-transfer-inst) | | `walletTransfer` | [Wallet-to-wallet Transfers](/guide/transfers/introduction#from-wallet-to-wallet) | ```mermaid flowchart LR Operations(Operations) Check(check) CardTopUp(cardTopup) BankDirectDebit(bankDirectDebit) BankTransfer(bankTransfer) CardTransaction(cardTransaction) Payins(Payins) Payouts(Payouts) Transfers(Transfers) CardTransactions(CardTransactions) Operations --- Check Operations --- CardTopUp Operations --- BankDirectDebit Operations --- BankTransfer Operations --- CardTransaction Check <--> Payins CardTopUp <--> Payins BankDirectDebit <--> Payins BankTransfer <--> Payins BankDirectDebit <--> Payouts BankTransfer <--> Payouts BankTransfer <--> Transfers CardTransaction <--> CardTransactions class Operations MermaidNeutralAlternate class Payins MermaidNeutral class Payouts MermaidNeutral class Transfers MermaidNeutral class CardTransactions MermaidNeutral ``` ## Key attributes Below are a few of the most important attributes. | Attribute | Type | Description | |---|---|---| | `operationType` | string | The type of bank operation, providing functional context about the initial operation. | | `initialFlow` | string | Provides technical context about the initial operation: `payin`, `payinRefund`, `payout`, `payoutRefund`, `transfer`, `cardTransaction`, `chargeback`. You can fetch the initial operation by making the corresponding request (using the `objectId` as a path parameter). | | `amount` | integer | The amount of the operation in cents (e.g., `100` stands for 1). | | `walletId` | integer | The unique identifier of the wallet associated with the operation. | | `direction` | string | Direction of the operation, which can either be: `CREDIT` – The funds are credited to the Wallet`DEBIT` – The funds are debited from the Wallet | | `objectId` | string | The unique identifier of the object the operation relates to (e.g., the initial `cardTransaction`). | | `label` | string | Information that you can expose to your end users. The label content differs depending on the context. | | `metadata` | object | Details about the initial operation. | | `status` | string | The status of the operation, which can be: `AUTHORIZED`, `DECLINED`, `SETTLED`, or `CANCELED`. | | `creation` | string | The date and time at which the object the operation relates to was created. *Format: RFC3339 standard.* | | `settlement` | string | The date and time at which the object the operation relates to was settled on the Wallet. *Format: RFC3339 standard.* | **API Reference – Refer to endpoint documentation** For a complete list of Operation attributes, check the [Operations](/api-reference/api-endpoints.html#tag/operations){target="\_self"} endpoint in the API Reference. ### Metadata The `metadata` object contains key information about the initial operation. This content differs depending on the operation. #### Transfers ::: code-group ```json [JSON] "metadata": { "label": "string || null", "codeStatus": "string", "tag": "string || null", "informationStatus": "string || null", "creditorWalletId": "string", "creditorFirstName": "string", // Encrypted if cryptography is activated "creditorLastName": "string", // Encrypted if cryptography is activated "creditorLegalName": "string", // Encrypted if cryptography is activated "creditorWalletEventName": "string", "debtorWalletId": "string", // Encrypted if cryptography is activated "debtorFirstName": "string", // Encrypted if cryptography is activated "debtorLastName": "string", // Encrypted if cryptography is activated "debtorLegalName": "string", "debtorWalletEventName": "string" } ``` ::: #### Card Transactions ::: code-group ```json [JSON] "metadata": { "maskedPan": "519872******4839", // Encrypted if cryptography is activated "mcc": { "code": 123456, }, "mid": { "value": "3256", // MerchantId, Encrypted if cryptography is activated "name": "Merchant Name", // MerchantName, Encrypted if cryptography is activated "city": "", // MerchantCity, Encrypted if cryptography is activated "country": "", "address": null }, "localAmount": { "amount": 1790, "currency": "978" }, "authorizationNote": "", // Encrypted if cryptography is activated "authorisationResponseCode": { "action": "Approved", "description": "APPROVED", "value": 08 }, "paymentLifeCycle": [ // for each Cardtransactions::PaymentStatus = S { "authorizationIssuerTime": "2024-04-16 08:23:20", "valueDate": "string", "paymentAmount": 0, "paymentLocalAmount": 0, "paymentCurrency": "string" } ], "paymentCountry": "FRA", "cardId": "999997173", "publicToken": "string", "is3DS":"0", "3dsExemptionType":"string || null", "optimizedMerchantName":"string || null", "merchantLogo":"string || null", "merchantCategory":"string || null", "transactionSubtype":"string || null", } ``` ::: #### Payins ::: code-group ```json [JSON] "metadata": { "payinId": "string", "payinTag": "string || null", // Encrypted if cryptography is activated "messageToUser": "string || null", // Encrypted if cryptography is activated "codeStatus": "string", "informationStatus": "string || null", "paymentMethodId": 0, "ibanFullName": "string || null", "dbtrIBAN": "******1319", // Encrypted if cryptography is activated "ibanTxEndToEndId": "string || null", "mandateId": "string || null", "debtorName": "string || null", "uniqueMandateReference": "string || null", "additionalData": ["string"], // Encrypted if cryptography is activated } ``` ::: #### PayinRefunds ::: code-group ```json [JSON] "metadata": { "payinId": "string", "payinTag": "string || null", // Encrypted if cryptography is activated "messageToUser": "string || null", // Encrypted if cryptography is activated "codeStatus": "string", "informationStatus": "string || null", "paymentMethodId": 0, "ibanFullName": "string || null", "dbtrIBAN": "string || null", // Encrypted if cryptography is activated "ibanTxEndToEndId": "string || null", "mandateId": "string || null", "debtorName": "string || null", "uniqueMandateReference": "string || null", "reasonTms":"string || null", "additionalData": ["string"] // Encrypted if cryptography is activated } ``` ::: #### Payouts ::: code-group ```json [JSON] "metadata": { "payoutTag": "string || null", "beneficiaryId": "string", "label": "string || null", "codeStatus": "string", "informationStatus": "string || null", "payoutTypeId": 0, "supportingFileLink": "string || null", "reasonCode": "string || null", "reasonDescription": "string || null", "endToEndId": "string || null", // SCT only "uniqueMandateReference": "string || null", // SDD only "beneficiaryName": "string || null" } ``` ::: #### PayoutRefunds ::: code-group ```json [JSON] "metadata": { "codeStatus": "string", "informationStatus": "string || null", "requestComment": "string || null", "reasonCode": "string || null", "refundDate": "string || null", "refundComment": "string || null", "payoutId": "string || null", "payoutRefundTag": "string || null", "beneficiaryName": "string || null", "label": "string || null", "endToEndId": "string || null", // SCT only "uniqueMandateReference": "string || null", // SDD only "payoutTypeId": 0, "beneficiaryId": "string || null", "payoutTag": "string" } ``` ::: #### Chargebacks Chargebacks of card top up payins. ::: code-group ```json [JSON] "metadata": { "payinId" : "string", "payinTag": "string || null", // Encrypted if cryptography is activated "payinrefundId": "string", "additionalData": "string", // Encrypted if cryptography is activated "chargebackReason": "string", "transactionReference":"string", } ``` ::: ### Labels You can expose the `label` field values to your end users to provide more information. The information displayed depends on the context and the table below relies on the latest version of the Operations feature. | Context | Exposed data | String example | |---|---|---| | Card Top Up | Indicates the name of the cardholder, along with the masked PAN of the card. | Alex Oak 553896XXXXXX8893 | | Cancelled Card Top Up | Indicates the name of the cardholder, along with the masked PAN of the card. | Alex Oak 553896XXXXXX8893 | | Chargeback on Card Top Up | Indicates the name of the cardholder and the card masked PAN. | Alex Oak 553896XXXXXX8893 | | Bank Transfer (Payin) | Indicates the IBAN full name, along with the `messageToUser` (custom field). | Alex Oak messageToUserExample | | Refund of Bank Transfer (Payin) | Indicates the IBAN full name, along with the `messageToUser` (custom field). | Alex Oak messageToUserExample | | Bank Transfer (Payout) | Indicates the Beneficiary name, along with the Payout `label`. | | | Refund of Bank Transfer (Payout) | Indicates the Beneficiary name, along with the Payout `label`. | | | Bank Direct Debit (Payin) | Indicates the debtor's name, along with the `messageToUser` (custom field), and the Unique Mandate Reference. | | | Refund of Bank Direct Debit (Payin) | Indicates the debtor's name, along with the `messageToUser` (custom field), and the Unique Mandate Reference. | | | Bank Direct Debit (Payout) | Indicates the Beneficiary name, the Payout `label`, and the Unique Mandate Reference. | Alex Oak rlabel96 UMR: 65c32b8dc64xx | | Refund of Bank Direct Debit (Payout) | Indicates the Beneficiary name, the Payout `label`, and the Unique Mandate Reference. | Alex Oak rlabel96 UMR: 65c32b8dc64xx | | Check | Indicates the user's name, along with the `messageToUser` (custom field), and the CMC7 A. | | | Refund of a Check | Indicates the user's name, along with the `messageToUser` (custom field), and the CMC7 A. | | | Transfer (wallet-to-wallet) | Indicates the user's name, along with the transfer `label`. | messageToUserExample Alex Oak | | Transfer (if `fees` or `creditNote`) | Indicates the Transfer `label` (custom field). | | | Card Transaction | Indicates the merchant's name and the masked PAN. If the currency of the transaction differs from the Wallet currency, also indicates the `paymentLocalAmount`. | Tree Cie(978 91.78) Card 734837\*\*\*\*\*\*9403 | ## Retrieve operations When requesting a list of operations, the following query parameters are required. | Parameter | Description | | --- | --- | | `walletId` | The unique identifier of the Wallet for which the operations are to be retrieved. | | `dateFrom` | The date and time from which the operations are to be retrieved. This parameter takes into account the `createdDate` for Payin, Payout, and Transfer objects, and the `authorizationIssuerTime` for Card Transactions. Format: HTML-encoded RFC 339 date-time. | | `dateTo` | The date and time up to which the operations are to be retrieved. This parameter takes into account the `createdDate` for Payin, Payout, and Transfer objects, and the `authorizationIssuerTime` for Card Transactions. Format: HTML-encoded RFC 339 date-time. | **Note – 3-month time frame support** The `dateTo` and `dateFrom` fields must be less than 3 months apart. To get the list of operations, use the following request (which supports [cursor-based pagination](/guide/api-basics/pagination#cursor-based-pagination)). The dates are to be HTML encoded (e.g., 2024-01-11T11:25:36+01:00 becomes `2024-01-11T11:25:36%2B01:00`). ::: code-group ```bash [CURL] curl -X GET '{baseUrl}/core-connect/operations?walletId={walletId}&dateFrom={dateFrom}&dateTo={dateTo}' \ --header 'Authorization: Bearer {accessToken}' \ ``` ::: Here is an example of a response. It returns an array of Operation objects along with a cursor and sorted by creation date. ::: code-group ```json [JSON] { "cursor": { "prev": null, "current": null, "next": null }, "data": [ { "amount": { "amount": 1000, "currency": "EUR" }, "walletId": 2647244, "operationType": "bankDirectDebit", "direction": "DEBIT", "status": "SETTLED", "objectId": "181212", "label": "Alex Oak rlabel96 UMR: 65c32b8dc64xx", "metadata": { "payoutTag": "65c32b8dc64xx|lFCS7WW4OugijXXX", "beneficiaryId": "429387", "beneficiaryName": "Alex Oak", "label": "rlabel96", "codeStatus": "160005", "informationStatus": "Remboursement par virement Validé", "payoutTypeId": 0, "uniqueMandateReference": "65c32b8dc64xx", "supportingFileLink": "", "reasonCode": null, "reasonDescription": null, "endToEndId": null }, "date": { "creation": "2024-02-07T08:04:48+01:00", "settlement": "2024-02-07T00:00:00+01:00" }, "initialFlow": "payout" } ] } ``` ::: ## Generate Operation Reports Operation Reports are CSV exports that include all operations for a given Wallet on a given period. They are mainly intended for administrative and back end use. Creating an operation report is a 2-step process: 1. [Request the Report](#request-a-report) 2. [Retrieve the Report](#retrieve-a-report) ### Request a Report To request a CSV report, you can use the following request. ::: code-group ```bash [CURL] curl -X POST '{baseUrl}/core-connect/operations/{walletId}/report' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is a `{payload}` example: ::: code-group ```json [JSON] { "dateFrom":"2022-06-05T00:00:00+02:00", "dateTo":"2023-06-15T00:00:00+02:00" } ``` ::: Answers with a `201` HTTP Status code. ### Retrieve a Report To check on a report creation and obtain the download URL, you can use the following request. **Note – Parameters are expected in query string** As opposed to the POST request, the `dateFrom` and `dateTo` are expected as query parameters. The dates are to be html encoded (e.g., 2024-01-11T11:25:36+01:00 becomes `2024-01-11T11:25:36%2B01:00`). ::: code-group ```bash [CURL] curl -X GET '{baseUrl}/core-connect/operations/{walletId}/report?dateFrom={dateFrom}&dateTo={dateTo}' \ --header 'Authorization: Bearer {accessToken}' \ ``` ::: Returns the following when the report is still being generated. ::: code-group ```json [JSON] { "status": "CREATED", "url": null } ``` ::: Returns the following when the report is ready for download. ::: code-group ```json [JSON] { "status": "COMPLETED", "url": "https://dev-connect-files.s3.eu-west-3.amazonaws.com/operation/report/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxx.csv" } ``` ::: **Information – Report creation can time out** If 15 minutes after the initial Report request you are still getting the `CREATED` status, then the Report creation process has timed out. ### Operation Report data Find below the list of fields included in the operation report .csv. | Field | Description | | --- | --- | | `date` | The date and time at which the object the operation relates to was created. | | `label` | Information that you can expose to your end users. The label content differs depending on the operation. | | `walletId` | The unique identifier of the wallet associated with the operation. | | `amount` | The amount of the operation in cents (e.g., `100` stands for 1). | | `currency` | The currency of the operation (e.g., `EUR`). | | `direction` | Direction of the operation, which can either be: `CREDIT` – The funds are credited to the Wallet`DEBIT` – The funds are debited from the Wallet | | `objectId` | The unique identifier of the object the operation relates to (e.g., the initial `cardTransaction`). | | `operationType` | The type of bank operation, providing functional context about the initial operation. | | `status` | The status of the operation, which can be: `AUTHORIZED`, `DECLINED`, `SETTLED`, or `CANCELED`. | | `initialFlow` | Provides technical context about the initial operation: `payin`, `payinRefund`, `payout`, `payoutRefund`, `transfer`, `cardTransaction`, `chargeback`. | | `beneficiaryId` | The unique identifier of the beneficiary (payouts, payout refunds). | | `creditorWalletId` | The unique identifier of the credited wallet for wallet-to-wallet transfers. | | `debtorWalletId` | The unique identifier of the debited wallet for wallet-to-wallet transfers. | | `tag` | The custom tag (transfers, payouts, payins). | | `mcc` | The card transaction's merchant category code. | | `mid` | The card transaction's merchant Id. | | `localAmount` | The card transaction's amount in the local currency in cents. | | `localCurrency` | The card transaction's local currency (e.g., `978`). | | `authorizationNote` | Contains detailed information regarding a declined card transaction. See the [Authorization notes](/guide/cards/authorization-notes) article for examples. | | `authorisationResponseCodeAction` | The action from the authorization response (e.g., declined or accepted), as listed in the [corresponding article](/guide/cards/authorization-notes#authorization-response-codes). | | `authorisationResponseCodeDescription` | The description of the authorization response code, as listed in the [corresponding article](/guide/cards/authorization-notes#authorization-response-codes). | | `authorisationResponseCodeValue` | The authorization response code, as listed in the [corresponding article](/guide/cards/authorization-notes#authorization-response-codes). | ## Operation object ::: code-group ```json [JSON] { "operationType": "bankTransfer", "initialFlow": "payout", "amount": { "amount": 6300, "currency": "EUR", }, "walletId": 630632, "direction": "DEBIT", "objectId": "408265455", "label": "Theo West Virement de M Alex Oak", "metadata": { "payoutTag": "VO - 1234554321", "beneficiaryId": "404897", "label": "Virement de M Alex Oak", "codeStatus": "140005", "informationStatus": "", "supportingFileLink": "", "reasonCode": null, "reasonDescription": null, "beneficiaryName": "Yvy Sala" }, "status": "AUTHORIZED", "date": { "creation": "2023-08-19T06:08:23+02:00", "settlement": null } } ``` ::: ## Endpoints | Endpoint | [Scope](/guide/api-basics/authentication#available-scopes) | | --- | --- | | [`/core-connect/operations`](/api-reference/api-endpoints.html#tag/Operations/getOperations){target="\_self"} Search Operations | `read_only` | | [`/core-connect/operations/{walletId}/report`](/api-reference/api-endpoints.html#tag/Operations/postOperationsReport){target="\_self"} Create a Report | `read_only` | | [`/core-connect/operations/{walletId}/report`](/api-reference/api-endpoints.html#tag/Operations/getOperationsReport){target="\_self"} Get a Report | `read_only` | | [`/simulation/operations`](/api-reference/api-endpoints.html#tag/Operations/simulateOperations){target="\_self"} Simulate operations | `read_write` | --- --- url: /guide/wallets/faking-operations.md description: >- Learn how to update and manage Treezor Wallet statuses within the Sandbox environment for development and API integration testing. --- # Emulation Emulation features are only available in `Sandbox` [environment](/guide/api-basics/environments). **Tip – You can also rely on webhooks** For operations that cannot be emulated in the Sandbox, [webhook examples](events) are provided. ## Credit funds To credit funds, check out the [transfer emulations](/guide/transfers/faking-operations) page. ## Operations To emulate [Account Statements](account-documents) in [Sandbox](/guide/api-basics/environments#sandbox), you need to generate fake operations for the desired month. This can be done using the following request. Endpoint: [`/simulation/operations`](/api-reference/api-endpoints.html#tag/Operations/simulateOperations){target="\_self"} ::: code-group <<< @/guide/wallets/snippets/simu\_operations.bash \[CURL] ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "walletId": "{walletId}", "date": "2023-10", "operations": { "payin": 5, "payinrefund": 2, "payout": 6, "payoutrefund": 1, "transfer": 3, "cardtransaction": 7, "transferfees":2, "transfercreditnote":1 } } ``` ::: Returns an HTTP `201 Created` status code. You can now view your operations by either: * Generating an account statement [`/core-connect/statements/{walletId}/raw`](/api-reference/api-endpoints.html#tag/Account%20Statements/getRawStatement){target="\_self"} * Retrieving operations [`/core-connect/operations`](/api-reference/api-endpoints.html#tag/Operations/getOperations){target="\_self"} ## Status Wallets are [created](creation) in a pending status that is usually very shortly after validated. To emulate a different status, prefix the Wallet `eventName` attribute with the following characters. | Prefix | `walletStatus` | `codeStatus` | Description | |:-: |- | - |- | | `p.1` | `PENDING` | `120001` | Information control | | `p.2` | `PENDING` | `120002` | Late information control | | `c.3` | `CANCELED` | `120003` | Wallet was closed internally | | `c.4` | `CANCELED` | `120004` | Wallet was closed by the User | | `v.5` | `VALIDATED` | `120005` | Wallet is valid | Wait a few minutes and make a `GET /v1/wallets` request for the Wallet you've just created. The API returns the Wallet with the emulated status. ### Example Let's take an example in which we'd like to simulate a Wallet closed by the User. ::: code-group <<< @/guide/wallets/snippets/create\_wallet.bash \[CURL] ::: With a `{payload}` containing the prefixed `eventName`: ::: code-group ```json [JSON] {6} { "walletTypeId": "10", "tariffId": 136, "userId": 100113410, "currency": "EUR", "eventName": "c.4Test Wallet" } ``` ::: The request returns the validated Wallet for now. You need to retrieve the Wallet a few moments after the creation with the following request: ::: code-group ```bash [CURL] curl -X GET '{baseUrl}/v1/wallets/{WalletId}' \ --header 'Authorization: Bearer {accessToken}' \ ``` ::: The Wallet object returned is `CANCELED`, with the mocked `codeStatus`: ::: code-group ```json [JSON] {6,7} { "wallets": [ { "walletId": 2643119, "walletTypeId": 9, "walletStatus": "CANCELED", "codeStatus": 120003, "informationStatus": "", "walletTag": "", "userId": 100113410, "userLastname": "Alex", "userFirstname": "Oak", "tariffId": 136, "eventName": "c.3test", "eventMessage": "", "contractSigned": 0, "bic": "TRZOFR21XXX", "iban": "FR7616798000010000264311929", "currency": "EUR", "createdDate": "2024-02-06 06:57:56", "modifiedDate": "2024-02-06 06:58:16", "payinCount": 0, "payoutCount": 0, "transferCount": 0, "solde": 0.0, "authorizedBalance": 0.0, "totalRows": 1, "country": "FR" } ] } ``` ::: --- --- url: /guide/wallets/transactions.md description: >- Retrieve read-only representation of banking operations of a given Wallet. Includes required parameters, request structure, and response examples. --- # Transactions Transactions are a read-only representation of banking operations on a [Wallet](./introduction). **Best practice – Use the [Operations](/guide/wallets/operations) feature** If you are using [Treezor Connect](/guide/overview/getting-started#treezor-api), the [Operations](/guide/wallets/operations) endpoint supersedes this one. ## Key attributes | Attribute | Type | Description | | --- | --- | --- | | `transactionId` | integer | The unique identifier of the transaction. | | `createdDate` | string | The date and time at which the transaction was created. | | `valueDate` | string | The date on which the payment was applied. | | `executionDate` | string| The date on which the transaction was executed. | | `transactionType` | string | The name of the transaction type. See [Transaction Types list](#transaction-types-transactiontypes). | | `name` | string | The name of the transaction. | | `foreignId` | integer | The unique identifier of the initial operation that created the Transaction (e.g., `payinId`, `payoutId`, etc.) | | `walletDebitBalance` | string | The balance of the debited Wallet (if any). | | `walletCreditBalance` | string | The balance of the credited Wallet (if any). | | `walletDebitId` | integer | The unique identifier of the debited Wallet (if any). | | `walletCreditId` | integer | The unique identifier of the credited Wallet (if any). | | `amount` | string | The amount of the transaction. | | `currency` | string | The currency of the transaction (format: ISO-4217). | **API – API Reference available** For a complete list of Transaction attributes, check the [Transactions](/api-reference/api-endpoints.html#tag/Transactions){target="\_self"} section of the API Reference. ### Transaction Types (`transactionType`) Below the list of possible values for the `transactionType` attribute. | Id | Name | Additional information | | :---: | --- | --- | | `1` | Payin | Transaction from an external account into a Treezor Wallet. | | `2` | Payout | Transaction from a Wallet to an external account. | | `3` | Transfer | Wallet-to-Wallet transfer. | | `5` | Payin Refund | Refund of a past transaction made into a Treezor Wallet. | | `10` | Card Transaction | Learn more in the [Card transactions](/guide/cards/transactions) section of the documentation. | | `11` | Payout Refund | Refund of a past transaction made from a Wallet to an external account. | | `13` | Payin Acquiring | Transaction capturing funds from a third-party card to credit a Treezor Wallet. [Learn more](/guide/acquiring/introduction). | | `14` | Payin Refund Acquiring | Refund of a card top-up. [Learn more](/guide/acquiring/refunds). | | `15` | SCTR Inst | [Received SEPA Instant Credit Transfer](/guide/transfers/credit-transfer-inst#received-instant-credit-transfers-sctr-inst) | | `17` | Payin SCT Instant Recall | Learn more in the [Recalls & RROs](/guide/transfers/sepa-recalls#sctr-inst-recalls) article. | | `18` | Payout SCT Instant Emit | [Emitted SEPA Instant Credit Transfer](/guide/transfers/credit-transfer-inst#emitted-instant-credit-transfers-scte-inst) | | `19` | Payin SCT Instant Emit Recall | Learn more in the [Recalls & RROs](/guide/transfers/sepa-recalls#sctr-inst-recalls) article. | | `20` | Credit Transfer Returned | SCT Return. | | `21` | Check Payin | [Check cashing](/guide/cheques/introduction) | | `22` | SDDE | [Emitted SEPA Direct Debit](/guide/transfers/direct-debit#emitted-direct-debits-sdde) | | `23` | SDDR | [Received SEPA Direct Debit](/guide/transfers/direct-debit#received-direct-debits-sddr) | | `24` | SDDR Reversal | SDDR refused after effective date. | | `25` | SCTR Recall | Learn more in the [Recalls & RROs](/guide/transfers/sepa-recalls#sctr-inst-recalls) article. | | `26` | Check Refund | Refund of a check cashing. | | `27` | SCTR | [Received SEPA Credit Transfer](/guide/transfers/credit-transfer#received-credit-transfers-sctr) | ## Transaction object ::: code-group ```json [JSON] { "transactionId": 0, "walletDebitId": 0, "walletCreditId": 0, "transactionType": "string", "foreignId": 0, "name": "string", "description": "string", "valueDate": "string", "executionDate": "string", "amount": "string", "walletDebitBalance": "string", "walletCreditBalance": "string", "currency": "string", "createdDate": "string", "totalRows": 0 } ``` ::: ## Retrieving transactions The [`/v1/transactions`](/api-reference/api-endpoints.html#tag/Transactions/getTransactions){target="\_self"} endpoint allows you to retrieve lists of transaction. The following example searches for `Payin` Transactions per `userId`. ::: code-group ```bash [CURL] curl -X GET '{baseUrl}/v1/transactions?userId={userId}&transactionType=Payin' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' ``` ::: Returns an array of Transaction objects. ::: code-group ```json [JSON] { "transactions": [ { "transactionId": 4823484, "walletDebitId": 9, "walletCreditId": 2540896, "transactionType": "Payin", "foreignId": "1234626", "name": "1234626", "description": "Payin bank transfer", "valueDate": "2023-12-21", "executionDate": "2023-12-21", "amount": "101.25", "walletDebitBalance": "0.00", "walletCreditBalance": "50203.75", "currency": "EUR", "createdDate": "2023-12-21 12:11:34", "totalRows": "2" }, { "transactionId": 4823455, "walletDebitId": 9, "walletCreditId": 2540896, "transactionType": "Payin", "foreignId": "1234606", "name": "1234606", "description": "Payin bank transfer", "valueDate": "2023-12-21", "executionDate": "2023-12-21", "amount": "101.25", "walletDebitBalance": "0.00", "walletCreditBalance": "50102.50", "currency": "EUR", "createdDate": "2023-12-21 12:05:40", "totalRows": "" } ] } ``` ::: ## Retrieving a transaction Endpoint: [`/v1/transactions/{transactionId}`](/api-reference/api-endpoints.html#tag/Transactions/getTransaction){target="\_self"} ::: code-group ```bash [CURL] curl -X GET '{baseUrl}/v1/transactions/{transactionId}' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ ``` ::: Returns the corresponding Transaction object. ::: code-group ```json [JSON] { "transactions": [ { "transactionId": 4823455, "walletDebitId": 9, "walletCreditId": 2540896, "transactionType": "Payin", "foreignId": "1234606", "name": "1234606", "description": "Paiement ", "valueDate": "2023-12-21", "executionDate": "2023-12-21", "amount": "101.25", "walletDebitBalance": "0.00", "walletCreditBalance": "50102.50", "currency": "EUR", "createdDate": "2023-12-21 12:05:40", "totalRows": "1" } ] } ``` ::: ## Endpoints | Endpoint |[Scope](/guide/api-basics/authentication#available-scopes) | | --- | --- | | [`/v1/transactions`](/api-reference/api-endpoints.html#tag/Transactions/getTransactions){target="\_self"} Search for transactions | `read_write` | | [`/v1/transactions/{transactionId}`](/api-reference/api-endpoints.html#tag/Transactions/getTransaction){target="\_self"} Retrieve a transaction | `read_write` | --- --- url: /guide/dashboard/wallets.md description: >- Let your team provide support regarding your end users wallets using the Treezor Dashboard. --- # Wallets Wallets are similar to bank accounts, each User at Treezor requires one to make any kind of banking operation. ## Accessing Wallets You may access wallet information by: * Taking advantage of the main *Search toolbar* * Navigating the *Profile Boards* view, *Wallets* tab once a user is selected ### Search toolbar The Dashboard main toolbar provides a series of search fields, most of them being based on user attributes. Among those fields, the **Wallet Id** one takes into account the `walletId` of the [Wallet](/guide/wallets/introduction). **Tip – Find out more about the filters** You may read the [Search toolbar](/guide/dashboard/users#search-toolbar) article to learn everything you need to know about the search fields. After clicking on the "Search" button for a given wallet, selecting the displayed wallet redirects you to the corresponding user Profile, *Wallets* tab. ### Profiles Board view, Wallets tab Once you've accessed a user Profile, click on the *Wallets* tab in order to view all the wallets attached to the user. The view is divided into two sections: * **Wallets list** – On the left-hand side, you can navigate and manage the user wallets. * **Operations** – On the right-hand side, you can view the operations of the selected wallet. ## Navigating the Wallet's information ### Wallets list section The *Wallets* tab displays the list of Wallets owned by the selected user. The following information is displayed for each wallet: *Status*, *Name*, *ID*, *[Current Balance](/guide/overview/glossary#balance)*, *[Authorized Balance](/guide/overview/glossary#balance)*, and *[IBAN](/guide/wallets/iban)*. You may also add the Wallet as a favorite for later operations: |      | Name | Description | |:---: |--- |--- | | | Star | Add as favorite. | | | Unstar | Remove from favorites. | #### Wallet commands When clicking on the "More" button (vertical ellipsis), the following commands are available: |      | Name | Description | |:---: |--- |--- | | | **Download document** | Provides access to the following commands to download your [templated PDFs](./templates): **Domiciliation certificate** – Attestation proving the account registered address.**Balance certificate** – Attestation proving the current balance on the account.**Closure certificate** - Attestation proving the account was closed.**Account details** – The account details (i.e., user name and address, the wallet IBAN, BIC, and account number).**Statement** – The [Statement](/guide/wallets/account-documents) for the selected month and year. | | | **Simulate** | Provides access to the following commands (Sandbox only): **Incoming bank transfer** – Prompts you to enter an amount to simulate an incoming bank transfer (SCTR)**Operations** – Allows you to populate the view with operations, for a given month and year. | | | **See wallet details** | Opens the *Wallet Details* popup, which displays all the information about the Wallet. | | | **Edit Wallet** | Opens the *Edit Wallet* popup, allowing you to update the Wallet name, tag, and description. The wallet type can also be changed as long as no operation occurred yet. | | | **Deactivate Wallet** | [Deactivates the wallet](#deactivating-a-wallet). This action is irreversible. | Please note available options may differ depending on the wallet status and your dashboard user role. ### Wallet operations section Once a wallet is selected, the corresponding [Operations](/guide/wallets/operations) (if any) are displayed in the right-hand side of the view. The list of operations can be sorted, filtered, and customized as you see fit. |      | Option | Description | |:---: |--- |--- | | | Date range | Allows you to define after (From) and/or before (To) which dates the operations are considered. Any operation whose date is not in the defined time frame is filtered out. | | | Amount range | Allows you to define the minimum and maximum amounts for the operations to be considered. Any transaction outside the frame is filtered out. | | | Initial flow | Allows you to only display operations whose initial flow is selected. | | | Operation type | Allows you to only display operations whose type is selected. | | | Direction | Allows you to only display operations whose direction is selected. | | | Clear | Resets all the sorting and filtering options. | | | Organize columns | Opens a panel that allows you to select which columns to display and in which order (drag & drop). You may save your changes or reset to the initial display by using the corresponding buttons. | ## Creating a Wallet Upon clicking on the "Add Wallet" button at the top of the Wallets list section, the *Create wallet* popup is displayed. In this popup, you can enter the Wallet name and [type](/guide/wallets/introduction#types-of-wallets). If you're operating in multiple countries, you may need to select the BIC too (in accordance with the user's distribution country). ## Managing Wallets ### Deactivating a Wallet You can [deactivate](/guide/wallets/introduction#deletion) a wallet using the *Deactivate Wallet* command available when clicking on the Wallet "More" button. A Wallet can only be deactivated if: * There is no pending operation and * The balance equals to EUR 0.00 Once the Wallet deactivated, it displays a "Canceled" status and no operation can be done with this wallet. ### Downloading operations Operations stand for banking operations originating from or targeting a Wallet (i.e., Card Transactions, Payins, Payouts, and Transfers) and their refunds. You can download the operations (CSV format) of the selected wallet by clicking on the "Download Operations" button located in the upper right corner of the *Wallets* tab. In the *Download operations* popup, 2 options are available. | Option | Description | | --- | --- | | **Download view** | Downloads the operations currently displayed in the *Operations* section while matching the filtering criteria. In this case, the operations amount will be displayed in euros (decimals). | | **Download within date range** | Downloads all operations in a defined date range. In this case, the operations amount will be displayed in cents. | **Reading – Learn about transferring funds** You can make payouts and wallet-to-wallet transfers from the Dashboard. See the [Transfers](transfers) article for more information. --- --- url: /guide/dashboard/webhooks.md description: >- Configure your webhook URL and subscribe to events for webhook notifications directly from the comfort of Treezor Dashboard interface. --- # Webhooks Webhooks allow Treezor to send to a URL of your choice information regarding that event. **Configuration – This Dashboard view is not available by default** Please contact Treezor if you're interested in this feature. ## Navigating the Webhooks view The *Webhooks* view displays the list of subscriptions for your Treezor environment. For each subscription, you can view the status ("Enabled", or "Pending"), the URL events are sent to, and the list of Events if specified. The following commands are available: | Command | Description | | --- | --- | | **Add Webhook** | Prompts the *Add a new webhook* popup, allowing you to enter a URL to which events will be sent. | | **Modify** | Prompts the *Update a webhook* popup, allowing you to define which specific events to subscribe. | | **Delete** | Allows you to delete a subscription. | ## Managing subscriptions ### Subscribing to events You can create a new subscription by clicking on the "Add Webhook" button. In the prompted *Add a new webhook* popup, enter the URL to which the event notifications are to be sent. The created webhook subscription is then added to the list, with a "Pending" status. ### Specifying event subscription By default, you subscribe to all events upon creating a webhook. You can specify to which events to subscribe by clicking on the "Modify" button. The *Update a webhook* popup is displayed, allowing you to select the desired events. **Reading – Learn more about Webhooks** Please refer to the [Webhooks](/guide/webhooks/introduction) section of the documentation to learn more about available events and the information they provide. Once the desired events selected, click on the "Save changes" button to update the subscription. --- --- url: /guide/webhooks/events-descriptions.md description: >- Explore all Treezor API webhook events. This guide provides a comprehensive list of event names, their triggering actions, and payload structures, categorized by feature for complete event-driven integration. --- # Events description If you wish to receive only a subset of webhooks, please contact your *Treezor Account Manager*. ## Categories Each documentation section has an article dedicated to the events triggered by a feature. Find below the list of categories of events. | Category | Events | | --- | --- | | [**Users**](/guide/users/introduction) | [User events](/guide/users/events#users) – [Document events](/guide/user-verification/events#documents) – [KYC events](/guide/user-verification/events) | | [**Wallets**](/guide/wallets/introduction) | [Wallet events](/guide/wallets/events#wallets) – [Balance events](/guide/wallets/events#balances) – [Transfer events](/guide/transfers/events#transfers) | | [**Checks**](/guide/cheques/introduction) | [Check events](/guide/cheques/events#payins) | | [**Cards**](/guide/cards/introduction) | [Card events](/guide/cards/events#cards) – [Card Transaction events](/guide/cards/events-tx#cardtransactions) – [3DSecure events](/guide/cards/events#_3dsecure) – [Country Group events](/guide/cards/events#country-group) – [MCC Group events](/guide/cards/events#mcc-group) – [MID Group events](/guide/cards/events#mid-group) | | [**Transfers**](/guide/transfers/introduction) | [Payin/Payout events](/guide/transfers/events#payins-payouts) – [SEPA events](/guide/transfers/events#sepa) – [Mandate events](/guide/transfers/events#mandates) – [Beneficiary events](/guide/transfers/events#beneficiaries) | ## Descriptions | Event name | Triggering action | Payload | |- |- |- | | `authorization.create` | A card topup authorization was created. | `authorization` ([Structure](/guide/acquiring/events#authorization-create)) | | `authorization.update` | A card topup authorization was updated. | `authorization` ([Structure](/guide/acquiring/events#authorization-update)) | | `authorization.cancel` | A card topup authorization was canceled. | `authorization` ([Structure](/guide/acquiring/events#authorization-cancel)) | | `balance.update` | A Wallet Balance has changed. | `balance` ([Structure](/guide/wallets/events#wallets)) | | `beneficiary.create` | A Beneficiary has been created. | `beneficiary` ([Structure](/guide/transfers/events#beneficiary-create)) | | `beneficiary.update` | A Beneficiary has been modified. | `beneficiary` ([Structure](/guide/transfers/events#beneficiary-update)) | | `card3DSv2Authentication.create` | A cardholder must be identified with 3DS authentication. | `card3DSv2Authentication` ([Structure](/guide/cards/events-tx#card3DSv2authentication-create)) | | `card3DSv2Authentication.update` | Indicates the final result of cardholder 3DS authentication. | `card3DSv2Authentication` ([Structure](/guide/cards/events-tx#card3DSv2authentication-update))| | `card.requestphysical` | A Physical Card has been requested. | `card` ([Structure](/guide/cards/events#card-requestphysical)) | | `card.createvirtual` | A Virtual Card has been created. | `card` ([Structure](/guide/cards/events#card-createvirtual)) | | `card.convertvirtual` | A Virtual Card has been converted to a physical one. | `card` ([Structure](/guide/cards/events#card-convertvirtual)) | | `card.expeditionTracking` | The manufacturer mailed the card. | `card` ([Structure](/guide/cards/events#card-expeditiontracking)) | | `card.changepin` | A Card PIN has been changed. | `card` ([Structure](/guide/cards/events#card-changepin)) | | `card.activate` | A Card has been activated. | `card` ([Structure](/guide/cards/events#card-activate)) | | `card.register3DS` | A Card has been register for 3DS. | `card` ([Structure](/guide/cards/events#card-register3ds)) | | `card.expiryAlert` | A Card expires the next month. | `card` ([Structure](/guide/cards/events#card-expiryalert)) | | `card.renew` | A Card has been renewed (the previous one has expired). | `card` ([Structure](/guide/cards/events#card-renew)) | | `card.regenerate` | A Card Image has been regenerated. | `card` ([Structure](/guide/cards/events#card-regenerate))| | `card.update` | A Card `mccRestristionGroupId`, `merchantRestrictionGroupId` and `countryRestrictionGroupId` have been updated. | `card` ([Structure](/guide/cards/events#card-update)) | | `card.limits` | A Card limits have been updated. | `card` ([Structure](/guide/cards/events#card-limits)) | | `card.options` | A Card options have been updated. | `card` ([Structure](/guide/cards/events#card-options)) | | `card.assignwallet` | A Card has been assigned to a new wallet. | `card` ([Structure](/guide/cards/events#card-assignwallet)) | | `card.setpin` | A Card PIN has been set. | `card` ([Structure](/guide/cards/events#card-setpin)) | | `card.unblockpin` | A Card PIN has been unblocked. | `card` ([Structure](/guide/cards/events#card-unblockpin)) | | `card.unblockcvc2` | A Card CVC has been unblocked. | `card` ([Structure](/guide/cards/events#card-unblockcvc2)) | | `cardBulkUpdate.create` | A Card Bulk Update has been created. | `cardBulkUpdate` ([Structure](/guide/cards/events#cardbulkupdate-create)) | | `cardBulkUpdate.update` | A Card Bulk Update has been updated (e.g., processing complete). | `cardBukUpdate` ([Structure](/guide/cards/events#cardbulkupdate-update)) | | `card.lockunlock` | A Card has been locked, unlocked, lost, stolen, or destroyed. | `card` ([Structure](/guide/cards/events#card-lockunlock)) | | `cardDigitalization.request` | **Production only.** | `cardDigitalization` ([Structure](/guide/cards/events#carddigitalization)) | | `cardDigitalization.update` | **Production only.** | `cardDigitalization` ([Structure](/guide/cards/events#carddigitalization-update)) | | `cardDigitalization.activation` | **Production only.** | `cardDigitalization` ([Structure](/guide/cards/events#carddigitalization-activation)) | | `cardDigitalization.complete` | **Production only.** | `cardDigitalization` ([Structure](/guide/cards/events#carddigitalization-complete)) | | `cardDigitalization.deactivated` | **Production only.** | ([Structure](/guide/cards/events#carddigitalization-deactivated)) | | `cardtransaction.create` | A Card Transaction has been initiated. | `cardtransaction` ([Structure](/guide/cards/events-tx#cardtransaction-create)) | | `card.acquiring.chargeback.create ` | A chargeback had been received. | `card.acquiring` ([Structure](/guide/acquiring/events#card-acquiring-chargeback-create)) | | `countryGroup.create` | A country restriction group has been created. | `countryGroup` ([Structure](/guide/cards/events#countrygroup-create)) | | `countryGroup.update` | A country restriction group has been updated. | `countryGroup` ([Structure](/guide/cards/events#countrygroup-update)) | | `countryGroup.cancel` | A country restriction group has been cancelled. | `countryGroup` ([Structure](/guide/cards/events#countrygroup-cancel)) | | `document.create` | A Document has been created. | `document` ([Structure](/guide/user-verification/events#document-create)) | | `document.update` | A Document has been modified. | `document` ([Structure](/guide/user-verification/events#document-update)) | | `document.cancel` | A Document has been deleted. | `document` ([Structure](/guide/user-verification/events#document-cancel)) | | `kycliveness.create` | A User has sent documents through the live verification process. | `kycliveness` ([Structure](/guide/user-verification/events#kycliveness-create)) | | `kycliveness.update` | The Live verification provided has analyzed the documents provided by the user. | `kycliveness` ([Structure](/guide/user-verification/events#kycliveness-update)) | | `mandate.create` | A Mandate has been created. | `mandate` ([Structure](/guide/transfers/events#mandate-create)) | | `mccGroup.create` | A MCC restriction group has been created. | `mccGroup` ([Structure](/guide/cards/events#mccgroup-create)) | | `mccGroup.update` | A MCC restriction group has been updated. | `mccGroup` ([Structure](/guide/cards/events#mccgroup-update)) | | `mccGroup.cancel` | A MCC restriction group has been canceled. | `mccGroup` ([Structure](/guide/cards/events#mccgroup-cancel))| | `merchantIdGroup.create` | A MID restriction group has been created. | `merchantIdGroup` ([Structure](/guide/cards/events#merchantidgroup-create)) | | `merchantIdGroup.update` | A MID restriction group has been updated. | `merchantIdGroup` ([Structure](/guide/cards/events#merchantidgroup-update))| | `merchantIdGroup.cancel` | A MID restriction group has been canceled. | `merchantIdGroup` ([Structure](/guide/cards/events#merchantidgroup-cancel)) | | `payin.create` | A payin object has been created. | `payin` ([Structure](/guide/transfers/events#payin-create)) | | `payin.update` | A payin object has been updated. | `payin` ([Structure](/guide/transfers/events#payin-update)) | | `payin.cancel` | A payin object has been canceled. | `payin` ([Structure](/guide/transfers/events#payin-cancel)) | | `payinrefund.create` | A Refund for a payin has been created. | `payinrefund` ([Structure](/guide/transfers/events#payinrefund-create))| | `payinrefund.update` | A Refund for a payin has been updated. | `payinrefund` ([Structure](/guide/transfers/events#payinrefund-update))| | `payinrefund.cancel` | A Refund for a payin has been canceled. | `payinrefund` ([Structure](/guide/transfers/events#payinrefund-cancel))| | `payout.create` | A payout object has been created. | `payout` ([Structure](/guide/transfers/events#payout-create)) | | `payout.update` | A payout object has been updated. | `payout` ([Structure](/guide/transfers/events#payout-update)) | | `payout.cancel` | A payout object has been canceled. | `payout` ([Structure](/guide/transfers/events#payout-cancel)) | | `payoutRefund.create` | A Refund for a payout has been created. | `payoutRefund` ([Structure](/guide/transfers/events#payoutrefund-create)) | | `payoutRefund.update` | A Refund for a payout has been updated. | `payoutRefund` ([Structure](/guide/transfers/events#payoutrefund-update)) | | `payoutRefund.cancel` | A Refund for a payout has been canceled. | `payoutRefund` ([Structure](/guide/transfers/events#payoutrefund-cancel)) | | `qes.created` | The user completed the QES verification process. | `qes` ([Structure](/guide/user-verification/events#qes-created)) | | `qes.processing` | The QES verification process is under review on the verification provider side. | `qes` ([Structure](/guide/user-verification/events#qes-processing)) | | `qes.aborted` | The user abandoned the QES process. | `qes` ([Structure](/guide/user-verification/events#qes-aborted)) | | `qes.finalized` | The QES process is done on the verification provider side, either successful or canceled. | `qes` ([Structure](/guide/user-verification/events#qes-finalized)) | | `recallR.need_response` | | `recallr` ([Structure](/guide/transfers/events#recallr-need-response)) | | `sca.wallet.create` | An SCA Wallet has been created. | `scaWallet` ([Structure](/guide/strong-customer-authentication/events#sca-wallet-create)) | | `sca.wallet.update` | An SCA Wallet has been activated. | `scaWallet` ([Structure](/guide/strong-customer-authentication/events#sca-wallet-update)) | | `sca.wallet.delete` | An SCA Wallet has been deleted. | `scaWallet` ([Structure](/guide/strong-customer-authentication/events#sca-wallet-delete)) | | `sca.wallet.lock` | An SCA Wallet has been locked. | `scaWallet` ([Structure](/guide/strong-customer-authentication/events#sca-wallet-lock)) | | `sca.wallet.resetPin` | An SCA Wallet has been created. | `scaWallet` ([Structure](/guide/strong-customer-authentication/events#sca-wallet-resetpin)) | | `sca.wallet.swap` | An SCA Wallet has been swapped. | `scaWallet` ([Structure](/guide/strong-customer-authentication/events#sca-wallet-swap)) | | `sca.wallet.unlock` | An SCA Wallet has been unlocked. | `scaWallet` ([Structure](/guide/strong-customer-authentication/events#sca-wallet-unlock)) | | `sepaSctrInst.reject_sctr_inst` | | `sepaSctrInst` ([Structure](/guide/transfers/events#sepasctrinst-reject-sctr-inst)) | | `sepa.refund_sddr` | A SEPA Direct Debit (SDDR) has been refunded. | `sepaSddr` ([Structure](/guide/transfers/events#sepa-refund-sddr)) | | `sepa.reject_sddr_core` | A SEPA Direct Debit (SDDR) has been rejected. | `sepaSddr` ([Structure](/guide/transfers/events#sepa-reject-sddr-core)) | | `sepa.reject_sddr_b2b` | A SEPA Direct Debit (SDDR B2B) has been rejected. | `sepaSddr` ([Structure](/guide/transfers/events#sepa-reject-sddr-b2b)) | | `sepa.return_sctr` | **Production only.** | `sepaSctr` ([Structure](/guide/transfers/events#sepa-return-sctr)) | | `sepa.return_sddr` | A SEPA Direct Debit (SDDR) has been returned. | `sepaSdde` ([Structure](/guide/transfers/events#sepa-return-sddr)) | | `separecallsctrinst.reception​` | | `separecallsctrinst` ([Structure](/guide/transfers/events#separecallsctrinst-reception)) | | `sepa_sddr.reception` | | `sepa_sddr` ([Structure](/guide/transfers/events#sepa-sddr-reception)) | | `topupCard.validate`| A Card Topup has been validated. | `topupCard` ([Structure](/guide/acquiring/events#topupcard-validate)) | | `topupCard.cancel`| A Card Topup has been canceled. | `topupCard` ([Structure](/guide/acquiring/events#topupcard-cancel)) | | `transaction.create` | A Transaction was created. | `transaction` ([Structure](/guide/transfers/events#transaction-create)) | | `transfer.create` | A Wallet-to-Wallet Transfer has been created. | `transfer` ([Structure](/guide/transfers/events#transfer-create)) | | `transfer.update` | A Wallet-to-Wallet Transfer has been updated. | `transfer` ([Structure](/guide/transfers/events#transfer-update)) | | `transfer.cancel` | A Wallet-to-Wallet Transfer has been canceled. | `transfer` ([Structure](/guide/transfers/events#transfer-cancel)) | | `user.create` | A User has been created. | `user` ([Structure](/guide/users/events#user-create)) | | `user.update` | A User has been modified. | `user` ([Structure](/guide/users/events#user-update)) | | `user.cancel` | A User has been deactivated. | `user` ([Structure](/guide/users/events#user-cancel))| | `user.kycreview` | Treezor has validated or refused the User KYC. | `user` ([Structure](/guide/user-verification/events#user-kycreview)) | | `user.kycrequest` | A User requested a KYC Review. | `user` ([Structure](/guide/user-verification/events#user-kycrequest)) | | `videoConference.created` | The user completed the video conference verification process. | `videoConference` ([Structure](/guide/user-verification/events#videoconference-created)) | | `videoConference.processing` | The video conference verification process is under review on the verification provider side. | `videoConference` ([Structure](/guide/user-verification/events#videoconference-processing)) | | `videoConference.aborted` | The user abandoned the video conference process. | `videoConference` ([Structure](/guide/user-verification/events#videoconference-aborted)) | | `videoConference.finalized` | The verification process is done on the verification provider side, either successful or canceled. | `videoConference` ([Structure](/guide/user-verification/events#videoconference-finalized)) | | `wallet.create` | A Wallet has been created. | `wallet` ([Structure](/guide/wallets/events#wallets)) | | `wallet.update` | A Wallet has been modified. | `wallet` ([Structure](/guide/wallets/events#wallet-update)) | | `wallet.cancel` | A Wallet has been deactivated. | `wallet` ([Structure](/guide/wallets/events#wallet-cancel)) | --- --- url: /guide/webhooks/integrity-checks.md description: >- Ensure Treezor API webhook authenticity and integrity. This guide details how to verify payloads using the relevant fields, covering signature generation (HMAC-SHA256) and secure handling of webhook responses. --- # Enforcing integrity Every `object_payload` you receive is accompanied by an `object_payload_signature`. This signature (or [hash](https://en.wikipedia.org/wiki/Hash_function)) allows you to make sure that: * **The payload was emitted by Treezor** * **The payload has not been altered** **Security – Check for integrity** You MUST check the integrity of the payload against the `object_payload_signature` before trusting it. ## How to check the payload integrity For each received webhook, follow these steps: * **Flatten** the received JSON payload * **Convert** UTF-8 characters to their Unicode sequence equivalent (`é` to `\u00e9`, `è` to `\u00e8`, etc.) * **Generate** the cryptographic signature of the payload (HMAC using the secret) * **Convert** the binary signature to base64 * **Compare** your signature to the one provided along with the webhook * **Respond** according to the comparison result ### Generate your own signature of the payload To verify the integrity of the webhooks, Treezor provided you with a `webhook_secret` string. **Security – Keep your secret string safe** If a third-party were to access this secret string, they could send you fake events and your application would trust them. This secret is used as a [salt](https://en.wikipedia.org/wiki/Salt_\(cryptography\)) to hash the payload of each event. ::: code-group ```js [JavaScript] // dependencies const fs = require('fs'); const crypto = require('crypto'); // declare a function to encode UTF-8 characters to their unicode sequence equivalent (\uxxxx) let encodeUTF8ToCodePoint = (s) => { return s.replace( /[^\x20-\x7F]/g, x => "\\u" + ("000"+x.codePointAt(0).toString(16)).slice(-4) ) } // function to compute the signature const computedSignature = crypto.createHmac('sha256', WEBHOOK_SECRET) .update( encodeUTF8ToCodePoint( JSON.stringify(body.object_payload).replace(/\//g, '\\/') ) ) .digest('base64'); ``` ```python [Python] # function to compute the signature def compute_signature(secret, payload): payload = json.dumps(payload, separators=(",", ":")) payload = payload.replace("\\/", "/") # Json dump escape / twice payload = payload.replace("\\/", "/") # remove all \ payload = payload.replace("/", "\\/") # add \ hmac_sha256 = hmac.new( secret.encode("utf-8"), payload=payload.encode("utf-8"), digestmod=hashlib.sha256 ) return base64.b64encode(hmac_sha256.digest()).decode("utf-8") ``` ```ruby [Ruby] # dependencies require 'json' require 'openssl' # Function to encode UTF-8 characters to their unicode sequence equivalent (\uxxxx) def encode_utf8_to_code_point(s) s.gsub('/', '\\/').gsub(/[^ -~]/) { |m| "\\u%04x" % m.ord } end # Function to compute the signature def compute_signature(secret, object_payload) digest = OpenSSL::Digest.new('sha256') hmac = OpenSSL::HMAC.digest(digest, secret, encode_utf8_to_code_point(object_payload.to_json)) base64_signature = [hmac].pack('m0') # Base64 encoding end ``` ```java [Java] // dependencies import java.util.regex.Pattern; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import java.nio.charset.StandardCharsets; import java.util.Base64; // Function to encode UTF-8 characters to their unicode sequence equivalent (\uxxxx) public static String encodeUTF8ToCodePoint(String s) { Pattern pattern = Pattern.compile("[^\\x20-\\x7E]"); return pattern.matcher(s).replaceAll(match -> { String hex = Integer.toHexString(match.group().codePointAt(0)); return "\\u" + ("0000" + hex).substring(hex.length()); }); } // Function to compute the signature public static String computeSignature(String secret, String objectPayload) throws Exception { // Initialize HMAC with SHA256 Mac sha256_Hmac = Mac.getInstance("HmacSHA256"); SecretKeySpec secretKey = new SecretKeySpec(secret.getBytes(StandardCharsets.US_ASCII), "HmacSHA256"); sha256_Hmac.init(secretKey); // Encode payload and replace characters String encodedPayload = encodeUTF8ToCodePoint(objectPayload).replace("/", "\\/"); byte[] payloadBytes = encodedPayload.getBytes(StandardCharsets.UTF_8); // Compute HMAC data byte[] hmacData = sha256_Hmac.doFinal(payloadBytes); // Convert to Base64 string return Base64.getEncoder().encodeToString(hmacData); } ``` ```php [PHP] // generate your own version of the signature function compute_signature(string $secret, array $object_payload) :string { return base64_encode( hash_hmac( 'sha256', // In PHP, there is no need to encode UTF-8 characters to their unicode sequence // since PHP's json_encode() function already does that automatically json_encode($object_payload), $secret, // as provided by your Treezor Account Manager true ) ); } ``` ::: **Information – Convert your signature UTF-8 characters to unicode** Treezor generates the `object_payload_signature` after converting all UTF-8 characters into the corresponding unicode sequences. You **must** do the same, otherwise you will produce mismatching signatures. (e.g., `é` must become `\u00e9`, `è` becomes `\u00e8`). ### Compare your signature with the webhook's signature ::: code-group ```php [PHP] // compare the newly generated signature with the webhook's signature if(strcomp( $payload_local_signature, // decode the payload and extract the provided signature from it json_decode(file_get_contents("php://input"), true)['object_payload_signature'] ) === 0) { // signature are identical, we can trust the payload // proceed... } else { // signatures differ, we cannot trust the payload Throw new Exception('Mismatching signatures', 500); } ``` ::: ## What should my application return? ### Signatures are identical You should return a `200` HTTP Status Code. **Best practice – Defer the verified webhook in a queueing system for async processing** Without asynchroneous processing, if your code fails to process the webhook, Treezor would not attempt to deliver the webhook again as you have already answered with a `200` HTTP Status Code. This could lead to data inconsistency on your side. ### Signatures don't match You should return an HTTP Status Code in the `500` range. Either way, there is no need to populate the response any further. When your server answers with a Status Code higher than `499` or when it takes more than **150ms** to answer, Treezor sends you the webhook again every minute (maximum of 30 attempts). If the 30 attempts limit is reached, then: * No more attempts are made * An incident notification is sent to Treezor Treezor will get in touch with you to diagnose the issue. Once the issue is resolved, webhook are sent normally again. ## Increased security Treezor offers several ways to increase the security of webhooks: ### IP Restriction You **may** request that they be sent to you from a fixed IP. This allows your code to check the source IP in addition to webhooks signatures. To request a fixed IP, please get in touch with your *Treezor Account Manager*. By default webhooks are sent from dynamic IP and don't allow for such checks. ### Amazon Web Services SQS If your infrastructure is built on AWS, you **should** get in touch with your *Treezor Account Manager* so that we can set up Amazon SQS instead of relying on webhook signatures. --- --- url: /guide/webhooks/race-conditions.md description: >- Manage webhook race conditions in the Treezor API. This guide explains why webhooks may be received out-of-order and provides the method to identify the latest events for accurate and consistent data processing. --- # Race conditions Treezor sends webhooks chronologically, but cannot guarantee that your servers will receive them in the same order. In some situations, you could receive a [`payin.update`](/guide/transfers/events#payin-update) before the associated [`payin.create`](/guide/transfers/events#payin-create) for instance. **Therefore, your code must not rely on the order in which webhooks are received**. ## Identifying the latest webhook To identify which of two or more webhooks were sent last, you must compare their `webhook_created_at` attribute with your locally stored values. Most webhook-contained objects also have a `createdDate` and `modifiedDate` attribute. You may also use these when they exist. This is of critical importance for [CardTransactions](/guide/cards/transactions-lifecycle) as they go through many steps and only the latest is authoritative. Failure to do so implies displaying outdated and erroneous information to the user. --- --- url: /guide/webhooks/retry.md description: >- Learn how to resend up to 20,000 webhooks per batch from a pre-generated CSV file. Includes required parameters, request structure, and response examples. --- # Retry webhooks Treezor provides a series of endpoins to resend webhooks. **Feature activation – Configuration required** Please contact Treezor to benefit from the retry webhooks feature. Resending webhooks is a 3-step process: 1. **Generate webhook history CSV file** for a given time frame. 2. **Request execution of the file** to resend the events contained generated .CSV file (up to 20,000 events). 3. **Retrieve the execution status** of the resent events batch. **Information – The `{webhooksBaseUrl}` variable isn't your [`{baseUrl}`](/guide/api-basics/environments)** * `https://webhook.sandbox.treezor.co` in [Sandbox](/guide/api-basics/environments#sandbox) * `https://webhook.api.treezor.co` in [Production](/guide/api-basics/environments#production) ## Generate webhook history CSV You first need to generate the .CSV file containing the webhook events you wish to resend. ### Parameters | Attribute | Type | Description | | --- | --- | --- | | `startAt` | string | The date and time from which to retrieve the webhooks. Format: RFC3339. | | `endAt` | string | The date and time up to which to retrieve the webhooks. Format: RFC3339. | | `webhook` | string | Filter for a specific event, if need be. Example: `wallet.create`. See the [Events description](./events-descriptions) article for the list of events. | ### Request example Endpoint: [`/retry/query`](/api-reference/webhook-endpoints.html#tag/Webhook%20Retry/webhookQueryRetry){target="\_self"} ::: code-group ```bash [CURL] curl -X POST '{webhooksBaseUrl}/retry/query' \ --header 'authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}`. ::: code-group ```json [JSON] { "startAt": "2025-06-10T12:10:00+02:00", "endAt": "2025-07-08T00:00:00+02:00", "webhook": "merchantIdGroup.create" } ``` ::: Returns the following object: ::: code-group ```json [JSON] { "queryId":"2bd5740a-528d-451d-a726-7f57c6d82008", "link": "https://your.csv.link", "expireIn": 300 } ``` ::: If the .CSV file contains more than 20,000 events, you must adjust the time frame until you reach 20,000 or lower in order to move to step 2. ## Resend events batch Now that a .CSV file with a maximum number of 20,000 events has been generated, you can use the execution endpoint to resend all the events contained in the file. ### Parameters | Attribute | Type | Description | | --- | --- | --- | | `queryId` | string | The unique identifier of the query obtained in the first step. | | `delay` | integer | The time between each webhook retry attempts in seconds, in order to not overload your servers. Can't exceed 1 hour (`3600`). | ### Request example Endpoint: [`/retry/exec`](/api-reference/webhook-endpoints.html#tag/Webhook%20Retry/webhookExecRetry){target="\_self"} ::: code-group ```bash [CURL] curl -X POST '{webhooksBaseUrl}/retry/exec' \ --header 'authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}`. ::: code-group ```json [JSON] { "queryId":"2bd5740a-528d-451d-a726-7f57c6d82008", "delay": 10 } ``` ::: Returns the following object: ::: code-group ```json [JSON] { "executionId":"12345678-1234-1234-1234-123456789abc", "status": "IN_PROGRESS" } ``` ::: ## Retrieve the execution status You can check whether the resend batch is completed using the dedicated request below with the `executionId` from the previous step. ### Request example Endpoint: [`/retry/exec/{executionId}`](/api-reference/webhook-endpoints.html#tag/Webhook%20Retry/checkWebhookRetryStatus){target="\_self"} ::: code-group ```bash [CURL] curl -X GET '{webhooksBaseUrl}/retry/exec/{executionId}' \ --header 'authorization: Bearer {accessToken}' ``` ::: Returns the following object, with the `status` valued to either `IN_PROGRESS` or `DONE`. ::: code-group ```json [JSON] {3} { "executionId":"12345678-1234-1234-1234-123456789abc", "status": "DONE", "lastEventAt": "2025-04-23T10:30:00Z" } ``` ::: --- --- url: /guide/webhooks/subscription-management.md description: >- Manage your Treezor API webhook subscriptions. This guide details how to register webhook endpoints, set up your back end to receive events, and manage subscribed events (list, update, unsubscribe) for tailored real-time notifications. --- # Subscription management Webhook reception requires you subscribe to them first. While a single subscription allows you to receive all webhooks, you can also register multiple endpoints to receive different events. During the subscription, if you don't specify an explicit list of webhooks that you whish to receive, you will automatically subscribe to all events. **Information – The `{webhooksBaseUrl}` variable isn't your [`{baseUrl}`](/guide/api-basics/environments)** * `https://webhook.sandbox.treezor.co` in [Sandbox](/guide/api-basics/environments#sandbox) * `https://webhook.api.treezor.co` in [Production](/guide/api-basics/environments#production) **Configuration – You may need assistance for your `{accessToken}`** While the `{accessToken}` should be either your BaaS API key or your [Connect JWT token](/guide/api-basics/authentication), webhook subscription may require an action from Treezor. Contact your *Treezor Implementation Manager* for more information. ## Declare a POST route in your back end In your back end, you should define a route that accepts HTTP POST requests. Below is an example using node.js/express: ::: code-group ```js [JavaScript] const express = require('express'); const app = express(); const bodyParser = require('body-parser'); // parse the application/json app.use(bodyParser.json()); // expose a POST endpoint app.post('/webhook', function (req, res) { // log each call (will be necessary to manually confirm the endpoint, step 3) console.log(JSON.stringify(req.body)); }); // start listering for webhooks app.listen(3000, function () { console.log('Example app listening on port 3000!') }); ``` ::: Then deploy this endpoint to a server: * Which is reachable from internet * On which you can consult the logs (to confirm your subscription at a later stage) **Tip – Making your development server reachable from internet** Several options are available to you to make your development server reachable from internet. See the [Testing in Sandbox](/guide/webhooks/testing-in-sandbox) article for more information. ## Register a hook endpoint The second step is to register your newly created endpoint using the following request. Endpoint: [`/settings/hooks`](/api-reference/webhook-endpoints.html#tag/Subscriptions/createSubscription){target="\_self"} ::: code-group ```bash [CURL] curl -X POST '{webhooksBaseUrl}/settings/hooks' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{"url":"{urlOfYourEndpoint}"}' ``` ::: Returns the list of webhooks including the newly created one **with a temporary `uuid`** in a pending status. The `uuid` changes when the subscription is validated later on. ::: code-group ```json [JSON] { "hooks":[ { "uuid":"d956cff0-04a2-530f-810b-66a5130e0e4a", "url":"{urlOfYourEndpoint}", "status":"PENDING" } ] } ``` ::: You are now receiving new events. ## List your webhooks subscriptions You can list your subscriptions using the following request. Endpoint: [`/settings/hooks`](/api-reference/webhook-endpoints.html#tag/Subscriptions/getSubscriptions){target="\_self"} ::: code-group ```bash [CURL] curl -X GET '{webhooksBaseUrl}/settings/hooks' \ --header 'Authorization: Bearer {accessToken}' ``` ::: Returns the list of subscriptions, with their `uuid` and `status`. ::: code-group ```json [JSON] { "hooks":[ { "uuid":"44c37ba5-f1fe-4d8a-ac2b-xxxxx6a2ae67", "url":"https:\/\/0***l.execute-api.eu-west-3.amazonaws.com\/dev\/aHR...3Q=", "status":"ENABLED" }, { "uuid":"cd98d460-f344-4c05-a192-xxxxxf6c0a4a", "url":"https:\/\/alexoak:****@0***l.execute-api.eu-west-3.amazonaws.com\/dev\/aHR...3Q=", "status":"ENABLED" }, { "uuid":"46a508cb-1c72-48be-a42d-xxxxxa704cec", "url":"https:\/\/alexoak:****@0***l.execute-api.eu-west-3.amazonaws.com\/dev\/aHR...Hk=", "status":"ENABLED" }, { "uuid":"0fae6471-25c3-4492-bc0d-xxxxx82e51ec", "url":"https:\/\/alexoak:****@trz.requestcatcher.com\/example", "status":"ENABLED" } ] } ``` ::: ## Retrieve details about a subscription You can retrieve the list of events to which a webhook is subscribed to, using the following request. Endpoint: [`/settings/hooks/{hookUuid}/events`](/api-reference/webhook-endpoints.html#tag/Events/getHookEvents){target="\_self"} ::: code-group ```bash [CURL] curl -X GET '{webhooksBaseUrl}/settings/hooks/{hookUuid}/events' \ --header 'Authorization: Bearer {accessToken}' ``` ::: Returns a list of [events](./events-descriptions#descriptions) to which you have subscribed. ::: code-group ```json [JSON] { "events":[ "payoutRefund.cancel", "payoutRefund.create", "payoutRefund.update" ] } ``` ::: **Note – An empty array is returned when you subscribed to all webhooks** The list of events is only relevant when you subscribed to specific webhooks. ## Update a subscription ### Update events list Specify the list of events in the payload (including the ones you've already subscribed to if any). Endpoint: [`/settings/hooks/{hookUuid}/events`](/api-reference/webhook-endpoints.html#tag/Events){target="\_self"} ::: code-group ```bash [CURL] curl -X POST '{webhooksBaseUrl}/settings/hooks/{hookUuid}/events' \ --header 'Authorization: Bearer {accessToken}' \ --header 'Content-Type: application/json' \ -d '{payload}' ``` ::: Here is an example of `{payload}`: ::: code-group ```json [JSON] { "events":[ "payoutRefund.cancel", "payoutRefund.create", "payoutRefund.update", "beneficiary.update", "beneficiary.create" ] } ``` ::: Returns the list of subscribed events as listed in the payload. ::: code-group ```json [JSON] { "events":[ "payoutRefund.cancel", "payoutRefund.create", "payoutRefund.update", "beneficiary.update", "beneficiary.create" ] } ``` ::: ### Remove an event You can remove one event at a time, specifying its name in the URL. Endpoint: [`/settings/hooks/{hookUuid}/events/{eventToDelete}`](/api-reference/webhook-endpoints.html#tag/Events/deleteHookEvents){target="\_self"} ::: code-group ```bash [CURL] curl -X DELETE '{webhooksBaseUrl}/settings/hooks/{hookUuid}/events/{eventToDelete}' \ --header 'Authorization: Bearer {accessToken}' ``` ::: Returns the list of subscribed events, without the one just removed. ::: code-group ```json [JSON] { "events":[ "payoutRefund.create", "payoutRefund.update", "beneficiary.update", "beneficiary.create" ] } ``` ::: --- --- url: /api-reference/webhook-endpoints.md description: >- The Webhook Treezor API Reference. Explore the endpoints dedicated to webhooks with detailed specifications, request/response examples, and schema definitions in an interactive OpenAPI 3.0.1 powered interface. ---