Back to Blog

Instagram Messaging API 2026: Send DMs Programmatically

Complete Instagram Messaging API guide. OAuth authentication, send DMs programmatically, handle webhooks, and build automated messaging flows.

By

+8

Post everywhere. One API.

Try Free

The Instagram Messaging API lets businesses send and receive direct messages programmatically through Instagram's official Graph API. If you're building customer support automation, notification systems, or conversational commerce flows, this guide covers what you need to integrate the Instagram DM API into your app.

Instagram's messaging capabilities are part of the Meta Graph API ecosystem. Unlike unofficial methods that risk account suspension, the official Instagram Direct Message API gives you reliable, scalable messaging for business accounts with proper authentication and rate limiting.

Prerequisites and Requirements

Business Account Requirements

The Instagram Messaging API only works with Instagram Business or Creator accounts connected to a Facebook Page. Personal accounts can't access the messaging endpoints.

RequirementDetails
Account TypeInstagram Business or Creator account
Facebook PageMust be linked to a Facebook Page
Meta AppRequires a registered Meta Developer App
Permissionsinstagram_business_manage_messages scope
App ReviewRequired for production access beyond test users

Creating a Meta Developer App

  1. Go to developers.facebook.com and create a new app
  2. Select "Business" as the app type
  3. Add the "Instagram Graph API" product to your app
  4. Configure your OAuth redirect URIs
  5. Note your App ID and App Secret
// Environment variables needed for Instagram API integration
interface InstagramConfig {
  clientId: string;      // Meta App ID
  clientSecret: string;  // Meta App Secret
  redirectUri: string;   // Your OAuth callback URL
  webhookVerifyToken: string; // For webhook verification
}

const config: InstagramConfig = {
  clientId: process.env.INSTAGRAM_CLIENT_ID || '',
  clientSecret: process.env.INSTAGRAM_CLIENT_SECRET || '',
  redirectUri: process.env.INSTAGRAM_REDIRECT_URI || '',
  webhookVerifyToken: process.env.INSTAGRAM_WEBHOOK_VERIFY_TOKEN || '',
};

Note: Store all credentials in environment variables. Never commit API secrets to version control.

OAuth 2.0 Authentication Flow

The Instagram Messaging API uses OAuth 2.0. You'll need a two-step token exchange to get long-lived access tokens.

Step 1: Generate Authorization URL

Direct users to Instagram's authorization page with the required scopes:

function getInstagramAuthUrl(state: string): string {
  const scopes = [
    'instagram_business_basic',
    'instagram_business_content_publish',
    'instagram_business_manage_messages', // Required for DMs
  ];

  const params = new URLSearchParams({
    client_id: config.clientId,
    redirect_uri: config.redirectUri,
    scope: scopes.join(','),
    response_type: 'code',
    auth_type: 'rerequest', // Force re-permission prompt
    state: state, // CSRF protection
  });

  return `https://www.instagram.com/oauth/authorize?${params.toString()}`;
}

Step 2: Exchange Code for Tokens

After the user authorizes your app, Instagram redirects to your callback URL with an authorization code. Exchange it for access tokens:

interface TokenResponse {
  accessToken: string;
  refreshToken: string;
  userId: string;
  expiresIn: number;
}

async function exchangeCodeForToken(
  code: string
): Promise<TokenResponse> {
  // Step 1: Exchange code for short-lived token
  const tokenResponse = await fetch(
    'https://api.instagram.com/oauth/access_token',
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
      },
      body: new URLSearchParams({
        client_id: config.clientId,
        client_secret: config.clientSecret,
        grant_type: 'authorization_code',
        redirect_uri: config.redirectUri,
        code: code,
      }),
    }
  );

  if (!tokenResponse.ok) {
    const error = await tokenResponse.text();
    throw new Error(`Token exchange failed: ${error}`);
  }

  const shortLivedData = await tokenResponse.json();
  const shortLivedToken = shortLivedData.access_token;
  const userId = shortLivedData.user_id;

  // Step 2: Exchange for long-lived token (60 days)
  const longLivedResponse = await fetch(
    `https://graph.instagram.com/access_token?` +
    `grant_type=ig_exchange_token&` +
    `client_secret=${config.clientSecret}&` +
    `access_token=${shortLivedToken}`,
    { method: 'GET' }
  );

  if (!longLivedResponse.ok) {
    const error = await longLivedResponse.text();
    throw new Error(`Long-lived token exchange failed: ${error}`);
  }

  const longLivedData = await longLivedResponse.json();

  return {
    accessToken: longLivedData.access_token,
    refreshToken: longLivedData.access_token, // Instagram uses same token
    userId: userId,
    expiresIn: longLivedData.expires_in, // ~60 days in seconds
  };
}

Refreshing Access Tokens

Long-lived tokens expire after 60 days. Refresh them before they lapse:

async function refreshAccessToken(
  currentToken: string
): Promise<{ accessToken: string; expiresIn: number }> {
  const response = await fetch(
    `https://graph.instagram.com/refresh_access_token?` +
    `grant_type=ig_refresh_token&` +
    `access_token=${currentToken}`,
    { method: 'GET' }
  );

  if (!response.ok) {
    const errorText = await response.text();
    throw new Error(
      `Token refresh failed: ${response.status} ${errorText}`
    );
  }

  const data = await response.json();

  if (data.error) {
    throw new Error(
      `Token refresh error: ${data.error.message}`
    );
  }

  if (!data.access_token) {
    throw new Error('Token refresh did not return an access_token');
  }

  return {
    accessToken: data.access_token,
    expiresIn: data.expires_in,
  };
}

Note: A good rule of thumb is to refresh tokens when they have less than 7 days remaining.

