Skip to main content

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

  1. Create a least-privilege Meta access token with the current Instagram content-publishing permissions required by your approved Meta app.
  2. Store the token in IntegrationAccount.apiKey and the numeric Instagram Business account ID in IntegrationAccount.accountId. Existing encrypted password identity values remain a compatibility fallback and should be migrated.
  3. Keep the account status exactly READY.
  4. Provide a public HTTPS still-image URL, optional caption and accessibility text, and confirm_publish: true.
  5. 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

NameTypeRequiredDefaultDescription
media_typestringYesIMAGEVersion 2 accepts only IMAGE.
source_urlstringYesPublic HTTPS image URL, at most 2,048 characters. Credentials, custom ports, query strings, fragments, localhost, IP literals, and local DNS names are rejected.
captionstringNoCaption up to 2,200 Unicode code points.
alt_textstringNoAccessibility text up to 1,000 Unicode code points.
location_idstringNoNumeric location ID, 1–32 digits.
instagram_account_idstringNoaccount bindingOptional numeric identity assertion. It must match the bound account.
confirm_publishbooleanYesfalseMust 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 keyTypeConditionDescription
ig.publish.container_idstringContainer creation succeedsNumeric container ID retained for reconciliation.
ig.publish.media_idstringPublication succeedsNumeric Instagram media ID.
ig.publish.permalinkstringBest-effort read succeedsVerified HTTPS instagram.com permalink.
ig.publish.statusstringAlwaysPUBLISHED 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

FieldRequirement
statusExactly READY
apiKeyEncrypted Meta access token with the least content-publishing permissions required by the approved app
accountIdNumeric Instagram Business account ID
passwordLegacy 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:

  1. POST /{instagram-business-account-id}/media with the image fields.
  2. POST /{instagram-business-account-id}/media_publish with the returned creation_id.
  3. GET /{media-id}?fields=id,permalink as 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

ConditionResultRetryableRecovery
Missing or false confirmationValidation failure before networkNoReview the content and set confirm_publish: true.
Non-IMAGE media typeValidation failure before networkNoUse a still image or a separately reviewed module with processing-state support.
schedule_time suppliedValidation failure before networkNoSchedule the workflow itself; do not claim provider scheduling.
Unsafe or unbounded inputValidation failure before networkNoCorrect the named field.
Missing, non-READY, or mismatched accountAccount failure before networkNoBind the intended READY Instagram account.
Container request failsSanitized provider/transport failureAmbiguousInspect Meta container state before one deliberate retry.
Publish request failsSanitized failure containing the safe container IDAmbiguousReconcile that container and Instagram media state before retrying.
Provider success lacks a numeric IDFails closed; never reports successAmbiguousInspect the provider response and account state.
Permalink read fails after a valid media IDPublication remains PUBLISHEDRead can be repeated separatelyUse 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/metadata are separate states.

See also the Social Media ExecModules guide and the retired SocialInstagramPublish migration guide.