Skip to main content

Cybersource Microform

Cybersource Microform is Cybersource's embedded, PCI-compliant card-entry widget. It renders card fields inside iframes on your checkout page — card details never touch your servers.

Centra's Cybersource plugin uses the Flex Microform v2 API and handles:

  • Generating a Capture Context JWT that authorizes Microform to render on your domain.
  • Payment authorization with direct capture — authorization and capture in one step (no separate capture request).
  • 3D Secure 2.0 payer authentication setup, device fingerprinting orchestration, enrollment check, and challenge flow.
  • JWS/MLE mutual authentication for enhanced API-level security (optional, requires activation on your Cybersource account).

The frontend partner implements:

  • Loading and rendering Cybersource Microform using the Capture Context.
  • Collecting card data and obtaining a Transient Token JWT via Microform.
  • Driving 3DS device fingerprinting and the optional challenge window.

Supported APIs: Cybersource Microform works with the Storefront API and the Checkout API (Legacy).

Plugin configuration (Centra admin)

Required credentials

Merchant ID

Your Cybersource merchant account identifier, found in the Business Center.

API Key

The key ID of your Cybersource REST API credentials. Generate this in the Business Center under Payment Configuration → Key Management → Generate Key → REST Shared Secret.

API Shared Secret

The shared secret paired with the API Key above. Centra uses it to sign all requests via HMAC-SHA256 HTTP Signature authentication. Keep it secret — treat it like a password.

Target origins

Comma-separated list of HTTPS origins (scheme + host + optional port — no trailing path, query string, or fragment) where Cybersource Microform will be embedded.

Examples:

https://checkout.example.com,https://www.example.com

Exceptions allowed for local development: http://localhost, http://127.0.0.1.

Valid originsInvalid origins
https://checkout.example.comhttps://checkout.example.com/payment
http://localhosthttps://checkout.example.com?ref=1
http://localhost:8080https://shop.brand.com#step2
https://shop.brand.com

Cybersource Microform refuses to initialize on an origin that is not in this list, so ensure every checkout domain (including staging environments) is listed.

Allowed card networks

Select the card brands that Microform will accept. Attempting to enter a card from an unlisted network will fail at the Microform level before submission.

ValueLabel
VISAVisa
MASTERCARDMastercard
AMEXAmerican Express
DINERSCLUBDiners Club
DISCOVERDiscover
JCBJCB
MAESTROMaestro
CUPChina UnionPay
CARTESBANCAIRESCartes Bancaires
ELOElo
MADAMada
MEEZAMeeza
UATPUATP
CARNETCarnet
EFTPOSEFTPOS
JAYWANJaywan
JCREWJ.Crew
KCPKCP
PAYPAKPayPak

Test mode

Set to Yes to use Cybersource's sandbox environment. Set to No for production.

In test mode, Centra uses the sandbox Capture Context endpoint and Microform loads from https://testflex.cybersource.com. In production, requests go to https://api.cybersource.com and Microform loads from https://flex.cybersource.com.

3D-Secure settings

Payer authentication (3D-Secure) enabled

  • Yes (default) — Centra runs the full 3DS 2.0 flow: payer authentication setup → device fingerprinting → enrollment check. Depending on the issuer's response, the flow is either frictionless (no user interaction) or requires a challenge window.
  • No — Centra skips 3DS and goes straight to authorization. Only use this when you have a specific agreement with Cybersource and your acquirer, or when you are testing other parts of the integration and don't want to be distracted by the additional payer authentication steps.

Ignore AVS result

When Yes, Centra instructs Cybersource to proceed with capture even if the address verification (AVS) check returns a decline. Defaults to No.

Useful for merchants who accept international cards where AVS matching rates are low, but only enable this after confirming the risk profile with your acquirer.

Authentication method

Centra supports two API authentication methods for communicating with Cybersource:

