Skip to main content
The SDK is a container and an event relay. It does not render card input or carry card data; capture happens on the provider’s own page, loaded over HTTPS in a WebView. Building in React Native? Use the React Native SDK instead; it wraps this one.

Install

The SDK is on Maven Central as io.meld:meldsdk. New Android projects already list mavenCentral() in their repositories.
The library declares the INTERNET and CAMERA permissions, which merge into your manifest. Camera is for KYC capture inside a provider’s surface. A minified build needs no keep rules of your own. The SDK ships its R8 rules, and they cover an app that leaves out Google Play services Wallet too.
0.8.0 is the release that brings the wallet contract every Meld SDK shares: the readiness checks, the shared error codes with the order’s paymentMethodType on each error, and the Activity mount. Everything else on this page works from 0.7.0, the first release with Google Pay.

Configure the environment

Call it once, before you check or mount an order, with the environment your backend created the order in. See Environments.

Create the order on your backend

The order comes from your server. Your API key never ships in the app. See Cards or Wallets for the request. Return the response to the app unchanged: the SDK reads what it needs from it.

Check readiness before you create the order

Two checks tell you what to offer, and both need 0.8.0 or later. They answer Ready, Unavailable or Unknown, with the same meaning on every Meld SDK. See Wallets → The integration loop. Each answers once, on the main thread, within 5 seconds.

Before you quote

Ask whether this device can pay with a method at all, for example to decide whether to show a Google Pay entry point:
  • GOOGLE_PAY asks Google Pay’s isReadyToPay for any Visa, Mastercard, American Express or Discover card the customer has added. It answers Ready when there is one and Unavailable when there is none. It answers Unknown when Google Play services is missing, out of date or slow, and, with the SDK configured for SANDBOX, when there is no card (see Google Pay in sandbox).
  • APPLE_PAY answers Unavailable: Apple Pay never runs on Android.
  • Any other method, such as CREDIT_DEBIT_CARD or a bank transfer, answers Unknown: nothing on the device decides it.
A provider can take fewer cards than this check counts. Coinbase takes only cards tokenized on the device, for example, so check the quote row too.

After you quote

Each headless quote row carries paymentMethodType and headlessPresentation. Ask the SDK whether this device can pay with a row, through its provider, before you offer it:
  • Ready: offer the method.
  • Unavailable: hide the method. This SDK doesn’t present the row on this device, or Google Pay reports no card on this phone that the provider’s request accepts. No order exists, so there is nothing to track.
  • Unknown: you may offer the method. Card rows answer Unknown, because nothing on the device decides whether a card pays. A Google Pay row answers Unknown when Google Play services is missing, out of date or slow, and, with the SDK configured for SANDBOX, when Google Pay finds no card.
Unavailable and Unknown carry a reason for your logs, and the SDK logs every Unknown reason under the MeldSDK tag. Readiness is advisory and moves no money. If you create the order anyway, the mounted order reports PAYMENT_METHOD_UNAVAILABLE when the device can’t pay, and that is the final word. On 0.7.0, Meld.presentationCapabilities(presentation, paymentMethodType) answers only whether this build can present the row. Hide the row when its surface is unsupported.

Mount the order

Call mount on the main thread. Branch only on surface == "unsupported" and on embeddable. Every other surface value, such as embedded or native-wallet, is informational and can change between releases: see Surface is informational.
  • Embeddable orders, the card forms, render into the ViewGroup you pass. Give it room.
  • Other orders, such as Google Pay, draw into none of your views and report requiresUserGesture = true. Mount them from the customer’s tap with Meld.mount(order, activity, handlers). The payment then lives as long as that Activity: it ends only when the Activity is destroyed or you unmount, not when one of your views leaves its window. A configuration change the Activity doesn’t handle itself destroys it, and so ends the payment.
