> ## Documentation Index
> Fetch the complete documentation index at: https://docs.rinne.com.br/llms.txt
> Use this file to discover all available pages before exploring further.

# Going to production

> Move a Tap on Phone integration from the sandbox to production: production artifact and environment, install source and device integrity, key handling, permissions for the Play Console, what the SDK sends, and the go-live checklist.

Production differs from the sandbox in what Rinne provides, in how strictly the device is checked, and in what your app has to declare on Google Play. Nothing in your integration code changes except the artifact and the environment.

## What Rinne provides at launch

When your integration is approved for launch, Rinne provides:

* The **production artifact**, `rinne-sdk-checkout-production`, on the same version as the sandbox artifact you tested with.
* A **production API key** for your backend, with the `tap_on_phone.*` permission.
* A **merchant enabled for contactless capture** in production.

Until then, production calls fail at `getReady` with `TAP_ON_PHONE_NOT_ENABLED` or `ACCESS_TOKEN_REJECTED`, and your app never reaches a card.

## Switch the environment

Replace the artifact and the environment. The production artifact reaches production only, and the sandbox artifact cannot reach it: asking a sandbox build for `Environment.PRODUCTION` throws `IllegalStateException` at `getReady`, which is a build misconfiguration to fix, not an error to handle.

<CodeGroup>
  ```kotlin build.gradle.kts theme={null}
  dependencies {
      implementation("br.com.rinne:rinne-sdk-checkout-production:0.1.0-alpha.4")
  }
  ```

  ```kotlin SalesActivity.kt theme={null}
  Payments.getReady(
      context = this,
      accessTokenProvider = { backend.fetchTapOnPhoneToken() },
      config = config,
      environment = Environment.PRODUCTION,
  ) { result -> /* ReadyResult.Ready | ReadyResult.Failed */ }
  ```
</CodeGroup>

Your backend mints production tokens at `https://api.rinne.com.br/core/v1/terminal/token` with the production key. Keep the sandbox and production keys on separate backend configurations so a sandbox key never reaches a production build.

## Install source and device integrity

Production enforces the integrity check the sandbox relaxes. Before every transaction the card reader verifies the device and the app that runs it:

* **Install from Google Play.** The production build must be installed from Google Play; the internal testing track is fine. A sideloaded APK fails the install-source check unless you name its installer package in `installerPackageNames` on `getReady`, which is meant for managed-device deployments, not for testing.
* **Device integrity.** The device must pass Play Integrity at `MEETS_DEVICE_INTEGRITY` or better; `MEETS_STRONG_INTEGRITY` is recommended for financial use. Rooted devices, unlocked bootloaders, custom ROMs and emulators are refused with `ATTESTATION_FAILED`.
* **Signing.** Sign the app with APK signature scheme v2 or newer, which Play App Signing already does. A build signed only with the legacy v1 scheme fails attestation.

<Warning>
  `ATTESTATION_FAILED` is not retriable. Your app should tell the merchant this device or this installation cannot take payments, and point them at a supported phone or at reinstalling from Google Play, rather than offering a retry.
</Warning>

## Keys and tokens

* The Rinne API key stays on your backend. The app only ever holds a token minted at `POST /v1/terminal/token`, valid for fifteen minutes and useless on any other endpoint.
* The SDK asks your `accessTokenProvider` for a fresh token on every handshake and never stores one, so there is no refresh loop to run.
* Revoking the key stops minting immediately; tokens already minted expire on their own within fifteen minutes.

## Release builds and R8

The SDK ships consumer keep rules that protect its public API and the enum constant names it matches at runtime. A release build with R8 needs nothing more. Run your production test on the minified build, not only on debug: R8 removing something reachable only at runtime shows up nowhere else.

## Permissions and the Play Console questionnaire

Your merged manifest carries nine permissions after adding the SDK. Four come from the SDK and five from the certified card-reader library, which every host receives.

| Permission                   | Why it is there                                                                          |
| ---------------------------- | ---------------------------------------------------------------------------------------- |
| `NFC`                        | Read contactless cards                                                                   |
| `VIBRATE`                    | Haptic feedback during the tap and on approval                                           |
| `INTERNET`                   | Authorisation and registration of the transaction                                        |
| `ACCESS_NETWORK_STATE`       | Detect a missing or unvalidated network before a sale                                    |
| `ACCESS_FINE_LOCATION`       | Required by the card reader to authorise a transaction; asked at runtime by the checkout |
| `ACCESS_COARSE_LOCATION`     | Declared alongside fine location                                                         |
| `HIGH_SAMPLING_RATE_SENSORS` | Tamper detection by the card reader                                                      |
| `RECEIVE_BOOT_COMPLETED`     | The card reader's own housekeeping after a reboot                                        |
| `HIDE_OVERLAY_WINDOWS`       | Keep other apps from drawing over the PIN pad                                            |

Confirm the list against a real build before filling in the questionnaire:

```bash theme={null}
./gradlew :app:assembleRelease
grep uses-permission app/build/intermediates/merged_manifest/release/*/AndroidManifest.xml
```

## What the SDK sends

Besides the transaction itself, the SDK reports its own reliability to Rinne: which stage a payment reached, which error code ended it, timings, the device model and OS version, a random per-run session id and the merchant id. It exists for the failures the backend can never see, such as attestation failures and network faults before a transaction is registered. It never includes cardholder data, it persists nothing on the device, and it cannot fail a sale. For the data-safety form, treat it as diagnostic data tied to the merchant account, never to the cardholder or the operator; when the merchant is an individual (a CPF account), that account identifies a person, so classify it according to your own data practices.

The card reader also keeps its own logs on the device for support triage. They never leave the phone.

## Versions

Pin the SDK version Rinne names for your launch, and upgrade only to versions Rinne announces as live. A new card-reader version needs its card configuration published on Rinne's side first; a build on a version without one fails at `getReady` with `EMV_CONFIG_UNAVAILABLE`.

## Go-live checklist

* The production artifact on the version Rinne named.
* `environment = Environment.PRODUCTION` in the production build only.
* Production API key on the backend; the token endpoint called on `api.rinne.com.br`.
* A production sale, a PIN sale, a declined sale and a refund verified on a phone installed from the internal testing track.
* The minified build tested end to end.
* The Play Console questionnaire answered with the nine permissions and the diagnostic data above.
* `ATTESTATION_FAILED`, `TAP_ON_PHONE_NOT_ENABLED` and `ACCESS_TOKEN_REJECTED` handled with the right message for each, as in [Results and errors](/tap-on-phone/android/results-and-errors).
* Reconciliation by `requestId` in place for process deaths.

Questions during launch go to [suporte@rinne.com.br](mailto:suporte@rinne.com.br).