MethodDescription
HTTP Signature (default)HMAC-SHA256 signing of request headers using your API Key and Shared Secret. No additional setup required beyond the credentials above.
JWS/MLEJSON Web Signature (request body signing) combined with Message-Level Encryption (request payload encryption with Cybersource's public key; response decryption with your private key). Requires separate key pairs and activation on the Cybersource side.

Switch to JWS/MLE only when Cybersource requires it for your account or when your security requirements mandate payload-level encryption in transit.

JWS/MLE key configuration

When JWS/MLE is selected as the authentication method, three key pairs must be configured in the plugin:

FieldDescription
MLE Encryption Key IDKey serial number (KSN) of the Cybersource-provided public certificate used to encrypt request payloads sent to Cybersource. Obtain this from your Business Center under Key Management.
MLE Encryption Key ContentsPEM-encoded public key. Paste the entire block, including -----BEGIN PUBLIC KEY----- and -----END PUBLIC KEY-----.
MLE Decryption Key IDKey ID of your private key that Cybersource uses to address encrypted responses to you.
MLE Decryption Key ContentsFull PEM-encoded RSA private key used to decrypt Cybersource's encrypted API responses. Paste the entire block including -----BEGIN PRIVATE KEY----- and -----END PRIVATE KEY-----.
JWS Signature Key IDKey ID of your private key used to sign request bodies with JWS.
JWS Signature Key ContentsFull PEM-encoded private key used for JWS signing.
Key ID and contents are not cross-validated

Centra only checks that each key ID is non-empty and that each key contents block is a valid PEM (public or private key). It does not verify that the key ID matches the provided key material — a mismatch will not be caught on save and will cause Cybersource to reject requests at runtime.

Key rotation

When you rotate MLE or JWS keys in the Cybersource Business Center:

  1. In the Business Center, generate or obtain the new key pair (Payment Configuration → Key Management). Note the new key ID.
  2. In the Centra admin, open the Cybersource plugin.
  3. Update both the key ID field and the key contents field for each key you are rotating. Always update both together — updating only one of them will not be caught on save, but will cause Cybersource to reject all subsequent payment requests.
  4. Save the plugin. Centra begins using the new keys immediately for all subsequent requests.
Zero-downtime rotation

Cybersource supports an overlapping validity window for MLE certificates — the old and new certificates are both accepted by Cybersource during the transition period. Schedule the Centra plugin update during this overlap to avoid declined payments.

For JWS signing keys, verify with Cybersource whether an overlap window applies to your account. If not, coordinate the Centra plugin update as close to the Cybersource-side key activation time as possible.

Restrictions

The plugin supports standard Centra payment restrictions: by market, pricelist, country, and language. These work identically to all other Centra payment plugins.

Flow

Centra's Cybersource integration always uses direct capture — authorization and capture happen in a single Cybersource API call. There is no separate capture step.

Standard authorization (3D-Secure disabled or bypassed)

This path applies when payer_authentication_enabled is No, or when threeDSecurePreference: standard-authorization is passed in the payment submission request.

CybersourceCentraBrowserCybersourceCentraBrowserpaymentInstructions1Create Capture Context2captureContext JWT3action: form, formFields.captureContext4Load Microform with captureContext5Shopper enters card data6microform.createToken()7transientToken JWT8paymentSubmission (captureContext, transientToken)9Process payment (authorize + capture)10Payment authorized11Order placed12

3D-Secure — frictionless flow

The frictionless path occurs when the card issuer authenticates the transaction without requiring an interactive challenge from the shopper (typically low-risk transactions with sufficient device fingerprint data).

IssuerCybersourceCentraBrowserIssuerCybersourceCentraBrowserpaymentInstructions1Create Capture Context2captureContext JWT3action: form, formFields.captureContext4Load Microform, shopper enters card data5microform.createToken()6transientToken JWT7paymentSubmission [1st call] (captureContext, transientToken)8Payer Authentication Setup9deviceDataCollectionUrl, referenceId, accessToken, token10action: javascript, formFields.payerAuthentication11Load device fingerprint iframe (deviceDataCollectionUrl + token)12Device fingerprint data posted (hidden iframe)13Fingerprint complete event (message)14paymentSubmission [2nd call] (captureContext, transientToken, payerAuthentication.referenceId, deviceInformation)15Check Enrollment163DS enrollment check17Authenticated — no challenge required (frictionless)18Frictionless authentication result19Process payment (authorize + capture with 3DS data)20Payment authorized21Order placed22

3D-Secure — challenge flow

The challenge path occurs when the issuer requires the shopper to complete an interactive step-up authentication (e.g., OTP, biometric, or bank app).

IssuerCybersourceCentraBrowserIssuerCybersourceCentraBrowserpaymentInstructions1Create Capture Context2captureContext JWT3action: form, formFields.captureContext4Load Microform, shopper enters card data5microform.createToken()6transientToken JWT7paymentSubmission [1st call] (captureContext, transientToken)8Payer Authentication Setup9deviceDataCollectionUrl, referenceId, accessToken, token10action: javascript, formFields.payerAuthentication11Load device fingerprint iframe12Device fingerprint data posted (hidden iframe)13Fingerprint complete event14paymentSubmission [2nd call] (captureContext, transientToken, payerAuthentication.referenceId, deviceInformation)15Check Enrollment163DS enrollment check17Challenge required18stepUpUrl, stepUpAccessToken, authenticationTransactionId19action: javascript, formFields (stepUpUrl, stepUpAccessToken, authenticationTransactionId)20Open challenge iframe (POST to stepUpUrl with stepUpAccessToken)21Render challenge UI (OTP, biometric, etc.)22Shopper completes challenge23Challenge complete event (message)24paymentResult (authenticationTransactionId, captureContext, transientToken)25Process payment (authorize + capture with 3DS auth data)26Payment authorized27Order placed28

Frontend implementation

Step 1 — Payment instructions

Call paymentInstructions to receive the Capture Context JWT. The Capture Context is a short-lived signed token that authorizes Microform to initialize on your domain and collect card data.

Storefront API:

mutation paymentInstructions($input: PaymentInstructionsInput!) {
paymentInstructions(input: $input) {
action {
__typename
... on FormPaymentAction {
formType
formFields
}
}
userErrors {
message
path
}
}
}

Validate the action shape before proceeding:

const action = response.paymentInstructions?.action;

if (
action?.__typename !== 'FormPaymentAction' ||
action.formType !== 'cybersource'
) {
// Unsupported response — surface an error or fallback
return;
}

const { captureContext } = action.formFields;

Step 2 — Load Cybersource Microform

Load the Microform script and initialize it with the Capture Context.

ModeMicroform script URL
Test (sandbox)https://testflex.cybersource.com/microform/bundle/v2/flex-microform.min.js
Productionhttps://flex.cybersource.com/microform/bundle/v2/flex-microform.min.js

The captureContext JWT tells Microform which card networks are allowed and verifies that it is rendering on an authorized target origin. Microform will refuse to initialize if the current page origin is not listed in the Centra plugin's Target origins field.

// After loading the Microform script
const flex = new Flex(captureContext);
const microform = flex.microform();

const cardNumber = microform.createField('number', { placeholder: 'Card number' });
const securityCode = microform.createField('securityCode', { placeholder: 'CVV' });

cardNumber.load('#card-number-container');
securityCode.load('#security-code-container');

load() replaces the element at the given ID with a Cybersource-hosted iframe. These two fields are the only ones rendered by Microform — expiration month and year are regular form inputs you collect separately and pass to createToken(). Your page never has direct access to raw card data entered into the iframes.

Microform provides built-in client-side behaviour: it detects the card type as the number is entered, auto-formats the number with spaces based on the detected card type, and adjusts the expected CVV length accordingly.

Step 3 — Obtain a transient token

When the shopper submits the payment form, call microform.createToken() to tokenize the entered card data. The resulting Transient Token JWT represents the card for one-time use in authorization.

const options = {
expirationMonth: '12', // from your expiry month input
expirationYear: '2030', // from your expiry year input
};

microform.createToken(options, (error, transientToken) => {
if (error) {
// Validation errors (e.g. invalid card number) or network error
console.error(error);
return;
}
// Proceed to payment submission with both captureContext and transientToken
submitPayment(captureContext, transientToken);
});

Step 4 — Payment submission (first call)

Call paymentSubmission with both JWTs. At this point, Centra either:

  • Proceeds to standard authorization (if 3DS is disabled or standard-authorization is requested).
  • Returns 3DS setup data for device fingerprinting (if 3DS is enabled).

Required fields (paymentMethodSpecificFields):

FieldTypeDescription
captureContextstring (JWT)The JWT received from paymentInstructions.
transientTokenstring (JWT)The JWT received from microform.createToken().

Optional fields:

FieldTypeDescription
threeDSecurePreferencestringOne of: standard-authorization, frictionless, challenge. Omit to use the plugin default (3DS if enabled).
warning
threeDSecurePreference requires a server-to-server call

Because this field influences the security level of the transaction, Centra only accepts it when the request is authenticated with the shared secret. A call from the browser without shared secret authentication will be rejected with HTTP 400 if this field is present.

Checkout API example:

{
"paymentMethodSpecificFields": {
"captureContext": "<captureContext JWT>",
"transientToken": "<transientToken JWT>"
}
}

threeDSecurePreference values:

ValueEffect
standard-authorizationSkip 3DS for this payment regardless of plugin setting.
frictionlessRequest frictionless 3DS from the issuer (issuer may still challenge).
challengeExplicitly request a challenge from the issuer.

Step 5 — Handle 3DS setup response

When 3DS is active and no payerAuthentication was in the request, Centra responds with action: javascript and the following formFields:

{
"captureContext": "<captureContext JWT>",
"transientToken": "<transientToken JWT>",
"payerAuthentication": {
"accessToken": "<JWT — POST this to the DDC iframe as field 'JWT'>",
"deviceDataCollectionUrl": "<Cardinal Commerce DDC endpoint — use this value as-is>",
"referenceId": "<UUID — pass back in the enrollment check>"
}
}

Always use deviceDataCollectionUrl exactly as returned by Centra — do not hardcode or reconstruct it. Cybersource provides different endpoints for sandbox (centinelapistag.cardinalcommerce.com) and production (centinelapi.cardinalcommerce.com), and the URL may change without notice.

Store captureContext, transientToken, and payerAuthentication.referenceId — all three are needed for the enrollment check call.

Step 6 — Device fingerprinting

Perform device fingerprinting by posting to deviceDataCollectionUrl inside a hidden iframe. This collects browser and device signals that the issuer uses for risk assessment.

<!-- Hidden iframe for device data collection -->
<iframe
id="ddc-iframe"
name="ddc-iframe"
style="display:none;"
height="1"
width="1"
></iframe>

<!-- Form targeting the hidden iframe -->
<form
id="ddc-form"
target="ddc-iframe"
method="POST"
action="{deviceDataCollectionUrl}"
>
<input type="hidden" name="JWT" value="{payerAuthentication.accessToken}" />
</form>
// Listen for completion before submitting enrollment check
window.addEventListener('message', (event) => {
let data;
try {
data = JSON.parse(event.data);
} catch {
return;
}

if (data.MessageType === 'profile.completed') {
// Device fingerprinting is done — proceed to enrollment check
checkEnrollment();
}
});

document.getElementById('ddc-form').submit();
Origin check

Verify event.origin matches the origin of deviceDataCollectionUrl before trusting the message content.

While waiting for the fingerprinting event, collect the device information fields that are required for the enrollment check:

const deviceInformation = {
ipAddress: '<shopper IP — collect server-side>',
httpAcceptBrowserValue: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
httpAcceptContent: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
httpBrowserLanguage: navigator.language,
httpBrowserJavaEnabled: navigator.javaEnabled?.() ?? false,
httpBrowserJavaScriptEnabled: true,
httpBrowserColorDepth: String(screen.colorDepth),
httpBrowserScreenHeight: String(screen.height),
httpBrowserScreenWidth: String(screen.width),
httpBrowserTimeDifference: new Date().getTimezoneOffset().toString(),
userAgentBrowserValue: navigator.userAgent,
};

The shopper's IP address must be collected server-side (from the HTTP request headers) and passed to the client, or fetched via a dedicated endpoint — JavaScript in the browser cannot reliably read the true client IP.

Step 7 — Enrollment check (second paymentSubmission call)

Once device fingerprinting is complete, call paymentSubmission a second time with the payerAuthentication object:

{
"paymentMethodSpecificFields": {
"captureContext": "<captureContext JWT>",
"transientToken": "<transientToken JWT>",
"payerAuthentication": {
"referenceId": "<referenceId from 3DS setup response>",
"deviceInformation": {
"ipAddress": "203.0.113.42",
"httpAcceptBrowserValue": "text/html,application/xhtml+xml,*/*;q=0.8",
"httpAcceptContent": "text/html,application/xhtml+xml,*/*;q=0.8",
"httpBrowserLanguage": "en-US",
"httpBrowserJavaEnabled": false,
"httpBrowserJavaScriptEnabled": true,
"httpBrowserColorDepth": "24",
"httpBrowserScreenHeight": "1080",
"httpBrowserScreenWidth": "1920",
"httpBrowserTimeDifference": "-60",
"userAgentBrowserValue": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) ..."
}
}
}
}

