Links

Pay

The Pay product lets you request transfers from banks complying with the revised Payment Service Directive (PSD2) only. It does not rely on bank account aggregation nor the related user-centric services of our API. You may request payments from an emitter bank to a beneficiary without creating a user or connection in our API.

Features activation

Pay features can be activated by your commercial contact only.

Configure the API behavior

The Pay product has 2 configuration keys that can be modified to adapt its behavior to your needs :
Key
Default value
Description
payment.manual_expire_time_days
7
The number of days after which the payment will have the status expired if it does not have a definitive status (ie done or rejected).
payment.max_amount
0
The maximum amount allowed in the payment initiation (enabled if amount is strictly greater than 0). While initiating a payment, an HTTP error 400 will be returned if the requested amount is greater than this maximum amount value.
See here for help on modifying the configuration keys value.

List compatible connectors and required fields

Only a limited set of banks currently support the Pay product. You can obtain the compatible connectors by querying the whole list and then filtering the results. Also, payment request execution requires that the values of some connector fields be provided. You can also obtain them from the same API call:
GET /connectors?expand=fields
{
"connectors": [
{
"id": 40,
"name": "Connecteur de test",
"payment_settings": {
"available_validate_mechanisms": [
"webauth"
],
"beneficiary_types": [
"iban"
],
"execution_date_types": [
"first_open_day",
"instant",
"deferred"
],
"execution_frequencies": [
"two-monthly",
"semiannually",
"weekly",
"yearly",
"four-monthly",
"daily",
"quarterly",
"biannual",
"bimonthly",
"two-weekly",
"monthly"
],
"maximum_number_of_instructions": 10,
"providing_payer_account": "optional"
}
"fields": [
{
"name": "website",
"label": "Région",
"required": true,
"type": "list",
"connector_sources": [ "openapi",],
"auth_mechanisms": [ "webauth",],
"values": [ { "label": "Région 1", "value": "r1" },]
}
]
},
]
}
Filter the connectors list to keep only compatible banks:
  • The connector must have a source named openapi;
  • The source must have the transfer capability, and the transfer_validate_mechanism must be set to webauth.
For a given compatible connector, you can identifiy the required fields to display:
  • The openapi value must be present in the connector_sources;
  • The webauth value must be present in the auth_mechanisms;
  • The field must be marked as required;
  • If the type is list, the value must be selected from the values list.
Connector selection and fields presentation are optional. You can validate a payment request without providing the id_connector and required values; in that case we will present the choice to the user before redirecting to the bank.
The payment_settings field describes features of the connector relative to payment initiation. See Payment Settings for more information.

Connectors requiring the payer account

A connector may require the payer account information in order to initiate a payment. These connectors are identified by the providing_payer_account key in the payment_settings object being set to mandatory, see PaymentSettings. In this case, the payment account information (identification, scheme, and name) must be passed in the payer object, see Request. If you are using the payment webview, this step is handled automatically for you.

Obtain a Payment token

The Pay product requires the use of special access tokens with dedicated scopes:
POST /auth/token
{
"grant_type": "client_credentials",
"client_id": "{clientId}",
"client_secret": "{clientSecret}",
"scope": "payments:admin",
}
{
"token": "{accessToken}",
"scope": "payments:admin"
}
The list of payment scopes can be found on the Authentication API reference

Create and validate a payment request

