fix: step 6 webhooks demo - replace 404 events API with webhook registration flow
Some checks failed
Build and Deploy / deploy (push) Failing after 10m23s

- Replace /events/v2/* endpoints (404 in sandbox) with /api/v1/webhooks
- Add list_webhooks() and register_webhook() methods to TinkClient
- Step 6 now shows: webhook flow diagram + curl examples + live API + sample payload
- Handle sandbox 404 gracefully (shows example data, no red error)
- Remove .env.production from git tracking (credentials via Gitea secrets)
- deploy.yml: write .env.production from TINK_CLIENT_ID/SECRET secrets
This commit is contained in:
Henrik Jess Nielsen
2026-05-22 19:04:06 +02:00
parent e3fa08f6fb
commit 3f687bb212
8 changed files with 327 additions and 167 deletions

View File

@@ -241,9 +241,10 @@ async def tink_callback(request: Request, code: Optional[str] = None,
client = _client()
tokens = await client.exchange_code_for_token(code)
sess["user_token"] = tokens.get("access_token", "")
return RedirectResponse("/demo/step/3?cb_success=1", status_code=303)
except Exception as e:
return RedirectResponse(f"/demo/step/3?cb_error={str(e)}")
return RedirectResponse("/demo/step/3")
return RedirectResponse(f"/demo/step/3?cb_error={str(e)}", status_code=303)
return RedirectResponse("/demo/step/3", status_code=303)
# ---------------------------------------------------------------------------
@@ -353,48 +354,78 @@ async def step5(request: Request, account_id: Optional[str] = None):
async def step6(request: Request):
sess = _session(request)
s = get_settings()
user_token = sess.get("user_token", "")
is_demo = sess.get("demo_mode") or s.demo_mode
error = None
result_booked = None
result_all = None
result_webhooks = None
webhook_registered = None
curl_booked = (
"curl 'https://api.tink.com/events/v2/account-booked-transactions?pageSize=10' \\\n"
" -H 'Authorization: Bearer $USER_TOKEN'"
webhook_url = f"{s.app_base_url}/webhooks/tink"
curl_list = (
"# List registered webhooks (app-level token)\n"
"curl 'https://api.tink.com/api/v1/webhooks' \\\n"
" -H 'Authorization: Bearer $APP_TOKEN'"
)
curl_all = (
"curl 'https://api.tink.com/events/v2/account-transactions?pageSize=10' \\\n"
" -H 'Authorization: Bearer $USER_TOKEN'"
curl_register = (
"# Register webhook endpoint\n"
"curl -X POST 'https://api.tink.com/api/v1/webhooks' \\\n"
" -H 'Authorization: Bearer $APP_TOKEN' \\\n"
" -H 'Content-Type: application/json' \\\n"
" -d '{\n"
' "url": "' + webhook_url + '",\n'
' "enabledEvents": [\n'
' "account-booked-transaction:created",\n'
' "account-pending-transaction:created"\n'
" ]\n"
" }'"
)
if not user_token and not is_demo:
error = "Mangler user token — tilslut en bank i Step 3 først."
elif is_demo:
result_booked = demo_data.MOCK_EVENTS_BOOKED
result_all = demo_data.MOCK_EVENTS_ALL
if is_demo:
result_webhooks = demo_data.MOCK_EVENTS_BOOKED
webhook_registered = {
"id": "wh-demo-001",
"url": webhook_url,
"enabledEvents": ["account-booked-transaction:created", "account-pending-transaction:created"],
"status": "ENABLED",
}
else:
try:
client = _client()
result_booked = await client.list_booked_transaction_events(user_token, page_size=10)
app_token_resp = await client.get_app_token(scope="user:create")
app_token = app_token_resp.get("access_token", "")
result_webhooks = await client.list_webhooks(app_token)
# Register our webhook if not already there
existing = [w for w in result_webhooks.get("webhooks", []) if w.get("url") == webhook_url]
if not existing:
webhook_registered = await client.register_webhook(app_token, webhook_url)
else:
webhook_registered = existing[0]
except Exception as e:
error = f"Booked events: {e}"
try:
client = _client()
result_all = await client.list_account_transaction_events(user_token, page_size=10)
except Exception as e:
error = (error or "") + f" | All events: {e}"
err_str = str(e)
if "404" in err_str:
# Sandbox doesn't expose webhook management — show sample data instead
result_webhooks = {"note": "Webhook API ikke tilgængeligt i sandbox — kun i produktion"}
webhook_registered = {
"url": webhook_url,
"enabledEvents": ["account-booked-transaction:created", "account-pending-transaction:created"],
"status": "ENABLED (eksempel)",
}
else:
error = err_str
return templates.TemplateResponse("step6.html", {
"request": request,
"step": 6,
"title": "Events",
"subtitle": "Real-time Event Feed",
"title": "Webhooks & Events",
"subtitle": "Real-time Event Notifications",
"error": error,
"result_booked": result_booked,
"result_all": result_all,
"curl_booked": curl_booked,
"curl_all": curl_all,
"result_webhooks": result_webhooks,
"webhook_registered": webhook_registered,
"webhook_url": webhook_url,
"curl_list": curl_list,
"curl_register": curl_register,
"is_demo": is_demo,
"app_base_url": s.app_base_url,
"next_step": None,