Skip to main content

Revup Unified SDK 1.0

Reference release: 1.0.29 — the last patch of the 1.0 line. Status: maintained. New integrations should start on 1.3. Existing 1.0 integrations keep working; when you are ready to move, follow Migrating 1.0 → 1.1.

Everything on this page describes 1.0.x only. Options, events and behaviours introduced later are documented on their own version page — nothing here silently inherits from a newer release, and nothing here is superseded by a newer page.


Contents​

  1. What the SDK does
  2. Quick start
  3. Loading the SDK script
  4. The container
  5. RevupConfig — constructor
  6. RevupOptions — init()
  7. form — card form options
  8. apms — alternative payment methods
  9. userInfo — payer email
  10. Languages
  11. Event contract
  12. Cleanup and re-initialization
  13. Environments, URLs and CSP
  14. Known limits of the 1.0 line

1. What the SDK does​

RevUp is a single hosted script that renders a complete payment block inside one element of your checkout page. It orchestrates two things:

  • A credit / debit card form, hosted in a sandboxed iframe on RevUp's domain, so card data never touches your page.
  • Alternative payment methods (APMs) — Apple Pay, Google Pay, PayPal, Stripe Link and Amazon Pay — rendered as buttons above the card form, limited to the methods enabled for your merchant account.

The script exposes one global constructor, Revup, and reports everything that happens through one native DOM event, onRevupMessage.

In 1.0 the layout is a single stack: APM buttons first, then the card form (or a "pay with card" entry point when the form starts collapsed). There are no payment zones and no accordion — those arrive in 1.1.


2. Quick start​

<div id="revup-container"></div>

<script
type="text/javascript"
charset="utf-8"
src="https://test.hosted.revuppayments.com/payments-widget/sdk/1/0/loader.js"
crossorigin="anonymous"
integrity="sha512-…">
</script>
window.addEventListener('onRevupSDKLoaded', async () => {
const revup = new Revup({
merchantDomain: window.location.host,
apiKey: 'YOUR_PUBLIC_API_KEY',
orderId: 'ORDER_ID_FROM_YOUR_BACKEND',
});

const stopListening = revup.onRevupMessage((event) => {
console.log(event.type, event);
});

await revup.init({
containerId: 'revup-container',
language: 'en-US',
form: { collapsed: false, showZipCode: true },
apms: { enabled: ['apple_pay', 'google_pay', 'paypal'] },
});
});

Order of operations that must be respected:

  1. Create the order on your backend and get its orderId.
  2. Load the script and wait for onRevupSDKLoaded.
  3. Make sure the container element exists in the DOM.
  4. new Revup(config) → attach your onRevupMessage listener → await revup.init(options).

init() is asynchronous. It resolves once the layout is built, the APM modules have been initialized and the card form iframe has been requested.


3. Loading the SDK script​

The SDK is delivered by a small loader script. The loader is what you reference in your page; it resolves and fetches the actual bundle at runtime.

The loader URL​

https://<host>/payments-widget/sdk/<major>/<minor>/loader.js
EnvironmentLoader URL (1.0 line)
Sandboxhttps://test.hosted.revuppayments.com/payments-widget/sdk/1/0/loader.js
Livehttps://hosted.revuppayments.com/payments-widget/sdk/1/0/loader.js

The two path segments before loader.js are the SDK's major and minor version. Patch releases inside a minor (1.0.28 → 1.0.29) do not change your script URL: the loader resolves the current patch on every page load. You only edit your <script> tag when RevUp announces a new minor or major.

Subresource integrity​

Use integrity in production. The SRI hash is issued per environment and per minor line, and RevUp provides it to you together with your API keys — request the current value from your RevUp contact rather than copying it from an example. Always pair integrity with crossorigin="anonymous".

Integrity hash

The integrity value is not published in this documentation. You may request it from RevUp by escalating a support ticket.

<script
type="text/javascript"
charset="utf-8"
src="https://hosted.revuppayments.com/payments-widget/sdk/1/0/loader.js"
crossorigin="anonymous"
integrity="sha512-…">
</script>

Dynamic loading (React, Vue, …)​

const script = document.createElement('script');
script.type = 'text/javascript';
script.charset = 'utf-8';
script.src = REVUP_SDK_URL;
script.crossOrigin = 'anonymous';
if (INTEGRITY_HASH) script.integrity = INTEGRITY_HASH;
document.head.appendChild(script);

The ready signal​

The loader fires onRevupSDKLoaded on window once Revup is available. Never construct Revup before that event:

