---
name: flinkey-integration
description: >-
  Build flinkey partner integrations — backend API, webhooks, mobile SDK, Box Commands.
  Use when implementing flinkey API authentication, car/user/assignment lifecycle,
  webhook handling, Tapkey Mobile SDK integration, or Box Commands. Use when the user
  mentions flinkey, flinkey API, flinkey BLE Box, Tapkey SDK, WITTE Mobile Library,
  assignment, digital key, or box command in a vehicle access context.
---

# flinkey Partner Integration

## Integration model

- Partner backend calls the flinkey API (REST, OAuth2)
- Partner mobile app uses Tapkey Mobile SDK for local BLE access
- Assignments are asynchronous — finalized through webhooks
- Anonymous flinkey users are the default for partner integrations

```
Customer -> Partner App -> Partner Backend -> flinkey API
                                          -> Webhook -> Backend
                              App -> Tapkey SDK -> flinkey BLE Box
```

## Environments

| Param | UAT | PROD |
|---|---|---|
| API | `https://api-uat.flinkey.de/v3` | `https://api.flinkey.de/v3` |
| Portal | `https://portal-uat.flinkey.com` | `https://portal.flinkey.com` |

Always start on UAT. All credentials are environment-specific.

## Credential rules

**Never hardcode:** API Manager credentials, flinkey-API-Key, bearer tokens, SDK Keys, webhook secrets, IdTokens, Tapkey access tokens, digital keys

**Never expose to mobile app:** API Manager credentials, flinkey-API-Key, bearer token, webhook secret

**Never log:** any of the above

Use environment variables:

```bash
FLINKEY_API_BASE_URL=https://api-uat.flinkey.de/v3
FLINKEY_API_MANAGER_USERNAME={{FLINKEY_API_MANAGER_USERNAME}}
FLINKEY_API_MANAGER_PASSWORD={{FLINKEY_API_MANAGER_PASSWORD}}
FLINKEY_API_KEY={{flinkeyApiKey}}
FLINKEY_CUSTOMER_ID={{FLINKEY_CUSTOMER_ID}}
FLINKEY_WEBHOOK_SECRET={{FLINKEY_WEBHOOK_SECRET}}
TAPKEY_SDK_KEY={{TAPKEY_SDK_KEY}}
```

## Backend recipes

### Authentication
1. Read credentials from secret storage
2. `POST /oauth2/token` with username, password, flinkey-API-Key
3. Store bearer token in backend memory only
4. Refresh when expired

### Customer context
1. `GET /customers` with bearer token
2. Select correct customer
3. Use `Customer-ID` header for all scoped calls

### Car lifecycle
1. Check local mapping for partner_vehicle_id
2. If exists, validate with `GET /cars/{carId}`
3. If missing, `PUT /cars` to create
4. Persist partner_vehicle_id -> flinkey_car_id

### User lifecycle
1. Check local mapping for partner_customer_id
2. If exists, reuse flinkey_user_id
3. If missing, `PUT /users` (type: Anonymous)
4. Persist partner_customer_id -> flinkey_user_id

### Assignment lifecycle
1. Verify customer permission
2. `PUT /assignments` with carId, userId, start, end
3. Store as pending
4. Wait for webhook result
5. If operationSucceeded=true, mark active
6. If false, mark failed, store errorMessage

### Webhook handling
1. Receive HTTPS POST
2. Validate secret header
3. Parse JSON (checksum, assignmentId, customerId, operationSucceeded)
4. Process idempotently
5. Update assignment state
6. Return 200/204

## Required mappings

```
Customer: partner_customer_id -> flinkey_user_id + environment
Vehicle:  partner_vehicle_id -> flinkey_car_id + environment
Assignment: partner_access_id -> flinkey_assignment_id + status + webhook state
```

## Mobile SDK

1. Backend provides IdToken via `POST /appsdk/idtoken`
2. App performs Tapkey SDK token exchange (AppAuth)
3. SDK resolves physical lock ID
4. SDK authenticates over BLE
5. Vehicle access granted/denied

## Box Commands

Local BLE commands via WITTE Mobile Library — not REST endpoints:
- `buildUnlockCarUnlockBox(readNfc)` — unlock vehicle and box
- `buildUnlockCarLockBox(readNfc)` — unlock vehicle, keep box locked
- `buildLockCarLockBox(readNfc)` — lock both
- `buildStatus(readNfc)` — query status
- `buildReadNfc()` — read NFC UIDs

Parse response with `BoxFeedbackV3Parser`. Convert to user-facing states.

## Agent behavior

- **Stop** when credentials, IDs or config are missing — do not invent values
- **Backend owns** all authorization decisions
- **Assignments are async** — never treat API response as final
- **Use placeholders** in documentation and generated code

## Reference documentation

- Full docs: see `/home/goldschm/cursor/flinkey-developer-docs/src/content/docs/`
- OpenAPI spec: see `/home/goldschm/cursor/flinkey-developer-docs/schemas/openapi.json`
- IKB source: see `/home/goldschm/cursor/flinkey-api-uat-validation/flinkey_ikb_20.md`
- For detailed recipes and prompt templates, see [recipes.md](recipes.md)
