# Limits and versions Source: https://docs.native.no/native-api/limits > **Preview.** The Native API is not live yet. This page describes the planned interface; names and fields can change before access opens. Size and rate limits, timeouts, versions, formats, image URLs and polling intervals for the Native API, and what is planned but not available. > **Not live for partners yet.** Partner access to the Native API is not live yet. Partner sign-in with client credentials is in development, so a partner backend cannot call these tools today. The limits on this page are the ones that apply today to signed-in Native users. Anything marked **in development** is not available. This page collects the numbers that bound a call: how big, how often and how long. It also covers how versions will work, the formats each destination takes, how long image URLs last and how often to poll. ## Size and count limits | Limit | Value | | --- | --- | | Posts per `create_posts` call | 1 to 20. | | Library images (`mediaIds`) per `create_posts` call | Up to 10. | | Entries per `reschedule_posts` call | 1 to 25. | | Reference images per `regenerate_post_image` call | Up to 9 Native library URLs. The input schema allows 10, but Native refuses a list of more than 9 with `bad_request`, because the slide being redrawn takes the tenth slot. | | Request body | Up to 12 MiB. | | Image upload as base64 (`dataBase64`) | Up to 11 MiB of characters, which is an image of about 8 MiB. Native caps the image itself at 8 MiB. | | Caption length | Per destination, as `characterLimit` on each destination: 2,200 for Instagram and 63,206 for Facebook. Stories use their base platform’s limit. A limit of 0 means no limit is recorded. A caption over its limit is refused at scheduling. | | Access token lifetime | One hour at most. See [Authentication](https://docs.native.no/authentication). | ## Request rate Today the edge in front of `https://mcp.native.no/mcp` allows 120 requests a minute from one IP address, across every tool. It is not a quota per partner or per client. Past it, the edge answers HTTP 429 before the request reaches a tool, so there is no error envelope. Slow down and back off. Every HTTP request to the endpoint counts, including the ones the SDK sends when it connects. Keep one connected client for as long as its token is valid, rather than connecting for each call. Two other rate limits come back as codes. `upstream_429` means Native itself is rate limiting the call. `rate_limited` on a destination means the social platform refused it. Both are retryable after a wait. See [Errors](https://docs.native.no/native-api/errors). ## Timeouts - Calls normally return within seconds. - Writes that contact platforms, `schedule_post` and `publish_post_now`, can take much longer. The gateway waits up to **120 seconds** for Native, then answers `upstream_timeout`. The work may still be running, so read the current state before you retry. - Set your client’s request timeout above 120 seconds, for example 150 seconds. The MCP SDK’s default is lower, and a slow write can time out on your side after it has already succeeded on Native’s. - `get_generation_job` with the default `wait: true` holds the call for up to about 24 seconds while the job settles. TypeScript: ```ts const result = await client.callTool( { name: "publish_post_now", arguments: { id: postId } }, undefined, { timeout: 150_000 }, // above the 120 s the gateway waits for Native ); ``` Generation is always asynchronous. `create_posts` returns a `batchId` and `regenerate_post_image` returns a `jobId`. Poll them as described under [polling](https://docs.native.no/native-api/limits#polling). Do not hold a call open. ## Plan allowance Each workspace has an AI budget, counted in Native tokens, that comes with its plan. For a profile made with `create_profile` (in development), that is the partner’s plan. When the budget runs out, calls that use AI fail with `usage_limit_exceeded`. `retryable` is `false`, and `resetDate` says when the budget refills. Posts in a batch that hit it carry the same code. A workspace with no active subscription gets `subscription_required`. ## Versions > **In development.** Versioned endpoints are in development. Today there is one endpoint, `https://mcp.native.no/mcp`, and no version to pin. This section describes how versions will work when they ship. - `https://mcp.native.no/mcp` will always serve the latest version. - `https://mcp.native.no/mcp/v1` will serve version 1, pinned, beside it. Partners should call the versioned endpoint. - Every version takes the same token. The audience stays `https://mcp.native.no/mcp`, so you switch versions by changing only the URL. - The `initialize` and `server/discover` results report the version in `capabilities.experimental["no.native/partner-api"]`, as `{ version, latestVersion }`. When `latestVersion` is greater than `version`, a newer contract has shipped: read the changelog. initialize result, excerpt: ```json { "capabilities": { "experimental": { "no.native/partner-api": { "version": 1, "latestVersion": 1 } } } } ``` ### Notice and overlap - **Notice:** Native will announce a breaking change at least 2 weeks before it ships. - **Overlap:** the previous version will keep running for at least 4 weeks after the new one ships. After it shuts down, its versioned endpoint will answer HTTP 404. - **Changelog:** every change will be listed with its date and whether it is breaking. ### Breaking changes These will ship only as a new version: - Removing or renaming a tool, an input field or an output field. - Tightening input: a new required field, a narrower type or range, or a value that used to be accepted and is now refused. - Removing an enum value from output, or changing what an existing field, status or error code means. - Changing which error code a given failure returns, or turning a success into an error. - Changing a default. ### Additive changes These can ship at any time, without a new version: - New tools. - New optional input fields. - New output fields. - New error codes for new failure cases. - New enum values in output. - New `blocked` and `reason` codes. Build your client to tolerate them. Ignore fields you do not use, and treat a code you do not recognise as its `retryable` flag says. ## Formats The destinations that matter most to partners, as names from Native’s `Platform` enum: | Destination | Kind | Caption | Notes | | --- | --- | --- | --- | | `INSTAGRAM` | Feed | Yes, up to 2,200 characters. | Images must sit within Instagram’s aspect band of 0.75 to 1.91, or pre-flight refuses them with `image_aspect_invalid`. Carousels are supported. | | `INSTAGRAM_STORIES` | Story | **Published without a caption.** | Needs media: one image or one video. | | `FACEBOOK` | Feed | Yes, up to 63,206 characters. | | | `FACEBOOK_STORIES` | Story | **Published without a caption.** | Needs media: one image or one video. | Stories use the brand’s Instagram or Facebook connection. They never appear as channels of their own. `get_profile` lists the story destinations a brand can use in `storyDestinations`. A post whose only destinations are stories, and which has no media, is refused with `media_required`. ### Aspect ratios - Story targets are 9:16. Feed targets are 4:5. - `regenerate_post_image` renders at the ratio of the first destination that holds that slot: 9:16 for `INSTAGRAM_STORIES`, `FACEBOOK_STORIES` and `TIKTOK`, and 4:5 for `INSTAGRAM`, `FACEBOOK`, `LINKEDIN` and `TWITTER`. 4:5 is also the default. On a post with only story destinations, a regenerated image is 9:16. - Native has not yet confirmed that the first render of a stories-only post from `create_posts` or `create_draft` comes out 9:16. Until it does, check the dimensions of the image `view_post` returns. - Every destination on a post shares the same image in each slot, and a 9:16 image fails Instagram feed pre-flight. Put feed and story content in separate posts. Do not mix `INSTAGRAM` and `INSTAGRAM_STORIES` on one post. ### Times Send times as ISO 8601, with `Z` or a numeric offset, such as `2026-11-02T09:00:00+01:00`. The gateway converts them to UTC. ### Destination names Wherever a post’s destinations appear, in `platforms`, `destinations[].platform` or `platformResults[].platform`, they are uppercase `Platform` enum names such as `INSTAGRAM`. `get_profile` is the exception. Its `channels[].platform` and `storyDestinations` use lowercase channel names such as `instagram` and `instagram_stories`. ## Asset URLs Image URLs come back from `view_post` (`imageUrls`, `destinations[].imageUrls`), `get_generation_job` (`imageUrls`, `outputs[].imageUrl`) and `regenerate_post_image` (`images[].url`). They are plain public Google Cloud Storage URLs, of the form `https://storage.googleapis.com//...`. - They are unsigned and do not expire. You can show them directly or copy them. Anyone who has a URL can open the image. - A URL stops resolving only when its stored file is deleted, for example when `delete_profile` (in development) erases a client’s images. - Replacing or removing an image on a post does not guarantee that the old URL stops working. Native keeps image history so edits can be restored, and library images outlive their posts. Do not count on a post edit to revoke access to an old URL. - A changed image always has a new URL. The URL is part of the content digest, so a changed image also means a new `contentDigest`. ## Polling Native has no webhooks yet, so you poll. These are the intervals to use: | What | Call | Interval | Done when | Notes | | --- | --- | --- | --- | --- | | Profile build (in development) | `get_profile` | About every 60 seconds. | `onboarding.status` is `ready` or `failed`. | Typically 10 to 30 minutes. On `failed`, read `onboarding.error` and retry with `create_profile` and the same `externalId`. | | Offboarding (in development) | `deactivate_profile` or `delete_profile`, called again with the same arguments | Every 30 seconds. | `status` is `deactivated` or `deleted`. | Usually within minutes. Repeating the call is safe. | | Account connected | `get_profile` | Once the client has finished connecting, then every 10 seconds for up to 2 minutes. With a headless link (in development), start when `returnUrl` reports `status=connected`, or after `complete_connect`. | The channel has `health: "connected"` and `readiness.canPublish` is `true`. | `status=failed` needs a fresh link, not polling. | | Post generation | `get_post_batch_status` | Every 5 seconds for the first minute, then every 15 seconds, then at most every 30 seconds. | `settled` is `true` **and** `imagesPendingCount` is 0. | `settled` covers copy only, and images can still be rendering. Give up and alert after about 15 minutes. Failed items carry `error.code`. | | Image render | `get_generation_job` | Call it with the default `wait: true`, since each call already waits about 24 seconds. Or use `wait: false` every 5 seconds. | `status` is `completed` or `failed`. | Never call `regenerate_post_image` again to retry a render that is still running. Template renders (in development) take a few minutes, so expect several polls. | | Scheduled publish | `get_post_status` | Once, a few minutes after `scheduledAt`. Then every 5 minutes for 30 minutes. | Every destination’s `state` is `published` or `failed`. | `stuck` means overdue with no outcome: stop polling and escalate. While a destination reads `scheduled`, keep polling. `pending` means no provider holds it, so it will not go out on its own: schedule or publish it again. | | After `publish_post_now` | `get_post_status` | Every 10 seconds for 2 minutes, then every 60 seconds for 10 minutes. | Every destination is `published` or `failed`. | Only the destinations that came back `pending` (`publishing_in_progress`) in `publishResults` need polling. They read `scheduled` here until they land. | | Channel health | `get_profile` | Daily, and before scheduling. | No end: keep checking. | Act on `needs_reauth` and `disconnected`, and on `expiring_soon` (`tokenExpiresAt`), before publishing breaks. | For every poll, back off exponentially with jitter on errors that are retryable, and stop on errors that are not. ## Planned, not available These are planned. None of them is available yet. - **Webhooks** are not available yet. They are planned for generation done, approval changes, publish success or failure, and account disconnected. Until then, poll as described under [polling](https://docs.native.no/native-api/limits#polling). - **Per-client monthly usage reporting** is planned, as a partner usage endpoint. It is not available yet. - **Caller-supplied idempotency keys** are planned, not available. Until then, sending the same tool call again is a new attempt, so check the current state before you retry a write that creates or publishes something. See [repeated calls](https://docs.native.no/native-api/errors#repeated-calls).