SDK
Install the PublishQ SDK for typed access to posts, accounts, media, and workspaces from a backend, a cron job, or an agent you built yourself.
@publishq/sdk is the official SDK for PublishQ. Typed calls for posts, accounts, media and workspaces, in the language your backend already speaks.
Install
npm install @publishq/sdkQuick start
import PublishQ from '@publishq/sdk';
const publishq = new PublishQ({ apiKey: process.env.PUBLISHQ_API_KEY! });
const { data } = await publishq.accounts.list();
for (const account of data?.accounts ?? []) {
console.log(account.platform, account.accountName);
}Server-side only
A pq_live_ key is a secret. Call the SDK from a backend, a script, a cron job or an agent you run yourself. Never ship it to a browser.
Errors are returned, not thrown
Every call resolves to { data, error } and never throws on an HTTP error, so a failed publish is a value you check rather than an exception that unwinds your job.
const { data, error } = await publishq.posts.create({
content: 'Shipped.',
accounts: [{ accountId: '<account-id>' }],
publishNow: true,
});
if (error) {
// The API's own error body, not a wrapper's summary of it
console.error(error);
return;
}
console.log(data.id);Posts
// A post with no schedule and no publishNow is saved as a draft
const { data: draft } = await publishq.posts.create({
content: 'Draft for review',
accounts: [{ accountId: '<account-id>' }],
});
// Scheduled, to several accounts, with per-account text
await publishq.posts.create({
content: 'The long version, for the platforms that allow it',
accounts: [
{ accountId: '<linkedin-account-id>' },
{
accountId: '<x-account-id>',
postOverrides: { content: 'The short version' },
},
],
scheduledAt: '2026-08-01T09:00:00.000Z',
});
await publishq.posts.list({ page: 1, limit: 20 });
await publishq.posts.get('<post-id>');
await publishq.posts.update('<post-id>', { content: 'Updated text' });
await publishq.posts.delete('<post-id>');
await publishq.posts.removeAccount('<post-id>', '<account-id>');Accounts
const { data } = await publishq.accounts.list({ platform: ['TIKTOK'] });
// TikTok has no default privacy level, and the options depend on the account.
// The privacyLevel you send must be one of the returned privacyLevelOptions.
const { data: info } = await publishq.accounts.getTikTokCreatorInfo('<account-id>');Media
const { data: media } = await publishq.media.upload({ file });
await publishq.media.list({ page: 1, limit: 20 });
await publishq.media.get('<media-id>');Pass the returned id in a post's mediaIds.
Workspaces
await publishq.workspaces.list();
await publishq.workspaces.get('<workspace-id>');
await publishq.workspaces.create({ name: 'Client A' });Runtime schemas
The SDK also ships Zod schemas for every request shape, so a body assembled at runtime can be checked before it is sent. This is useful when the values come from a model rather than from your own code.
import { zCreatePostAccount } from '@publishq/sdk';
const parsed = zCreatePostAccount.safeParse(whateverTheAgentProduced);
if (!parsed.success) {
// Ask the agent to try again, without spending an API call
}Related
- Build an agent on the social media SDK
- MCP Server if the agent already speaks MCP
- CLI if a shell command is enough