Setting Up Webhooks for Real-time Messages

To receive incoming messages in real-time, you need to configure webhooks. Instagram sends POST requests to your endpoint whenever a user messages your business account.

Webhook Verification Endpoint

Instagram verifies your webhook URL with a GET request before activating it:

import { Request, Response } from 'express';

function handleWebhookVerification(
  req: Request,
  res: Response
): void {
  const mode = req.query['hub.mode'];
  const token = req.query['hub.verify_token'];
  const challenge = req.query['hub.challenge'];

  if (mode === 'subscribe' && token === config.webhookVerifyToken) {
    console.log('Webhook verified successfully');
    res.status(200).send(challenge);
    return;
  }

  console.error('Webhook verification failed');
  res.status(403).send('Verification failed');
}

Build faster with Late

One API call to post everywhere. No OAuth headaches. No platform-specific code.

Free tier • No credit card • 99.97% uptime

Sending Messages via the Instagram DM API

Sending Text Messages

To send Instagram DMs programmatically, use the messages endpoint:

interface SendMessageOptions {
  accessToken: string;
  igUserId: string;      // Your Instagram Business Account ID
  recipientId: string;   // The user's Instagram-scoped ID
  text: string;
}

interface SendMessageResponse {
  messageId: string;
}

async function sendTextMessage(
  options: SendMessageOptions
): Promise<SendMessageResponse> {
  const { accessToken, igUserId, recipientId, text } = options;

  const response = await fetch(
    `https://graph.instagram.com/${igUserId}/messages`,
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${accessToken}`,
      },
      body: JSON.stringify({
        recipient: {
          id: recipientId,
        },
        message: {
          text: text,
        },
      }),
    }
  );

  if (!response.ok) {
    const error = await response.text();
    throw new Error(`Failed to send message: ${error}`);
  }

  const data = await response.json();
  return { messageId: data.message_id };
}

Rate Limits and Best Practices

Rate Limit Overview

Limit TypeThresholdWindow
API Calls200 callsPer hour per user
Messages SentVariesBased on conversation history
Webhook ResponsesMust respond within 20 secondsPer event

Best Practices

  1. Implement exponential backoff for rate limit errors
  2. Cache user tokens to avoid repeated auth calls
  3. Use webhook acknowledgment immediately, process asynchronously
  4. Monitor token expiration and refresh proactively
  5. Log all API interactions for debugging

Frequently Asked Questions

Is the Instagram Messaging API free?

Yes. You need a Meta Developer account, an approved Meta App, and must pass App Review to access messaging permissions in production. There are no per-message fees from Meta, but you're responsible for your own infrastructure costs.

Can I send automated DMs to anyone on Instagram?

No. The API only lets you message users who have initiated a conversation with your business account first. Once a user messages you, a 24-hour standard messaging window opens during which you can send replies. After the 24-hour window closes, you can still send Human Agent messages for up to 7 days, but only for customer support purposes (not promotional content). You cannot send unsolicited messages or cold outreach.

What's the difference between the Instagram Messaging API and Graph API?

The Instagram Graph API covers all Instagram functionality: posting content, reading insights, managing comments, and messaging. The Instagram Messaging API is the messaging subset, using the /messages endpoint. Both use the same OAuth 2.0 authentication and access tokens.

How long do Instagram API access tokens last?

Short-lived tokens expire after 1 hour. Long-lived tokens last 60 days. Exchange short-lived tokens for long-lived ones immediately after OAuth, then refresh before they expire. Best practice is to refresh when tokens have less than 7 days remaining.

Do I need App Review to use the Instagram Messaging API?

Yes, for production use. During development you can test with up to 25 test users without App Review. To message real users at scale, you'll need to submit for Meta App Review and get the instagram_business_manage_messages permission approved. This typically takes 2-5 business days.

Using Late for Instagram Messaging Integration

Building and maintaining Instagram Messaging API integrations takes real effort. You're on the hook for OAuth flows, token refresh, webhook management, rate limiting, and error handling, across potentially multiple social platforms.

Late provides a unified API that simplifies Instagram messaging integration alongside other social platforms. Instead of building separate integrations for each one, Late offers:

  • Unified Authentication: Single OAuth flow for Instagram, Facebook, Twitter, LinkedIn, and more
  • Automatic Token Management: Late handles token refresh and expiration automatically
  • Webhook Abstraction: Normalized webhook events across all platforms
  • Built-in Rate Limiting: Intelligent request queuing and retry logic
  • Type-Safe SDK: Full TypeScript support with comprehensive types

With Late, the Instagram messaging implementation looks like this:

import { Late } from '@getlate/sdk';

const late = new Late({ apiKey: process.env.LATE_API_KEY });

// Send a message through Late's unified API
await late.messages.send({
  accountId: 'instagram-account-id',
  recipientId: 'user-id',
  content: {
    text: 'Hello from Late!',
  },
});

// Handle incoming messages with normalized events
late.webhooks.on('message.received', (event) => {
  console.log('Platform:', event.platform); // 'instagram'
  console.log('Message:', event.content.text);
});

Late handles the complexity so you can focus on your app's core functionality. Check out the Late documentation to get started with Instagram messaging and other social platform integrations.

Miquel Palet - Author

Written by

Miquel Palet

Founder & CEO

Miquel is the founder of Late, building the most reliable social media API for developers. Previously built multiple startups and scaled APIs to millions of requests.

View all articles

Learn more about Late with AI

See what AI assistants say about Late API and this topic

One API. 14+ platforms.

Ship social media features in minutes, not weeks.

Built for developers. Loved by agencies. Trusted by 6,325 users.