Integration model
Finbility provides a standard REST payment API plus a merchant-side secure card component. The frontend component is delivered through finbility-card.js, which wraps Evervault card fields behind a simpler integration surface.
- Frontend renders one secure card block and writes encrypted values into your form.
- Backend uses OAuth 2.0, then calls payment, query, webhook, and refund APIs.
- Apple Pay and Google Pay use the
/v1/paymentCollectAPI only; redirect the customer topay_urlto complete payment in the wallet. - Default selectors, hidden field mappings, and built-in copy keep checkout integration minimal.
Prerequisites
- Client ID and Client Secret for Finbility OAuth.
- A checkout page served over HTTPS.
Base URL
Get your Client ID and Client Secret
API credentials are managed in the merchant dashboard under Settings > My profile > API Key.
- Use the displayed Client ID together with the Client Secret returned when the key is first generated or reset.
- The dashboard only shows a masked secret after creation. Save the full Client Secret immediately because it is only displayed once.
- If the secret is lost or needs to be rotated, reset the API Key in the dashboard and update your backend configuration before requesting new OAuth tokens.
clientSecret in browser code, public pages, or mobile app bundles.
Get an access token before calling backend APIs
| Header | Required | Description |
|---|---|---|
Authorization |
Yes | Basic + Base64(clientId:clientSecret) |
Accept |
Yes | application/json |
Content-Type |
Yes | application/x-www-form-urlencoded |
{
"access_token": "653633b2-8287-47b6-a7e4-40ec252fe9a8",
"token_type": "bearer",
"expires_in": 43035,
"scope": "write,read"
}
Authorization: Bearer <access_token> when calling payment and refund APIs.
Use finbility-card.js as the merchant integration layer
The script automatically loads the Evervault browser SDK, generates the secure card UI inside your mount element, manages loading and error states, enables the submit button when the encrypted payload is ready, and writes values into hidden inputs.
- The component handles secure fields, default copy, loading state, and hidden field updates.
- You control locale, theme, callbacks, form action, and backend payload mapping.
- The default integration only needs one script tag, one mount div, and one submit button.
Minimal integration
- Include
finbility-card.json the checkout page. - Add a form with a single mount container and a submit button.
- Initialize
FinbilityPayCard. The secure component renders cardholder name, card number, expiry, and CVC. - Submit the form only after
controller.hasEncryptedPayload()is true.
Environment script URLs
Use the matching script URL for each environment.
| Environment | Script URL |
|---|---|
| Test | https://test.payment.finbility.io/web/js/finbility-card.js |
| Production | https://payment.finbility.io/web/js/finbility-card.js |
https://test.payment.finbility.io with https://payment.finbility.io.
<script src="https://test.payment.finbility.io/web/js/finbility-card.js"></script>
<form id="credit_card_form" action="<YOUR_BACKEND_PAYMENT_ENDPOINT>" method="post" novalidate>
<div id="finbility-pay-card"></div>
<input type="hidden" name="cardholderName" id="finbility-pay-holder">
<input type="hidden" name="cardNumber" id="finbility-pay-card-number">
<input type="hidden" name="expirationMonth" id="finbility-pay-expiration-month">
<input type="hidden" name="expirationYear" id="finbility-pay-expiration-year">
<input type="hidden" name="cvNumber" id="finbility-pay-cv-number">
<button type="submit" id="js-pay-btn" disabled="disabled">Pay</button>
</form>
<script>
var controller = window.FinbilityPayCard.create({
locale: "en_US"
});
document.getElementById("credit_card_form").addEventListener("submit", function (event) {
event.preventDefault();
if (!controller || controller.isFailed()) {
return;
}
if (!controller.hasEncryptedPayload()) {
return;
}
this.submit();
});
</script>
Configuration and customization
Hidden inputs can be pre-rendered by the merchant form or created automatically by the component. Locale, theme, callbacks, and selectors can be customized without changing the integration model.
window.FinbilityPayCard.create({
locale: "en_US"
});
| Option | Type | Description |
|---|---|---|
locale |
string | Built-in locales: en_US and zh_CN. |
selectors |
object | Override mount, form, and submitButton. |
hiddenFields |
object | Override hidden field ids and names. Supported keys include holder, number, expiryMonth, expiryYear, and cvc. |
messages |
object | Override default field labels, placeholders, hints, and status copy. |
theme |
object | Override colors, radius, and text sizes without changing the integration model. |
cardOptions |
object | Pass supported Evervault card options such as field set or color scheme. |
onReady, onError, onChange, onStateChange |
function | Lifecycle callbacks for host page control and analytics. |
Example with custom selectors and hidden field ids
window.FinbilityPayCard.create({
locale: "zh_CN",
selectors: {
mount: "#custom-pay-card",
form: "#custom-form",
submitButton: "#submit-btn"
},
hiddenFields: {
holder: { id: "encryptedHolder", name: "cardholderName" },
number: { id: "encryptedCardNumber", name: "cardNumber" },
expiryMonth: { id: "encryptedMonth", name: "expirationMonth" },
expiryYear: { id: "encryptedYear", name: "expirationYear" },
cvc: { id: "encryptedCvc", name: "cvNumber" }
}
});
Browser expectations
finbility-card.jsis implemented in ES5 style for broad browser compatibility.- Target current versions of Chrome, Edge, Safari, and Firefox for merchant checkout pages.
- The script loads the Evervault browser SDK internally, so merchants only need to include one JS file.
Card payment: send the encrypted payload to the payment API
Your backend receives the form submission, maps the encrypted values to Finbility request fields, and calls /v1/paymentDirect with your OAuth access token. Wallet payments (Apple Pay, Google Pay) use /v1/paymentCollect instead.
Request headers
| Header | Required | Description |
|---|---|---|
Authorization |
Yes | Bearer <access_token> |
Accept |
Yes | application/json |
Content-Type |
Yes | application/json |
Core request fields
| Parameter | Required | Description |
|---|---|---|
channel_merchant_id | No | Unique ID assigned by the upstream provider |
order_id | Yes | Merchant order number, unique per payment attempt. |
payment_method | Yes | Payment method code, for example FINBI. |
amount | Yes | Transaction amount with two decimals. |
currency | Yes | ISO currency code, for example USD or EUR. |
request_type | Yes | Request source, for example WEB, WAP, or SDK. |
description | Yes | Order description. Avoid /, =, and &. |
return_url | Yes | Redirect URL after payment completion. |
notify_url | Yes | Webhook URL for payment result notifications. |
website | Yes | Merchant website URL. |
cardholder | Yes | Cardholder name. |
cardnum | Yes | Encrypted card number from cardNumber. |
cardmonth | Yes | Card expiry month, two digits, for example 12. |
cardyear | Yes | Card expiry year, four digits, for example 2027. |
cardcvv | Yes | Encrypted security code from cvNumber. |
source | Yes | Customer object described below. |
expirationMonth and expirationYear from the form to cardmonth and cardyear.
Customer source fields
| Parameter | Required | Description |
|---|---|---|
client_ip | Yes | Customer IP address. |
first_name | Yes | Customer first name. |
middle_name | No | Customer middle name. |
last_name | Yes | Customer last name. |
country | Yes | ISO country code, for example US or CN. |
state | Conditional | Required for US and CA card payments. |
city | Yes | City name. |
zip | Conditional | Required for US and CA card payments. |
email | Yes | Customer email address. |
address1 | Yes | Primary address line. |
address2 | No | Secondary address line. |
phone | Yes | Phone number. |
cpf | No | Brazilian tax ID when required by method or region. |
{
"return_url": "https://merchant.example/return",
"notify_url": "https://merchant.example/notify",
"payment_method": "FINBI_3D",
"request_type": "WEB",
"order_id": "100096247512",
"amount": "1.00",
"currency": "USD",
"description": "Product Title",
"website": "https://merchant.example",
"cardnum": "ev:encrypted:card-number",
"cardmonth": "09",
"cardyear": "2026",
"cardcvv": "ev:encrypted:cvc",
"cardholder": "Chris Ma",
"source": {
"first_name": "Chris",
"middle_name": "",
"last_name": "Ma",
"country": "US",
"state": "CA",
"city": "Los Angeles",
"zip": "90001",
"email": "test@example.com",
"phone": "1-555-0100",
"address1": "100 Main Street",
"address2": "Suite 18",
"client_ip": "203.0.113.10",
"cpf": ""
}
}
3DS browser header
BrowserInfo: {"acceptHeader":"application/json","language":"en","userAgent":"Mozilla/5.0","javaEnabled":"true","colorDepth":"24","screenHeight":"1080","screenWidth":"1920","timeZoneOffset":"-480"}
/v1/paymentDirect. Apple Pay and Google Pay must use /v1/paymentCollect instead. See the wallet section below.
Apple Pay and Google Pay
Apple Pay and Google Pay are server-side collect flows. Your backend calls /v1/paymentCollect with the wallet payment method code, then redirects the customer to the pay_url returned in the API response. The customer completes payment in the Apple Pay or Google Pay wallet UI; Finbility notifies your notify_url and redirects to return_url when finished.
These methods do not use finbility-card.js and do not accept card fields. Request parameters match the card payment API except for the endpoint, payment_method, and the absence of card-related fields.
Payment method codes
payment_method |
Method | Endpoint |
|---|---|---|
FINBI_AP | Apple Pay | POST /v1/paymentCollect |
FINBI_GP | Google Pay |
Integration flow
- Obtain an OAuth access token (same as other backend APIs).
- POST order and customer details to
/v1/paymentCollectwithFINBI_APorFINBI_GP. - Read
pay_urlfrom the response and redirect the customer (HTTP 302 or client-sidewindow.location). - The customer authorizes payment in Apple Pay or Google Pay.
- Receive the final result on
notify_urland reconcile withGET /v1/payment/{payment_id}if needed.
Request headers
| Header | Required | Description |
|---|---|---|
Authorization | Yes | Bearer <access_token> |
Accept | Yes | application/json |
Content-Type | Yes | application/json |
Core request fields
Same fields as the card payment API, except card fields and the 3DS BrowserInfo header are not used.
| Parameter | Required | Description |
|---|---|---|
channel_merchant_id | No | Unique ID assigned by the upstream provider. |
order_id | Yes | Merchant order number, unique per payment attempt. |
payment_method | Yes | FINBI_AP for Apple Pay or FINBI_GP for Google Pay. |
amount | Yes | Transaction amount with two decimals. |
currency | Yes | ISO currency code, for example USD or EUR. |
request_type | Yes | Request source, for example WEB, WAP, or SDK. |
description | Yes | Order description. Avoid /, =, and &. |
return_url | Yes | Redirect URL after payment completion. |
notify_url | Yes | Webhook URL for payment result notifications. |
website | Yes | Merchant website URL. |
source | Yes | Customer object (same structure as card payments). |
cardholder, cardnum, cardmonth, cardyear, or cardcvv for wallet payments. Calling /v1/paymentDirect with FINBI_AP or FINBI_GP is rejected by the API.
Example: Apple Pay
{
"return_url": "https://merchant.example/return",
"notify_url": "https://merchant.example/notify",
"payment_method": "FINBI_AP",
"request_type": "WEB",
"order_id": "100096247513",
"amount": "1.00",
"currency": "USD",
"description": "Product Title",
"website": "https://merchant.example",
"source": {
"first_name": "Chris",
"middle_name": "",
"last_name": "Ma",
"country": "US",
"state": "CA",
"city": "Los Angeles",
"zip": "90001",
"email": "test@example.com",
"phone": "1-555-0100",
"address1": "100 Main Street",
"address2": "Suite 18",
"client_ip": "203.0.113.10"
}
}
Example: Google Pay
{
"return_url": "https://merchant.example/return",
"notify_url": "https://merchant.example/notify",
"payment_method": "FINBI_GP",
"request_type": "WEB",
"order_id": "100096247514",
"amount": "1.00",
"currency": "EUR",
"description": "Product Title",
"website": "https://merchant.example",
"source": {
"first_name": "Chris",
"last_name": "Ma",
"country": "DE",
"city": "Berlin",
"zip": "10115",
"email": "test@example.com",
"phone": "+49-30-1234567",
"address1": "Example Street 1",
"client_ip": "203.0.113.10"
}
}
Redirect after create payment
When the payment is created successfully and a wallet step is required, the response includes pay_url. Redirect the customer to that URL to enter the Apple Pay or Google Pay flow. Query and webhook behavior are the same as for card payments.
{
"payment_id": "65df5a6791a211e583461c6f65f84b6d",
"transaction_id": "72c17f2d91a211e583461c6f65f84b6d",
"payment_method": "FINBI_AP",
"status": "PENDING",
"pay_url": "https://...",
"order_id": "100096247513",
"amount": "1.00",
"currency": "USD"
}
window.location.href = response.pay_url (web) or an HTTP 302 from your server. After authorization, the wallet provider returns the customer to your return_url and posts the result to notify_url.
Response and query flow
The create-payment response and the payment query response share the same core structure.
| Field | Description |
|---|---|
payment_id | Finbility payment identifier. |
transaction_id | Platform transaction identifier. |
status | Current payment status. |
error_code | Error code when a payment does not succeed. |
remarks | Human-readable failure reason. |
pay_url | Redirect URL when the method requires an external step. For FINBI_AP and FINBI_GP, redirect the customer here to complete Apple Pay or Google Pay. |
{
"payment_id": "65df5a6791a211e583461c6f65f84b6d",
"transaction_id": "72c17f2d91a211e583461c6f65f84b6d",
"create_time": "2015-07-07T08:05:38Z",
"update_time": "2015-07-07T08:05:38Z",
"payment_method": "FINBI",
"status": "SUCCESS",
"error_code": "",
"remarks": "",
"order_id": "100096247512",
"description": "Product Title",
"amount": "1.00",
"currency": "USD",
"request_type": "WEB",
"pay_url": "https://..."
}
Payment result notification
Finbility sends a POST request to your notify_url when the payment result is available.
| Field | Description |
|---|---|
transaction_id | Platform transaction identifier. |
order_id | Merchant order number. |
payment_id | Finbility payment identifier. |
payment_method | Payment method code. |
error_message | Failure reason, empty on success. |
status | Current transaction status. |
{
"transaction_id": "72c17f2d91a211e583461c6f65f84b6d",
"order_id": "100096247512",
"payment_id": "65df5a6791a211e583461c6f65f84b6d",
"payment_method": "FINBI_3D",
"error_message": "",
"status": "SUCCESS"
}
Refund by order id
| Header | Required | Description |
|---|---|---|
Authorization | Yes | Bearer <access_token> |
Accept | Yes | application/json |
Content-Type | Yes | application/json |
Refund request body
| Parameter | Required | Description |
|---|---|---|
amount | Yes | Refund amount. |
currency | Yes | Currency code. |
refund_order_id | Yes | Merchant refund order number, unique per refund. |
description | No | Optional refund description. |
{
"amount": "1.00",
"currency": "USD",
"refund_order_id": "R20260414001",
"description": "Customer requested refund"
}
Refund query
The response returns the refund identifier, status, amount, currency, timestamps, and any failure reason.
Test cards
Use the following values in the test environment (https://test.openapi.finbility.io). Do not use them in production.
Pure API integration (encrypted payloads)
For backend-only testing with POST /v1/paymentDirect, send the pre-encrypted sandbox values below. Map them to cardnum and cardcvv; set cardmonth to 12 and cardyear to 2027.
| API field | Test value |
|---|---|
cardnum |
ev:QkTC:uFPwr6En2GjHgYsG:AmxayDxmzMrpYZrFEws9oXFpoZ2/zZ8U/JqPK//KHs1D:2ji+ErydhhW/CPlDPQDmYAsHkOrTaJI5sNfGCTYjupgeVMPQ0zsTlOUppQ8bcAs:$ |
cardcvv |
ev:QkTC:5zat9SYrUnXlQogT:AmxayDxmzMrpYZrFEws9oXFpoZ2/zZ8U/JqPK//KHs1D:ix/L7iCeAxYk5xaV7lwpxRXAZgGbq7ge3RX8DfV6p0tffQ:$ |
cardmonth |
12 |
cardyear |
2027 |
Checkout UI integration (plain text)
For testing with finbility-card.js on the hosted checkout page or the demo page, enter these values in the secure card form. The component encrypts card number and CVC before submit.
| Field | Test value |
|---|---|
| Card number | 4149011500000147 |
| CVC | 123 |
| Expiry | 12/27 (1227 in MMYY) |
Status and error handling
Typical payment statuses
- SUCCESS: payment completed.
- FAILED: payment could not be completed.
- PROCESSING: payment is still being processed.
- PENDING: payment is waiting for a downstream step or confirmation (e.g. before wallet redirect).
Wallet payment methods
FINBI_AP— Apple Pay (POST /v1/paymentCollect)FINBI_GP— Google Pay (POST /v1/paymentCollect)
Integration checks
- Ensure the checkout page is served over HTTPS.
- Do not submit until the card controller reports an encrypted payload.
- For wallet payments, redirect to
pay_urlafter create payment. - Log webhook callbacks and reconcile them with payment query results.
- Handle token expiry and OAuth refresh on the backend.