Skip to main content
On this page

Every DEUNA SDK returns immediate UI outcomes through callbacks. The exact success object depends on the opened experience, while errors, close actions, BIN detection, and installment selection use smaller contracts.

Response anatomy#

01 · widget
Emit a local outcome
The active experience invokes a callback.
02 · app
Update the interface
Show confirmation, recovery, loading, or closure state.
03 · backend
Reconcile the order
Retrieve current state or process a verified webhook.
04 · business
Act once
Fulfill, retry, or escalate from the authoritative state.

Callback matrix#

CallbackPayloadContract
onSuccess(data)Experience resultPayment and Next Action usually return order data; Elements returns credential data. Treat it as client data until reconciled.
onError(error)Normalized SDK errorRead type, metadata.code, and metadata.message. Native payment errors can also include an order.
onClosed(action, metadata?)Closure reasonWeb uses userAction or systemAction; native SDKs expose their typed close action. Closure is not success or failure.
onEventDispatch(event, payload)Raw lifecycle eventAnalytics and diagnostics only. Payload varies by experience.
onResize({height, width})Pixel dimensionsResize embedded Web or React Native hosts.
onCardBinDetected(data)BIN selectionWeb and React Native type {cardBin, cardBrand}; native callbacks expose JSON.
onInstallmentSelected(data)Installment selectionWeb and React Native type {cardBin, installmentPlanOptionId}; native callbacks expose JSON.
onPaymentProcessing()No payloadLock duplicate submission while payment is in flight.

Web and React Native types#

Public callback shapesJavaScript
type ClosedAction = 'userAction' | 'systemAction';

type SdkError = {
  type: string;
  metadata: {
    code: string;
    message: string;
  };
};

type CardBinDetected = {
  cardBin: string;
  cardBrand: string;
};

type InstallmentSelected = {
  cardBin: string;
  installmentPlanOptionId: string;
};

type Dimensions = {
  height: number;
  width: number;
};

Handle errors by category, while keeping the provider or experience code for support diagnostics:

JavaScript
const callbacks = {
  onSuccess: async (data) => {
    setCheckoutState('verifying');
    const verifiedOrder = await fetch(`/api/orders/${merchantOrderId}`).then(r => r.json());
    renderFromAuthoritativeState(verifiedOrder);
  },
  onError: ({type, metadata}) => {
    logSafeDiagnostic({type, code: metadata.code});
    showRecoveryMessage(type, metadata.code);
  },
  onClosed: (action, metadata) => {
    restorePaymentMethods();
    if (metadata) logSafeDiagnostic({action, code: metadata.code});
  },
};

Native error types#

The iOS and Android SDKs normalize payment errors into PaymentsError with type, optional metadata, and an optional order snapshot.

CategoryAndroidiOSMeaning
ConnectivityNO_INTERNET_CONNECTIONnoInternetConnectionThe device cannot reach the service.
TokenINVALID_ORDER_TOKENinvalidOrderTokenThe token is empty or invalid for the experience.
InitializationINITIALIZATION_FAILEDinitializationFailedThe widget could not be prepared or presented.
RetrievalORDER_COULD_NOT_BE_RETRIEVED, ORDER_NOT_FOUNDorderCouldNotBeRetrieved, orderNotFoundOrder lookup failed. Reconcile on the backend before retrying.
PaymentPAYMENT_ERRORpaymentErrorThe payment experience reported an error. Read metadata.
Navigation—errorWhileLoadingTheURLiOS could not load the widget URL.
Customer—userErroriOS received a customer-facing error category.
FallbackUNKNOWN_ERRORunknownErrorPreserve safe diagnostics and show a generic recovery path.
AndroidKotlin
callbacks.onError = { error ->
    val code = error.metadata?.code ?: "UNKNOWN_ERROR"
    logger.warn("DEUNA SDK error", mapOf("type" to error.type.name, "code" to code))
    renderRecovery(error.type)
}
iOSSwift
callbacks.onError = { error in
    let code = error.metadata?.code ?? "UNKNOWN_ERROR"
    logger.warning("DEUNA SDK error: \(error.type) / \(code)")
    renderRecovery(error.type)
}

Success is experience-specific#

ExperienceWhat onSuccess representsNext step
Payment WidgetThe widget completed its purchase path and returns order-shaped data.Reconcile the order on your backend before fulfillment.
Next ActionThe required customer action completed and returns order-shaped data.Re-fetch the same order; do not create another one.
Elements / Payment VaultA credential or wallet flow completed.Send only the documented credential or result to your backend flow.
VoucherVoucher presentation or its supported action completed.Show instructions, then wait for authoritative asynchronous payment status.

The order model evolves independently of SDK callback plumbing. Use the API endpoint reference for the current backend schema instead of copying arbitrary fields from a client payload.

Embedded resize handling#

JavaScript
const host = document.querySelector('#deuna-widget');

await DeunaSDK.initPaymentWidget({
  orderToken,
  mode: 'target',
  target: '#deuna-widget',
  callbacks: {
    onResize: ({height}) => {
      host.style.height = `${Math.ceil(height)}px`;
    },
    onSuccess: verifyOrder,
    onError: showRecovery,
  },
});

Give the host a stable minimum height while the iframe loads, then let onResize update it. On small screens, avoid a fixed pixel width and allow the host to fill the viewport.

Safe handling checklist#

  • Keep callback functions idempotent; lifecycle signals can occur near navigation or retries.
  • Disable duplicate submission during onPaymentProcessing and while submit() is pending.
  • Render human-readable copy from an allow-list. Do not expose raw provider messages by default.
  • Log type, safe error code, SDK version, environment, and a merchant correlation ID—not credentials or card data.
  • Restore focus when a modal closes and announce errors through an accessible live region.
  • Verify the current order state after ambiguous closure, timeout, or network interruption.

Public source contracts#

The callback shapes are verified against the current Web callback interfaces, React Native callback interfaces, iOS callback base, and Android shared callbacks. Use the version installed by your application when a repository’s main branch is newer than your pinned release.