window.addEventListener('onRevupSDKLoaded', () => {
// window.Revup is now defined
});

4. The container​

<div id="revup-container"></div>

The element must already be in the DOM when you call init(). Any id works — you pass it as containerId. If the element is missing, init() throws:

Container with id: <containerId> not found, please check if the container is present in the DOM

The SDK renders its layout inside this element and manages its contents. Do not place your own children inside it.


5. RevupConfig — constructor​

const revup = new Revup({
merchantDomain: window.location.host,
apiKey: 'YOUR_PUBLIC_API_KEY',
orderId: 'ORDER_ID',
// version: '2',
});
PropertyTypeRequiredDescription
merchantDomainstringYesYour merchant domain, e.g. window.location.host or your production domain. It must match a domain registered for your merchant account.
apiKeystringYesThe public API key for the environment you are targeting (sandbox or live).
orderIdstringYesIdentifier of the order this checkout session pays for. In 1.0 this is the only place orderId can be supplied.
versionstringNoAPI version path segment. Defaults to the SDK's built-in version (currently "2"). Unrelated to the SDK version in the loader URL.

The constructor performs no network calls; it only records the configuration. All work happens in init().


6. RevupOptions — init()​

await revup.init({
containerId: 'revup-container',
language: 'en-US',
form: { /* … */ },
apms: { /* … */ },
userInfo: { /* … */ },
});
PropertyTypeRequiredDefaultDescription
containerIdstringYes—id of the element that will host the payment UI.
languagestringNobrowser language, then 'en-US'BCP 47 language code for form labels, APM button labels and placeholders. See Languages.
formobjectNosee belowCard form options. See form.
apmsobjectNo{}Alternative payment method options. See apms.
userInfoobjectNo{}Payer information collected by the card form. See userInfo.

1.0 does not accept orderId or appearance in init(). orderId is a constructor-only field, and visual styling is configured through form.styles / form.buttonStyles. The top-level appearance object arrives in 1.1.

Public methods​

MethodReturnsDescription
revup.init(options)Promise<void>Builds the layout, initializes APMs, loads the card form. Throws if containerId is not in the DOM.
revup.getApmsAvailable()Promise<string[]>Payment methods enabled for your merchant account in the current session. Safe to call before init(). Resolves to [] when nothing is available.
revup.onRevupMessage(handler)() => voidSubscribes to SDK events and returns a cleanup function. See Event contract.
Revup.getAvailableLanguages()string[]Static. All language codes the SDK supports. Callable before init().

getApmsAvailable() adds an extra round-trip and is not required for initialization — if you use it, call it in parallel with loading the SDK.


7. form — card form options​

form: {
collapsed: false,
showZipCode: true,
cardBrands: ['visa', 'mastercard', 'american_express'],
buttonStyles: {
backgroundColor: '#306de5',
textColor: '#FFFFFF',
height: 44,
borderRadius: 16,
},
}
PropertyTypeDefaultDescription
collapsedbooleantrueWhen true, the card form is hidden behind a card entry point — but only if at least one APM button actually renders. If no APM button renders, the form is always shown expanded regardless of this value.
showZipCodebooleanfalseShows the ZIP / postal-code field.
cardBrandsCardBrand[]['visa', 'mastercard']Brand marks shown in the card-number field before a brand is detected, and the set used to recognise the brand as the payer types. An empty array is ignored and the default is kept.
buttonStylesobjectsee belowColours and geometry of the card form's submit button.
stylesobject—Additional style overrides forwarded to the hosted form.
themestring'bootstrap'Base theme of the hosted form.
textDirectionstring'ltr'Accepted and stored, but has no visual effect in 1.0 — the hosted form does not read it. Right-to-left mirroring is only implemented from 1.2.
selfHostedDomainbooleantrueWhen true, 3-D Secure device-fingerprint (DDC) requests run inside the hosted card form iframe. Set to false when the SDK is embedded directly on your primary checkout page and your gateway requires a first-party browser context for those requests. Nested-iframe setups are not supported with false.
userInfoobject{}Same shape as top-level userInfo; the top-level form is preferred.

buttonStyles​

KeyTypeDefaultNotes
backgroundColorstring'#306de5'Any CSS colour.
textColorstring'#FFFFFF'Any CSS colour.
heightnumber (px)44Clamped to 44–55. Non-numeric values fall back to the default.
borderRadiusnumber (px)16Clamped to 0–60. Non-numeric values fall back to the default.

Option validation​

