Tapaya
Accettazione in presenzaGuida all'integrazioneIntegrazione dell'SDK mobile

Integrazione dell'SDK mobile

Android

Integri Tapaya Accept SDK nella Sua applicazione mobile.

Tapaya Accept SDK integra l'elaborazione dei pagamenti con carta direttamente nella Sua app. È disponibile per Android (Kotlin) e per React Native / Expo, ed entrambe le versioni sono destinate a dispositivi Android. Il pacchetto React Native è un sottile wrapper dell'SDK Android, quindi le interfacce, i tipi e i casi di errore descritti di seguito sono gli stessi in entrambi.

Ogni esempio di codice in questa pagina è suddiviso in schede per linguaggio. Ne scelga uno e l'intera pagina si adegua.

Installazione

build.gradle.kts
dependencies {
    implementation("com.tapaya:accept:1.15.0")
}

Android: aggiunga la dipendenza al file build.gradle.kts a livello di modulo, quindi sincronizzi il progetto.

React Native: installi il pacchetto con npx expo install @tapayadot/accept-react-native, aggiunga il config plugin come mostrato, quindi rigeneri il progetto nativo con npx expo prebuild --clean e lo avvii con npx expo run:android.

Inizializzazione

Accept è il punto di accesso a tutte le funzionalità dell'SDK. Lo inizializzi una sola volta all'avvio dell'app (su Android, di solito nella classe Application), quindi esegua l'autenticazione separatamente con un token dell'esercente.

Passaggio 1: inizializzazione

// Sandbox is the default (isProduction = false)
Accept.initialize(context = this)

// Target production explicitly
Accept.initialize(context = this, isProduction = true)

// Or drive it from your build type
Accept.initialize(context = this, isProduction = !BuildConfig.DEBUG)

Su React Native non c'è alcun context: lo gestisce il modulo nativo.

Passaggio 2: autenticazione

Dopo l'inizializzazione, chiami Accept.auth.authenticate() per far accedere un esercente con un token ottenuto dal Suo backend. La chiamata è asincrona e, in caso di errore, fallisce con un errore dell'SDK. In caso di successo, lo stato dell'SDK diventa authenticated.

// suspend; call from a coroutine
try {
    val sdkToken = myBackendApi.getSdkToken()
    Accept.auth.authenticate(sdkToken)
    // Accept.state now emits SdkState.Authenticated
} catch (e: AcceptException) {
    // handle authentication failure
}

Osservi il ciclo di vita per reagire a queste transizioni: idle → initialized → authenticated.

// Accept.state is a StateFlow<SdkState>
Accept.state.collect { state ->
    if (state == SdkState.Authenticated) loadMerchant()
}

Concetti fondamentali

L'oggetto Accept espone l'SDK tramite un piccolo insieme di interfacce:

InterfacciaScopo
Accept.authAutenticare una sessione dell'esercente.
Accept.merchantProfilo dell'esercente, configurazione, stato dell'onboarding.
Accept.paymentsCreare e gestire i pagamenti con carta.
Accept.pluginInstallazione e attivazione del terminale (app plugin).
Accept.displaysInformazioni sui display del dispositivo per i terminali a doppia faccia (“double-sided”).
Accept.sdkVersione dell'SDK, ambiente, ID del dispositivo, importi minimi.
Accept.stateStato del ciclo di vita: StateFlow<SdkState> in Kotlin, un getter più addStateListener() in React Native.

Accettare un pagamento

Chiami Accept.payments.pay() con l'importo (nell'unità minima della valuta) e un codice valuta ISO 4217, quindi osservi il flusso di eventi PaymentEvent che restituisce: prima l'avanzamento, poi l'esito finale. pay() non genera mai eccezioni; un errore nella creazione del pagamento arriva invece come evento CreationFailed.

L'unica differenza è il modo in cui si osserva il flusso: Kotlin restituisce un Flow<PaymentEvent> da raccogliere in una coroutine, mentre React Native accetta un listener e restituisce una sottoscrizione che si può chiudere con remove().

