API reference

Schedule posts on your connected accounts from your own tools. Every endpoint is authenticated with an API key generated in Settings → API keys. The API is included in the Pro and Enterprise plans, free trial included.

Base URL — https://hello-socials.com/api/v1

Prefer to publish by asking Claude or ChatGPT? Connect the MCP server

Authentication

Pass your key as a Bearer token. Keys are stored hashed — the plaintext value is shown only once, when you create it. A key carries scopes: read for GET endpoints, write for POST.

Authorization: Bearer hs_live_xxxxxxxxxxxxxxxxxxxx
GET/api/v1/accounts

Lists your connected accounts. Call it once and store the ids in your tool's configuration: a display name changes when you rename a page, an id never does.

curl https://hello-socials.com/api/v1/accounts \
  -H "Authorization: Bearer hs_live_xxx"
{
  "data": [
    {
      "id": "cmnj4p2z0000abcd",
      "network": "TWITTER",
      "username": "hellowesign",
      "displayName": "HelloWeSign",
      "status": "connected"
    },
    {
      "id": "cmnj53dc0000efgh",
      "network": "LINKEDIN_PAGE",
      "username": "hellowesign",
      "displayName": "HelloWeSign",
      "status": "connected"
    }
  ]
}

status tells you whether an account needs reconnecting before you send it anything: connected, expiring_soon or expired.

POST/api/v1/posts

Creates a scheduled post: text only, with images, or with one video. X, LinkedIn, Facebook and Threads accept text on its own; Instagram, Pinterest and TikTok require an image or a video. YouTube is not available through the API yet.

curl -X POST https://hello-socials.com/api/v1/posts \
  -H "Authorization: Bearer hs_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "content": "Audit trail de signature électronique : retrouver chaque étape d'\''un document.",
    "socialAccountIds": ["cmnj53dc0000efgh"],
    "scheduledAt": "2026-09-04T09:30:00Z",
    "media": [
      { "url": "https://example.com/images/audit-trail.png" }
    ]
  }'

Video to TikTok and an Instagram reel in one call:

curl -X POST https://hello-socials.com/api/v1/posts \
  -H "Authorization: Bearer hs_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "content": "Nouvelle fonctionnalité #meetarabic",
    "socialAccountIds": ["<tiktok-account-id>", "<instagram-account-id>"],
    "scheduledAt": "2026-10-20T18:00:00+02:00",
    "media": [
      { "url": "https://example.com/videos/demo.mp4", "type": "video", "coverTimestampMs": 2500 }
    ],
    "postType": "reel",
    "tiktok": { "privacyLevel": "PUBLIC_TO_EVERYONE", "disableComment": false }
  }'

Body fields

contentRequired. The post text.
socialAccountIdsRequired. Array of account ids from GET /accounts. One id is the common case; several send the same text to several accounts at once.
scheduledAtOptional. ISO 8601 with timezone, in the future.
mediaOptional. Array of { "url": "https://…" } objects, in display order. Or a single video: [{ "url": "https://…", "type": "video", "coverTimestampMs": 2500 }]: the cover is the frame at that moment (1 s by default), sent as an image to Instagram and Facebook and as a timestamp to TikTok; "thumbnailUrl" can provide a custom cover image instead. Required for Instagram, Pinterest and TikTok.
captionsOptional. { "<socialAccountId>": "caption" }: a caption for one account instead of content (e.g. a different TikTok caption). Accounts not listed use content.
postTypesOptional. { "<socialAccountId>": "post" | "reel" | "story" }: a format for one Instagram or Facebook account, overriding postType (e.g. two Facebook pages as posts, Instagram as a story).
postTypeOptional, Instagram and Facebook. "post" (default), "reel" (requires a video) or "story". A single Instagram video is published as a reel either way.
draftOptional. true saves the post as a draft (status DRAFT): nothing is published until you review and schedule it in HelloSocials, Posts › Drafts tab.
tiktokOptional, TikTok accounts only. privacyLevel (PUBLIC_TO_EVERYONE by default, or MUTUAL_FOLLOW_FRIENDS, FOLLOWER_OF_CREATOR, SELF_ONLY), title (90 characters max), disableComment, disableDuet, disableStitch (true by default), autoAddMusic (true by default), isCommercial with isOwnBrand or isPaidPartnership.

About scheduledAt

An ISO 8601 timestamp with an explicit timezone. A naive timestamp is rejected: it would be read in the server's timezone, and a post meant for 9:30 would go out at another hour. Omit the field to publish as soon as possible — the publisher runs every 5 minutes.

"2026-09-04T09:30:00Z"        ✓
"2026-09-04T11:30:00+02:00"   ✓
"2026-09-04T09:30:00"         ✗ no timezone
"2026-09-04"                  ✗

About media

Pass public https URLs. Each image is downloaded when the post is created, converted to JPEG (1080 px on the longest side) and stored on our side: the post does not depend on your URL any more, even if it goes out days later. Accepted sources: JPEG, PNG, GIF (first frame) and WebP, 20 MB max each. If one image fails, nothing is created and the response says which one. Video: a single item { "url", "type": "video", "thumbnailUrl"? }, MP4 or MOV, 50 MB max, stored as is (no re-encoding); Facebook, Instagram, TikTok, X, LinkedIn and Threads accept it, Pinterest does not.

Images per network

TWITTER4
LINKEDIN9
LINKEDIN_PAGE9
FACEBOOK10
THREADS10
INSTAGRAM10
PINTEREST1
TIKTOK35

Validation is all-or-nothing

If any target account fails validation, nothing is created and the response lists what went wrong. This avoids a post going out on one network while silently failing on another.

{
  "error": "Caption exceeds the character limit for at least one target network",
  "details": {
    "accounts": [{ "id": "cmnj4p2z0000abcd", "network": "TWITTER", "limit": 280, "length": 412 }]
  }
}
GET/api/v1/posts/{id}

Returns the state of a post, network by network. Publishing is asynchronous: creation answers PENDING, and the real outcome only exists once the worker has run.

{
  "data": {
    "id": "cmtlg7ca2000004jp",
    "status": "PUBLISHED",
    "scheduledAt": "2026-09-04T09:30:00.000Z",
    "publishedAt": "2026-09-04T09:30:12.000Z",
    "media": [{ "url": "https://…/posts/…/k3J9x.jpg" }],
    "results": [
      {
        "socialAccountId": "cmnj53dc0000efgh",
        "network": "LINKEDIN_PAGE",
        "status": "PUBLISHED",
        "externalId": "urn:li:share:7123456789",
        "error": null
      }
    ]
  }
}

Character limits

X is counted the way X counts: every URL is 23 characters whatever its length, emoji and CJK characters count as 2. Other networks count raw characters.

TWITTER280
LINKEDIN3000
LINKEDIN_PAGE3000
FACEBOOK63206
THREADS500
INSTAGRAM2200
PINTEREST500
TIKTOK2200

Errors

Errors return a JSON body with an error field, and details when a specific account or field is at fault.

400Invalid body, unknown account, unsupported network, content too long, too many images, image unreachable or invalid, bad date
401Missing, invalid, revoked or expired API key
403The key lacks the required scope, or the account has no active Pro or Enterprise subscription
404Post not found for this key's owner