{"_id":"@aipricinglab/sdk","_rev":"13-5c45786690cbaefd41abde8146ab05a6","name":"@aipricinglab/sdk","dist-tags":{"latest":"1.1.0"},"versions":{"0.1.0":{"name":"@aipricinglab/sdk","version":"0.1.0","keywords":["ai","metering","usage","limits","billing","rate-limiting","llm","tokens","openai","anthropic","stripe","saas"],"author":{"name":"AiPricingLab"},"license":"MIT","_id":"@aipricinglab/sdk@0.1.0","maintainers":[{"name":"s.caste","email":"s.castellitti.dev@gmail.com"}],"homepage":"https://aipricinglab.space","bugs":{"url":"https://aipricinglab.space/support"},"dist":{"shasum":"c10a025bd90620a4c70a4af2e769e99246f3c6f6","tarball":"https://registry.npmjs.org/@aipricinglab/sdk/-/sdk-0.1.0.tgz","fileCount":8,"integrity":"sha512-g3+b7f2y8n12h4XX1g3yr/JJUuIwlLCQjS3+NlyHL0QWB0aD43pGbpFBxnJ93xMDGSnITeB72BINl9ea3mc9lg==","signatures":[{"sig":"MEUCIQDDLj7xT9pKCzHCfscoDG1swN1Dd+NG1X5IJcl+/4/KtAIgCmQpdp3Zja0VG8O7rYau0kMWkzc354w8SqG1tz8bgKs=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":46081},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"8fa704c4f114354074f0be9a10f2598096d4e7c7","scripts":{"dev":"tsup --watch","build":"tsup","typecheck":"tsc --noEmit","prepublishOnly":"pnpm build"},"_npmUser":{"name":"s.caste","email":"s.castellitti.dev@gmail.com"},"_npmVersion":"10.9.2","description":"Usage metering and limits SDK for AI-powered apps. Track LLM tokens, image generations, video seconds, and any other AI consumption — provider-agnostic.","directories":{},"_nodeVersion":"23.10.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.0","typescript":"^5.8.3"},"_npmOperationalInternal":{"tmp":"tmp/sdk_0.1.0_1778242438188_0.9812135774869997","host":"s3://npm-registry-packages-npm-production"},"deprecated":"Package no longer supported. Contact Support at https://www.npmjs.com/support for more info."},"0.2.0":{"name":"@aipricinglab/sdk","version":"0.2.0","keywords":["ai","metering","usage","limits","billing","rate-limiting","llm","tokens","openai","anthropic","stripe","saas"],"author":{"name":"AiPricingLab"},"license":"MIT","_id":"@aipricinglab/sdk@0.2.0","maintainers":[{"name":"s.caste","email":"s.castellitti.dev@gmail.com"}],"homepage":"https://aipricinglab.space","bugs":{"url":"https://aipricinglab.space/support"},"dist":{"shasum":"ae39a8241c3f42f736725e6c49996176205d3765","tarball":"https://registry.npmjs.org/@aipricinglab/sdk/-/sdk-0.2.0.tgz","fileCount":8,"integrity":"sha512-p2wBKfWFeltQXOD1jWryzqXWoYqTNwurmz/kSpoNC0fSxR/7koDZGcHgqjQTE3cqf7hrmDgEris717fuNiXiWQ==","signatures":[{"sig":"MEYCIQDszLWKU8A9bqUu2uuqalx9/D7pDESHaPkPdTI/OdT0OAIhAII3TzVy61HjQo8ZKnQWPv29JiGpDsY+WjlH7R6GY5p7","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":54749},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"cb2265ffa442a6d22404265f4e203bf0446fb591","scripts":{"dev":"tsup --watch","build":"tsup","typecheck":"tsc --noEmit","prepublishOnly":"pnpm build"},"_npmUser":{"name":"s.caste","email":"s.castellitti.dev@gmail.com"},"_npmVersion":"10.9.2","description":"Usage metering and limits SDK for AI-powered apps. Track LLM tokens, image generations, video seconds, and any other AI consumption — provider-agnostic.","directories":{},"_nodeVersion":"23.10.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.0","typescript":"^5.8.3"},"_npmOperationalInternal":{"tmp":"tmp/sdk_0.2.0_1778279676918_0.569553357504978","host":"s3://npm-registry-packages-npm-production"},"deprecated":"Package no longer supported. Contact Support at https://www.npmjs.com/support for more info."},"0.3.0":{"name":"@aipricinglab/sdk","version":"0.3.0","keywords":["ai","metering","usage","limits","billing","rate-limiting","llm","tokens","openai","anthropic","stripe","saas"],"author":{"name":"AiPricingLab"},"license":"MIT","_id":"@aipricinglab/sdk@0.3.0","maintainers":[{"name":"s.caste","email":"s.castellitti.dev@gmail.com"}],"homepage":"https://aipricinglab.space","bugs":{"url":"https://aipricinglab.space/support"},"dist":{"shasum":"40ad4aba4a7aadbdd4f04ea7af36fa1bf888b8dc","tarball":"https://registry.npmjs.org/@aipricinglab/sdk/-/sdk-0.3.0.tgz","fileCount":8,"integrity":"sha512-zF8FqRxxAj9Qpa9j553v843k5Lzs4RYlrQKfDPoucDat8a1E/cl9oVCy3mSm0mfEMAJooCWEnpKYazbzarx+Sw==","signatures":[{"sig":"MEQCIAGkJV0gVVh2Hyvy9wk5chIxBJCa0+V71eDq/NGo6csRAiAnwsu2USYUGUPIuy6mFyLL18P7Tg/luJvCh3OTojuPzg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":54945},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"2ecc6b9605cc1e75ac4627d039a3a015b2fa7df0","scripts":{"dev":"tsup --watch","build":"tsup","typecheck":"tsc --noEmit","prepublishOnly":"pnpm build"},"_npmUser":{"name":"s.caste","email":"s.castellitti.dev@gmail.com"},"_npmVersion":"10.9.2","description":"Usage metering and limits SDK for AI-powered apps. Track LLM tokens, image generations, video seconds, and any other AI consumption — provider-agnostic.","directories":{},"_nodeVersion":"23.10.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.0","typescript":"^5.8.3"},"_npmOperationalInternal":{"tmp":"tmp/sdk_0.3.0_1778294115100_0.16536692301549571","host":"s3://npm-registry-packages-npm-production"},"deprecated":"Package no longer supported. Contact Support at https://www.npmjs.com/support for more info."},"0.3.1":{"name":"@aipricinglab/sdk","version":"0.3.1","keywords":["ai","metering","usage","limits","billing","rate-limiting","llm","tokens","openai","anthropic","stripe","saas"],"author":{"name":"AiPricingLab"},"license":"MIT","_id":"@aipricinglab/sdk@0.3.1","maintainers":[{"name":"s.caste","email":"s.castellitti.dev@gmail.com"}],"homepage":"https://aipricinglab.space","bugs":{"url":"https://aipricinglab.space/support"},"dist":{"shasum":"bd62ddb8166c003491afbd223bcf248d05feee86","tarball":"https://registry.npmjs.org/@aipricinglab/sdk/-/sdk-0.3.1.tgz","fileCount":8,"integrity":"sha512-U4FyvNVSpB5uV+D5tSWzKEDJFIarJT9raGUlcFn0hUwtH4lJayPp/ZwFNmsFRrzxlWFAcgcUgZTCm1JQFYlxUA==","signatures":[{"sig":"MEUCIQDv2EzVR475e3tK267M5b6Vp+aUguy+LtpwX8Sr81ED0AIga5k+zSjj4Vxstsvza4b3DmFQ5OgyrA51K/9TsKoQ/pY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":55777},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"493b4840da159a9ad96b38d3b31af909ba3f9b55","scripts":{"dev":"tsup --watch","build":"tsup","typecheck":"tsc --noEmit","prepublishOnly":"pnpm build"},"_npmUser":{"name":"s.caste","email":"s.castellitti.dev@gmail.com"},"_npmVersion":"10.9.2","description":"Usage metering and limits SDK for AI-powered apps. Track LLM tokens, image generations, video seconds, and any other AI consumption — provider-agnostic.","directories":{},"_nodeVersion":"23.10.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.0","typescript":"^5.8.3"},"_npmOperationalInternal":{"tmp":"tmp/sdk_0.3.1_1778419068780_0.882132886142599","host":"s3://npm-registry-packages-npm-production"},"deprecated":"Package no longer supported. Contact Support at https://www.npmjs.com/support for more info."},"0.3.2":{"name":"@aipricinglab/sdk","version":"0.3.2","keywords":["ai","metering","usage","limits","billing","rate-limiting","llm","tokens","openai","anthropic","stripe","saas"],"author":{"name":"AiPricingLab"},"license":"MIT","_id":"@aipricinglab/sdk@0.3.2","maintainers":[{"name":"s.caste","email":"s.castellitti.dev@gmail.com"}],"homepage":"https://aipricinglab.space","bugs":{"url":"https://aipricinglab.space/support"},"dist":{"shasum":"f4a06126599541137342a7afc35cfb12036e13f8","tarball":"https://registry.npmjs.org/@aipricinglab/sdk/-/sdk-0.3.2.tgz","fileCount":8,"integrity":"sha512-AlDAuks000QCBhg41+ZN9pcRD4jXwHjPvQiLeeO0Fw1bFagx4VoTPHuiUqxmzj85bzqetrN2o3RPGF9bPSyQyA==","signatures":[{"sig":"MEYCIQCrAkleFTfBNTVj4Vf2VUHwz8xB4RnZiuhyuNmgrsspFwIhAKcCOdfkPlYYIu3X0T4nTpfGDORzK0HUyiM6ZoIuxSBm","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":58986},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"fbd8d74e5be4a54c23ed380df2e81aac27e4c944","scripts":{"dev":"tsup --watch","build":"tsup","typecheck":"tsc --noEmit","prepublishOnly":"pnpm build"},"_npmUser":{"name":"s.caste","email":"s.castellitti.dev@gmail.com"},"_npmVersion":"10.9.2","description":"Usage metering and limits SDK for AI-powered apps. Track LLM tokens, image generations, video seconds, and any other AI consumption — provider-agnostic.","directories":{},"_nodeVersion":"23.10.0","dependencies":{"@vercel/analytics":"^2.0.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.0","typescript":"^5.8.3"},"_npmOperationalInternal":{"tmp":"tmp/sdk_0.3.2_1778457984781_0.6744841261370442","host":"s3://npm-registry-packages-npm-production"},"deprecated":"Package no longer supported. Contact Support at https://www.npmjs.com/support for more info."},"0.3.3":{"name":"@aipricinglab/sdk","version":"0.3.3","keywords":["ai","metering","usage","limits","billing","rate-limiting","llm","tokens","openai","anthropic","stripe","saas"],"author":{"name":"AiPricingLab"},"license":"MIT","_id":"@aipricinglab/sdk@0.3.3","maintainers":[{"name":"s.caste","email":"s.castellitti.dev@gmail.com"}],"homepage":"https://aipricinglab.space","bugs":{"url":"https://aipricinglab.space/support"},"dist":{"shasum":"40517f6806c5128c93277784b97b141886778ecb","tarball":"https://registry.npmjs.org/@aipricinglab/sdk/-/sdk-0.3.3.tgz","fileCount":8,"integrity":"sha512-cHXf03SmwhQrZ956krC+lZKObh4SDojHf21IBm+05hXHOJntlIRP9A5GubtakTyysuAr2yx+q0G3vuwlqm4crQ==","signatures":[{"sig":"MEYCIQDxNe6OMVo919tq7FND+1EU9p7fT9JS3vkdGd5hjVrgygIhALIi68xuEJDHDBvYdAgqLKiIphbOO3REwd7fqnd0Y1fu","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":71038},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"56d596eca8a3fd4fb9b06a62dfd822491e3910cf","scripts":{"dev":"tsup --watch","build":"tsup","typecheck":"tsc --noEmit","prepublishOnly":"pnpm build"},"_npmUser":{"name":"s.caste","email":"s.castellitti.dev@gmail.com"},"_npmVersion":"10.9.2","description":"Usage metering and limits SDK for AI-powered apps. Track LLM tokens, image generations, video seconds, and any other AI consumption — provider-agnostic.","directories":{},"_nodeVersion":"23.10.0","dependencies":{"@vercel/analytics":"^2.0.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.0","typescript":"^5.8.3"},"_npmOperationalInternal":{"tmp":"tmp/sdk_0.3.3_1778488526317_0.8527275532282506","host":"s3://npm-registry-packages-npm-production"},"deprecated":"Package no longer supported. Contact Support at https://www.npmjs.com/support for more info."},"0.4.0":{"name":"@aipricinglab/sdk","version":"0.4.0","keywords":["ai","metering","usage","limits","billing","rate-limiting","llm","tokens","openai","anthropic","stripe","saas"],"author":{"name":"AiPricingLab"},"license":"MIT","_id":"@aipricinglab/sdk@0.4.0","maintainers":[{"name":"s.caste","email":"s.castellitti.dev@gmail.com"}],"homepage":"https://aipricinglab.space","bugs":{"url":"https://aipricinglab.space/support"},"dist":{"shasum":"f415cd47d6f3a66831bec371a274d8a652253b47","tarball":"https://registry.npmjs.org/@aipricinglab/sdk/-/sdk-0.4.0.tgz","fileCount":8,"integrity":"sha512-1pQP2vgT2rOOT3B1yBcrg8MMEg4sAvzL274ct8b01ocIzmClG7BeQqyVxs2nu8bh5dsag712ONOOjBoEUkd59Q==","signatures":[{"sig":"MEYCIQC0Yi4GqoM3NXf7qTZebeDIXfnapf9YLbj2XOFQEz5HXAIhAILWqi+QGQuADsOZF+dN2e7i41AAXAQ/WB/tTtT5C9bF","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":75763},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"7249857edfde1a19e1aa093b6b749ef7990ea2a9","scripts":{"dev":"tsup --watch","build":"tsup","typecheck":"tsc --noEmit","prepublishOnly":"pnpm build"},"_npmUser":{"name":"s.caste","email":"s.castellitti.dev@gmail.com"},"_npmVersion":"10.9.2","description":"Usage metering and limits SDK for AI-powered apps. Track LLM tokens, image generations, video seconds, and any other AI consumption — provider-agnostic.","directories":{},"_nodeVersion":"23.10.0","dependencies":{"@vercel/analytics":"^2.0.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.0","typescript":"^5.8.3"},"_npmOperationalInternal":{"tmp":"tmp/sdk_0.4.0_1778536853086_0.429211866982119","host":"s3://npm-registry-packages-npm-production"},"deprecated":"Package no longer supported. Contact Support at https://www.npmjs.com/support for more info."},"0.5.1":{"name":"@aipricinglab/sdk","version":"0.5.1","keywords":["ai","metering","usage","limits","billing","rate-limiting","llm","tokens","openai","anthropic","stripe","saas"],"author":{"name":"AiPricingLab"},"license":"MIT","_id":"@aipricinglab/sdk@0.5.1","maintainers":[{"name":"s.caste","email":"s.castellitti.dev@gmail.com"}],"homepage":"https://aipricinglab.space","bugs":{"url":"https://aipricinglab.space/support"},"dist":{"shasum":"39b52f8f90f18c6bffc537bd68cd4fdcc2cedfa7","tarball":"https://registry.npmjs.org/@aipricinglab/sdk/-/sdk-0.5.1.tgz","fileCount":8,"integrity":"sha512-+44NvuMYxJFHDKM3yahLueZmqBmmuDZ1NGGVRLSzmGGgVN9pFO3hEYfCFuFSPQ8fXzZlgFyM501wYvZFU1LisQ==","signatures":[{"sig":"MEQCIE916no79GLNmaXdQfrTBehiKWntHcK9MK+GyS2OShddAiBjPbU5jKKiE9AHFBmNm+k0FugVPPWrUCJIhQNb/5NhYQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":80149},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"e5c33cdb75585419993e84e2f50dd47fdda1ef3e","scripts":{"dev":"tsup --watch","build":"tsup","typecheck":"tsc --noEmit","prepublishOnly":"pnpm build"},"_npmUser":{"name":"s.caste","email":"s.castellitti.dev@gmail.com"},"_npmVersion":"10.9.2","description":"Usage metering and limits SDK for AI-powered apps. Track LLM tokens, image generations, video seconds, and any other AI consumption — provider-agnostic.","directories":{},"_nodeVersion":"23.10.0","dependencies":{"@vercel/analytics":"^2.0.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.0","typescript":"^5.8.3"},"_npmOperationalInternal":{"tmp":"tmp/sdk_0.5.1_1778582159068_0.5269895443991073","host":"s3://npm-registry-packages-npm-production"},"deprecated":"Package no longer supported. Contact Support at https://www.npmjs.com/support for more info."},"0.7.0":{"name":"@aipricinglab/sdk","version":"0.7.0","keywords":["ai","metering","usage","limits","billing","rate-limiting","llm","tokens","openai","anthropic","stripe","saas"],"author":{"name":"AiPricingLab"},"license":"MIT","_id":"@aipricinglab/sdk@0.7.0","maintainers":[{"name":"s.caste","email":"s.castellitti.dev@gmail.com"}],"homepage":"https://aipricinglab.space","bugs":{"url":"https://aipricinglab.space/support"},"dist":{"shasum":"a9e27c73a505e34ae3fb5845666610aed125013f","tarball":"https://registry.npmjs.org/@aipricinglab/sdk/-/sdk-0.7.0.tgz","fileCount":8,"integrity":"sha512-9dDnJYJxAQ4La+Jk5CCka7NXtdiIY6QPFOQuym6+HzSjLLo+5rqJJnauBsVdHJNnxM0BRtSqm4lqoZpH+CCm5w==","signatures":[{"sig":"MEUCIFpIJHPW0bz6TA7++HkKGI/HLWkZnpiouSFcjYXNbMjCAiEAssTq5vBkdr4SbPZcD+ufziRnerT160zVQwCody+5xlY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":106725},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"9e083871cb5620568b0c36977d43759e4fb1b2d0","scripts":{"dev":"tsup --watch","build":"tsup","typecheck":"tsc --noEmit","prepublishOnly":"pnpm build"},"_npmUser":{"name":"s.caste","email":"s.castellitti.dev@gmail.com"},"_npmVersion":"10.9.2","description":"Usage metering and limits SDK for AI-powered apps. Track LLM tokens, image generations, video seconds, and any other AI consumption — provider-agnostic.","directories":{},"_nodeVersion":"23.10.0","dependencies":{"@vercel/analytics":"^2.0.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.0","typescript":"^5.8.3"},"_npmOperationalInternal":{"tmp":"tmp/sdk_0.7.0_1778718666045_0.6534874567693605","host":"s3://npm-registry-packages-npm-production"},"deprecated":"Package no longer supported. Contact Support at https://www.npmjs.com/support for more info."},"0.9.0":{"name":"@aipricinglab/sdk","version":"0.9.0","keywords":["ai","metering","usage","limits","billing","rate-limiting","llm","tokens","openai","anthropic","stripe","saas"],"author":{"name":"AiPricingLab"},"license":"MIT","_id":"@aipricinglab/sdk@0.9.0","maintainers":[{"name":"s.caste","email":"s.castellitti.dev@gmail.com"}],"homepage":"https://aipricinglab.space","bugs":{"url":"https://aipricinglab.space/support"},"dist":{"shasum":"1ea113189e0180f2c76976c083d576a776d8904e","tarball":"https://registry.npmjs.org/@aipricinglab/sdk/-/sdk-0.9.0.tgz","fileCount":8,"integrity":"sha512-1NF+DnuGBeLewWwuxVuEnK19Ck1Ryjh2e7wLMMAcXqA4oJ5lzJ8g3YVE1VPP2rd+VlHMUvKQ67736CadOGkiVw==","signatures":[{"sig":"MEUCIQDUA6ZxXLvoj76u3OxytXnw6eOsnUew7UhrfmNgr7BGBAIgdjEtVSmf+zMpMilNbPBfj4e7Lm5HiMG4bMJ/7m1+tYk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":132230},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"2216a22b14e47f72752564c4d19c9096fab7a200","scripts":{"dev":"tsup --watch","build":"tsup","typecheck":"tsc --noEmit","prepublishOnly":"pnpm build"},"_npmUser":{"name":"s.caste","email":"s.castellitti.dev@gmail.com"},"_npmVersion":"10.9.2","description":"Usage metering and limits SDK for AI-powered apps. Track LLM tokens, image generations, video seconds, and any other AI consumption — provider-agnostic.","directories":{},"_nodeVersion":"23.10.0","dependencies":{"@vercel/analytics":"^2.0.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.0","typescript":"^5.8.3"},"_npmOperationalInternal":{"tmp":"tmp/sdk_0.9.0_1778839541402_0.9746307320174785","host":"s3://npm-registry-packages-npm-production"},"deprecated":"Package no longer supported. Contact Support at https://www.npmjs.com/support for more info."},"1.0.0":{"name":"@aipricinglab/sdk","version":"1.0.0","keywords":["ai","metering","usage","limits","billing","rate-limiting","llm","tokens","openai","anthropic","stripe","saas"],"author":{"name":"AiPricingLab"},"license":"MIT","_id":"@aipricinglab/sdk@1.0.0","maintainers":[{"name":"s.caste","email":"s.castellitti.dev@gmail.com"}],"homepage":"https://aipricinglab.space","bugs":{"url":"https://aipricinglab.space/support"},"dist":{"shasum":"3da325e8f6b3e2f0c786c0fbebe427c054918589","tarball":"https://registry.npmjs.org/@aipricinglab/sdk/-/sdk-1.0.0.tgz","fileCount":9,"integrity":"sha512-a9aLgZWKhq+YnLCqasdpgoj3tg1iJVat3SbSk5yACJbwXH+vNhfqAoXhrYR8/lebP1gHAgEQpt9wXJkEeV3bqg==","signatures":[{"sig":"MEUCIQD0xmshJKaRxA76Z9kvLtObdB3TO7dH7bFQZ+tK88TgigIgBiD/3dDf+34grqGzBIUNtHowDuiXlu0ys8RNGvRPzsA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":305622},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"4b7aead65a22d23ee5fb4401c653ece7649d1009","scripts":{"dev":"tsup --watch","test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest","prepublishOnly":"pnpm build"},"_npmUser":{"name":"s.caste","email":"s.castellitti.dev@gmail.com"},"_npmVersion":"10.9.2","description":"Usage metering and limits SDK for AI-powered apps. Track LLM tokens, image generations, video seconds, and any other AI consumption - provider-agnostic.","directories":{},"_nodeVersion":"23.10.0","dependencies":{"@vercel/analytics":"^2.0.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.0","vitest":"^4.1.6","typescript":"^5.8.3"},"_npmOperationalInternal":{"tmp":"tmp/sdk_1.0.0_1779493536417_0.2660201503773294","host":"s3://npm-registry-packages-npm-production"},"deprecated":"Package no longer supported. Contact Support at https://www.npmjs.com/support for more info."},"1.1.0":{"name":"@aipricinglab/sdk","version":"1.1.0","keywords":["ai","metering","usage","limits","billing","rate-limiting","llm","tokens","openai","anthropic","stripe","saas"],"author":{"name":"AiPricingLab"},"license":"MIT","_id":"@aipricinglab/sdk@1.1.0","maintainers":[{"name":"s.caste","email":"s.castellitti.dev@gmail.com"}],"homepage":"https://aipricinglab.space","bugs":{"url":"https://aipricinglab.space/support"},"dist":{"shasum":"7ed386f253081d070359e1df0d02e11246b5454f","tarball":"https://registry.npmjs.org/@aipricinglab/sdk/-/sdk-1.1.0.tgz","fileCount":9,"integrity":"sha512-/e3e35qL0Sy/5JsXWx0Kj/dsnbrrjXsCCORqZmX0Y8tyKiL0FZPNkIlcrMZeSNPMRwAPajcfrxS5QT6wIDyvMA==","signatures":[{"sig":"MEUCIQDWAwCzeep0jc5Vd5NyNlaeEGLU1OlhkM82T4jaVaOgZAIgRyrOYBqLq2qrpqdPiGsXabqYPaveSB7byw42HN7Z7B0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":330864},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"e6a0ffad4396fab0a8dc44db7bded781b998dcd0","scripts":{"dev":"tsup --watch","test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest","prepublishOnly":"pnpm build"},"_npmUser":{"name":"s.caste","email":"s.castellitti.dev@gmail.com"},"_npmVersion":"10.9.2","description":"Usage metering and limits SDK for AI-powered apps. Track LLM tokens, image generations, video seconds, and any other AI consumption - provider-agnostic.","directories":{},"_nodeVersion":"23.10.0","dependencies":{"@vercel/analytics":"^2.0.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.0","vitest":"^4.1.6","typescript":"^5.8.3"},"_npmOperationalInternal":{"tmp":"tmp/sdk_1.1.0_1779580676501_0.6051834003286132","host":"s3://npm-registry-packages-npm-production"},"deprecated":"Package no longer supported. Contact Support at https://www.npmjs.com/support for more info."}},"time":{"created":"2026-05-08T12:13:58.121Z","modified":"2026-06-03T14:32:22.227Z","0.1.0":"2026-05-08T12:13:58.326Z","0.2.0":"2026-05-08T22:34:37.130Z","0.3.0":"2026-05-09T02:35:15.264Z","0.3.1":"2026-05-10T13:17:48.938Z","0.3.2":"2026-05-11T00:06:24.953Z","0.3.3":"2026-05-11T08:35:26.454Z","0.4.0":"2026-05-11T22:00:53.243Z","0.5.1":"2026-05-12T10:35:59.216Z","0.7.0":"2026-05-14T00:31:06.250Z","0.9.0":"2026-05-15T10:05:41.541Z","1.0.0":"2026-05-22T23:45:36.566Z","1.1.0":"2026-05-23T23:57:56.686Z"},"bugs":{"url":"https://aipricinglab.space/support"},"author":{"name":"AiPricingLab"},"license":"MIT","homepage":"https://aipricinglab.space","keywords":["ai","metering","usage","limits","billing","rate-limiting","llm","tokens","openai","anthropic","stripe","saas"],"description":"Usage metering and limits SDK for AI-powered apps. Track LLM tokens, image generations, video seconds, and any other AI consumption - provider-agnostic.","maintainers":[{"name":"s.caste","email":"s.castellitti.dev@gmail.com"}],"readme":"# @aipricinglab/sdk\n\n[![npm version](https://img.shields.io/npm/v/@aipricinglab/sdk.svg)](https://www.npmjs.com/package/@aipricinglab/sdk)\n\nThe official TypeScript SDK for **[AiPricingLab](https://aipricinglab.space)** - drop-in usage metering, limits, and plan enforcement for AI-powered apps.\n\nStop building your own meter for LLM tokens, image generations, video seconds, or any other AI consumption. Define plans in the dashboard, install this SDK, and ship.\n\n- 🌐 Website: <https://aipricinglab.space>\n- 📚 Docs: <https://aipricinglab.space/docs>\n- 🐛 Issues: <https://aipricinglab.space/support>\n\n---\n\n## Features\n\n- **Provider-agnostic** - works with OpenAI, Anthropic, Replicate, Fal, your own models, anything you bill against.\n- **Atomic reservations** - `reserve` / `commit` / `release` prevents parallel requests from blowing past limits.\n- **Behavioral analytics** - PostHog-style `capture` / `identify` / `alias` for paywalls, onboarding, and conversion funnels. Browser-safe with a public key.\n- **Prompt + artefact capture** - optionally attach the prompt/response strings and the generated binary (image, video, audio) to each event for inspection in the dashboard. Strictly observational - no impact on quotas.\n- **Zero runtime dependencies** - uses the platform `fetch`. Tiny bundle, works in Node, Bun, Deno, Edge, and the browser.\n- **Typed errors** - every failure mode is a typed `AiPricingLabError` with a stable `code`.\n- **Public + secret keys** - read a user's own usage from the browser with `pk_live_...`, do everything else from the backend with `sk_live_...`.\n\n> **New here?** Read the [tracking guide](https://github.com/aipricinglab/aipricinglab/blob/main/docs/tracking-guide.md)\n> - a top-to-bottom walk-through of subscribing a user, picking a metering\n> pattern, capturing prompts and media, and handling the unhappy paths.\n\n## Install\n\n```bash\nnpm install @aipricinglab/sdk\n# or\npnpm add @aipricinglab/sdk\n# or\nyarn add @aipricinglab/sdk\n```\n\nRequires Node 18+ (or any runtime with global `fetch`).\n\n> **Upgrading from 0.x?** 1.0 is the hybrid-privacy release - anonymous\n> aggregate pre-login, identified post-login, no cookie banner needed in the\n> EU by default. See [`MIGRATION.md`](./MIGRATION.md) for the full guide.\n\n## Quick start\n\nGrab a secret key from your app's **API keys** tab at <https://aipricinglab.space>, then:\n\n```ts\nimport { createClient } from '@aipricinglab/sdk';\n\nconst apl = createClient({ apiKey: process.env.AIPRICINGLAB_KEY! });\n\n// Just record consumption - fire-and-forget.\nawait apl.track('user_abc123', 'image.flux-pro', 1);\n```\n\nThat's it. The event is now visible in your AiPricingLab dashboard, counted against any matching plan limits.\n\n### Event naming convention\n\nThe plan builder generates match rules in the form **`<category>.<modelId>`**, where `category` is one of `image`, `llm`, `video`, `audio`. Use the same shape in your `track` / `canUse` / `reserve` calls so events count toward plan rows automatically:\n\n| Category | Example event name |\n|---|---|\n| Image generation | `image.flux-pro`, `image.gemini-3.1-image` |\n| Language model | `llm.gpt-4o`, `llm.claude-sonnet-4-6` |\n| Video generation | `video.runway-gen3`, `video.veo-2` |\n| Audio generation | `audio.elevenlabs-v2`, `audio.whisper` |\n\nA plan can also have a **category total** (e.g. *\"30 images of any kind per month\"*). Those use the wildcard pattern `<category>.*`, which matches any event that starts with that prefix - you don't need to emit anything special.\n\nYou're free to use any other event names too - they just won't match the structural plan rows; they'll only fire if you've added a matching custom group.\n\n## Reserve / commit / release (recommended)\n\nFor strict enforcement, use the three-step pattern. It atomically increments the counter *before* the AI call so two parallel requests can't both squeeze through under the limit:\n\n```ts\nimport { createClient, AiPricingLabError } from '@aipricinglab/sdk';\n\nconst apl = createClient({ apiKey: process.env.AIPRICINGLAB_KEY! });\n\nasync function generateImage(userId: string, prompt: string) {\n  // 1. Reserve quota before the AI call.\n  const reservation = await apl.reserve(userId, 'image.flux-pro', 1);\n\n  if (!reservation.allowed) {\n    throw new Error(`Limit reached: ${reservation.reasons?.join(', ')}`);\n  }\n\n  try {\n    const image = await callFluxPro(prompt);\n\n    // 2. Commit on success - the charge is final.\n    await apl.commit(reservation.reservationId!);\n    return image;\n  } catch (err) {\n    // 3. Release on failure - the user is not charged.\n    //    Pass an errorCode + reason to record *why* the quota was refunded.\n    await apl.release(reservation.reservationId!, {\n      errorCode: 'provider_error',\n      reason: err instanceof Error ? err.message : String(err),\n    });\n    throw err;\n  }\n}\n```\n\nReservations auto-expire after 60 seconds if you forget to commit or release, so a crashed server won't permanently lock quota.\n\nBoth `errorCode` (≤100 chars, stable identifier you'll group on) and `reason` (≤500 chars, human-readable detail) are optional. They're stored on the released reservation so you can audit upstream failures, surface error rates per model, or settle disputed charges.\n\n## Track (fire-and-forget)\n\nSimpler, no atomicity guarantee. Use it when slight over-counting is acceptable.\n\n### `quantity` semantics\n\n`quantity` is **the number of units the event consumed** in whatever unit the matching plan limit uses:\n\n- For an `image` plan with unit `count` → `quantity = 1` per generation.\n- For an `llm` plan with unit `tokens` → `quantity = totalInputTokens + totalOutputTokens`.\n- For an `llm` plan with unit `cents` → `quantity = costInCents` (integer cents).\n- For a `video` plan with unit `seconds` → `quantity = clipLengthInSeconds`.\n\n```ts\n// LLM call - pass total tokens consumed\nawait apl.track('user_abc123', 'llm.gpt-4o', 1842, {\n  inputTokens: '920',\n  outputTokens: '922',\n});\n\n// Video clip - pass duration in seconds\nawait apl.track('user_abc123', 'video.runway-gen3', 8);\n```\n\n## Check without charging\n\n```ts\nconst { allowed, matched, reasons } = await apl.canUse('user_abc123', 'image.flux-pro');\n\nif (!allowed) {\n  return showUpgradePrompt(reasons);\n}\n```\n\nOr the boolean shorthand:\n\n```ts\nif (await apl.can('user_abc123', 'image.flux-pro')) {\n  // proceed\n}\n```\n\n### Fail-closed by default\n\n`canUse` and `reserve` return `{ allowed: false, matched: false }` when:\n\n- The `event` string doesn't match any limit group on the user's plan → `reasons: ['unmatched_event']` (typo, missing limit group, or mistyped event name).\n- The user has no active subscription on file → `reasons: ['no_subscription']`. Either you forgot to call `upsertSubscription`, or the user was canceled via `cancelSubscription` and `endsAt` has now passed.\n\nThis is intentional - silent fail-open is a footgun. To make typos and missing setup obvious during development, the SDK also `console.warn`s once per call when `matched === false` and `process.env.NODE_ENV !== 'production'`. Production stays silent.\n\nEvery event sent to `track()` is *recorded regardless* (even unmatched / no-subscription) so you can inspect them in the dashboard's **Events** activity feed, which shows status badges (Counted / Not matched / Limit reached / No plan) and \"did you mean?\" suggestions for typos.\n\n## Prompt and response logging\n\nBoth `track` and `reserve` / `commit` accept optional `prompt` and `response`\nstrings on a trailing options bag. When the app has prompt logging enabled\nin the dashboard, they're persisted to `event_logs` keyed to the event row.\nWhen the toggle is off, the strings are silently dropped server-side, so you\ncan pass them unconditionally and flip the dashboard switch later.\n\n```ts\n// Track flow\nawait apl.track('user_abc123', 'image.flux-pro', 1, undefined, {\n  prompt: 'a cat in a tiny hat',\n  response: 'https://cdn.example/img.png',\n});\n\n// Reserve/commit flow - prompt is captured before the AI call,\n// response after.\nconst { reservationId } = await apl.reserve(\n  'user_abc123', 'image.flux-pro', 1, undefined,\n  { prompt: 'a cat in a tiny hat' },\n);\ntry {\n  const url = await callFluxPro(prompt);\n  await apl.commit(reservationId!, { response: url });\n} catch (err) {\n  await apl.release(reservationId!, {\n    errorCode: 'provider_error',\n    reason: err instanceof Error ? err.message : String(err),\n  });\n}\n```\n\nPer-field cap: 32 KB. Longer values are server-side truncated with\n`…[truncated]`.\n\n## Media attachments\n\nBoth `track` and `commit` accept an optional `media` array - the binary\nartefact the AI produced (image, video clip, audio file). Stored alongside\nthe event row for later inspection in the dashboard. **Purely observational:**\nno quota, no credit charge, no impact on `canUse` / `reserve` decisions.\n\n```ts\nconst image = await callFluxPro(prompt);\n\nawait apl.track('user_abc123', 'image.flux-pro', 1, undefined, {\n  prompt: 'a cat in a tiny hat',\n  media: [{\n    kind: 'image',\n    mime: 'image/png',\n    filename: 'out.png',\n    data: image.bytes,                  // Uint8Array | Blob | ReadableStream\n    sizeBytes: image.bytes.byteLength,\n  }],\n});\n```\n\n`reserve` does **not** accept media - the AI call hasn't run yet. Pass\nmedia on `commit` instead:\n\n```ts\nawait apl.commit(reservationId!, {\n  response: 'flux_image_42',\n  media: [{ kind: 'image', mime: 'image/png', data: bytes, sizeBytes: bytes.byteLength }],\n});\n```\n\nThe response carries a `media: MediaResult[]` aligned with the input array.\nEach entry has a `status` of `uploaded` / `skipped` / `failed` / `pending`,\nplus a `skipReason` or `failReason` when applicable.\n\n**Media handling never throws.** If the app toggle is off, the eligibility\ngate rejects the file, or the upload network call fails, the metering event\nstill succeeds and `media[i].status` reflects what happened. Wire an\n`onMediaError` callback on `createClient` to surface failures to your\nobservability stack:\n\n```ts\nconst apl = createClient({\n  apiKey: process.env.AIPRICINGLAB_KEY!,\n  onMediaError: (err, input) => logger.warn({ err, input }, 'apl media upload failed'),\n});\n```\n\nPer-file cap 100 MB, per-request 10 files / 200 MB aggregate. Full design\nand storage layout: see the project's `docs/media-uploads.md`.\n\n## Variant-gated plan rows\n\nSome plans gate a model by output tier - e.g. *\"100 standard images, 10 4K images\"*. Pass the `variant` key in `metadata` so the right bucket is incremented:\n\n```ts\nawait apl.track('user_abc123', 'image.gemini-3.1-image', 1, { variant: '4k' });\n```\n\n`variant` is the only reserved metadata key - everything else is yours.\n\n### Metadata is string-only\n\nMetadata values must be strings (`Record<string, string>`). The API rejects numbers and booleans, so coerce them on your side:\n\n```ts\nawait apl.track('user_abc123', 'llm.gpt-4o', 1842, {\n  inputTokens: String(920),    // ✅\n  cached: String(true),         // ✅\n  // outputTokens: 922,         // ❌ rejected\n});\n```\n\n## Read a user's own usage (browser-safe)\n\nUse a `pk_live_...` key in client-side code. Public keys can only read usage; they cannot track, reserve, or modify subscriptions. The SDK auto-routes public keys to the public-safe endpoint:\n\n```ts\nconst apl = createClient({ apiKey: 'pk_live_...' });\n\nconst usage = await apl.usage(currentUserId);\n// → { userId, period: { start, end } | null, counters: [{ groupId, count, costCents }, ...] }\n```\n\n`period` is `null` when the user has no active subscription on the app.\n\n## Manage subscriptions\n\nMove a user onto a plan from your backend:\n\n```ts\nawait apl.upsertSubscription({\n  userId: 'user_abc123',\n  planId: 'plan_pro_monthly',\n});\n```\n\nCalling `upsertSubscription` with the **same** `planId` the user is already on is a no-op: counters keep ticking, `started_at` is preserved, periods don't reset. Safe to call on every login or webhook retry.\n\n### Plan-change semantics\n\nWhen you move a user onto a *different* plan mid-period, each limit group on the new plan picks one of three behaviors (configured per-plan in the dashboard's **Advanced** section):\n\n| Mode | What happens to counters at switch time |\n|---|---|\n| **`carry`** *(default)* | Existing counters with the same limit-group ID continue. Brand-new groups start at 0. |\n| **`reset`** | Counters for the new plan's groups are wiped - the user starts the period from 0. |\n| **`block`** | Counters are pre-filled to quota; `canUse` / `reserve` return `limit_reached` until the next period rollover. |\n\nThis lets you choose the right downgrade/upgrade UX - generous (`carry`), clean-slate (`reset`), or anti-abuse (`block`, which closes the \"free→pro→cancel→fresh free quota\" cycling exploit).\n\n### Cancellation\n\nThere are two cancellation patterns depending on your product. **Pick one - don't mix them for the same user.**\n\n#### Pattern A - your app has a free plan (most consumer apps)\n\nDon't call `cancelSubscription`. Just move the user to the free plan:\n\n```ts\nawait apl.upsertSubscription({\n  userId: 'user_abc123',\n  planId: 'free',\n});\n```\n\nThe user keeps using your app under free-tier limits. The transition is recorded in the subscription history as `plan_changed: pro → free` (queryable later for churn analytics). Period and counter behavior follow whichever `onPlanChange` mode the new plan's limit groups are configured with.\n\n#### Pattern B - your app requires a paid subscription (no free tier)\n\nCall `cancelSubscription` when the user churns out:\n\n```ts\nawait apl.cancelSubscription({\n  userId: 'user_abc123',\n  // optional: schedule cancellation at period end instead of immediately\n  endsAt: '2026-06-30T23:59:59Z',\n  reason: 'user_cancel',\n});\n```\n\nEffect once `endsAt` is reached (immediately if omitted):\n\n- `canUse(...)` returns `{ allowed: false, matched: false, reasons: ['no_subscription'] }` - **the user is blocked**.\n- `reserve(...)` returns the same shape and creates no reservation - **the user is blocked**.\n- `track(...)` still records the event for visibility (you'll see the attempt in the dashboard) but increments no counters and bills no cost. The event row is marked `match_status: 'no_subscription'`.\n\nYour code should already be guarded with `if (!result.allowed) return ...`, so cancellation flows through without needing any client-side change beyond a \"subscribe to continue\" UI.\n\n`endsAt` accepts a future ISO timestamp to schedule the cancellation (e.g. \"let them use it until the billing period ends\"). The user keeps their current plan and limits until that moment, then is blocked.\n\nTo reactivate a canceled user, call `upsertSubscription({ userId, planId })` - that clears `endsAt` and logs a fresh transition in the history.\n\n### Subscription history\n\nEvery `created` / `plan_changed` / `canceled` transition is appended to a server-side audit log (`subscription_events`) - never overwritten. This powers churn / downgrade analytics, \"which plan was this user on last Tuesday?\" lookups, and dispute resolution. A no-op upsert (same plan, no change) writes **no** history row; only real state changes are recorded.\n\n## Credit packs\n\nPlans set recurring quotas; **credit packs** are one-shot top-ups that don't reset on period rollover. Use them for paid bolt-ons (\"buy 100 extra images\"), promo grants, or refunds. Credits are consumed automatically by `track` / `reserve` when the user is out of plan quota - there's nothing to wire on the consumption side.\n\nAll credit ops live under `client.credits.*`.\n\n```ts\n// Grant 100 image credits to a user after a Stripe webhook.\n// `externalRef` makes this idempotent - replaying the same Stripe event\n// is a no-op, no double-grant.\nawait apl.credits.grant({\n  userId: 'user_abc123',\n  packId: 'pack_image_topup',\n  quantity: 100,\n  externalRef: stripeEvent.id,\n  source: 'purchase',\n});\n```\n\n```ts\n// Browser-safe: list a user's own balances. Public keys (`pk_*`) are accepted\n// when `userId` matches the end-user that key represents.\nconst apl = createClient({ apiKey: 'pk_live_...' });\nconst { credits } = await apl.credits.list({\n  userId: currentUserId,\n  event: 'image.flux-pro',     // optional: only packs that cover this event\n});\n```\n\n```ts\n// Read counters and credits together - both come back from usage().\nconst { counters, credits } = await apl.usage(currentUserId, 'image.*');\n//                                                          ^ same filter applies to both\n```\n\n```ts\n// Audit trail / ledger - paginated, newest first. Requires a secret key.\nconst { entries, nextCursor } = await apl.credits.history({ userId: 'user_abc123', limit: 50 });\n```\n\n```ts\n// Refund / clawback - sets remaining to 0 and records an admin_adjust ledger row.\nawait apl.credits.revoke({ balanceId: 'cb_...', reason: 'chargeback' });\n```\n\n| Method | Purpose |\n|---|---|\n| `credits.grant({ userId, packId, quantity, externalRef?, expiresAt?, source?, notes? })` | Issue a credit balance. Idempotent on `externalRef`. Secret key required. |\n| `credits.revoke({ balanceId, reason? })` | Zero out a balance. Secret key required. |\n| `credits.list({ userId, event?, includeExpired? })` | List a user's live balances. Public key OK when reading the key's own user. |\n| `credits.history({ userId, limit?, cursor? })` | Paginated ledger history. Secret key required. |\n\n## Behavioral analytics\n\nMetering answers *\"how much did this user consume?\"*. **Analytics** answers\n*\"what did this user do?\"* - paywall views, onboarding steps, checkout funnels,\nfeature engagement. It's a separate surface from `track` / `reserve`, writes to\nits own tables, and is **browser-safe with a `pk_*` key**.\n\nThe default mode is **`hybrid`**: anonymous aggregate pre-login, identified\npost-login. No `localStorage`, no cookie, **no cookie banner needed in the EU**\nout of the box. Configure once at `createClient` if you need a different\nposture:\n\n```ts\nimport { createClient } from '@aipricinglab/sdk';\n\nconst apl = createClient({\n  apiKey: process.env.NEXT_PUBLIC_APL_KEY!,\n  // analytics: { mode: 'hybrid', requireConsent: true }, // ← defaults\n});\n```\n\n### `capture` - omit `distinctId` while anonymous\n\n```ts\n// Pre-login: anonymous aggregate event. No person profile, no stored IP.\napl.analytics.capture({ event: 'paywall_shown' });\n\n// Post-login: identified event linked to the user's profile.\napl.analytics.capture({\n  distinctId: user.id,\n  event: 'paywall_shown',\n  properties: { placement: 'after_3rd_image', plan: 'pro' },\n});\n```\n\nOne event = one `capture()` call. You choose the event names; the dashboard\nbuilds funnels and reports from them. A curated set of **reserved event names**\n(`paywall_shown`, `checkout_completed`, `onboarding_step`, …) get first-class\ntreatment - badges, preset funnels, property hints. Import the catalogue for\ncompile-time-safe names:\n\n```ts\nimport { RESERVED_EVENTS, isReservedEvent } from '@aipricinglab/sdk';\n```\n\n### `identify` - link an identity\n\n```ts\nawait apl.analytics.identify(user.id, {\n  email: user.email, plan: 'pro',\n});\n```\n\n`identify` is idempotent - safe to call on every page load.\n\n**Merging a pre-signup anonymous session into the new account is\nconsent-gated** under GDPR / ePrivacy. Acquire user consent through your\ncookie banner first, then pass it explicitly - the SDK throws\n`consent_required` otherwise:\n\n```ts\nawait apl.analytics.identify(user.id, { email }, undefined, {\n  mergeAnonymousId: anonId,\n  consentGiven: true,\n});\n```\n\n### `alias`\n\n```ts\nawait apl.analytics.alias('user_uuid_old', 'user_email@example.com');\n```\n\nThe same consent gate kicks in when either id is an APL anonymous session\n(an id minted by `getAnonymousId()`, recognised by its `anon_` prefix) -\npass `{ consentGiven: true }`.\n\n### Person profiles\n\nProfile properties live on the *person*, not the event. Update them via\n`identify`, or inline from `capture` with the reserved `$set` / `$set_once`\nkeys (identified events only):\n\n```ts\napl.analytics.capture({\n  distinctId: user.id,\n  event: 'subscription_started',\n  properties: {\n    plan: 'pro',\n    $set: { plan: 'pro' },\n    $set_once: { first_paid_at: new Date().toISOString() },\n  },\n});\n```\n\n### Privacy & GDPR - secret-key only\n\nBackend-only privileged operations. All six refuse a `pk_*` key with\n`requires_secret_key`.\n\n```ts\nawait apl.analytics.optOut('user_12345');      // Art. 21 right to object\nawait apl.analytics.optIn('user_12345');\nawait apl.analytics.isOptedOut('user_12345');\n\nconst { jobId } = await apl.analytics.deletePerson('user_12345');  // Art. 17\nawait apl.analytics.getDeletionStatus(jobId);\n\nconst { downloadUrl, expiresAt } = await apl.analytics.exportPerson('user_12345');\n// Art. 15 / 20 - share `downloadUrl` with the data subject (valid 24h)\n```\n\nAfter `optOut`, subsequent `capture()` calls for that user are silently\ndropped - the response shape is normal so the caller cannot tell. After\n`deletePerson`, an async worker cascades the delete across analytics +\nmetering surfaces; new captures drop in the meantime via `pending_deletion`.\n\n### `getAnonymousId` (deprecated in hybrid mode)\n\n`getAnonymousId()` is still exported for `identified`-mode use cases, but\nemits a deprecation warning on first call. In `hybrid` mode (the default),\nyou don't need it - omit `distinctId` from `capture()` instead.\n\n### Batching\n\nSend up to 100 events in a single request:\n\n```ts\nawait apl.analytics.captureBatch([\n  { distinctId: 'u1', event: 'onboarding_step', properties: { step: '1' } },\n  { distinctId: 'u1', event: 'onboarding_step', properties: { step: '2' } },\n]);\n```\n\nAnalytics events count against a separate per-workspace quota; exceeding it\nthrows `analytics_quota_exceeded`. Full guide:\n[`docs/analytics.md`](https://github.com/aipricinglab/aipricinglab/blob/main/docs/analytics.md)\n· dev-facing privacy guide:\n[`docs/analytics-privacy.md`](https://github.com/aipricinglab/aipricinglab/blob/main/docs/analytics-privacy.md).\n\n## Error handling\n\nEvery method throws a typed `AiPricingLabError` on failure:\n\n```ts\nimport { AiPricingLabError } from '@aipricinglab/sdk';\n\ntry {\n  await apl.track('user_abc123', 'image.flux-pro');\n} catch (err) {\n  if (err instanceof AiPricingLabError) {\n    console.error(err.code, err.status, err.message);\n    // err.code: 'limit_reached' | 'invalid_key' | 'not_found' | 'workspace_limit_reached' | ...\n  }\n}\n```\n\n## API reference\n\n| Method | Purpose |\n|---|---|\n| `track(userId, event, quantity?, metadata?, { prompt?, response?, media? }?)` | Record consumption. Optional prompt/response are stored when prompt logging is on; optional media is uploaded out-of-band when the app toggle is on. |\n| `canUse(userId, event, quantity?, metadata?)` | Check if allowed; returns `{ allowed, matched, reasons, details }`. |\n| `can(userId, event, quantity?, metadata?)` | Boolean shorthand for `canUse`. |\n| `reserve(userId, event, quantity?, metadata?, { prompt? }?)` | Atomically hold quota; returns a `reservationId`. Optional `prompt` is captured before the AI call. |\n| `commit(reservationId, { response?, media? }?)` | Confirm a reservation. Optional response/media are persisted same as on `track`. |\n| `release(reservationId, { reason?, errorCode?, response? }?)` | Cancel a reservation; quota returned. Optional fields are persisted for auditing. |\n| `usage(userId, event?)` | Read a user's current counters. |\n| `availablePlans()` | Fetch the app's public plan catalogue. Browser-safe with a `pk_*` key. |\n| `upsertSubscription({ userId, planId, customLimits?, endsAt?, cycleStart? })` | Assign or change a user's plan. Use this for downgrades when you have a free plan. |\n| `cancelSubscription({ userId, endsAt?, reason? })` | Cancel a user's subscription. Use when you have no free plan and want to block the user post-cancellation. |\n| `credits.grant(...)` / `credits.revoke(...)` / `credits.list(...)` / `credits.history(...)` | One-shot credit packs that survive period rollover. See **Credit packs** above. |\n| `analytics.capture({ distinctId, event, properties?, timestamp? })` | Record one behavioral event. Browser-safe with a `pk_*` key. |\n| `analytics.captureBatch(events)` | Send up to 100 behavioral events in one request. |\n| `analytics.identify(distinctId, properties?, propertiesOnce?, anonymousId?)` | Identify a user; pass `anonymousId` to merge a pre-signup session. |\n| `analytics.alias(distinctId, alias)` | Bridge two ids for the same person, no profile change. |\n| `getAnonymousId(storageKey?)` | Stable per-browser anonymous id for pre-signup events. |\n\nFull request/response types are exported from the package - your editor will pick them up.\n\n## Configuration\n\n```ts\ncreateClient({\n  apiKey: 'sk_live_...',          // required\n  baseUrl: 'https://www.aipricinglab.space', // optional\n  analytics: {\n    mode: 'hybrid',               // 'hybrid' (default) | 'identified' | 'aggregate'\n    requireConsent: true,         // default\n  },\n});\n```\n\n`baseUrl` - only set this if you're running a self-hosted instance.\n\n`analytics.mode` - see the [behavioral-analytics section](#behavioral-analytics).\nThe default `hybrid` mode is EU-friendly out of the box and writes nothing to\nthe browser. `identified` requires a cookie consent banner in the EU. `aggregate`\ndisables `identify()` / `alias()` entirely.\n\n`analytics.requireConsent` - a posture flag that you (the developer) won't\nwrite a persistent browser identifier without consent. The SDK writes\nnothing to the browser in `hybrid` mode regardless; the flag matters when\nyou opt into `identified`-mode features that call `getAnonymousId()`.\n\n## License\n\nMIT © [AiPricingLab](https://aipricinglab.space)\n","readmeFilename":"README.md"}