The Activity mount needs 0.8.0 or later. It throws MeldMountException.MissingHost for an embeddable order, and MeldMountException.PresentationUnavailable when the Activity is not on screen. On 0.7.0, mount every order with a view. For a Google Pay order, the view only locates the Activity, and the payment ends when the view leaves its window, so keep it attached until a terminal callback. Keep the handle until a terminal callback. handle.unmount() tears the surface down and delivers no callback. After onPaymentSubmitted you can unmount straight away: the SDK keeps a provider-hosted page alive for up to 60 seconds, so the provider can finish confirming the payment.

Events

Every callback runs on the main thread and receives the order’s id. The five events covers what each one means and how onCancel and onError relate to the status. Each mount delivers exactly one terminal callback, onPaymentSubmitted, onCancel or onError with recoverable: false, and drops every callback after it. If the session ends without one while you still hold the handle, you get onError with PAYMENT_OUTCOME_UNKNOWN, or with PAYMENT_REJECTED after a FAILED status. To retry after a terminal callback, create a new order.

Error codes

Every Meld SDK shares these codes, with the same attemptMayExist for each: see Wallets → Error codes. They need 0.8.0 or later. MeldErrorCode names these codes. error.attemptMayExist, or MeldErrorCode.attemptMayExist(code), is false only for the five codes that say no attempt exists, and true for every other code, including one this build doesn’t know. error.paymentMethodType is the mounted order’s paymentMethodType, such as GOOGLE_PAY, or null when the order has none. Word your message from it rather than from the code. detail carries the provider’s own event or code. Log it; don’t branch on it.

Card forms that fail before they show

The Banxa and Uphold card forms run a provider SDK, bundled with this one, inside the WebView. When that page fails before the form shows, they report a shared code, with the form’s own code in detail:

Codes the card forms pass through

The Android SDK adds no code of its own. Its card forms pass the provider’s other codes through, and each can follow a payment, so attemptMayExist is true for all of them:

Google Pay

Coinbase presents Google Pay through its own payment page. The SDK loads that page out of sight and presses its Google Pay button once, so the customer sees only Google Pay’s sheet. Such an order reports embeddable = false, surface = "native-wallet" and requiresUserGesture = true. Before you offer it, meet Before you go live: your own Coinbase project with Google Pay enabled, your app’s own approval in the Google Pay & Wallet Console, and a physical phone with Android System WebView 137 or later and Google Play services 25.18.30 or later. On a WebView without Payment Request support, Meld.capabilities reports unsupported. How to test it, and what OR_BIBED_11 and the other failures mean, are in Wallets → Testing and Wallets → Troubleshooting.

What the SDK adds to your app

  • From 0.7.0, the package queries for org.chromium.intent.action.PAY, IS_READY_TO_PAY and UPDATE_PAYMENT_DETAILS, through which the provider page’s Payment Request reaches Google Pay.
  • From 0.8.0, Google Play services Wallet (com.google.android.gms:play-services-wallet 20.0.0), for the readiness checks only. Your merged manifest gains the com.google.android.gms.wallet.api.enabled and com.google.android.gms.version meta-data and the non-exported com.google.android.gms.common.api.GoogleApiActivity.
  • Nothing from Google Maps. Wallet uses play-services-maps only for the LatLng of its loyalty, offer and gift card objects, which the SDK never builds, so the SDK excludes it. Your merged manifest gains none of Maps’ entries, such as the OpenGL ES 2 uses-feature with required="true". An app that uses Maps keeps its own dependency on it.

Leaving out Google Play services Wallet

Wallet is there for the readiness checks only, so you can exclude it:
Google Pay orders still mount, and every Google Pay readiness check then answers Unknown. A minified build still needs no rules of your own: the SDK’s R8 rules let Wallet be missing.

Provider notes

  • Mercuryo. Create the order with the customer’s public IP as clientIpAddress: Mercuryo binds its widget to it. Its KYC liveness check needs the camera, so request the CAMERA permission at run time before you mount.
  • Coinbase. Google Pay only, for US customers paying USD. See Google Pay with Coinbase.
Apple Pay never runs on Android: every Apple Pay order reports unsupported.

Settlement

Settlement is your webhook. onPaymentSubmitted fires when the customer finishes paying, which is earlier: unmount and show a pending state until the webhook arrives. See Configure webhooks.