Payments guide

Use case

Bind observations to a payment attempt

Use the order or payment attempt created by your backend as the correlation boundary. Collect close to confirmation so transaction-time observations remain fresh.

Payment event flow

1. Create payment attempt
2. Open confirmation UI
3. Start observation window
4. Collect before confirm
5. Send with action_id

Use one payment_attempt ID for both collections. Generate a separate idempotency key for the event upload.

Purpose-bound profile

import { consentFor, DeviceIntel } from "react-native-device-risk-signals";

const paymentIntel = new DeviceIntel({
  consent: consentFor([
    "device_identity",
    "application",
    "os_integrity",
    "device_security_posture",
    "network",
    "runtime",
    "transaction_safety",
  ]),
  config: {
    probes: {
      application: {
        fields: {
          include: [
            "appVersion",
            "appBuild",
            "bundleId",
            "installerPackage",
            "signingCertificateSha256",
            "isDebuggable",
          ],
        },
      },
      transaction_safety: { enabled: true, timeoutMs: 900 },
    },
  },
});

Field projection limits the returned event, but native data is collected before projection. Disable an entire probe when its collection itself is outside the approved purpose.

Two-stage transaction window

On Android, the first enabled transaction_safety collection starts lazy screenshot and obscured-touch observation. The second collection reads what happened during the protected screen.

// When the confirmation screen opens:
await paymentIntel.collect({
  sessionId: paymentAttempt.id,
});

// Immediately before the user confirms:
const observations = await paymentIntel.collect({
  sessionId: paymentAttempt.id,
  clientId: authenticatedAccountId,
});

Keep this probe disabled until it has been calibrated on representative physical devices for the exact payment UI.

Transport through the host application

await api.post(
  "/api/v1/device-signal-events",
  {
    action_id: paymentAttempt.id,
    action_type: "payment_attempt",
    sdk_version: SDK_VERSION,
    platform: Platform.OS,
    observations,
  },
  { headers: { "Idempotency-Key": eventUploadId } },
);

The SDK performs no request. Use the application's authenticated API client, retry policy, certificate controls, and request-size limits.

Backend handling

Validate binding

Confirm that action_id belongs to the authenticated account, is open, and matches the payment attempt being confirmed.

Validate freshness

Compare collected_at, server receipt time, payment creation time, and the allowed confirmation window.

Combine evidence

Use raw observations alongside amount, currency, account history, payment instrument state, velocity, and server-side network evidence.

The SDK does not calculate a risk score or approve or decline a payment. Never make a payment decision from one device observation, and preserve a review or recovery path.

Optional Android capture permissions

DETECT_SCREEN_CAPTURE on Android 14+ and DETECT_SCREEN_RECORDING on Android 15+ are host-declared permissions. The library declares neither and never shows a permission prompt. Without them, related fields are omitted.

See the exact permission matrix.