Files
tink-demo/src/demo_data.py
Henrik Jess Nielsen ab591be464 feat: Tink open banking demo — 6-step API walkthrough
Demonstrates the full Tink integration flow for open banking:
  Step 1 — Client credentials auth (app token)
  Step 2 — Create Tink user with external_user_id
  Step 3 — Connect bank via Tink Link OAuth redirect
  Step 4 — List accounts (v2 endpoint)
  Step 5 — List transactions (v2 endpoint, cursor pagination)
  Step 6 — Webhooks (register endpoint, receive events)

Built with Python / FastAPI + Jinja2 templates.
Each step shows live JSON responses, cURL examples and API version badges.
Includes server-side token store (prevents session cookie overflow),
asyncio lock on OAuth callback, and demo mode with realistic mock data.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-23 02:08:27 +02:00

229 lines
9.1 KiB
Python

"""
Realistic mock data for demo mode.
Used when DEMO_MODE=true or when no bank is connected.
Data mimics real Tink API v2 responses for a Danish user.
"""
MOCK_CREDENTIALS = {
"credentials": [
{
"id": "dk-demobank-cred-001",
"providerName": "dk-demobank-open-banking-embedded",
"type": "PASSWORD",
"status": "UPDATED",
"statusUpdated": "2026-05-22T08:00:00Z",
"updated": "2026-05-22T08:00:00Z",
"fields": {"username": "demo_user_001"},
}
]
}
MOCK_ACCOUNTS = {
"accounts": [
{
"id": "acc-8f3a2e1b-demo",
"name": "Løbende konto",
"type": "CHECKING",
"balances": {
"booked": {
"amount": {"value": {"unscaledValue": "4275850", "scale": "2"}, "currencyCode": "DKK"},
},
"available": {
"amount": {"value": {"unscaledValue": "4275850", "scale": "2"}, "currencyCode": "DKK"},
},
},
"identifiers": {
"iban": {"iban": "DK5000400440116243"},
"financialInstitution": {"accountNumber": "0440116243"},
},
"dates": {"lastRefreshed": "2026-05-22T08:00:00Z"},
"financialInstitutionId": "dk-demobank",
},
{
"id": "acc-9c4d3f2a-demo",
"name": "Opsparing",
"type": "SAVINGS",
"balances": {
"booked": {
"amount": {"value": {"unscaledValue": "18500000", "scale": "2"}, "currencyCode": "DKK"},
},
},
"identifiers": {
"iban": {"iban": "DK5000400440116244"},
"financialInstitution": {"accountNumber": "0440116244"},
},
"dates": {"lastRefreshed": "2026-05-22T08:00:00Z"},
"financialInstitutionId": "dk-demobank",
},
],
"nextPageToken": "",
}
MOCK_TRANSACTIONS = {
"transactions": [
{
"id": "tx-001-demo",
"accountId": "acc-8f3a2e1b-demo",
"amount": {"value": {"unscaledValue": "-89900", "scale": "2"}, "currencyCode": "DKK"},
"dates": {"booked": "2026-05-22", "value": "2026-05-22"},
"description": "Spotify AB",
"status": "BOOKED",
"categories": {"pfm": {"id": "expenses.entertainment.streaming", "name": "Streaming"}},
"merchantInformation": {"merchantName": "Spotify", "merchantCategoryCode": "7995"},
"types": {"financialInstitutionTypeCode": "CSCD", "type": "DEFAULT"},
},
{
"id": "tx-002-demo",
"accountId": "acc-8f3a2e1b-demo",
"amount": {"value": {"unscaledValue": "-45000", "scale": "2"}, "currencyCode": "DKK"},
"dates": {"booked": "2026-05-21", "value": "2026-05-21"},
"description": "Netto Supermarked",
"status": "BOOKED",
"categories": {"pfm": {"id": "expenses.food.groceries", "name": "Dagligvarer"}},
"merchantInformation": {"merchantName": "Netto", "merchantCategoryCode": "5411"},
"types": {"type": "DEFAULT"},
},
{
"id": "tx-003-demo",
"accountId": "acc-8f3a2e1b-demo",
"amount": {"value": {"unscaledValue": "3500000", "scale": "2"}, "currencyCode": "DKK"},
"dates": {"booked": "2026-05-20", "value": "2026-05-20"},
"description": "Løn maj 2026",
"status": "BOOKED",
"categories": {"pfm": {"id": "income.salary", "name": "Løn"}},
"types": {"type": "DEFAULT"},
},
{
"id": "tx-004-demo",
"accountId": "acc-8f3a2e1b-demo",
"amount": {"value": {"unscaledValue": "-120000", "scale": "2"}, "currencyCode": "DKK"},
"dates": {"booked": "2026-05-19", "value": "2026-05-19"},
"description": "Matas Strøget",
"status": "BOOKED",
"categories": {"pfm": {"id": "expenses.personal.health", "name": "Helse & Skønhed"}},
"merchantInformation": {"merchantName": "Matas", "merchantCategoryCode": "5912"},
"types": {"type": "DEFAULT"},
},
{
"id": "tx-005-demo",
"accountId": "acc-8f3a2e1b-demo",
"amount": {"value": {"unscaledValue": "-8500000", "scale": "2"}, "currencyCode": "DKK"},
"dates": {"booked": "2026-05-01", "value": "2026-05-01"},
"description": "Husleje maj",
"status": "BOOKED",
"categories": {"pfm": {"id": "expenses.housing.rent", "name": "Husleje"}},
"types": {"type": "DEFAULT"},
},
{
"id": "tx-006-demo",
"accountId": "acc-8f3a2e1b-demo",
"amount": {"value": {"unscaledValue": "-35000", "scale": "2"}, "currencyCode": "DKK"},
"dates": {"booked": "2026-05-18", "value": "2026-05-18"},
"description": "DSB Rejse",
"status": "BOOKED",
"categories": {"pfm": {"id": "expenses.transport.public", "name": "Offentlig transport"}},
"merchantInformation": {"merchantName": "DSB", "merchantCategoryCode": "4112"},
"types": {"type": "DEFAULT"},
},
{
"id": "tx-007-demo",
"accountId": "acc-8f3a2e1b-demo",
"amount": {"value": {"unscaledValue": "-19900", "scale": "2"}, "currencyCode": "DKK"},
"dates": {"booked": "2026-05-17", "value": "2026-05-17"},
"description": "Netflix International",
"status": "BOOKED",
"categories": {"pfm": {"id": "expenses.entertainment.streaming", "name": "Streaming"}},
"merchantInformation": {"merchantName": "Netflix", "merchantCategoryCode": "7995"},
"types": {"type": "DEFAULT"},
},
{
"id": "tx-008-demo",
"accountId": "acc-8f3a2e1b-demo",
"amount": {"value": {"unscaledValue": "-62500", "scale": "2"}, "currencyCode": "DKK"},
"dates": {"booked": "2026-05-16", "value": "2026-05-16"},
"description": "Fakta Falkoner",
"status": "BOOKED",
"categories": {"pfm": {"id": "expenses.food.groceries", "name": "Dagligvarer"}},
"merchantInformation": {"merchantName": "Fakta", "merchantCategoryCode": "5411"},
"types": {"type": "DEFAULT"},
},
{
"id": "tx-009-demo",
"accountId": "acc-8f3a2e1b-demo",
"amount": {"value": {"unscaledValue": "-15000", "scale": "2"}, "currencyCode": "DKK"},
"dates": {"booked": "2026-05-23", "value": "2026-05-23"},
"description": "7-Eleven Nørreport",
"status": "PENDING",
"categories": {"pfm": {"id": "expenses.food.restaurants", "name": "Mad & Drikke"}},
"merchantInformation": {"merchantName": "7-Eleven", "merchantCategoryCode": "5499"},
"types": {"type": "DEFAULT"},
},
],
"nextPageToken": "",
}
MOCK_EVENTS_BOOKED = {
"events": [
{
"id": "evt-booked-001",
"type": "account-booked-transaction",
"accountId": "acc-8f3a2e1b-demo",
"created": "2026-05-22T08:12:33Z",
"transaction": {
"id": "tx-001-demo",
"description": "Spotify AB",
"amount": {"value": {"unscaledValue": "-89900", "scale": "2"}, "currencyCode": "DKK"},
"status": "BOOKED",
"dates": {"booked": "2026-05-22"},
},
},
{
"id": "evt-booked-002",
"type": "account-booked-transaction",
"accountId": "acc-8f3a2e1b-demo",
"created": "2026-05-21T14:22:10Z",
"transaction": {
"id": "tx-002-demo",
"description": "Netto Supermarked",
"amount": {"value": {"unscaledValue": "-45000", "scale": "2"}, "currencyCode": "DKK"},
"status": "BOOKED",
"dates": {"booked": "2026-05-21"},
},
},
],
"nextPageToken": "",
}
MOCK_EVENTS_ALL = {
"events": [
{
"id": "evt-pending-001",
"type": "account-transaction",
"accountId": "acc-8f3a2e1b-demo",
"created": "2026-05-23T11:05:44Z",
"transaction": {
"id": "tx-009-demo",
"description": "7-Eleven Nørreport",
"amount": {"value": {"unscaledValue": "-15000", "scale": "2"}, "currencyCode": "DKK"},
"status": "PENDING",
"dates": {"booked": "2026-05-23"},
},
},
{
"id": "evt-booked-001",
"type": "account-booked-transaction",
"accountId": "acc-8f3a2e1b-demo",
"created": "2026-05-22T08:12:33Z",
"transaction": {
"id": "tx-001-demo",
"description": "Spotify AB",
"amount": {"value": {"unscaledValue": "-89900", "scale": "2"}, "currencyCode": "DKK"},
"status": "BOOKED",
"dates": {"booked": "2026-05-22"},
},
},
],
"nextPageToken": "",
}