SDKs & frameworks

Post to Instagram with Python

A working Python example that posts to Instagram via the PostGate API using the requests library.

Quick answer

Post to Instagram with Python using the standard requests library: connect a Business or Creator account through PostGate's hosted OAuth, load your API key from an environment variable, then send POST /api/posts with the profile ID, post body, a media URL, and a stable Idempotency-Key. Confirm delivery by reading the targets array on GET /api/posts/{id}.

This uses Python's standard requests library against POST /api/posts directly. PostGate does generate a typed Python client from its OpenAPI contract (see SDKs & MCP), but the published package name for it isn't documented publicly, so this guide sticks to the one thing guaranteed to match what ships: the REST contract itself. For the general Python setup, see the Python quickstart.

01

Step 1 — Connect a Business or Creator account

Instagram's publishing API only works against a professional account — Business or Creator, not personal. See why that requirement exists. Through PostGate's hosted OAuth, the customer authorizes access once; PostGate stores and refreshes the resulting token, so your Python backend never handles or stores Instagram credentials directly.

02

Step 2 — Install requests and set the key

Load the API key from an environment variable — never hardcode it, and never ship it to a notebook or frontend a customer can open. Use a pg_test_ key while you build; it runs the complete lifecycle against a sandbox adapter without publishing anything real. See Authentication.

SetupPostGate API
pip install requests
export POSTGATE_API_KEY="pg_test_..."
03

Step 3 — Send the request

Attach the connected Instagram profile ID, the post body, and a media URL, with a stable Idempotency-Key so a dropped connection and a retry never post twice — see Idempotency & safe retries.

post_to_instagram.pyPostGate API
import os
import requests

API_URL = "https://postgate.studio"
API_KEY = os.environ["POSTGATE_API_KEY"]

response = requests.post(
    f"{API_URL}/api/posts",
    headers={
        "Authorization": f"Bearer {API_KEY}",
        "Content-Type": "application/json",
        "Idempotency-Key": "ig-launch-004",
    },
    json={
        "post": {"body": "We just shipped something."},
        "profiles": ["pro_instagram123"],
        "media": ["https://cdn.example.com/announcement.jpg"],
    },
)
response.raise_for_status()
post = response.json()
print(post["id"], post["status"])
04

Step 4 — Confirm delivery, do not assume it

The create response is acceptance, not proof of publication. Read GET /api/posts/{id} and look at the targets array — a published target carries Instagram's own media ID and permalink. For production traffic, subscribe to the post.published / post.partial / post.failed webhooks instead of polling — see the full delivery lifecycle.

confirm_delivery.pyPostGate API
status = requests.get(
    f"{API_URL}/api/posts/{post['id']}",
    headers={"Authorization": f"Bearer {API_KEY}"},
).json()

for target in status["targets"]:
    print(target["platform"], target["status"], target.get("permalink"))
05

Step 5 — Handle the failure paths you will actually hit

A failed target returns a structured error with a stable code and a retryable flag — see errors & retries. profile_disconnected means Instagram revoked or expired the token and the customer needs to reconnect. platform_content_rejected means the content itself was rejected and needs to change, not retry.

Frequently asked questions

Can I post to a personal Instagram account with Python?

No. Instagram's publishing API only works against a professional account — Business or Creator, not personal. Through PostGate's hosted OAuth the customer authorizes access once; PostGate stores and refreshes the resulting token, so your Python backend never handles or stores Instagram credentials directly.

Do I need an Instagram SDK, or is the requests library enough?

The standard requests library against POST /api/posts is enough. PostGate does generate a typed Python client from its OpenAPI contract, but the published package name for it is not documented publicly, so the REST contract itself is the one thing guaranteed to match what ships.

How do I test Instagram posting without publishing anything real?

Use a pg_test_ API key while you build — it runs the complete lifecycle against a sandbox adapter without publishing anything real. Load the key from an environment variable; never hardcode it, and never ship it to a notebook or frontend a customer can open.

How do I know my Python script actually published the post?

The create response is acceptance, not proof of publication. Read GET /api/posts/{id} and look at the targets array — a published target carries Instagram's own media ID and permalink. For production traffic, subscribe to the post.published, post.partial, and post.failed webhooks instead of polling.

What do profile_disconnected and platform_content_rejected mean?

A failed target returns a structured error with a stable code and a retryable flag. profile_disconnected means Instagram revoked or expired the token and the customer needs to reconnect. platform_content_rejected means the content itself was rejected and needs to change — retrying it will not help.

Build it with PostGate

One API for every social platform your customers care about — sandboxed, documented, and ready today.

Start building Read the docs