Blog/Tutorials

How to post to Instagram via API in TypeScript

May 22, 2026·8 min readTutorials

Step-by-step guide to authenticating Instagram users, uploading media, and scheduling posts using the Aether API — from zero to your first published post.

Instagram's API is notoriously complex — app review, business account requirements, rate limit tiers, and media format restrictions that vary by content type. Aether wraps all of that into three API calls. Here's how to go from zero to your first published post.

Prerequisites

  • An Aether account — free tier is enough
  • An Aether API key from the dashboard
  • Node.js 18+ in your project

1. Install the SDK

npm install aether

2. Connect an Instagram account

Aether uses Connect Links to handle Instagram OAuth on your behalf. You generate a one-time URL and redirect your user to it — Aether handles the Instagram app review, permissions, and token storage.

import Aether from "aether";

const aether = new Aether({ apiKey: process.env.AETHER_API_KEY });

// 1. Generate an OAuth link for your user
const link = await aether.connectLinks.create({
  platform: "instagram",
  redirectUrl: "https://yourapp.com/oauth/instagram/callback",
});

console.log(link.url);
// → https://connect.aetherhq.dev/oauth/ig_...
// Redirect the user to this URL

While your Aether app is in development, only Instagram accounts you've added as testers in the Meta Developer Portal can complete this flow. Instagram requires app review for production access.

3. Publish and schedule posts

Once an Instagram profile is connected, publishing is a single API call. Use overrides.instagram to attach hashtags, media, or alt text specific to Instagram without affecting other platforms.

// 2. Once connected, list their profiles
const profiles = await aether.profiles.list({ platform: "instagram" });
const profileId = profiles.data[0]?.id;

// 3. Publish a post immediately
const post = await aether.posts.create({
  profileIds: [profileId],
  text: "Shipping something new today 🚀 #buildinpublic",
  overrides: {
    instagram: {
      hashtags: ["#launch", "#api", "#indiehacker"],
    },
  },
});

console.log(post.status); // "published"
console.log(post.platformResults?.instagram?.url); // post URL

Scheduling with timezone support

Pass any ISO 8601 timestamp with a UTC offset to scheduledFor. Aether stores the absolute UTC time and re-derives the local time at publish — so daylight saving transitions don't corrupt your schedule.

// Schedule for 9am EST tomorrow
const scheduled = await aether.posts.create({
  profileIds: [profileId],
  text: "Good morning from the Aether team ☀️",
  scheduledFor: "2026-06-01T09:00:00-05:00",
  overrides: {
    instagram: {
      mediaUrls: ["https://yourcdn.com/image.jpg"],
      altText: "Product screenshot showing the new dashboard",
    },
  },
});

console.log(scheduled.status); // "scheduled"
console.log(scheduled.scheduledFor); // "2026-06-01T14:00:00.000Z"

Next steps

  • Subscribe to post.published and post.failed webhooks to track publish status in your system
  • Use GET /v1/analytics/posts/:postId to pull impressions, likes, and reach after publishing
  • Check the scheduling guide for rate limits and bulk CSV upload