All deviceInformation fields are required. Missing fields cause a validation error.

Step 8 — Handle enrollment check response

Three outcomes are possible:

Outcome A — Frictionless (order placed immediately)

Centra places the order directly without any browser interaction. The response is a standard Centra order confirmation. No additional steps needed.

Outcome B — Challenge required (action: javascript)

The issuer requires the shopper to complete a challenge. Centra returns:

{
"action": "javascript",
"formFields": {
"authenticationTransactionId": "<UUID>",
"stepUpUrl": "<Cardinal Commerce step-up endpoint — use this value as-is>",
"stepUpAccessToken": "<JWT>",
"paReq": "<base64 payer auth request>"
}
}

Always use stepUpUrl exactly as returned — do not hardcode the Cardinal endpoint. Cybersource provides different hosts for sandbox (centinelapistag.cardinalcommerce.com) and production (centinelapi.cardinalcommerce.com).

Open the challenge in an iframe:

<iframe
id="step-up-iframe"
style="width: 400px; height: 400px;"
></iframe>

The `paReq` field is a base64-encoded JSON payload. Decoded, it contains a `challengeWindowSize` value that indicates the issuer's preferred iframe dimensions:

| `challengeWindowSize` | Width × Height |
|---|---|
| `01` | 250 × 400 |
| `02` | 390 × 400 |
| `03` | 500 × 600 |
| `04` | 600 × 400 |
| `05` | Full screen |

