SDK responses and callbacks
Handle success, error, close, resize, BIN, installment, and processing callbacks consistently across DEUNA SDKs.
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#
Callback matrix#
| Callback | Payload | Contract |
|---|---|---|
onSuccess(data) | Experience result | Payment and Next Action usually return order data; Elements returns credential data. Treat it as client data until reconciled. |
onError(error) | Normalized SDK error | Read type, metadata.code, and metadata.message. Native payment errors can also include an order. |
onClosed(action, metadata?) | Closure reason | Web uses userAction or systemAction; native SDKs expose their typed close action. Closure is not success or failure. |
onEventDispatch(event, payload) | Raw lifecycle event | Analytics and diagnostics only. Payload varies by experience. |
onResize({height, width}) | Pixel dimensions | Resize embedded Web or React Native hosts. |
onCardBinDetected(data) | BIN selection | Web and React Native type {cardBin, cardBrand}; native callbacks expose JSON. |
onInstallmentSelected(data) | Installment selection | Web and React Native type {cardBin, installmentPlanOptionId}; native callbacks expose JSON. |
onPaymentProcessing() | No payload | Lock duplicate submission while payment is in flight. |
Web and React Native types#
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:
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.
| Category | Android | iOS | Meaning |
|---|---|---|---|
| Connectivity | NO_INTERNET_CONNECTION | noInternetConnection | The device cannot reach the service. |
| Token | INVALID_ORDER_TOKEN | invalidOrderToken | The token is empty or invalid for the experience. |
| Initialization | INITIALIZATION_FAILED | initializationFailed | The widget could not be prepared or presented. |
| Retrieval | ORDER_COULD_NOT_BE_RETRIEVED, ORDER_NOT_FOUND | orderCouldNotBeRetrieved, orderNotFound | Order lookup failed. Reconcile on the backend before retrying. |
| Payment | PAYMENT_ERROR | paymentError | The payment experience reported an error. Read metadata. |
| Navigation | — | errorWhileLoadingTheURL | iOS could not load the widget URL. |
| Customer | — | userError | iOS received a customer-facing error category. |
| Fallback | UNKNOWN_ERROR | unknownError | Preserve safe diagnostics and show a generic recovery path. |
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)
}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#
| Experience | What onSuccess represents | Next step |
|---|---|---|
| Payment Widget | The widget completed its purchase path and returns order-shaped data. | Reconcile the order on your backend before fulfillment. |
| Next Action | The required customer action completed and returns order-shaped data. | Re-fetch the same order; do not create another one. |
| Elements / Payment Vault | A credential or wallet flow completed. | Send only the documented credential or result to your backend flow. |
| Voucher | Voucher 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#
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
onPaymentProcessingand whilesubmit()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.