Every key inside form is type-checked at runtime. A key with the wrong type — or a key the SDK does not recognise — is rejected, the default is used instead, and a message is written to the browser console:

<key> is not a valid option, default value was setted instead.

This never throws and never blocks the checkout.

Supported card brands​

visa, mastercard, american_express, unionpay, jcb, discover, diners_club, maestro, visa_electron, vpay, rupay, elo, elo_new, hipercard, verve, troy, mir, cartes_bancaires, girocard, dankort, bancontact, interac, bc_card, dinacard, cabal, napas, mada, knet, benefit.


8. apms — alternative payment methods​

In 1.0 the APM configuration is flat: one list of enabled methods plus two side-tables keyed by method name.

apms: {
enabled: ['apple_pay', 'google_pay', 'paypal', 'stripe_link', 'amazon_pay'],
buttonTypes: {
apple_pay: 'book',
google_pay: 'buy',
paypal: 'checkout',
},
capabilityDetection: ['apple_pay', 'google_pay'],
}
PropertyTypeDescription
enabledstring[]The methods to render, in render order. Each name is additionally filtered against the methods your merchant account actually has enabled; a name that is not enabled is silently skipped.
buttonTypesRecord<string, string>Vendor button style variant, per method.
capabilityDetectionstring[]Methods that must pass a device/browser support check before their button is rendered. Methods not listed skip the check.

Available method names​

apple_pay, google_pay, paypal, stripe_link, amazon_pay.

credit_card is not an APM name — the card flow is configured through form. Query what your account has enabled with revup.getApmsAvailable().

Button style variants (buttonTypes)​

MethodAccepted values
apple_payadd-money, book, buy, check-out, continue, contribute, donate, order, pay, plain, reload, rent, set-up, subscribe, support, tip, top-up
google_paybook, buy, checkout, donate, order, pay, plain, subscribe
paypalpaypal, checkout, buynow, pay, installment
stripe_link, amazon_paynot applicable — the value is ignored

An unrecognised value falls back to plain and dispatches an apm.unavailable event carrying the explanation; the button still renders.

Capability detection​

MethodCheck performed
apple_payApplePaySession.canMakePayments(), plus canMakePaymentsWithActiveCard() when a merchant identifier is available
google_payisReadyToPay()
all othersnone — the flag is ignored

If a listed method fails its check, the SDK dispatches apm.unavailable for that method and does not render an unusable button.

APM initialization is fault-isolated: a method that fails to initialize removes itself and never prevents the other methods or the card form from rendering.


9. userInfo — payer email​

userInfo: {
email: { required: true, value: 'buyer@example.com' },
}
PropertyTypeDefaultDescription
email.requiredbooleanfalseWhen true, the hosted card form shows an email field above the card inputs and requires a valid address before the payment can be submitted.
email.valuestring''Pre-fills the email field when it is shown.

When the payer supplies an email, the payment request includes it (trimmed). When email.required is false or omitted, no email field is shown.


10. Languages​

language accepts a BCP 47 code. When omitted, the SDK detects the browser language and falls back to en-US.

19 supported languages: en-US, ar-SA, cs-CZ, de-DE, es-ES, fr-FR, it-IT, ja-JP, ko-KR, nl-NL, pl-PL, pt-PT, ro-RO, ru-RU, th-TH, tr-TR, uk-UA, zh-CN, zh-TW.

Read them at runtime with Revup.getAvailableLanguages() — a static method, callable before init().

language: 'ar-SA' translates the strings only. Right-to-left layout mirroring does not exist in 1.0.


11. Event contract​

Everything the SDK reports reaches your page as a single native CustomEvent named onRevupMessage, dispatched on document.

Listening​

// Helper — unwraps event.detail for you and returns a cleanup function
const stop = revup.onRevupMessage((event) => {
console.log(event.type, event);
});

// Or the native listener — read the SDK event from event.detail
document.addEventListener('onRevupMessage', (e) => {
const event = e.detail;
});

Guarantees​

  1. Events are dispatched on document with bubbles: false. A listener on window, or on your container element, will never fire. Listen on document.
  2. context, data and error are omitted when empty — always use optional chaining (event.context?.orderId).
  3. Payloads are sanitized before dispatch: card numbers, CVVs, API keys and other PCI/PII patterns are masked. Raw card data never appears in an event.
  4. Critical misconfiguration (missing container, invalid required fields) throws — it is not dispatched as an event.
  5. These events are advisory. Always confirm the final payment outcome server-side using transactionId / orderId.

Envelope​

Every event has the same shape:

