Instagram Business Publish ExecModule
Overview
InstagramPublishModule version 2.0.0 publishes one still image to an Instagram Business account through the Meta Graph API. It creates one media container, publishes that container once, and then makes one best-effort read for the permalink.
Version 2 replaces a catalog-incomplete implementation that exposed zero inputs and outputs, put the access token in query strings, logged exception and provider details, treated a two-write provider sequence as idempotent, and claimed unsupported scheduling behavior. The hardened module binds identity and credentials to a READY IntegrationAccount, uses an authorization header, validates bounded inputs and provider identifiers, and never retries an ambiguous write.
Usage
- Create a least-privilege Meta access token with the current Instagram content-publishing permissions required by your approved Meta app.
- Store the token in
IntegrationAccount.apiKeyand the numeric Instagram Business account ID inIntegrationAccount.accountId. Existing encryptedpasswordidentity values remain a compatibility fallback and should be migrated. - Keep the account status exactly
READY. - Provide a public HTTPS still-image URL, optional caption and accessibility text, and
confirm_publish: true. - Run one approved publication. If either provider write times out or returns a transient error, inspect Instagram and the emitted container ID before any deliberate retry.
Inputs
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
media_type | string | Yes | IMAGE | Version 2 accepts only IMAGE. |
source_url | string | Yes | — | Public HTTPS image URL, at most 2,048 characters. Credentials, custom ports, query strings, fragments, localhost, IP literals, and local DNS names are rejected. |
caption | string | No | — | Caption up to 2,200 Unicode code points. |
alt_text | string | No | — | Accessibility text up to 1,000 Unicode code points. |
location_id | string | No | — | Numeric location ID, 1–32 digits. |
instagram_account_id | string | No | account binding | Optional numeric identity assertion. It must match the bound account. |
confirm_publish | boolean | Yes | false | Must be true before either provider write is sent. |
Raw access_token, token, secret, authorization, endpoint, server, Graph base URL, mock, and test values are rejected from workflow configuration. Any normalized apiKey projection is ignored; the runtime resolves the credential only from the bound account.
Outputs
| Workflow state key | Type | Condition | Description |
|---|---|---|---|
ig.publish.container_id | string | Container creation succeeds | Numeric container ID retained for reconciliation. |
ig.publish.media_id | string | Publication succeeds | Numeric Instagram media ID. |
ig.publish.permalink | string | Best-effort read succeeds | Verified HTTPS instagram.com permalink. |
ig.publish.status | string | Always | PUBLISHED or ERROR. |
A permalink read failure does not erase a confirmed publication. The run remains PUBLISHED, retains the verified media ID, and reports that the permalink is unavailable.
IntegrationAccount Requirements
| Field | Requirement |
|---|---|
status | Exactly READY |
apiKey | Encrypted Meta access token with the least content-publishing permissions required by the approved app |
accountId | Numeric Instagram Business account ID |
password | Legacy encrypted identity fallback only; migrate the ID to accountId |
The token is sent only as Authorization: Bearer .... It is never placed in a URL, form body, output, workflow state, event detail, or error message. Provider bodies are not copied into failures.
Configuration
Workflow Studio exposes the account binding, still-image URL, caption, alt text, optional location, and explicit confirmation. The fallback catalog initializes confirm_publish to false and no longer offers the fabricated schedule_time field.
Example configuration:
{
"media_type": "IMAGE",
"source_url": "https://cdn.example.com/releases/launch.png",
"caption": "Release notes are live.",
"alt_text": "A product release architecture diagram",
"location_id": "123456789",
"confirm_publish": true
}
Operations
One execution performs at most three requests in this order:
POST /{instagram-business-account-id}/mediawith the image fields.POST /{instagram-business-account-id}/media_publishwith the returnedcreation_id.GET /{media-id}?fields=id,permalinkas a best-effort read.
The two POST requests are single-attempt, non-idempotent writes. The module does not cache, deduplicate, automatically retry, schedule, upload local bytes, poll video processing, or create reels or carousels.
Errors and Failure Modes
| Condition | Result | Retryable | Recovery |
|---|---|---|---|
| Missing or false confirmation | Validation failure before network | No | Review the content and set confirm_publish: true. |
| Non-IMAGE media type | Validation failure before network | No | Use a still image or a separately reviewed module with processing-state support. |
schedule_time supplied | Validation failure before network | No | Schedule the workflow itself; do not claim provider scheduling. |
| Unsafe or unbounded input | Validation failure before network | No | Correct the named field. |
| Missing, non-READY, or mismatched account | Account failure before network | No | Bind the intended READY Instagram account. |
| Container request fails | Sanitized provider/transport failure | Ambiguous | Inspect Meta container state before one deliberate retry. |
| Publish request fails | Sanitized failure containing the safe container ID | Ambiguous | Reconcile that container and Instagram media state before retrying. |
| Provider success lacks a numeric ID | Fails closed; never reports success | Ambiguous | Inspect the provider response and account state. |
| Permalink read fails after a valid media ID | Publication remains PUBLISHED | Read can be repeated separately | Use the media ID to inspect Instagram. |
HTTP 429 and 5xx errors explicitly state that automatic retry is disabled. Tokens, authorization headers, response bodies, captions, alt text, and source URLs are omitted from failure logs.
Example
Input:
{
"media_type": "IMAGE",
"source_url": "https://cdn.example.com/releases/launch.png",
"caption": "Release notes are live.",
"confirm_publish": true
}
Expected workflow state after verified publication:
{
"ig.publish.container_id": "17889400000000000",
"ig.publish.media_id": "17900400000000000",
"ig.publish.permalink": "https://www.instagram.com/p/ABC123/",
"ig.publish.status": "PUBLISHED"
}
The exact identifiers come from Meta. If the final read is unavailable, the permalink key is absent while the media ID and PUBLISHED state remain.
Notes
- Pagination: none. The module publishes one image and performs one single-resource read.
- Limits: URL 2,048 characters; caption 2,200 Unicode code points; alt text 1,000 Unicode code points; numeric identifiers 1–32 digits.
- Idempotency: false. Container creation and publication are separate non-idempotent writes with no provider idempotency key.
- Rate limits: HTTP 429 is surfaced without an automatic write retry. Respect Meta app and account limits before another execution.
- API constraints: version 2 supports a remotely hosted still image only. Video, reels, stories, carousels, local upload, container polling, and provider scheduling are intentionally deferred.
- Destructive behavior: the module creates public social content but does not edit or delete existing media. Compensate through an authorized Instagram deletion or moderation workflow if needed.
- Observability: events name the validation, container, publish, and permalink stages without logging credentials or user content.
- Testing boundary: deterministic tests cover request construction, header-only authentication, validation, account binding, response mapping, malformed success, redaction, ambiguous failures, metadata discovery, and permalink degradation. No real Meta publication is attempted without an authorized account.
- Runtime boundary: merged source, production documentation, public launch content, and deployed
/v1/modules/metadataare separate states.
See also the Social Media ExecModules guide and the retired SocialInstagramPublish migration guide.