amount e currency sono obbligatori. Per i parametri facoltativi (paymentToken, receiptConfig, nfcPosition, metadata, tip, transactionTimeout, display), consulti Creare un pagamento.

In React Native

Gli stessi parametri arrivano come un unico oggetto PaymentRequest, pay({ amount, currency, tip, … }), con number al posto di Long e Record<string, string> al posto di Map<String, String>. Un solo nome cambia: il timeout è transactionTimeoutMs e accetta semplici millisecondi (0…120000) anziché una Duration.

Flusso di pagamento

Accept.payments.pay(amount = 15000, currency = "CZK") // 150.00 Kč
    .collect { event ->
        when (event) {
            PaymentEvent.Creating -> Log.d("pay", "creating")
            is PaymentEvent.Created -> Log.d("pay", "created ${event.paymentToken}")
            PaymentEvent.Launched -> Log.d("pay", "launched")
            is PaymentEvent.Result -> Log.d("pay", event.payResult.toString())
            is PaymentEvent.CreationFailed -> Log.e("pay", event.cause.toString())
        }
    }

L'evento finale con il risultato contiene un PayResult: riuscito (con paymentToken, metadata, authCode, receiptDetails), rifiutato (metadata, receiptDetails), annullato (metadata) o non riuscito (reason, metadata). Kotlin li modella come sottoclassi PayResult.Success / Declined / Canceled / Failed; React Native come unione discriminata su cui si dirama con payResult.type === 'success'. Il dettaglio completo è in Esito del pagamento. In seguito può interrogare un pagamento con Accept.payments.status(paymentToken), interromperlo con Accept.payments.cancel(paymentToken) o rimborsarlo con Accept.payments.refund(paymentToken, reason).

Solo l'esito (React Native)

Se la Sua interfaccia non mostra gli stati intermedi, payAsync() riduce l'intero flusso al PayResult finale e viene rifiutata con un AcceptError per tutto ciò che pay() avrebbe segnalato come creationFailed. Non ha un equivalente in Kotlin: lì raccolga il Flow oppure ne prenda solo l'ultimo evento.

const result = await Accept.payments.payAsync({ amount: 15000, currency: 'CZK' });
if (result.type === 'success') {
    console.log(result.paymentToken, result.receiptUrl);
}

Informazioni sull'esercente e sull'SDK

Accept.merchant espone il profilo e la configurazione di pagamento dell'esercente che ha effettuato l'accesso. Accept.sdk espone informazioni sulla build dell'SDK e su questo dispositivo. Ogni membro descritto di seguito richiede prima Accept.initialize() (tranne Accept.sdk.version), e tutto ciò che si trova su Accept.merchant richiede inoltre un Accept.auth.authenticate() completato, altrimenti la chiamata genera NotInitialized o NotAuthenticated.

Esercente

val info = Accept.merchant.info()                      // MerchantInformation?
val config = Accept.merchant.config()                  // MerchantConfig
val currencies = Accept.merchant.availableCurrencies() // List<String>
val status = Accept.merchant.onboardingStatus()        // OnboardingStatus
MembroRestituisceDescrizione
info()MerchantInformation?Il profilo aziendale registrato dell'esercente. null se il profilo non è ancora disponibile.
config()MerchantConfigLa configurazione di pagamento dell'esercente.
availableCurrencies()List<String>Codici ISO 4217 che l'esercente può accettare. Forma abbreviata di config().availableCurrencies.
onboardingStatus()OnboardingStatusIndica se l'esercente può già accettare pagamenti.

Tutti e quattro sono suspend e in caso di errore generano NotAuthenticated, NoInternetConnection o Unknown.

MerchantInformation contiene il profilo aziendale registrato. Sempre presenti: merchantId (UUID), email, businessType (BusinessType), legalName, registrationNumber, mcc e l'indirizzo registrato (addressLine1, city, country). Facoltativi (null se l'esercente non li ha forniti): vatNumber, incorporationDate, addressLine2, postalCode, state, phone, averageItemValue, expectedMonthlyTurnover, businessModelDescription, numberOfEmployees, annualTurnover, balanceSheetTotal, statementDescriptor, termsVersion.

