# 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/api_v3.md

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`). Internally anybill always stores both an
`anybillUserId` and an `externalId` for every user. The two integration
variants differ in *how* that user record is created, not in which id is
used afterwards:

- **Implicit user creation via `externalId` (recommended):** Pass any
  stable identifier from the customer's own system (customer number,
  loyalty card number, user id) as `externalId`. The anybill user is
  created on the first receipt that is sent with that `externalId` via
  the Vendor API `POST /v3/bill` endpoint. The `POST /v3/user/token`
  call itself does **not** create a user; it returns HTTP 404 until a
  matching user exists. No pre-registration step is required and no
  anybill user id has to be persisted on the customer side.
  *This flow has to be enabled per tenant on the anybill side. Contact
  `dev@anybill.de` if it is not active for your account yet.*
- **Explicit user creation via `POST /v3/user`:** Create the anybill
  user up front, store the returned `userId` alongside your own user
  record and use it for subsequent token requests. Use this if you need
  to control the user life cycle yourself (for example to pre-register
  users before their first receipt, or to run explicit user management
  operations).

Prefer the implicit `externalId` flow unless you have a concrete reason
to manage anybill users explicitly. Both flows result in the same user
record on anybill's side.

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

Always consult the platform-specific integration page for the exact
method names, types and up-to-date examples. The snippets below are
starting points, not copy-paste-ready production code.

### Android (Kotlin) - token-based login

Reference: https://developer.anybill.de/the_anybill_sdk/android_integration.md

```kotlin
val result = YourApi.getTokenForUser() // accessToken, refreshToken, expiresIn
val user = TokenUser(result.accessToken, result.refreshToken, result.expiresIn)

when (val tokenLogin = AuthProvider.loginTokenUser(user)) {
    is ApiResult.EmptySuccess -> Unit // continue
    is ApiResult.GenericError -> Unit // handle error
    is ApiResult.NetworkError -> Unit // handle error
}
```

### iOS (Swift) - token-based login

Reference: https://developer.anybill.de/the_anybill_sdk/ios_integration.md

```swift
let result = await YourApi.getTokenForUser()
let tokenUser = TokenUser(
    accessToken: result.accessToken,
    expiresIn: result.expiresIn,
    refreshToken: result.refreshToken
)

authProvider.loginTokenUser(tokenUser: tokenUser) { result in
    switch result {
    case .success: break // continue
    case .failure(let error): break // handle error.type
    }
}
```

### Flutter (Dart) - token-based login

Reference: https://developer.anybill.de/the_anybill_sdk/flutter_integration.md

```dart
final tokens = await YourApi.getTokenForUser();

final loginCall = await AuthProvider.instance.loginUserWithToken(
  accessToken: tokens.accessToken,
  refreshToken: tokens.refreshToken,
  expiresIn: tokens.expiresIn,
);
```

### React Native (TypeScript) - token-based login

Reference: https://developer.anybill.de/the_anybill_sdk/react_native_integration.md

```ts
const { loginWithToken } = useAuth();

const result = await YourApi.getTokenForUser();
const tokenUser: TokenUser = {
  accessToken: result.accessToken,
  refreshToken: result.refreshToken,
  expiresIn: result.expiresIn,
};

const loginResult = await loginWithToken(tokenUser);
```

### Web (TypeScript) - token-based login

Reference: https://developer.anybill.de/the_anybill_sdk/web_integration.md

```ts
import { ApiConfig, AuthProvider } from "@anybill/base";

ApiConfig.initialize(clientId, environment);

await AuthProvider.instance.loginTokenUser(accessToken, refreshToken);
```

## 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
  implicit `externalId` flow the existing customer id is enough.
- Expect the first `POST /v3/user/token` call for a new `externalId` to
  return HTTP 404 until at least one receipt with that `externalId` has
  been sent via the Vendor API. Handle this by retrying once a receipt
  is known to exist, not by creating the user from the client.
- 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.