{
id: string; // UUID v4, unique per event
type: SdkEventType; // what happened
source: 'form' | 'apm';
timestamp: string; // ISO 8601

context?: {
orderId?: string;
transactionId?: string;
apm?: string; // APM events only
transactionStatus?: string;
};

data?: unknown; // event-specific, see below
error?: {
name: string; // machine-readable, see Error names
message: string; // human-readable, sanitized
statusCode?: number; // HTTP status, when the failure came from an HTTP response
};
}

There is no error.code — the machine-readable field is error.name.

Event types​

typesource: 'form'source: 'apm'Meaning
initialized✅—The card form iframe is loaded and ready.
validation.changed✅—Card form validity changed.
payment.submitted✅✅A payment attempt started. Not an outcome.
payment.action_required✅✅Further action is needed (3-D Secure challenge on the card path).
payment.success✅✅Terminal — approved.
payment.failed✅✅Terminal — declined or errored.
payment.cancelled✅ (gateway-reported)✅Terminal — the payer backed out.
apm.unavailable—✅An APM cannot be used and its button will not render.

Only payment.success, payment.failed and payment.cancelled end a payment attempt.


source: 'form' — the card form​

initialized​

Fires once, when the form iframe has loaded and reported its size.

FieldValue
context.orderIdthe order id
data.message'initialized'

Use it to remove your loading placeholder. It is not a signal that the payment can be submitted — use validation.changed for that.

validation.changed​

Fires whenever the form's validity or submission state changes.

FieldValue
context.orderIdthe order id
data.isValidboolean — all fields pass validation
data.isCallingboolean — a submission is in flight

This is the signal to enable or disable your own payment button.

1.0 does not report which individual fields are invalid. data.invalidFields arrives in 1.2.

payment.submitted​

Fires when the payer submits the form, before the gateway responds.

FieldValue
context.orderIdthe order id
data.isValidtrue
data.isCallingtrue

Treat it strictly as a "processing" state.

Terminal card events — one shared payload​

payment.action_required, payment.success, payment.failed (gateway decline) and payment.cancelled are all produced from the same gateway response, so they share one payload shape. The event type is derived from the gateway's transactionStatus:

Gateway transactionStatusEvent dispatched
successpayment.success
failedpayment.failed (error.name: 'PaymentFailed')
cancelled, cancelled_by_userpayment.cancelled
waiting_user_interaction, in_processpayment.action_required
anything elsepayment.submitted

Payload:

FieldValue
context.orderIdthe order id
context.transactionIdthe gateway transaction id, when one exists
data.actionpresent only when the gateway returned a challenge — see below
data.transactionResult.statusthe raw status the form received
data.transactionResult.responsethe full gateway response body

transactionStatus and transactionId are deliberately not repeated at the top of data: they are represented by the event type and by context.transactionId. The gateway's own copy is still readable at data.transactionResult.response.transactionStatus.

payment.action_required — the 3-D Secure challenge​

When the gateway asks for a challenge, data.action describes where to send the payer. The same object is reachable at data.transactionResult.response.action.

FieldValue
data.action.urlURL to redirect to or POST to
data.action.method'GET' or 'POST'
data.action.parametersarray of { key, value } pairs to submit
document.addEventListener('onRevupMessage', (e) => {
const { type, source, data } = e.detail;
if (type !== 'payment.action_required' || source !== 'form') return;

const { url, method, parameters } = data.action;

if (method === 'POST') {
const form = document.createElement('form');
form.method = 'POST';
form.action = url;
for (const { key, value } of parameters) {
const input = document.createElement('input');
input.type = 'hidden';
input.name = key;
input.value = value;
form.appendChild(input);
}
document.body.appendChild(form);
form.submit();
} else {
window.location.href = url;
}
});

payment.failed — two different causes​

Causeerror.nameWhere the detail is
The gateway declined (transactionStatus: 'failed')PaymentFaileddata.transactionResult.response
The form could not submit at all (network error, configuration/encryption failure)FormSubmitErrorerror.message

Read the decline reason from data, not from error.message. On a PaymentFailed event error.message is the generic string "Payment failed". The gateway's actual reason is in the response body at data.transactionResult.response.message. On a FormSubmitError event there is no gateway response, and error.message is the real description.

error.statusCode is never set on form events. When the payment call itself failed with an HTTP error, the status is at data.transactionResult.status.

Do not rethrow — the form re-enables itself and the payer can retry.


source: 'apm' — alternative payment methods​

