Use the CLI to create and monitor Comment or Amplify tasks, upload media, review drafts, queue posts, and inspect performance.
Install & authenticate#
Requires Node.js 20 or newer and a checkout of the HumanPost repository. The package is currently installed from source. Run this from the repository root:
npm install -g ./cli
humanpost --version
humanpost --help
Create an API key in Settings → Integrations. The Publishing preset covers this draft workflow. Add analytics:read for reports, workspace:read for asset browsing, and media:read for asset download URLs.
Set HUMANPOST_API_KEY through your shell or secrets manager. Alternatively, save a default profile from a private key file, then verify your connection:
cat /secure/path/api-key | humanpost auth login --key-stdin
humanpost doctor
humanpost context --json
humanpost accounts list --json
doctor should return connected: true, the discovered tool count, and your company/scopes. Check the company before creating a draft. Copy an accountId from accounts list for submission. On POSIX, profiles require a directory with permissions 700 and a config file with permissions 600. The CLI rejects symbolic links and shared credential files. Keys never appear in command arguments or diagnostics, and saved keys stay bound to their API server.
Named profiles and test servers
cat /secure/path/api-key | humanpost auth login --key-stdin --profile production
humanpost doctor --profile production
humanpost accounts list --profile production --json
Pass --profile production on every command using that profile. Environment credentials take precedence. HUMANPOST_API_BASE or --base-url chooses another API server; saved credentials are bound to their exact server URL. HTTP is supported on loopback for local testing.
Inspect stored account profiles#
humanpost accounts list --platform tiktok --json
humanpost accounts get ACCOUNT_ID --json
Requires accounts:read. List returns {data:[...]}; get returns one account directly. Both include profilePictureUrl, bio (strings or null), and warmupSearchTerms (an array, empty when absent). Setup values may still be requested; pending profile edits retain previous values until worker approval. GIMI can display and compare stored configuration. These reads do not independently verify the live social profile or completed warm-up. Creation still sends warmup.searchTerms (1–5 terms); longer historical lists remain readable.
Update account profiles#
Edit username, display name, bio and picture in one asynchronous request. Save changed fields in profile.json; add a ready image upload ID as profilePictureUploadId. Requires accounts:write to submit and accounts:read to poll. Two fully completed requests per account per rolling 30 days are included; platform restrictions also apply.
humanpost accounts profile-allowance ACCOUNT_ID --json
humanpost accounts update-profile ACCOUNT_ID --file profile.json --idempotency-key profile-october-1 --json
humanpost accounts profile-request ACCOUNT_ID REQUEST_ID --json
humanpost accounts profile-request ACCOUNT_ID REQUEST_ID --wait --wait-timeout 300 --json
Keep the same body and key on retries. --wait leaves server work running if it times out. See the profile quickstart, JSON example, costs and platform limits.
Upload a profile photo#
humanpost uploads local ./profile.png --json
humanpost uploads get UPLOAD_ID --json
# Put the ready upload's url into account.json as profilePictureUrl.
humanpost accounts create --file account.json --json
Use JPEG, PNG, or WebP up to 10 MB for profile photos. Use the ready upload's url, not its temporary signed uploadUrl. Direct image URLs remain supported and are decoded into owned assets before setup. Download the actual image from Drive first; viewer pages cannot be used as photos. The account response and worker setup use the same validated image. Existing stored photos remain until a replacement is approved.
Create and monitor Comment or Amplify tasks#
Choose the Tasks key preset in Settings → Integrations. It includes task read, write, screenshot, account read, and usage scopes. Select an active TikTok or Instagram account and check its task availability and credits.
humanpost tasks types --account-id ACCOUNT_ID --json
humanpost usage --json
Save this as task.json. Replace ACCOUNT_ID and the post URL with your account and target post. Change type to comment_video for a standalone Comment. Amplify includes Repost + Like and Comment under one public task.
{
"type": "amplify_video",
"accountId": "ACCOUNT_ID",
"externalReference": "partner-order-123",
"payload": {
"targetVideoUrl": "https://www.tiktok.com/@creator/video/123456",
"commentText": "hi"
}
}
humanpost tasks create --file task.json --idempotency-key partner-order-123 --json
humanpost tasks get TASK_ID --json
humanpost tasks list --type amplify_video --all --json
humanpost tasks events TASK_ID --all --json
humanpost tasks evidence TASK_ID --all --json
humanpost tasks get TASK_ID --wait --wait-timeout 300 --json
Store the returned taskId. Reuse the same payload and key on creation retries. The original ID follows Comment attempts and Amplify components. Business hours and worker availability can defer work. pending_approval means waiting for HumanPost review; completed means approved. A wait timeout includes the current task and does not cancel work. Screenshot links expire; request new links when needed.
Use availableActions from the task response to show controls. Cancel remaining work with a reason; resume reopens blocked Amplify components on their original account without another charge.
humanpost tasks cancel TASK_ID --data '{"reason":"Customer cancelled"}' --json
humanpost tasks resume TASK_ID --json
Cancellation preserves history and cannot undo platform actions. Comment approval prevents cancellation. Amplify refunds only when neither component was approved. Review and payouts remain with HumanPost.
Create your first draft#
1. Save this as files.json, replacing the paths with two local JPG, PNG, WebP, or HEIC images. Carousels require 2–20 images, up to 50 MB each. Paths resolve from your terminal's current directory.
[
"./slide1.png",
"./slide2.png"
]
humanpost uploads local-batch --file files.json --state upload-progress.json --json
The result contains ordered results with an uploadId and status: ready for each image. Retain upload-progress.json; rerunning this command reuses finished uploads.
2. Save this as draft.json. Replace UPLOAD_1 and UPLOAD_2 with the returned IDs in slide order.
{
"media": [
"UPLOAD_1",
"UPLOAD_2"
],
"caption": "Our launch is here"
}
humanpost drafts create --file draft.json --idempotency-key launch-draft-1 --json
humanpost posts content POST_ID --json
humanpost posts preview POST_ID --json
Replace POST_ID with the returned postId. The post remains a draft until you submit it. Open the media URLs from preview to inspect the finished images. Keep the same payload and key when retrying this creation; choose a new key for a different draft.
Edit and preview artwork#
Optional: add text before submitting. Copy versionId from posts content into expectedVersionId and retain the same upload IDs. Save this as edit.json:
{
"expectedVersionId": "VERSION_ID",
"slides": [
{
"image": "UPLOAD_1",
"textElements": [
{
"content": "Launch day",
"style": {
"fontSize": 48,
"positionY": 20
}
}
]
},
{
"image": "UPLOAD_2",
"textElements": []
}
]
}
humanpost drafts update POST_ID --file edit.json --json
humanpost posts render POST_ID --idempotency-key launch-preview-1 --wait --json
humanpost posts preview POST_ID --json
Rendering returns a jobId, and --wait polls it until complete or the terminal timeout. Check preview status: ready and open its mediaUrls before submitting. Editing the artwork invalidates its preview; render the new version with a new operation key. expectedVersionId rejects stale edits.
Submit and track#
Save targets.json using the accountId returned earlier:
{
"accountIds": [
"ACCOUNT_ID"
]
}
humanpost posts queue POST_ID --file targets.json --idempotency-key launch-submit-1 --json
humanpost posts get POST_ID --json
humanpost posts list --all --json
Submission returns the post's status and per-account targets. Managed accounts can require approval; a queued post has not yet been published. To delay eligibility, add scheduledAfter as an ISO timestamp; expiresAt prevents release after its deadline. Worker-local windows and capacity determine the actual posting time. See Scheduling posts.
Performance reports and assets#
Save report.json with your UTC-midnight date range: from is inclusive and to is exclusive. These dates illustrate September 2026; choose dates with collected analytics for your company.
{
"from": "2026-09-01T00:00:00Z",
"to": "2026-10-01T00:00:00Z",
"groupBy": "account",
"comparePrevious": true,
"topLimit": 10
}
humanpost analytics report --file report.json --idempotency-key september-report-1 --wait --json
humanpost workspace folders --search launch --all --json
humanpost usage --json
Reports include observed growth, prior-period comparisons, latest cumulative top-post counters, and coverage/freshness. Missing observations do not imply zero performance. Reports and workspace browsing require their corresponding scopes. See the API reference for grouping and filter fields.
Automation & recovery#
Results are JSON on stdout; errors go to stderr. --json also makes errors machine-readable, including requestId and details. Reads and keyed writes retry transient failures at most twice. Supply a stable key for retries across invocations; generated keys only protect retries within one invocation.
Remote imports use durable server jobs. Save this as urls.json and replace the example URL with a public HTTPS image:
{
"items": [
{
"kind": "image",
"sourceUrl": "https://example.com/slide.jpg"
}
]
}
humanpost uploads batch --file urls.json --idempotency-key launch-assets-1 --wait --json
humanpost jobs get JOB_ID --wait --json
humanpost drafts create --help
humanpost drafts create --schema
humanpost mcp config --client cursor
--wait defaults to 300 seconds; --wait-timeout changes it. Timeouts leave server jobs running. --all follows cursors, including empty search pages, with a default 1,000-page bound (--max-pages). Request timeouts default to 60 seconds (--timeout). Local upload state contains temporary signed URLs and requires permissions 600 on POSIX. Keep it private and avoid concurrent writers to the same path. Ctrl-C aborts terminal work with exit 130.
Images must contain valid bytes matching their declared type, one image, and at most 40 megapixels. Convert unsupported HEIC files to JPG. Completed uploads use a separate validated copy, so the original signed upload URL cannot change media already accepted by HumanPost.
Troubleshooting#
Exit codes: 0 success, 1 network/server/job failure, 2 validation, 3 authentication/scope, 4 conflict, 130 interrupted. Include the returned requestId when requesting support.
Private file permissions (exit 3)
On POSIX, use chmod 700 on the HumanPost config directory and chmod 600 on config.json and local upload state files. Files must belong to you and must not be symbolic links. State files contain temporary signed upload URLs; keep them private.
invalid_media_specs (exit 2)
Upload a valid image whose bytes match its MIME type: one image, at most 40 megapixels. Convert unsupported HEIC files to JPG. Videos must meet the technical requirements shown in the error hint.
rate_limit_unavailable (exit 1)
HumanPost temporarily cannot verify request limits, so the operation stops before running. Retry shortly using the original payload and idempotency key.
Authentication or scope error (exit 3)
Run humanpost auth status and humanpost doctor. Pass --profile NAME on every command that uses a named profile. Create a key with the required scopes if access is missing.
idempotency_conflict (exit 4)
Retry the same operation with its original payload and key. For a new or changed operation, choose a new key.
version_conflict (exit 4)
Run humanpost posts content POST_ID, merge your edit into the current slides, and use the returned versionId as expectedVersionId.
Upload interrupted (exit 1)
Rerun local-batch with the same manifest, files, server, and --state path. Ready upload IDs are reused.
Job still running (exit 1)
Use the returned jobId with humanpost jobs get JOB_ID --wait. A terminal timeout does not cancel server work.
Job partially failed (exit 1)
Use --json to inspect error.details.job.results. Reuse successful upload IDs and submit only failed items as a new batch with a new key.
analytics_unavailable (exit 1)
Complete the analytics V3 backfill before retrying. Reports require ready rollups; absent observations do not mean zero performance.