Create an API key
Open Dashboard → AI & API and create a key. Copy it once. It starts with pw_live_. Send it on every request:
Header
Authorization: Bearer pw_live_…
Every URL below starts at https://postwing.io/api/v1.
the whole flow
You call PostWing. PostWing publishes to Instagram at the time you set. The post also shows up on your calendar.
Open Dashboard → AI & API and create a key. Copy it once. It starts with pw_live_. Send it on every request:
Header
Authorization: Bearer pw_live_…
Every URL below starts at https://postwing.io/api/v1.
Connect the Instagram account you want to post from. You only do this once.
The simple way is in the dashboard. Open Accounts, choose Instagram, and finish the Instagram login.
From the API, start that same login. The response includes a url. Open it and approve Instagram.
Start connect
curl -s -X POST "https://postwing.io/api/v1/accounts" \
-H "Authorization: Bearer pw_live_…" \
-H "Content-Type: application/json" \
-d '{ "platform": "instagram" }'After you finish in the browser, sync. This imports the account into your workspace and returns the account id.
Sync
curl -s -X POST "https://postwing.io/api/v1/accounts/sync" \ -H "Authorization: Bearer pw_live_…"
In the response, find the object where platform is instagram and copy account_id. That is the id you send when you create the post.
Sync response
{
"synced_count": 1,
"accounts": [
{
"account_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"platform": "instagram",
"handle": "brand",
"display_name": "Brand",
"status": "connected"
}
]
}Connected Instagram in the dashboard instead? The sync response is not in front of you, so list accounts and copy the same field:
List accounts
curl -s -X GET "https://postwing.io/api/v1/accounts" \ -H "Authorization: Bearer pw_live_…"
Send the caption, a future time, and the Instagram account_id you copied after sync. Instagram needs an image or a video, so this example includes one image. This call creates the post. Instagram does not publish until you confirm in the next step. scheduled_at is UTC. The image URL has to be public HTTPS.
Create a feed post
curl -s -X POST "https://postwing.io/api/v1/posts/preview" \
-H "Authorization: Bearer pw_live_…" \
-H "Content-Type: application/json" \
-d '{
"caption": "New hours this week. We are open until 7.",
"scheduled_at": "2026-10-12T15:00:00Z",
"targets": [
{ "account_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901" }
],
"media_items": [
{ "url": "https://cdn.example.com/storefront.jpg", "type": "image" }
]
}'One image goes to the feed. Add more images in media_items for a carousel, up to 10.
You get back three things that matter:
Response
{
"preview": {
"caption": "New hours this week. We are open until 7.",
"scheduled_at": "2026-10-12T15:00:00.000Z",
"post_type": "image",
"targets": [
{
"account_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"platform": "instagram",
"handle": "brand"
}
]
},
"confirmation_token": "eyJ…signature",
"expires_in_seconds": 300
}The same post can go to Facebook and TikTok. Connect each channel the way you connected Instagram, then copy its account_id from the sync response.
Connect Facebook
curl -s -X POST "https://postwing.io/api/v1/accounts" \
-H "Authorization: Bearer pw_live_…" \
-H "Content-Type: application/json" \
-d '{ "platform": "facebook" }'Connect TikTok
curl -s -X POST "https://postwing.io/api/v1/accounts" \
-H "Authorization: Bearer pw_live_…" \
-H "Content-Type: application/json" \
-d '{ "platform": "tiktok" }'Open each url, finish the login, then sync once. Copy account_id where platform is facebook, and where platform is tiktok or tiktok_business.
Add those ids to targets on the create call. One request, one confirm. Every account publishes at the same scheduled_at. Leave caption off a target to use the shared caption. Set caption when that channel needs different text.
Create one post for three channels
curl -s -X POST "https://postwing.io/api/v1/posts/preview" \
-H "Authorization: Bearer pw_live_…" \
-H "Content-Type: application/json" \
-d '{
"caption": "New hours this week. We are open until 7.",
"scheduled_at": "2026-10-12T15:00:00Z",
"targets": [
{ "account_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901" },
{
"account_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"caption": "Open until 7 this week."
},
{ "account_id": "c3d4e5f6-a7b8-9012-cdef-123456789012" }
],
"media_items": [
{ "url": "https://cdn.example.com/storefront.jpg", "type": "image" }
]
}'Then confirm once, the same way as the next step.
When the post you just created looks right, confirm with the token from that response. Use the token as-is. Do not invent one.
Confirm
curl -s -X POST "https://postwing.io/api/v1/posts/confirm" \
-H "Authorization: Bearer pw_live_…" \
-H "Content-Type: application/json" \
-d '{ "confirmation_token": "eyJ…signature" }'The response includes view_url. Open it to see the post on your calendar. Every account in targets publishes at the time you set, including Facebook and TikTok when you added them. You can edit or cancel later from the dashboard or with the same API.
If confirm says the token expired, create the post again and confirm the new token within 5 minutes.
video
A video becomes a Reel. Use the same Instagram account_id from sync. share_to_feed also puts that Reel on the main feed. thumbnail_url is the cover.
Create a Reel
curl -s -X POST "https://postwing.io/api/v1/posts/preview" \
-H "Authorization: Bearer pw_live_…" \
-H "Content-Type: application/json" \
-d '{
"caption": "A 15-second look at the new menu",
"scheduled_at": "2026-10-12T18:00:00Z",
"targets": [
{
"account_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"platform_options": { "share_to_feed": true }
}
],
"media_items": [
{
"url": "https://cdn.example.com/reel.mp4",
"type": "video",
"thumbnail_url": "https://cdn.example.com/cover.jpg"
}
]
}'share_to_feed defaults to true, so the Reel also goes on the main feed. Set it to false to keep the Reel off the feed. Leave thumbnail_url off to use a frame from the video.
Videos imported from a URL need to be 100MB or smaller. A file on your computer uses the direct upload URL, covered in the API docs.
trial
A trial Reel is a video you test before everyone sees it. Use the same Instagram account_id, and set trial_reel_type.
Create a trial Reel
curl -s -X POST "https://postwing.io/api/v1/posts/preview" \
-H "Authorization: Bearer pw_live_…" \
-H "Content-Type: application/json" \
-d '{
"caption": "Testing this Reel before it reaches everyone",
"scheduled_at": "2026-10-12T18:30:00Z",
"targets": [
{
"account_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"platform_options": { "trial_reel_type": "manual" }
}
],
"media_items": [
{ "url": "https://cdn.example.com/reel.mp4", "type": "video" }
]
}'manual means you decide when the Reel graduates. performance lets it graduate on its own if it does well.
The account needs 1,000 followers, and you can post up to 5 trial Reels a day. Leave trial_reel_type off for a normal Reel.
questions
No. Instagram needs an image or a video. Create the post with caption, scheduled_at, the Instagram account_id, and media_items. Then confirm with the token.