BusinessType è uno tra INDIVIDUAL, COMPANY, NONPROFIT_ORGANIZATION, GOVERNMENT_ENTITY o PARTNERSHIP.

MerchantConfig contiene availableCurrencies: List<String> e la valuta predefinita dell'esercente, currency: String?.

OnboardingStatus è un'interfaccia sealed: ReadyForPayments oppure RequiresAction(state), dove state è un OnboardingState: NOT_STARTED, PENDING, ACTIVE, ATTENTION_NEEDED, ACTION_REQUIRED, BLOCKED, WAITING_FOR_KYB, WAITING_FOR_STAKEHOLDERS o PENDING_ACQUIRER_APPROVAL. Il significato di ogni stato è spiegato in Onboarding degli esercenti.

SDK

Accept.sdk.version            // String, e.g. "1.15.0"
Accept.sdk.isProduction       // Boolean
Accept.sdk.deviceId()         // String?  (suspend)
Accept.sdk.minimumAmounts()   // List<MinimumAmount>  (suspend)
MembroRestituisceDescrizione
versionStringLa versione dell'SDK. Leggibile prima di initialize().
isProductionBooleanIndica se initialize() ha impostato la produzione (true) o la sandbox (false).
deviceId()String?L'ID stabile di questo dispositivo, assegnato al primo authenticate() riuscito e conservato finché l'app non viene disinstallata. null prima di allora. Lo indichi nelle richieste di assistenza.
minimumAmounts()List<MinimumAmount>L'importo minimo pagabile per ogni valuta supportata. Ogni voce è currency: String, amount: Long nell'unità minore della valuta.

App plugin

Ogni pagamento con carta passa a Tapaya Terminal, l'app plugin di Tapaya; è sempre obbligatoria e non esiste alcun percorso di pagamento con carta che la salti. Verifichi se è installata, quindi attivi il terminale, oppure apra la scheda nello store affinché l'esercente possa installarla.

A questo scopo usi Accept.plugin.isInstalled(), Accept.plugin.activateTerminal() e Accept.plugin.install(). Il codice e tutti gli esiti dell'attivazione sono descritti in Installare e attivare il terminale.

Legga lo stato attuale del plugin con Accept.plugin.status() oppure disconnetta l'esercente dal plugin con Accept.plugin.logout().

Autorizzazioni

I pagamenti con carta richiedono che l'app host disponga dell'autorizzazione alla posizione (ACCESS_FINE_LOCATION). L'SDK non la richiede al posto Suo: la ottenga con le API di autorizzazione standard di Android prima di chiamare pay().

class PaymentActivity : AppCompatActivity() {
    private val requestLocation = registerForActivityResult(
        ActivityResultContracts.RequestPermission()
    ) { granted ->
        if (granted) launchPaymentFlow() else showPermissionRationale()
    }

    fun startPayment() {
        requestLocation.launch(Manifest.permission.ACCESS_FINE_LOCATION)
    }
}

Se, quando viene eseguito pay(), l'autorizzazione alla posizione manca o la posizione non può essere determinata, il flusso emette PaymentEvent.CreationFailed con causa LocationPermissionRequired, LocationUnavailable o LocationTimeout.

Gestione degli errori

Ogni errore gestito porta uno dei nomi riportati di seguito. In Kotlin ciascuno è una sottoclasse della classe sealed AcceptException; in React Native sono tutti un'unica classe AcceptError il cui code contiene il nome, mentre i campi del payload (minimum, currency, state, …) si trovano sullo stesso oggetto.

Le chiamate asincrone (authenticate, merchant.*, payments.status/cancel/refund, plugin.activateTerminal/status/logout/updateInfo, clear) falliscono con uno di questi. payments.pay() è l'eccezione: non genera mai eccezioni e segnala gli stessi errori come evento CreationFailed che ne riporta la causa.

