# DunSocial Docs
> How to plan, write, schedule and publish social posts with DunSocial — from the app, the REST API, the CLI, or an AI assistant over MCP.
# Welcome
Source: https://www.dunsocial.com/docs
DunSocial is one place to write, schedule, and publish your social media posts. These docs explain every part of the app in plain language.
Use the **App / API / CLI / MCP** tabs in the sidebar to switch sections. You are in the App guide.
## Start here
## Popular topics
---
# Notification preferences
Source: https://www.dunsocial.com/docs/account-and-settings/notification-preferences
Control which emails you get from DunSocial. Open **Settings**, then **Notifications**.
### Post notifications
Turn these on or off as you like:
- **When published successfully**: an email when a post goes out. (On by default.)
- **When failed to publish**: an email if a post fails. (On by default.)
- **When scheduled**: an email when you schedule a post. (On by default.)
- **When rescheduled**: an email when a scheduled post is moved. (Off by default.)
- **One hour before publishing**: a reminder before a post goes out. (Off by default.)
- **When a draft is about to be deleted**: a warning before a draft auto-deletes. (Off by default.)
### Account emails
At the account level you can also control:
- **Activation emails**: important messages about getting set up and using your account.
- **Marketing emails**: product news and tips.
### Tip
If you only want the essentials, keep failure and publish emails on and turn the rest off.
---
# Profile settings
Source: https://www.dunsocial.com/docs/account-and-settings/profile-settings
Your profile holds your personal details in DunSocial.
### Steps
1. Open **Settings**, then **Profile**.
2. Update your details, such as your name.
3. Save your changes.
### Good to know
- Your profile is personal to you and carries across every workspace you belong to.
- Workspace details, like the workspace name and timezone, are set separately under Settings, then Workspace.
- For email preferences, see "Notification preferences".
---
# Reconnect an account
Source: https://www.dunsocial.com/docs/account-and-settings/reconnect-an-account
Sometimes a social account disconnects, usually because the platform expired its access. Reconnecting fixes it.
### When to reconnect
- An account shows as disconnected or needs attention.
- A post failed because DunSocial could not reach the account.
### Steps
1. Open **Settings → accounts**, or go to **Connect** at `/{workspace}/connect`.
2. Find the account that needs attention.
3. Click **Reconnect** (or Connect).
4. Log in to that platform again and approve access.
5. The account goes back to connected.
### Good to know
- DunSocial refreshes most accounts automatically in the background, so this does not happen often.
- Only owners and admins can connect or reconnect accounts.
- After reconnecting, your scheduled posts for that account can go out as normal.
---
# Themes and appearance
Source: https://www.dunsocial.com/docs/account-and-settings/themes-and-appearance
Pick how DunSocial looks.
### Steps
1. Open **Settings**, then **Themes**.
2. Choose a theme:
- **System**: matches your device setting.
- **Light**: a bright look.
- **Dark**: a darker look.
3. Your choice applies right away.
### Good to know
- **System** follows your computer or phone, switching automatically between light and dark.
- Your theme choice is remembered for next time.
---
# API
Source: https://www.dunsocial.com/docs/api
The DunSocial API lets your app, script, or integration talk to the same workspace you use in the dashboard. Schedule posts, manage drafts and media, search memory, and more.
## Start here
## Browse by area
---
# Chat and generate
Source: https://www.dunsocial.com/docs/api/ai
AI routes need a **session** bearer (PATs cannot call AI). Most also need **`X-Workspace-Id`**. Extra rate limit: about **20 requests per minute**.
### Chat (streaming)
`POST /api/ai/chat`
Returns a streaming UI message response. History is auto-saved for the workspace.
### Generate for a platform
`POST /api/ai/generate/:type`
`:type` is one of: `x-tweet`, `x-thread`, `linkedin`, `bluesky`, `threads`, `youtube-shorts`, `reddit`.
Body: most types need `{ "topic": "..." }`. LinkedIn needs `{ "content": "..." }` (source text to rewrite). Optional fields include `subreddit`, `count`.
Response: `{ type, items: [{ id, text }] }`.
### Transcribe audio
`POST /api/ai/transcribe` — **Bearer only** (no workspace header).
Send either:
- JSON `{ audioBase64, filename?, mimeType?, language? }`, or
- multipart form with `audio` / `file`
Returns `{ transcript, metadata }`. **503** if speech-to-text is not configured. **413** if the file is too large.
### Daily ideas
Needs enough memory in the workspace (about **5+** memories).
| Method | Path |
|--------|------|
| `GET` | `/api/ai/daily-ideas?count=` |
| `GET` | `/api/ai/daily-ideas/all` |
| `GET` | `/api/ai/daily-ideas/eligibility` → `{ hasEnough }` |
### Chat history
| Method | Path |
|--------|------|
| `GET` | `/api/ai/history?limit=&offset=` |
| `POST` | `/api/ai/history` — `{ title, messages, sessionId? }` |
| `POST` | `/api/ai/history/auto-save` |
| `GET` / `PATCH` / `DELETE` | `/api/ai/history/:id` |
### Extract facts and grounding
| Method | Path | Notes |
|--------|------|-------|
| `POST` | `/api/ai/extract-facts/text` | `{ text }` |
| `POST` | `/api/ai/extract-facts/url` | `{ urls[], additionalText? }` — daily quota |
| `POST` | `/api/ai/grounding/url-analysis` | `{ urls[], question }` |
| `POST` | `/api/ai/grounding/google-search` | `{ query }` |
| `POST` | `/api/ai/generate-voice-preset` | `{ description }` |
| `POST` | `/api/documents/extract-facts/pdf` | `{ fileBase64, filename }` — needs Bearer + `X-Workspace-Id` |
| `POST` | `/api/documents/extract-facts/text` | docx / txt / md — needs Bearer + `X-Workspace-Id` |
### Feedback
`POST /api/feedback` with `{ content, pageRoute, userAgent? }`. Optional `X-Workspace-Id`.
---
# Drafts
Source: https://www.dunsocial.com/docs/api/drafts
Drafts are per user inside a workspace. They auto-expire after about **14 days**. Needs **Bearer** + **`X-Workspace-Id`**.
### List drafts
`GET /api/drafts?limit=&offset=`
### Create a draft
`POST /api/drafts`
Useful fields: `content`, `platformContent`, `socialAccountIds`, `selectedPlatforms`, `name`, `mediaUrls`, `platformMedia`.
For Pinterest drafts, set `selectedPlatforms: ["pinterest"]` and optional Pinterest options.
Returns **201**.
### Get, update, delete
| Method | Path | Notes |
|--------|------|-------|
| `GET` | `/api/drafts/:id` | — |
| `PATCH` | `/api/drafts/:id` | Body must include `id` (same as the path) plus fields to update |
| `DELETE` | `/api/drafts/:id` | — |
### Clear all drafts
`DELETE /api/drafts` → `{ deletedCount }` for the current user in that workspace.
### Remove a media key from drafts
`POST /api/drafts/remove-media` with `{ "storageKey": "..." }` → `{ updatedCount }`.
---
# Authentication
Source: https://www.dunsocial.com/docs/api/getting-started/authentication
Every authenticated request sends a bearer token:
```
Authorization: Bearer
```
You can use a **session token** from sign-in, or a **personal access token** (PAT) created for CI and scripts.
### Session token (humans and apps)
Sign in with email and password through Better Auth:
Use the returned token on later requests. Sign out with `POST /api/auth/sign-out`. Check the current session with `GET /api/auth/get-session`.
Email verification is required for new accounts. Sessions last about 30 days.
### Personal access tokens (CI and agents)
PATs are best for automation. Create one while signed in (Settings → CLI in the app, or the API):
The response includes the raw token **once**. Store it like a password. Format: `dun_pat__`.
PATs are bound to a single workspace. Send that workspace in `X-Workspace-Id`. A mismatch returns **403**.
#### Available scopes
| Scope | What it allows |
|-------|----------------|
| `workspace:read` | Read workspace and members |
| `posts:read` | List and get posts |
| `posts:schedule` | Schedule posts and threads |
| `posts:publish` | Publish now |
| `posts:delete` | Cancel or delete posts |
| `drafts:write` | Create, update, delete drafts |
| `media:read` / `media:write` | Gallery and uploads |
| `memory:read` / `memory:write` | Memories and collections |
Use `scopes: ["*"]` for all scopes. Empty scopes fall back to a small CI default set.
PATs cannot call AI, webhooks management, notifications, billing, or CLI token management. Those need a session.
### Workspace header
Most content routes need a workspace:
You must be an active member. Suspended members get **403**.
### Device login (CLI)
The CLI uses a device-code flow (`POST /api/cli/auth/start` and `poll`). That is covered in the [CLI install guide](/docs/cli/getting-started/install-and-sign-in). The result is still a normal session bearer token.
### List and revoke PATs
| Method | Path | Notes |
|--------|------|-------|
| `GET` | `/api/cli/tokens` | Metadata only (no secrets) |
| `DELETE` | `/api/cli/tokens/:id` | Revoke |
### Connecting MCP assistants
Assistants connect with **OAuth** — paste `https://api.dunsocial.com/api/mcp` and approve in the browser. See the [MCP guide](/docs/mcp) for setup and connection management.
---
# Errors and rate limits
Source: https://www.dunsocial.com/docs/api/getting-started/errors-and-rate-limits
When something goes wrong, the API returns a JSON body and an HTTP status code.
### Error shape
Some service errors also include a `message` field. Prefer reading `error` first.
### Status codes
| Status | Meaning |
|--------|---------|
| **400** | Bad input or a business rule failed (validation, wrong status) |
| **401** | Missing or invalid bearer token |
| **403** | Authenticated, but not allowed (role, scope, suspended, wrong workspace) |
| **404** | Resource not found or not visible to you |
| **409** | Conflict (for example workspace slug already taken) |
| **413** | Body too large (for example audio for transcription) |
| **429** | Rate limited, or X monthly posting cap reached |
| **500** | Unexpected server error |
| **503** | A dependency is not configured (for example speech-to-text) |
### Rate limits
| Scope | Limit |
|-------|--------|
| General `/api/*` | About **100 requests per minute** per authenticated user, or client IP |
| Auth (`/api/auth/*`) | About **20 requests per 15 minutes** per client IP |
| CLI device login (`/api/cli/auth/*`) | About **30 requests per 15 minutes** per client IP |
| AI routes (`/api/ai/*`) | About **20 requests per minute** |
When limited, expect **429** and `X-RateLimit-*` headers. Back off and retry.
### Platform caps
Scheduling or publishing to X can return **429** when the workspace hits its monthly X posting cap. Check usage with `GET /api/posts/x-cap-usage` before a large batch. Dry-run character limits and required platform metadata with `POST /api/posts/validate` (HTTP 200 + `{ valid, issues[] }`, no writes).
### Tips
- Retry **429** and occasional **500** with exponential backoff.
- Do not retry **401** or **403** without fixing auth or permissions.
- For validation failures, the `error` string usually names the field or rule.
---
# Overview
Source: https://www.dunsocial.com/docs/api/getting-started/overview
The DunSocial API is a REST API. You send JSON over HTTPS and get JSON back. Most routes need a signed-in user and a workspace.
### Base URL
```
https://api.dunsocial.com
```
All paths in these docs are relative to that host. Example: `GET /api/user/profile` means `https://api.dunsocial.com/api/user/profile`.
### What you can build
- Schedule and publish posts from your own app or script
- Manage drafts, media, and brand memory
- Connect social accounts and list members
- Receive events with webhooks when posts publish or fail
For TypeScript apps, use the [SDK](/docs/sdk). For terminal and CI workflows, use the [CLI](/docs/cli). For chat assistants, use [MCP](/docs/mcp).
The PAT-safe OpenAPI contract is at `https://api.dunsocial.com/api/openapi.json`.
### Common headers
| Header | When | Notes |
|--------|------|-------|
| `Authorization` | Almost every route | `Bearer ` — session or personal access token |
| `Content-Type` | JSON bodies | `application/json` |
| `X-Workspace-Id` | Workspace-scoped routes | Must be a workspace you belong to |
Some routes also accept a workspace id in the path (`/api/workspaces/:id/...`) or as `?workspaceId=`. Prefer `X-Workspace-Id` for consistency.
### Response shape
Successful responses usually look like this:
List endpoints often paginate:
### Quick example
Sign in, then list workspaces:
Next: [Authentication](/docs/api/getting-started/authentication).
---
# Upload and gallery
Source: https://www.dunsocial.com/docs/api/media
Media lives in the workspace gallery. Needs **Bearer** + **`X-Workspace-Id`**.
### Limits
| Kind | Max size | Types |
|------|----------|-------|
| Images | **8MB** | jpeg, png, gif, webp |
| Video | **512MB** | mp4, quicktime, webm |
### Upload flow
1. Ask for a presigned URL
2. Upload bytes to that URL
3. Confirm the upload so it appears in the gallery
#### 1. Get an upload URL
`POST /api/media/upload-url`
Response: `{ uploadUrl, storageKey, expiresAt }`.
#### 2. PUT the file
`PUT` the raw file to `uploadUrl` with the correct `Content-Type`.
#### 3. Complete
`POST /api/media/complete`
Body: `{ storageKey, originalFilename, mimeType, fileSize, width?, height?, duration?, altText? }`
`duration` is stored as **milliseconds**. Values under 1000 are treated as seconds (MCP/API clients) and converted on write.
Returns **201** with the asset and a `previewUrl`.
### List gallery
| Method | Path | Notes |
|--------|------|-------|
| `GET` | `/api/media` | Paginated assets + preview URLs |
| `GET` | `/api/media/gallery` | Assets with usage status |
### Get and batch
| Method | Path |
|--------|------|
| `GET` | `/api/media/:id` |
| `POST` | `/api/media/batch` — `{ ids? , storageKeys? }` |
| `GET` | `/api/media/:id/relationships` — posts/drafts using it + `canDelete` |
### Alt text
`PATCH /api/media/:id/alt-text` with `{ "altText": "..." }`
### Validate for a platform
`GET /api/media/validate?mediaAssetId=&platform=` → `{ valid, issues[] }`
### Delete
`DELETE /api/media/:id`
Optional body: `{ cleanupDrafts?, forceDeleteScheduled? }`
Fails with **400** if the asset is used in a published post (or scheduled without `forceDeleteScheduled`).
---
# Memories and collections
Source: https://www.dunsocial.com/docs/api/memory
Memory powers AI that knows your voice and facts. Needs **Bearer** + **`X-Workspace-Id`**.
### Collections
Collections group memories. Listing lazy-creates default **Personal** and **Workspace** collections if needed.
| Method | Path | Body |
|--------|------|------|
| `GET` | `/api/memory/collections` | — |
| `POST` | `/api/memory/collections` | `{ name, color?, isPrivate? }` |
| `GET` | `/api/memory/collections/:id` | — |
| `PATCH` | `/api/memory/collections/:id` | `{ name?, color?, isPrivate? }` |
| `DELETE` | `/api/memory/collections/:id` | — |
You can only edit or delete collections you created. Default collections cannot change visibility or be deleted (**400** / **403**).
### Save memories
`POST /api/memory`
Batch: `POST /api/memory/batch` with `{ texts: string[], collectionId }` → `{ success, count }`.
### List memories
`GET /api/memory?collectionId=COLLECTION_ID&limit=`
`collectionId` is required (**400** if missing).
### Semantic search
`POST /api/memory/search`
Returns matches with `text`, `score`, and `collectionId`.
### Update or delete
| Method | Path | Body |
|--------|------|------|
| `PATCH` | `/api/memory/:id` | `{ collectionId, memoryId, text }` |
| `DELETE` | `/api/memory/:id` | `{ collectionId, memoryId }` |
Both need the collection id in the body so permissions can be checked.
---
# Notification devices
Source: https://www.dunsocial.com/docs/api/notifications
Notification routes need a **session** bearer. Register devices with [`POST /api/user/devices`](/docs/api/user-and-devices/devices-and-account).
### Status
`GET /api/notifications/status`
Returns `{ configured, deviceCount }`.
### List devices
`GET /api/notifications/devices`
### Remove a device by id
`DELETE /api/notifications/devices/:id`
### Send a test push
`POST /api/notifications/test`
Body: `{ title?, body?, deviceId? }`
Returns **503** if Firebase is not configured. Useful while building a mobile client.
---
# Manage posts
Source: https://www.dunsocial.com/docs/api/posts/manage-posts
All routes need **Bearer** + **`X-Workspace-Id`**.
### List posts
`GET /api/posts`
Query params: `status`, `socialAccountId`, `groupId`, `limit`, `offset`
Each item includes **`mediaUrls`** (media asset ids, same field as `GET /api/posts/:id`). You do not need to fetch every post to reconcile which assets a batch uses.
### Get one post
`GET /api/posts/:id` — **404** if missing or outside the workspace. Same post fields as list, plus you can resolve asset ids to preview URLs via the media API.
### Update a post
`PATCH /api/posts/:id`
Only drafts and scheduled posts can be edited. Body may include `content`, `metadata`, `mediaUrls`, `scheduledAt`, and statuses `draft` / `scheduled` / `cancelled`. The body `id` must match the path. DunSocial sets `published` / `failed` automatically; you cannot set them through this endpoint.
### Reschedule
`POST /api/posts/:id/reschedule`
Body: `{ "content", "scheduledAt", "metadata"?, "mediaUrls"? }`
Works for `scheduled` or `failed` posts.
### Cancel
`POST /api/posts/:id/cancel` — only when status is `scheduled`.
### Bulk cancel
`POST /api/posts/bulk-cancel` with `{ "ids": ["...", "..."] }` → `{ cancelledCount }`.
### Delete
`DELETE /api/posts/:id` — removes the post, cancels any pending schedule job, and refunds X monthly cap usage when a scheduled X post is deleted.
### Helpers
| Method | Path | Notes |
|--------|------|-------|
| `POST` | `/api/posts/validate` | Dry-run schedule checks (no writes). See [Schedule and publish](/docs/api/posts/schedule-and-publish). |
| `GET` | `/api/posts/scheduled-count?socialAccountId=` | Count of scheduled posts |
| `GET` | `/api/posts/x-cap-usage` | X monthly usage |
| `POST` | `/api/posts` | Low-level create (prefer schedule / publish-now) |
| `POST` | `/api/posts/:id/status` | Client status helper (`draft` / `scheduled` / `cancelled` only) |
---
# Schedule and publish
Source: https://www.dunsocial.com/docs/api/posts/schedule-and-publish
Post routes need **Bearer** auth and **`X-Workspace-Id`**.
### Schedule a post
`POST /api/posts/schedule`
Returns **201** with one post per social account. Validation is **all-or-nothing**: a character-limit or platform-metadata error creates **zero** posts. After validation passes, each account is inserted and queued. If QStash fails mid-batch, earlier accounts in that `groupId` may already be `scheduled`.
### Validate without writing
`POST /api/posts/validate`
Same body as schedule / publish-now, without `scheduledAt`. Runs the same media, character-limit, per-platform metadata, and X monthly-cap checks. **Does not** create posts or queue jobs.
Returns **200**:
`valid: true` and an empty `issues` array means the same payload can be sent to schedule or publish-now.
### Publish now
`POST /api/posts/publish-now`
Same body as schedule, without `scheduledAt`. Optional `naturalPosting` boolean.
### Threads (X only)
| Method | Path |
|--------|------|
| `POST` | `/api/posts/schedule-thread` |
| `POST` | `/api/posts/publish-thread-now` |
Body shape:
Threads need **2–25** tweets. Response includes `threadHeadPost`, `totalTweets`, and `postIds`.
### Required per-platform metadata
When `socialAccountIds` includes that platform, the matching `metadata` block is **required**. There is no default Instagram `format` (do not assume `reel`).
| Platform | Required field | Required keys | Notes |
|----------|----------------|---------------|-------|
| Reddit | `metadata.reddit` | `subreddit`, `title`, `kind` | `kind`: `self`, `link`, `image`, or `video`. Flair when the subreddit requires it. |
| Instagram | `metadata.instagram` | `format` | `format`: `feed_image`, `carousel`, `reel`, or `story`. Optional `caption` (max 2200, at most 5 hashtags). Feed/carousel/story images: JPEG, PNG, GIF, or WebP (non-JPEG converts at publish). |
| Pinterest | `metadata.pinterest` | `boardId`, `title`, `description` | Exactly **one** image. |
| TikTok | `metadata.tiktok` | `privacyLevel` | Exactly **one** video. Optional `title` (max 2200). |
| Discord | `metadata.discord` | `channelId` | Text or announcement channel from the connected server. Optional `channelName`. Up to 10 attachments; total request max 25 MB. |
| Slack | `metadata.slack` | `channelId` | Public or private channel from the connected Slack team. Optional `channelName`. Up to 10 attachments; 50 MB per file. |
X, LinkedIn, Bluesky, Threads, YouTube, and Facebook Pages do not need a metadata block for a text/media post. Facebook Pages are text, one link, and photos only (no video).
### Character limits (on `content`)
| Platform | Limit |
|----------|-------|
| X | **280**, or **25,000** when the connected account is X Premium |
| Bluesky | 300 |
| Threads | 500 |
| LinkedIn | 3,000 |
| Instagram | 2,200 (caption in `metadata.instagram` is also capped at 2,200) |
| TikTok | 2,200 |
| Facebook Pages | **63,206** (images only; no `metadata.facebook`) |
| Pinterest | 800 (`metadata.pinterest.description` also 800; title 100) |
| YouTube | 5,000 description (title 100, handled separately) |
| Reddit | 40,000 (`metadata.reddit.title` max 300) |
| Discord | 2,000 |
| Slack | 4,000 |
### Media on a post
`mediaUrls` can be media asset ids, `https://media.dunsocial.com/...` URLs, or storage keys like `media/uploads/...`. Stored and returned posts keep **asset ids** in `mediaUrls`.
### Common errors
| Status | Cause |
|--------|-------|
| **400** | Character limits, missing/invalid platform options, bad media |
| **404** | Media asset missing |
| **429** | X monthly posting cap |
Check cap usage: `GET /api/posts/x-cap-usage`. Dry-run the same checks with `POST /api/posts/validate`.
---
# List and connect
Source: https://www.dunsocial.com/docs/api/social-accounts
Social account routes need **Bearer** + **`X-Workspace-Id`**. List responses never include OAuth access tokens.
### List accounts
`GET /api/social-accounts`
Also available as `GET /api/workspaces/:id/social-accounts`.
Each item includes id, provider, username / display name, avatar, expiry, and safe metadata.
### Disconnect
`DELETE /api/social-accounts/:id`
Admins and owners only. Members get **403**.
### Start OAuth
`GET /api/social-accounts/oauth/:provider`
Providers: `x`, `linkedin`, `linkedin-business`, `threads`, `youtube`, `pinterest`, `instagram`, `reddit`, `tiktok`, `facebook`. Facebook Pages are limited beta — connect the Page in the DunSocial app (OAuth starts there, same as every other provider).
Returns `{ redirect }` with the provider authorize URL. Pass `?redirect=1` to receive an HTTP 302 instead. Admins and owners only.
Pinterest alias: `GET /api/social-accounts/oauth/pinterest/start`.
Reddit eligibility helper (permissions only): `GET /api/social-accounts/oauth/reddit/eligibility`.
OAuth **callbacks** are browser redirects handled by DunSocial. You do not call them from your integration.
### Bluesky (app password)
`POST /api/social-accounts/connect/bluesky`
Returns `{ socialAccountId, profile }`.
Helpers: `GET /api/social-accounts/bluesky/profile`, `POST .../bluesky/profile/refresh` with `{ "socialAccountId": "..." }`.
### Composer helpers
Useful read-only helpers while composing:
| Path | Purpose |
|------|---------|
| `GET .../pinterest/boards` | Boards for a Pinterest account |
| `POST .../pinterest/boards` | Create a board (`name`, optional `privacy`: `PUBLIC` or `SECRET`). Default is public. |
| `GET .../reddit/flair-options?subreddit=` | Flair options |
| `GET .../reddit/post-requirements` | Subreddit rules summary |
| `GET .../x/heatmap` | Best-time heatmap data |
Prefer `/api/posts/*` for publishing rather than any platform-specific publish shortcuts.
---
# Devices and account
Source: https://www.dunsocial.com/docs/api/user-and-devices/devices-and-account
### Register a push device
`POST /api/user/devices`
`platform` is `"ios"` or `"android"`.
Unregister with `DELETE /api/user/devices/:token` (URL-encode the FCM token).
For listing devices and notification status, see [Notifications](/docs/api/notifications).
### Account deletion plan
Before deleting an account, check impact:
`GET /api/user/account/deletion-plan`
Returns owned shared workspaces, solo workspaces, memberships, whether you can delete now, and a blocked reason if not.
### Delete account
`DELETE /api/user/account`
Permanently deletes your account. **Blocked** while you own any workspace that still has other members — transfer ownership or close those workspaces first.
Solo-owned workspaces are closed as part of the flow.
---
# Profile
Source: https://www.dunsocial.com/docs/api/user-and-devices/profile
User routes sit under `/api/user`. They need a bearer token. They do **not** need `X-Workspace-Id` unless noted.
### Get your profile
`GET /api/user/profile`
Returns the current user record (id, name, email, image, and related fields).
### Update your profile
`PATCH /api/user/profile`
Body: `{ "name"?: string, "image"?: string }`
### Profile image upload
1. `POST /api/user/profile/image/upload-url` with `{ filename, contentType, size }`
2. `PUT` the file bytes to the returned `uploadUrl`
3. `PATCH /api/user/profile` with the storage key or image URL as needed
Limits: jpeg, png, gif, or webp · max **5MB**.
Remove the image with `DELETE /api/user/profile/image`.
### Email
| Method | Path | Notes |
|--------|------|-------|
| `GET` | `/api/user/email-availability?email=` | `{ available }` |
| `PATCH` | `/api/user/email` | `{ email, otp }` — requires verified change-email OTP; **400** if taken/invalid |
### Default workspace
| Method | Path | Body / query |
|--------|------|----------------|
| `GET` | `/api/user/default-workspace` | — |
| `PATCH` | `/api/user/default-workspace` | `{ workspaceId: string \| null }` |
You must be a member of the workspace you set. Otherwise **403**.
### Email preferences
`GET` / `PATCH /api/user/email-preferences` — activation and marketing email toggles.
---
# Manage endpoints
Source: https://www.dunsocial.com/docs/api/webhooks
Webhooks notify your systems when posts schedule, publish, or fail. Workspace **owners and admins** need a **session** bearer (PATs cannot manage webhooks) and **`X-Workspace-Id`**. Max **10** endpoints per workspace.
For a product overview, see the [App webhooks guide](/docs/webhooks/webhooks).
### Event catalog
`GET /api/webhooks/events`
Event types:
- `post.scheduled`
- `post.rescheduled`
- `post.cancelled`
- `post.published`
- `post.publish_failed`
- `social_account.reconnect_required`
### Create an endpoint
`POST /api/webhooks`
Returns **201** with the endpoint and a plain **`secret` once**. Store it and verify signatures on your side.
### Verify signatures
Every delivery includes:
| Header | Value |
|--------|-------|
| `X-DunSocial-Signature` | `v1=` + hex HMAC-SHA256 of `{timestamp}.{rawBody}` using the endpoint secret |
| `X-DunSocial-Timestamp` | Unix seconds used in the signed string |
| `X-DunSocial-Event-Id` | Stable event id |
| `X-DunSocial-Delivery-Id` | This delivery attempt id |
Verify by recomputing HMAC-SHA256 of the string `{timestamp}.{rawBody}` with the endpoint secret, then comparing the hex digest to the value after `v1=`. Reject if the signature mismatches, or if the timestamp is too far from your clock (replay window). Use the **raw request body** string — re-serializing JSON can change bytes and fail verification.
### List, get, update, delete
| Method | Path | Notes |
|--------|------|-------|
| `GET` | `/api/webhooks` | Secrets masked |
| `GET` | `/api/webhooks/:id` | — |
| `PATCH` | `/api/webhooks/:id` | name / url / events / enabled |
| `DELETE` | `/api/webhooks/:id` | Soft-delete |
### Secrets
| Method | Path |
|--------|------|
| `POST` | `/api/webhooks/:id/rotate-secret` — new secret once |
Secrets are returned only when an endpoint is created or rotated. Store the value securely; the current secret cannot be revealed later.
### Test and deliveries
`POST /api/webhooks/:id/test` — sends a test delivery.
`GET /api/webhooks/:id/deliveries?status=&eventType=&limit=&offset=` — paginated delivery log.
---
# Members and invites
Source: https://www.dunsocial.com/docs/api/workspaces-and-team/members-and-invites
Team routes live under `/api/workspaces/:id/team/*`. Send `Authorization` and be a member of that workspace.
### List members
`GET /api/workspaces/:id/members`
`GET /api/workspaces/:id/team/members`
### Your role
`GET /api/workspaces/:id/team/role` → `"owner" | "admin" | "member"`
### Team stats
`GET /api/workspaces/:id/team/stats` — member counts, seat limit, and whether you can invite.
### Invite someone
`POST /api/workspaces/:id/team/invitations`
`role` is `"admin"` or `"member"`. Seat limits and existing memberships return **400**. Only admins and owners can invite (**403** otherwise).
| Method | Path | Notes |
|--------|------|-------|
| `GET` | `.../team/invitations` | Pending invites (empty if you are not admin/owner) |
| `POST` | `.../team/invitations/resend` | `{ email, role }` |
| `DELETE` | `.../team/invitations/:invitationId` | Cancel |
### Accept or reject an invite
These use only the bearer token (no workspace header):
| Method | Path |
|--------|------|
| `POST` | `/api/workspaces/invitations/:invitationId/accept` |
| `POST` | `/api/workspaces/invitations/:invitationId/reject` |
Wrong email → **403**. Expired invite → **400**.
### Manage members
| Method | Path | Who |
|--------|------|-----|
| `DELETE` | `.../team/members/:memberId` | Admin/owner (with role rules) |
| `POST` | `.../team/members/:memberId/suspend` | Admin/owner |
| `POST` | `.../team/members/:memberId/unsuspend` | Admin/owner |
| `PATCH` | `.../team/members/:memberId/role` | Owner only — `{ role: "admin" \| "member" }` |
---
# Workspaces
Source: https://www.dunsocial.com/docs/api/workspaces-and-team/workspaces
Workspaces group your social accounts, posts, media, and team. Most content routes need `X-Workspace-Id` set to one of these ids.
### List workspaces
`GET /api/workspaces`
Returns each workspace with your role.
### Create a workspace
`POST /api/workspaces`
Body: `{ "name": "Acme", "slug"?: "acme", "timezone"?: "America/New_York" }`
Returns **201**. Explicit slug conflicts return **409**.
Check a slug first: `GET /api/workspaces/slug-availability?slug=acme`
### Get a workspace
`GET /api/workspaces/:id`
Requires membership. Includes role and a short subscription summary.
### Update a workspace
`PATCH /api/workspaces/:id`
Body: `{ "name"?, "timezone"?, "logo"? }`
Members with role `member` cannot update (**403**). Owners and admins can.
### Profile and logo
| Method | Path | Notes |
|--------|------|-------|
| `PATCH` | `/api/workspaces/:id/profile` | `{ name, slug, logo? }` — slug conflicts return **409** |
| `POST` | `/api/workspaces/:id/logo/upload-url` | Presigned upload |
| `DELETE` | `/api/workspaces/:id/logo` | Clear logo |
### AI voice settings
| Method | Path |
|--------|------|
| `GET` / `PATCH` | `/api/workspaces/:id/ai-voice-settings` |
| `GET` / `POST` | `/api/workspaces/:id/ai-voice-presets` |
| `PATCH` / `DELETE` | `/api/workspaces/:id/ai-voice-presets/:presetId` |
Members cannot change voice settings.
### Notification preferences
`GET` / `PATCH /api/workspaces/:id/notification-preferences`
### Social accounts on a workspace
`GET /api/workspaces/:id/social-accounts` — sanitized list (no OAuth tokens). Same data as [Social accounts](/docs/api/social-accounts).
### Close or transfer (owner only)
| Method | Path | Body |
|--------|------|------|
| `GET` | `/api/workspaces/:id/close-impact` | — |
| `POST` | `/api/workspaces/:id/close` | `{ confirmName }` must match the workspace name |
| `POST` | `/api/workspaces/:id/transfer-ownership` | `{ newOwnerUserId }` |
Closing permanently removes the workspace and its data. Transfer first if others should keep access.
---
# Add or remove seats
Source: https://www.dunsocial.com/docs/billing/add-or-remove-seats
A seat is one team member. Adjust your seat count as your team changes.
### Add seats
1. Open **Billing**.
2. Increase your seat count.
3. Confirm.
You can now invite more members from **Settings**, then **Team**.
### Remove seats
1. Open **Billing**.
2. Decrease your seat count.
3. Confirm.
A seat reduction may be scheduled to take effect at the end of your current billing period, so you keep what you paid for until then.
### Good to know
- You cannot have fewer seats than the number of members in the workspace. Remove members first if needed.
- Only owners and admins can change seats.
- Adding seats usually takes effect right away so you can invite people immediately.
---
# Billing FAQ
Source: https://www.dunsocial.com/docs/billing/billing-faq
### How does pricing work?
DunSocial bills per seat. You pay for the number of team members in your workspace.
### Can I have different plans for different workspaces?
Yes. Each workspace has its own plan and billing.
### Who can manage billing?
Only owners and admins.
### What happens when I add a seat?
Adding a seat usually takes effect right away, so you can invite a new member immediately.
### What happens when I remove a seat?
A seat reduction may be scheduled for the end of your current billing period. You keep the seat until then.
### How are payments handled?
Payments for new checkouts are processed through Polar. Older workspaces may still bill through Stripe.
### What do I need before I can post?
An active plan and at least one connected social account.
### How do I cancel?
Open **Billing** and cancel your subscription there. Your access continues until the end of the current period.
---
# Manage your subscription
Source: https://www.dunsocial.com/docs/billing/manage-your-subscription
You manage your plan from the **Billing** area.
### What you can see
- Your current plan and price.
- Your billing interval.
- Your number of seats.
- When your current period ends.
- Your subscription status.
### What you can do
- Update your payment method.
- Change your plan or billing interval.
- Add or remove seats.
- Cancel your subscription.
### Steps
1. Open **Billing**.
2. Review your plan details.
3. Make your change and confirm.
### Good to know
- Billing for new checkouts runs through Polar. Some older workspaces still bill through Stripe.
- Only owners and admins can manage billing.
- Each workspace has its own subscription, so changes only affect the workspace you are in.
---
# Plans and seats
Source: https://www.dunsocial.com/docs/billing/plans-and-seats
DunSocial bills per seat. A seat is one team member in your workspace.
### How it works
- Each workspace has its own plan.
- You pay for the number of seats you need.
- Add seats as your team grows, and remove them when it shrinks.
- You can usually choose a billing interval, such as monthly.
### Set up your plan
1. Open **Billing**.
2. Choose a plan and the number of seats.
3. Enter your payment details.
4. Confirm.
Your workspace becomes active and you can start posting.
### Good to know
- You need an active plan and at least one connected account to publish.
- Billing for new checkouts runs through Polar. Some older workspaces still bill through Stripe.
- Only owners and admins can manage billing.
- See "Add or remove seats" to change how many people can join.
---
# CLI
Source: https://www.dunsocial.com/docs/cli
The DunSocial CLI lets you work with your workspace from a terminal. Install the `dunsocial` package from npm, then use the `dun` command on your laptop, with a coding agent, or in CI.
## Start here
## Browse by area
---
# Agent skills
Source: https://www.dunsocial.com/docs/cli/ci-and-agents/agent-skills
The npm package ships a short skill file that teaches local coding agents how to authenticate, pick a workspace, and schedule posts. Remote chat hosts (ChatGPT / Claude in the browser) should keep using [MCP](/docs/mcp) instead.
### List targets
`list` shows every supported agent and the install path under your home directory. `path` prints the bundled skill file inside the package.
### Install
Supported targets include: `claude`, `codex`, `cursor`, `pi`, `opencode`, `agents`, `copilot`, `windsurf`, `goose`, `gemini`, `amp`, `grok`, `continue`, `antigravity`.
### Where skills land
| Target | Path |
|--------|------|
| `claude` | `~/.claude/skills/dunsocial/` |
| `codex` | `~/.codex/skills/dunsocial/` (+ pointer in `~/.codex/AGENTS.md`) |
| `cursor` | `~/.cursor/skills/dunsocial/` |
| `pi` | `~/.pi/agent/skills/dunsocial/` |
| `opencode` | `~/.config/opencode/skills/dunsocial/` |
| `agents` | `~/.agents/skills/dunsocial/` |
| `copilot` | `~/.copilot/skills/dunsocial/` |
| `windsurf` | `~/.codeium/windsurf/skills/dunsocial/` |
| `goose` | `~/.config/goose/skills/dunsocial/` |
| `gemini` | `~/.gemini/skills/dunsocial/` |
| `amp` | `~/.config/agents/skills/dunsocial/` |
| `grok` | `~/.grok/skills/dunsocial/` |
| `continue` | `~/.continue/skills/dunsocial/` |
| `antigravity` | `~/.gemini/antigravity/skills/dunsocial/` |
Restart or open a new agent session after installing.
### What agents should do
1. Prefer `--json` on every command.
2. Run `auth status` → `workspace use` → `accounts list` before posting.
3. Never invent account ids.
4. Treat `drafts create` as a draft, not a publish.
---
# CI and tokens
Source: https://www.dunsocial.com/docs/cli/ci-and-agents/ci-and-tokens
For automation, use a personal access token instead of device login. Create one in the app under **Settings → CLI**.
### Secrets to set
| Secret / env | Value |
|--------------|-------|
| `DUN_TOKEN` | `dun_pat_…` access token |
| `DUN_WORKSPACE_ID` | Workspace id from the app or `dun workspace list` |
Optional: pin a package version in CI (`npx dunsocial@0.4.0`) so upgrades are intentional.
### Example: schedule on release
### GitHub Actions sketch
Set `DUN_TOKEN` and `DUN_WORKSPACE_ID` as repository secrets. `CI=1` also enables `--yes` for destructive commands and defaults JSON when stdout is not a TTY.
### PAT tips
- Tokens are bound to one workspace.
- Prefer the smallest scopes you need.
- Revoke from Settings → CLI if a secret leaks.
- Never log the full token.
- PATs cannot manage other tokens, billing, or AI routes.
### Headless login with a token
For pure CI, exporting `DUN_TOKEN` is enough — you do not need to write a local config file.
---
# Flags and output
Source: https://www.dunsocial.com/docs/cli/ci-and-agents/flags-and-output
### Global flags
| Flag | Purpose |
|------|---------|
| `--json` / `-j` | Machine-readable output (default in CI / non-TTY) |
| `--workspace` / `-w` | Override workspace for this command |
| `--api-url` | Override API base URL |
| `--token` | Override bearer token for this command |
| `--debug` | Log HTTP method/path/status to stderr |
| `--quiet` / `-q` | Suppress human success output |
| `--yes` / `-y` | Skip destructive confirmations |
| `--help` / `-h` | Help |
| `--version` / `-v` | Version |
### Env vars
| Variable | Purpose |
|----------|---------|
| `DUN_TOKEN` | Bearer token |
| `DUN_WORKSPACE_ID` | Default workspace |
| `DUN_API_URL` | API base |
| `DUN_CONFIG` | Config file path |
| `DUN_JSON=1` | Force JSON (`0` forces human) |
| `DUN_DEBUG=1` | Debug HTTP |
| `CI=1` | Treat as CI (JSON + `--yes`) |
### Success and error JSON
Success:
Failure:
Progress and debug lines go to **stderr**, so scripts can parse stdout safely.
### Exit codes
| Code | Meaning |
|------|---------|
| **0** | Ok |
| **1** | Usage / unknown command |
| **2** | Auth |
| **3** | Forbidden / missing scope |
| **4** | Validation |
| **5** | Not found |
| **6** | Rate limited |
| **7** | Network |
### Help
### Common pitfalls
- Need a workspace: `workspace use` or `--workspace` / `DUN_WORKSPACE_ID`
- `--accounts` wants DunSocial account **ids**, not handles
- Upload local files with `media upload` before attaching
- Platform options go in `--meta '{…}'`
- Destructive `delete` needs `--yes` unless `CI=1`
---
# Drafts
Source: https://www.dunsocial.com/docs/cli/drafts
Drafts are not publishes. Create one when you want to save an idea for later in the same workspace.
### List and get
### Create
| Flag | Purpose |
|------|---------|
| `--text` | Draft body (required) |
| `--platforms` | e.g. `x,linkedin,pinterest` |
| `--accounts` | Optional social account ids |
| `--media` | Media asset ids |
| `--name` | Optional draft name |
### Update
### Delete
Requires `--yes`:
---
# Authentication
Source: https://www.dunsocial.com/docs/cli/getting-started/authentication
The CLI talks to `https://api.dunsocial.com` with a bearer token. You can sign in with a browser once on your machine, or use a personal access token for CI and agents.
### Check status
`status` shows whether you are authenticated, which workspace is selected, and where config is stored. `whoami` returns your profile.
### Device login (laptop)
1. The CLI starts a device-code login.
2. Your browser opens `app.dunsocial.com/cli/authorize` (or you open the link manually).
3. You approve and pick a workspace if asked.
4. The CLI saves a session token locally.
Sign out and clear local config:
### Personal access tokens (CI and agents)
Create a token in the app under **Settings → CLI**. It is shown **once**. Format: `dun_pat_…`.
Then set env vars (preferred over putting the token in a file for CI):
You can also pass a token for one login:
#### Token scopes
| Scope | Allows |
|-------|--------|
| `workspace:read` | List workspaces and members |
| `posts:read` | List and get posts |
| `posts:schedule` | Schedule posts and threads |
| `posts:publish` | Publish now |
| `posts:delete` | Cancel or delete posts |
| `drafts:write` | Create, update, delete drafts |
| `media:read` / `media:write` | Gallery and uploads |
| `memory:read` / `memory:write` | Memories and collections |
CI defaults usually include workspace + posts schedule/publish + media. Missing scope → exit code **3** (forbidden). PATs cannot create or revoke other tokens, manage billing, or call AI.
### Where config lives
Local config file (mode `0600` when possible):
```
~/.config/dunsocial/config.json
```
Override the path with `DUN_CONFIG`.
### Env vars (env wins over the file)
| Variable | Purpose |
|----------|---------|
| `DUN_TOKEN` | Bearer session or PAT |
| `DUN_WORKSPACE_ID` | Default workspace for commands |
| `DUN_API_URL` | API base (default `https://api.dunsocial.com`) |
| `DUN_JSON=1` | Force JSON output |
| `DUN_DEBUG=1` | Log HTTP to stderr |
| `DUN_CONFIG` | Custom config file path |
Per-command overrides: `--token`, `--workspace`, `--api-url`.
### Next step
Pick a workspace with [Workspaces](/docs/cli/workspaces-and-accounts/workspaces), then list [Accounts](/docs/cli/workspaces-and-accounts/accounts).
---
# Install and sign in
Source: https://www.dunsocial.com/docs/cli/getting-started/install-and-sign-in
You need Node.js 20 or newer. Then install the package and sign in.
### Install
Check that it works:
You can also run it without a global install: `npx dunsocial --help`.
### Sign in on your machine
A browser window opens so you can approve access. After that, you are signed in on this computer.
If the browser does not open:
Follow the link and code shown in the terminal.
### Choose your workspace
### See connected accounts
Copy the **account id** you want to post with (not the @username). You will pass that id to post commands.
### Access tokens for CI and agents
For GitHub Actions or other automation, create a personal access token instead of device login. Full details are on [Authentication](/docs/cli/getting-started/authentication) and [CI and tokens](/docs/cli/ci-and-agents/ci-and-tokens).
Quick setup:
1. In DunSocial, open **Settings**, then **CLI**.
2. Create an access token and copy it (shown once).
3. Set `DUN_TOKEN` and `DUN_WORKSPACE_ID` in your environment or CI secrets.
### Discovery order
After install, always do this before posting:
1. `dun auth status --json`
2. `dun workspace list` then `dun workspace use `
3. `dun accounts list` — copy the social account **id**
4. Schedule or publish
### Good to know
- Device login is best for your laptop. Tokens are best for CI and agents.
- Prefer ChatGPT or Claude **in the browser**? Use [MCP](/docs/mcp/getting-started/what-is-mcp) instead of the CLI.
---
# What is the CLI
Source: https://www.dunsocial.com/docs/cli/getting-started/what-is-the-cli
The DunSocial CLI lets you post and schedule from a terminal. Install the `dunsocial` package from npm, then use the `dun` command on your machine, in a coding agent, or in CI.
### What it is
- A small command-line tool that talks to your DunSocial workspace.
- Works on your laptop, with local AI coding agents, and in GitHub Actions or other CI.
- Uses the same workspaces, accounts, and posts you see in the app.
### CLI vs MCP
DunSocial has two ways for tools to act for you:
Same workspace either way. Prefer MCP when you are chatting in a remote assistant. Prefer the CLI when you want scripts, CI, or a local terminal.
### Why use it
- Schedule or publish a post without opening the dashboard.
- Announce a release from CI when you ship.
- Let a local coding agent draft and schedule for you.
### How to get started
1. [Install and sign in](/docs/cli/getting-started/install-and-sign-in)
2. [Choose a workspace and account](/docs/cli/workspaces-and-accounts/workspaces)
3. [Schedule or publish a post](/docs/cli/posts/schedule-and-publish)
For automation, see [CI and tokens](/docs/cli/ci-and-agents/ci-and-tokens).
---
# Media
Source: https://www.dunsocial.com/docs/cli/media
Upload local files into the workspace gallery, then pass the returned asset id to `posts schedule` or `posts publish` with `--media`.
### Upload
The CLI requests a presigned URL, uploads the file, then completes the asset. Supported types include jpeg, png, gif, webp, mp4, mov, and webm.
### List and get
### Delete
Requires `--yes`:
### Attach to a post
---
# Memory
Source: https://www.dunsocial.com/docs/cli/memory
Memory collections hold notes that AI and your team can reuse. Needs a workspace and the right PAT scopes (`memory:read` / `memory:write`) if you use a token.
### Collections
### List and save memories
### Search
### Delete a memory
Requires `--yes` and the collection id. To delete a collection itself, use `dun memory collections delete` above.
---
# Manage posts
Source: https://www.dunsocial.com/docs/cli/posts/manage-posts
### List posts
`--status` examples: `scheduled`, `published`, `failed`, `draft`, `cancelled`.
JSON list items include `mediaUrls` (media asset ids), the same field as `dun posts get`.
### Get one post
### Reschedule
If you omit `--text`, the CLI keeps the existing content, media, and metadata.
### Cancel a scheduled post
### Delete
Destructive. Requires `--yes` (or `CI=1`):
### X monthly cap
Useful before a large batch of X posts.
---
# Schedule and publish
Source: https://www.dunsocial.com/docs/cli/posts/schedule-and-publish
Needs auth and a workspace. Use account **ids** from `dun accounts list`.
### Validate before you enqueue
`dun posts validate` calls `POST /api/posts/validate` — the same character-limit and platform-metadata checks as schedule/publish, with no writes. Reddit accounts still get the extra live flair/requirements check afterward.
Use `--meta` when the accounts include Reddit, Instagram, Pinterest, TikTok, Discord, or Slack. Instagram `format` is required (`feed_image`, `carousel`, `reel`, or `story`) — there is no default. Instagram feed/carousel/story images may be JPEG, PNG, GIF, or WebP; non-JPEG stills convert to JPEG at publish. Discord requires `{"discord":{"channelId":"..."}}` from `dun discord channels`. Slack requires `{"slack":{"channelId":"..."}}` from `dun slack channels`.
### Schedule a post
Pass either `--in` (relative) or `--at` (ISO time), not both.
Absolute time:
`--in` accepts values like `30m`, `2h`, `1d`, `1w` (and longer forms like `minutes`, `hours`).
Multiple accounts (comma-separated):
With media (upload first — see [Media](/docs/cli/media)):
Platform-specific options go in `--meta` as JSON:
### Publish now
Optional `--natural` (natural posting). Alias: `publish-now`.
### X threads
Provide a JSON file (array of tweets, or `{ "tweets": […] }`), or split `--text` with `||`.
Threads need at least **2** tweets. Use one X account id (`--account`).
### Flags cheat sheet
| Flag | Purpose |
|------|---------|
| `--text` / `-t` | Post content |
| `--accounts` / `-a` | Social account ids |
| `--in` / `--at` | When to schedule |
| `--media` | Media asset ids |
| `--meta` | Platform metadata JSON |
| `--natural` | Natural posting (publish) |
| `--json` | Machine-readable output |
Posts created from the CLI show a CLI source badge in the app.
---
# Accounts
Source: https://www.dunsocial.com/docs/cli/workspaces-and-accounts/accounts
Post commands need DunSocial **social account ids**, not @handles. List them after you pick a workspace.
### List accounts
`--platform` filters by provider. Aliases include `x` / `twitter`, `linkedin`, `linkedin-business`, `bluesky`, `threads`, `reddit`, `pinterest`, `instagram`, `youtube`, `tiktok`, `facebook` / `fb` / `facebook-page`. Facebook Pages are limited beta — connect the Page in the DunSocial app, then list it here.
Each row includes:
- `id` — use this with `--accounts`
- `providerName`, `username`, `displayName`
- `isConnected`, `expiresAt`
### Tips
- Do not invent account ids. Always list first.
- Connect new accounts in the DunSocial app, then run `accounts list` again.
- `account` / `accounts` are both accepted.
---
# Workspaces
Source: https://www.dunsocial.com/docs/cli/workspaces-and-accounts/workspaces
Most commands need a workspace. Set a default once, or pass `--workspace` / `DUN_WORKSPACE_ID` on each command.
### List workspaces
Shows id, name, slug, your role, timezone, and plan status.
### Set the default
This writes the default into `~/.config/dunsocial/config.json`.
### Show the current workspace
If nothing is selected, you will get a validation error asking you to run `workspace use`.
### Override for one command
`workspaces` is an alias of `workspace`.
---
# Compose a post
Source: https://www.dunsocial.com/docs/composing-and-ai/compose-a-post
The composer is where you write and send your posts.
### Steps
1. Click **Compose**.
2. Pick the accounts you want to post to. You can choose more than one.
3. Type your post. The preview shows how it will look on each platform.
4. Add images or video if you want. You can upload new files or pick from your **Gallery**.
5. Choose what to do next:
- **Publish now** to send it right away.
- **Schedule** to pick a date and time.
- **Save as draft** to finish later.
### Tips
- Each platform has its own limits, like character counts. The composer flags anything that will not fit.
- You can tweak the text per platform so each post reads well where it lands.
- Need help writing? Use **Write with AI** to generate a first version.
That is it. Your post appears in **Posts** once scheduled or published.
---
# Write with AI
Source: https://www.dunsocial.com/docs/composing-and-ai/write-with-ai
If you are not sure what to write, let the AI draft it for you.
### How to use it
1. In the composer, open the AI writing option.
2. Give it a topic or a rough idea of what you want to say.
3. Choose the platform you are writing for (for example an X thread, a LinkedIn post, or a Reddit post).
4. The AI generates one or more options.
5. Pick one, then edit it until it sounds right.
### What it can create
- Single posts for X, LinkedIn, Bluesky, Threads, Reddit, and more.
- X threads with several connected posts.
- Short-form video ideas for YouTube Shorts.
### It learns your voice
The AI uses your **Brand memory** and your **voice and tone settings** so posts sound like you, not generic. The more you save to memory and set your tone, the closer it gets.
### Daily ideas
DunSocial can also suggest post ideas each day to help you stay consistent when you are short on inspiration.
---
# Your voice and tone settings
Source: https://www.dunsocial.com/docs/composing-and-ai/your-voice-and-tone-settings
Voice settings tell the AI how you like to sound. Set them once and every AI draft follows them.
### Where to find them
Open **Settings**, then **Personalization**.
### What you can set
You can create voice presets that describe:
- **Tone**: for example friendly, professional, or playful.
- **Style**: how you like sentences and posts structured.
- **Personality**: the character or attitude your brand shows.
### How to use presets
1. Create a preset and give it a clear title, like "Casual updates" or "Formal announcements".
2. Fill in the tone, style, and personality.
3. Save it.
4. When you write with AI, pick the preset that fits the post.
You can keep several presets for different kinds of content. Voice settings work together with **Brand memory**: memory holds the facts, voice settings shape how those facts are said.
---
# Contact
Source: https://www.dunsocial.com/docs/contact
Have a question, a problem, or a request? Reach us by email or through Support.
You can also reach the team on the community channels linked in the app.
---
# Drafts
Source: https://www.dunsocial.com/docs/content-and-media/drafts
A draft is a post you have started but not scheduled or published yet.
### Save a draft
1. Write your post in the composer.
2. Click **Save as draft**.
Your draft is stored in the **Drafts** area.
### Come back to it
1. Open **Drafts**.
2. Click the draft you want.
3. Edit it, then schedule, publish, or save it again.
### Good to know
- Drafts keep your text, chosen accounts, and attached media.
- Drafts can be set to auto-delete after a period of time. If a draft is close to being deleted, you can get a warning email so you have time to act. Turn this on in notification settings.
- Use drafts to prepare content in batches, then schedule them when you are ready.
---
# Gallery and media library
Source: https://www.dunsocial.com/docs/content-and-media/gallery-and-media-library
The **Gallery** is your media library. Every image and video you upload lives here, ready to reuse.
### Upload media
1. Open **Gallery**.
2. Upload an image or video.
3. It is saved to your workspace library.
You can also upload media directly while composing a post.
### Reuse media
When writing a post, pick from the Gallery instead of uploading again. This keeps your assets organized and saves time.
### Status labels
Each asset shows how it is being used:
- **Published**: used in a post that already went out.
- **Scheduled**: attached to an upcoming post.
- **Draft**: attached to a draft.
- **Unused**: not attached to anything yet.
### Tips
- Clean up unused files now and then to keep the library tidy.
- Media in the Gallery is shared across your workspace, so your team can reuse it too.
---
# Posts (published history)
Source: https://www.dunsocial.com/docs/content-and-media/posts-published-history
The **Posts** area is not just for upcoming content. It is also a record of everything you have published.
### What you see
- Posts that have gone out, marked as published.
- The platforms each post was sent to.
- The date and time it published.
- Any posts that failed, so you can review them.
### Ways to browse
- Use the **list** view for a straightforward history.
- Use the **calendar** view to see published posts by day.
- **Filter** by status or by social account to narrow things down.
### Why it helps
- Check what you have already posted before writing something new.
- Spot failed posts and try them again.
- Keep a simple history of your activity across every connected platform.
---
# Connect your first account
Source: https://www.dunsocial.com/docs/getting-started/connect-your-first-account
Before you can publish, connect at least one social account to your workspace.
### Steps
1. Open **Settings → accounts**, or go to **Connect** at `/{workspace}/connect`.
2. Find the platform you want, for example X or LinkedIn.
3. Click **Connect**.
4. You are sent to that platform to log in and approve access.
5. Once approved, you come back to DunSocial and the account shows as connected.
### Good to know
- Some platforms are generally available and connect right away.
- A few platforms are in beta. For those, you request access first and connect once you are approved.
- Only workspace owners and admins can connect or disconnect accounts. Members can post with the accounts that are already connected.
- If an account ever stops working, you can reconnect it from the same screen. See "Reconnect an account".
Once at least one account is connected, you are ready to compose your first post.
---
# Create your workspace
Source: https://www.dunsocial.com/docs/getting-started/create-your-workspace
A workspace is your home base in DunSocial. It holds your connected accounts, posts, drafts, media, and team members.
When you sign up, we walk you through creating your first workspace.
### Steps
1. Sign up or log in.
2. Enter a **workspace name** (for example, your brand or company name).
3. Pick a **workspace address** (slug). This is a short, unique name used in your links.
4. Choose your **timezone**. Scheduling uses this, so pick the timezone you actually post from.
5. Click **Continue**.
### After you create it
We take you straight to connecting a social account, then to choosing a plan. You need a connected account and an active plan before you can start posting.
You can change your workspace name and other details later in **Settings**, then **Workspace**.
You can also create more than one workspace, for example one per client or brand. See "Switch workspaces" to move between them.
---
# Quick tour of the app
Source: https://www.dunsocial.com/docs/getting-started/quick-tour-of-the-app
Here is what you will find in the sidebar.
### Main areas
- **Compose**: Write a new post, pick your platforms, and schedule or publish it.
- **Posts**: See what is scheduled and what has already gone out. Includes a calendar view.
- **Drafts**: Posts you saved to finish later.
- **Gallery**: Your media library of uploaded images and videos.
- **Memory**: Facts and notes that help the AI write in your voice.
- **Analytics**: Performance for published posts.
- **Settings**: Profile, connected accounts, notifications, theme, team, billing, webhooks, MCP, and more.
Connected accounts live under **Settings → accounts** (or `/connect`). Billing is under **Settings → billing**.
### Switching workspaces
Your current workspace name shows near the top of the sidebar. Click it to switch to another workspace or create a new one.
### Getting help
Use the sidebar or search to find a guide. If you need more help, [contact us](/docs/contact).
---
# What is DunSocial
Source: https://www.dunsocial.com/docs/getting-started/what-is-dunsocial
DunSocial is one place to write, schedule, and publish your social media posts. Instead of hopping between apps, you plan everything from a single dashboard.
### What you can do
- Write a post once and send it to more than one platform.
- Schedule posts for later, or publish right away.
- Get help writing with AI that learns your voice over time.
- Keep your images and videos in one media library.
- Work together with your team in shared workspaces.
### Platforms you can post to
Some platforms are open to everyone. A few are in beta and ask you to request access first. Each platform page tells you which is which.
### Where to start
1. Create your workspace.
2. Connect your first social account.
3. Write and schedule your first post.
The next few pages walk you through each step.
---
# MCP
Source: https://www.dunsocial.com/docs/mcp
MCP (Model Context Protocol) lets AI assistants connect to your DunSocial workspace and act for you. Draft, schedule, and publish by chatting instead of clicking around the dashboard.
## Start here
## Platforms
---
# Connect your assistant
Source: https://www.dunsocial.com/docs/mcp/connect/connect-your-assistant
Paste the MCP URL into your assistant. You approve access in the browser — no token to copy.
### Step 1: Open Settings → MCP
In DunSocial, open **Settings**, then **MCP**. Copy the endpoint:
### Step 2: Add it to your assistant
Pick your client and use the matching snippet.
### Step 3: Approve and test
1. Sign in to DunSocial if asked.
2. Choose the workspace the assistant should use.
3. Approve the scopes.
4. Ask something simple: *“List my connected social accounts and the posts scheduled this week.”*
### Tips
- Most actions need a connected social account. Ask the assistant to list accounts first and use the **account id**, not the @handle.
- Creating a draft is not the same as publishing. Say “publish” or “schedule” when you want it live.
- If tools fail with a permission error, reconnect so publish and write scopes are included — see [Authentication](/docs/mcp/getting-started/authentication).
- If **Claude** fails while adding the connector, run the Claude Code command from Settings → MCP instead, then `/mcp` to authorize. That path uses the same OAuth URL without the Claude.ai connector UI.
- Prefer the [CLI](/docs/cli) for CI and local scripts.
---
# Authentication
Source: https://www.dunsocial.com/docs/mcp/getting-started/authentication
DunSocial MCP uses **OAuth**. You do not paste a long-lived secret into ChatGPT or Claude. You add the MCP URL; the client opens DunSocial so you can sign in, pick a workspace, and approve access.
### The URL
Find the same URL under **Settings → MCP**. Manage or revoke connections there too.
### What happens when you connect
1. Your assistant calls the MCP endpoint.
2. DunSocial asks you to sign in (if needed).
3. You **choose a workspace**. The connection stays bound to that workspace.
4. You **approve scopes** (what the assistant may do).
5. The client receives short-lived tokens and refreshes them for you.
### Scopes
| Scope | What it allows |
|-------|----------------|
| `workspace:read` | List and view posts, drafts, media, memories, accounts, and workspace details |
| `drafts:write` | Create and edit drafts (not publish) |
| `posts:schedule` | Schedule, reschedule, and cancel posts |
| `posts:publish` | Publish immediately |
| `content:delete` | Delete posts, drafts, memories, or media |
| `memory:write` | Create collections and save or update memories |
| `media:write` | Upload to the gallery |
| `offline_access` | Stay connected with refresh tokens |
Publish tools need `posts:publish`. If consent only showed “view workspace content,” disconnect in Settings → MCP and connect again so the full set is granted.
### Workspace binding
OAuth connections are locked to the workspace you picked at consent. Asking the assistant to use a different workspace will fail until you reconnect for that workspace.
### Good to know
- Tokens are never put in the URL query string for new setups.
- Prefer MCP for remote chat hosts. Prefer the [CLI](/docs/cli) and personal access tokens for CI.
- Revoke a connection anytime from **Settings → MCP**.
---
# What is MCP
Source: https://www.dunsocial.com/docs/mcp/getting-started/what-is-mcp
MCP (Model Context Protocol) is how AI assistants connect to DunSocial and act on your behalf. Instead of clicking around the dashboard, you ask Claude, ChatGPT, Cursor, or another client to draft, schedule, or publish for you.
### What it is
- A secure connection between DunSocial and tools that support MCP.
- Uses the same workspace, accounts, posts, drafts, media, and memory as the app.
- Connects with **OAuth** — you paste a URL, pick a workspace, and approve access in the browser.
### MCP vs CLI vs the app
Same workspace either way. Prefer MCP when you are chatting in a remote assistant. Prefer the [CLI](/docs/cli) for scripts and CI.
### Why use it
- Draft and schedule posts by chatting.
- Save notes to memory without leaving your assistant.
- Upload media and check connected accounts from one conversation.
### Endpoint
```
https://api.dunsocial.com/api/mcp
```
Copy it from **Settings → MCP** in the app, or use the snippets on [Connect your assistant](/docs/mcp/connect/connect-your-assistant).
### Next steps
1. [Authentication](/docs/mcp/getting-started/authentication) — workspaces and scopes
2. [Connect your assistant](/docs/mcp/connect/connect-your-assistant)
3. [Tools overview](/docs/mcp/tools/tools-overview)
---
# Discord
Source: https://www.dunsocial.com/docs/mcp/platforms/discord
Prefer `schedule_discord_post` and `publish_discord_now`. Do **not** treat `create_draft` as a successful Discord message.
### Flow
1. `list_social_accounts` — find the Discord account **id**
2. `list_discord_channels` — pick a real `channelId` (do not guess). Text and announcement channels only.
3. Upload media if the message needs attachments (`get_upload_url` → PUT → `complete_upload`)
4. `publish_discord_now` (or schedule) with:
- `socialAccountId`
- `channelId`
- `content` (up to 2,000 characters; required unless `mediaUrls` is set)
- optional `channelName`
- optional `mediaUrls` (up to 10 images or videos; total request max 25 MB)
### Example ask
> List Discord channels, then publish “Ship notes for Friday” to #announcements with this screenshot.
### Drafts
If you only want a draft for the web composer, use `create_draft` with `selectedPlatforms: ["discord"]`. That still does **not** publish.
### Common mistakes
- Using a channel name instead of `channelId` from `list_discord_channels`
- Skipping the channel entirely — `metadata.discord.channelId` is required
- Assuming a draft is live on Discord
- Claiming embeds, forums, polls, or Discord analytics — V1 is text and attachments only
---
# Facebook Pages
Source: https://www.dunsocial.com/docs/mcp/platforms/facebook
Facebook v1 is **Pages only** (not a personal profile). There is **no** `schedule_facebook_post` or `publish_facebook_now`. Use the generic tools against a connected Page.
Limited beta — the Page must already be connected in the DunSocial app.
### What you can post
- Text
- Text plus **one** URL (no extra metadata)
- One or more **images**
- Caption/message cap: **63,206** characters
- **No** video, Reels, Stories, or `metadata.facebook`
### Flow
1. `list_social_accounts` — find the Facebook account **id** (display name is the Page name)
2. Optional: `get_upload_url` → PUT the image → `complete_upload`
3. `schedule_post` or `publish_now` with `socialAccountIds` and `content`
4. Drafts: `create_draft` / `update_draft` with `selectedPlatforms: ["facebook"]`
Aliases the draft tools accept: `facebook`, `fb`, `facebook-page`, `facebook page`, `facebook_page`.
### Example ask
> Publish “Hello from the Page” to my Facebook Page now. If I uploaded a photo, attach that asset.
### Common mistakes
- Adding `metadata.facebook` — v1 does not use it
- Attaching video
- Treating a draft as a live Page post
- Expecting a dedicated Facebook MCP tool pair
---
# Instagram
Source: https://www.dunsocial.com/docs/mcp/platforms/instagram
Prefer `schedule_instagram_post` and `publish_instagram_now`.
### Formats
| Format | Media |
|--------|-------|
| `feed_image` | One image (JPEG, or PNG/WebP/GIF converted to JPEG at publish) |
| `carousel` | 2–10 images or videos (still images convert to JPEG at publish) |
| `reel` | One video |
| `story` | One image or one video (images convert to JPEG at publish) |
Upload media with the gallery tools first, then pass asset ids in `mediaUrls`.
### Useful options
- `caption` (up to about 2200 characters)
- `altText`
- Reel extras: `shareToFeed`, cover image, thumb offset, audio name
- `collaborators` (up to a few usernames)
### Example ask
> Upload these three photos and publish an Instagram carousel with this caption…
### Tip
Use the Instagram social account **id** from `list_social_accounts`. Caption and media rules still apply the same as in the app.
---
# Pinterest
Source: https://www.dunsocial.com/docs/mcp/platforms/pinterest
Prefer `schedule_pinterest_post` and `publish_pinterest_now`. Do **not** treat `create_draft` as a successful Pin.
### Flow
1. `list_social_accounts` — find the Pinterest account **id**
2. `list_pinterest_boards` — pick a real `boardId` (do not guess). If the account has no board, call `create_pinterest_board` with a `name` (default **PUBLIC** so it appears on the profile; `SECRET` for private)
3. `get_upload_url` → PUT the image → `complete_upload`
4. `publish_pinterest_now` (or schedule) with:
- `socialAccountId`
- `boardId`
- `title` (up to 100 characters)
- `description` (up to 800)
- exactly **one** entry in `mediaUrls`
- optional `link`, `boardName`
### Example ask
> Upload this image, then publish a Pin to my Landing page board titled “Core Flows” with a short description and link to dunsocial.com.
### Drafts
If you only want a draft for the web composer, use `create_draft` with `selectedPlatforms: ["pinterest"]` plus board/title options. That still does **not** publish.
### Common mistakes
- Using a board name instead of `boardId` from `list_pinterest_boards` or `create_pinterest_board`
- Passing more than one image
- Skipping `complete_upload` after the PUT
- Assuming a draft is live on Pinterest
- Passing search tags — Pinterest's pin-create API has no tags field; put keywords in `title` / `description`
---
# Reddit
Source: https://www.dunsocial.com/docs/mcp/platforms/reddit
Prefer `schedule_reddit_post` and `publish_reddit_now`.
### Key fields
| Field | Notes |
|-------|-------|
| `socialAccountId` | From `list_social_accounts` (not your Reddit username) |
| `subreddit` | With or without `r/` |
| `title` | Post title |
| `kind` | `self`, `link`, `image`, or `video` |
| `body` | For self posts |
| `url` | For link posts |
| `mediaUrls` | Exactly one asset for image/video kinds |
| `scheduledAt` | Required when scheduling (ISO time) |
Optional: flair, NSFW, spoiler, and related flags when the subreddit needs them.
### Example ask
> Schedule a Reddit self post to r/SideProject tomorrow titled “We launched DunSocial MCP” with this body…
### Tip
Ask the assistant to list accounts first so it uses the correct DunSocial social account id.
---
# Slack
Source: https://www.dunsocial.com/docs/mcp/platforms/slack
Prefer `schedule_slack_post` and `publish_slack_now`. Do **not** treat `create_draft` as a successful Slack message.
### Flow
1. `list_social_accounts` — find the Slack account **id**
2. `list_slack_channels` — pick a real `channelId` (do not guess). Public and private channels the bot can see.
3. Upload media if the message needs attachments (`get_upload_url` → PUT → `complete_upload`)
4. `publish_slack_now` (or schedule) with:
- `socialAccountId`
- `channelId`
- `content` (up to 4,000 characters; required unless `mediaUrls` is set)
- optional `channelName`
- optional `mediaUrls` (up to 10 images or videos; 50 MB per file)
### Example ask
> List Slack channels, then publish “Ship notes for Friday” to #launches with this screenshot.
### Drafts
If you only want a draft for the web composer, use `create_draft` with `selectedPlatforms: ["slack"]`. That still does **not** publish.
### Common mistakes
- Using a channel name instead of `channelId` from `list_slack_channels`
- Skipping the channel entirely — `metadata.slack.channelId` is required
- Assuming a draft is live on Slack
- Posting to a private channel without inviting the DunSocial Slack app. Public channels are joined automatically on publish. If Slack asks you to reconnect, reconnect the publish app so it can join channels and share files.
- Claiming DMs, thread replies, Block Kit, or Slack analytics — V1 is text and attachments only
- Confusing this with the Slack agent in Settings → Integrations. Publish uses a separate Slack app.
---
# X threads
Source: https://www.dunsocial.com/docs/mcp/platforms/x-threads
`schedule_thread` and `publish_thread_now` post **X/Twitter threads** — not Meta Threads. Meta Threads can still appear as a draft platform elsewhere in the product.
### Rules
- One X `socialAccountId` from `list_social_accounts`
- Between **2 and 25** tweets
- Each tweet: `content`, optional `mediaUrls`
- Schedule needs `scheduledAt`
### Example ask
> Schedule a 4-tweet X thread for this afternoon on my main X account…
### Cap usage
Ask for `get_x_cap_usage` before a large batch so you do not hit the monthly X posting cap.
---
# Media, memory, and workspaces
Source: https://www.dunsocial.com/docs/mcp/tools/media-memory-workspaces
### Media
| Tool | What it does |
|------|----------------|
| `list_media` / `get_media` | Browse the gallery |
| `get_upload_url` | Get a short-lived upload URL (`filename`, `mimeType`, `fileSize`) |
| `complete_upload` | Confirm the upload after the file bytes are PUT |
| `delete_media` | Remove an asset |
Upload flow:
1. `get_upload_url`
2. HTTP **PUT** the file bytes to that URL
3. `complete_upload`
4. Pass the asset id / storage key into schedule or publish tools
Limits: images (jpeg, png, gif, webp) up to about **8MB**; video (mp4, mov, webm) up to about **512MB**. Needs `media:write` to upload.
### Memory
| Tool | What it does |
|------|----------------|
| `list_collections` / `create_collection` | List or create collections |
| `update_collection` / `delete_collection` | Rename, recolor, or delete (creator only; default collections cannot change visibility or be deleted) |
| `list_memories` | List memories in a collection |
| `save_memory` / `save_memories_batch` | Add notes |
| `search_memory` | Semantic search (`prompt`, `collectionIds`) |
| `update_memory` / `delete_memory` | Edit or remove |
Writing memories needs `memory:write`.
### Workspaces
| Tool | What it does |
|------|----------------|
| `list_workspaces` | Workspaces you belong to |
| `get_workspace` | Details for the connected workspace |
| `list_members` | Team members |
| `list_social_accounts` | Connected accounts (use these **ids** when posting) |
| `list_pinterest_boards` | Boards for a Pinterest account |
| `create_pinterest_board` | Create a public or secret board (returns a live `boardId`) |
| `list_discord_channels` | Text and announcement channels for the connected Discord server |
| `list_slack_channels` | Public and private channels for the connected Slack team |
OAuth locks you to the workspace you approved. `list_workspaces` is still useful for context; switching requires a new connection.
---
# Posts and drafts
Source: https://www.dunsocial.com/docs/mcp/tools/posts-and-drafts
### Posts
| Tool | What it does |
|------|----------------|
| `list_posts` | List posts (optional status, account, pagination). Includes `mediaUrls` (asset ids). |
| `get_post` | Get one post by id |
| `validate_post` | Dry-run schedule/publish checks (no writes). Call before schedule/publish; fix `issues[].next` when `valid` is false. |
| `schedule_post` | Schedule for later (`socialAccountIds`, `content`, `scheduledAt`, optional media/metadata) |
| `publish_now` | Publish immediately |
| `schedule_thread` / `publish_thread_now` | X/Twitter threads (2–25 tweets) |
| `schedule_reddit_post` / `publish_reddit_now` | Reddit self, link, image, or video |
| `schedule_instagram_post` / `publish_instagram_now` | Feed image, carousel, or Reel |
| `schedule_pinterest_post` / `publish_pinterest_now` | Image Pin to a board |
| `schedule_discord_post` / `publish_discord_now` | Discord text and attachments to a channel |
| `schedule_slack_post` / `publish_slack_now` | Slack text and files to a channel |
| `reschedule_post` | Change time **and** content (`content` and `scheduledAt` are both required) |
| `cancel_post` | Cancel a scheduled post |
| `delete_post` | Delete a post |
| `get_x_cap_usage` | X monthly posting cap |
Needs scopes: read tools use `workspace:read`; schedule/cancel need `posts:schedule`; publish tools need `posts:publish`; delete needs `content:delete`.
### Example ask
> Schedule this LinkedIn post for tomorrow at 15:00 UTC on account `ACCOUNT_ID`: “We just shipped …”
The assistant should call `schedule_post` with ISO `scheduledAt` and the social account id.
### Drafts
| Tool | What it does |
|------|----------------|
| `list_drafts` / `get_draft` | Browse drafts |
| `create_draft` / `update_draft` | Save ideas (optional platforms, accounts, media, Pinterest options) |
| `delete_draft` | Remove a draft |
Drafts need `drafts:write` (delete needs `content:delete`). A draft never publishes by itself.
### Platform metadata on generic tools
`schedule_post` and `publish_now` can carry `metadata.reddit`, `metadata.instagram`, `metadata.pinterest`, `metadata.discord`, or `metadata.slack` plus `mediaUrls`. Discord requires `metadata.discord.channelId` from `list_discord_channels` (optional `channelName`). Slack requires `metadata.slack.channelId` from `list_slack_channels` (optional `channelName`). Facebook Pages need **no** metadata — pass the Page account id, text, and optional images. Prefer the dedicated tools when available.
---
# Tools overview
Source: https://www.dunsocial.com/docs/mcp/tools/tools-overview
Once connected, your assistant can use **53 tools** against the workspace you approved. Ask in plain language — the client picks the right tool.
### Discovery order
Tell your assistant to do this before posting:
1. List workspaces (if needed) and confirm the connected workspace.
2. List social accounts and copy the **account id**.
3. Upload media if the post needs an image or video.
4. Call `validate_post`. If `valid` is false, fix `issues[].next` and retry — do not publish yet.
5. Schedule or publish (or save a draft if you are not ready).
### What you can ask
- “List my connected accounts.”
- “Schedule this LinkedIn post for tomorrow at 9am.”
- “Save this note to my brand memory collection.”
- “Upload this image, then publish a Pinterest pin to my Landing page board.”
- “List Discord channels, then publish this update to #announcements.”
### Tool groups
| Group | Examples |
|-------|----------|
| Posts | List, schedule, publish, threads, reschedule, cancel, delete, X cap |
| Drafts | List, create, update, delete |
| Media | List, upload URL, complete upload, delete |
| Memory | Collections, save, search, update, delete |
| Workspaces | List workspaces, members, social accounts, list/create Pinterest boards, list Discord channels |
### Important rules
- **`create_draft` is not a publish.** Use schedule or publish tools to go live.
- Use DunSocial **social account ids** from `list_social_accounts`, not @handles.
- OAuth is bound to one workspace. Switch by reconnecting for another workspace.
- Prefer dedicated Reddit / Instagram / Pinterest / Discord / Slack tools when posting to those platforms — see [Platforms](/docs/mcp/platforms/discord).
### Next
- [Posts and drafts](/docs/mcp/tools/posts-and-drafts)
- [Media, memory, and workspaces](/docs/mcp/tools/media-memory-workspaces)
---
# Brand memory
Source: https://www.dunsocial.com/docs/memory/brand-memory
Memory is where you save facts about you or your brand. The AI uses these when it writes, so it stays accurate and on-brand.
### What to save
- Who you are and what you do.
- Your products, features, and pricing.
- Words and phrases you like to use.
- Things to avoid saying.
- Any facts you do not want the AI to get wrong.
### How it works
1. Open **Memory** from the sidebar.
2. Add memories as short notes. You can group them into collections.
3. When you write with AI, it searches your memories for anything relevant and uses it.
This uses semantic search, which means it finds related notes even when the wording is different. You do not have to match exact keywords.
### Tips
- Keep each memory short and focused on one fact.
- Update memories when things change, like a new price or a new product.
- Everyone in the workspace benefits, so the AI writes consistently across your team.
---
# Memory collections
Source: https://www.dunsocial.com/docs/memory/memory-collections
Memories are grouped into collections. A collection is a named group of related facts, like "Brand voice" or "Product facts". Each one has a colour so it is easy to spot.
### Private and shared collections
- **Shared collections** are visible to everyone in the workspace. Use these for facts the whole team should write from, like your brand voice or product details.
- **Private collections** are visible only to you. Use these for your own notes and drafts. They show a small lock.
Your workspace starts with a default shared collection. You can add as many as you like.
### Group your memory
1. Open **Memory** from the sidebar.
2. Click **New collection**, give it a name, pick a colour, and choose private or shared.
3. Add memories to it, or move existing memories in.
Grouping keeps memory tidy and lets you pick exactly which facts the AI should use for a given post.
---
# How memory improves your posts
Source: https://www.dunsocial.com/docs/memory/memory-improves-your-posts
Memory is what makes AI drafts sound like you instead of generic.
### How it shapes a response
When you write with AI, it searches your selected collections for facts that relate to your request. It finds related notes even when the wording is different, then uses them to ground the draft. So the post uses your real product details, your preferred words, and avoids anything you told it to skip.
### It gets better over time
The more you save, the more the AI has to work with:
- Add or correct facts to give future drafts better context.
- Saving examples of your voice teaches it your tone and phrasing.
- Shared collections keep the whole team's posts consistent.
A good habit: whenever the AI gets something wrong, save the correction as a memory. Review future drafts before publishing to check that the correction is reflected.
---
# Save and use memory in AI studio
Source: https://www.dunsocial.com/docs/memory/memory-in-ai-studio
AI studio can both read your memory and add to it while you work.
### Use memory
1. Open **AI studio** from the composer.
2. Click **collections** near the message box.
3. Pick the collections you want the AI to use.
Now when you ask for a post, the AI searches those collections and pulls in anything relevant, so the draft matches your brand.
### Save memory
You do not need to leave the chat to save a fact. Just tell the studio, for example "remember that our brand voice is warm and direct", and it stores that as a new memory. It can also update or remove memories when you ask.
You can also add memory on the **Memory** page by saving a note to a collection.
---
# Post to Bluesky
Source: https://www.dunsocial.com/docs/platforms/post-to-bluesky
Connect your Bluesky account to publish posts. Bluesky is generally available.
### Connect
1. Open **Connect**.
2. Find **Bluesky** and click **Connect**.
3. Enter your Bluesky login details in the connect dialog.
4. Your account shows as connected.
### What is supported
- Text posts.
- Images.
- Scheduling and publishing right away.
### Gotchas
- Use the credentials Bluesky asks for when connecting.
- If the account disconnects, reconnect it from the Connect screen. DunSocial keeps the connection fresh in the background.
---
# Post to Discord
Source: https://www.dunsocial.com/docs/platforms/post-to-discord
Publish text messages and attachments to a text or announcement channel in the connected Discord server.
### Connect
Open **Connect**, click **Connect** on Discord, authorize the DunSocial bot, and pick the server. Each workspace can connect one Discord server.
### What is supported
- Text messages (up to 2,000 characters).
- Up to 10 attachments (images and video). Total request size 25 MB.
- A **channel picker** in compose. `channelId` is required; `channelName` is optional.
- Scheduling and publishing right away.
### Gotchas
- Choose a channel before you schedule. Posts without a channel will not publish.
- One Discord server per workspace. Reconnect Discord to switch servers.
- V1 is text and attachments only — no embed builder, forums, polls, or Discord analytics.
- If the bot is removed from the server, reconnect Discord from the Connect screen.
---
# Post to Facebook Pages
Source: https://www.dunsocial.com/docs/platforms/post-to-facebook
Publish to a **Facebook Page you manage**. Personal Facebook profiles are not supported. This is **limited beta** — request access, then connect the Page.
### Request access
1. Open **Connect**.
2. Find **Facebook Page** and start the beta request.
3. Enter the **Page name or URL**.
4. Submit the request.
Once you are approved, you can connect the Page and start posting.
### Connect
After approval, click **Connect**, log in with Facebook, and pick the Page. DunSocial shows the **Page name**, not the person who authenticated.
### What is supported
- Page feed posts: text, one link, and photos.
- Up to 20 images. No video, Reels, Stories, Groups, or ads.
- Scheduling and publishing right away (DunSocial’s scheduler, not Facebook’s).
### Gotchas
- You must have `CREATE_CONTENT` permission on the Page.
- Facebook Pages are images-only in v1. Use another network for video.
- Access is refreshed automatically. If the Page disconnects, reconnect it from the Connect screen.
- Until Meta App Review is live, only testers and admins on the DunSocial Meta app can complete OAuth.
---
# Post to Instagram
Source: https://www.dunsocial.com/docs/platforms/post-to-instagram
Publish to Instagram. This is in **beta**, so you request access first.
### Request access
1. Open **Connect**.
2. Find **Instagram** and start the beta request.
3. Enter your Instagram identifier.
4. Submit the request.
Once approved, you can connect and start posting.
### Connect
After approval, click **Connect** on Instagram, log in, and approve access.
### What is supported
- Feed **image** posts (JPEG, or PNG/WebP/GIF converted to JPEG at publish).
- **Carousel** posts with several images (same image types).
- **Reels** (video).
- **Stories** (one image or one video). Images convert to JPEG at publish. Meta does not accept a story caption.
- Captions and alt text (feed, carousel, and Reels).
- Scheduling and publishing right away.
### Gotchas
- Instagram needs media on every post, so add at least one image or video.
- Meta only accepts JPEG images. We convert PNG, WebP, and GIF (first frame) when the post publishes. The gallery original is unchanged.
- Reels and other videos can take a few minutes for Instagram to process. A timeout is not a broken connection — we keep waiting and retry the same container.
- Instagram access lasts a long time but is refreshed automatically. If it disconnects, reconnect from the Connect screen.
---
# Post to LinkedIn
Source: https://www.dunsocial.com/docs/platforms/post-to-linkedin
Connect your personal LinkedIn profile to publish posts. LinkedIn (personal) is generally available.
### Connect
1. Open **Connect**.
2. Find **LinkedIn** and click **Connect**.
3. Log in to LinkedIn and approve access.
4. You return to DunSocial with LinkedIn connected.
### What is supported
- Text posts to your personal profile.
- Up to 20 images, **or** exactly one video (MP4 or QuickTime / MOV). Do not mix video and images in the same post.
- Scheduling and publishing right away.
### Gotchas
- This connects your personal profile. To post as a company, use **LinkedIn Business Pages** instead.
- Video posts support one clip only. Prefer MP4; size is limited by DunSocial upload caps (512 MB).
- LinkedIn access is refreshed automatically in the background. If the account disconnects, reconnect it from the Connect screen.
---
# Post to LinkedIn Business Pages
Source: https://www.dunsocial.com/docs/platforms/post-to-linkedin-business-pages
Publish posts to your company LinkedIn Page. This is in **beta**, so you request access first.
### Request access
1. Open **Connect**.
2. Find **LinkedIn Business** and start the beta request.
3. Enter your **company name** and your **LinkedIn Page URL**.
4. Submit the request.
Once you are approved, you can connect the Page and start posting.
### Connect
After approval, click **Connect** on LinkedIn Business, log in, and approve access to your Page.
### What is supported
- Posts published as your company Page.
- Images or exactly one video (MP4/MOV). Do not mix video and images.
- Scheduling and publishing right away.
### Gotchas
- You must manage the LinkedIn Page you want to post to.
- Access is refreshed automatically. If the Page disconnects, reconnect it from the Connect screen.
---
# Post to Pinterest
Source: https://www.dunsocial.com/docs/platforms/post-to-pinterest
Publish image Pins to Pinterest boards, and refresh organic Pin metrics (impressions, clicks, saves) on the analytics dashboard.
### Connect
Open **Connect**, click **Connect** on Pinterest, log in, and approve access. DunSocial uses Standard Pinterest API access (production Pins and analytics — not the Trial sandbox).
### What is supported
- Image Pins (board, title, description, optional destination link).
- Scheduling and publishing right away.
- Organic Pin analytics on the analytics page (impressions, outbound clicks, saves, reactions) plus follower counts.
### Gotchas
- Pinterest is image based, so add an image to your Pin.
- If the account disconnects, reconnect it from the Connect screen.
- Analytics look back up to 90 days per Pinterest's API window.
---
# Post to Reddit
Source: https://www.dunsocial.com/docs/platforms/post-to-reddit
Publish posts to subreddits. Connect Reddit from the Connect screen, then compose with a title, community, and post type.
### Connect
1. Open **Connect**.
2. Find **Reddit** and click **Connect**.
3. Log in to Reddit and approve access.
Once connected, add Reddit as a destination when you compose.
### What is supported
- Text (self), link, image, and video posts.
- A **title**, which Reddit requires.
- Choosing the **subreddit** to post to.
- Post flair and common rule flags (NSFW, spoiler).
- Scheduling and publishing right away.
### Gotchas
- Every subreddit has its own rules. Make sure your post follows them, or Reddit may reject it.
- If the account disconnects, reconnect it from the Connect screen.
---
# Post to Slack
Source: https://www.dunsocial.com/docs/platforms/post-to-slack
Publish text messages and files to a public or private channel in the connected Slack workspace.
### Connect
Open **Connect**, click **Connect** on Slack, and authorize the DunSocial publish app. Each workspace connects one Slack team. This is a separate Slack app from the Slack agent in Settings → Integrations — connect Slack again here even if the agent is already installed.
### What is supported
- Text messages (up to 4,000 characters).
- Up to 10 attachments (images and video). Per-file cap 50 MB.
- A **channel picker** in compose. `channelId` is required; `channelName` is optional.
- Scheduling and publishing right away.
### Gotchas
- Choose a channel before you schedule. Posts without a channel will not publish.
- Public channels are joined automatically when you publish. For a private channel, invite the DunSocial Slack app into that channel first.
- File attachments require the bot to be in the channel. If Slack asks you to reconnect, do that from Connect so the publish app can pick up `channels:join`.
- One Slack team per workspace. Reconnect Slack to switch teams.
- V1 is text and attachments only — no DMs, thread replies, Block Kit, or Slack analytics.
- If the publish app is uninstalled from Slack, reconnect Slack from the Connect screen.
---
# Post to Threads
Source: https://www.dunsocial.com/docs/platforms/post-to-threads
Publish posts to Threads. This is in **beta**, so you request access first.
### Request access
1. Open **Connect**.
2. Find **Threads** and start the beta request.
3. Enter your **Threads username**.
4. Submit the request.
Once approved, you can connect and start posting.
### Connect
After approval, click **Connect** on Threads, log in, and approve access.
### What is supported
- Text posts.
- Images and video.
- Scheduling and publishing right away.
### Gotchas
- Threads access lasts a long time but is still refreshed automatically. If it disconnects, reconnect from the Connect screen.
---
# Post to TikTok
Source: https://www.dunsocial.com/docs/platforms/post-to-tiktok
Connect your TikTok account to schedule and publish videos. TikTok is in **limited beta** — request access from Connect before you can authorize the app.
### Connect
1. Open **Connect**.
2. Find **TikTok** and request beta access with your TikTok username.
3. After approval, click **Connect**, log in with TikTok, and approve `video.publish`.
4. You return to DunSocial with TikTok connected.
### What is supported
- Direct Post of a single video to your TikTok profile.
- Caption/title, privacy level, and comment / duet / stitch toggles.
- Scheduling and publishing right away.
- MCP tools: `schedule_tiktok_post` and `publish_tiktok_now`.
### Gotchas
- Until TikTok finishes auditing the DunSocial app, posts may be limited to **private / self-only** visibility.
- Videos are pulled from DunSocial media hosting (`media.dunsocial.com`). That domain must stay verified in the TikTok developer portal.
- Photo posts are not supported yet.
- If the account disconnects, reconnect it from the Connect screen. DunSocial refreshes tokens in the background.
---
# Post to X (Twitter)
Source: https://www.dunsocial.com/docs/platforms/post-to-x-twitter
Connect your X account to publish posts and threads. X is generally available to everyone.
### Connect
1. Open **Connect**.
2. Find **X** and click **Connect**.
3. Log in to X and approve access.
4. You return to DunSocial with X connected.
### What is supported
- Single posts.
- Threads (multiple posts in a row).
- Images and video.
- Scheduling and auto-schedule best times.
### Gotchas
- X limits how many posts you can send in a month. You can view your monthly cap usage so you do not run out.
- X access tokens are short lived. DunSocial refreshes them for you in the background, but if the account ever disconnects, just reconnect it from the Connect screen.
---
# Post to YouTube
Source: https://www.dunsocial.com/docs/platforms/post-to-youtube
Connect your YouTube channel to publish **Shorts**. DunSocial does not upload regular YouTube videos — landscape and long-form clips are rejected.
### Connect
1. Open **Connect**.
2. Find **YouTube** and click **Connect**.
3. Log in with your Google account and approve access to your channel.
4. You return to DunSocial with YouTube connected.
### What is supported
- Publishing YouTube Shorts (vertical or square, 3 minutes or less).
- Scheduling and publishing right away.
- DunSocial appends `#Shorts` when it is missing so the clip lands on the Shorts shelf.
### Gotchas
- Landscape videos and clips longer than 3 minutes are rejected. They will not publish as regular YouTube videos.
- CLI and MCP uploads need width, height, and duration on the media asset so DunSocial can confirm the clip is a Short.
- YouTube may show a note about channel requirements when you connect. Follow the on-screen guidance if it appears.
- If the channel disconnects, reconnect it from the Connect screen. DunSocial keeps the connection fresh in the background.
- YouTube also caps how many videos a channel can upload per day. DunSocial cannot raise that limit — wait for YouTube to reset it (usually within 24 hours) and try again.
---
# Manage scheduled posts
Source: https://www.dunsocial.com/docs/scheduling/manage-scheduled-posts
The **Posts** area shows everything you have scheduled and everything already published.
### Views
- **List**: A simple list of upcoming and past posts.
- **Calendar**: See your posts laid out by day. Handy for spotting gaps or busy days. The calendar shows how many posts are queued.
### Filter
You can filter posts by status, such as scheduled, published, failed, or cancelled, and by social account. This helps you focus on one platform or one state at a time.
### From here you can
- Open a post to see its details.
- Reschedule it to a new time.
- Cancel it so it does not go out.
- Delete it.
If a post ever fails to publish, it shows a failed status so you can review and try again. Turn on failure emails in notification settings to hear about it right away.
---
# Reschedule or cancel
Source: https://www.dunsocial.com/docs/scheduling/reschedule-or-cancel
Plans change. You can move or stop any scheduled post before it publishes.
### Reschedule
1. Open **Posts**.
2. Find the scheduled post.
3. Open it and choose **Reschedule**.
4. Pick a new date and time.
5. Confirm.
The post keeps its content and just moves to the new time.
### Cancel
1. Open the scheduled post.
2. Choose **Cancel**.
3. Confirm.
The post will not publish. It stays in your list marked as cancelled so you have a record.
### Delete
If you want to remove a post entirely, choose **Delete** instead of cancel.
### Notifications
If you have reschedule emails turned on, you get a note when a post is moved. See "Notification preferences" to control these.
---
# Schedule a post
Source: https://www.dunsocial.com/docs/scheduling/schedule-a-post
Scheduling lets you write now and publish later. DunSocial sends the post for you at the time you pick.
### Steps
1. Write your post in the composer.
2. Choose the accounts to post to.
3. Click **Schedule**.
4. Pick a date and time.
5. Confirm.
Your post now appears in **Posts** with a scheduled status.
### Good to know
- Times use your workspace timezone. Set the right timezone in Settings so posts go out when you expect.
- You can schedule the same post to several platforms at once.
- Not sure when to post? Try **Smart times** to let DunSocial suggest a good slot.
- You can change or cancel a scheduled post any time before it goes out. See "Reschedule or cancel".
### Notifications
Based on your notification settings, you can get an email when a post is scheduled, one hour before it publishes, and when it publishes or fails.
---
# Smart times and best time to post
Source: https://www.dunsocial.com/docs/scheduling/smart-times-best-time-to-post
Not sure when to post? DunSocial can pick a good time for you.
### Auto-schedule
When scheduling, choose the **auto-schedule** option to place your post at a suggested best time instead of picking one by hand.
### How it decides
- DunSocial looks at activity patterns to find slots when your audience is more likely to be active.
- For X, it can use your account activity to suggest the next good slot.
- If it does not have enough of your own data yet, it falls back to sensible default times.
### Steps
1. In the composer, click **Schedule**.
2. Turn on auto-schedule (best time).
3. DunSocial suggests a time. You can accept it or adjust it.
4. Confirm.
### Tip
Your workspace timezone matters here. Make sure it is set correctly in Settings so suggested times line up with your real audience.
---
# SDK
Source: https://www.dunsocial.com/docs/sdk
The TypeScript SDK is a small client over the same REST API the CLI uses. Install `dunsocial-sdk`, pass a personal access token, and schedule or publish from your app.
## Start here
## OpenAPI
The language-agnostic contract lives at [`sdks/openapi/openapi.yaml`](https://github.com/thisuxhq/dunpostsapp/blob/main/sdks/openapi/openapi.yaml) and is served at `https://api.dunsocial.com/api/openapi.json`.
For raw HTTP details, use the [API reference](/docs/api). This tab covers the TypeScript helpers only.
---
# Authentication
Source: https://www.dunsocial.com/docs/sdk/getting-started/authentication
Create a token in the app under **Settings → CLI**. It is shown once. Format: `dun_pat_…`.
The client sends `Authorization: Bearer ` and `User-Agent: dunsocial-sdk/`. Workspace-scoped calls also send `X-Workspace-Id`. `workspaces.list` does not need a workspace id.
### Scopes
| Scope | SDK methods |
|-------|-------------|
| `workspace:read` | `workspaces.*`, `accounts.*`, `personalization.get` |
| `workspace:write` | `personalization.set`, `personalization.clear` |
| `posts:read` | `posts.list`, `posts.get`, `posts.validate`, `drafts.list`, `drafts.get` |
| `posts:schedule` | `posts.schedule`, `reschedule`, `cancel`, threads |
| `posts:publish` | `posts.publish`, `posts.publishThread` |
| `posts:delete` | `posts.delete` |
| `drafts:write` | `drafts.create`, `update`, `delete` |
| `media:read` / `media:write` | Gallery vs `media.upload` |
| `memory:read` | Collection GET and memory list |
| `memory:write` | `memory.search`, save, collection writes |
Missing token or workspace throws `DunSocialError` with `code: missing_config` before any request. `401` is an invalid PAT. `403` is the wrong workspace, a missing scope, or a suspended member. `402` is an unpaid workspace — see `error.billingUrl`.
PATs cannot call AI, billing, team admin, webhook endpoint CRUD, or CLI token admin. Those stay session-only.
---
# Install
Source: https://www.dunsocial.com/docs/sdk/getting-started/install
The package is ESM, `fetch` only, and runs on Node 20+, Bun, and Cloudflare Workers.
Constructor options:
| Option | Env fallback | Notes |
|--------|--------------|--------|
| `token` | `DUN_TOKEN` | Personal access token (`dun_pat_…`) |
| `workspaceId` | `DUN_WORKSPACE_ID` | Required for workspace-scoped methods |
| `baseUrl` | `DUN_API_URL` | Defaults to `https://api.dunsocial.com` |
| `fetch` | — | Inject for tests |
| `timeoutMs` | — | Defaults to 60s |
Same env names as the [CLI](/docs/cli/getting-started/authentication).
---
# Media
Source: https://www.dunsocial.com/docs/sdk/media
`media.upload` hides the three-step API: request an upload URL, PUT the bytes, then complete the gallery row.
Accepted input: `Uint8Array`, `ArrayBuffer`, or `Blob`. Images max 8MB (`image/jpeg`, `image/png`, `image/gif`, `image/webp`). Video max 512MB (`video/mp4`, `video/quicktime`, `video/webm`).
A failed PUT after the URL is issued does not create a gallery row. If the presign expired, call `upload()` again.
List and delete use the same gallery as the app: `media.list()`, `media.get(id)`, `media.delete(id)`.
---
# Posts
Source: https://www.dunsocial.com/docs/sdk/posts
`publish` queues the row (`status: scheduled`). `wait(id)` polls until `published`, `failed`, or `cancelled`.
### Validate
`POST /api/posts/validate` returns HTTP 200 even when the post is invalid:
Pass `throwOnInvalid: true` to raise `DunSocialError` instead.
### Threads
X only. Two to 25 tweets. Singular `socialAccountId`.
SDK `mediaIds` map to API `mediaUrls`. Platform metadata (Reddit, Instagram, Pinterest, TikTok, Discord) is the same as the [API posts guide](/docs/api/posts/schedule-and-publish). Facebook Pages need no metadata — text, one link, or photos (63,206 characters, images only).
---
# Webhooks
Source: https://www.dunsocial.com/docs/sdk/webhooks
The SDK only verifies deliveries. Creating endpoints still needs a session — see the [API webhooks guide](/docs/api/webhooks).
The signature is HMAC-SHA256 of `{timestamp}.{rawBody}`, sent as `X-DunSocial-Signature: v1=…`. Pass the **raw** body. The default replay window is 300 seconds.
Events: `post.scheduled`, `post.rescheduled`, `post.cancelled`, `post.published`, `post.publish_failed`, `social_account.reconnect_required`.
---
# Webhook events
Source: https://www.dunsocial.com/docs/webhooks/webhook-events
A webhook fires whenever an event you subscribed to happens. You choose which events each endpoint listens for.
### Events you can subscribe to
- **post.scheduled** when a post is scheduled.
- **post.rescheduled** when a scheduled post is moved.
- **post.cancelled** when a scheduled post is cancelled.
- **post.published** when a post goes out.
- **post.publish_failed** when a post fails to publish.
- **social_account.reconnect_required** when a connected account needs reconnecting.
For the API catalog and signature headers, see [Manage endpoints](/docs/api/webhooks).
### Deliveries
Each event sends a signed request to your URL. If your endpoint does not return a success response, DunSocial retries a few times. You can review every attempt in the delivery log.
---
# Webhooks
Source: https://www.dunsocial.com/docs/webhooks/webhooks
Webhooks let DunSocial notify your own systems when something happens, such as a post publishing. This is aimed at developers who want to build custom automations.
### Set up a webhook
1. Open **Settings**, then **Webhooks**.
2. Add a new endpoint.
3. Enter a **name** and the **URL** where events should be sent.
4. Choose which **events** you want to receive.
5. Save. Make sure the endpoint is **enabled**.
### Security
Each endpoint has a **secret**. Use it to verify that incoming requests really came from DunSocial via `X-DunSocial-Signature` (`v1=` HMAC-SHA256 of `{timestamp}.{rawBody}`). Full header list and verify steps: [API webhooks](/docs/api/webhooks).
### Deliveries
You can see a log of delivery attempts for each endpoint, including:
- The event type.
- The delivery status.
- How many attempts were made.
- The last response code and any error.
### Tip
If deliveries are failing, check that your URL is reachable and returns a success response. You can review the error details in the delivery log.
---
# Invite your team
Source: https://www.dunsocial.com/docs/workspaces-and-team/invite-your-team
Bring teammates into your workspace to plan and post together.
### Steps
1. Open **Settings**, then **Team**.
2. Click **Invite**.
3. Enter your teammate's email.
4. Choose a **role** (owner, admin, or member).
5. Send the invite.
Your teammate gets an invite and joins the workspace once they accept.
### Good to know
- Only owners and admins can invite people.
- Each seat on your plan is one member. If you are out of seats, add more in Billing before inviting.
- You can remove members later from the same Team screen.
- See "Roles and permissions" to understand what each role can do.
---
# Roles and permissions
Source: https://www.dunsocial.com/docs/workspaces-and-team/roles-and-permissions
DunSocial has three roles. Each one has a different level of access.
### The three roles
- **Owner**: Full access. Can do everything, including changing member roles and transferring ownership.
- **Admin**: Can manage the team, connect and disconnect social accounts, manage billing, and change workspace settings.
- **Member**: Can create and manage their own content using the accounts already connected to the workspace.
### Who can do what
| Action | Owner | Admin | Member |
| --- | --- | --- | --- |
| Create and schedule posts | Yes | Yes | Yes |
| Use connected accounts | Yes | Yes | Yes |
| Connect or disconnect accounts | Yes | Yes | No |
| Invite or remove members | Yes | Yes | No |
| Manage billing and seats | Yes | Yes | No |
| Change workspace settings | Yes | Yes | No |
| Change member roles | Yes | No | No |
### Notes
- Admins cannot change roles. Only an owner can.
- Admins can suspend members but not other admins.
- Set a person's role when you invite them, and change it later from **Settings**, then **Team** (owners only).
---
# Switch workspaces
Source: https://www.dunsocial.com/docs/workspaces-and-team/switch-workspaces
If you belong to more than one workspace, you can move between them quickly.
### Steps
1. Find your current workspace name near the top of the sidebar.
2. Click it to open the workspace menu.
3. Pick the workspace you want to switch to.
DunSocial loads that workspace with its own accounts, posts, and settings.
### Create another workspace
From the same menu, choose to create a new workspace. This is useful for a new brand or client. See "Create your workspace" for the setup steps.
### Good to know
- Each workspace has its own plan and billing.
- Your role can be different in each workspace.
- Switching does not affect anything in your other workspaces.
---
# Workspaces explained
Source: https://www.dunsocial.com/docs/workspaces-and-team/workspaces-explained
A workspace is a container for everything you do in DunSocial.
### What a workspace holds
- Connected social accounts.
- Posts, drafts, and scheduled content.
- Your media Gallery.
- Brand memory and voice settings.
- Team members and their roles.
- Its own plan and billing.
### Why use more than one
- Keep separate brands or clients apart.
- Give different teams their own space.
- Keep accounts, content, and billing cleanly divided.
### Your workspace settings
Open **Settings**, then **Workspace**, to change the name, address, timezone, and other details. Owners and admins can manage these settings.
Each workspace has its own timezone, which scheduling uses. Set it to match where you post from.