0
# Post Operations
1
2
Modern NPF (Neue Post Format) post creation, editing, and deletion with media upload support, plus legacy post format methods for backward compatibility.
3
4
## Capabilities
5
6
### NPF Post Creation
7
8
Creates a new post using the modern Neue Post Format with support for media uploads and complex content layouts.
9
10
```javascript { .api }
11
/**
12
* Creates or reblogs an NPF post
13
* @param blogIdentifier - Blog name or URL where the post will be created
14
* @param params - Post content and configuration parameters
15
* @returns Promise resolving to created post information
16
*/
17
createPost(blogIdentifier: string, params: NpfPostParams | NpfReblogParams): Promise<any>;
18
19
interface NpfPostParams {
20
/** An array of NPF content blocks to be used to make the post */
21
content: NpfContentBlock[];
22
/** An array of NPF layout objects to be used to lay out the post content */
23
layout?: NpfLayoutBlock[];
24
/** The initial state of the new post. Defaults to "published" */
25
state?: 'published' | 'queue' | 'draft' | 'private' | 'unapproved';
26
/** The exact future date and time (ISO 8601 format) to publish the post */
27
publish_on?: string;
28
/** The exact date and time (ISO 8601 format) in the past to backdate the post */
29
date?: string;
30
/** Tags to associate with the post */
31
tags?: string[];
32
/** A source attribution for the post content */
33
source_url?: string;
34
/** Whether this should be a private answer, if this is an answer */
35
is_private?: boolean;
36
/** A custom URL slug to use in the post's permalink URL */
37
slug?: string;
38
/** Who can interact with this when reblogging */
39
interactability_reblog?: 'everyone' | 'noone';
40
}
41
42
interface NpfReblogParams extends NpfPostParams {
43
/** The unique public identifier of the Tumblelog that's being reblogged from */
44
parent_tumblelog_uuid: string;
45
/** The unique public post ID being reblogged */
46
parent_post_id: string;
47
/** The unique per-post hash validating that this is a genuine reblog action */
48
reblog_key: string;
49
/** Whether or not to hide the reblog trail with this new post */
50
hide_trail?: boolean;
51
/** Array of specific reblog trail item indexes to exclude from your reblog */
52
exclude_trail_items?: number[];
53
}
54
```
55
56
**Usage Examples:**
57
58
```javascript
59
const fs = require('node:fs');
60
61
// Create a simple text post
62
await client.createPost('myblog', {
63
content: [
64
{
65
type: 'text',
66
text: 'Hello, Tumblr! This is my first NPF post.',
67
},
68
],
69
tags: ['hello', 'first-post'],
70
});
71
72
// Create a post with image upload
73
await client.createPost('myblog', {
74
content: [
75
{
76
type: 'image',
77
media: fs.createReadStream('/path/to/image.jpg'),
78
alt_text: 'A beautiful sunset over the mountains',
79
},
80
{
81
type: 'text',
82
text: 'Amazing sunset from my hike today!',
83
},
84
],
85
tags: ['photography', 'nature'],
86
});
87
88
// Create a scheduled post
89
await client.createPost('myblog', {
90
content: [
91
{
92
type: 'text',
93
text: 'This post is scheduled for the future!',
94
},
95
],
96
state: 'queue',
97
publish_on: '2024-12-25T12:00:00Z',
98
});
99
100
// Reblog a post with additional content
101
await client.createPost('myblog', {
102
content: [
103
{
104
type: 'text',
105
text: 'Great points in this post!',
106
},
107
],
108
parent_tumblelog_uuid: 'original-blog-uuid',
109
parent_post_id: '12345678901',
110
reblog_key: 'AbCdEfGh',
111
});
112
```
113
114
### NPF Post Editing
115
116
Edits an existing NPF post with updated content, layout, or metadata.
117
118
```javascript { .api }
119
/**
120
* Edit an NPF post
121
* @param blogIdentifier - Blog name or URL containing the post
122
* @param postId - The ID of the post to edit
123
* @param params - Updated post content and configuration parameters
124
* @returns Promise resolving to updated post information
125
*/
126
editPost(blogIdentifier: string, postId: string, params: NpfPostParams | NpfReblogParams): Promise<any>;
127
```
128
129
**Usage Examples:**
130
131
```javascript
132
// Edit post content
133
await client.editPost('myblog', '12345678901', {
134
content: [
135
{
136
type: 'text',
137
text: 'Updated content for this post!',
138
},
139
],
140
tags: ['updated', 'edited'],
141
});
142
143
// Update post tags only
144
await client.editPost('myblog', '12345678901', {
145
content: [], // Keep existing content
146
tags: ['new-tag', 'another-tag'],
147
});
148
149
// Change post state
150
await client.editPost('myblog', '12345678901', {
151
content: [], // Keep existing content
152
state: 'draft', // Move to drafts
153
});
154
```
155
156
### Post Deletion
157
158
Permanently deletes a post from a blog.
159
160
```javascript { .api }
161
/**
162
* Deletes a given post
163
* @param blogIdentifier - Blog name or URL containing the post
164
* @param postId - The ID of the post to delete
165
* @returns Promise resolving when deletion completes
166
*/
167
deletePost(blogIdentifier: string, postId: string): Promise<any>;
168
```
169
170
**Usage Examples:**
171
172
```javascript
173
// Delete a post
174
await client.deletePost('myblog', '12345678901');
175
176
// Delete multiple posts
177
const postsToDelete = ['12345678901', '12345678902', '12345678903'];
178
for (const postId of postsToDelete) {
179
await client.deletePost('myblog', postId);
180
}
181
```
182
183
### Legacy Post Creation (Deprecated)
184
185
Creates a post using the legacy post format. This method is deprecated in favor of NPF methods.
186
187
```javascript { .api }
188
/**
189
* Creates a post on the given blog using legacy format
190
* @deprecated Legacy post creation methods are deprecated. Use NPF methods.
191
* @param blogIdentifier - Blog name or URL
192
* @param params - Legacy post parameters
193
* @returns Promise resolving to created post information
194
*/
195
createLegacyPost(blogIdentifier: string, params: Record<string, any>): Promise<any>;
196
```
197
198
**Usage Examples:**
199
200
```javascript
201
// Create legacy text post (deprecated - use createPost instead)
202
await client.createLegacyPost('myblog', {
203
type: 'text',
204
title: 'My Post Title',
205
body: 'This is the post body content.',
206
tags: 'tag1,tag2,tag3',
207
});
208
209
// Create legacy photo post (deprecated)
210
await client.createLegacyPost('myblog', {
211
type: 'photo',
212
caption: 'Photo caption',
213
source: 'https://example.com/image.jpg',
214
});
215
```
216
217
### Legacy Post Editing (Deprecated)
218
219
Edits a post using the legacy post format. This method is deprecated in favor of NPF methods.
220
221
```javascript { .api }
222
/**
223
* Edits a given post using legacy format
224
* @deprecated Legacy post creation methods are deprecated. Use NPF methods.
225
* @param blogIdentifier - Blog name or URL
226
* @param params - Legacy post parameters including post ID
227
* @returns Promise resolving when edit completes
228
*/
229
editLegacyPost(blogIdentifier: string, params: Record<string, any>): Promise<any>;
230
```
231
232
**Usage Examples:**
233
234
```javascript
235
// Edit legacy post (deprecated - use editPost instead)
236
await client.editLegacyPost('myblog', {
237
id: '12345678901',
238
title: 'Updated Post Title',
239
body: 'Updated post body content.',
240
});
241
```
242
243
### Legacy Post Reblogging (Deprecated)
244
245
Reblogs a post using the legacy post format. This method is deprecated in favor of NPF methods.
246
247
```javascript { .api }
248
/**
249
* Reblogs a given post using legacy format
250
* @deprecated Legacy post creation methods are deprecated. Use NPF methods.
251
* @param blogIdentifier - Blog name or URL
252
* @param params - Legacy reblog parameters
253
* @returns Promise resolving when reblog completes
254
*/
255
reblogPost(blogIdentifier: string, params: Record<string, any>): Promise<any>;
256
```
257
258
**Usage Examples:**
259
260
```javascript
261
// Reblog post (deprecated - use createPost with reblog params instead)
262
await client.reblogPost('myblog', {
263
id: '12345678901',
264
reblog_key: 'AbCdEfGh',
265
comment: 'Great post!',
266
});
267
```
268
269
## NPF Content Block Types
270
271
```javascript { .api }
272
// Content block type union
273
type NpfContentBlock = AudioBlock | ImageBlock | LinkBlock | PaywallBlock | TextBlock | VideoBlock;
274
275
// Text content block
276
interface TextBlock {
277
type: 'text';
278
text?: string;
279
subtype?: 'heading1' | 'heading2' | 'quirky' | 'quote' | 'indented' | 'chat' | 'ordered-list-item' | 'unordered-list-item';
280
[prop: string]: any;
281
}
282
283
// Image content block with media upload support
284
interface ImageBlock {
285
type: 'image';
286
media: ReadStream | MediaObject;
287
alt_text?: string;
288
caption?: string;
289
[prop: string]: any;
290
}
291
292
// Video content block with media upload support
293
interface VideoBlock {
294
type: 'video';
295
media: ReadStream | MediaObject;
296
[prop: string]: any;
297
}
298
299
// Audio content block with media upload support
300
interface AudioBlock {
301
type: 'audio';
302
media: ReadStream | MediaObject;
303
title?: string;
304
artist?: string;
305
album?: string;
306
[prop: string]: any;
307
}
308
309
// Link content block
310
interface LinkBlock {
311
type: 'link';
312
url?: string;
313
title?: string;
314
description?: string;
315
author?: string;
316
site_name?: string;
317
display_url?: string;
318
poster?: MediaObject[];
319
[prop: string]: any;
320
}
321
322
// Paywall content block
323
interface PaywallBlock {
324
type: 'paywall';
325
text?: string;
326
title?: string;
327
url?: string;
328
[prop: string]: any;
329
}
330
331
// Media object for referencing existing media
332
interface MediaObject {
333
url: string;
334
type?: string;
335
width?: number;
336
height?: number;
337
original_dimensions_missing?: boolean;
338
has_original_dimensions?: boolean;
339
cropped?: boolean;
340
}
341
```
342
343
## NPF Layout Block Types
344
345
```javascript { .api }
346
// Layout block type union
347
type NpfLayoutBlock = NpfLayoutAsk | NpfLayoutRows;
348
349
// Ask layout for question/answer posts
350
interface NpfLayoutAsk {
351
type: 'ask';
352
blocks: readonly number[];
353
attribution: {
354
type: 'user' | 'blog' | 'link' | 'app';
355
url?: string;
356
name?: string;
357
avatar?: MediaObject[];
358
};
359
}
360
361
// Rows layout for organizing content blocks
362
interface NpfLayoutRows {
363
type: 'rows';
364
display: readonly {
365
blocks: readonly number[];
366
mode?: {
367
type: 'carousel' | 'photoset';
368
};
369
}[];
370
truncate_after?: 1;
371
}
372
```
373
374
## Media Upload Support
375
376
NPF posts support media uploads through Node.js ReadStream objects:
377
378
```javascript
379
const fs = require('node:fs');
380
381
// Upload image from file system
382
await client.createPost('myblog', {
383
content: [
384
{
385
type: 'image',
386
media: fs.createReadStream('./photo.jpg'),
387
alt_text: 'Description of the image',
388
},
389
],
390
});
391
392
// Upload video
393
await client.createPost('myblog', {
394
content: [
395
{
396
type: 'video',
397
media: fs.createReadStream('./video.mp4'),
398
},
399
],
400
});
401
402
// Upload audio
403
await client.createPost('myblog', {
404
content: [
405
{
406
type: 'audio',
407
media: fs.createReadStream('./song.mp3'),
408
title: 'Song Title',
409
artist: 'Artist Name',
410
},
411
],
412
});
413
```
414
415
## Authentication Requirements
416
417
All post operations require OAuth authentication with all four credentials:
418
- `consumer_key`
419
- `consumer_secret`
420
- `token`
421
- `token_secret`
422
423
Additionally, you must have posting permissions for the specified blog.