{"_id":"@boomin/sdk","_rev":"7-712899327c6952599e67476132f5bf5d","name":"@boomin/sdk","dist-tags":{"latest":"1.0.0-beta.7"},"versions":{"1.0.0-beta.1":{"name":"@boomin/sdk","version":"1.0.0-beta.1","keywords":["boomin","distribution","partnerships","affiliate","referral","payouts","api","sdk"],"author":{"name":"Boomin"},"license":"MIT","_id":"@boomin/sdk@1.0.0-beta.1","maintainers":[{"name":"ikleveland","email":"kleveland.bishop@gmail.com"}],"homepage":"https://github.com/Boomin-Ai/sdk#readme","bugs":{"url":"https://github.com/Boomin-Ai/sdk/issues"},"dist":{"shasum":"c6f5be58446b245761b42bfc83015a00cf853864","tarball":"https://registry.npmjs.org/@boomin/sdk/-/sdk-1.0.0-beta.1.tgz","fileCount":12,"integrity":"sha512-QlwbyluklJtaDBxWLeNJv6YeXPSxkGi2qbbBQQyNjC7RnQUjYSLYQI4cLhN1LNAiOY7pHwM4CDfkktc9m+c9lQ==","signatures":[{"sig":"MEYCIQD0av++yDP+AznmWzy2B6kDu7j4Sy43lT/ixBds99HnZAIhAPlrMyJgFiSIxPhbbXDhwWl2ni21PcnviPBZ4by05AXL","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":109031},"main":"./src/index.js","type":"module","types":"./src/index.d.ts","engines":{"node":">=18"},"exports":{".":{"types":"./src/index.d.ts","import":"./src/index.js","default":"./src/index.js"},"./errors":{"types":"./src/errors.d.ts","import":"./src/errors.js","default":"./src/errors.js"},"./webhooks":{"types":"./src/webhooks.d.ts","import":"./src/webhooks.js","default":"./src/webhooks.js"}},"gitHead":"7f8d4b211d9d4a914d3b0958eda41528342665e7","scripts":{"test":"node --test 'test/*.test.js'","build":"node --check src/index.js && node --check src/core.js && node --check src/casing.js && node --check src/errors.js && node --check src/resources.js && node --check src/webhooks.js","pack:dry":"npm pack --dry-run","typecheck":"tsc -p tsconfig.json"},"_npmUser":{"name":"ikleveland","email":"kleveland.bishop@gmail.com"},"repository":{"url":"git+https://github.com/Boomin-Ai/sdk.git","type":"git","directory":"packages/sdk"},"_npmVersion":"10.9.2","description":"Boomin platform SDK — programmable distribution infrastructure (programs, partnerships, enrollments, distributions, deployments, performance, payouts).","directories":{},"_nodeVersion":"22.16.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.5.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk_1.0.0-beta.1_1785734136059_0.36875521341358786","host":"s3://npm-registry-packages-npm-production"}},"1.0.0-beta.2":{"name":"@boomin/sdk","version":"1.0.0-beta.2","keywords":["boomin","distribution","partnerships","affiliate","referral","payouts","api","sdk"],"author":{"name":"Boomin"},"license":"MIT","_id":"@boomin/sdk@1.0.0-beta.2","maintainers":[{"name":"ikleveland","email":"kleveland.bishop@gmail.com"}],"homepage":"https://github.com/Boomin-Ai/sdk#readme","bugs":{"url":"https://github.com/Boomin-Ai/sdk/issues"},"dist":{"shasum":"94ad7b351e4c3bd9122e22b5dfa5b13046da05f9","tarball":"https://registry.npmjs.org/@boomin/sdk/-/sdk-1.0.0-beta.2.tgz","fileCount":12,"integrity":"sha512-nuBjYJPJpobWs895jBR7CdMys+hPUcPu69yFV4R6u3GFAygl+GxLEzwNnH7/GulgY2Vss3Vxjdyj24/pmkwMmw==","signatures":[{"sig":"MEUCIQC/7H5EXHut0p7dr7USzs9+KnB285UXJPyvxyHWYY5O8QIgFzRr7X4dMHiAWiGJlnv4+MPxvCpyVb1nc0uLJ+W1Bd4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@boomin%2fsdk@1.0.0-beta.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":141972},"main":"./src/index.js","type":"module","types":"./src/index.d.ts","engines":{"node":">=18"},"exports":{".":{"types":"./src/index.d.ts","import":"./src/index.js","default":"./src/index.js"},"./errors":{"types":"./src/errors.d.ts","import":"./src/errors.js","default":"./src/errors.js"},"./webhooks":{"types":"./src/webhooks.d.ts","import":"./src/webhooks.js","default":"./src/webhooks.js"}},"gitHead":"a355c8d195ca8e979a58cc1bdb2308d0ba391511","scripts":{"test":"node --test 'test/*.test.js'","build":"node --check src/index.js && node --check src/core.js && node --check src/casing.js && node --check src/errors.js && node --check src/resources.js && node --check src/webhooks.js","pack:dry":"npm pack --dry-run","typecheck":"tsc -p tsconfig.json"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:1697a402-345f-4a0a-b9b1-7edd569b98dc"}},"repository":{"url":"git+https://github.com/Boomin-Ai/sdk.git","type":"git","directory":"packages/sdk"},"_npmVersion":"11.16.0","description":"Boomin platform SDK — programmable distribution infrastructure (programs, partnerships, enrollments, distributions, deployments, performance, payouts).","directories":{},"_nodeVersion":"24.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.5.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk_1.0.0-beta.2_1785742320855_0.32672056548270834","host":"s3://npm-registry-packages-npm-production"}},"1.0.0-beta.3":{"name":"@boomin/sdk","version":"1.0.0-beta.3","keywords":["boomin","distribution","partnerships","affiliate","referral","payouts","api","sdk"],"author":{"name":"Boomin"},"license":"MIT","_id":"@boomin/sdk@1.0.0-beta.3","maintainers":[{"name":"ikleveland","email":"kleveland.bishop@gmail.com"}],"homepage":"https://github.com/Boomin-Ai/sdk#readme","bugs":{"url":"https://github.com/Boomin-Ai/sdk/issues"},"dist":{"shasum":"82df65f9e4ab5eb48a15a4da340eb90115d4ce9b","tarball":"https://registry.npmjs.org/@boomin/sdk/-/sdk-1.0.0-beta.3.tgz","fileCount":12,"integrity":"sha512-jZjt2Kc6bx8UQo5AgMQ9D9J/4tYLe8XH3oKCuXfZqYMi8BXuXK7gkHHPIqKcIfRNuTHjgUuv5ZAbpYzoIDq9yw==","signatures":[{"sig":"MEUCIEOJ71XpbDFDRprXgqX6RfAaXggREfQZocKEWGEfbRjQAiEA8iPvUsU0P9678nJ4L/cEMWLmkvuGzVisbXoGxoV7m7U=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@boomin%2fsdk@1.0.0-beta.3","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":144590},"main":"./src/index.js","type":"module","types":"./src/index.d.ts","engines":{"node":">=18"},"exports":{".":{"types":"./src/index.d.ts","import":"./src/index.js","default":"./src/index.js"},"./errors":{"types":"./src/errors.d.ts","import":"./src/errors.js","default":"./src/errors.js"},"./webhooks":{"types":"./src/webhooks.d.ts","import":"./src/webhooks.js","default":"./src/webhooks.js"}},"gitHead":"134719bf4885c52fe9c4fe8cbfcce2b891989ae8","scripts":{"test":"node --test 'test/*.test.js'","build":"node --check src/index.js && node --check src/core.js && node --check src/casing.js && node --check src/errors.js && node --check src/resources.js && node --check src/webhooks.js","pack:dry":"npm pack --dry-run","typecheck":"tsc -p tsconfig.json"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:1697a402-345f-4a0a-b9b1-7edd569b98dc"}},"repository":{"url":"git+https://github.com/Boomin-Ai/sdk.git","type":"git","directory":"packages/sdk"},"_npmVersion":"11.16.0","description":"Boomin platform SDK — programmable distribution infrastructure (programs, partnerships, enrollments, distributions, deployments, performance, payouts).","directories":{},"_nodeVersion":"24.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.5.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk_1.0.0-beta.3_1786279104045_0.49694147987011417","host":"s3://npm-registry-packages-npm-production"}},"1.0.0-beta.4":{"name":"@boomin/sdk","version":"1.0.0-beta.4","keywords":["boomin","distribution","partnerships","affiliate","referral","payouts","api","sdk"],"author":{"name":"Boomin"},"license":"MIT","_id":"@boomin/sdk@1.0.0-beta.4","maintainers":[{"name":"ikleveland","email":"kleveland.bishop@gmail.com"}],"homepage":"https://github.com/Boomin-Ai/sdk#readme","bugs":{"url":"https://github.com/Boomin-Ai/sdk/issues"},"dist":{"shasum":"6430bc49ffaaac732a8a11445501c5b1aabc2e4e","tarball":"https://registry.npmjs.org/@boomin/sdk/-/sdk-1.0.0-beta.4.tgz","fileCount":12,"integrity":"sha512-sLvm8Yil+SIVEfo1iTdzCX21CWTyjrY6ZOPE3kob+hC2o2W1DwZtVmsFP8hp/Eg3mdJP/eKjcmCehVbwH0YqbQ==","signatures":[{"sig":"MEQCID0ZWd9Nhzvg5Hz78PK1YfGtrW2tU2wEBB0FJ44tI63pAiBqnm+JLAhmdgwVPUHoKHXw4VnGYnxJH0SB+8q1MfoG+A==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@boomin%2fsdk@1.0.0-beta.4","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":144992},"main":"./src/index.js","type":"module","types":"./src/index.d.ts","engines":{"node":">=18"},"exports":{".":{"types":"./src/index.d.ts","import":"./src/index.js","default":"./src/index.js"},"./errors":{"types":"./src/errors.d.ts","import":"./src/errors.js","default":"./src/errors.js"},"./webhooks":{"types":"./src/webhooks.d.ts","import":"./src/webhooks.js","default":"./src/webhooks.js"}},"gitHead":"fd29f8473714c21f989e9182973c4067efd2ad5e","scripts":{"test":"node --test 'test/*.test.js'","build":"node --check src/index.js && node --check src/core.js && node --check src/casing.js && node --check src/errors.js && node --check src/resources.js && node --check src/webhooks.js","pack:dry":"npm pack --dry-run","typecheck":"tsc -p tsconfig.json"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:1697a402-345f-4a0a-b9b1-7edd569b98dc"}},"repository":{"url":"git+https://github.com/Boomin-Ai/sdk.git","type":"git","directory":"packages/sdk"},"_npmVersion":"11.16.0","description":"Boomin platform SDK — programmable distribution infrastructure (programs, partnerships, enrollments, distributions, deployments, performance, payouts).","directories":{},"_nodeVersion":"24.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.5.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk_1.0.0-beta.4_1786565896958_0.15249555548114002","host":"s3://npm-registry-packages-npm-production"}},"1.0.0-beta.5":{"name":"@boomin/sdk","version":"1.0.0-beta.5","keywords":["boomin","distribution","partnerships","affiliate","referral","payouts","api","sdk"],"author":{"name":"Boomin"},"license":"MIT","_id":"@boomin/sdk@1.0.0-beta.5","maintainers":[{"name":"ikleveland","email":"kleveland.bishop@gmail.com"}],"homepage":"https://github.com/Boomin-Ai/sdk#readme","bugs":{"url":"https://github.com/Boomin-Ai/sdk/issues"},"dist":{"shasum":"fb676d305894d3885687f337da2d042032be81d7","tarball":"https://registry.npmjs.org/@boomin/sdk/-/sdk-1.0.0-beta.5.tgz","fileCount":12,"integrity":"sha512-as92HSTqY7+1I3AscPkwpYt5baLlg8MIRos2BryeBI2036a6hAc8mPe1WKieConsyCUuC92wYfCG5tKe2X57Sw==","signatures":[{"sig":"MEYCIQDGWpmMo1DMA3R+yIocLU7tEZq8sjoNUDTVlG7OxBBM2QIhALSmcA4dmbjqzNIFwXaYED0ZLnRdgbFwkLHMiAA9V92e","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@boomin%2fsdk@1.0.0-beta.5","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":164134},"main":"./src/index.js","type":"module","types":"./src/index.d.ts","engines":{"node":">=18"},"exports":{".":{"types":"./src/index.d.ts","import":"./src/index.js","default":"./src/index.js"},"./errors":{"types":"./src/errors.d.ts","import":"./src/errors.js","default":"./src/errors.js"},"./webhooks":{"types":"./src/webhooks.d.ts","import":"./src/webhooks.js","default":"./src/webhooks.js"}},"gitHead":"136e7f17e001fd516cfa85dbe2fa916b54e34a91","scripts":{"test":"node --test 'test/*.test.js'","build":"node --check src/index.js && node --check src/core.js && node --check src/casing.js && node --check src/errors.js && node --check src/resources.js && node --check src/webhooks.js","pack:dry":"npm pack --dry-run","typecheck":"tsc -p tsconfig.json"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:1697a402-345f-4a0a-b9b1-7edd569b98dc"}},"repository":{"url":"git+https://github.com/Boomin-Ai/sdk.git","type":"git","directory":"packages/sdk"},"_npmVersion":"11.17.0","description":"Boomin platform SDK — programmable distribution infrastructure (programs, partnerships, enrollments, distributions, deployments, performance, payouts).","directories":{},"_nodeVersion":"24.19.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.5.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk_1.0.0-beta.5_1786886810353_0.07315571945907884","host":"s3://npm-registry-packages-npm-production"}},"1.0.0-beta.6":{"name":"@boomin/sdk","version":"1.0.0-beta.6","keywords":["boomin","distribution","relationships","affiliate","referral","payouts","api","sdk"],"author":{"name":"Boomin"},"license":"MIT","_id":"@boomin/sdk@1.0.0-beta.6","maintainers":[{"name":"ikleveland","email":"kleveland.bishop@gmail.com"}],"homepage":"https://github.com/Boomin-Ai/sdk#readme","bugs":{"url":"https://github.com/Boomin-Ai/sdk/issues"},"dist":{"shasum":"4eef9b22c12d1be209da5d88ae9ebaca83a74f0a","tarball":"https://registry.npmjs.org/@boomin/sdk/-/sdk-1.0.0-beta.6.tgz","fileCount":12,"integrity":"sha512-LZJNTmD/hr5OsCV1R4tUeSiZoaEZKOXQHpeyr+BCdZ0uSfyWce2HtgBKbyonnCMWn+EuFe9aCbbRFxfqME4seQ==","signatures":[{"sig":"MEQCIAlTLsrfOXeIIF3U4d5Tk16tzb7tNNMY+d0+Lm6DSXuuAiAGBBucbyY/kPeaPK8wvth3VUk9JcMFzb0ZeUeiYAcKeA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@boomin%2fsdk@1.0.0-beta.6","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":163826},"main":"./src/index.js","type":"module","types":"./src/index.d.ts","engines":{"node":">=18"},"exports":{".":{"types":"./src/index.d.ts","import":"./src/index.js","default":"./src/index.js"},"./errors":{"types":"./src/errors.d.ts","import":"./src/errors.js","default":"./src/errors.js"},"./webhooks":{"types":"./src/webhooks.d.ts","import":"./src/webhooks.js","default":"./src/webhooks.js"}},"gitHead":"c61d91fea908051548d6d2e2f2ce2dfdeae6e4dd","scripts":{"test":"node --test 'test/*.test.js'","build":"node --check src/index.js && node --check src/core.js && node --check src/casing.js && node --check src/errors.js && node --check src/resources.js && node --check src/webhooks.js","pack:dry":"npm pack --dry-run","typecheck":"tsc -p tsconfig.json"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:1697a402-345f-4a0a-b9b1-7edd569b98dc"}},"repository":{"url":"git+https://github.com/Boomin-Ai/sdk.git","type":"git","directory":"packages/sdk"},"_npmVersion":"11.17.0","description":"Boomin platform SDK — programmable distribution infrastructure (programs, relationships, enrollments, distributions, deployments, performance, payouts).","directories":{},"_nodeVersion":"24.19.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.5.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk_1.0.0-beta.6_1788181973126_0.8561968483657254","host":"s3://npm-registry-packages-npm-production"}},"1.0.0-beta.7":{"name":"@boomin/sdk","version":"1.0.0-beta.7","description":"Boomin platform SDK — programmable distribution infrastructure (programs, relationships, enrollments, distributions, deployments, performance, payouts).","type":"module","repository":{"type":"git","url":"git+https://github.com/Boomin-Ai/sdk.git","directory":"packages/sdk"},"main":"./src/index.js","types":"./src/index.d.ts","exports":{".":{"types":"./src/index.d.ts","import":"./src/index.js","default":"./src/index.js"},"./webhooks":{"types":"./src/webhooks.d.ts","import":"./src/webhooks.js","default":"./src/webhooks.js"},"./errors":{"types":"./src/errors.d.ts","import":"./src/errors.js","default":"./src/errors.js"}},"engines":{"node":">=18"},"publishConfig":{"access":"public"},"scripts":{"build":"node --check src/index.js && node --check src/core.js && node --check src/casing.js && node --check src/errors.js && node --check src/resources.js && node --check src/webhooks.js","typecheck":"tsc -p tsconfig.json","test":"node --test 'test/*.test.js'","pack:dry":"npm pack --dry-run"},"devDependencies":{"typescript":"^5.5.0"},"keywords":["boomin","distribution","relationships","affiliate","referral","payouts","api","sdk"],"author":{"name":"Boomin"},"license":"MIT","gitHead":"ebe3ee22d257d04e2b33a845bf5b6e3e15a53bab","_id":"@boomin/sdk@1.0.0-beta.7","bugs":{"url":"https://github.com/Boomin-Ai/sdk/issues"},"homepage":"https://github.com/Boomin-Ai/sdk#readme","_nodeVersion":"22.16.0","_npmVersion":"11.19.0","dist":{"integrity":"sha512-uPPxs3EIa8vn3X8FTYRbkCKXoeIbuKZ8g6xfZBnbZJHtqa1SNUf9oqezidgtjSqSP36BMFABBKur/Y1f24VfoA==","shasum":"6b919e564b6dd46d01a3c646e384d3afc8163379","tarball":"https://registry.npmjs.org/@boomin/sdk/-/sdk-1.0.0-beta.7.tgz","fileCount":12,"unpackedSize":165068,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIFaiLyLbwi3qoWMMnxub0MIsVRhd5cgRmPbkB4nurEvOAiBghinOnNOw7Ol0Atf4Ks2WtQf9D1X2AuS8yB/Cbwl48g=="}]},"_npmUser":{"name":"ikleveland","email":"kleveland.bishop@gmail.com"},"directories":{},"maintainers":[{"name":"ikleveland","email":"kleveland.bishop@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/sdk_1.0.0-beta.7_1788473590166_0.5464807275038042"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-03T05:15:35.821Z","modified":"2026-09-03T22:13:10.543Z","1.0.0-beta.1":"2026-08-03T05:15:36.182Z","1.0.0-beta.2":"2026-08-03T07:32:00.973Z","1.0.0-beta.3":"2026-08-09T12:38:24.178Z","1.0.0-beta.4":"2026-08-12T20:18:17.098Z","1.0.0-beta.5":"2026-08-16T13:26:50.493Z","1.0.0-beta.6":"2026-08-31T13:12:53.252Z","1.0.0-beta.7":"2026-09-03T22:13:10.328Z"},"bugs":{"url":"https://github.com/Boomin-Ai/sdk/issues"},"author":{"name":"Boomin"},"license":"MIT","homepage":"https://github.com/Boomin-Ai/sdk#readme","keywords":["boomin","distribution","relationships","affiliate","referral","payouts","api","sdk"],"repository":{"type":"git","url":"git+https://github.com/Boomin-Ai/sdk.git","directory":"packages/sdk"},"description":"Boomin platform SDK — programmable distribution infrastructure (programs, relationships, enrollments, distributions, deployments, performance, payouts).","maintainers":[{"name":"ikleveland","email":"kleveland.bishop@gmail.com"}],"readme":"# @boomin/sdk\n\nThe Boomin platform SDK — programmable distribution infrastructure. A\n**Distribution** is a coordinated business objective (Boomin's PaymentIntent)\nthat fans out into concrete **Deployments** — one per execution channel: a\npartner program (whose enrolled entities each carry their own link on it), an\nowned channel, or paid media.\n\nBuilt on `fetch` + WebCrypto only: works on Node >= 18, Cloudflare Workers,\nBun, Deno, browsers, and edge runtimes. Zero dependencies, zero Node builtins.\n\n```sh\nnpm install @boomin/sdk\n```\n\n## Quickstart\n\n```js\nimport Boomin from \"@boomin/sdk\";\n\nconst boomin = new Boomin(process.env.BOOMIN_SECRET_KEY);\n\n// 1. Invite a entity into a program (enrollment payload carries the program)\nconst enrollment = await boomin.enrollments.create({\n  program: \"prog_123\",\n  email: \"creator@example.com\",\n});\nawait boomin.enrollments.approve(enrollment.id);\n\n// 2. Draft a distribution against that program (`name` is required)\nconst distribution = await boomin.distributions.create({\n  name: \"Spring launch\",\n  objective: \"acquisition\",\n  programs: [\"prog_123\"],\n  spec: { enrollment_policy: \"all_approved\" },\n});\n\n// 3. Validate, then launch — launch is ALWAYS async (202 + operation).\n//    `operation` here is an id STRING, not an object.\nawait boomin.distributions.validate(distribution.id);\nconst { operation } = await boomin.distributions.launch(distribution.id);\nconst settled = await boomin.operations.wait(operation, { timeout: 120000 });\nconsole.log(settled.status); // \"succeeded\" | \"partial\" | \"failed\" | \"canceled\"\n```\n\n`operations.wait()` accepts either form — the id string that `launch` returns,\nor the operation object that `pause`/`resume`/`cancel` return alongside their\nresource.\n\n### Field naming\n\n**The SDK is camelCase in both directions.** You write camelCase params, and\nyou read camelCase properties back. The REST wire is snake_case; translating is\nthe SDK's job, not yours.\n\n```js\nconst event = await boomin.performance.events.create(\n  { deployment: \"dep_123\", type: \"sale\", valueMinor: 4999 }, // → value_minor\n  { idempotencyKey: \"evt_123\" },                             // → Idempotency-Key header\n);\n\nevent.valueMinor; // 4999      ← wire field value_minor\nevent.receivedAt; //           ← wire field received_at\n```\n\nRequests convert by **declared schema**, not by guesswork. The nested structures\nthe API owns — `subjects[]` and `budget` on `distributions.create/update` —\nconvert too:\n\n```js\nawait boomin.distributions.create({\n  name: \"Spring launch\",\n  subjects: [{ kind: \"event\", id: \"…\", role: \"primary\" }],\n  budget: { mode: \"funded\", asset: \"credit\", totalMinor: 10000 }, // → total_minor\n});\n```\n\n**Your payloads are never renamed, in either direction.** These fields are\nopaque: their keys round-trip byte-identical, at any depth.\n\n`metadata` · `properties` · `spec` · `permissions` · `rights` ·\n`compensationDefaults` · `desiredState` · `observedState` · `externalIds` ·\n`stats`\n\n```js\nawait boomin.performance.events.create({\n  deployment: \"dep_123\", type: \"sale\",\n  properties: { orderId: \"1001\", customerTier: \"gold\" }, // stored exactly so\n});\n```\n\nSnake_case params are still accepted — but **only one spelling per field**.\nSending both throws before the request is issued:\n\n```js\nboomin.webhooks.endpoints.create({\n  url: \"https://example.com/hook\",\n  enabledEvents: [\"payout.settled\"],\n  enabled_events: [\"distribution.live\"],\n});\n// ConflictingParametersError (code: conflicting_parameters)\n//   \"enabledEvents\" and \"enabled_events\" refer to the same API field.\n```\n\nThe v1 API also rejects fields it does not recognize (`400 invalid_request`,\nnaming the field and, where it can tell, the field you meant) rather than\ndropping them — so a typo is never a silent no-op.\n\nNeed the wire objects verbatim (proxying, logging)? Construct the client with\n`rawResponses: true` and every response comes back in its snake_case form.\nRequest conversion is unaffected.\n\n### Client options\n\n```js\nconst boomin = new Boomin(\"sk_live_...\", {\n  baseUrl: \"https://api.boomin.ai\", // API origin (paths live under /v1/platform)\n  brand: \"acme\",                    // brand id or slug; threads Boomin-Brand\n  maxRetries: 2,                    // retries on 429/5xx (idempotent requests only)\n  timeout: 30000,                   // per-request timeout, ms\n  rawResponses: false,              // true → snake_case wire objects, unconverted\n});\n```\n\nEvery method accepts trailing per-call options:\n\n```js\nawait boomin.distributions.launch(id, {}, {\n  idempotencyKey: \"launch-2026-08-01\", // otherwise auto-generated per mutation\n  brand: \"acme-eu\",                    // per-call Boomin-Brand override\n  timeout: 10000,\n  maxRetries: 0,\n});\n```\n\n### Idempotency is header-canonical\n\nEvery mutation carries an `Idempotency-Key` header — auto-generated per call,\nor yours via the per-call option above. **There is no body idempotency field.**\nWriting `idempotencyKey` into a *params* object makes it an unknown body field,\nand the API answers `400 invalid_request`:\n\n```js\n// ✗ 400 — idempotency_key is not a body field\nawait boomin.distributions.create({ name: \"Spring launch\", idempotencyKey: \"k\" });\n\n// ✓ header\nawait boomin.distributions.create({ name: \"Spring launch\" }, { idempotencyKey: \"k\" });\n```\n\nThe same option supplies `performance.events.create` its ingest identity, so\none concept covers HTTP replay and measurement de-duplication.\n\nNothing mutates as a side effect of inspection: `distributions.validate(id)` is\nthe non-mutating way to check a distribution before you launch it.\n\n### Pagination\n\nList calls resolve one page (`{ object: \"list\", data, hasMore }` — the wire's\n`has_more`, camelCased like everything else) and are also async-iterable across\nevery page:\n\n```js\nconst page = await boomin.relationships.list({ limit: 20 });\npage.hasMore; // boolean\n\nfor await (const enrollment of boomin.enrollments.list({ program: \"prog_123\" })) {\n  // auto-pagination via starting_after\n  enrollment.approvalStatus; // ← wire field approval_status\n}\n```\n\n### Errors\n\n```js\nimport { OperationConflictError, FundingRequiredError } from \"@boomin/sdk/errors\";\n\ntry {\n  await boomin.distributions.launch(id);\n} catch (err) {\n  if (err instanceof OperationConflictError) {\n    // a live operation already holds this subject (code: operation_conflict)\n  } else if (err instanceof FundingRequiredError) {\n    // fund the brand wallet, the launch operation waits (code: funding_required)\n  } else if (err.code === \"band_limit_reached\") {\n    // upgrade the entity band\n  }\n}\n```\n\nAll errors extend `BoominError` (`code`, `status`, `requestId`). Subclasses:\n`AuthenticationError`, `PermissionError`, `InvalidRequestError`,\n`RateLimitError`, `ConflictError`, `APIError`, plus distinctly typed\n`OperationConflictError`, `BandLimitReachedError`, `FundingRequiredError`,\n`ConflictingParametersError`, and `WebhookSignatureVerificationError`.\n\nPayout configuration adds five, for the conditions a script actually branches\non: `PayoutRulesRequiredError` (nothing configured — *not* nothing owed),\n`PayoutRailRequiredError` (no active rail; nothing is auto-provisioned),\n`PayoutRailAlreadyExistsError` (create is not upsert — call `update`),\n`ImmutableParameterError` (rule economics are frozen; `param` names the\nconcept), `PayoutBatchEmptyError` and `PayoutBatchStateError` (the batch's\nstatus forbids this transition — read it and look at `status`). Everything else\nin the payout registry — `payout_rule_not_found`, `payout_rail_not_found`,\n`payout_export_format_invalid`, `payout_export_unconfigured` — arrives on its\nstatus-derived class and is matched by `code`.\n\n`ConflictingParametersError` is the one raised **client-side, before anything is\nsent** — `status` is `null`, `param` names the camelCase spelling and\n`conflictsWith` its snake_case twin. It extends `InvalidRequestError`, so an\nexisting 400-family catch keeps working.\n\n### Payouts\n\nMoney-out is one primitive with three parts, and the client nests exactly like\nthe REST tree: `payouts.rules` (how a entity **earns**), `payouts.rails` (how\nmoney physically **leaves**), `payouts.batches` (one frozen disbursement run).\nThere is no root `payoutRules` / `payoutRails` client.\n\n```js\n// 1. A rail — how money leaves. Create is CREATE, not upsert: a second create\n//    for a configured rail throws PayoutRailAlreadyExistsError rather than\n//    silently rewriting where your money lands.\nconst rail = await boomin.payouts.rails.create({\n  rail: \"csv_batch\",\n  isDefault: true,\n  config: {\n    format: \"paypal_payouts_csv\", // required on csv_batch — PayPal's and Wise's\n                                  // column sets differ, so there is no default\n    walletFunded: false,\n    columns: [                    // YOUR data — see below\n      { key: \"email\",  header: \"Email Address\" },\n      { key: \"amount\", header: \"Amount\" },\n    ],\n  },\n});\n\n// 2. A rule — how a entity earns. Money is *Minor, never cents.\nconst rule = await boomin.payouts.rules.create({\n  name: \"Registration CPA\",\n  type: \"cpa\",                                       // revenue_split | cpa | threshold_bonus\n  scope: { type: \"program\", program: \"prog_123\" },   // discriminated, never applies_to/scope_id\n  metricKey: \"event_registration\",\n  perUnitMinor: 500,                                 // ← wire field per_unit_minor\n});\n\n// 3. Run the period, then export.\nconst run = await boomin.payouts.run({ periodStart: \"2026-08-01\", periodEnd: \"2026-09-01\" });\nrun.outcome;        // \"payouts_created\" | \"no_eligible_activity\"  ← branch on THIS\nrun.payoutsCreated; // …not on a count\nrun.summary.totalAmountMinor;\n\nconst accepted = await boomin.payouts.exportCsv({ periodStart: \"2026-08-01\" });\nawait boomin.operations.wait(accepted.operation);\nconst batch = await boomin.payouts.batches.retrieve(accepted.batch);\nbatch.downloadUrl;  // presigned, RE-MINTED on every read\n\n// 4. Tell Boomin what the provider actually did.\nawait boomin.payouts.batches.confirm(batch.id, {\n  externalBatchRef: \"PAYPAL-2026-08\",  // same ref replays one operation — a retry\n  results: [{ item: \"pbi_1\", status: \"paid\" }],  // after a timeout can't pay twice\n});\n```\n\n**`config.columns` is your data, and it round-trips byte-identical.** The SDK\nconverts camelCase to the snake_case wire everywhere else, but every key,\nheader string and array position inside `columns` is sent and returned exactly\nas you wrote it. That is not politeness: those headers are the file your bank\ningests, and a \"helpfully\" re-cased header is a different file. `config.format`\nand `config.walletFunded` are the API's own fields and convert normally.\n\nThree shapes worth knowing before you script against them:\n\n- **`run` distinguishes \"misconfigured\" from \"nothing owed\".** A brand with no\n  active rule and no active content split throws `PayoutRulesRequiredError`\n  (409). A brand that is configured but had no qualifying activity **succeeds**\n  with `outcome: \"no_eligible_activity\"`. Treating those alike pays nobody and\n  reports success.\n- **`exportCsv` and `batches.export` are 202s** resolving\n  `{ batch, status, operation }` as id **strings**. No `downloadUrl` — it lives\n  on `batches.retrieve()`, re-minted per read instead of expiring in a body.\n- **A rule's economics are immutable.** `rules.update` takes `name` and\n  `status` only; anything else throws `ImmutableParameterError` naming the\n  frozen concept. To change money: create a replacement rule, activate it, then\n  `rules.archive(old)`. Archive is the only removal verb — a hard delete would\n  cascade the ledger rows the rule produced, erasing the record of money that\n  was actually paid.\n\n### Webhooks\n\nVerify `Boomin-Signature: t=<ts>,v1=<hmac>` (HMAC-SHA256, WebCrypto — note\n`constructEvent` is async). Pass the RAW request body, never a re-parse.\n\n```js\nimport { constructEvent } from \"@boomin/sdk/webhooks\"; // or Boomin.webhooks.constructEvent\n\nexport default {\n  async fetch(request, env) {\n    const payload = await request.text();\n    const event = await constructEvent(\n      payload,\n      request.headers.get(\"Boomin-Signature\"),\n      env.BOOMIN_WEBHOOK_SECRET, // or [oldSecret, newSecret] during rotation\n      { tolerance: 300 },\n    );\n    // Verified events are camelCased like every other SDK value.\n    if (event.type === \"distribution.live\") {\n      event.data.object.planHash; // ← wire field plan_hash\n    }\n    return new Response(\"ok\");\n  },\n};\n```\n\nEndpoint management lives on the instance. The signing secret is revealed once,\non create (and again on `rotateSecret`) — store it then, or you will have to\nrotate to see another:\n\n```js\nconst endpoint = await boomin.webhooks.endpoints.create({\n  url: \"https://example.com/webhooks/boomin\",\n  enabledEvents: [\"distribution.live\", \"payout.settled\"],\n});\nconsole.log(endpoint.id, endpoint.secret); // whsec_… — shown ONLY here\nconsole.log(endpoint.enabledEvents);       // ← wire field enabled_events\n```\n\n`enabledEvents: []` (or omitting it) subscribes the endpoint to **every** public\nevent type. Then `.list()`, `.retrieve()`, `.update()`, `.rotateSecret()`, `.del()`.\n\n## Resource clients\n\n| Client | Methods |\n| --- | --- |\n| `programs` | `create` `retrieve` `update` `list` `standingPreview` + nested `requirements` / `tiers` (CRUD) / `connectConfig` / `handoffConfig` (retrieve, update) |\n| `entities` | `retrieve` `list` (canonical; `entities` delegates here) |\n| `relationships` | `list` `retrieve` `pause` `resume` `end` `updatePermissions` (canonical; `relationships` delegates here) |\n| `assertions` | `create` (assert) `revoke` (claim-addressed) `list` `retrieveEvent` |\n| `operatingTypes` | `create` `retrieve` `update` `list` `archive` (keys never recycled) |\n| `metricKeys` | `create` `retrieve` `update` `list` (built-ins flagged) `archive` |\n| `enrollments` | `create` (invite) `approve` `reject` `pause` `resume` `update` (set `operatingType`) `list` `retrieve` + nested `requirementOverrides` (create/retrieve/update/list/del) |\n| `distributions` | `create` `update` `retrieve` `list` `validate` `launch` `pause` `resume` `cancel` |\n| `deployments` | `retrieve` `list` `pause` `resume` `cancel` |\n| `connections` | `list` `retrieve` `revoke` |\n| `performance` | `summary` + `events.create` (measurement ingestion IN) |\n| `events` | `list({ type?, startingAfter? })` (operational feed OUT) |\n| `operations` | `retrieve` `list` `wait(operationOrId, { timeout })` |\n| `webhooks` | `endpoints.create/retrieve/update/list/del` + static `Boomin.webhooks.constructEvent` |\n| `payouts` | `list` `run` `exportCsv` `connectStatus` + nested `rules.create/retrieve/list/update/archive`, `rails.create/retrieve/list/update`, `batches.create/retrieve/list/export/confirm/cancel` |\n\n`resume` is the canonical verb on every surface — never `unpause`.\n\n## MIGRATING to 1.0.0-beta.5 (relationship naming)\n\nRELATIONSHIP_CORE renamed the pair-level nouns: an **entity** is who you have\nrelationships with, a **relationship** is the durable bond. Nothing breaks:\n\n- `boomin.entities` / `boomin.relationships` still work — they are deprecated\n  getters that **delegate** to `boomin.entities` / `boomin.relationships`, and\n  they will never be removed. New code should use the canonical names.\n- Requests now ride the canonical routes (`/entities`, `/relationships`).\n  Legacy ids (`ptnr_…`, `pship_…`) no longer decode (2026-08-31 hard break); responses\n  carry `ent_…` / `rel_…` ids and `object: \"entity\" | \"relationship\"`.\n- Types: `Entity` / `Relationship` are canonical; `Entity` / `Relationship`\n  remain as deprecated aliases. Webhook payloads stored before the flip keep\n  deserializing (`relationship` stays in the response field map).\n- New in beta.5: `boomin.assertions` (tenant truth, claim-addressed),\n  `boomin.operatingTypes` (capacity vocabulary), `boomin.metricKeys` (tenant\n  `x:` metrics; payout stays built-ins-only in v1),\n  `boomin.enrollments.requirementOverrides`, `enrollments.update`\n  (set/clear `operatingType`), and `programs.standingPreview` (read-only\n  what-ifs — the engine behind `boomin standing test`).\n\n## Contributing\n\n`src/casing.js` is the single boundary between camelCase and the snake_case\nwire. When the API grows a new **nested** request structure, declare it in\n`REQUEST_FIELD_MAP` there; when it grows a new customer-owned free-form blob,\ndeclare it in `RESPONSE_FIELD_MAP` (which computes `OPAQUE_FIELDS`). Nothing\nelse in the package makes a casing decision.\n\nA field can be both, and `payout_rail.config` is the worked example: the object\nis API-owned (so `walletFunded` must convert) while `columns` inside it is the\ncustomer's (so it must not). Declaring only one half is a bug in either\ndirection — one 400s a valid call, the other silently rewrites a bank file.\n\n## License\n\nMIT\n","readmeFilename":"README.md"}