Getting started
Overview
Pay-by-link
is a method that breaks the payment process in two distinct phases:
- the creation of a payment request, operated by the creditor (receiver of funds)
- the acceptance & authorization of the payment, operated by the debtor (the source of funds)
The payment request encapsulates metadata such as: amount, currency, the list of goods to be acquired etc. Once its created, the payment request is wrapped into a transportable object - aka the link
- such as a URL or a QR code. The link is sent to a debtor who will only check/approve & authorize the payment.
FinqLink is a platform for developing pay-by-link applications, built on top of the Finqware Payments API. It comes with a simple API for generating payment links and a web application for operating the links.
Payment providers
- A
payment-provider
is a partner institution that operates payment services. FinqLink integrates with these providers over APIs such as open-banking payment initiation APIs. - Each provider has a unique code. Eg:
rzb_ro
,cec_ro
etc. - A provider may have one or multiple
payment-methods
offering different capabilities (domestic-only transfers, corporate-only transfers etc) - we provide an API and a dashboard for quering and visualising all the details regarding providers & methods.
How to test
- Get a set of API test credentials (contact Finqware)
- Use the
/providers/list
endpoint to query for the available/supported payment providers. - Create a payment link using the
/links/create
endpoint. Thepayment-method
will be used to restrict more or less the options shown to the end-user when opening the payment link. - Send the payment link to someone in order to operate the payment.
Sandbox testing
rzb_ro
- debtor IBAN:RO03RZBR0000069999999999
, creditor IBAN:RO10RZBR0000069999999970
, PSU ID:9999999998
- Test scenarios: (1) submit the debtor IBAN and/or PSU ID via the API; (2) do not submit them, let the user do the input
bt_ro
- username:testbt
, password:testbt
, pin:1234567
cec_ro
- username:testcecapi
, password:testcecapi
, IBAN:RO42CECEAG0202RON0007466
Security
What made this section unhelpful for you?
Overview
The Link API is secured by OAuth2 (mandatory for production access) and mTLS (optional).
Mutual TLS (mTLS) and OAuth2 Client Credentials are two distinct security mechanisms that can complement each other to provide robust authentication and secure communication in API integrations.
Note: for testing purposes we also support an internal authentication method that requires client_id/client_secret with each API call. The code examples in this document use this particular method.
Mutual TLS (mTLS)
mTLS is a mechanism for ensuring that both the client and server authenticate each other over a TLS connection. It is an extension of standard TLS (which typically only authenticates the server to the client).
- How mTLS Works:
- Client Authentication: In addition to the server presenting its certificate, the client also presents its own certificate to the server.
- Certificate Verification: Both parties verify the certificates they receive. This ensures that both the client and server are who they claim to be, providing bidirectional authentication.
- Secure Communication: Once both parties are authenticated, a secure encrypted communication channel is established.
- Benefits of mTLS:
- Strong, cryptographic client authentication.
- Prevents unauthorized clients from connecting to the server.
- Ensures data integrity and confidentiality during transmission.
OAuth2 Client Credentials Grant
OAuth2 Client Credentials Grant is a method for obtaining access tokens that can be used to authenticate requests to an API. It is typically used when a client (such as a service or application) needs to access resources or APIs on behalf of itself, not on behalf of a user.
- How OAuth2 Client Credentials Grant Works:
- The client (service or application) authenticates with the authorization server using its client ID and secret.
- If the credentials are valid, the authorization server issues an access token.
- The client uses this access token to authenticate its requests to the resource server (API).
- Benefits of OAuth2 Client Credentials:
- Provides a mechanism for API clients to obtain access tokens for authenticating requests.
- Supports fine-grained authorization and scopes to control access to resources.
- Enables centralized management of client credentials and access policies.
Private Key JWT
Private Key JWT is a method of client authentication where the client creates and signs a JWT using its own private key. This method is described in a combination of RFC 7521 (Assertion Framework) and RFC 7523 (JWT Profile for Client Authentication, and referenced by OpenID Connect and FAPI 2.0 Security Profile.
Although we support the Client Secret (RFC 6749) authentication, we recommend Private Key JWT as it does not involve a process of sharing secrets.
How mTLS and OAuth2 Client Credentials Complement Each Other
When used together, mTLS and OAuth2 Client Credentials Grant provide a powerful combination of strong client authentication and fine-grained authorization. Here’s how they complement each other:
- Dual Authentication and Authorization:
- mTLS provides a strong, cryptographic client authentication mechanism, ensuring that only authorized clients (those with valid client certificates) can establish a connection.
- OAuth2 Client Credentials provides a token-based mechanism for authorizing the client's access to specific APIs or resources. The access token contains information about the client's permissions and access scope.
- Layered Security:
- By using both mTLS and OAuth2, you establish multiple layers of security. Even if an access token is somehow obtained by an attacker, mTLS ensures that only clients with a valid certificate can connect. Conversely, even if a client possesses a valid certificate, it still needs a valid access token to access protected resources.
- Preventing Token Theft and Replay Attacks:
- With mTLS, the secure communication channel prevents token theft during transmission. Even if a token were somehow intercepted, it would be useless without the client's certificate to establish the connection.
- Enhanced Security for Sensitive Applications:
- For highly sensitive applications, combining mTLS with OAuth2 Client Credentials ensures that only authenticated clients (validated by their certificates) and authorized clients (validated by their tokens) can access resources. This is particularly important in zero-trust environments or for internal microservices communication.
- Compliance and Regulatory Requirements:
- Some industries require strong client authentication and end-to-end encryption. Combining mTLS with OAuth2 can help meet these regulatory requirements by ensuring secure communication and controlled access.
Summary
By combining mTLS with OAuth2 Client Credentials Grant, you gain the benefits of both strong client authentication and fine-grained access control, enhancing the overall security posture of your application.
What made this section unhelpful for you?
How-to
mTLS
Setting up mTLS requires two steps. Please contact us for:
- enabling your API Client for mTLS
- sharing your certificate/s in order to be added to our PKI infrastructure
Certificate requirements
- Certificates must use either RSA or ECDSA ciphers.
- For client (leaf) certificates:
- The Basic Constraints extension must not contain
CA=true
. - The Extended Key Usage extension must contain
clientAuth
. - The Extended Key Usage extension must not contain the
codeSigning
,timeStamping
, orOCSPSigning
fields. - The certificate must not be expired.
- The client certificate cannot be a self-signed certificate.
- For root and intermediate certificates:
- The Basic Constraints extension must contain
CA=true
. - The Key Usage extension must be set to
keyCertSign
. - The Extended Key Usage extension should contain the
clientAuth
field. - The certificate must not be expired.
OAuth2
Setting up OAuth2 requires few steps. Please contact us for:
- enabling your API Client for OAuth2
- sharing the public key which we'll use to verify the signed requests to our Authorization server (example script for generating the public/private key pair)
Getting an access token
Making requests to the Link API in production requires a valid Bearer access token, sent via the standard Authorization
header. The process below describes the way to acquire an access token (example script for local tests with curl/Postman)
Your backend is responsible to implement a mechanism for keeping an up-to-date access-token available at all times. There are mature libraries for implementing this process, available in all mainstream programming languages (eg: Java, NodeJS).
Step-1: build a token with a payload such as below and sign it with your private key. The signed token is called a client_assertion
in OAuth2 terms.
The example below assumes your client_id is xyz123abc
and key id (kid): a1b2c3
:
The JSON Header has to specify your key id (kid):
{
"alg": "RS256",
"typ": "JWT",
"kid": "a1b2c3"
}
The JSON payload:
{
"aud": "https://finqware.okta.com/oauth2/ausfqbxutkZBUKUgQ417/v1/token",
"iss": "xyz123abc",
"sub": "xyz123abc",
"iat": 1741161292,
"exp": 1741164892,
"jti": "9CF1E…479C"
}
Step-2: use the client_assertion
computed above to make a call to our /token
endpoint in order to get an access-token.
curl --location --request POST 'https://finqware.okta.com/oauth2/ausfqbxutkZBUKUgQ417/v1/token' \ --header 'Accept: application/json' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'client_id=xyz123abc' \ --data-urlencode 'grant_type=client_credentials' \ --data-urlencode 'scope=pay_by_link' \ --data-urlencode 'client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer' \ --data-urlencode 'client_assertion=eyJhbGciOiJSUzI1NiIsIn....le3qGb5mp-yUmPqUwoyZaA9g'
Use the received access-token for making calls to the Link API until its expiration (each access-token is valid for a limited time).
What made this section unhelpful for you?
Create Link
Create a new payment link.
There are three flows currently supported (set via options/type):
link
: a standard transportable payment link. Offers maximum flexibility in terms of expiration and user optionality. Use this flow when generating payment links expected to be operated after a longer time. Example: an invoice sent over email which you don't expect an immediate action for.wrapped_sca
: a transportable payment link for immediate usage. The authorisation URL is requested at link creation, hence there is no optionality anymore for the user to choose a different payment provider. Use this flow when (1) you know upfront all the payment details and (2) you expect immediate action from your user, as the authorisation URL may expire in minutes.direct_sca
: a non-transportable payment link. This is a native authorisation URL received from the payment provider. Only available to regulated companies under PSD2 (PISP).
Header Parameters
Required for OAuth2-enabled clients (mandatory for production)
Body Parameters
An identifier for your Link app
A secret used for authenticating & authorising your client app. Not required for OAuth2-enabled clients.
Show child attributes
A set of filters for restricting payment-methods.
Show child attributes
Transfer related input.
Show child attributes
Response
Response Attributes
Request identifier
Creation timestamp
Expiry timestamp.
A unique id identifying the link object.
A public id used in the web_url.
The name of the client app that generated the link.
The URL to the payment link.
A URL pointing to a QR code.
Response Attributes
Response Attributes
What made this section unhelpful for you?
Base URL
Sandbox:
https://sandbox-link.finqware.com/
Production:
https://link.finqware.com/
Response
{
"request_id": "F4xsHcQ5cKDMQHQAAALB",
"created_at": "2023-10-09T11:13:54.729934Z",
"expires_at": "2023-10-09T12:13:54.729940Z",
"link_id": "4751bfcc-283a-44c2-96ab-0401421c22c3",
"web_id": "MTliNDUxNTItYTAxMi00N2FjLThjZDYtMDhlM2E2ZmZhNGQ3",
"api_client_app": "test-tenant-app",
"web_url": "http://localhost:4004/web/v1/links/cda95b1e-e842-4ca0-a777-989ba55756c3",
"qr_code": "qr code url - coming soon"
}
What made this section unhelpful for you?
Get Link
Retrieve information on an existing payment link.
Header Parameters
Required for OAuth2-enabled clients (mandatory for production)
Body Parameters
An identifier for your Link app.
A secret used for authenticating & authorising your client app. Not required for OAuth2-enabled clients.
The ID of the link to retrieve. This is a required parameter and should be a unique identifier for the link
Response
Response Attributes
A registered app that created the link.
Expiry timestamp.
A unique id identifying the link object.
A URL pointing to a QR code.
An id associated to the API request, for debugging purposes.
created
started
intent_accepted
awaiting_authz
received
submitted
completed
failed
revoked
A public id used in the web URL
A user-facing web endpoint for operating the payment link.
What made this section unhelpful for you?
Base URL
Sandbox:
https://sandbox-link.finqware.com/
Production:
https://link.finqware.com/
Response
{
"api_client_app": "test_client_app",
"expires_at": "2024-03-03T14:46:08Z",
"is_expired": false,
"link_id": "a7cd73bf-d678-49fb-bfe7-dd42c141b69a",
"qr_code": "coming soon",
"request_id": "F7kWqlbu0HMtFwEAAAzB",
"status": "created",
"web_id": "YTdjZDczYmYtZDY3OC00OWZiLWJmZTctZGQ0MmMxNDFiNjlh",
"web_url": "https://dev1-link-2ncnhzxiia-ey.a.run.app/web/beta/links/ZGM1NGQ4MjYtYjM2YS00NTk4LTk0ZmYtM2VhOTZmMzQ3Mzdk"
}
What made this section unhelpful for you?
List Links
List the links owned by an application identified by the client_id.
Header Parameters
Required for OAuth2-enabled clients (mandatory for production)
Body Parameters
An identifier for your Link app
A secret used for authenticating & authorising your client app. Not required for OAuth2-enabled clients.
Response
Response Attributes
A registered app that created the link.
A list of links owned by the registered app identified by client_id.
Show child attributes
What made this section unhelpful for you?
Base URL
Sandbox:
https://sandbox-link.finqware.com/
Production:
https://link.finqware.com/
Response
{
"api_client_app": "test",
"client_id": "test",
"links": [
{
"expires_at": "2024-03-02T16:38:19Z",
"is_expired?": true,
"link_id": "7d5de5d7-ad1a-4fe8-a25e-4a072c5ab1d2",
"status": "started",
"web_id": "N2Q1ZGU1ZDctYWQxYS00ZmU4LWEyNWUtNGEwNzJjNWFiMWQy",
"web_url": "https://dev1-link-2ncnhzxiia-ey.a.run.app/web/beta/links/ZGM1NGQ4MjYtYjM2YS00NTk4LTk0ZmYtM2VhOTZmMzQ3Mzdk"
}
],
"request_id": "F7kXZpDnO_sUeaUAAAHE"
}
What made this section unhelpful for you?
List Providers
List the supported payment-providers. You may check our dashboard built on top of this API for an overview.
Header Parameters
Required for OAuth2-enabled clients (mandatory for production)
Body Parameters
An identifier for your Link app
A secret used for authenticating & authorising your client app. Not required for OAuth2-enabled clients.
Filter for a specific list of service providers and their details.
Show child attributes
Options for showing service provider details
Show child attributes
Response
Response Attributes
Show child attributes
What made this section unhelpful for you?
Base URL
Sandbox:
https://sandbox-link.finqware.com/
Production:
https://link.finqware.com/
Response
{
"providers": [
{
"public_name": "cec_ro",
"provider_name": "CEC Bank",
"country": "ro",
"swift_code": "CECEROBU",
"description": null,
"payment_methods": [
{
"public_name": "cec_ro_sbx1",
"payment_scheme": "ro_domestic",
"interface_type": "psd2_api",
"transfer_type": "single_transfer",
"remitter_type": [
"retail"
],
"interface_env": "sandbox",
"interface": {
"interface_scope": "initiation",
"authz_flow": "redirect"
},
"features": {
"transfer_max_limit": null,
"transfer_min_limit": null,
"transfer_fee": "n/a",
"fee_bearer": [
"sender"
],
"bop_codes": [],
"currencies": [
"RON"
],
"cross_border": false
},
"validation_schema": {}
},
{
"public_name": "bt_ro_sbx1",
"payment_scheme": "ro_domestic",
"interface_type": "psd2_api",
"transfer_type": "single_transfer",
"remitter_type": [
"retail"
],
"interface_env": "sandbox",
"interface": {
"interface_scope": "initiation",
"authz_flow": "redirect"
},
"features": {
"transfer_max_limit": null,
"transfer_min_limit": null,
"transfer_fee": "n/a",
"fee_bearer": [
"sender"
],
"bop_codes": [],
"currencies": [
"RON"
],
"cross_border": false
}
},
{
"public_name": "rzb_ro_sbx1",
"payment_scheme": "ro_domestic",
"interface_type": "psd2_api",
"transfer_type": "single_transfer",
"remitter_type": [
"retail"
],
"interface_env": "sandbox",
"interface": {
"interface_scope": "initiation",
"authz_flow": "redirect"
},
"features": {
"transfer_max_limit": null,
"transfer_min_limit": null,
"transfer_fee": "n/a",
"fee_bearer": [
"sender"
],
"bop_codes": [],
"currencies": [
"RON"
],
"cross_border": false
},
"validation_schema": {}
}
],
"supports_instant_payments?": false,
"supports_corporate_payments?": false,
"supports_cross_border_transfers?": false
},
{
"public_name": "bt_ro",
"provider_name": "Banca Transilvania",
"country": "ro",
"swift_code": "BTRLRO22",
"description": null,
"payment_methods": [
{
"public_name": "bt_ro_sbx1",
"payment_scheme": "ro_domestic",
"interface_type": "psd2_api",
"transfer_type": "single_transfer",
"remitter_type": [
"retail"
],
"interface_env": "sandbox",
"interface": {
"interface_scope": "initiation",
"authz_flow": "redirect"
},
"features": {
"transfer_max_limit": null,
"transfer_min_limit": null,
"transfer_fee": "n/a",
"fee_bearer": [
"sender"
],
"bop_codes": [],
"currencies": [
"RON"
],
"cross_border": false
}
}
],
"supports_instant_payments?": false,
"supports_corporate_payments?": false,
"supports_cross_border_transfers?": false
},
{
"public_name": "rzb_ro",
"provider_name": "Raiffeisen Bank",
"country": "ro",
"swift_code": "RZBRROBU",
"description": null,
"payment_methods": [
{
"public_name": "rzb_ro_sbx1",
"payment_scheme": "ro_domestic",
"interface_type": "psd2_api",
"transfer_type": "single_transfer",
"remitter_type": [
"retail"
],
"interface_env": "sandbox",
"interface": {
"interface_scope": "initiation",
"authz_flow": "redirect"
},
"features": {
"transfer_max_limit": null,
"transfer_min_limit": null,
"transfer_fee": "n/a",
"fee_bearer": [
"sender"
],
"bop_codes": [],
"currencies": [
"RON"
],
"cross_border": false
},
"validation_schema": {}
}
],
"supports_instant_payments?": false,
"supports_corporate_payments?": false,
"supports_cross_border_transfers?": false
}
],
"request_id": "F7q9MRrexqV8nOQAAA-F"
}
What made this section unhelpful for you?
Get Provider
Details on a particular payment-provider. You may check our dashboard built on top of this API for an overview.
Header Parameters
Required for OAuth2-enabled clients (mandatory for production)
Body Parameters
An identifier for your Link app.
A secret used for authenticating & authorising your client app. Not required for OAuth2-enabled clients.
The ID of the link to retrieve. This is a required parameter and should be a unique identifier for the link
Please check the 'options' field from the /providers/list endpoint.
Show child attributes
Response
Response Attributes
Show child attributes
An id associated to the API request, for debugging purposes.
What made this section unhelpful for you?
Base URL
Sandbox:
https://sandbox-link.finqware.com/
Production:
https://link.finqware.com/
Response
{
"provider": {
"public_name": "rzb_ro",
"provider_name": "Raiffeisen Bank",
"country": "ro",
"swift_code": "RZBRROBU",
"description": null,
"payment_methods": [
{
"public_name": "rzb_ro_sbx1",
"payment_scheme": "ro_domestic",
"interface_type": "psd2_api",
"transfer_type": "single_transfer",
"remitter_type": [
"retail"
],
"interface_env": "sandbox",
"interface": {
"interface_scope": "initiation",
"authz_flow": "redirect"
},
"validation_schema": {},
"features": {
"transfer_max_limit": null,
"transfer_min_limit": null,
"transfer_fee": "n/a",
"fee_bearer": [
"sender"
],
"bop_codes": [],
"currencies": [
"RON"
],
"cross_border": false
}
}
],
"supports_instant_payments?": false,
"supports_corporate_payments?": false,
"supports_cross_border_transfers?": false
},
"request_id": "F7q_YlpfvKTWdA0AANSH"
}
What made this section unhelpful for you?
Callback redirect
A redirect endpoint used for direct_sca
flows only (available only to PIS-regulated entities).
Header Parameters
Required for OAuth2-enabled clients (mandatory for production)
Body Parameters
An identifier for your Link app.
A secret used for authenticating & authorising your client app. Not required for OAuth2-enabled clients.
The query string received from the bank via redirect.
If true, the request will await for a final status from the service provider, attempted by our backend in a background process.
Response
Response Attributes
What made this section unhelpful for you?
Base URL
Sandbox:
https://sandbox-link.finqware.com/
Production:
https://link.finqware.com/
Response
{
"api_client_app": "my_api_client_1",
"link_id": "571e3e4b-dcde-49e1-aedb-e5e7afecc7b2",
"request_id": "dcee6707-1711-4884-93a3-4d32e71c7999",
"status": "authorised",
"web_id": "NTcxZTNlNGItZGNkZS00OWUxLWFlZGItZTVlN2FmZWNjN2Iy"
}