dunsocial-sdk
v0.3.0
Published
TypeScript SDK for the DunSocial REST API — schedule, publish, upload media, and verify webhooks.
Maintainers
Readme
dunsocial-sdk
TypeScript client for the DunSocial REST API. Schedule and publish posts, upload media, search brand memory, and verify webhook signatures.
import { DunSocial } from 'dunsocial-sdk';
const dun = new DunSocial({
token: process.env.DUN_TOKEN,
workspaceId: process.env.DUN_WORKSPACE_ID
});
await dun.posts.schedule({
content: 'Shipping the TypeScript SDK.',
socialAccountIds: ['acc_x'],
scheduledAt: new Date(Date.now() + 60 * 60 * 1000)
});Requires Node 20+, Bun, or Cloudflare Workers. The package uses fetch and Web Crypto only.
Install
npm install dunsocial-sdk
# bun add dunsocial-sdk
# pnpm add dunsocial-sdkCreate a personal access token in the app under Settings → CLI. Format: dun_pat_….
export DUN_TOKEN=dun_pat_…
export DUN_WORKSPACE_ID=your_workspace_idConstructor options override env. Names match the CLI: DUN_TOKEN, DUN_WORKSPACE_ID, DUN_API_URL.
Auth
Every request sends Authorization: Bearer <token> and User-Agent: dunsocial-sdk/<version>. Workspace-scoped methods also send X-Workspace-Id.
| Method | Scope |
|--------|--------|
| workspaces.list / get | workspace:read |
| accounts.list | workspace:read |
| personalization.get | workspace:read |
| personalization.set / clear | workspace:write |
| posts.list / get / validate | posts:read |
| drafts.list / get | posts:read |
| posts.schedule / reschedule / cancel / threads | posts:schedule |
| posts.publish / publishThread | posts:publish |
| posts.delete | posts:delete |
| drafts.create / update / delete | drafts:write |
| media.list / get | media:read |
| media.upload / delete | media:write |
| memory GET (collections / list) | memory:read |
| memory.search / save / collection writes | memory:write |
workspaces.list works without a workspace id. A PAT bound to one workspace still lists that workspace.
Posts
const [post] = await dun.posts.publish({
content: 'Live now.',
socialAccountIds: ['acc_x'],
mediaIds: ['media_1']
});
const published = await dun.posts.wait(post.id);publish queues the row (status: scheduled). wait(id) polls until published, failed, or cancelled.
validate is HTTP 200 even when the post is invalid:
const result = await dun.posts.validate({
content: 'Hello Reddit',
socialAccountIds: ['acc_reddit'],
metadata: { reddit: { subreddit: 'startups', title: 'Hello', kind: 'self' } }
});
// result.valid === false → result.issues[]Pass throwOnInvalid: true if you want a DunSocialError instead.
Reddit schedule/publish requires metadata.reddit (subreddit, title, kind). Call posts.validate() first. reschedule() accepts optional metadata; omit it so the API keeps the existing reddit options.
mediaIds in the SDK map to API mediaUrls. scheduledAt accepts a Date or ISO string.
Media
const asset = await dun.media.upload({
file: new Uint8Array(await Bun.file('cover.png').arrayBuffer()),
filename: 'cover.png',
mimeType: 'image/png'
});upload() hides the three-step flow: request a signed URL, PUT the bytes, complete the gallery row. Images max 8MB; video max 16GB (X Premium / Premium+ Post-video ceiling). Schedule and publish re-check the connected X account: default 20 min / 8 GB; Premium and Premium+ 125 min / 16 GB.
Webhooks
import { DunSocial } from 'dunsocial-sdk';
export async function POST(request: Request) {
const rawBody = await request.text();
const event = await DunSocial.webhooks.constructEvent(
rawBody,
{
signature: request.headers.get('X-DunSocial-Signature') ?? '',
timestamp: request.headers.get('X-DunSocial-Timestamp') ?? ''
},
process.env.DUN_WEBHOOK_SECRET!
);
// event.type: post.published | post.publish_failed | …
}HMAC-SHA256 of {timestamp}.{rawBody}. Use the raw body; the default replay window is 300 seconds.
Errors
import { DunSocial, DunSocialError } from 'dunsocial-sdk';
try {
await dun.posts.schedule({ /* … */ });
} catch (err) {
if (err instanceof DunSocialError && err.code === 'subscription_required') {
console.log(err.billingUrl);
}
}| Code | HTTP | Retry? |
|------|------|--------|
| missing_config | — | no |
| unauthorized | 401 | no |
| forbidden | 403 | no |
| not_found | 404 | no |
| subscription_required | 402 | no — see billingUrl |
| rate_limited | 429 | yes (Retry-After) |
| x_cap_exceeded | 429 | no |
| timeout / network | 5xx / abort | 5xx once |
CLI vs SDK vs MCP
| Surface | Use when |
|---------|----------|
| SDK (dunsocial-sdk) | Your app or backend talks to DunSocial in TypeScript |
| CLI (dunsocial / dun) | Terminal, CI, local agents |
| MCP | Claude, ChatGPT, Cursor call tools in chat |
| REST | Any other language — OpenAPI |
The SDK does not wrap the CLI. Both call the same HTTP API.
OpenAPI
- File: sdks/openapi/openapi.yaml
- Live: https://api.dunsocial.com/api/openapi.json
- Docs: https://www.dunsocial.com/docs/sdk
License
MIT