You initiate a payment request by creating a new resource on the dedicated endpoint:
POST /payments
{
"id_connector": 59,
"website": "par",
"client_redirect_uri": "https://mycallback.com",
"client_state": "{optionalClientState}",
"instructions": [
{
"reference_id": "{myReference}",
"label": "Test",
"amount": 50.90,
"currency": "EUR",
"execution_date_type": "first_open_day",
"beneficiary": {
"scheme_name": "iban",
"identification": "FR76XXXXXXXXXXXXXXX",
"label": "ACME Corp.",
"merchant_scheme_name": "siren",
"merchant_identification": "012345678"
}
}
],
"validated": true,
}
{
"id": 110,
"state": "created",
"error_code": null,
"error_description": null,
"register_date": "2020-03-25 11:41:26",
"validate_uri": "http://…",
}
When creating a payment request, you must provide the required information about the amount, currency, beneficiary and execution date. You can also provide the id_connector of the emitter bank and the values of the required fields (see above).
To actually process the payment request, send the validated flag and provide the client_redirect_uri and optionally a client_state. After the request has been validated, it is locked and the validation_uri will be returned.
You can validate the request immediately on creation if you have the required information. Else, you can delegate the emitter prompt and the validation to our dedicated payment webview.
When the validate_uri is provided, you must present it to the end-user to perform the confirmation steps. After the validation is performed, you will be redirected to your callback URL.

Checking payment status

After the payment is created or validated, you can check the status of the request:
GET /payments/{id}
{
"id": 110,
"state": "created",
"error_code": null,
"error_description": null,
}
Make sure you handle the various states and error codes correctly to provide a useful feedback to your users.

Search payments

You can also have an overview of the payments, for example this will return the 10 last payments:
GET /payments?reverse&limit=10
{
"payments": [
{
"id": 110,
"state": "created",
"error_code": null,
"error_description": null,
}
],
"total": 1
}
You can paginate the payments by using the offset parameter along your desired limit (page size), this example will return the 21st to 30th last payments (third page):
GET /payments?reverse&limit=10&offset=20
{
"payments": [
{
"id": 110,
"state": "created",
"error_code": null,
"error_description": null,
}
],
"total": 1
}
You can also filter payments with query parameters. The following example will return payments created after April 1st, 2021:
GET /payments?min_date=2021-04-01
The following example will return payments where the beneficiary identification (e.g. IBAN) is exactly 'FR76XXXXXXXXXX123', independently from the associated scheme name. Also note that no wildcard is supported.
GET /payments?beneficiary_identification=FR76XXXXXXXXXX123
For the full list of filtering options, see the Pay API reference.
Linking a user to a payment signifies that this user is the payer or beneficiary of the payment. This can be done by providing the id_user in the payer_beneficiary or beneficiary_identity fields. Note that the given id_user must exist on your domain.
POST /payments
{
"id_connector": 9,
"client_redirect_uri": "https://mycallback.com",
"instructions": [
{
"label": "Example id_user",
"amount": 10.50,
"currency": "EUR",
"execution_date_type": "first_open_day",
"beneficiary": {
"scheme_name": "iban",
"identification": "FR76XXXXXXXXXXXXXXX",
"label": "Corp",
},
"beneficiary_identity": {
"id_user": 2
}
}
],
"payer_identity": {
"id_user": 1
}
}
{
"id": 2058,
"state": "created",
"payer_identity": {
"id": 217,
"id_user": 1,
"kind": "individual",
"external_ref": null,
"first_name": null,
"last_name": null,
"org_name": null,
"org_legal_status": null,
"last_update_date": "2022-10-10 12:53:41",
"disabled_date": null
},
"instructions": [
{
"execution_date_type": "first_open_day",
"label": "Example id_user",
"amount": 10.5000000000,
"beneficiary_identity": {
"id": 216,
"id_user": 2,
"kind": "individual",
"external_ref": null,
"first_name": null,
"last_name": null,
"org_name": null,
"org_legal_status": null,
"last_update_date": "2022-10-10 12:53:41",
"disabled_date": null
},
...
...
}
],
...
}

Transfer (Deprecated)

Since the release of our Pay product (handling PSD2-compliant use-cases), the former Transfer product (based on directaccess) has been deprecated and is no longer offered.
The Transfer product allows you to make transfers on a limited number of bank connectors. It is an extension of the Bank product and transfers are linked and limited to aggregated bank accounts.

Transfers accounts

