Docs › API reference › Providers

Providers API: platform limits and media rules

Read what each platform supports (text limits, media rules, settings) and why one may be locked, then build your client from it.

Updated

A provider is a platform OmniPosts can post to, such as Bluesky or LinkedIn. GET /v1/providers is the capability registry: for every provider it states what a post may contain, which extra settings it accepts, how to connect it, which numbers it can report, and whether it is open right now.

OmniPosts's own composer draws its screens from this registry and nothing is hard-coded. Your client can do the same and stay correct when limits or availability change.

List providers

The answer is { "items": [ ... ] } with one object per provider. This example is abridged to the parts that matter most. The values belong to one provider and differ for others, so always read them live.

curl https://omniposts.dev/v1/providers \
  -H "Authorization: Bearer omniposts_..."
{
  "items": [
    {
      "id": "bluesky",
      "displayName": "Bluesky",
      "tier": "FREE",
      "enabled": true,
      "lockedReason": null,
      "lockedKind": null,
      "auth": {
        "kind": "APP_PASSWORD",
        "fields": [
          { "name": "identifier", "label": "Handle or email", "help": "...", "secret": false },
          { "name": "appPassword", "label": "App password", "help": "...", "secret": true }
        ],
        "inputs": []
      },
      "text": { "maxLength": 300, "counter": "GRAPHEMES", "required": true },
      "media": {
        "maxImages": 4,
        "maxImageBytes": 2000000,
        "imageMimes": ["image/jpeg", "image/png", "image/webp"],
        "maxVideos": 0,
        "maxVideoBytes": 0,
        "videoMimes": [],
        "maxAltTextLength": 2000,
        "mediaRequired": false,
        "ingest": "UPLOAD"
      },
      "uiFields": [],
      "readback": "EXACT"
    }
  ]
}

Fields

Field Meaning
id, displayName The provider id you pass as providerId when connecting, and its name
tier FREE or GATED. A gated provider depends on an outside approval or a paid platform plan
enabled true when you can connect it and post to it now
lockedReason, lockedKind When enabled is false: one sentence of why, and a machine kind (below). Both are null when enabled
auth How to connect. See below
text maxLength, how it is counted (counter), and whether text is required
media Image and video rules
uiFields Extra per-channel settings a post can carry
readback How OmniPosts can check a post after sending: EXACT, SEARCH or NONE
analytics, accountAnalytics Which numbers the platform can report. See Reports
apiVersion, checkedDate, stale The platform API version OmniPosts targets, when it was last checked, and true if that was over 90 days ago

Text

maxLength is measured by counter:

  • GRAPHEMES counts what a person sees as one character (an emoji is one).
  • CODE_POINTS counts Unicode code points.
  • WEIGHTED counts with the platform's own weighting, where some characters count for more than one.

If required is true, a post with no text and no media is refused for that channel.

Media

Field Meaning
maxImages, maxVideos How many of each a post may carry. 0 means none
maxImageBytes, maxVideoBytes Largest file, in bytes
imageMimes, videoMimes Accepted types
maxAltTextLength Longest image description
mediaRequired true if a post must have an image or video
ingest UPLOAD (OmniPosts uploads the file) or URL (the platform fetches it from a public address)

A post cannot mix images and video. Upload files with Media, which also reports, per provider, what each file would be refused for.

Settings (uiFields)

Some platforms take extra options, such as a visibility or a title. Each entry has a name, a label, a type (TEXT, TEXTAREA, SELECT or TOGGLE), options (for SELECT), a defaultValue, whether it is required, some help, and a lockedValue (a value you must keep for now). Send values as strings in a target's settings map when you create a post:

A TOGGLE takes "true" or "false". A name that is not listed is refused for that channel as setting_unknown.

{ "channelId": "CHANNEL_ID", "settings": { "name": "value" } }

Why a provider is locked

lockedKind is one of:

Kind Meaning
platform_review Waiting for the platform's own app review or audit
paid_access The platform charges for posting and paid posting is not switched on
not_configured This OmniPosts server has no app credentials for the platform yet
switched_off Posting is switched off for another reason, such as a safety switch
upcoming Coming soon: OmniPosts has announced it, and it is not open to connect yet

While a provider is locked, connecting it is refused, and a post to an existing channel on it is rejected with channel_switched_off. Availability changes as reviews finish. lockedReason and lockedKind are for your integration and your logs: the OmniPosts app and website show every locked provider simply as "Coming soon", and the failure messages for a locked provider say only that ("X is coming soon to OmniPosts.", "Posting to X is paused for now, so this post wasn't sent."). See Channels and the Channels screen in the app.

How to use it

  • Fetch the registry when your app starts and cache it for a short time, not forever.
  • Validate text length and media against it before you call the API, using counter to count. The API checks again and answers per channel, so your check is a convenience.
  • Show a provider as "Coming soon" when enabled is false. Keep lockedReason and lockedKind for your logs and your own logic; do not show them to people.
  • Draw connect forms from auth.fields (and auth.inputs), and settings forms from uiFields.
  • Do not hard-code a list of providers or limits. New providers appear here first.