Skip to content

Latest commit

History

History
407 lines (276 loc) · 8.19 KB

File metadata and controls

407 lines (276 loc) · 8.19 KB

Programmatic API Reference

Use SubstackClient directly for programmatic access to Substack.

import{SubstackClient}from'@postcli/substack/client';

Constructor

constclient=newSubstackClient({token: string,// Base64-encoded auth tokenpublicationUrl: string,// e.g. "https://myname.substack.com"maxRequestsPerSecond?: number,// Rate limiting (optional)});

Methods

testConnectivity

Test if authentication is valid by fetching a single post from your publication.

testConnectivity(): Promise<boolean>

Returns:true if the token works, false otherwise.

constok=awaitclient.testConnectivity();

ownProfile

Get your own Substack profile. Extracts author byline from your publication's first post.

ownProfile(): Promise<Profile>

Returns:Profile with fields: id, name, handle, bio, photoUrl, publications[].

constme=awaitclient.ownProfile();console.log(me.name,me.handle);console.log(me.publications.map(p=>p.subdomain));

profileForSubdomain

Get a profile by publication subdomain.

profileForSubdomain(subdomain: string): Promise<Profile>
constprofile=awaitclient.profileForSubdomain('nicolascole77');console.log(profile.name,profile.bio);

listPosts

List posts from a publication's archive.

listPosts(options?: {subdomain?: string,// Defaults to own publicationlimit?: number,// Default: 10offset?: number,// Default: 0}): Promise<PreviewPost[]>

Returns: Array of PreviewPost with fields: id, title, subtitle, slug, publishedAt, canonicalUrl, coverImage, wordcount, reactionCount, commentCount, restacks, authors[], truncatedBody, publicationSubdomain.

// Own postsconstmyPosts=awaitclient.listPosts({limit: 20});// Another publicationconstposts=awaitclient.listPosts({subdomain: 'platformer',limit: 5});

getPost

Get a full post by slug.

getPost(slug: string,subdomain?: string): Promise<FullPost>

Returns:FullPost with all PreviewPost fields plus: htmlBody, description, postTags[], youtubeUrls[].

constpost=awaitclient.getPost('my-first-post');console.log(post.title,post.htmlBody);

getPostById

Get a post by numeric ID. Searches the archive to find the slug, then fetches the full post.

getPostById(id: number,subdomain?: string): Promise<FullPost>

If no subdomain is given, searches all your publications. Paginates through the archive in pages of 50 with up to 20 attempts per subdomain.

constpost=awaitclient.getPostById(12345);

listNotes

List notes from the reader feed. Filters feed items to only those with typeBucket=notes.

listNotes(options?: {limit?: number,// Default: 10}): Promise<Note[]>

Returns: Array of Note with fields: id, body, author ({ name, handle }), publishedAt, reactions, childrenCount.

Automatically paginates through the feed until limit notes are collected or no more pages are available.

constnotes=awaitclient.listNotes({limit: 25});

listComments

List comments on a post.

listComments(postId: number,options?: {subdomain?: string,// Defaults to ownlimit?: number,// Default: 50}): Promise<Comment[]>

Returns: Array of Comment with fields: id, body, authorName, authorId, date, reactions, childrenCount.

constcomments=awaitclient.listComments(12345,{limit: 10});

getFeed

Get the authenticated user's reader feed.

getFeed(options?: {tab?: string,// "for-you", "subscribed", or category slugcursor?: string,// Pagination cursor}): Promise<{items: SubstackFeedItem[],nextCursor?: string}>

Returns: Feed items and an optional cursor for the next page.

constfeed=awaitclient.getFeed({tab: 'subscribed'});for(constitemoffeed.items){console.log(item.type,item.entity_key);}// Paginateconstpage2=awaitclient.getFeed({tab: 'subscribed',cursor: feed.nextCursor});

getProfileFeed

Get a user's profile feed (their comments and notes).

getProfileFeed(userId: number,options?: {cursor?: string,}): Promise<{items: SubstackFeedItem[],nextCursor?: string}>
constprofile=awaitclient.ownProfile();constmyFeed=awaitclient.getProfileFeed(profile.id);

getComment

Get a single comment with its parent comments (ancestors in the thread).

getComment(commentId: number): Promise<{comment: any,parentComments: any[],}>
constdetail=awaitclient.getComment(54321);console.log(detail.parentComments.length,'parents');console.log(detail.comment.body);

getCommentReplies

Get replies to a comment (children threads).

getCommentReplies(commentId: number): Promise<{rootComment: any,branches: {comment: any,descendants: any[]}[],}>

Each branch contains a direct reply and its nested descendants.

constreplies=awaitclient.getCommentReplies(54321);for(constbranchofreplies.branches){console.log(branch.comment.body);console.log(' nested:',branch.descendants.length);}

publishNote

Publish a new note. Text is converted to ProseMirror format. Supports **bold** markdown.

publishNote(text: string,options?: {replyMinimumRole?: string,// Default: "everyone"}): Promise<{id: number}>
constresult=awaitclient.publishNote('Just shipped **v2.0**!');console.log('Published note:',result.id);

replyToNote

Reply to a note or comment.

replyToNote(parentId: number,text: string): Promise<{id: number}>
constreply=awaitclient.replyToNote(98765,'Thanks for sharing!');console.log('Reply ID:',reply.id);

commentOnPost

Comment on a post. Substack converts the plain text body to ProseMirror server-side.

commentOnPost(postId: number,text: string,subdomain?: string): Promise<{id: number}>
constcomment=awaitclient.commentOnPost(12345,'Great article!');console.log('Comment ID:',comment.id);

reactToPost

React to a post (heart).

reactToPost(postId: number,subdomain?: string): Promise<void>
awaitclient.reactToPost(12345);

reactToComment

React to a comment or note (heart).

reactToComment(commentId: number): Promise<void>
awaitclient.reactToComment(54321);

restackPost

Restack a post to your feed.

restackPost(postId: number): Promise<void>
awaitclient.restackPost(12345);

restackNote

Restack a note/comment to your feed.

restackNote(commentId: number): Promise<void>
awaitclient.restackNote(98765);

getSubdomain

Get the default subdomain for this client (extracted from the publication URL).

getSubdomain(): string
constsub=client.getSubdomain();// "myname"

Static Methods

SubstackClient.verifyToken

Verify an auth token is valid by testing reader feed access.

staticverifyToken(token: string): Promise<boolean>
constvalid=awaitSubstackClient.verifyToken(myToken);

SubstackClient.discoverProfile

Auto-discover user profile from a token and optional substack.lli JWT. Used during login to find the user's handle and publications without prompting.

staticdiscoverProfile(token: string,lliToken?: string): Promise<{handle: string|null,name: string|null,id: number,publications: {subdomain: string,name: string}[],subscriptions: {subdomain: string,name: string}[],}|null>

SubstackClient.extractUserId

Extract the userId from a substack.lli JWT token.

staticextractUserId(lliToken?: string): number|null