Nimply Developers

Data model

Workspaces, channels, posts, and media — the mental model in five minutes.

Four resources cover almost everything the API does. Get these straight and every endpoint becomes predictable.

Workspace  ─ the tenant your API key belongs to
 ├── Channels   ─ connected social accounts (Instagram, LinkedIn, …)
 ├── Posts      ─ content, each targeting exactly ONE channel
 ├── Media      ─ imported images/videos, attachable to posts
 └── Webhooks   ─ endpoints that receive events about the above

Workspace — the boundary of everything

Every credential is bound to one workspace: an API key (nim_live_...) is created inside a workspace, and an OAuth access token (nim_oat_...) is issued for the workspace the user picked during consent. There is no cross-workspace access — a key can only see the channels, posts, and media of its own workspace, and resources from other workspaces return 404, not 403.

GET /v1/workspace tells you which workspace you're in and which scopes your credential has (grantedScopes).

Channels — where posts go

A channel is one connected social account. The type field has 13 values across 9 platforms:

PlatformChannel types
FacebookFACEBOOK_PAGE, FACEBOOK_GROUP
InstagramINSTAGRAM_PROFESSIONAL, INSTAGRAM_PERSONAL
Twitter/XTWITTER
LinkedInLINKEDIN_PROFILE, LINKEDIN_PAGE
TikTokTIKTOK_PERSONAL, TIKTOK_BUSINESS
YouTubeYOUTUBE
PinterestPINTEREST
Google BusinessGOOGLE_BUSINESS
ThreadsTHREADS

Channels are connected in the Nimply app (the API can't connect them — that requires the platform's own OAuth dance). Before publishing, check that isConnected is true and tokenStatus is not NEEDS_RECONNECT. Each channel also has a timezone and a posting schedule (GET /v1/channels/{id}/schedule) — the weekday time slots used by "next_slot" scheduling.

Posts — one post, one channel

A post targets exactly one channel. When you call POST /v1/posts with several channelIds, Nimply creates one post per channel and returns them all — each with its own id, status, and lifecycle. Keep this in mind when you later schedule, poll, or delete: you operate on individual per-channel posts.

Status lifecycle

                      request-approval
          ┌─────────────────────────────────────┐
          │                                     ▼
        DRAFT ◄───────── reject ─────── PENDING_APPROVAL
          │ ▲                                   │
          │ └── approve (no publish time) ──────┤
          │                                     │ approve (has a
          │ schedule / publish now / next_slot  │  future publish time)
          ▼                                     │
       SCHEDULED ◄──────────────────────────────┘

          │  publish time reached
          ├──────────────► PUBLISHED   (live on the platform)
          └──────────────► FAILED      (the platform rejected it)

       ARCHIVED  — archived in the Nimply app; find with ?status=ARCHIVED
  • DRAFT — created, nothing will happen until you act ("schedule": "draft" is the default).
  • PENDING_APPROVAL — a draft sent for review via POST /v1/posts/{id}/request-approval. Approving returns it to SCHEDULED (if it has a future publish time) or DRAFT; rejecting returns it to DRAFT.
  • SCHEDULED — queued for a publish time. Note that "publish now" is also asynchronous: the post briefly sits in SCHEDULED while the queue processes it.
  • PUBLISHED — successfully live. Published posts can't be edited or deleted via the API.
  • FAILED — publishing was attempted and rejected by the platform.
  • ARCHIVED — archived in the Nimply app; excluded from your normal workflow but still readable.

Content types

The contentType field selects the format on the platform:

ValueMeaning
POSTA standard feed post (default). Multiple media on a POST become a carousel — order follows mediaIds.
REELA short-form vertical video (Reels-style surface).
STORYAn ephemeral story.
VIDEOA regular video post (e.g. a YouTube upload — use title too).

Platform-specific options

POST /v1/posts covers the fields every platform understands: content, title, contentType, mediaIds, schedule. Four platforms support more than that, and each has a dedicated create endpoint that accepts its full option set and validates platform-required fields at request time:

PlatformEndpointNotable options
YouTubePOST /v1/posts/youtubetitle (required), videoType (video/short), category, visibility, license, notifySubscribers, allowEmbedding, madeForKids
TikTokPOST /v1/posts/tiktokprivacyLevel (required), allowComments, allowDuet, allowStitch, brandContent, brandOrganic
PinterestPOST /v1/posts/pinterestboardId (required), link, altText
LinkedInPOST /v1/posts/linkedinvisibility (PUBLIC/CONNECTIONS)

Two helper endpoints supply the values these options need: GET /v1/channels/{id}/pinterest/boards lists a channel's boards, and GET /v1/channels/{id}/tiktok/creator-info returns the privacy levels a TikTok account allows (plus Duet/Stitch availability and the max video duration).

Rule of thumb: use the generic endpoint for simple cross-platform posting, and the platform endpoint whenever you need platform features. Facebook, Instagram, Twitter/X, and Threads have no extra options — the generic endpoint is all they need.

Media — upload once, attach anywhere

Media assets are imported by URL (POST /v1/media with a publicly reachable url) into workspace storage, then referenced by id in a post's mediaIds array — in display order. Assets are workspace-level, not post-level: one uploaded image can be attached to many posts. Types are IMAGE, VIDEO, GIF, and DOCUMENT. The url returned on a media asset is a signed delivery URL that expires after 24 hours — re-fetch the asset for a fresh one, and don't store it.

Webhooks — events about posts and channels

Webhooks are registered per workspace and fire for post events (post.created, post.updated, post.published, post.failed, post.deleted, and the approval trio post.approval_requested / post.approved / post.rejected) and channel events (channel.disconnected). Every delivery envelope carries the workspaceId plus the affected postId/channelId, and is signed with your endpoint's secret.

Next steps

On this page