Cookbook
This cookbook is for fintech engineers wiring up their loan portfolio to Waafir's monitoring API. Each recipe walks one task end to end with all three reference clients — cURL, TypeScript, Python — so a reader does not have to translate between languages mentally. The recipes lean toward the failure-and-edge-case paths a real integration hits, not just the happy path.
Who this is for
You have been issued a personal access token (PAT) by your Waafir organization administrator, and you are writing the code that submits your daily loan-tape data — borrowers, loans, scheduled repayments, actual payments, collateral, and collateral valuations — into Waafir. Your data lands in Waafir's bronze archive on submission and is normalised into the silver entity tables by the import worker; from there the daily aggregator powers the investor monitoring tab on any data room linked to the portfolio.
How to use these recipes
Every recipe has the same shape: a short prose lead, three fenced code blocks in fixed order, and a brief verification paragraph. The code blocks are:
- cURL — copy-paste against your shell. The least opinionated; useful for one-off probes and CI checks.
- TypeScript —
fetch-based against the public JSON contracts. No SDK install required; the same shapes a future Waafir TypeScript SDK will wrap. - Python —
requests-based against the same JSON contracts. The standard library is enough; no Waafir-specific package is required.
Each recipe also cites the friction-scenario identifier it anchors. The full catalog of scenarios lives in docs/implementation/friction-scenarios.md inside the platform repository; the cookbook is the integrator-facing companion to that catalog.
Authentication
All endpoints require a PAT in the Authorization header:
Authorization: Bearer <YOUR_PAT>A PAT is scoped to a single Waafir organization and carries that organization's identity on every request. Treat it as a secret; rotate it via the dashboard when it leaks. The API base URL throughout these recipes is https://app.waafir.io — replace it with your staging URL if you are integrating against the sandbox tenant first.
Conventions used in the recipes
- All shell variables in cURL examples are written as
${UPPER_CASE_NAME}so you canexportthem once and re-use them across recipes. - TypeScript and Python examples assume
BASE_URLandPATare read from the environment. Adapt to your configuration loader. - The
Idempotency-Keyheader is the platform-wide convention for safe retries; see the retry recipe for the precise semantics. - All write endpoints accept your own
external_idvalues — caller-supplied identifiers stay the canonical handle through ingestion, reconciliation, and tape downloads. You never need to learn Waafir's internal UUIDs.
What the cookbook does not cover
The cookbook is task-oriented. For exhaustive endpoint definitions, request and response schemas, and error code references, see the API reference section once it ships alongside the cookbook. For product concepts — what a portfolio is, how it relates to a data room, why the medallion model matters — see Data rooms and the foundational-concepts section.
The recipes
- Bulk import a loan tape via async NDJSON — the foundational ingestion flow: presigned upload, commit, poll for completion.
- Validate a load with dry-run before committing data — same flow with
?dryRun=true; learn what your file contains before any silver rows are written. - Retry safely with an idempotency key — survive transient network failures without creating duplicate imports.
- Inspect partial-failure errors after an import — page through per-row errors when an import lands as
partial. - Cancel an in-flight import — stop a long-running import at the next batch boundary without partially-written rows.
- Reconcile your data by external ID — confirm a row landed, by your own identifier, and verify daily counts.
UI Conventions
The interface conventions Waafir follows — explicit saving, notifications, confirm dialogs, keyboard shortcuts, mobile, accessibility, and the current state of dark mode.
Bulk import a loan tape via async NDJSON
Walk the two-phase async import flow — start an import, upload an NDJSON file to the returned presigned URL, commit, then poll until the worker finishes processing.