Every APM event carries context.apm with the method identifier, except apm.unavailable raised by the SDK's own APM bootstrap.

EventWhenPayload
payment.submittedThe payer opened the wallet sheet / popupcontext: { orderId, apm }, data.message
payment.successThe gateway approvedcontext: { transactionId, orderId, apm }, data.message
payment.failedThe gateway declined, or the vendor flow erroredcontext: { transactionId?, orderId, apm }, error: { name, message, statusCode? }
payment.cancelledThe payer dismissed the wallet sheet or popupcontext: { orderId, apm }, data.message ('User cancelled' for Apple Pay and Google Pay)
apm.unavailableThe method cannot rendercontext: { apm, orderId? }, error: { name, message, statusCode? }

apm.unavailable is dispatched for, among others: the vendor SDK failing to load, an unsupported device when capability detection is enabled, no active card in the wallet, a missing vendor configuration, an invalid buttonTypes value, or the merchant-level availability lookup failing.

payment.cancelled is a normal outcome, not a failure — restore your checkout state and let the payer choose again.

Error names​

error.nameOrigin
apms_initialization_errorThe SDK's APM bootstrap: configuration validation, or the availability lookup
apple_pay_errorApple Pay
google_pay_errorGoogle Pay
paypal_errorPayPal
stripe_link_errorStripe Link (and Amazon Pay, which is served through the same module in 1.0)
PaymentFailedCard form — gateway decline
FormSubmitErrorCard form — submission could not be sent

A complete handler​

const stop = revup.onRevupMessage((event) => {
const { type, source, context, data, error } = event;

switch (type) {
case 'initialized':
hideLoadingPlaceholder();
break;

case 'validation.changed':
myPayButton.disabled = !data.isValid || data.isCalling;
break;

case 'payment.submitted':
showSpinner();
break;

case 'payment.action_required':
if (source === 'form' && data?.action) redirectToChallenge(data.action);
break;

case 'payment.success':
// Advisory — confirm server-side before fulfilling
confirmOnServer(context.orderId, context.transactionId);
break;

case 'payment.failed':
showError(error.message);
break;

case 'payment.cancelled':
restoreCheckout();
break;

case 'apm.unavailable':
hideMethod(context?.apm);
break;
}
});

12. Cleanup and re-initialization​

1.0 has no destroy() method. To tear the SDK down:

// 1. Remove your event listener
stopListening();

// 2. Clear the container
const container = document.getElementById('revup-container');
if (container) container.innerHTML = '';

// 3. For a new order, build a fresh instance
revup = new Revup({ ...config, orderId: newOrderId });
await revup.init({ containerId: 'revup-container', form: { /* … */ } });

Because orderId is a constructor field in 1.0, changing the order always requires a new Revup instance. Do not reuse an instance across orders.

A proper destroy() — which also removes the injected preconnect hints and appearance state that innerHTML = '' leaves behind — arrives in 1.1, together with the ability to switch order without recreating the instance.


13. Environments, URLs and CSP​

EnvironmentLoader host
Sandboxhttps://test.hosted.revuppayments.com
Livehttps://hosted.revuppayments.com

Use the API key that matches the environment; a sandbox key will not work against live.

Your Content Security Policy must allow:

  • script-src — the loader host above, and https://js.stripe.com when Stripe-served methods (Stripe Link, Amazon Pay) are enabled.
  • frame-src — the RevUp form origin, and the wallet/vendor origins for the APMs you enable.
  • connect-src — the RevUp API origin.

The exact origins for your account are provided with your API keys. The SDK's API base URL and form URL are fixed at build time; your integration only supplies merchantDomain, apiKey and orderId.


14. Known limits of the 1.0 line​

These are the reasons to plan a move to a newer minor. Each links to where it is solved.

Limit in 1.0Resolved in
orderId can only be set on the constructor; a new order needs a new instance1.1
No destroy() — teardown leaves injected page state behind1.1
Styling limited to form.styles / form.buttonStyles1.1 — full Appearance API
One flat APM stack; no secondary / overflow zones1.1
Only 5 APMs; no iDEAL, Pix or SEPA Direct Debit1.1
No session API — every change is a full teardown1.1
validation.changed does not say which fields are invalid1.2
textDirection: 'rtl' has no visual effect1.2

Patch history of the 1.0 line​

The loader always serves the newest patch of the minor, so a merchant pinned to /sdk/1/0/ is on 1.0.29. Patches in this line were bug fixes, performance work and security updates; the public API described on this page is the 1.0.29 surface and did not change in a breaking way within the line.