{"_id":"@blueticked/sdk","_rev":"8-14f5cf936da76177e7da8ff153e22aad","name":"@blueticked/sdk","dist-tags":{"latest":"0.7.0"},"versions":{"0.2.0":{"name":"@blueticked/sdk","version":"0.2.0","keywords":["blueticked","whatsapp","whatsapp-api","sms","email","messaging","notifications","api","typescript","south-africa"],"author":{"name":"Blueticked"},"license":"MIT","_id":"@blueticked/sdk@0.2.0","maintainers":[{"name":"shaunschoeman","email":"accounts@blueticked.com"}],"homepage":"https://blueticked.com/docs/sdk","bugs":{"email":"developers@blueticked.com"},"dist":{"shasum":"5c9308d78dc9aa5a3a9fa52f72fcea6a69b47346","tarball":"https://registry.npmjs.org/@blueticked/sdk/-/sdk-0.2.0.tgz","fileCount":7,"integrity":"sha512-JH2tMsk8XA0ij8njha8tcqipMa9Fej8dDkgQtrLuWtB8EODIO8FiZdWy6EK0RgSjA7f1XSMnqxbe2GS6yi8TkA==","signatures":[{"sig":"MEUCIQDgR4inLol3cERtZjXIwIFA0ZWHoM/KNeC+NWiY/2QL1QIgGZKM7rboRQWCYgXp19YjcOU6iMJ9Z1JklBYn1uQI4+4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":237455},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18.0.0"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}}},"gitHead":"7ca819593b7e492fb1365c55e076d03df1158f0e","scripts":{"lint":"eslint src","test":"vitest run","build":"tsup src/index.ts --format esm,cjs --dts --clean","gen:types":"openapi-typescript ./openapi.json -o ./src/generated/openapi-types.ts","typecheck":"tsc --noEmit","prepublishOnly":"pnpm test && pnpm build"},"_npmUser":{"name":"shaunschoeman","email":"accounts@blueticked.com"},"_npmVersion":"11.9.0","description":"Official TypeScript SDK for the Blueticked API — send WhatsApp, SMS and email from one endpoint. Typed, zero-dependency, generated from the published OpenAPI spec.","directories":{},"sideEffects":false,"_nodeVersion":"24.14.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.2","tsup":"^8.3.5","vitest":"^2.1.9","typescript":"^5.7.2","@blueticked/config":"workspace:*","openapi-typescript":"^7.4.4"},"_npmOperationalInternal":{"tmp":"tmp/sdk_0.2.0_1786229753115_0.8884667474356414","host":"s3://npm-registry-packages-npm-production"},"deprecated":"0.6.1 exposes the API key via JSON.stringify(client) - upgrade to 0.7.0"},"0.3.0":{"name":"@blueticked/sdk","version":"0.3.0","keywords":["blueticked","whatsapp","whatsapp-api","sms","email","messaging","notifications","api","typescript","south-africa"],"author":{"name":"Blueticked"},"license":"MIT","_id":"@blueticked/sdk@0.3.0","maintainers":[{"name":"shaunschoeman","email":"accounts@blueticked.com"}],"homepage":"https://blueticked.com/docs/sdk","bugs":{"email":"developers@blueticked.com"},"dist":{"shasum":"9a77bff900abfac2e19242dd16a207688d3e7f2b","tarball":"https://registry.npmjs.org/@blueticked/sdk/-/sdk-0.3.0.tgz","fileCount":7,"integrity":"sha512-Ylvq1myuf7WzY36fE1kdVCqu05FNFJstTPSGrv6bKm2eszVqWHNt11zISD9xHcpAwQSpH+x86C4Y8KYL86IKEQ==","signatures":[{"sig":"MEQCIEIXsjmwCccWfkOIjbCUD86Z0HJos9ZSIWmpuxaM8b0+AiARzppjdyDrmsuyfEdIXGp2BavEiJYlrc4lObN7+1Pxnw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":255892},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18.0.0"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}}},"gitHead":"475c6f1cb86042b9019b30e07d84b73df73040c5","scripts":{"lint":"eslint src","test":"vitest run","build":"tsup src/index.ts --format esm,cjs --dts --clean","gen:types":"openapi-typescript ./openapi.json -o ./src/generated/openapi-types.ts","typecheck":"tsc --noEmit","prepublishOnly":"pnpm test && pnpm build"},"_npmUser":{"name":"shaunschoeman","email":"accounts@blueticked.com"},"_npmVersion":"11.9.0","description":"Official TypeScript SDK for the Blueticked API — send WhatsApp, SMS and email from one endpoint. Typed, zero-dependency, generated from the published OpenAPI spec.","directories":{},"sideEffects":false,"_nodeVersion":"24.14.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.2","tsup":"^8.3.5","vitest":"^2.1.9","typescript":"^5.7.2","@blueticked/config":"workspace:*","openapi-typescript":"^7.4.4"},"_npmOperationalInternal":{"tmp":"tmp/sdk_0.3.0_1786236946386_0.9175421679611064","host":"s3://npm-registry-packages-npm-production"},"deprecated":"0.6.1 exposes the API key via JSON.stringify(client) - upgrade to 0.7.0"},"0.4.0":{"name":"@blueticked/sdk","version":"0.4.0","keywords":["blueticked","whatsapp","whatsapp-api","sms","email","messaging","notifications","api","typescript","south-africa"],"author":{"name":"Blueticked"},"license":"MIT","_id":"@blueticked/sdk@0.4.0","maintainers":[{"name":"shaunschoeman","email":"accounts@blueticked.com"}],"homepage":"https://blueticked.com/docs/sdk","bugs":{"email":"developers@blueticked.com"},"dist":{"shasum":"5b474273c2cfcf75aad06399f11fcc247bcbea50","tarball":"https://registry.npmjs.org/@blueticked/sdk/-/sdk-0.4.0.tgz","fileCount":7,"integrity":"sha512-p3IeV79mgxOLAlGUiVorMp19f5ft5Ou+0NRrFLYZspZcQnqLHwv4/0ydvgGxdmsEH5dRBw8pJgfwuQGemMmDjw==","signatures":[{"sig":"MEUCIA8l7WXb4rrzSHXibj0DCqm7hcRtskQ2MaHO2zaP3vToAiEA+6RzP/2zqpXYNuPFxC0u6CxQdfhGKqzFpuXLxvaGMEE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":261616},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18.0.0"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}}},"gitHead":"e732b0377a576b18a8aaa0b2c00eef21dbc7072a","scripts":{"lint":"eslint src","test":"vitest run","build":"tsup src/index.ts --format esm,cjs --dts --clean","gen:types":"openapi-typescript ./openapi.json -o ./src/generated/openapi-types.ts","typecheck":"tsc --noEmit","prepublishOnly":"pnpm test && pnpm build"},"_npmUser":{"name":"shaunschoeman","email":"accounts@blueticked.com"},"_npmVersion":"11.9.0","description":"Official TypeScript SDK for the Blueticked API — send WhatsApp, SMS and email from one endpoint. Typed, zero-dependency, generated from the published OpenAPI spec.","directories":{},"sideEffects":false,"_nodeVersion":"24.14.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.2","tsup":"^8.3.5","vitest":"^2.1.9","typescript":"^5.7.2","@blueticked/config":"workspace:*","openapi-typescript":"^7.4.4"},"_npmOperationalInternal":{"tmp":"tmp/sdk_0.4.0_1786239887731_0.6590893527094162","host":"s3://npm-registry-packages-npm-production"},"deprecated":"0.6.1 exposes the API key via JSON.stringify(client) - upgrade to 0.7.0"},"0.5.0":{"name":"@blueticked/sdk","version":"0.5.0","keywords":["blueticked","whatsapp","whatsapp-api","sms","email","messaging","notifications","api","typescript","south-africa"],"author":{"name":"Blueticked"},"license":"MIT","_id":"@blueticked/sdk@0.5.0","maintainers":[{"name":"shaunschoeman","email":"accounts@blueticked.com"}],"homepage":"https://blueticked.com/docs/sdk","bugs":{"email":"developers@blueticked.com"},"dist":{"shasum":"a138eacb6fe7fad3265fccf07ec4d7700344f09d","tarball":"https://registry.npmjs.org/@blueticked/sdk/-/sdk-0.5.0.tgz","fileCount":7,"integrity":"sha512-+UzWwZuuzngvwx8bVjx7U2invi6ubmMm0mDb5wLeB4h57YaoZS2L59U7afjAlPywmNNGsElAx2r5GZ8UVatIlQ==","signatures":[{"sig":"MEUCIQDTSZoiNLm8WDPNSmB5I29F5NDsvUdzpnZspjgHplVCJwIgVw0ZI0osZW5Val93VbWt/Xeo80+X/lq0RNc9PERnH9E=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":274401},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18.0.0"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}}},"gitHead":"abe7be696b2c171394962b52d691d93bdb44c65e","scripts":{"lint":"eslint src","test":"vitest run","build":"tsup src/index.ts --format esm,cjs --dts --clean","gen:types":"openapi-typescript ./openapi.json -o ./src/generated/openapi-types.ts","typecheck":"tsc --noEmit","prepublishOnly":"pnpm test && pnpm build"},"_npmUser":{"name":"shaunschoeman","email":"accounts@blueticked.com"},"_npmVersion":"11.9.0","description":"Official TypeScript SDK for the Blueticked API — send WhatsApp, SMS and email from one endpoint. Typed, zero-dependency, generated from the published OpenAPI spec.","directories":{},"sideEffects":false,"_nodeVersion":"24.14.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.2","tsup":"^8.3.5","vitest":"^2.1.9","typescript":"^5.7.2","@blueticked/config":"workspace:*","openapi-typescript":"^7.4.4"},"_npmOperationalInternal":{"tmp":"tmp/sdk_0.5.0_1786280000320_0.3379920333918802","host":"s3://npm-registry-packages-npm-production"},"deprecated":"0.6.1 exposes the API key via JSON.stringify(client) - upgrade to 0.7.0"},"0.6.0":{"name":"@blueticked/sdk","version":"0.6.0","keywords":["blueticked","whatsapp","whatsapp-api","sms","email","messaging","notifications","api","typescript","south-africa"],"author":{"name":"Blueticked"},"license":"MIT","_id":"@blueticked/sdk@0.6.0","maintainers":[{"name":"shaunschoeman","email":"accounts@blueticked.com"}],"homepage":"https://blueticked.com/docs/sdk","bugs":{"email":"developers@blueticked.com"},"dist":{"shasum":"576724cd36ca8703a50ed12fe3ebfcaccf984038","tarball":"https://registry.npmjs.org/@blueticked/sdk/-/sdk-0.6.0.tgz","fileCount":7,"integrity":"sha512-Kfk+jkH3ry7WVlpshFe+VzFRTdIxS2z4WO91z09nUc2GoN5pblIxUIZsx+EqE96FOvONmyU+iR5qhG5B2AHe5Q==","signatures":[{"sig":"MEUCIBabvORbTPgBFhsoiqyGOcJptclRgT122lb2dfJZNnbeAiEA3SgAm/GYv226UEVpRWf6FKLvmmLAk9DZuPor1ADmUPk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":286255},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18.0.0"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}}},"gitHead":"2a96bdaeaa16481ee6d3456ab28e74d5f4d21d5d","scripts":{"lint":"eslint src","test":"vitest run","build":"tsup src/index.ts --format esm,cjs --dts --clean","gen:types":"openapi-typescript ./openapi.json -o ./src/generated/openapi-types.ts","typecheck":"tsc --noEmit","prepublishOnly":"pnpm test && pnpm build"},"_npmUser":{"name":"shaunschoeman","email":"accounts@blueticked.com"},"_npmVersion":"11.9.0","description":"Official TypeScript SDK for the Blueticked API — send WhatsApp, SMS and email from one endpoint. Typed, zero-dependency, generated from the published OpenAPI spec.","directories":{},"sideEffects":false,"_nodeVersion":"24.14.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.2","tsup":"^8.3.5","vitest":"^2.1.9","typescript":"^5.7.2","@blueticked/config":"workspace:*","openapi-typescript":"^7.4.4"},"_npmOperationalInternal":{"tmp":"tmp/sdk_0.6.0_1786305782258_0.2768680929755212","host":"s3://npm-registry-packages-npm-production"},"deprecated":"0.6.1 exposes the API key via JSON.stringify(client) - upgrade to 0.7.0"},"0.6.1":{"name":"@blueticked/sdk","version":"0.6.1","keywords":["blueticked","whatsapp","whatsapp-api","sms","email","messaging","notifications","api","typescript","south-africa"],"author":{"name":"Blueticked"},"license":"MIT","_id":"@blueticked/sdk@0.6.1","maintainers":[{"name":"shaunschoeman","email":"accounts@blueticked.com"}],"homepage":"https://blueticked.com/docs/sdk","bugs":{"email":"developers@blueticked.com"},"dist":{"shasum":"21fec0c9d09926ab6984b9ec48b8586085eef2fe","tarball":"https://registry.npmjs.org/@blueticked/sdk/-/sdk-0.6.1.tgz","fileCount":7,"integrity":"sha512-AOejKSdJUlSov+x5ZrYpWejuSNyU2QLAtfznDgMNI+tsHO4Gyxr5pM/8MdQhCQzc2XBY2CrqQfnwPseWb5XNUg==","signatures":[{"sig":"MEUCIGIT7qLqeDin2P7E/bY26LEnlMsgWBEBvGy4wCNAg3D/AiEAy6h0xss5N48+BM2cCOCvck++0XT0xqzCAhBVrlXgMyc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":287163},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18.0.0"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}}},"gitHead":"4c4b19a4209e00d9102a6e59d31641c24f6e14fb","scripts":{"lint":"eslint src","test":"vitest run","build":"tsup src/index.ts --format esm,cjs --dts --clean","gen:types":"openapi-typescript ./openapi.json -o ./src/generated/openapi-types.ts","typecheck":"tsc --noEmit","prepublishOnly":"pnpm test && pnpm build"},"_npmUser":{"name":"shaunschoeman","email":"accounts@blueticked.com"},"_npmVersion":"11.9.0","description":"Official TypeScript SDK for the Blueticked API — send WhatsApp, SMS and email from one endpoint. Typed, zero-dependency, generated from the published OpenAPI spec.","directories":{},"sideEffects":false,"_nodeVersion":"24.14.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.2","tsup":"^8.3.5","vitest":"^2.1.9","typescript":"^5.7.2","@blueticked/config":"workspace:*","openapi-typescript":"^7.4.4"},"_npmOperationalInternal":{"tmp":"tmp/sdk_0.6.1_1786350161283_0.5963354910863126","host":"s3://npm-registry-packages-npm-production"},"deprecated":"0.6.1 exposes the API key via JSON.stringify(client) - upgrade to 0.7.0"},"0.7.0":{"name":"@blueticked/sdk","version":"0.7.0","keywords":["blueticked","whatsapp","whatsapp-api","sms","email","messaging","notifications","api","typescript","south-africa"],"author":{"name":"Blueticked"},"license":"MIT","_id":"@blueticked/sdk@0.7.0","maintainers":[{"name":"shaunschoeman","email":"accounts@blueticked.com"}],"homepage":"https://blueticked.com/docs/sdk","bugs":{"email":"developers@blueticked.com"},"dist":{"shasum":"c124b7cecfb7d1aacff47100e820a4b7b10683ba","tarball":"https://registry.npmjs.org/@blueticked/sdk/-/sdk-0.7.0.tgz","fileCount":7,"integrity":"sha512-O4s/OWEE6m43Djo/TYT5xV8ZbG6whGwADILdvOmv7viiMFXc2T7PybfvAVZh7MjgvqRgX5XQlP6zxgXs5fSgUg==","signatures":[{"sig":"MEQCIGDHVgF5N6k28GOL1yGvhwO03GrQ0D/QfKNkCbAFuxyWAiBNTD00vThMwB0j8egDCqu9VnwsN/htSAPJS4DI+kxxmQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":327424},"main":"./dist/index.cjs","type":"module","_from":"file:blueticked-sdk-0.7.0.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18.0.0"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}}},"scripts":{"lint":"eslint src","test":"vitest run","build":"tsup src/index.ts --format esm,cjs --dts --clean","gen:types":"openapi-typescript ./openapi.json -o ./src/generated/openapi-types.ts","typecheck":"tsc --noEmit"},"_npmUser":{"name":"shaunschoeman","email":"accounts@blueticked.com"},"_resolved":"C:\\Users\\shaun\\AppData\\Local\\Temp\\ae87d21952f9180cf2d097f21160603a\\blueticked-sdk-0.7.0.tgz","_integrity":"sha512-O4s/OWEE6m43Djo/TYT5xV8ZbG6whGwADILdvOmv7viiMFXc2T7PybfvAVZh7MjgvqRgX5XQlP6zxgXs5fSgUg==","_npmVersion":"11.9.0","description":"Official TypeScript SDK for the Blueticked API — send WhatsApp, SMS and email from one endpoint. Typed, zero-dependency, generated from the published OpenAPI spec.","directories":{},"sideEffects":false,"_nodeVersion":"24.14.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.2","tsup":"^8.3.5","vitest":"^2.1.9","typescript":"^5.7.2","@blueticked/config":"0.0.0","openapi-typescript":"^7.4.4"},"_npmOperationalInternal":{"tmp":"tmp/sdk_0.7.0_1788128003724_0.6000050963758992","host":"s3://npm-registry-packages-npm-production"}}},"time":{"created":"2026-08-08T22:55:52.943Z","modified":"2026-08-30T22:14:12.252Z","0.2.0":"2026-08-08T22:55:53.262Z","0.3.0":"2026-08-09T00:55:46.537Z","0.4.0":"2026-08-09T01:44:47.878Z","0.5.0":"2026-08-09T12:53:20.459Z","0.6.0":"2026-08-09T20:03:02.410Z","0.6.1":"2026-08-10T08:22:41.541Z","0.7.0":"2026-08-30T22:13:23.900Z"},"bugs":{"email":"developers@blueticked.com"},"author":{"name":"Blueticked"},"license":"MIT","homepage":"https://blueticked.com/docs/sdk","keywords":["blueticked","whatsapp","whatsapp-api","sms","email","messaging","notifications","api","typescript","south-africa"],"description":"Official TypeScript SDK for the Blueticked API — send WhatsApp, SMS and email from one endpoint. Typed, zero-dependency, generated from the published OpenAPI spec.","maintainers":[{"name":"shaunschoeman","email":"accounts@blueticked.com"}],"readme":"# @blueticked/sdk\n\nOfficial TypeScript SDK for the [Blueticked](https://blueticked.com) API —\nWhatsApp business messaging for developers. Zero dependencies; runs on Node 18+,\nserverless and edge runtimes.\n\n```bash\nnpm install @blueticked/sdk\n```\n\n> **Server-side only.** Your API key is a bearer secret: it sends messages and\n> spends your prepaid wallet. Never import this package into browser or mobile\n> code, where every visitor can read it — call Blueticked from your server and\n> expose your own endpoint. The client refuses to construct in a browser for\n> this reason; a genuinely trusted first-party context can pass\n> `dangerouslyAllowBrowser: true`.\n\n## Send your first message\n\n```ts\nimport { Blueticked } from \"@blueticked/sdk\";\n\nconst bt = new Blueticked({ apiKey: process.env.BLUETICKED_API_KEY! });\n\nconst message = await bt.messages.send({\n  channel: \"whatsapp\",\n  to: { phone: \"+27821234567\" },\n  template_id: \"your-approved-template-id\",\n  template_variables: { \"1\": \"Sam\" },\n});\n\nconsole.log(message.status); // \"queued\"\n```\n\nUse a `blu_test_` key to build your whole integration without a WhatsApp\nBusiness Account — test sends are simulated end to end and never bill.\n\n## Send a customer statement (PDF per recipient)\n\n```ts\nawait bt.messages.send({\n  channel: \"whatsapp\",\n  to: { phone: \"+27821234567\" },\n  template_id: \"statement-template-id\", // template with a DOCUMENT header\n  template_variables: { \"1\": \"Sam\", \"2\": \"May 2026\" },\n  document: {\n    url: \"https://files.example.com/statements/acct-1001.pdf\",\n    filename: \"Statement May 2026.pdf\",\n  },\n});\n```\n\n## Bulk campaign\n\n```ts\nawait bt.campaigns.create({\n  name: \"May statements\",\n  channel: \"whatsapp\",\n  audience: { type: \"list\", list_id: \"...\" },\n  template_id: \"statement-template-id\",\n  template_variables: { \"1\": { source: \"first_name\" } },\n  document_source: {\n    mode: \"url_field\",\n    field_key: \"statement_url\",\n    filename_template: \"Statement {{first_name}}.pdf\",\n    missing_policy: \"skip\",\n  },\n  mode: \"now\",\n});\n```\n\n## Resources\n\nThe client exposes one property per resource:\n\n| Resource           | Methods                                                                                                                                   |\n| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------- |\n| `bt.workspace`     | `getContext`, `getReadiness`                                                                                                              |\n| `bt.businesses`    | `list`, `create`, `createKey`                                                                                                             |\n| `bt.messages`      | `send`, `get`                                                                                                                             |\n| `bt.contacts`      | `upsert`, `list`, `listAll`, `get`, `update`, `delete`, `erase`                                                                           |\n| `bt.groups`        | `list`, `listAll`, `create`, `get`, `update`, `delete`, `members.add`, `members.remove`                                                   |\n| `bt.segments`      | `list`, `listAll`                                                                                                                         |\n| `bt.campaigns`     | `create`, `list`, `listAll`, `get`                                                                                                        |\n| `bt.templates`     | `create`, `list`, `listAll`, `get`                                                                                                        |\n| `bt.flows`         | `create`, `list`, `listAll`, `get`, `update`, `delete`, `publish`                                                                         |\n| `bt.conversations` | `list`, `listAll`, `get`, `update`, `messages`, `messagesAll`                                                                             |\n| `bt.channels`      | `list`, `whatsapp.readiness`, `createConnectSession`, `listConnectSessions`, `revokeConnectSession`                                       |\n| `bt.email`         | `sendingDomain.get/register/verify/remove`                                                                                                |\n| `bt.suppression`   | `list`, `listAll`, `add`, `remove`                                                                                                        |\n| `bt.wallet`        | `get`, `ledger`, `ledgerAll`                                                                                                              |\n| `bt.events`        | `send`                                                                                                                                    |\n| `bt.integrations`  | `list`, `listAll`, `create`, `get`, `update`, `delete`, `deliveries`, `deliveriesAll`, `test`                                             |\n| `bt.conversions`   | `record`                                                                                                                                  |\n| `bt.commerce`      | `listProducts`, `createProduct`, `updateProduct`, `deleteProduct`, `uploadProductImage`, `listOrders`, `ordersOverview`, `getOrder`, `setOrderFulfilment`, `listDiscounts`, `createDiscount`, `updateDiscount`, `deleteDiscount`, `getFulfilment`, `setFulfilment`, `listPaymentLinks`, `createPaymentLink` |\n| `bt.automations`   | `list`, `recipes`, `get`, `create`, `update`, `delete`                                                                                              |\n| `bt.journeys`      | `list`, `get`, `enroll`                                                                                                                   |\n| `bt.aiAgents`      | `list`, `get`, `chat`, `handoff`, `pause`                                                                                                                  |\n| `bt.sites`         | `list`, `create`, `publish`, `unpublish`                                                                                                  |\n| `bt.formSubmissions` | `list`, `markRead`                                                                                                                      |\n| `bt.webhooks`      | `list`, `create`, `update`, `rotateSecret`, `delete`, `test`, `deliveries`, `deliveriesAll`, `replayDelivery`, `verify`, `constructEvent` |\n\nSome writes are one-directional because the API is: a new automation always\nlands PAUSED, `bt.aiAgents.pause` has no `resume`, and publishing a site needs\nthe separate `sites:publish` scope. Switching on anything that will talk to\ncustomers stays a decision a human makes in the dashboard.\n\n## Group a contact and fire an event\n\n```ts\nconst group = await bt.groups.create({ name: \"May statements\" });\nawait bt.groups.members.add(group.id, [\"contact-id-1\", \"contact-id-2\"]);\n\n// Later, when your billing system settles an invoice, let automations react:\nawait bt.events.send({\n  event: \"invoice.paid\",\n  phone: \"+27821234567\",\n  data: { amount: 199, plan: \"pro\" },\n});\n```\n\n## Check the wallet balance\n\n```ts\nconst wallet = await bt.wallet.get();\nconsole.log(wallet.balance_zar_cents, wallet.balance_credits);\n\nconst ledger = await bt.wallet.ledger({ limit: 50 });\nfor (const entry of ledger.data) {\n  console.log(entry.direction, entry.amount_zar_cents, entry.reason);\n}\n```\n\n## Wire up an outbound integration\n\n```ts\nconst integration = await bt.integrations.create({\n  name: \"Practice booking API\",\n  endpoint_url: \"https://booking.example.com/hooks/blueticked\",\n  auth_type: \"signature\", // a signing secret is generated for you\n});\n\n// Integrations start paused — verify the endpoint, then it flips to active.\nconst result = await bt.integrations.test(integration.id);\nif (result.passed) {\n  console.log(\"Live:\", result.delivery_id);\n}\n```\n\n## Erase a contact (POPIA)\n\n`await bt.contacts.erase(\"contact-id\")` is irreversible: it anonymises PII in\nplace, scrubs related records, and answers `{ erased_at, already_erased }`.\n\n## Verify webhooks\n\nPass the whole incoming header set (a Web `Headers` or Node's `req.headers`) and\nyour endpoint secret. This is the rotation-grace-aware path: on rotation\nBlueticked co-signs every delivery with both the new and old secret for 24 hours\n(`x-blueticked-signature` and `x-blueticked-signature-previous`), so deliveries\nkeep verifying whether or not you have swapped your stored secret yet.\n\n```ts\n// In your webhook route — pass the RAW body, not re-serialized JSON.\nconst event = await bt.webhooks.constructEvent(\n  rawBody,\n  req.headers, // both signature headers are checked for you\n  process.env.BLUETICKED_WEBHOOK_SECRET!,\n);\n\nif (event.event === \"message.delivered\") {\n  // ...\n}\n```\n\nDuring your own rollover, `bt.webhooks.verify(rawBody, req.headers, [newSecret,\noldSecret])` accepts either secret. The single-signature form\n`verify(rawBody, signatureString, secret)` still works for back-compat.\n\nInspect and replay deliveries:\n\n```ts\nawait bt.webhooks.test(\"webhook-id\", { event: \"message.delivered\", channel: \"sms\" });\n\nconst failures = await bt.webhooks.deliveries({ status: \"failed\" });\nfor (const attempt of failures.data) {\n  console.log(attempt.response_status, attempt.response_body);\n}\n\n// Fix the receiver first. Replays must be harmless when processed twice.\nawait bt.webhooks.replayDelivery(\"delivery-id\", { idempotencyKey: \"repair-1\" });\n```\n\n## Auto-pagination\n\nEvery `list()` returns one `Page` (`data`, `next_cursor`, `has_more`). To sweep\nevery row without a hand-written cursor loop, use the matching `listAll()` — an\nasync iterator that threads cursors for you and yields items one at a time:\n\n```ts\nfor await (const contact of bt.contacts.listAll({ tag: [\"vip\"] })) {\n  console.log(contact.id);\n}\n```\n\n`listAll()` exists on `contacts`, `groups`, `segments`, `campaigns`, `templates`,\n`flows`, `conversations`, `suppression` and `integrations`; the id-scoped lists have\n`conversations.messagesAll(id)` and `integrations.deliveriesAll(id)`, and the wallet\nhas `wallet.ledgerAll()`. Iteration is bounded — after 10,000 pages it throws\n`auto_pagination_limit`, so a misbehaving cursor cannot spin forever. `list()` is\nunchanged for one page at a time.\n\n## Errors\n\nEvery non-2xx response throws a typed `BluetickedError`:\n\n```ts\nimport { BluetickedError } from \"@blueticked/sdk\";\n\ntry {\n  await bt.messages.send(/* ... */);\n} catch (err) {\n  if (err instanceof BluetickedError) {\n    console.error(err.code, err.status, err.requestId);\n    // Some codes carry structured context — `resource_in_use` names what\n    // still references the resource, `plan_limit_reached` names the limit.\n    if (err.details) console.error(err.details);\n  }\n}\n```\n\n### What to do about it, as data\n\nEvery error carries `nextSteps` — the remedy, structured, so you branch on it\ninstead of parsing the message:\n\n```ts\ncatch (err) {\n  if (!(err instanceof BluetickedError)) throw err;\n\n  if (err.needsHuman) {\n    // A person must act in a browser: no rewrite of this request can work.\n    for (const s of err.nextSteps) notifyOperator(s.description, s.url);\n    return;\n  }\n  if (err.isTransient) return scheduleRetry(err); // upstream review or outage\n  throw err;                                      // your bug — fix the call\n}\n```\n\nEach step has a stable `action`, a `by` of `caller` | `human` | `waiting`, a\none-sentence `description`, and where relevant the `endpoint` that fixes it or\nthe `url` a person should open. The mistake this prevents is treating `503\nchannel_unavailable` as transient: nobody has connected WhatsApp, so every retry\nfails identically — the client throws at once instead of spending the budget.\n\n### Rehearsing failures\n\nA sandbox key can ask for a specific failure, so error handling is tested before\nit is met in production:\n\n```ts\nawait bt.request(\"GET\", \"/v1/readiness\", undefined, {\n  headers: { \"X-Simulate-Error\": \"channel_unavailable\" },\n});\n// Throws the real error: real status, real code, real nextSteps.\n// `err.details.simulated === true` lets a test assert it took effect.\n```\n\nAn unrecognised code is answered with the list you may request. Live keys\n**refuse** the header rather than ignore it — a suite that appeared to pass\nagainst a live key would prove nothing.\n\n### Retries and idempotency\n\nRequests are retried on 429 and 5xx, honouring `Retry-After`. A 429 is always\nsafe to retry: it was refused before any work happened.\n\nA POST is retried only where the route **deduplicates on `Idempotency-Key`** —\nmessages, campaigns, contacts, templates, flows, groups, webhooks,\nintegrations, `events/send`, flow publish and delivery replay. There a key is\ngenerated for you (override with `idempotencyKey`), so a retry cannot\ndouble-send. Any other POST fails at once with `retry_unsafe`: the first\nattempt may have landed before the error reached you, so retrying would create\na second resource. An error you can see beats a duplicate you cannot.\n\n### Anything without a typed method\n\nEvery endpoint in the spec has a typed method — the coverage guard fails the\nbuild otherwise. The escape hatch covers the one gap a published package cannot\nclose itself: a route shipped after the version you installed. Same auth,\nretries and errors.\n\nThe response type is yours to declare, so declare the envelope the route really\nsends; the exported types save writing nested shapes by hand:\n\n```ts\nimport type { CommerceOrder } from \"@blueticked/sdk\";\n\nconst res = await bt.request<{\n  ok: boolean;\n  orders: CommerceOrder[];\n  total: number;\n}>(\"GET\", \"/v1/commerce/orders?limit=10\");\n```\n\n## Docs\n\n- Reference and guides: https://blueticked.com/docs\n- OpenAPI 3.1 document: https://app.blueticked.com/api/v1/openapi.json\n- Written for coding agents: https://app.blueticked.com/llms-full.txt\n\nAll three are public. `app.blueticked.com/developers/docs` is the same content\nbehind sign-in.\n\n## Updating types\n\nRequest and response types are hand-maintained in `src/types/` and\n`src/resources/`; a committed OpenAPI snapshot (`openapi.json`) and its\ngenerated mirror (`src/generated/openapi-types.ts`) keep them honest. When the\nAPI surface changes, refresh both from the repo root and fix whatever the guards\nname:\n\n```bash\npnpm sdk:gen\npnpm --filter @blueticked/sdk test\npnpm --filter @blueticked/sdk typecheck\n```\n\nSix guards fail on drift a review would miss. Each was written after the defect\nit now catches, so none of them is decorative:\n\n- `response-shape-drift` — any method declaring a response key the API never\n  sends, hiding a required one, or dropping `has_more` from a list.\n- `openapi-drift` — the core drift-prone types, pinned at compile time as well.\n- `coverage` — an endpoint the spec documents that no SDK method reaches.\n- `readme-method-table` — this README's Resources table naming a method that\n  does not exist, or omitting one that does.\n- `docs-examples` — a `bt.request<T>()` example, here or in `src/index.ts`,\n  declaring a response the route does not send.\n- `error-codes-documented` — JSDoc naming an error code that is neither in the\n  contract's enum nor minted by this client.\n\nDrift that predates a guard is recorded in `tests/support/known-shape-gaps.ts`\nwith a reason each, and that ledger is itself checked for entries which no\nlonger drift — so it cannot rot into a silence.\n\nThe snapshot's REQUEST schemas come from documentation examples rather than the\nAPI's validators, so they can carry fields the server derives itself. The guards\ntherefore judge responses, where the spec is authoritative.\n","readmeFilename":"README.md"}