Use this value to size the iframe dynamically instead of hardcoding `400 × 400`.

<form
id="step-up-form"
target="step-up-iframe"
method="POST"
action="{stepUpUrl}"
>
<input type="hidden" name="JWT" value="{stepUpAccessToken}" />
</form>
// Store authenticationTransactionId for use in paymentResult
const { authenticationTransactionId } = formFields;

// Listen for challenge completion
window.addEventListener('message', (event) => {
let data;
try {
data = JSON.parse(event.data);
} catch {
return;
}

if (data.MessageType === 'customer.stepUpComplete') {
// Shopper completed the challenge — call paymentResult
completePayment(authenticationTransactionId, captureContext, transientToken);
}
});

document.getElementById('step-up-form').submit();

Outcome C — Authentication failed

Centra returns an error response (action: failed). Display the error to the shopper and allow them to retry or choose another payment method.

Step 9 — paymentResult (post-challenge only)

This step is only required after a 3DS challenge (Outcome B above). Call paymentResult to complete the authorization:

Storefront API:

mutation paymentResult($paymentMethodFields: Map!) {
paymentResult(paymentMethodFields: $paymentMethodFields) {
type
... on PaymentResultSuccessPayload {
order {
number
orderDate
status
totals {
type
price {
value
formattedValue
currency {
code
}
}
}
}
}
userErrors {
message
path
}
}
}

