Finbility Payment
Developer Documentation

Accept card payments with one frontend script and a standard backend API.

finbility-card.js is the merchant-side entry point. It renders the secure card UI, loads Evervault automatically, encrypts sensitive fields in the browser, and writes the result back to your form for submission.

Overview

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/paymentCollect API only; redirect the customer to pay_url to 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

Sandbox: https://test.openapi.finbility.io
Production: https://openapi.finbility.io
OAuth 2.0

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.
Keep API credentials on the server side only. Do not expose clientSecret in browser code, public pages, or mobile app bundles.

Get an access token before calling backend APIs

POST /v1/oauth/token?grant_type=client_credentials&scope=write,read
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"
}
Use the returned token as Authorization: Bearer <access_token> when calling payment and refund APIs.
Frontend

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.
Real checkout pages only need one script tag and one mount div to get started. Hidden inputs are optional from the component perspective, but keeping them in markup is still a good way to make the submit payload easy to understand.
Quick Start

Minimal integration

  1. Include finbility-card.js on the checkout page.
  2. Add a form with a single mount container and a submit button.
  3. Initialize FinbilityPayCard. The secure component renders cardholder name, card number, expiry, and CVC.
  4. 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
Usage: Use the test URL for integration and QA. For production, replace 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>
The component injects its own title, top helper text, secure card shell, loading state, and bottom error area. Merchants only need to provide the mount container.
Configuration

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.js is 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.
Backend

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.

POST /v1/paymentDirect

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_idNoUnique ID assigned by the upstream provider
order_idYesMerchant order number, unique per payment attempt.
payment_methodYesPayment method code, for example FINBI.
amountYesTransaction amount with two decimals.
currencyYesISO currency code, for example USD or EUR.
request_typeYesRequest source, for example WEB, WAP, or SDK.
descriptionYesOrder description. Avoid /, =, and &.
return_urlYesRedirect URL after payment completion.
notify_urlYesWebhook URL for payment result notifications.
websiteYesMerchant website URL.
cardholderYesCardholder name.
cardnumYesEncrypted card number from cardNumber.
cardmonthYesCard expiry month, two digits, for example 12.
cardyearYesCard expiry year, four digits, for example 2027.
cardcvvYesEncrypted security code from cvNumber.
sourceYesCustomer object described below.
Only card number and CVC are encrypted by the frontend component. Expiry month and year remain plain text; map expirationMonth and expirationYear from the form to cardmonth and cardyear.

Customer source fields

Parameter Required Description
client_ipYesCustomer IP address.
first_nameYesCustomer first name.
middle_nameNoCustomer middle name.
last_nameYesCustomer last name.
countryYesISO country code, for example US or CN.
stateConditionalRequired for US and CA card payments.
cityYesCity name.
zipConditionalRequired for US and CA card payments.
emailYesCustomer email address.
address1YesPrimary address line.
address2NoSecondary address line.
phoneYesPhone number.
cpfNoBrazilian 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"}
Card payments use /v1/paymentDirect. Apple Pay and Google Pay must use /v1/paymentCollect instead. See the wallet section below.
Wallet Payments

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_APApple PayPOST /v1/paymentCollect
FINBI_GPGoogle Pay

Integration flow

  1. Obtain an OAuth access token (same as other backend APIs).
  2. POST order and customer details to /v1/paymentCollect with FINBI_AP or FINBI_GP.
  3. Read pay_url from the response and redirect the customer (HTTP 302 or client-side window.location).
  4. The customer authorizes payment in Apple Pay or Google Pay.
  5. Receive the final result on notify_url and reconcile with GET /v1/payment/{payment_id} if needed.
POST /v1/paymentCollect

Request headers

Header Required Description
AuthorizationYesBearer <access_token>
AcceptYesapplication/json
Content-TypeYesapplication/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_idNoUnique ID assigned by the upstream provider.
order_idYesMerchant order number, unique per payment attempt.
payment_methodYesFINBI_AP for Apple Pay or FINBI_GP for Google Pay.
amountYesTransaction amount with two decimals.
currencyYesISO currency code, for example USD or EUR.
request_typeYesRequest source, for example WEB, WAP, or SDK.
descriptionYesOrder description. Avoid /, =, and &.
return_urlYesRedirect URL after payment completion.
notify_urlYesWebhook URL for payment result notifications.
websiteYesMerchant website URL.
sourceYesCustomer object (same structure as card payments).
Do not send 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"
}
Merchant redirect: 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.
Payment Response

Response and query flow

The create-payment response and the payment query response share the same core structure.

GET /v1/payment/{payment_id}
Field Description
payment_idFinbility payment identifier.
transaction_idPlatform transaction identifier.
statusCurrent payment status.
error_codeError code when a payment does not succeed.
remarksHuman-readable failure reason.
pay_urlRedirect 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://..."
}
Webhook

Payment result notification

Finbility sends a POST request to your notify_url when the payment result is available.

Field Description
transaction_idPlatform transaction identifier.
order_idMerchant order number.
payment_idFinbility payment identifier.
payment_methodPayment method code.
error_messageFailure reason, empty on success.
statusCurrent transaction status.
{
  "transaction_id": "72c17f2d91a211e583461c6f65f84b6d",
  "order_id": "100096247512",
  "payment_id": "65df5a6791a211e583461c6f65f84b6d",
  "payment_method": "FINBI_3D",
  "error_message": "",
  "status": "SUCCESS"
}
Refund

Refund by order id

POST /v1/refund/{order_id}
Header Required Description
AuthorizationYesBearer <access_token>
AcceptYesapplication/json
Content-TypeYesapplication/json

Refund request body

Parameter Required Description
amountYesRefund amount.
currencyYesCurrency code.
refund_order_idYesMerchant refund order number, unique per refund.
descriptionNoOptional refund description.
{
  "amount": "1.00",
  "currency": "USD",
  "refund_order_id": "R20260414001",
  "description": "Customer requested refund"
}

Refund query

GET /v1/refund/{refund_id}

The response returns the refund identifier, status, amount, currency, timestamps, and any failure reason.

Sandbox

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)
Encrypted payloads from the checkout UI are environment-specific. Use the plain-text values above for frontend testing, and the pre-encrypted values above for direct API calls without the card component.
Reference

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_url after create payment.
  • Log webhook callbacks and reconcile them with payment query results.
  • Handle token expiry and OAuth refresh on the backend.
If the card component enters an error state, block payment submission and surface a retry path. The built-in UI already exposes service-unavailable copy and a refresh action; the host page should respect that state instead of forcing form submission.