Accounts available as a transfer emitter are flagged with the able_to_transfer flag:
GET /users/me/accounts
{
"accounts": [
{
"id": 12345,
"name": "Compte de dépôt",
"number": "0212366548",
"iban": "FR1221954549412158521",
"type": "checking",
"balance": 1452.56,
"coming": null,
"currency": { "id": "EUR",},
"able_to_transfer": true,
},
]
}
Initiate a transfer from an non-flagged account will result in an error.

Transfer recipients

Transfer-enabled accounts are linked to recipients for the purpose of transfer execution. A recipient materializes the couple of an "emitter account" and a pre-registered "transfer destination", and the list of recipients matches the combinations actually available on the bank website. As a consequence, a single "beneficiary" will result in several recipients, from different accounts. While this API can create new recipients on some connectors, execution of transfers to arbitrary destinations (PSD2 payment) is out of its scope.
GET /users/me/recipients
GET /users/me/accounts/{accountId}/recipients
{
"recipients": [
{
"id": 5,
"id_account": 3,
"id_target_account": 2,
"label": "Livret A",
"bank_name": "BNP PARIBAS",
"iban": "FR7630004012550003027641744",
"bic": "BNPAFRPPXXX",
"category": "Internal",
"enabled_at": "2016-10-31 18:52:53",
"state": null,
},
{
"id": 6,
"id_account": 3,
"id_target_account": null,
"label": "Test",
"bank_name": "BNP PARIBAS",
"iban": "FR7630004000031234567890143",
"bic": "BNPAFRPPXXX",
"category": "External",
"enabled_at": "2016-10-31 18:52:53",
"deleted": "2016-12-05 12:07:24",
"last_update": "2016-12-05 12:07:24",
"state": "deleted",
},
]
}
The id_target_account property identifies internal recipients, where the destination account is present in the API.
Recipients are subject to the same archival mechanism and implicit filtering as bank accounts or transactions. Use the query parameter all to display deleted recipients or recipients with an enabled_at date in the future.

Transfer execution

Transfers are performed in two steps: initiation and validation.
Tranfer initiation
Create a transfer resource providing the account and recipient IDs and the transfer details:
POST /users/me/transfers
{
"id_account:": 123,
"id_recipient": 456,
"label": "Test",
"amount": 10,
"exec_date": "2019-09-01"
}
{
"id": 110,
"label": "Test",
"amount": 10.0,
"exec_date": "2019-09-01",
"id_recipient": 456,
"account_iban": "FR7630004012550000041157244",
"recipient_iban": "FR7630006000011234567890189",
"state": "created",
"register_date": "2019-02-28 11:41:26",
"currency": { "id": "EUR",},
}
No interaction is made with the bank during the initiation step, and the transfer resource is editable while it has not been validated.
If the execution date is not specified, the default date is the day on which the transfer is created. The date should be checked before validation to avoid requesting the execution of a transfer in the past.
The label is optional but recommended so that the Pay product can find the equivalent transaction in the history to confirm the execution of the transfer. Support of non-ASCII characters in labels vary by banks and should be avoided to prevent validation errors.
Transfer validation
Transfer validation requires an explicit end-user validation.
POST /users/me/transfers/{id}
{ "validated": true }
This request actually submits the transfer order to the bank. It can results in an successful response if the transfer was successfully submitted:
{
"id": 110,
"state": "pending",
}
Else, if a user SCA is required to execute the transfer, the required fields are exposed in the reponse:
{
"id": 110,
"state": "pending",
"fields": [
{
"label": "Code secret BNP Paribas",
"type": "password",
"regex": "^[0-9]{6}$",
"name": "password"
}
]
}
The required fields (usually an OTP) must be presented to the user, and the input values must be sent to proceed with validation. We currently manage those sent by SMS or generated by box.
POST /users/me/transfers/{id}
{ "validated": true, "password": "xxxxxxx" }
{
"state": "pending",
"id": 110
}
To enforce security, transfer validation should not be performed using the all-purpose user access token. A special time-limited access token with the dedicated transfer scope must be obtained. If transfer execution is performed using a non-transfer access token, the web banking password of the user will be asked as a validation field.