Variables:

{
"paymentMethodFields": {
"authenticationTransactionId": "<from challenge response formFields>",
"captureContext": "<captureContext JWT from paymentInstructions>",
"transientToken": "<transientToken JWT from Microform>"
}
}

All three fields are required. Missing any of them returns an error without attempting authorization.

What Centra returns (backend contract)

paymentInstructions — Capture Context

{
"action": "form",
"formType": "cybersource",
"formFields": {
"captureContext": "<short-lived JWT>"
}
}

Use captureContext to initialize Microform. Cybersource typically issues Capture Context JWTs with a 15-minute validity window — call paymentInstructions again if the shopper takes longer than that before submitting.

paymentSubmission — 3DS setup (action: javascript, first call)

Returned when 3DS is enabled and no payerAuthentication was present in the request:

{
"action": "javascript",
"formFields": {
"captureContext": "<captureContext JWT — echo from request>",
"transientToken": "<transientToken JWT — echo from request>",
"payerAuthentication": {
"accessToken": "<JWT — POST this to the DDC iframe as field 'JWT'>",
"deviceDataCollectionUrl": "<Cardinal Commerce DDC endpoint>",
"referenceId": "<UUID>"
}
}
}

The deviceDataCollectionUrl domain differs by environment:

EnvironmentDomain
Sandboxcentinelapistag.cardinalcommerce.com
Productioncentinelapi.cardinalcommerce.com

