{"_id":"@aimdoc/sdk","_rev":"12-80184104a605a47eb9e55ca089e0ba42","name":"@aimdoc/sdk","dist-tags":{"latest":"2.7.0"},"versions":{"1.0.0":{"name":"@aimdoc/sdk","version":"1.0.0","_id":"@aimdoc/sdk@1.0.0","maintainers":[{"name":"benjskoog","email":"ben@aimdoc.ai"}],"dist":{"shasum":"9b4b3f65bc6c7c49d4e0d52fb5a101980c1bfb9c","tarball":"https://registry.npmjs.org/@aimdoc/sdk/-/sdk-1.0.0.tgz","fileCount":5,"integrity":"sha512-gZBOBLZAkNuGOttrl9P9S457jgy+mFuS3Tyib+XF87YHpxjNC+BCRf2itdZCab2dYAy9QO6eJSTiAM+5X39/eQ==","signatures":[{"sig":"MEQCIEalfWbZ+oJjvlYNe+zrTi2Mbr5O4C1uamhST751nDGxAiAxRyRzEHuTvaaVbYsBsIsLKNzfIBbyuwAcTXdv0BIjBQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":3092},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.mjs","gitHead":"da69bf3ef79b033844878b7a489b2cee5b79bcef","scripts":{"dev":"tsup --watch","build":"tsup"},"_npmUser":{"name":"benjskoog","email":"ben@aimdoc.ai"},"_npmVersion":"10.8.1","description":"Aimdoc SDK for web applications","directories":{},"_nodeVersion":"22.4.0","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.6","typescript":"^5.7.3"},"_npmOperationalInternal":{"tmp":"tmp/sdk_1.0.0_1738709465561_0.3432730899765375","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@aimdoc/sdk","version":"1.0.1","_id":"@aimdoc/sdk@1.0.1","maintainers":[{"name":"benjskoog","email":"ben@aimdoc.ai"}],"dist":{"shasum":"5f161ebc2707596be754d63245587e4cfcb48a0b","tarball":"https://registry.npmjs.org/@aimdoc/sdk/-/sdk-1.0.1.tgz","fileCount":5,"integrity":"sha512-VGscz77V2lMIOg/IZtwAGHYJPwkEkmD2Jd3R06Tixk+MX1hOqDBcJFoTESnNWyiR7fAlYDNYm9wb7BJx5OJkWA==","signatures":[{"sig":"MEQCID6YwI+zFORMPFjWH9SnC0F1lNvGMx8l6+MF7qwtiREfAiBt5A1d7Y4UEN7ihkxZfZ2SmS3l4bzDnMNAV/+WUllK/g==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":3938},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.mjs","gitHead":"95bf0c5bfe920f6ba358f1a12aaa922819bdf053","scripts":{"dev":"tsup --watch","build":"tsup"},"_npmUser":{"name":"benjskoog","email":"ben@aimdoc.ai"},"_npmVersion":"10.8.1","description":"Aimdoc SDK for web applications","directories":{},"_nodeVersion":"22.4.0","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.6","typescript":"^5.7.3"},"_npmOperationalInternal":{"tmp":"tmp/sdk_1.0.1_1738881734271_0.4497253916306625","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@aimdoc/sdk","version":"1.0.2","_id":"@aimdoc/sdk@1.0.2","maintainers":[{"name":"benjskoog","email":"ben@aimdoc.ai"}],"dist":{"shasum":"cf663ec3c3d9e27b3bbbfafb39543fd01c1a0cfb","tarball":"https://registry.npmjs.org/@aimdoc/sdk/-/sdk-1.0.2.tgz","fileCount":5,"integrity":"sha512-hpRIfkt445Eq+xBRhvhHcypKU1keFdX8fdrJnG1H2eu+hYejei3x9EcdZbuJ5IioRxE3oySrVzizkEV2bVT2zw==","signatures":[{"sig":"MEUCIGb1EYaGLcdiv6lBiCAgiBAJJ+k/WUJKlT0Vrfu2DpMnAiEAxlAdrmHPCrOs1f8/4jqaXTwwgi+e+HTE7BOOAbv5w7o=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":4644},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.mjs","gitHead":"95bf0c5bfe920f6ba358f1a12aaa922819bdf053","scripts":{"dev":"tsup --watch","build":"tsup"},"_npmUser":{"name":"benjskoog","email":"ben@aimdoc.ai"},"_npmVersion":"10.8.1","description":"Aimdoc SDK for web applications","directories":{},"_nodeVersion":"22.4.0","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.6","typescript":"^5.7.3"},"_npmOperationalInternal":{"tmp":"tmp/sdk_1.0.2_1738882060911_0.19162955406664528","host":"s3://npm-registry-packages-npm-production"}},"1.0.3":{"name":"@aimdoc/sdk","version":"1.0.3","_id":"@aimdoc/sdk@1.0.3","maintainers":[{"name":"benjskoog","email":"ben@aimdoc.ai"}],"dist":{"shasum":"21281c747c0810c365574de7631adce51895f224","tarball":"https://registry.npmjs.org/@aimdoc/sdk/-/sdk-1.0.3.tgz","fileCount":5,"integrity":"sha512-BPffHHqvA1YIh9TWIJJerMm5uCInb5RQGPhhHkCWxXo7maV/iw6h9DvoSCmqwZtD1mHdk0DoZ6L5s6mUamn6BA==","signatures":[{"sig":"MEQCIA+qbo//l58lHVhgJz6ZKq99BGbsSu3xly/IiiydY3g1AiASKizJXBNJP4g4YHXBzveev75gQoCSlc/nwghmb/xP6Q==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":5788},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.mjs","gitHead":"e99856b70621e6d6a392b8750aa6555fb135ccbb","scripts":{"dev":"tsup --watch","build":"tsup"},"_npmUser":{"name":"benjskoog","email":"ben@aimdoc.ai"},"_npmVersion":"10.8.1","description":"Aimdoc SDK for web applications","directories":{},"_nodeVersion":"22.4.0","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.6","typescript":"^5.7.3"},"_npmOperationalInternal":{"tmp":"tmp/sdk_1.0.3_1739251918941_0.0010672021994648784","host":"s3://npm-registry-packages-npm-production"}},"2.0.0":{"name":"@aimdoc/sdk","version":"2.0.0","license":"MIT","_id":"@aimdoc/sdk@2.0.0","maintainers":[{"name":"benjskoog","email":"ben@aimdoc.ai"}],"dist":{"shasum":"12b31b34a453168792b0e5f12cd92a4d07a3fa9d","tarball":"https://registry.npmjs.org/@aimdoc/sdk/-/sdk-2.0.0.tgz","fileCount":5,"integrity":"sha512-rbTgtr1npfErYwF4hqAdxf2rSxV6vPBkaJCDgn4qy3qhFZbMQL5dCZyRLH+s9N7pQ5RxfJ/Zobtqm1XeGwNwEw==","signatures":[{"sig":"MEUCIHVSDDcZ/FFF8CxghMBl/LQgDj0ZPV+cZfU6fA3DHzrSAiEA847PajeO4lxtMqvluQopx0AkjkKrTcU4wMtIgvmYKUY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":5364},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.mjs","gitHead":"04c0a4fb6e4e49d8f86879a40fccf8fb1c1d348b","scripts":{"build":"tsup"},"_npmUser":{"name":"benjskoog","email":"ben@aimdoc.ai"},"_npmVersion":"11.4.2","description":"Aimdoc SDK — typed helpers for identify, openChat, and sendMessage","directories":{},"_nodeVersion":"24.3.0","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.6","typescript":"^5.7.3"},"_npmOperationalInternal":{"tmp":"tmp/sdk_2.0.0_1772412260001_0.5888641047702394","host":"s3://npm-registry-packages-npm-production"}},"2.0.1":{"name":"@aimdoc/sdk","version":"2.0.1","license":"MIT","_id":"@aimdoc/sdk@2.0.1","maintainers":[{"name":"benjskoog","email":"ben@aimdoc.ai"}],"dist":{"shasum":"a28d5f6e66dc9bd6aa62d053a276483d440a481d","tarball":"https://registry.npmjs.org/@aimdoc/sdk/-/sdk-2.0.1.tgz","fileCount":5,"integrity":"sha512-wywVvat0ioZpjhPO7xpQd0L7kIKMAamcBEszPi3F1UuMaDoGNoKTlyUI2xhs+mB+uWthao1MOOQRLuA1tElThg==","signatures":[{"sig":"MEUCIF1/GPyhuYhKNXXfgJcxO3qFemGp0eAtk5LvXEZhRLtHAiEA7oT/UCPH2hDPHcxSrIe53MmVRw5fj6ssL1DDx1E85XY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":5592},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.mjs","gitHead":"04c0a4fb6e4e49d8f86879a40fccf8fb1c1d348b","scripts":{"build":"tsup"},"_npmUser":{"name":"benjskoog","email":"ben@aimdoc.ai"},"_npmVersion":"11.4.2","description":"Aimdoc SDK — typed helpers for identify, openChat, and sendMessage","directories":{},"_nodeVersion":"24.3.0","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.6","typescript":"^5.7.3"},"_npmOperationalInternal":{"tmp":"tmp/sdk_2.0.1_1772428288841_0.9313172069926716","host":"s3://npm-registry-packages-npm-production"}},"2.0.2":{"name":"@aimdoc/sdk","version":"2.0.2","license":"MIT","_id":"@aimdoc/sdk@2.0.2","maintainers":[{"name":"benjskoog","email":"ben@aimdoc.ai"}],"dist":{"shasum":"b8e060c7d9423a5f0a3c736a6463f046c9ffd883","tarball":"https://registry.npmjs.org/@aimdoc/sdk/-/sdk-2.0.2.tgz","fileCount":5,"integrity":"sha512-sC68HdeSuf+XrUBWLyGul2VUP61paCyIIA/GXYn18G70RkImwnR2COh4IWs/S1eMKp9JkAYZzZaSigVXvzjFMQ==","signatures":[{"sig":"MEYCIQDsw3dY/DkFsyXxGyHlmaoIsWO3B/qLx9csuT+Sgl5RDgIhAOpnyuqhQyrl51lPgRPa+UX81BBTaxoZNoJXCSWJYJ+i","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":4352},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.mjs","gitHead":"04c0a4fb6e4e49d8f86879a40fccf8fb1c1d348b","scripts":{"build":"tsup"},"_npmUser":{"name":"benjskoog","email":"ben@aimdoc.ai"},"_npmVersion":"11.4.2","description":"Aimdoc SDK — typed helpers for identify, openChat, and sendMessage","directories":{},"_nodeVersion":"24.3.0","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.6","typescript":"^5.7.3"},"_npmOperationalInternal":{"tmp":"tmp/sdk_2.0.2_1772473051662_0.8672849660252397","host":"s3://npm-registry-packages-npm-production"}},"2.0.3":{"name":"@aimdoc/sdk","version":"2.0.3","license":"MIT","_id":"@aimdoc/sdk@2.0.3","maintainers":[{"name":"benjskoog","email":"ben@aimdoc.ai"}],"dist":{"shasum":"72ef4052ff9d0c2cbd0e4a975584be8566e46bdf","tarball":"https://registry.npmjs.org/@aimdoc/sdk/-/sdk-2.0.3.tgz","fileCount":6,"integrity":"sha512-hXqJNaQsynA4uWbv/VL3ZB8XkvSpqhywVYRfsh+KGc3HHnrxmSUKd3oJ29GG4HZvQEN+zygRPPW518MbubuWgg==","signatures":[{"sig":"MEQCICZyc/o8FAsPMp6aMbti0QdKH1Ri8n35pLqRz15RK9GbAiBatok4OAmIxkelX2i4UbxcYXnXs7CDlzsma/w9qCTEhg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":5778},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.mjs","gitHead":"c321699b575df509b967cf2f0dae11e3b125674c","scripts":{"build":"tsup"},"_npmUser":{"name":"benjskoog","email":"ben@aimdoc.ai"},"_npmVersion":"11.4.2","description":"Aimdoc SDK — typed helpers for identify, openChat, and sendMessage","directories":{},"_nodeVersion":"24.3.0","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.6","typescript":"^5.7.3"},"_npmOperationalInternal":{"tmp":"tmp/sdk_2.0.3_1780977293411_0.811725276430548","host":"s3://npm-registry-packages-npm-production"}},"2.3.0":{"name":"@aimdoc/sdk","version":"2.3.0","license":"MIT","_id":"@aimdoc/sdk@2.3.0","maintainers":[{"name":"benjskoog","email":"ben@aimdoc.ai"}],"dist":{"shasum":"59d6ee894b957c14150ba00c04fc17a9b2dbc8b8","tarball":"https://registry.npmjs.org/@aimdoc/sdk/-/sdk-2.3.0.tgz","fileCount":6,"integrity":"sha512-X4RD8uKUJflzsOLIBijYEj20ZZUaPU8/tnrYSFdUoCUfI44OaqZiXRQAK3XuZvhyLyFBVD/SNpqXiAZq4hPnQQ==","signatures":[{"sig":"MEYCIQCjQA5/fbgJnPqwxd2aOHhMFLAB1TLmCvJpoa6QjbPBmwIhAOw+SyeVJoq6rt2vd3ySonnLuuBGFuZJf1NP/a9RTECi","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":13068},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.mjs","gitHead":"9cf027dd8c7308046d895c2ee8091f41f04e191a","scripts":{"build":"tsup"},"_npmUser":{"name":"benjskoog","email":"ben@aimdoc.ai"},"overrides":{"picomatch":"^4.0.5"},"_npmVersion":"11.4.2","description":"Aimdoc SDK — typed helpers for identify, openChat, and sendMessage","directories":{},"_nodeVersion":"24.3.0","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.6","typescript":"^5.7.3"},"_npmOperationalInternal":{"tmp":"tmp/sdk_2.3.0_1786041214580_0.6789492896093543","host":"s3://npm-registry-packages-npm-production"}},"2.4.0":{"name":"@aimdoc/sdk","version":"2.4.0","license":"MIT","_id":"@aimdoc/sdk@2.4.0","maintainers":[{"name":"benjskoog","email":"ben@aimdoc.ai"}],"dist":{"shasum":"9dff6f524340bb4efa0c988104ea1d68ef14cec0","tarball":"https://registry.npmjs.org/@aimdoc/sdk/-/sdk-2.4.0.tgz","fileCount":6,"integrity":"sha512-SSjYolUyDo1Gx8Ggsw/MwYSVrGx7WpR0MwXab0uxOECFVF2o/MHjg1ZRlus04l1CwxgD2ZsHwH6DmtiTr+S5Ow==","signatures":[{"sig":"MEUCIQDQtcTG1D7gSsuoYsvUKhXE1RuSgqGSnep6K7nV8wyhAQIgS4BR9nnslwtzGkqqHfOSJyO+8KoIfY9vwc7Ad7E3j+s=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":21118},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.mjs","gitHead":"64ca9b02dfc65a3c4e7a6ec387d12789fd608c29","scripts":{"build":"tsup"},"_npmUser":{"name":"benjskoog","email":"ben@aimdoc.ai"},"overrides":{"picomatch":"^4.0.5"},"_npmVersion":"11.4.2","description":"Aimdoc SDK — typed helpers for identify, openChat, and sendMessage","directories":{},"_nodeVersion":"24.3.0","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.6","typescript":"^5.7.3"},"_npmOperationalInternal":{"tmp":"tmp/sdk_2.4.0_1786421677133_0.5549878878141885","host":"s3://npm-registry-packages-npm-production"}},"2.6.0":{"name":"@aimdoc/sdk","version":"2.6.0","license":"MIT","_id":"@aimdoc/sdk@2.6.0","maintainers":[{"name":"benjskoog","email":"ben@aimdoc.ai"}],"dist":{"shasum":"6ced8673f452d2b70e4efac3c53b33c44359a4b8","tarball":"https://registry.npmjs.org/@aimdoc/sdk/-/sdk-2.6.0.tgz","fileCount":10,"integrity":"sha512-peYYzaeljZkqScOAs26bM++mBU/JMYSTBEtecHYdfD76Brq0fKNj9j+QQinQKGmb98YiNoyobmrCrpXk5oO3xQ==","signatures":[{"sig":"MEUCIQDM73QLTf2eQRaTWfD91nHcJ122xtBxfz7NhxJxUsI7TAIgbHFUhtEoQ0ujGLhmU3N+a7OIvvR/rP6PqW7dUK2cTRg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":80731},"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"},"./server":{"types":"./dist/server.d.ts","import":"./dist/server.mjs","require":"./dist/server.js"}},"gitHead":"d82ea376a1488de30671a937e9e6a96b8a234844","scripts":{"build":"tsup"},"_npmUser":{"name":"benjskoog","email":"ben@aimdoc.ai"},"overrides":{"picomatch":"^4.0.5"},"_npmVersion":"11.4.2","description":"Aimdoc SDK — chat widget helpers and the direct Services API client","directories":{},"_nodeVersion":"24.3.0","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.6","typescript":"^5.7.3"},"_npmOperationalInternal":{"tmp":"tmp/sdk_2.6.0_1787668630509_0.43429468761444023","host":"s3://npm-registry-packages-npm-production"}},"2.7.0":{"name":"@aimdoc/sdk","version":"2.7.0","description":"Aimdoc SDK — chat widget helpers and the direct Services API client","main":"dist/index.js","module":"dist/index.mjs","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"},"./server":{"types":"./dist/server.d.ts","import":"./dist/server.mjs","require":"./dist/server.js"}},"scripts":{"build":"tsup"},"devDependencies":{"tsup":"^8.3.6","typescript":"^5.7.3"},"overrides":{"picomatch":"^4.0.5"},"license":"MIT","_id":"@aimdoc/sdk@2.7.0","gitHead":"b7d3e7317e0ed06b897f949deae73bfd4debb125","_nodeVersion":"24.3.0","_npmVersion":"11.4.2","dist":{"integrity":"sha512-zQDyJVJ7Ckbi2shdN2IUV3MVjkPkTedaf/PhbOllkHKz4sTBr0mutQntEUTUKB2v0F2tE1wvbgVbOZ4v7JTGBA==","shasum":"2af4e1b324d2eb7457bdc067e45050959dab6132","tarball":"https://registry.npmjs.org/@aimdoc/sdk/-/sdk-2.7.0.tgz","fileCount":10,"unpackedSize":88445,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCN7RgX/4YNMZxx/OXuBXpCf0K+qy0QpcK5niD7K7YiVQIgXm1maJRu6lyLFxp5XsO2BPqS0JXBGjITrOCTJR6SEVg="}]},"_npmUser":{"name":"benjskoog","email":"ben@aimdoc.ai"},"directories":{},"maintainers":[{"name":"benjskoog","email":"ben@aimdoc.ai"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/sdk_2.7.0_1787776551580_0.18969951414741715"},"_hasShrinkwrap":false}},"time":{"created":"2025-02-04T22:51:05.473Z","modified":"2026-08-26T20:35:51.907Z","1.0.0":"2025-02-04T22:51:05.730Z","1.0.1":"2025-02-06T22:42:14.468Z","1.0.2":"2025-02-06T22:47:41.097Z","1.0.3":"2025-02-11T05:31:59.121Z","2.0.0":"2026-03-02T00:44:20.164Z","2.0.1":"2026-03-02T05:11:29.032Z","2.0.2":"2026-03-02T17:37:31.811Z","2.0.3":"2026-06-09T03:54:53.540Z","2.3.0":"2026-08-06T18:33:34.725Z","2.4.0":"2026-08-11T04:14:37.326Z","2.6.0":"2026-08-25T14:37:10.648Z","2.7.0":"2026-08-26T20:35:51.733Z"},"license":"MIT","description":"Aimdoc SDK — chat widget helpers and the direct Services API client","maintainers":[{"name":"benjskoog","email":"ben@aimdoc.ai"}],"readme":"# Aimdoc SDK\n\nTyped helpers for interacting with an embedded Aimdoc agent.\n\nThe package also includes a direct, headless Services client. It talks to\nAimdoc's API from the host application—no Agent, iframe, or `postMessage`\ntransport is involved.\n\n## Services\n\nCreate a test or live publishable key in **Services → SDK**. The key is safe to\nship in frontend code: it selects an Aimdoc organization and environment but\ndoes not grant service access.\n\nFor a signed-in customer, your backend creates a fresh, one-time identity\nassertion using the same identity-verification secret used by `identify`:\n\n```ts\n// Server only — never expose AIMDOC_IDENTITY_SECRET in browser code.\nimport { createServicesIdentityAssertion } from '@aimdoc/sdk/server';\n\nexport async function getAimdocServicesIdentity(user: User) {\n  return createServicesIdentityAssertion({\n    publishableKey: process.env.NEXT_PUBLIC_AIMDOC_SERVICES_KEY!,\n    identitySecret: process.env.AIMDOC_IDENTITY_SECRET!,\n    contact: {\n      external_id: user.id,\n      email: user.email,\n      first_name: user.firstName,\n      account: user.account\n        ? { external_id: user.account.id, name: user.account.name }\n        : undefined,\n    },\n  });\n}\n```\n\nConfigure the browser client with a callback that fetches a fresh assertion.\nThe callback matters on long-lived pages because every assertion has a\nshort expiry and a one-time `jti`. Aimdoc exchanges it for a ten-minute,\norigin-bound session held only in memory.\n\n```ts\nimport { aimdoc } from '@aimdoc/sdk';\n\naimdoc.configureServices({\n  publishableKey: import.meta.env.VITE_AIMDOC_SERVICES_KEY,\n  getIdentityAssertion: async () => {\n    const response = await fetch('/api/aimdoc/services-identity', {\n      credentials: 'same-origin',\n    });\n    if (!response.ok) throw new Error('Could not identify Services user');\n    return response.text();\n  },\n});\n\nconst services = await aimdoc.services.list();\nconst details = await aimdoc.services.get(services[0].key);\nconst run = await aimdoc.services.invoke(details.key, { topic: 'Q3 plan' });\nconst latest = await aimdoc.services.getRun(run.id);\n\nif (details.allowed_actions.includes('request_access')) {\n  await aimdoc.services.requestAccess(details.key, 'Please enable this for our team.');\n}\n```\n\nAnonymous catalogs work by omitting the identity provider. They can reveal\nofferings whose discovery default permits it, but cannot invoke or request\naccess. CORS is scoped to `/sdk/v1`, uses no cookies, accepts valid HTTPS\norigins without domain registration, and permits HTTP localhost only outside\nproduction.\n\n### Automations\n\nA verified customer can schedule any service they are allowed to invoke and\nautomate. Access is re-resolved server-side on every call and again at every\nscheduled execution — never taken from the client:\n\n```ts\nconst automations = await aimdoc.services.listAutomations();\n\nconst automation = await aimdoc.services.createAutomation('weekly-account-report', {\n  schedule: { frequency: 'weekly', weekday: 0, at: '08:00' }, // Mondays 08:00\n  timezone: 'America/New_York',\n  inputBindings: { focus: 'usage' }, // fixed values, validated against the input schema\n});\n\nawait aimdoc.services.manageAutomation(automation.id, { action: 'pause' });\nawait aimdoc.services.manageAutomation(automation.id, {\n  schedule: { frequency: 'daily', at: '07:30' },\n});\nawait aimdoc.services.manageAutomation(automation.id, { action: 'cancel' });\n```\n\nSchedules are structured — `frequency` of `once` | `hourly` | `daily` |\n`weekly` | `monthly` with a wall-clock `at: 'HH:MM'`, plus `weekday` (0 =\nMonday) for weekly and `day_of_month` (1–28) for monthly. Cron strings are not\naccepted. Results are always saved to the customer's run history; subject\nautomations may additionally deliver to `email`. Pausing or cancelling always\nworks for the owner, while resuming and material updates require current\n`invoke` + `create_automation` access — a revoked customer keeps visibility\ninto their automation but cannot run it. Mutations send an `Idempotency-Key`\nautomatically; pass `{ idempotencyKey }` on `createAutomation` to make your\nown retries safe.\n\n## Compatibility promise\n\nThe message protocol between this SDK and the Aimdoc widget is additive-only:\nmessage types and fields are never removed or renamed. `identify` forwards the\npayload you pass verbatim, so new payload fields work even on older SDK\nversions — upgrading gets you the TypeScript types.\n\n## Identify\n\nUse `identify` to tell Aimdoc who the signed-in user is. Persistent fields\n(including `attributes`) are stored on the contact; use\n`setNextMessageContext` instead for transient, per-turn state.\n\n```ts\nimport { aimdoc } from '@aimdoc/sdk';\n\naimdoc.identify({\n  external_id: 'user_123',        // your app's stable user id\n  email: 'jane@acme.com',\n  first_name: 'Jane',\n  company: 'Acme',                // legacy contact-level company field\n  account: {\n    external_id: 'account_456',   // your app's stable account/tenant id\n    name: 'Acme',\n    domain: 'acme.com',            // optional; work-email domain is the fallback\n  },\n  attributes: { plan: 'enterprise', seats: 12 },\n  user_hash: accountAwareHashFromYourServer,\n});\n```\n\n`account.external_id` is required when `account` is present. `name` and\n`domain` are optional. An explicitly supplied name updates the account;\nomitted or empty fields do not clear existing data. The legacy top-level\n`company` field still updates the contact, but never names the account.\n\n### Identity verification (recommended)\n\nWithout verification, anyone can call `identify` with any email. To prove the\nidentification comes from your app, sign `\"{external_id}:{email}\"` — with the\nemail trimmed and lowercased — **on your server** with the\nidentity-verification secret from your Aimdoc dashboard\n(Integrations → Identity Verification) and pass the signature as `user_hash`.\nBoth values must match what you pass to `identify`; the email is part of the\nsigned message so a signature can never be replayed against someone else's\nemail.\n\n```ts\n// Server (Node.js) — never do this in the browser; the secret must stay server-side\nimport { createHmac } from 'crypto';\nconst userHash = createHmac('sha256', process.env.AIMDOC_IDENTITY_SECRET)\n  .update(`${user.id}:${user.email.trim().toLowerCase()}`)\n  .digest('hex');\n```\n\n```python\n# Server (Python)\nimport hashlib, hmac, os\nuser_hash = hmac.new(\n    os.environ[\"AIMDOC_IDENTITY_SECRET\"].encode(),\n    f\"{user_id}:{email.strip().lower()}\".encode(),\n    hashlib.sha256,\n).hexdigest()\n```\n\n```ts\n// Client — include the server-computed hash in identify\naimdoc.identify({\n  external_id: user.id,\n  email: user.email,\n  user_hash: userHashFromServer,\n});\n```\n\nA valid `user_hash` marks the identity as verified. An invalid one is always\nrejected. Once your traffic is signed, enable **enforce identity verification**\nin the dashboard to reject unsigned identify calls entirely.\n\n### Signing an identify with an account\n\nAccount fields affect shared account data, so an identify containing `account`\nalways requires identity verification, even when organization-wide enforcement\nis disabled. Sign this canonical v2 JSON object instead of the legacy message:\n\n```ts\n// Server (Node.js)\nimport { createHmac } from 'crypto';\n\nconst canonicalizeDomain = (value = '') => {\n  if (!value.trim()) return '';\n  const url = new URL(value.includes('://') ? value : `https://${value}`);\n  return url.hostname.toLowerCase().replace(/\\.+$/, '').replace(/^www\\./, '');\n};\n\nconst signedPayload = JSON.stringify({\n  account: {\n    domain: canonicalizeDomain(account.domain),\n    external_id: account.external_id.trim(),\n    name: (account.name || '').trim(),\n  },\n  email: user.email.trim().toLowerCase(),\n  external_id: user.id.trim(),\n  version: 2,\n});\n\nconst userHash = createHmac('sha256', process.env.AIMDOC_IDENTITY_SECRET)\n  .update(signedPayload)\n  .digest('hex');\n```\n\nThe key order shown above is part of the canonical representation. The hash\ncovers every account field, so changing the external ID, name, or domain\ninvalidates it.\n\n### Signing an account identify with a lifecycle stage (v3)\n\n`account.stage` lets your app assert the account's lifecycle stage (for\nexample `trial`, `customer`, or `churned` — any stage key configured in your\nAimdoc dashboard except `anonymous`). Because stage changes shared account\nstate, the claim must be covered by the signature: when `stage` is present,\n`stage` joins the `account` object (sorted key order: `domain`, `external_id`,\n`name`, `stage`) and `version` becomes `3`. Without `stage`, keep signing the\nv2 payload exactly as above — existing v2 integrations are unaffected.\n\n```ts\nconst signedPayload = JSON.stringify({\n  account: {\n    domain: canonicalizeDomain(account.domain),\n    external_id: account.external_id.trim(),\n    name: (account.name || '').trim(),\n    stage: account.stage.trim(),\n  },\n  email: user.email.trim().toLowerCase(),\n  external_id: user.id.trim(),\n  version: 3,\n});\n```\n\nAn unknown or unconfigured stage key is rejected with a `400` naming the\nvalid keys. Do not send an empty string — omit `stage` entirely when there is\nno claim.\n\n### Signing objective claims (v4)\n\nObjectives let your app sync journey progress when a user does something\nthemselves (for example completing onboarding, or starting a trial), keyed by\nthe objective keys defined on the agent this identify targets (the agent's\nObjectives tab in the Aimdoc dashboard). Claims are a map of\n`{ key: 'in_progress' | 'done' }` and can appear in two places:\n\n- `account.objectives` — account-level objectives;\n- top-level `objectives` — person-level objectives for the identified user.\n\nBecause objectives change shared journey state, **any identify carrying\nobjectives requires a signature**, even without an `account` object. When\nobjectives are present, they join the canonical payload where they appear and\n`version` becomes `4`:\n\n```ts\nconst signedPayload = JSON.stringify({\n  account: {\n    domain: canonicalizeDomain(account.domain),\n    external_id: account.external_id.trim(),\n    name: (account.name || '').trim(),\n    objectives: { trial_started: 'done' },  // sorted key order within the map\n    stage: account.stage.trim(),            // include only when claiming a stage\n  },\n  email: user.email.trim().toLowerCase(),\n  external_id: user.id.trim(),\n  objectives: { completed_onboarding: 'done' },  // person-level claims\n  version: 4,\n});\n```\n\nThe canonical representation is compact JSON with keys sorted alphabetically\nat every level (including inside the objectives maps — `JSON.stringify` does\nnot sort for you if your object keys are not already in order). Omit whichever\nobjectives map has no claims; for a person-only claim omit `account` entirely.\nWithout objectives, keep signing the v2/v3 payload as above — existing\nintegrations are unaffected.\n\nAn unknown objective key, a key claimed at the wrong level, or an invalid\nstatus is rejected with a `400`. A claim that violates the objective's policy\n(for example a stage-locked objective on an account that has not reached that\nstage) is also a `400` naming the reason. Objective statuses only move\n\"forward\" automatically; your signed claims may set any status, including\nregressing one — the AI can never override an explicit claim you send.\n\nThe canonical domain is the ASCII (IDNA/punycode) form of the hostname —\nNode's `URL` produces this automatically, as shown above. Domains that cannot\nbe IDNA-encoded (for example hostnames containing underscores) are rejected\nwith a `400 Account domain is invalid` before the signature is checked.\n\n## Next Message Context\n\nUse `setNextMessageContext` to provide host application context for the next message sent to the in-app agent:\n\n```ts\nimport { aimdoc } from '@aimdoc/sdk';\n\naimdoc.setNextMessageContext({\n  accountId: 'acct_123',\n  plan: 'enterprise',\n  currentWorkflow: 'Invite teammates',\n});\n```\n\nThe context is added to the agent's system prompt for one turn only. It is not stored as a visible chat message, and it is cleared after the next message payload is sent.\n\nIf a page hosts multiple agents, pass `agentId` to target one widget:\n\n```ts\naimdoc.setNextMessageContext(\n  { currentWorkflow: 'Invite teammates' },\n  { agentId: 'agent_123' }\n);\n```\n\n## Display Options\n\nUse `setDisplayOptions` to override the widget's display behavior for the current page view — for example, deciding per user segment whether the widget auto-opens:\n\n```ts\nimport { aimdoc } from '@aimdoc/sdk';\n\naimdoc.setDisplayOptions({ autoOpen: isExistingUser ? false : true });\n```\n\nOptions override the agent-level configuration from the Aimdoc dashboard and stay in effect until the page unloads. Call it as early as you like — options are applied retroactively as long as the auto-open timer hasn't fired yet, and repeated calls merge key-by-key with the latest value winning. `setDisplayOptions` never closes a chat that is already open, so an `autoOpen: false` arriving after the widget opened (or after the visitor opened it manually) is a no-op.\n\nTo move a corner-anchored widget away from overlapping page controls, provide\nan additional horizontal and/or vertical offset in pixels:\n\n```ts\naimdoc.setDisplayOptions({ cornerOffset: { x: 16, y: 80 } });\n```\n\nAvailable options:\n\n- `autoOpen` — `false` suppresses a configured auto-open; `true` enables auto-open even on an agent that has it disabled (using the agent's configured delay, or 3 seconds when it has none).\n- `autoOpenSeconds` — seconds before auto-open fires, overriding the agent's configured delay.\n- `openOncePerSession` — overrides the agent's \"only auto-open once per session\" setting. Note the once-per-session flag is only recorded when the widget actually opens, so a page that suppresses auto-open does not consume it.\n- `hidden` — `true` fully suppresses the widget for this page view; `false` does **not** override visibility rules configured in the dashboard, it only declines to hide.\n- `cornerOffset` — optional non-negative pixel offsets. `x` moves desktop corner-anchored surfaces inward from the configured left/right edge and `y` moves them upward from the bottom. Partial updates merge by axis. Mobile fullscreen layouts, centered copilot surfaces, expanded sidebars, and an operator position that the user has dragged are unchanged.\n- `collapsedMode` — `'chat'` (corner bubble) or `'copilot'` (centered input bar), overriding the agent's configured collapsed presentation. Ignored on mobile and on the in-app (operator) surface, which always uses its command-bar pill.\n- `expandedMode` — the layout the widget opens into: `'chat'` (corner chat window), `'sidebar'` (full-height panel that pushes the page content aside), or `'copilot'` (centered modal). Mobile always uses the fullscreen chat; the in-app (operator) surface supports `'chat'` and `'sidebar'` and **defaults to `'sidebar'`**. Takes effect immediately, including re-laying-out a chat that is already open — useful for giving specific routes (an onboarding page, say) a sidebar layout while the rest of the site keeps the corner widget.\n\n### Sidebar layout and `position: fixed` elements\n\nThe sidebar pushes page content aside by padding the document element, which reflows normal-flow (and `position: sticky`) layouts correctly. Elements that size against the viewport — `position: fixed` headers/buttons, `100vw`-wide sections — don't respond to that padding and would sit underneath the sidebar. The widget provides hooks to adapt them:\n\n- CSS variable `--aimdoc-sidebar-width` on `<html>` (`400px` open, `0px` closed):\n\n  ```css\n  .my-fixed-header {\n    padding-right: var(--aimdoc-sidebar-width, 0px);\n    transition: padding-right 300ms ease-out;\n  }\n  ```\n\n- `aimdoc:sidebar` window event with `{ open, width, position }` in `detail`, for JS-driven layouts.\n- A synthetic window `resize` event fires once the slide animation settles, so container-measuring components (charts, editors) re-measure automatically.\n\nIf a page hosts multiple agents, pass `agentId` to target one widget:\n\n```ts\naimdoc.setDisplayOptions({ autoOpen: false }, { agentId: 'agent_123' });\n```\n\nIf you embed the widget with the static script snippet instead of the npm SDK, the same options can be passed at initialization:\n\n```js\nwindow.aimdoc.initAgentChat('ai-assistant', {\n  agentId: 'agent_123',\n  displayOptions: {\n    autoOpen: false,\n    cornerOffset: { x: 16, y: 80 },\n  },\n});\n```\n","readmeFilename":"README.md"}