{"_id":"@axis-social/sdk","_rev":"3-27ab2ffe4960e8b8a1b777c3100413ec","name":"@axis-social/sdk","dist-tags":{"latest":"0.1.2"},"versions":{"0.1.0":{"name":"@axis-social/sdk","version":"0.1.0","keywords":["axis","social","instagram","facebook","messaging","inbox","sdk"],"author":{"name":"Wilson Kinyua","email":"wilsonkinyuam@gmail.com"},"license":"MIT","_id":"@axis-social/sdk@0.1.0","maintainers":[{"name":"wilsonkinyua","email":"wilsonkinyuam@gmail.com"}],"homepage":"https://github.com/wilsonkinyua/axis-social#readme","bugs":{"url":"https://github.com/wilsonkinyua/axis-social/issues"},"dist":{"shasum":"49a5aa76ee883962602517603d4a9596db2a1b6b","tarball":"https://registry.npmjs.org/@axis-social/sdk/-/sdk-0.1.0.tgz","fileCount":10,"integrity":"sha512-pFXjhXg/Rf0gdYzeE3yXwDdagMbwnLF1Nn2Ygsmj4KO/IVrVAOB9KAlYFFBB4pbXLL62rcPkOWahKDSM56HI2w==","signatures":[{"sig":"MEYCIQCFJ8M4n+DgDFjWo2H/Jb2FGpEz5KyNbDldfjetgIO3lgIhAKLk3H2czmv1JYhv4O2n5GS0ycmE7/MctCjyiEWqEcTC","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":57809},"main":"dist/index.js","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"c32e61c840754e2c77727398b90848365572edc3","scripts":{"lint":"tsc -p tsconfig.json --noEmit","build":"tsc -p tsconfig.json","prepublishOnly":"yarn build"},"_npmUser":{"name":"wilsonkinyua","email":"wilsonkinyuam@gmail.com"},"repository":{"url":"git+https://github.com/wilsonkinyua/axis-social.git","type":"git","directory":"packages/sdk"},"_npmVersion":"11.12.1","description":"Axis Social SDK — typed client with Bearer auth, automatic idempotency keys, retries, and a webhook signature verifier","directories":{},"_nodeVersion":"24.15.0","dependencies":{"@axis-social/types":"^0.1.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/sdk_0.1.0_1781674603900_0.7666371785697543","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@axis-social/sdk","version":"0.1.1","keywords":["axis","social","instagram","facebook","messaging","inbox","sdk"],"author":{"name":"Wilson Kinyua","email":"wilsonkinyuam@gmail.com"},"license":"MIT","_id":"@axis-social/sdk@0.1.1","maintainers":[{"name":"wilsonkinyua","email":"wilsonkinyuam@gmail.com"}],"homepage":"https://github.com/wilsonkinyua/axis-social#readme","bugs":{"url":"https://github.com/wilsonkinyua/axis-social/issues"},"dist":{"shasum":"c212c020c6349a68e11477d56019d82cbcb5da0b","tarball":"https://registry.npmjs.org/@axis-social/sdk/-/sdk-0.1.1.tgz","fileCount":10,"integrity":"sha512-gm9V8ePDvwRdBoDnW2jSWEnteJjZQjXJXL0LLtxePJOjKJkF8CYr7AX0hue000WKgrPsDBwKJ0BOpCv+4Dcmtg==","signatures":[{"sig":"MEUCIQCosgUrk/lZFWlkjsekeNIjyer4VkR7+ubPO/A9mLBUvQIgOxafpnxku3igQtd+Xdi7PXWHt53DtP40UPLQtPvl7y4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":57682},"main":"dist/index.js","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"c32e61c840754e2c77727398b90848365572edc3","scripts":{"lint":"tsc -p tsconfig.json --noEmit","build":"tsc -p tsconfig.json","prepublishOnly":"yarn build"},"_npmUser":{"name":"wilsonkinyua","email":"wilsonkinyuam@gmail.com"},"repository":{"url":"git+https://github.com/wilsonkinyua/axis-social.git","type":"git","directory":"packages/sdk"},"_npmVersion":"11.12.1","description":"Axis Social SDK — typed client with Bearer auth, automatic idempotency keys, retries, and a webhook signature verifier","directories":{},"_nodeVersion":"24.15.0","dependencies":{"@axis-social/types":"^0.1.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/sdk_0.1.1_1781675089835_0.7376923034332974","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@axis-social/sdk","version":"0.1.2","description":"Axis Social SDK — typed client with Bearer auth, automatic idempotency keys, retries, and a webhook signature verifier","license":"MIT","keywords":["axis","social","instagram","facebook","messaging","inbox","sdk"],"author":{"name":"Wilson Kinyua","email":"wilsonkinyuam@gmail.com"},"repository":{"type":"git","url":"git+https://github.com/wilsonkinyua/axis-social.git","directory":"packages/sdk"},"main":"dist/index.js","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"publishConfig":{"access":"public"},"scripts":{"build":"tsc -p tsconfig.json","lint":"tsc -p tsconfig.json --noEmit","prepublishOnly":"yarn build"},"dependencies":{"@axis-social/types":"^0.1.0"},"gitHead":"c32e61c840754e2c77727398b90848365572edc3","_id":"@axis-social/sdk@0.1.2","bugs":{"url":"https://github.com/wilsonkinyua/axis-social/issues"},"homepage":"https://github.com/wilsonkinyua/axis-social#readme","_nodeVersion":"24.15.0","_npmVersion":"11.12.1","dist":{"integrity":"sha512-/VTvNl3vHp2CtmwefNrAtgHhFAIB6A9uQsDYbyvSgfOCIt/7vcBSuQMKl1eVrBd9UPtlWmCgeXTDQ64xQ7ClKA==","shasum":"42914fb0ab44b4c71c161baa581d815cd9cd1916","tarball":"https://registry.npmjs.org/@axis-social/sdk/-/sdk-0.1.2.tgz","fileCount":10,"unpackedSize":57396,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIH9UfkDbslL5azuMtcmZnL0cyjjqJ4fgLL6AQNFke6KpAiEAuSKvI0tUv/0bTTzFJVHKJC5dOm8bS5Iqx42K3IEIqLk="}]},"_npmUser":{"name":"wilsonkinyua","email":"wilsonkinyuam@gmail.com"},"directories":{},"maintainers":[{"name":"wilsonkinyua","email":"wilsonkinyuam@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/sdk_0.1.2_1781675418825_0.9390712834553065"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-17T05:36:43.727Z","modified":"2026-06-17T05:50:19.095Z","0.1.0":"2026-06-17T05:36:44.053Z","0.1.1":"2026-06-17T05:44:49.989Z","0.1.2":"2026-06-17T05:50:18.954Z"},"bugs":{"url":"https://github.com/wilsonkinyua/axis-social/issues"},"author":{"name":"Wilson Kinyua","email":"wilsonkinyuam@gmail.com"},"license":"MIT","homepage":"https://github.com/wilsonkinyua/axis-social#readme","keywords":["axis","social","instagram","facebook","messaging","inbox","sdk"],"repository":{"type":"git","url":"git+https://github.com/wilsonkinyua/axis-social.git","directory":"packages/sdk"},"description":"Axis Social SDK — typed client with Bearer auth, automatic idempotency keys, retries, and a webhook signature verifier","maintainers":[{"name":"wilsonkinyua","email":"wilsonkinyuam@gmail.com"}],"readme":"# @axis-social/sdk\n\nTyped TypeScript client for the Axis Social API — one class that wraps every endpoint (connections, publishing, inbox, outbound webhooks, realtime) with Bearer auth, automatic idempotency keys, retry-on-`429`/`5xx`, and a webhook signature verifier.\n\n---\n\n## 1. Install\n\n```bash\nyarn add @axis-social/sdk\n# or\nnpm install @axis-social/sdk\n```\n\nRequires Node 18+ (or any runtime with a global `fetch` and `crypto.randomUUID`).\n\n---\n\n## 2. The mental model\n\nEverything in Axis Social hangs off three nouns. Knowing how they relate keeps you from guessing at IDs later.\n\n```\nApp key (axs_…)  ──auth──►  Tenant  ──owns──►  Connection (a connected IG/FB/… account)\n                                                    │\n                                  ┌─────────────────┼──────────────────┐\n                                  ▼                 ▼                  ▼\n                              Post (publish)   InboxThread       InboxAccount\n                                                (DMs / comments)  (per-connection settings)\n```\n\n- **App key** — `axs_{env}_{keyId}.{secret}`. Identifies _which_ integration app is calling. Sent as a `Bearer` token. The SDK validates the shape locally and refuses to construct if it's malformed.\n- **Tenant** — the identity everything is scoped to, sent on **every** request as `x-axis-tenant`. It **MUST be the Axis Accounts (SSO) user id, namespaced as `ws_<axisAuthId>`** — derived from the logged-in session the same way in every Axis app. The SSO id is the only identifier shared across Axis apps, so using it as the tenant is what lets a connection made in one app (e.g. Engage) appear in another (Social) with no reconnect. **Do NOT** pass a local per-app workspace/DB id — those differ per app and fragment the same user across apps. The server auto-provisions the internal tenant on first use, so a new `ws_<axisAuthId>` value works immediately. One app key serves many tenants; you fix the tenant when you build the client.\n- **Connection** — one connected social account (an Instagram account, a Facebook Page, …), identified by a `ConnectionDto.id`. You get one by running the **connect flow** (§4). Almost everything downstream — posting, inbox threads, account settings — is keyed by `connectionId`.\n\n> **Auth is Bearer-only.** Despite the historical package description mentioning HMAC request signing, the client authenticates requests purely with the `Bearer` app key plus the `x-axis-tenant` header. HMAC only appears in **one** place: verifying _inbound_ outbound-webhook deliveries (§7). Don't sign your own requests.\n\n---\n\n## 3. Construct the client\n\n```ts\nimport { AxisSocial, AxisSocialError } from '@axis-social/sdk';\n\nconst axis = new AxisSocial({\n  baseUrl: 'https://api.myaxis.ai', // no trailing slash needed — it's trimmed for you\n  appKey: process.env.AXIS_APP_KEY!, // axs_{env}_{keyId}.{secret}\n  tenant: `ws_${axisAuthId}`, // Axis Accounts (SSO) user id, namespaced ws_<axisAuthId> — same in every Axis app\n  // optional:\n  // fetch:      customFetch,            // defaults to global fetch (auto-bound)\n  // maxRetries: 3,                      // 429/5xx retries before giving up (default 3)\n});\n\n// Smoke-test credentials:\nawait axis.ping(); // -> { ok: true }\nawait axis.whoami(); // -> identity the key/tenant resolve to\n```\n\nEvery method returns a `Promise` of the **unwrapped** payload — the SDK strips the `{ data }` envelope for you. List endpoints that paginate return `{ data, meta }` instead (see §6).\n\n### How errors surface\n\nAny non-2xx response throws an `AxisSocialError` (never a bare `fetch` rejection for HTTP errors):\n\n```ts\ntry {\n  await axis.posts.create({\n    targets: [\n      /* … */\n    ],\n  });\n} catch (e) {\n  if (e instanceof AxisSocialError) {\n    e.status; // HTTP status, e.g. 409\n    e.code; // machine code, e.g. \"missing_capability\"\n    e.message; // human-readable\n    e.details; // structured hints, e.g. { connectIntegrationKey: \"meta\" }\n    e.body; // full parsed error envelope\n  }\n}\n```\n\n`e.details.connectIntegrationKey` is the actionable one: when a write fails because the connection lacks a capability, it tells you which integration to connect to gain it.\n\n---\n\n## 4. Connect a social account (the OAuth-style flow)\n\nYou can't post or read an inbox until a tenant has a **connection**. Connecting is a two-step redirect dance — `start` hands you a URL to send the user to, the provider redirects back, and `complete` finalizes it.\n\n```ts\n// Step 1 — begin. `network` is the platform: \"instagram\" | \"facebook\" | …\nconst startRes = await axis.connections.start('instagram', {\n  redirectUrl: 'https://app.example.com/connections/callback', // where the provider returns the user\n  // integration: \"aggregator\",  // default; pick a specific integration if you support more than one\n});\n\n// startRes.kind tells you how to proceed:\n//   \"redirect\"        -> send the browser to startRes.redirectUrl\n//   \"qr\"              -> render startRes.qr for the user to scan\n//   \"embeddedSignup\"  -> launch the provider's embedded signup widget\nwindow.location.href = startRes.redirectUrl!;\n\n// Step 2 — after the provider redirects back to your redirectUrl, finalize:\nconst connection = await axis.connections.complete('instagram', {\n  // accountId / network / provider params arrive on your callback query string — forward them here\n});\nconnection.id; // <- the connectionId you'll use everywhere downstream\nconnection.connected; // true\nconnection.bindings; // the surfaces (feed, story, dm, comments…) this account can act on\n```\n\n### Inspecting, switching, and the non-destructive lifecycle\n\n```ts\nawait axis.connections.list(); // every connection for this tenant\nawait axis.connections.capabilities('instagram'); // what a network *could* do once connected\n\n// Disconnect WITHOUT losing history. Tears down the upstream account (stops vendor billing,\n// fully disconnects on Meta) but KEEPS the connection record and all saved DMs/comments.\nawait axis.connections.disconnect(connection.id);\n\n// Reconnect re-authorizes the retained account and reuses its stored history.\n// Returns a redirect to follow, exactly like start(). Pass redirectUrl for a one-call connect.\nconst re = await axis.connections.reconnect(connection.id, {\n  redirectUrl: 'https://app.example.com/connections/callback',\n});\n\n// Move an existing connection to a different integration without re-running the full connect:\nawait axis.connections.switchIntegration(connection.id, {\n  integration: 'meta',\n});\n```\n\n> **Disconnect is non-destructive by design.** There is no \"delete connection\" in this SDK. Disconnect → reconnect preserves the thread/entry history end-to-end.\n\n---\n\n## 5. Publish a post\n\nA post fans out to one or more **targets**. Each target names a `connectionId` and a `surface` (e.g. `\"feed\"`, `\"story\"`) — the surfaces available come from the connection's `bindings`.\n\n```ts\nconst post = await axis.posts.create({\n  content: 'Launch day. 🚀',\n  media: [{ url: 'https://cdn.example.com/hero.jpg', type: 'image' }],\n  targets: [\n    { connectionId: connection.id, surface: 'feed' },\n    { connectionId: connection.id, surface: 'story' },\n  ],\n  // scheduledFor: \"2026-07-01T09:00:00Z\",  // omit to publish now\n});\n\npost.id;\npost.status; // \"scheduled\" | \"publishing\" | \"published\" | \"failed\" | …\npost.results; // per-surface outcome\npost.externalIds; // provider-side ids once published, keyed by surface\n\n// Lifecycle:\nawait axis.posts.get(post.id);\nawait axis.posts.update(post.id, { content: 'Edited copy' }); // before it publishes\nawait axis.posts.retry(post.id); // re-attempt a failed post\nawait axis.posts.delete(post.id);\n\n// Poll several posts at once (e.g. a feed of cards):\nawait axis.posts.liveStatus([post.id, 'post_2', 'post_3']);\n```\n\nWrites are **idempotent automatically** — see §8. To dedupe a user double-clicking \"Publish\", pass your own key:\n\n```ts\nawait axis.posts.create(input, { idempotencyKey: `publish:${draftId}` });\n```\n\n---\n\n## 6. Read and work the inbox\n\nThe inbox unifies **DMs** and **comments** into `threads`. A thread holds `entries` (individual messages or comments). Comment threads nest one level of replies.\n\n### List threads (cursor-paginated)\n\nThis is the one family that returns the `{ data, meta }` envelope, because you page through it:\n\n```ts\nlet cursor: string | undefined;\ndo {\n  const page = await axis.inbox.threads.list({\n    type: 'dm', // \"dm\" | \"comment\"\n    status: 'open',\n    unreadOnly: true,\n    connectionId: connection.id,\n    limit: 50, // default 25, max 100\n    cursor, // omit on the first call\n  });\n\n  for (const thread of page.data) {\n    thread.unreadCount;\n    thread.previewText;\n    thread.lastInboundAt; // provider event time, not ingest time\n  }\n\n  cursor = page.meta.nextCursor; // undefined when you've reached the end\n} while (cursor);\n```\n\n> **Times are provider times.** Entries expose `platformCreatedAt` (when the user actually sent it) alongside `createdAt` (when Axis ingested it). Ordering and `lastInboundAt` use the provider time, so backfilled history shows real send times. Sort/display on `platformCreatedAt ?? createdAt`.\n\n### Read one thread and reply\n\n```ts\nconst thread = await axis.inbox.threads.get(threadId); // includes participants + entries\n\nconst entry = await axis.inbox.threads.reply(threadId, {\n  message: 'Thanks for reaching out!',\n  // attachmentUrl / attachmentType  — to send media\n  // parentEntryId                   — to reply under a specific comment\n});\n\nawait axis.inbox.threads.setStatus(threadId, { status: 'closed' });\n```\n\n### Moderate comments\n\n`action()` is the general verb; the named helpers are thin wrappers over it. `entryId` is the comment **entry's** `id`.\n\n```ts\nawait axis.inbox.threads.hide(threadId, entryId);\nawait axis.inbox.threads.unhide(threadId, entryId);\nawait axis.inbox.threads.like(threadId, entryId);\nawait axis.inbox.threads.unlike(threadId, entryId);\nawait axis.inbox.threads.deleteComment(threadId, entryId);\n\n// Reply to a public comment privately, as a DM to its author:\nawait axis.inbox.threads.privateReply(\n  threadId,\n  entryId,\n  'DMing you the details!',\n);\n\n// Equivalent low-level form:\nawait axis.inbox.threads.action(threadId, { action: 'hide', entryId });\n```\n\n### Per-account inbox settings\n\n```ts\nawait axis.inbox.accounts.list();\nawait axis.inbox.accounts.updateSettings(connection.id, {\n  isEnabled: true,\n  config: { aiMode: 'suggest', syncEnabled: true }, // stored verbatim — the service never acts on these\n});\n```\n\n`config` is a free-form bag the service persists but never interprets. Use it to stash your own per-connection flags.\n\n---\n\n## 7. Receive events via outbound webhooks\n\nInstead of polling, register an HTTPS endpoint and Axis will POST events to it (new DM, new comment, post status change, …).\n\n### Register an endpoint\n\n```ts\nconst ep = await axis.webhooks.register(\n  'https://app.example.com/hooks/axis',\n  ['message.received', 'comment.received'], // omit the array to subscribe to ALL events\n);\nep.secret; // ⚠️ returned EXACTLY ONCE — store it now; list() never returns it again\n\nawait axis.webhooks.list(); // endpoints (without secrets)\nawait axis.webhooks.delete(ep.id);\n```\n\n### Verify and handle a delivery\n\nEvery delivery carries a signature header. **Verify it before trusting the body.** The SDK ships the exact verifier:\n\n```ts\nimport { verifyWebhookSignature } from '@axis-social/sdk';\n\n// Express-style handler. You MUST have the raw, unparsed request body.\napp.post('/hooks/axis', express.raw({ type: '*/*' }), (req, res) => {\n  const rawBody = req.body.toString('utf8');\n  const timestamp = req.header('x-axis-timestamp')!;\n  const signature = req.header('x-axis-signature')!; // \"sha256=<hex>\"\n\n  const ok = verifyWebhookSignature({\n    secret: process.env.AXIS_WEBHOOK_SECRET!, // the secret from register()\n    rawBody,\n    timestamp,\n    signature,\n  });\n  if (!ok) return res.status(401).end();\n\n  const event = JSON.parse(rawBody); // { type, …payload }\n  switch (event.type) {\n    case 'message.received':\n      /* … */ break;\n    case 'comment.received':\n      /* … */ break;\n  }\n  res.status(200).end();\n});\n```\n\nThe signature is `sha256=` + HMAC-SHA256 of `` `${timestamp}.${rawBody}` `` using your endpoint secret. Other headers on each delivery: `x-axis-event` (the event type) and `x-axis-delivery` (a unique delivery id, useful for your own dedupe/logging).\n\n### Browser realtime (alternative to webhooks)\n\nFor live UI, mint a short-lived token instead of exposing the app key to the browser:\n\n```ts\nconst { token, wsUrl, expiresIn } = await axis.realtime.token();\n// open a WebSocket to wsUrl with `token` — the tenant is embedded in it.\n```\n\n---\n\n## 8. Cross-cutting behavior (how the client treats every call)\n\n- **Idempotency.** Every write (`POST`/`PATCH`/`DELETE`) sends an `Idempotency-Key`. If you don't pass one, the SDK generates a UUID per logical write and **keeps it stable across retries**, so a retried request never double-applies. Pass your own (`{ idempotencyKey }`) to dedupe across separate calls — e.g. a user clicking a button twice.\n- **Retries.** `429` and `5xx` responses retry up to `maxRetries` (default 3). `429` honors the `Retry-After` header; otherwise backoff is `min(2^attempt, 8)` seconds. The idempotency key is reused on every retry, so retries are safe.\n- **Envelope unwrapping.** `request()`-based methods return `data` directly; paginated `list()` methods return `{ data, meta }`.\n- **Abort.** Pass `{ signal }` (an `AbortSignal`) to any call to cancel it.\n- **Headers, automatically:** `Authorization: Bearer <appKey>`, `x-axis-tenant: <tenant>`, `Idempotency-Key` (writes), `content-type: application/json` (when there's a body).\n\n---\n\n## 9. Invariants & gotchas\n\nThe rules that bite if you get them wrong:\n\n1. **Never construct or sign requests by hand.** Use the `AxisSocial` instance. Auth is Bearer-only; the SDK adds every required header.\n2. **`tenant` MUST be `ws_<axisAuthId>`** — the Axis Accounts (SSO) user id, never a local per-app workspace/DB id. Using anything else fragments the user's data across Axis apps.\n3. **`connectionId` is the spine.** To post, read inbox, or change settings, you first need a connection from `connections.list()` or the connect flow. Don't fabricate one.\n4. **Don't delete connections.** Use `disconnect` → `reconnect`; history is preserved deliberately.\n5. **Read provider time, not ingest time** when ordering or displaying messages: `platformCreatedAt ?? createdAt`.\n6. **The webhook secret is shown once.** When you write `register()` code, also write the code that persists `ep.secret`.\n7. **Catch `AxisSocialError`** and branch on `.code` / `.details.connectIntegrationKey`, not on string-matching `.message`.\n8. **Pagination is cursor-based.** Loop on `meta.nextCursor` until it's `undefined`; never assume offset/limit.\n\n---\n\n## 10. Reference\n\n### Client surface\n\n| Group            | Method                                                                   | HTTP                                               | Returns                                |\n| ---------------- | ------------------------------------------------------------------------ | -------------------------------------------------- | -------------------------------------- |\n| `connections`    | `list()`                                                                 | `GET /v1/connections`                              | `ConnectionDto[]`                      |\n|                  | `capabilities(network?)`                                                 | `GET /v1/integrations/capabilities`                | `CapabilitiesResponse`                 |\n|                  | `start(network, body?, opts?)`                                           | `POST /v1/connections/{network}/start`             | `StartConnectResponse`                 |\n|                  | `complete(network, body?, opts?)`                                        | `POST /v1/connections/{network}/complete`          | `ConnectionDto`                        |\n|                  | `reconnect(id, body?, opts?)`                                            | `POST /v1/connections/{id}/reconnect`              | `StartConnectResponse`                 |\n|                  | `disconnect(id, opts?)`                                                  | `POST /v1/connections/{id}/disconnect`             | `ConnectionDto`                        |\n|                  | `switchIntegration(id, body, opts?)`                                     | `POST /v1/connections/{id}/switch-integration`     | `ConnectionDto`                        |\n| `posts`          | `create(input, opts?)`                                                   | `POST /v1/posts`                                   | `PostDto`                              |\n|                  | `list(query?)`                                                           | `GET /v1/posts`                                    | `PagedResponse<PostDto>`               |\n|                  | `get(id)`                                                                | `GET /v1/posts/{id}`                               | `PostDto`                              |\n|                  | `update(id, patch, opts?)`                                               | `PATCH /v1/posts/{id}`                             | `PostDto`                              |\n|                  | `retry(id, opts?)`                                                       | `POST /v1/posts/{id}/retry`                        | `PostDto`                              |\n|                  | `delete(id, opts?)`                                                      | `DELETE /v1/posts/{id}`                            | —                                      |\n|                  | `liveStatus(ids)`                                                        | `GET /v1/posts/live-status`                        | `LiveStatusResponse`                   |\n| `inbox.threads`  | `list(query?)`                                                           | `GET /v1/inbox/threads`                            | `PagedResponse<InboxThreadDto>`        |\n|                  | `get(id)`                                                                | `GET /v1/inbox/threads/{id}`                       | `InboxThreadDto`                       |\n|                  | `reply(id, body, opts?)`                                                 | `POST /v1/inbox/threads/{id}/reply`                | `InboxEntryDto`                        |\n|                  | `action(id, body, opts?)`                                                | `POST /v1/inbox/threads/{id}/actions`              | —                                      |\n|                  | `setStatus(id, body, opts?)`                                             | `POST /v1/inbox/threads/{id}/status`               | —                                      |\n|                  | `hide` / `unhide` / `like` / `unlike` / `deleteComment` / `privateReply` | `POST …/actions`                                   | —                                      |\n| `inbox.accounts` | `list()`                                                                 | `GET /v1/inbox/accounts`                           | `InboxAccountDto[]`                    |\n|                  | `updateSettings(connectionId, settings, opts?)`                          | `PATCH /v1/inbox/accounts/{connectionId}/settings` | `InboxAccountDto`                      |\n| `webhooks`       | `register(url, events?, opts?)`                                          | `POST /v1/webhooks`                                | `{ id, url, events, enabled, secret }` |\n|                  | `list()`                                                                 | `GET /v1/webhooks`                                 | endpoints (no secret)                  |\n|                  | `delete(id, opts?)`                                                      | `DELETE /v1/webhooks/{id}`                         | —                                      |\n| `realtime`       | `token()`                                                                | `POST /v1/realtime/tokens`                         | `{ token, expiresIn, wsUrl }`          |\n| `admin`          | `releaseNativeClaim(network, externalAccountId, opts?)`                  | `POST /v1/admin/native-claims/release`             | `{ released, previousOwnerTenantId? }` |\n|                  | `webhookInbox.list(status?)`                                             | `GET /v1/admin/webhook-inbox`                      | inbound deliveries                     |\n|                  | `webhookInbox.requeue(id, opts?)`                                        | `POST /v1/admin/webhook-inbox/{id}/requeue`        | —                                      |\n| —                | `ping()`                                                                 | `GET /v1/ping`                                     | `{ ok: true }`                         |\n| —                | `whoami()`                                                               | `GET /v1/whoami`                                   | identity                               |\n\n> `admin.*` requires the `admin` scope on the app key.\n\n### Webhook event types\n\n`message.received` · `comment.received` · `thread.reply` · `post.status` · `account.updated` (plus any future string types — handle the `default` case).\n\n### Headers the SDK sends / expects\n\n| Header                           | Direction        | Purpose                                      |\n| -------------------------------- | ---------------- | -------------------------------------------- |\n| `Authorization: Bearer <appKey>` | request          | Auth                                         |\n| `x-axis-tenant`                  | request          | Tenant scope                                 |\n| `Idempotency-Key`                | request (writes) | Safe retries / dedupe                        |\n| `Retry-After`                    | response         | Backoff hint on `429`                        |\n| `x-axis-signature`               | inbound webhook  | `sha256=<hmac>` over `{timestamp}.{rawBody}` |\n| `x-axis-timestamp`               | inbound webhook  | Signed timestamp                             |\n| `x-axis-event`                   | inbound webhook  | Event type                                   |\n| `x-axis-delivery`                | inbound webhook  | Unique delivery id                           |\n\n### Exports\n\n```ts\nimport {\n  AxisSocial, // the client\n  AxisSocialError, // thrown on non-2xx\n  verifyWebhookSignature, // inbound-webhook verifier\n} from '@axis-social/sdk';\nimport type {\n  AxisSocialOptions,\n  RequestOptions,\n  AxisErrorBody,\n  AxisErrorCode,\n  Scope,\n  QueryParams,\n} from '@axis-social/sdk';\n```\n\nAll request/response DTOs (`ConnectionDto`, `PostDto`, `InboxThreadDto`, …) are re-exported from `@axis-social/types`.\n","readmeFilename":"README.md"}