Always use the URL as returned by Centra — do not hardcode it.

paymentSubmission — challenge required (action: javascript, second call)

Returned when the enrollment check determines the issuer requires a challenge:

{
"action": "javascript",
"formFields": {
"authenticationTransactionId": "<UUID>",
"stepUpUrl": "<Cardinal Commerce step-up endpoint>",
"stepUpAccessToken": "<JWT — POST this to the step-up iframe as field 'JWT'>",
"paReq": "<base64 encoded payer auth request>"
}
}

The stepUpUrl domain follows the same sandbox/production split as deviceDataCollectionUrl above.

paymentResult — required fields

FieldSource
authenticationTransactionIdFrom challenge response formFields
captureContextThe JWT returned by paymentInstructions
transientTokenThe JWT generated by microform.createToken()

Testing

Enable test mode

Set Test mode to Yes in the Centra admin. All Cybersource API calls will go to https://apitest.cybersource.com and Microform will load from https://testflex.cybersource.com.

In your frontend, detect test mode from the deviceDataCollectionUrl or stepUpUrl origins returned in the API responses — the sandbox uses cardinalcommerce.com domains for both environments, so confirm test mode routing through the Cybersource API hostname in your backend logs.

Load Microform from the sandbox URL in test mode

https://testflex.cybersource.com/microform/bundle/v2/flex-microform.min.js

Test cards

Use Cybersource's official test cards. Commonly used numbers for general authorization testing:

Card numberNetworkExpected result
4111111111111111VisaSuccessful authorization
5555555555554444MastercardSuccessful authorization

For 3DS-specific test scenarios (frictionless, challenge, authentication failure), refer directly to the Cybersource Payer Authentication testing guide — 3DS test card numbers are environment-specific and subject to change between sandbox versions.

Validate all flows

  • Standard authorization — submit with threeDSecurePreference: standard-authorization and verify the order is placed in one round trip.
  • 3DS frictionless — complete device fingerprinting and verify the order is placed without a challenge window.
  • 3DS challenge — complete device fingerprinting, open the challenge iframe, complete the simulated challenge, and verify paymentResult places the order.
  • AVS decline handling — test with a card that triggers AVS decline; verify behavior with ignore_avs_result both on and off.
  • Authentication failure — verify the frontend surfaces the error message and allows retry.

See also