# Instagram Messaging API

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.

| Requirement | Details |
| --- | --- |
| Account Type | Instagram Business or Creator account |
| Facebook Page | Must be linked to a Facebook Page |
| Meta App | Requires a registered Meta Developer App |
| Permissions | `instagram_business_manage_messages` scope |
| App Review | Required for production access beyond test users |

### Creating a Meta Developer App

1. Go to [developers.facebook.com](https://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

```typescript
// 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:

```typescript
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:

```typescript
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:

```typescript
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:

```typescript
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');
}
```

## Sending Messages via the Instagram DM API

### Sending Text Messages

To **send Instagram DMs programmatically**, use the messages endpoint:

```typescript
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 Type         | Threshold                                   | Window                   |
| ------------------ | ------------------------------------------- | ------------------------- |
| API Calls          | 200 calls                                   | Per hour per user        |
| Messages Sent      | Varies                                      | Based on conversation history |
| Webhook Responses   | Must respond within 20 seconds             | Per 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 Zernio 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.

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

- **Unified Authentication**: Single OAuth flow for Instagram, Facebook, Twitter, LinkedIn, and more
- **Automatic Token Management**: Zernio 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 Zernio, the Instagram messaging implementation looks like this:

```typescript
import { Zernio } from '@getlate/sdk';

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

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

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

Zernio handles the complexity so you can focus on your app's core functionality. Check out the [Zernio documentation](/content/docs/index.html) to get started with Instagram messaging and other social platform integrations.
