# anybill SDK Integration

This project integrates the anybill SDK for digital receipts. This file
provides context for AI coding agents working on the integration.

## What is anybill

anybill is a digital receipt solution for retail merchants. The Frontend SDK
enables consumer-facing apps to receive, display, and manage digital receipts
issued at point of sale.

## Official documentation

- Overview and machine-readable index: https://developer.anybill.de/llms.txt
- Frontend SDKs: https://developer.anybill.de/the_anybill_sdk/overview.md
- Android: https://developer.anybill.de/the_anybill_sdk/android_integration.md
- iOS: https://developer.anybill.de/the_anybill_sdk/ios_integration.md
- Flutter: https://developer.anybill.de/the_anybill_sdk/flutter_integration.md
- React Native: https://developer.anybill.de/the_anybill_sdk/react_native_integration.md
- Web: https://developer.anybill.de/the_anybill_sdk/web_integration.md
- Partner Platform API: https://developer.anybill.de/partner_platform_api/

When in doubt, fetch the relevant `.md` page and follow the official flow.

## Authentication model

The Frontend SDK is initialised with a short-lived access token that the
customer backend mints via the anybill Partner Platform API
(`POST /v3/user/token`). The token request accepts either:

- `externalId` (recommended): any stable identifier from the customer's
  own system (customer number, loyalty card number, user id). anybill
  creates the underlying anybill user transparently on first use, either
  on this token request or on the first receipt that is sent with the
  same `externalId` via the Vendor API `POST /v3/bill` endpoint. No
  pre-registration step is required and no anybill user id has to be
  persisted on the customer side.
- `userId`: an anybill user id obtained from an explicit
  `POST /v3/user` call. Use this only if the integration has to manage
  the anybill user life cycle explicitly (for example to delete the
  user on request).

Pick the `externalId` variant unless there is a concrete reason to
manage anybill users manually.

The SDK handles token refresh internally. When refresh fails, the SDK calls
a customer-provided callback; the customer app must then request a new
token from the customer backend and pass it back to the SDK.

**Never embed anybill API keys or partner credentials in the client app.**
Token minting always happens server-side.

## SDK initialization contract

The SDK requires:
- An environment (sandbox / production)
- A valid access token obtained via the flow above
- A token-refresh callback that returns a new token when called

Consult the platform-specific integration page for the exact method names
and types.

## Common pitfalls

- Do not hardcode tokens. Tokens are short-lived by design.
- Do not call the anybill App API directly from the client. Use the SDK.
- Do not create anybill users from the client. Token requests (and, if
  needed, explicit user creation) are a backend responsibility via the
  Partner Platform API.
- Do not introduce a separate "anybill user id" field in your data model
  unless you actually use the explicit `POST /v3/user` flow. With the
  `externalId` flow the existing customer id is enough.
- Treat token-refresh failures as a signal to re-authenticate the user,
  not as a transient error to retry blindly.

## When generating code

- Prefer the idiomatic patterns of the host app (e.g. Hilt/Koin on Android,
  Swift concurrency on iOS, Provider/Riverpod on Flutter).
- Wrap SDK calls in a thin adapter layer so the rest of the app does not
  depend on anybill types directly. This keeps the integration swappable
  and testable.
- Surface SDK errors through the app's existing error-handling pipeline;
  do not introduce a parallel error path.

## Out of scope for AI agents

- Do not generate production API keys or tokens.
- Do not modify the customer backend's token-minting endpoint without
  explicit human review.
- Do not change authentication flows based on assumptions. If the flow
  is unclear, fetch the relevant doc page and ask the developer.
