Overview
Tap to Pay lets a merchant accept contactless card payments on a standard phone — no separate card terminal. The card is read by the phone's NFC hardware through the Adyen Tap to Pay (SoftPOS) SDK, while Straumur handles session provisioning, the charge, and settlement.
This guide covers the Tap to Pay integrator API: you embed the Adyen Tap to Pay SDK in your own app and drive it through Straumur.
Adyen expires every Tap to Pay SDK version six months after its release. Once the version in your app expires, Tap to Pay payments stop working on every phone running it (card reader transactions without PIN still go through). Twelve months after expiry the version is withdrawn entirely and all transactions are blocked.
An app you build once and leave alone will stop taking payments within six months. This is not a warning you can defer:
- Plan a recurring SDK upgrade and app release from the start, and get the new version onto your merchants' phones before the old one expires.
- Adyen does not backport fixes to older minor or patch versions, so the upgrade path is always forward to the latest version.
- Adyen publishes each version's expiry date in that version's release notes. Track it for the version you ship.
Who this is for
The integrator API is for anyone embedding Tap to Pay in their own app, authenticated by an API key:
- Merchants building their own point-of-sale app — the key is scoped to that merchant's own stores.
- Partners integrating on behalf of the merchants they serve — the key spans every merchant on the partner's contracts.
The API is identical for both. What differs is scope: every request names the target store by its MID, and the key may only act on stores whose contract it is authorized for.
How it fits together
Your app owns the operator experience (who is signed in, how they authenticate) behind your own backend. Your backend calls Straumur with the API key — Straumur never talks to the device directly. Every charge still flows through Straumur, so you get one consistent record and settlement.
A payment is three steps:
- Create a session. Your app asks the SDK for a
setupToken, sends it to your backend, which calls Straumur (/sessions). Straumur returns thesdkDatathe SDK needs to establish its Adyen SoftPOS session. - Take a payment. Your backend calls Straumur (
/payment) with the amount in minor units and the device's POIID; Straumur pre-creates the charge and returns a ready-to-runSaleToPOIRequestthat the SDK executes to read the card. - Receive the result. Straumur owns the amount and reference, so the authorization result arrives on your payment webhook exactly as it does for any other Straumur payment.
Because Straumur builds the charge request server-side, the amount and reference are always authoritative — the device app cannot alter them.
Retiring a device
To stop using a phone (lost, replaced or retired), have your backend stop serving it: without new sessions and payments from your backend, it cannot take payments. Straumur can also disable a device on request. A disabled device is rejected on both calls with error 2047, and the same installation cannot be registered again.
Sample integration
A complete, runnable reference is on GitHub: straumur-tap-to-pay-sample.
It contains a small backend that holds the API key and brokers both calls, plus two merchant apps — native Android (Kotlin) and React Native — that drive the Adyen SDK. Each app is a single file, and both share the same backend. Start from it: it already sends amounts in minor units and forwards the device details on each session.
The sample is split that way deliberately, and your integration should be too: your API key is a bearer credential for your whole account and must never ship inside the app, where it can be extracted from the binary. Keep it on your backend, as the sample does.
Adyen does not publish React Native or Flutter wrappers for the Tap to Pay SDK, so those stacks need a native bridge. The sample's React Native app includes a small Kotlin bridge you can reuse.
Prerequisites
Before you start, make sure you have:
- The Adyen Tap to Pay / SoftPOS SDK integrated in your app (iOS and/or Android), and a plan to keep it up to date (see the warning above).
- An API key (
X-API-key) whose contract covers the merchant store you will transact on. See API Keys. - The merchant store boarded to Adyen and with Tap to Pay enabled on its contract. Straumur (or your partner manager) handles boarding.
- The store's MID, which identifies the store on every call.
Authentication
Every request authenticates with your API key in the X-API-key header and targets a store by its MID:
curl -X POST https://checkout-api.staging.straumur.is/api/v1/taptopay/integrator/sessions \
-H "X-API-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"storeMid": "1234567890", ...}'
If the MID does not resolve to a store your key is authorized for, the request is rejected with error 2045 — the same response whether the store does not exist or is simply outside your scope, so keys can't probe MIDs they don't own.
Endpoints
| Endpoint | Method | Purpose |
|---|---|---|
/api/v1/taptopay/integrator/sessions | POST | Create a SoftPOS session for a device. |
/api/v1/taptopay/integrator/payment | POST | Start a charge on a device. |
All endpoints share the base URL https://checkout-api.staging.straumur.is (staging).
Errors
Errors return HTTP 400 with the standard Checkout API error body:
{
"errorMessage": "Tap to Pay device is not active. Value: [A8E90121-598F-4553-89E0-B5492AFD9D37]",
"responseIdentifier": "e3605f81-6b09-4ce1-83ad-5a8d49f3cd44",
"errorCode": "2047"
}
Branch on errorCode; errorMessage is English text for your logs, not for display. Quote the responseIdentifier when contacting Straumur support. Each endpoint page lists the errors it returns, and Errors has the full list.