@rebornpay/checkout-3ds
v0.2.0
Published
Browser-side 3DS2 helpers for RebornPay card checkout (device collection, challenge, orchestration)
Maintainers
Readme
@rebornpay/checkout-3ds
Browser-side helpers for RebornPay 3DS2 card payments. Device fingerprint collection and the ACS challenge must run in the buyer's browser — never on your server.
Aligned with Core Services 3DS endpoints and normalized status codes (AUTHENTICATION_SUCCESSFUL, PENDING_CHALLENGE, AUTHENTICATION_FAILED).
Install
npm install @rebornpay/checkout-3dsCheckout session flow
For payment links / POST /v1/checkout-sessions:
import {
collectDeviceInformation,
buildThreeDsBilling,
runCheckoutThreeDs,
} from "@rebornpay/checkout-3ds";
const threeDs = await runCheckoutThreeDs(
sessionId,
{
slugToken: cardToken,
returnUrl: window.location.href,
deviceInformation: collectDeviceInformation(),
billing: buildThreeDsBilling({
fullName: "Maria Silva",
email: "[email protected]",
address1: "Rua Exemplo 123",
city: "São Paulo",
state: "SP",
postalCode: "01310100",
}),
},
{
setup: (id, token) =>
fetch(`/v1/checkout-sessions/${id}/threeds/setup`, {
method: "POST",
body: JSON.stringify({ slugToken: token }),
}).then((r) => r.json()),
authenticate: (id, input) =>
fetch(`/v1/checkout-sessions/${id}/threeds/authenticate?paymentMethod=CREDIT_CARD`, {
method: "POST",
body: JSON.stringify(input),
}).then((r) => r.json()),
challengeResult: (id, authenticationTransactionId) =>
fetch(`/v1/checkout-sessions/${id}/threeds/challenge-result`, {
method: "POST",
body: JSON.stringify({ authenticationTransactionId }),
}).then((r) => r.json()),
},
);
// Pass `threeDs` to POST /v1/checkout-sessions/{id}/confirmTransaction API flow (seller backend)
For direct card charges via POST /v1/transactions/threeds/* (stateless — caller keeps requestId / referenceId between steps):
import {
collectDeviceInformation,
buildThreeDsBilling,
runTransactionThreeDs,
} from "@rebornpay/checkout-3ds";
const threeDs = await runTransactionThreeDs(
{
card: { cardToken: "tok_abc" },
amount: 9990,
returnUrl: window.location.href,
deviceInformation: collectDeviceInformation(),
billing: buildThreeDsBilling({ /* ... */ }),
},
{
setup: (body) =>
fetch("/v1/transactions/threeds/setup", {
method: "POST",
headers: { "X-Api-Key": apiKey, "Content-Type": "application/json" },
body: JSON.stringify(body),
}).then((r) => r.json()),
authenticate: (body) =>
fetch("/v1/transactions/threeds/authenticate", {
method: "POST",
headers: { "X-Api-Key": apiKey, "Content-Type": "application/json" },
body: JSON.stringify(body),
}).then((r) => r.json()),
challengeResult: (body) =>
fetch("/v1/transactions/threeds/challenge-result", {
method: "POST",
headers: { "X-Api-Key": apiKey, "Content-Type": "application/json" },
body: JSON.stringify(body),
}).then((r) => r.json()),
},
);
// Pass `threeDs` to POST /v1/transactionsAuthenticate status codes
Core Services normalizes Dock responses before returning them to clients:
| code | Meaning |
|--------|---------|
| AUTHENTICATION_SUCCESSFUL | Frictionless — use xid, cavv, specificationVersion → confirm |
| PENDING_CHALLENGE | Open stepUpUrl, then call challenge-result |
| AUTHENTICATION_FAILED | Card not authenticated — do not charge |
Confirm payload
Both flows produce CheckoutThreeDsConfirmPayload for confirm/create transaction:
| Field | Source |
|-------|--------|
| xid, cavv, directoryServerTransactionId | authenticate (frictionless) or challenge-result |
| secureVersion | specificationVersion (frictionless) or secureVersion (challenge) |
| threeDsServerTransactionId | authenticationTransactionId (frictionless) or threeDsServerTransactionId (challenge) |
| cavvResultCode | Client-supplied (default "2" via DEFAULT_CAVV_RESULT_CODE) |
IP address
Never trust deviceInformation.ipAddress from the browser. Proxy threeds/authenticate through your BFF and overwrite the IP from x-forwarded-for / x-real-ip.
Docs
Full checkout flow: RebornPay API docs.
