{"_id":"@blnkfinance/blnk-typescript","_rev":"7-513fc35274c6365d02dc1e7d7d1e239a","name":"@blnkfinance/blnk-typescript","dist-tags":{"latest":"1.5.0"},"versions":{"1.0.0":{"name":"@blnkfinance/blnk-typescript","version":"1.0.0","keywords":["sdk","typescript","blnk","finance","api"],"author":{"name":"Blnk Finance"},"license":"MIT","_id":"@blnkfinance/blnk-typescript@1.0.0","maintainers":[{"name":"jerryblnk","email":"jerry@blnkfinance.com"}],"homepage":"https://github.com/blnkfinance/blnk-ts#readme","bugs":{"url":"https://github.com/blnkfinance/blnk-ts/issues"},"tap":{"plugin":["@tapjs/nock"],"coverage-map":"tests/map.mjs"},"dist":{"shasum":"f4ebe152d4fce3e9b07b91c4d6709b1cbf56d3d5","tarball":"https://registry.npmjs.org/@blnkfinance/blnk-typescript/-/blnk-typescript-1.0.0.tgz","fileCount":216,"integrity":"sha512-iWPbLnCl85pq38jI2mTeWk/w6ZsME2+9A/YjY3bioopr60F8d2o341allU34y8qxzDgBA32xcn80Lpfcb8K3pw==","signatures":[{"sig":"MEQCIEYDuPa/EzyFXE8hhWrE/h9th8CpXv2yYscTktbxnZLrAiBF5TL+e1I/yiUVKGO3Wl5mBxFJavNuXRFvoIjGQREomg==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":633427},"main":"dist/src/index.js","types":"dist/src/index.d.ts","gitHead":"661c6264ccf221a67a567d6e6c3f5c5523294179","scripts":{"fix":"gts fix","lint":"gts lint","clean":"gts clean","compile":"tsc","prepare":"npm run compile","pretest":"npm run compile","posttest":"npm run lint","test:unit":"tap tests/unit"},"_npmUser":{"name":"jerryblnk","email":"jerry@blnkfinance.com"},"repository":{"url":"git+https://github.com/blnkfinance/blnk-ts.git","type":"git"},"_npmVersion":"10.8.3","description":"Blnk Finance SDK in TypeScript","directories":{"test":"tests","example":"examples"},"_nodeVersion":"22.9.0","dependencies":{"form-data":"^4.0.0","node-fetch":"^2.7.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"gts":"^5.3.1","tap":"^21.0.1","prettier":"^3.3.3","typescript":"^5.6.3","@types/node":"20.12.7","@types/node-fetch":"^2.6.11"},"_npmOperationalInternal":{"tmp":"tmp/blnk-typescript_1.0.0_1730059772377_0.25786529341475806","host":"s3://npm-registry-packages"}},"1.0.1":{"name":"@blnkfinance/blnk-typescript","version":"1.0.1","keywords":["sdk","typescript","blnk","finance","api"],"author":{"name":"BLNK"},"license":"MIT","_id":"@blnkfinance/blnk-typescript@1.0.1","maintainers":[{"name":"jerryblnk","email":"jerry@blnkfinance.com"}],"tap":{"plugin":["@tapjs/nock"],"coverage-map":"tests/map.mjs"},"dist":{"shasum":"7c9c1f92a1c736c8a6b85adf9ca53d32e5b0dd44","tarball":"https://registry.npmjs.org/@blnkfinance/blnk-typescript/-/blnk-typescript-1.0.1.tgz","fileCount":216,"integrity":"sha512-LIIsasDz5qdGzvYO7QSL/TW2anotCih1rcA7mWhcNdbE0oYTE0svSiPPYJWLZnUFHQmz48pdfQ1GBXwsqvqvDQ==","signatures":[{"sig":"MEUCIQC/ci+2dr9oApbiNnv+xa6mhX91AV0nGV2ufu4n5wUqIwIgW5l5buPh3PCB+YH3Ir0c5W0JSYIXDYN0m0W/mpwcRDc=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":634436},"main":"dist/src/index.js","types":"dist/src/index.d.ts","gitHead":"6977ee4f378fb1d3ebbc9e849bee111aeb0e8142","scripts":{"fix":"gts fix","lint":"gts lint","clean":"gts clean","compile":"tsc","prepare":"npm run compile","pretest":"npm run compile","posttest":"npm run lint","test:unit":"tap tests/unit"},"_npmUser":{"name":"jerryblnk","email":"jerry@blnkfinance.com"},"overrides":{"whatwg-url":"^14.0.0"},"_npmVersion":"10.8.3","description":"Blnk Finance SDK in TypeScript","directories":{},"_nodeVersion":"22.9.0","dependencies":{"form-data":"^4.0.0","node-fetch":"^2.7.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"gts":"^6.0.2","tap":"^21.0.1","prettier":"^3.3.3","typescript":"^5.4.3","@types/node":"20.12.7","@types/node-fetch":"^2.6.11"},"_npmOperationalInternal":{"tmp":"tmp/blnk-typescript_1.0.1_1730105543945_0.9988754500892192","host":"s3://npm-registry-packages"}},"1.0.2":{"name":"@blnkfinance/blnk-typescript","version":"1.0.2","keywords":["sdk","typescript","blnk","finance","api"],"author":{"name":"BLNK"},"license":"MIT","_id":"@blnkfinance/blnk-typescript@1.0.2","maintainers":[{"name":"jerryblnk","email":"jerry@blnkfinance.com"}],"tap":{"plugin":["@tapjs/nock"],"coverage-map":"tests/map.mjs"},"dist":{"shasum":"8cd966e6b39b107cf047859198fc9fdecb5e404d","tarball":"https://registry.npmjs.org/@blnkfinance/blnk-typescript/-/blnk-typescript-1.0.2.tgz","fileCount":216,"integrity":"sha512-bvn4H8CAO2N5Db/zT+Fkxf8vHbQ8cP70lPnXPxYk4LPVt7IIn8svwRA7C2mA+EliMOk6ZmAjNgVweO+dT0uLBg==","signatures":[{"sig":"MEUCIQCkRzFZY6O7tkga+JINSd82iElkZP8UsJVr3jMz21R9IwIgPAThySGPI/A3s54peLyi1NRkXJLEejCYPGWRE4jxH70=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":637005},"main":"dist/src/index.js","types":"dist/src/index.d.ts","gitHead":"2123b9979ed9e6884234d246b20b003863482633","scripts":{"fix":"gts fix","lint":"gts lint","clean":"gts clean","compile":"tsc","prepare":"npm run compile","pretest":"npm run compile","posttest":"npm run lint","test:unit":"tap tests/unit"},"_npmUser":{"name":"jerryblnk","email":"jerry@blnkfinance.com"},"overrides":{"whatwg-url":"^14.0.0"},"_npmVersion":"10.8.3","description":"Blnk Finance SDK in TypeScript","directories":{},"_nodeVersion":"22.9.0","dependencies":{"form-data":"^4.0.0","node-fetch":"^2.7.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"gts":"^6.0.2","tap":"^21.0.1","prettier":"^3.3.3","typescript":"^5.4.3","@types/node":"20.12.7","@types/node-fetch":"^2.6.11"},"_npmOperationalInternal":{"tmp":"tmp/blnk-typescript_1.0.2_1731420072544_0.1127697286863596","host":"s3://npm-registry-packages"}},"1.3.0":{"name":"@blnkfinance/blnk-typescript","version":"1.3.0","keywords":["sdk","typescript","blnk","finance","api"],"author":{"name":"BLNK"},"license":"MIT","_id":"@blnkfinance/blnk-typescript@1.3.0","maintainers":[{"name":"jerryblnk","email":"jerry@blnkfinance.com"},{"name":"ubokabasi","email":"emmanuella.etop-essien@blnkfinance.com"}],"tap":{"plugin":["@tapjs/nock"],"coverage-map":"tests/map.mjs"},"dist":{"shasum":"e36fb839b780fcb1eead1a3b108fc83e6b50184c","tarball":"https://registry.npmjs.org/@blnkfinance/blnk-typescript/-/blnk-typescript-1.3.0.tgz","fileCount":458,"integrity":"sha512-bvzepyUCtICqzmRKYeRALolW0RMtLlI0OGjwKA+HZnqrTYK3SXyXeFsOFwJ/bx68vRcTsrFwXwH5Qufa2FHloA==","signatures":[{"sig":"MEUCIQCVw747gTWsNOSTCMBlsV9eCmkwyNNB87C0oZG1lVRPIAIgRWlw6dAfUGOApd8TiOa6yG016fpD4Kt7h11tW9yahSs=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1172298},"main":"dist/src/index.js","types":"dist/src/index.d.ts","engines":{"node":">=18"},"gitHead":"f3d8a52a8404740921a21f229fb04ebe9dce21fc","scripts":{"fix":"gts fix","lint":"gts lint","clean":"gts clean","compile":"tsc","prepare":"npm run compile","pretest":"npm run compile","posttest":"npm run lint","test:unit":"tap tests/unit"},"_npmUser":{"name":"ubokabasi","email":"emmanuella.etop-essien@blnkfinance.com"},"overrides":{"tmp":"^0.2.7","whatwg-url":"^16.0.1"},"_npmVersion":"10.8.2","description":"Blnk Finance SDK in TypeScript","directories":{},"_nodeVersion":"20.20.2","dependencies":{"form-data":"^4.0.5"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"gts":"^6.0.2","tap":"^21.6.2","prettier":"^3.8.1","typescript":"^5.9.3","@types/node":"^25.5.0"},"_npmOperationalInternal":{"tmp":"tmp/blnk-typescript_1.3.0_1783705732079_0.08557578131182231","host":"s3://npm-registry-packages-npm-production"}},"1.4.0":{"name":"@blnkfinance/blnk-typescript","version":"1.4.0","keywords":["sdk","typescript","blnk","finance","api"],"author":{"name":"BLNK"},"license":"MIT","_id":"@blnkfinance/blnk-typescript@1.4.0","maintainers":[{"name":"jerryblnk","email":"jerry@blnkfinance.com"},{"name":"ubokabasi","email":"emmanuella.etop-essien@blnkfinance.com"}],"tap":{"plugin":["@tapjs/nock"],"coverage-map":"tests/map.mjs"},"dist":{"shasum":"a857cb3d1c5bcc6861058164035879e1c65a903f","tarball":"https://registry.npmjs.org/@blnkfinance/blnk-typescript/-/blnk-typescript-1.4.0.tgz","fileCount":470,"integrity":"sha512-b/uNDms4XaCFNN3R5YM1PtEVLjk2aZK+KlSiHUoL/qfoN+w/GmRa39NCdFtFwSIR0L5GXVnd6YCmmQzb0yoHww==","signatures":[{"sig":"MEUCIQCLTyMHdJxKWZkH3yvFwBJYRhio6bvyJ8rkUju8fg5nQgIgAr3SnifXAik4mCKop57wfgGQkaow1bi+ji7fyHkJI5s=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1253606},"main":"dist/src/index.js","types":"dist/src/index.d.ts","engines":{"node":">=18"},"gitHead":"d91460b243c8130ae65d747e43ee003751978eca","scripts":{"fix":"gts fix","lint":"gts lint","clean":"gts clean","compile":"tsc","prepare":"npm run compile","pretest":"npm run compile","posttest":"npm run lint","test:unit":"tap tests/unit"},"_npmUser":{"name":"ubokabasi","email":"emmanuella.etop-essien@blnkfinance.com"},"overrides":{"tmp":"^0.2.7","sigstore":"^4.1.1","whatwg-url":"^16.0.1"},"_npmVersion":"10.8.2","description":"Blnk Finance SDK in TypeScript","directories":{},"_nodeVersion":"20.20.2","dependencies":{"form-data":"^4.0.5"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"gts":"^6.0.2","tap":"^21.6.2","prettier":"^3.8.1","typescript":"^5.9.3","@types/node":"^25.5.0"},"_npmOperationalInternal":{"tmp":"tmp/blnk-typescript_1.4.0_1788376029740_0.07938738992775152","host":"s3://npm-registry-packages-npm-production"}},"1.5.0":{"_id":"@blnkfinance/blnk-typescript@1.5.0","tap":{"plugin":["@tapjs/nock"],"coverage-map":"tests/map.mjs"},"dist":{"shasum":"1afca74cec672d58cbe1cf66a8e75f5e47a0edd1","tarball":"https://registry.npmjs.org/@blnkfinance/blnk-typescript/-/blnk-typescript-1.5.0.tgz","fileCount":494,"integrity":"sha512-RrAf1gm8+0kh6QghSN45DPtJ7/1t0uKJVtJw0tVZ7CZtS7kyBZTmBZVE/7EL1RVlx31zvVAOltSvS508TDiGFw==","signatures":[{"sig":"MEYCIQCUN/vq9/eEt8AZu/idDcHUyApYvoh9PUiWaB/ZItG9ewIhAPApGPgpDhWU6EYfIPONFEpHNcS4iHzqLHKoDKLZtYHC","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIFV5rr6w8zVbuL0yOv/KgFFPxfzt7UBSRoV7RUDBr6YeAiBKD4TwREpNxyjM9Gb7Swnf/JWCxv6Zo1DRewMO31Z4RA=="}],"unpackedSize":1351448},"main":"dist/src/index.js","name":"@blnkfinance/blnk-typescript","types":"dist/src/index.d.ts","author":{"name":"BLNK"},"engines":{"node":">=18"},"gitHead":"4592d8b5fe89fdf541015e7436633608e3bc6185","license":"MIT","scripts":{"fix":"gts fix","lint":"gts lint","clean":"gts clean","compile":"tsc","prepare":"npm run compile","pretest":"npm run compile","posttest":"npm run lint","test:unit":"tap tests/unit"},"version":"1.5.0","_npmUser":{"name":"ubokabasi","email":"emmanuella.etop-essien@blnkfinance.com"},"keywords":["sdk","typescript","blnk","finance","api"],"overrides":{"tmp":"^0.2.7","sigstore":"^4.1.1","whatwg-url":"^16.0.1"},"_npmVersion":"10.8.2","description":"Blnk Finance SDK in TypeScript","directories":{},"maintainers":[{"name":"jerryblnk","email":"jerry@blnkfinance.com"},{"name":"ubokabasi","email":"emmanuella.etop-essien@blnkfinance.com"}],"_nodeVersion":"20.20.2","dependencies":{"form-data":"^4.0.5"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"gts":"^6.0.2","tap":"^21.6.2","prettier":"^3.8.1","typescript":"^5.9.3","@types/node":"^25.5.0"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/blnk-typescript_1.5.0_1790232410251_0.985188916502431"}}},"time":{"created":"2024-10-27T20:09:32.258Z","modified":"2026-09-24T06:46:50.607Z","1.0.0":"2024-10-27T20:09:32.687Z","1.0.1":"2024-10-28T08:52:24.152Z","1.0.2":"2024-11-12T14:01:12.896Z","1.3.0":"2026-07-10T17:48:52.237Z","1.4.0":"2026-09-02T19:07:09.888Z","1.5.0":"2026-09-24T06:46:50.343Z"},"author":{"name":"BLNK"},"license":"MIT","keywords":["sdk","typescript","blnk","finance","api"],"description":"Blnk Finance SDK in TypeScript","maintainers":[{"name":"jerryblnk","email":"jerry@blnkfinance.com"},{"name":"ubokabasi","email":"emmanuella.etop-essien@blnkfinance.com"}],"readme":"![Blnk logo](https://res.cloudinary.com/dmxizylxw/image/upload/v1724847576/blnk_github_logo_eyy2lf.png)\n\n## Blnk TypeScript SDK Documentation\n\n\n---\n\n## 1. Installation\n\n### Prerequisites\nEnsure that you have the following installed on your machine:\n- **Docker** and **Docker Compose** for running Blnk’s server locally.\n- **Node.js** (v14 or later) and **npm** for installing the Blnk TypeScript SDK.\n\n### Step 1: Clone the Blnk Repository\n\nTo start, clone the Blnk repository from GitHub:\n\n```bash\ngit clone https://github.com/blnkfinance/blnk && cd blnk\n```\n\n### Step 2: Install Blnk TypeScript SDK\n\nInstall the Blnk TypeScript SDK in your project:\n\n```bash\nnpm install @blnkfinance/blnk-typescript@1.5.0 --save\n```\n\n`v1.5.0` targets **Blnk Core 0.15.4**. See [RELEASE.md](RELEASE.md) for the error catalogue, `Search.multiSearch`, and list methods (`Ledgers.list`, `LedgerBalances.list`, `Transactions.list`, `BalanceMonitor.listByBalanceId`).\n\n### Step 3: Setting Up Configuration\n\nIn your cloned directory, create a configuration file named `blnk.json` with the following content:\n\n```json\n{\n  \"project_name\": \"Blnk\",\n  \"data_source\": {\n    \"dns\": \"postgres://postgres:password@postgres:5432/blnk?sslmode=disable\"\n  },\n  \"redis\": {\n    \"dns\": \"redis:6379\"\n  },\n  \"server\": {\n    \"domain\": \"blnk.io\",\n    \"ssl\": false,\n    \"ssl_email\": \"jerryenebeli@gmail.com\",\n    \"port\": \"5001\"\n  },\n  \"notification\": {\n    \"slack\": {\n      \"webhook_url\": \"https://hooks.slack.com\"\n    }\n  }\n}\n```\n\nThis configuration sets up connections to PostgreSQL and Redis, specifies your server details, and allows Slack notifications if needed.\n\n---\n\n## 2. Launching Blnk\n\nWith Docker Compose, launch the Blnk server:\n\n```bash\ndocker compose up\n```\n\nOnce running, your server will be accessible at [http://localhost:5001](http://localhost:5001).\n\n### Health check\n\n`System.health` checks whether Blnk Core is running (GET `/health`):\n\n```typescript\nconst health = await blnk.System.health();\n// health.status === 200\n// health.data?.status === 'UP'\n```\n\n---\n\n## 3. Using the Blnk CLI\n\nThe Blnk CLI offers quick access to manage ledgers, balances, and transactions. To verify the installation and view available commands, use:\n\n```bash\nblnk --help\n```\n\n---\n\n## 4. Creating Your First Ledger\n\n### What is a Ledger?\nIn Blnk, ledgers are used to categorize balances for organized tracking. When you first install Blnk, an internal ledger called the General Ledger is created by default.\n\n### Step-by-Step: Creating a Ledger\n\nUsing the SDK, create a ledger for user accounts:\n\n```typescript\nimport { BlnkInit } from '@blnkfinance/blnk-typescript';\n\nconst blnk = await BlnkInit('<secret_key_if_set>', { baseUrl: 'http://localhost:5001' });\nconst { Ledgers } = blnk;\n\nconst newLedger = await Ledgers.create({\n    name: \"Customer Savings Account\",\n    meta_data: {\n        project_owner: \"YOUR_APP_NAME\"\n    }\n});\nconsole.log(\"Ledger Created:\", newLedger);\n```\n\nThis creates a new ledger for storing customer balances.\n\n### Updating a ledger name\n\nRename an existing ledger without changing its ID or affecting balances and transactions:\n\n```typescript\nconst updatedLedger = await Ledgers.update(\n  'ldg_073f7ffe-9dfd-42ce-aa50-d1dca1788adc',\n  { name: 'Updated Customer Savings Account' },\n);\nconsole.log('Ledger Updated:', updatedLedger);\n```\n\n### List ledgers, balances, and transactions\n\n`Ledgers.list`, `LedgerBalances.list`, and `Transactions.list` wrap Core's `GET /ledgers`, `GET /balances`, and `GET /transactions` (present since ~0.14.x; this SDK is aligned with Core 0.15.4). Omit options to use Core's default page (`limit=10` / `offset=0` for ledgers and balances, `limit=20` for transactions). Invalid `limit` or `offset` is rejected client-side with HTTP 400.\n\n```typescript\nconst firstPage = await Ledgers.list();\nconst nextPage = await Ledgers.list({ limit: 10, offset: 10 });\n\nconst balances = await LedgerBalances.list({ limit: 50 });\n\nconst recentTransactions = await Transactions.list({ limit: 100 });\n```\n\n---\n\n## 5. Creating Identities\n\nRegister customers or organizations before linking them to balances. Only `identity_type` is required; all other fields are optional and match the [Create Identity API reference](https://docs.blnkfinance.com/reference/create-identity). The SDK validates `identity_type` and field formats (for example `identity_id`, `dob`, `gender`) when you provide them.\n\nMinimal create:\n\n```typescript\nconst { Identity } = blnk;\n\nconst minimal = await Identity.create({\n  identity_type: 'individual',\n});\n```\n\nFull example with optional caller-supplied `identity_id` (`idt_` + UUID) and ISO 8601 `dob`:\n\n```typescript\nconst { Identity } = blnk;\n\nconst newIdentity = await Identity.create({\n  identity_id: 'idt_11111111-1111-4111-8111-111111111111',\n  identity_type: 'individual',\n  first_name: 'Jane',\n  last_name: 'Doe',\n  gender: 'female',\n  dob: '1990-01-15T00:00:00Z',\n  email_address: 'jane@example.com',\n  phone_number: '+1234567890',\n  nationality: 'US',\n  category: 'customer',\n  street: '123 Main St',\n  country: 'USA',\n  state: 'NY',\n  post_code: '10001',\n  city: 'New York',\n});\nconsole.log('Identity Created:', newIdentity);\n```\n\n### Tokenize identity fields\n\n| Method | Endpoint | Use case |\n|--------|----------|----------|\n| `Identity.getTokenizedFields(id)` | `GET /identities/{identity_id}/tokenized-fields` | List fields currently tokenized on an identity |\n| `Identity.tokenizeField(id, field)` | `POST /identities/{identity_id}/tokenize/{field}` | Tokenize one PII field on an identity |\n| `Identity.tokenize(id, data)` | `POST /identities/{identity_id}/tokenize` | Tokenize multiple PII fields on an identity |\n| `Identity.detokenize(id, data)` | `POST /identities/{identity_id}/detokenize` | Detokenize fields and return original values |\n| `Identity.detokenizeField(id, field)` | `GET /identities/{identity_id}/detokenize/{field}` | Detokenize one field and return its original value |\n\n```typescript\nconst { Identity } = blnk;\n\nconst tokenizedFields = await Identity.getTokenizedFields(identity.data!.identity_id);\n// tokenizedFields.data?.tokenized_fields — e.g. [\"FirstName\", \"EmailAddress\"]\n\n// Tokenize a single field (PascalCase struct name in the path).\nconst oneField = await Identity.tokenizeField(identity.data!.identity_id, 'EmailAddress');\n// oneField.data?.message — \"Field tokenized successfully\"\n\n// Use PascalCase struct field names — not the snake_case JSON keys on IdentityData.\nconst tokenized = await Identity.tokenize(identity.data!.identity_id, {\n  fields: ['FirstName', 'LastName', 'EmailAddress', 'PhoneNumber'],\n});\n// tokenized.data?.message — \"Fields tokenized successfully\"\n\n// Detokenize specific fields, or pass { fields: [] } to detokenize all tokenized fields.\nconst restored = await Identity.detokenize(identity.data!.identity_id, {\n  fields: ['FirstName', 'EmailAddress'],\n});\n// restored.data?.fields — e.g. { FirstName: \"Jane\", EmailAddress: \"jane@example.com\" }\n\n// Detokenize a single field and read the original value.\nconst email = await Identity.detokenizeField(identity.data!.identity_id, 'EmailAddress');\n// email.data?.value — e.g. \"jane@example.com\"\n```\n\n> Field names must be Core struct names (`FirstName`, `EmailAddress`, …). Passing `first_name` or `email_address` from `IdentityData` will be rejected.\n\nSee the [Get tokenized fields reference](https://docs.blnkfinance.com/reference/get-tokenized-fields), [Tokenize field reference](https://docs.blnkfinance.com/reference/tokenize-field), [Tokenize identity reference](https://docs.blnkfinance.com/reference/tokenize-identity), [Detokenize field reference](https://docs.blnkfinance.com/reference/detokenize-field), and [Detokenize identity reference](https://docs.blnkfinance.com/reference/detokenize-identity).\n\n### Delete identity\n\n| Method | Endpoint | Use case |\n|--------|----------|----------|\n| `Identity.delete(id)` | `DELETE /identities/{identity_id}` | Remove an identity record (Core 0.15.0+) |\n\n```typescript\nconst { Identity } = blnk;\n\nconst deleted = await Identity.delete(identity.data!.identity_id);\n// deleted.data?.message — \"Identity deleted successfully\"\n```\n\nSee the [Delete identity reference](https://docs.blnkfinance.com/reference/delete-identity).\n\n---\n\n## 6. Creating Balances\n\nBalances represent the store of value within a ledger, like a wallet or account. Each balance belongs to a ledger.\n\n### Step-by-Step: Creating a Balance\n\nTo create a balance, specify the `ledger_id` and other details:\n\n```typescript\nconst { LedgerBalances } = blnk;\n\nconst newBalance = await LedgerBalances.create({\n    ledger_id: \"ldg_073f7ffe-9dfd-42ce-aa50-d1dca1788adc\",\n    currency: \"USD\",\n    meta_data: {\n        first_name: \"Alice\",\n        last_name: \"Hart\",\n        account_number: \"1234567890\"\n    }\n});\nconsole.log(\"Balance Created:\", newBalance);\n```\n\nCreate a General Ledger balance on Core **0.15.3+** with `ledger_id: \"general_ledger_id\"` and an `@` indicator:\n\n```typescript\nconst glBalance = await LedgerBalances.create({\n  ledger_id: \"general_ledger_id\",\n  currency: \"USD\",\n  indicator: \"@WorldUSD\",\n});\n```\n\nWith fund lineage tracking enabled (requires `identity_id`):\n\n```typescript\nconst lineageBalance = await LedgerBalances.create({\n  ledger_id: \"ldg_073f7ffe-9dfd-42ce-aa50-d1dca1788adc\",\n  identity_id: \"idt_3b63c8da-af29-4cc3-ad38-df17d87456e6\",\n  currency: \"USD\",\n  track_fund_lineage: true,\n  allocation_strategy: \"FIFO\", // FIFO | LIFO | PROPORTIONAL\n});\n```\n\n### Get balance\n\n`LedgerBalances.get` retrieves a balance by ID (`GET /balances/{balance_id}`). Pass `{ from_source: true }` to reconstruct the balance from transactions instead of snapshots:\n\n```typescript\nconst response = await LedgerBalances.get(\n  'bln_5ce86029-3c2e-4e2a-aae2-7fb931ca4c4f',\n  { from_source: true },\n);\n\n// response.data.balance_id\n// response.data.balance\n```\n\n### Get balance by indicator\n\n`LedgerBalances.getByIndicator` retrieves a balance by its indicator and currency (`GET /balances/indicator/{indicator}/currency/{currency}`):\n\n```typescript\nconst response = await LedgerBalances.getByIndicator('@World', 'USD');\n\n// response.data.balance_id\n// response.data.indicator\n// response.data.currency\n```\n\n### Update balance identity\n\n`LedgerBalances.updateIdentity` links a balance to an identity (`PUT /balances/{id}/identity`):\n\n```typescript\nconst response = await LedgerBalances.updateIdentity(\n  'bln_5ce86029-3c2e-4e2a-aae2-7fb931ca4c4f',\n  { identity_id: 'idt_3b63c8da-af29-4cc3-ad38-df17d87456e6' },\n);\n\n// response.data.message\n```\n\n### Create balance snapshots\n\n`LedgerBalances.createSnapshot` triggers daily balance snapshots in batches (`POST /balances-snapshots`). Omit `batch_size` or pass zero to use the server default (1000):\n\n```typescript\nconst response = await LedgerBalances.createSnapshot({ batch_size: 500 });\n\n// response.data.message\n```\n\n### Get historical balance\n\n`LedgerBalances.getAt` retrieves a balance at a specific timestamp (`GET /balances/{balance_id}/at`):\n\n```typescript\nconst response = await LedgerBalances.getAt(\n  'bln_5ce86029-3c2e-4e2a-aae2-7fb931ca4c4f',\n  { timestamp: '2025-02-24T08:55:26Z', from_source: true },\n);\n\n// response.data.balance.balance_id\n// response.data.balance.balance\n// response.data.timestamp\n```\n\n### Get balance lineage\n\n`LedgerBalances.getLineage` retrieves the provider breakdown for a balance with fund lineage enabled (`GET /balances/{balance_id}/lineage`):\n\n```typescript\nconst response = await LedgerBalances.getLineage(\n  'bln_5ce86029-3c2e-4e2a-aae2-7fb931ca4c4f',\n);\n\n// response.data.balance_id\n// response.data.total_with_lineage\n// response.data.providers\n```\n\n### Delete balance monitor\n\n| Method | Endpoint | Use case |\n|--------|----------|----------|\n| `BalanceMonitor.list()` | `GET /balance-monitors` | List all balance monitors |\n| `BalanceMonitor.listByBalanceId(id)` | `GET /balance-monitors/balances/{balance_id}` | List monitors for one balance |\n| `BalanceMonitor.delete(id)` | `DELETE /balance-monitors/{monitor_id}` | Remove a balance monitor (Core 0.15.0+) |\n\n```typescript\nconst { BalanceMonitor } = blnk;\n\nconst forBalance = await BalanceMonitor.listByBalanceId(\n  'bln_5ce86029-3c2e-4e2a-aae2-7fb931ca4c4f',\n);\n// forBalance.data — MonitorDataResp[]\n\nconst deleted = await BalanceMonitor.delete(monitor.data!.monitor_id);\n// deleted.data?.message — \"BalanceMonitor deleted successfully\"\n```\n\nSee the [Delete balance monitor reference](https://docs.blnkfinance.com/reference/delete-balance-monitor).\n\n---\n\n## 6. Recording Transactions\n\nTransactions track financial activities within your application. Blnk ensures that each transaction is both immutable and idempotent.\n\n### Step-by-Step: Recording a Transaction\n\nTo record a transaction, you’ll need the `source` and `destination` balance IDs:\n\n```typescript\nconst { Transactions } = blnk;\n\nconst newTransaction = await Transactions.create({\n    amount: 750,\n    reference: \"ref_001adcfgf\",\n    currency: \"USD\",\n    precision: 100,\n    source: \"bln_28edb3e5-c168-4127-a1c4-16274e7a28d3\",\n    destination: \"bln_ebcd230f-6265-4d4a-a4ca-45974c47f746\",\n    description: \"Sent from app\",\n    meta_data: {\n        sender_name: \"John Doe\",\n        sender_account: \"00000000000\"\n    }\n});\nconsole.log(\"Transaction Recorded:\", newTransaction);\n```\n\n### Dry-run a transaction\n\nOn Core **0.15.3+**, set `dry_run: true` on create, bulk create, refund, inflight `updateStatus`, `bulkCommitInflight`, or `bulkVoidInflight` to preview balances without writing anything. The response is HTTP 200 with `would_apply` and `balances` — not a posted transaction.\n\n```typescript\nconst preview = await Transactions.create({\n  amount: 120,\n  precision: 100,\n  reference: 'ref_card_settle_4821',\n  description: 'Card settlement preview',\n  currency: 'USD',\n  source: '@WorldUSD',\n  destination: '@MyBalance',\n  dry_run: true,\n});\n// preview.status === 200\n// preview.data?.dry_run === true\n// preview.data?.would_apply\n```\n\n`dry_run` is discriminated so a preview is never typed as a posted transaction. Requests typed with a plain request type keep the posted response, so existing code is unaffected:\n\n```typescript\nconst body: CreateTransactions<Meta> = {/* ... */};\nconst posted = await Transactions.create(body);\nposted.data?.transaction_id; // still typed\n\n// Preview: pass the flag inline, or type the body as DryRun<...>\nconst previewBody: DryRun<CreateTransactions<Meta>> = {...body, dry_run: true};\nconst preview = await Transactions.create(previewBody);\npreview.data?.would_apply; // TransactionPreview — no transaction_id\n```\n\nWhen the flag is only known at runtime the response widens to the posted-or-preview union, so narrow before reading posted-only fields:\n\n```typescript\nconst result = await Transactions.create({...body, dry_run: shouldPreview});\n\nif (result.data && 'transaction_id' in result.data) {\n  console.log('posted', result.data.transaction_id);\n} else if (result.data) {\n  console.log('preview', result.data.would_apply);\n}\n```\n\nSee [Dry-run transactions](https://docs.blnkfinance.com/transactions/dry-run).\n\n### Atomic split transactions\n\nSet `atomic: true` when creating a split transaction (`destinations` or `sources`) so all legs succeed or fail together:\n\n```typescript\nconst response = await Transactions.create({\n  amount: 1000,\n  precision: 100,\n  reference: 'atomic_split_ref_001',\n  description: 'Atomic fee split',\n  currency: 'USD',\n  source: '@FundingPool',\n  destinations: [\n    { identifier: 'bln_fee', distribution: '240.23' },\n    { identifier: 'bln_recipient', distribution: 'left' },\n  ],\n  atomic: true,\n  skip_queue: true,\n});\n```\n\n### Get transaction by ID\n\n`Transactions.get` retrieves a transaction by its `transaction_id` (GET `/transactions/{transaction_id}`):\n\n```typescript\nconst response = await Transactions.get('txn_04551509-d7d3-4eab-a1fd-2eb12809b5a4');\n```\n\n### Get transaction by reference\n\n`Transactions.getByReference` retrieves a transaction by its `reference` (GET `/transactions/reference/{reference}`):\n\n```typescript\nconst response = await Transactions.getByReference('ref_04551509-d7d3-4eab-a1fd-2eb12809b5a4');\n```\n\n### Recover queued transactions\n\n`Transactions.recoverQueue` manually triggers recovery of stuck queued transactions (`POST /transactions/recover`). Optionally pass a `threshold` duration query (e.g. `5m`, `1h`):\n\n```typescript\nconst response = await Transactions.recoverQueue({ threshold: '5m' });\n\n// response.data.recovered, response.data.threshold\n```\n\n### Get transaction lineage\n\n`Transactions.getLineage` retrieves fund allocation and shadow transactions for a transaction (GET `/transactions/{transaction_id}/lineage`):\n\n```typescript\nconst response = await Transactions.getLineage('txn_8d2ce2f0-0d75-4a91-9d43-2ad2c2e6b9ad');\n\n// response.data.transaction_id\n// response.data.fund_allocation\n// response.data.shadow_transactions\n```\n\n### Update inflight transaction status\n\nCore **0.15.0** queues inflight commit and void by default. The response includes `queued: true` (status is typically `QUEUED` until the worker processes the action). Send `skip_queue: true` for immediate `APPLIED` or `VOID` responses (previous synchronous behavior).\n\n`Transactions.updateStatus` accepts `precise_amount` for partial commits on inflight transactions (in addition to `amount`). Omit both fields to commit the full remaining inflight amount:\n\n```typescript\n// Queued commit (default in Core 0.15.0)\nconst queued = await Transactions.updateStatus(transactionId, { status: 'commit' });\n// queued.data?.queued === true\n\n// Synchronous commit\nawait Transactions.updateStatus(transactionId, {\n  status: 'commit',\n  skip_queue: true,\n});\n\n// Partial commit in minor units\nawait Transactions.updateStatus(transactionId, {\n  status: 'commit',\n  precise_amount: 50000,\n  skip_queue: true,\n});\n```\n\n### Bulk commit inflight transactions\n\n`Transactions.bulkCommitInflight` commits multiple independently-created inflight transactions in one request (`POST /transactions/inflight/bulk/commit`). By default, each item is queued (`status: 'queued'` in results). Pass `skip_queue: true` for synchronous processing. Omit `amount` and `precise_amount` on an item to commit the full remaining inflight amount:\n\n```typescript\nconst response = await Transactions.bulkCommitInflight({\n  skip_queue: true,\n  transactions: [\n    { transaction_id: 'txn_11111111-1111-4111-8111-111111111111' },\n    { transaction_id: 'txn_22222222-2222-4222-8222-222222222222', amount: 40 },\n    {\n      transaction_id: 'txn_33333333-3333-4333-8333-333333333333',\n      precise_amount: 125034,\n    },\n  ],\n});\n\n// response.data.succeeded, response.data.failed, response.data.results\n\nconst commitPreview = await Transactions.bulkCommitInflight({\n  dry_run: true,\n  transactions: [\n    { transaction_id: 'txn_11111111-1111-4111-8111-111111111111' },\n  ],\n});\n// commitPreview.data?.dry_run === true\n// commitPreview.data?.would_apply\n```\n\n### Bulk void inflight transactions\n\n`Transactions.bulkVoidInflight` voids multiple independently-created inflight transactions in one request (`POST /transactions/inflight/bulk/void`). By default, each item is queued. Pass `skip_queue: true` for synchronous void:\n\n```typescript\nconst response = await Transactions.bulkVoidInflight({\n  skip_queue: true,\n  transaction_ids: [\n    'txn_11111111-1111-4111-8111-111111111111',\n    'txn_22222222-2222-4222-8222-222222222222',\n  ],\n});\n\n// response.data.succeeded, response.data.failed, response.data.results\n\nconst voidPreview = await Transactions.bulkVoidInflight({\n  dry_run: true,\n  transaction_ids: ['txn_11111111-1111-4111-8111-111111111111'],\n});\n```\n\n### Refund a transaction\n\n`Transactions.refund` accepts an optional body with `skip_queue` to process the refund synchronously. On Core **0.15.3+** you can also set `description`, `meta_data`, and `dry_run`. Omit the body to queue the refund (default):\n\n```typescript\n// Queued refund (default)\nawait Transactions.refund(transactionId);\n\n// Synchronous refund\nawait Transactions.refund(transactionId, { skip_queue: true });\n\n// Refund with description and metadata\nawait Transactions.refund(transactionId, {\n  description: 'Card reversal',\n  meta_data: { type: 'refund' },\n});\n\n// Preview without writing\nawait Transactions.refund(transactionId, { dry_run: true });\n```\n\n### Create transaction response\n\n`Transactions.create` resolves to a `CreateTransactionResponse` that matches the Core API reference, including `hash`, `parent_transaction`, `allow_overdraft`, and inflight date fields (`scheduled_for`, `inflight_expiry_date`, `inflight_commit_date`):\n\n```typescript\ninterface CreateTransactionResponse<T extends Record<string, unknown>> {\n  transaction_id: string;\n  amount: number;\n  precision: number;\n  precise_amount: number | string;\n  reference: string;\n  description: string;\n  rate?: number;\n  currency: string;\n  status: StatusType;\n  hash: string;\n  parent_transaction: string; // empty string when none\n  allow_overdraft: boolean;\n  inflight: boolean;\n  created_at: Date | string;\n  scheduled_for: Date | string;\n  inflight_expiry_date: Date | string;\n  inflight_commit_date: Date | string;\n  effective_date?: Date | string;\n  source?: string;\n  destination?: string;\n  meta_data?: T;\n}\n```\n\n---\n\n## 7. Bulk Transactions\n\nThe Blnk JavaScript SDK supports bulk transactions, allowing you to submit multiple transaction records in a single request for improved performance and atomic transaction processing.\n\n### Overview\n\nThe bulk transactions API provides the following benefits:\n- **Performance**: Submit multiple transactions in one API call\n- **Atomicity**: Ensure all transactions succeed or fail together (when `atomic: true`)\n- **Async Processing**: Process large batches asynchronously\n- **Inflight Support**: Create multiple inflight transactions that can be committed or voided later\n\n### Method Signature\n\n```typescript\nasync createBulk<T extends Record<string, unknown>>(data: BulkTransactions<T>)\n```\n\n### Parameters\n\n#### BulkTransactions Interface\n\n```typescript\ninterface BulkTransactions<T extends Record<string, unknown>> {\n  atomic?: boolean;        // Optional: All transactions succeed or fail together\n  inflight?: boolean;      // Optional: Create transactions as inflight\n  run_async?: boolean;     // Optional: Process transactions asynchronously\n  skip_queue?: boolean;    // Optional: Process without queuing\n  transactions: CreateTransactions<T>[]; // Required: Array of transaction objects\n}\n```\n\n### Usage Examples\n\n#### Basic Bulk Transactions\n\n```typescript\nconst { Transactions } = blnk;\n\n// Basic bulk transactions without additional options\nconst basicBulkData = {\n  transactions: [\n    {\n      amount: 1000,\n      precision: 100,\n      reference: 'bulk_txn_001',\n      description: 'Payment 1',\n      currency: 'USD',\n      source: '@source_account_1',\n      destination: '@destination_account_1',\n    },\n    {\n      amount: 2000,\n      precision: 100,\n      reference: 'bulk_txn_002',\n      description: 'Payment 2',\n      currency: 'USD',\n      source: '@source_account_2',\n      destination: '@destination_account_2',\n    },\n  ],\n};\n\nconst response = await Transactions.createBulk(basicBulkData);\nconsole.log('Bulk transaction response:', response);\n```\n\n#### Atomic Bulk Transactions\n\n```typescript\n// Atomic transactions - all succeed or all fail\nconst atomicBulkData = {\n  atomic: true,\n  transactions: [\n    {\n      amount: 5000,\n      precision: 100,\n      reference: 'atomic_txn_001',\n      description: 'Atomic payment 1',\n      currency: 'USD',\n      source: '@source_account_1',\n      destination: '@destination_account_1',\n    },\n    {\n      amount: 3000,\n      precision: 100,\n      reference: 'atomic_txn_002',\n      description: 'Atomic payment 2',\n      currency: 'USD',\n      source: '@source_account_2',\n      destination: '@destination_account_2',\n    },\n  ],\n};\n\nconst atomicResponse = await Transactions.createBulk(atomicBulkData);\n```\n\n#### Async Bulk Transactions with All Options\n\n```typescript\n// Process transactions asynchronously with atomic and inflight options\nconst asyncBulkData = {\n  atomic: true,\n  inflight: true,\n  run_async: true,\n  transactions: [\n    {\n      amount: 12000,\n      precision: 100,\n      reference: 'async_txn_001',\n      description: 'Async atomic inflight payment 1',\n      currency: 'USD',\n      source: '@source_account_1',\n      destination: '@destination_account_1',\n      allow_overdraft: true,\n      inflight_expiry_date: new Date(Date.now() + 48 * 60 * 60 * 1000), // 48 hours\n      meta_data: {\n        department: 'sales',\n        project: 'Q4_campaign',\n      },\n    },\n    {\n      amount: 8500,\n      precision: 100,\n      reference: 'async_txn_002',\n      description: 'Async atomic inflight payment 2',\n      currency: 'USD',\n      source: '@source_account_2',\n      destination: '@destination_account_2',\n      allow_overdraft: true,\n      inflight_expiry_date: new Date(Date.now() + 48 * 60 * 60 * 1000), // 48 hours\n      meta_data: {\n        department: 'marketing',\n        project: 'Q4_campaign',\n      },\n    },\n  ],\n};\n\nconst asyncResponse = await Transactions.createBulk(asyncBulkData);\n```\n\n### Bulk transaction response\n\n`Transactions.createBulk` resolves to a `BulkTransactionResponse` that matches the Core API reference (`batch_id`, `status`, `transaction_count`, and optional `message` for async batches):\n\n```typescript\ninterface BulkTransactionResponse {\n  batch_id: string;\n  status: 'applied' | 'inflight' | 'queued' | string;\n  transaction_count?: number; // present on synchronous success\n  message?: string;           // present when run_async is true\n}\n```\n\n### Response Format\n\nThe bulk API returns batch metadata (not nested transaction objects). See **Bulk transaction response** above for the typed shape.\n\n### Validation Rules\n\nThe bulk transactions API validates the following:\n\n1. **Required Fields**: `transactions` array must be provided and cannot be empty\n2. **Max Size**: `transactions` array cannot exceed **10,000** items\n3. **Transaction Validation**: Each transaction in the array must pass standard transaction validation\n4. **Unique References**: All transaction references must be unique within the bulk request\n5. **Boolean Flags**: `atomic`, `inflight`, `run_async`, and `skip_queue` must be booleans if provided\n6. **Standard Transaction Rules**: All existing transaction validation rules apply to each transaction\n\n### Error Handling\n\nCompare `response.error?.code` against the constants in `BlnkErrorCode`, which mirror the full Core 0.15.4 catalogue (`TXN_ALREADY_REFUNDED`, `BAL_NOT_FOUND`, `TXN_INSUFFICIENT_FUNDS`, `TXN_DUPLICATE_REFERENCE`, `LGR_NOT_FOUND`, and so on):\n\n```typescript\nimport {BlnkErrorCode} from '@blnkfinance/blnk-typescript';\n\nconst refund = await Transactions.refund(transactionId);\nif (refund.error?.code === BlnkErrorCode.TXN_ALREADY_REFUNDED) {\n  // 409: already refunded, or this id is itself a refund — nothing to do\n}\n```\n\n```typescript\ntry {\n  const response = await Transactions.createBulk(bulkData);\n  if (response.status === 201) {\n    console.log('Bulk transactions created successfully:', response.data);\n  } else {\n    console.error('Bulk transaction error:', response.message);\n  }\n} catch (error) {\n  console.error('Network or system error:', error);\n}\n```\n\n### Migration from Single Transactions\n\nConverting from single transactions to bulk transactions is straightforward:\n\n#### Before (Single Transactions)\n```typescript\nconst tx1 = await Transactions.create(transactionData1);\nconst tx2 = await Transactions.create(transactionData2);\n```\n\n#### After (Bulk Transactions)\n```typescript\nconst bulkResponse = await Transactions.createBulk({\n  transactions: [transactionData1, transactionData2]\n});\n```\n\nThis migration provides better performance and the option for atomic processing.\n\n---\n\n## 8. Viewing Ledgers, Balances, and Transactions\n\nThe Blnk CLI allows you to list all ledgers, balances, and transactions quickly:\n\n- **List Ledgers:** `blnk ledgers list`\n- **List Balances:** `blnk balances list`\n- **List Transactions:** `blnk transactions list`\n\n---\n\n## Search\n\nBlnk search APIs on the `Search` service:\n\n| Method | Endpoint | Use case |\n|--------|----------|----------|\n| `Search.search(params, collection)` | `POST /search/{collection}` | Full-text search via Typesense |\n| `Search.multiSearch(params)` | `POST /multi-search` | Several Typesense searches in one request (Core 0.10.0+) |\n| `Search.filter(params, collection)` | `POST /{collection}/filter` | Structured DB filters (Core 0.13.2+) |\n| `Search.startReindex(options?)` | `POST /search/reindex` | Rebuild Typesense index from DB |\n| `Search.getReindexStatus()` | `GET /search/reindex` | Poll reindex progress |\n\nCollections: `ledgers`, `balances`, `transactions`, `identities`.\n\n### Typesense search\n\n```typescript\nconst { Search } = blnk;\n\nconst results = await Search.search(\n  { q: 'payment', per_page: 10 },\n  'transactions',\n);\n```\n\nSearch several collections in one request (`POST /multi-search`; results come back\nin the same order as the searches):\n\n```typescript\nconst { Search } = blnk;\n\nconst multi = await Search.multiSearch({\n  searches: [\n    { collection: 'transactions', q: 'ref_001', query_by: 'reference' },\n    { collection: 'balances', q: '*', filter_by: 'currency:USD' },\n    { collection: 'ledgers', q: 'savings', query_by: 'name' },\n  ],\n});\n\nconst transactionHits = multi.data?.results[0]?.hits;\n```\n\nRequires Blnk Core v0.10.0+ (`router.POST(\"/multi-search\", a.MultiSearch)` in\n[`api/api.go`](https://github.com/blnkfinance/blnk/blob/master/api/api.go)). This\nSDK is aligned with Core 0.15.4.\n\n### DB filter\n\n```typescript\nconst { Search } = blnk;\n\nconst filtered = await Search.filter(\n  {\n    filters: [{ field: 'status', operator: 'eq', value: 'APPLIED' }],\n    logical_operator: 'and',\n    sort_by: 'created_at',\n    sort_order: 'desc',\n    include_count: true,\n    limit: 20,\n    offset: 0,\n  },\n  'transactions',\n);\n// filtered.data?.data — matching transaction records\n// filtered.data?.total_count — present when include_count is true\n```\n\nSee the [Search via DB reference](https://docs.blnkfinance.com/reference/search-db) for supported operators and fields.\n\n### Typesense reindex\n\n```typescript\nconst { Search } = blnk;\n\nconst reindex = await Search.startReindex({ batch_size: 1000 });\n// reindex.data?.message — \"Reindex operation started\"\n// reindex.data?.progress.status — \"pending\" | \"in_progress\" | \"completed\" | \"failed\"\n```\n\nSee the [Start reindex reference](https://docs.blnkfinance.com/reference/start-reindex).\n\nPoll progress after starting a reindex:\n\n```typescript\nconst status = await Search.getReindexStatus();\n// status.data?.status — \"in_progress\" | \"completed\" | \"failed\"\n// status.data?.phase — e.g. \"indexing_transactions\" or \"done\"\n```\n\nSee the [Get reindex status reference](https://docs.blnkfinance.com/reference/get-reindex).\n\n---\n\n## Reconciliation\n\n| Method | Endpoint | Use case |\n|--------|----------|----------|\n| `Reconciliation.upload(file, source)` | `POST /reconciliation/upload` | Upload external data file |\n| `Reconciliation.createMatchingRule(data)` | `POST /reconciliation/matching-rules` | Define match criteria |\n| `Reconciliation.updateMatchingRule(id, data)` | `PUT /reconciliation/matching-rules/{rule_id}` | Update an existing matching rule |\n| `Reconciliation.deleteMatchingRule(id)` | `DELETE /reconciliation/matching-rules/{rule_id}` | Remove a matching rule |\n| `Reconciliation.run(data)` | `POST /reconciliation/start` | Start batch reconciliation from upload |\n| `Reconciliation.runInstant(data)` | `POST /reconciliation/start-instant` | Reconcile inline external transactions |\n| `Reconciliation.get(id)` | `GET /reconciliation/{reconciliation_id}` | View reconciliation status and counts |\n\n### Update a matching rule\n\n```typescript\nconst { Reconciliation } = blnk;\n\nconst updated = await Reconciliation.updateMatchingRule('rule_abc123', {\n  name: 'Updated matcher',\n  description: 'Amount with 2% drift matcher',\n  criteria: [\n    { field: 'amount', operator: 'equals', allowable_drift: 0.02 },\n    { field: 'currency', operator: 'equals' },\n  ],\n});\n// updated.data?.rule_id, updated.data?.updated_at\n```\n\nSee the [Update matching rule reference](https://docs.blnkfinance.com/reference/update-matching-rule).\n\n### Delete a matching rule\n\n```typescript\nconst { Reconciliation } = blnk;\n\nconst deleted = await Reconciliation.deleteMatchingRule('rule_abc123');\n// deleted.data?.message — \"Matching rule deleted successfully\"\n```\n\nSee the [Delete matching rule reference](https://docs.blnkfinance.com/reference/delete-matching-rule).\n\n### Get reconciliation status\n\n```typescript\nconst { Reconciliation } = blnk;\n\nconst status = await Reconciliation.get('recon_3803ea0d-28b4-4c73-a36b-5a9eb7a3edfd');\n// status.data?.status — e.g. started, in_progress, completed, failed\n// status.data?.matched_transactions, unmatched_transactions\n```\n\nSee the [View reconciliation details reference](https://docs.blnkfinance.com/reference/get-reconciliations).\n\n### Start batch reconciliation\n\n`Reconciliation.run` starts reconciliation from a prior upload (`POST /reconciliation/start`). Core 0.15.0 returns only a reconciliation ID — poll `Reconciliation.get(id)` or listen for `reconciliation.completed` / `reconciliation.failed` webhooks for results.\n\n```typescript\nconst { Reconciliation } = blnk;\n\nconst started = await Reconciliation.run({\n  upload_id: upload.data!.upload_id,\n  strategy: 'one_to_one',\n  dry_run: true,\n  grouping_criteria: 'amount',\n  matching_rule_ids: [rule.data!.rule_id],\n});\n// started.data?.reconciliation_id — use with Reconciliation.get() or webhooks\n```\n\nSee the [Start reconciliation reference](https://docs.blnkfinance.com/reference/start-reconciliation).\n\n### Instant reconciliation\n\n```typescript\nconst { Reconciliation } = blnk;\n\nconst instant = await Reconciliation.runInstant({\n  external_transactions: [\n    {\n      id: 'txn_1',\n      amount: 5.49,\n      reference: 'INV-2023-002',\n      currency: 'GBP',\n      description: 'Card payment',\n      date: '2024-11-15T14:25:30Z',\n      source: 'bank-api',\n    },\n  ],\n  strategy: 'one_to_one',\n  dry_run: true,\n  matching_rule_ids: ['rule_abc123'],\n});\n// instant.data?.reconciliation_id — reconciliation run ID\n```\n\nSee the [Instant reconciliation reference](https://docs.blnkfinance.com/reference/instant-reconciliation).\n\n---\n\n## Metadata\n\n| Method | Endpoint | Use case |\n|--------|----------|----------|\n| `Metadata.update(id, data)` | `POST /{id}/metadata` | Add or update metadata on a ledger, transaction, balance, or identity |\n\n### Update metadata\n\n```typescript\nconst { Metadata } = blnk;\n\nconst updated = await Metadata.update('ldg_073f7ffe-9dfd-42ce-aa50-d1dca1788adc', {\n  meta_data: {\n    project_owner: 'Acme LLC',\n    update_status: 'Approved',\n  },\n});\n// updated.data?.meta_data — merged metadata from Core\n```\n\nSee the [Update metadata reference](https://docs.blnkfinance.com/reference/update-metadata).\n\n---\n\n## Hooks\n\n| Method | Endpoint | Use case |\n|--------|----------|----------|\n| `Hooks.create(data)` | `POST /hooks` | Register a pre- or post-transaction webhook |\n| `Hooks.list(options?)` | `GET /hooks` | List hooks, optionally by `type` query |\n| `Hooks.get(id)` | `GET /hooks/{id}` | View hook details |\n| `Hooks.update(id, data)` | `PUT /hooks/{id}` | Update an existing webhook |\n| `Hooks.delete(id)` | `DELETE /hooks/{id}` | Delete a webhook |\n\n> Hook management requires the **master key** (`server.secret_key`) in `X-Blnk-Key`. Regular API keys return `403`.\n\n### Register a hook\n\n```typescript\nconst { Hooks } = blnk;\n\nconst hook = await Hooks.create({\n  name: 'Pre-transaction validation',\n  url: 'https://api.example.com/validate',\n  type: 'PRE_TRANSACTION',\n  active: true,\n  timeout: 30,\n  retry_count: 3,\n});\n// hook.data?.id — registered hook ID\n```\n\nSee the [Register hooks reference](https://docs.blnkfinance.com/reference/create-hooks).\n\n### List hooks\n\n```typescript\nconst allHooks = await Hooks.list();\nconst preTxnHooks = await Hooks.list({ type: 'PRE_TRANSACTION' });\n```\n\nSee the [List hooks by type reference](https://docs.blnkfinance.com/reference/list-hooks-by-type).\n\n### View a hook\n\n```typescript\nconst hookDetails = await Hooks.get(hook.data!.id);\n// hookDetails.data?.name, hookDetails.data?.active, etc.\n```\n\nSee the [View hooks reference](https://docs.blnkfinance.com/reference/view-hooks).\n\n### Update a hook\n\n```typescript\nconst updated = await Hooks.update(hook.data!.id, {\n  name: 'Pre-transaction validation (updated)',\n  url: 'https://api.example.com/validate-v2',\n  type: 'PRE_TRANSACTION',\n  active: false,\n  timeout: 45,\n  retry_count: 5,\n});\n```\n\nSee the [Update hooks reference](https://docs.blnkfinance.com/reference/update-hooks).\n\n### Delete a hook\n\n```typescript\nconst deleted = await Hooks.delete(hook.data!.id);\n// deleted.data?.message — \"hook deleted successfully\"\n```\n\nSee the [Delete hooks reference](https://docs.blnkfinance.com/reference/delete-hooks).\n\n---\n\n## API Keys\n\n| Method | Endpoint | Use case |\n|--------|----------|----------|\n| `ApiKeys.create(data)` | `POST /api-keys` | Create a scoped API key |\n| `ApiKeys.list(options?)` | `GET /api-keys` | List API keys for an owner |\n| `ApiKeys.delete(id, options?)` | `DELETE /api-keys/{id}` | Revoke an API key |\n\n> API key management requires the **master key** or scoped permissions (`api-keys:write` to create, `api-keys:read` to list, `api-keys:delete` to revoke). The raw `key` value is only returned once at creation.\n\n### Create an API key\n\n```typescript\nconst { ApiKeys } = blnk;\n\nconst apiKey = await ApiKeys.create({\n  name: 'Service Account',\n  owner: 'merchant_a',\n  scopes: ['ledgers:read', 'balances:write'],\n  expires_at: '2026-03-11T00:00:00Z',\n});\n// apiKey.data?.key — store securely; shown only once\n```\n\nSee the [Create API key reference](https://docs.blnkfinance.com/reference/create-api-key).\n\n### List API keys\n\n```typescript\nconst keys = await ApiKeys.list({ owner: 'merchant_a' });\n// keys.data?.[0]?.api_key_id, keys.data?.[0]?.scopes, etc.\n```\n\nSee the [List API keys reference](https://docs.blnkfinance.com/reference/get-api-key).\n\n### Revoke an API key\n\n```typescript\nawait ApiKeys.delete('api_key_abc123', { owner: 'merchant_a' });\n// 204 No Content on success; response.data is null\n```\n\nSee the [Revoke API key reference](https://docs.blnkfinance.com/reference/delete-api-key).\n\n---\n\n## Additional Resources\n\nFor more examples and advanced use cases, please refer to the [Examples Code](https://github.com/blnkfinance/blnk-ts/tree/main/examples).\n\n### Issue Reporting\nIf you encounter any issues, please [report them on GitHub](https://github.com/blnkfinance/blnk/issues).\n","readmeFilename":"README.md"}