Tipi di eccezione

EccezioneDescrizione
Ciclo di vita
NotInitializedUna chiamata richiede prima Accept.initialize().
NotAuthenticatedUna chiamata richiede prima Accept.auth.authenticate().
SessionExpiredLa sessione autenticata è scaduta; ripeta l'autenticazione.
UnknownEnvironment(key)Chiave di ambiente non riconosciuta (overload interno di initialize).
Pagamenti
PaymentInProgressUn pay() precedente è ancora in attesa di un risultato.
CurrencyNotAvailableForMerchant(code)Valuta non configurata per l'esercente.
UnsupportedCurrency(code)Valuta non riconosciuta dall'SDK.
AmountBelowMinimum(minimum, currency)Importo inferiore al minimo configurato.
TransactionTimeoutOutOfRange(transactionTimeout)transactionTimeout al di fuori dell'intervallo da 0 a 120 secondi.
PaymentCreationFailed(cause)Qualsiasi altro errore durante la creazione di un pagamento.
PaymentNotFoundToken di status()/cancel()/refund() sconosciuto al backend.
Posizione
LocationPermissionRequiredL'app host non dispone dell'autorizzazione alla posizione.
LocationUnavailableNessun provider è riuscito a determinare la posizione.
LocationTimeoutPosizione non determinata in tempo.
Plugin / terminale
PluginUnavailableApp plugin non installata, oppure non è stato possibile collegarsi al suo servizio.
PluginTimeoutIl plugin non ha risposto in tempo.
ActivationInProgressUn activateTerminal() precedente è ancora in attesa di un risultato.
NoTidsAvailableForMerchantAll'esercente non resta alcun terminale (TID) non assegnato da attivare.
PluginAlreadyAuthenticatedPlugin già autenticato per questo esercente.
PluginMerchantMismatchPlugin autenticato con un altro esercente; chiami prima plugin.logout().
PluginNotReadyForPayments(status)pay() è stato eseguito mentre il plugin non era in PluginStatus.ReadyForPayments; status riporta lo stato attuale.
MerchantOnboardingIncomplete(state)L'esercente non ha completato l'onboarding.
Sistema
NoInternetConnectionIl dispositivo non ha connettività di rete.
Unknown(cause)Qualsiasi errore che l'SDK non riconosce come proprio.

Risultato o eccezione

Un pagamento che raggiunge il terminale ma non va a buon fine non è un'eccezione: arriva come PaymentEvent.Result con PayResult.Declined, Canceled o Failed(reason). Allo stesso modo, l'attivazione del terminale restituisce ActivateTerminalResult.Failed(reason).

Gestione delle eccezioni

Racchiuda la chiamata in un blocco try/catch e gestisca separatamente i casi specifici che Le interessano, ricorrendo a un catch generico per il resto. Kotlin distingue in base alla sottoclasse dell'eccezione; React Native verifica con AcceptError.is() ed esegue uno switch su code.

try {
    val status = Accept.payments.status(paymentToken)
} catch (e: SessionExpired) {
    // Re-authenticate
} catch (e: NoInternetConnection) {
    // Ask the user to check connectivity
} catch (e: AcceptException) {
    // Handle any other SDK error
    Log.e("Payment", "Error: ${e.message}")
}

Logging

Durante lo sviluppo attivi il logging di debug per diagnosticare i problemi.

Accept.setDebugLoggingEnabled(true)

Disconnessione

Cancelli tutto lo stato dell'SDK salvato localmente (token di autenticazione, ID del dispositivo, configurazione in cache) e riporti lo stato dell'SDK a idle. Esegua questa operazione quando l'utente si disconnette. Per disconnettere l'esercente anche dall'app Tapaya Terminal, chiami prima Accept.plugin.logout().

Accept.plugin.logout() // suspend; signs out of the Tapaya Terminal app
Accept.clear()         // suspend; clears local SDK state
Manca qualcosa in questa pagina?Richieda una funzionalità. Alleghiamo questa pagina, così il team vede il contesto.