DEV Community

Cover image for Cómo Usar la API de Instagram Graph en 2026
Roobia
Roobia

Posted on • Originally published at apidog.com

Cómo Usar la API de Instagram Graph en 2026

TL;DR

La API de Instagram Graph permite gestionar cuentas de Instagram Business y Creator de forma programática. Utiliza autenticación OAuth 2.0 de Facebook Login y puntos finales GraphQL para publicación, estadísticas, comentarios y mensajería, con límite de 200 llamadas/hora por aplicación. Esta guía muestra cómo autenticar, publicar contenido, obtener estadísticas, gestionar comentarios e integrar en producción.

Prueba Apidog hoy

Introducción

Instagram cuenta con más de 2 mil millones de usuarios activos mensuales y más de 200 millones de empresas usan cuentas Business. Si desarrollas herramientas de gestión de redes sociales, análisis o integraciones de e-commerce, la API de Instagram Graph es fundamental.

Los gestores de redes sociales que manejan 10+ cuentas pierden hasta 30 horas semanales en publicaciones y respuestas manuales. Una integración robusta automatiza publicación, moderación, análisis de sentimientos e informes.

Esta guía cubre la integración completa de la API de Instagram Graph: autenticación OAuth, publicación de contenido, insights de medios, gestión de comentarios, webhooks y despliegue productivo.

💡 Apidog simplifica las pruebas de integración de API. Prueba tus endpoints de Instagram, valida OAuth, inspecciona respuestas y depura publicaciones en un solo workspace. Importa especificaciones, simula respuestas y comparte escenarios de prueba con tu equipo.

¿Qué es la API de Instagram Graph?

La API de Instagram Graph otorga acceso programático a cuentas Business y Creator mediante la API de Facebook Graph:

  • Publicación de contenido: fotos, videos, reels, carruseles.
  • Estadísticas y análisis: de medios y cuenta.
  • Gestión de comentarios y menciones.
  • Mensajes directos (con Messenger Platform).
  • Seguimiento de hashtags y menciones.
  • Gestión de historias.
  • Shopping y etiquetas de producto.

Características clave

Característica Descripción
API basada en grafos Acceso a recursos por nodos
OAuth 2.0 Autenticación via Facebook Login
Webhooks Notificaciones en tiempo real
Limitación de tasa 200 llamadas/hora/app
Publicación de contenido Fotos, videos, reels, carruseles
Estadísticas Métricas de engagement, alcance e impresiones
Moderación Gestión de comentarios, menciones y mensajes

Requisitos de la cuenta

Tipo de cuenta Acceso a la API
Business Acceso completo
Creator Acceso completo
Personal Sin acceso (convertir primero)
Privada Estadísticas limitadas

Arquitectura de la API

Estructura base:

https://graph.facebook.com/v18.0/
Enter fullscreen mode Exit fullscreen mode

Comparación de versiones

Versión Estado Fin de soporte Uso recomendado
v18.0 Actual Marzo 2026 Nuevas integraciones
v17.0 Obsoleta Enero 2026 Integraciones existentes
v16.0 Retirada Expirada No usar

Facebook publica nuevas versiones cada trimestre. Usa siempre la más reciente.


Primeros pasos: Configuración de autenticación

Paso 1: Crear una cuenta de desarrollador de Facebook

  1. Ve al Portal de desarrolladores de Facebook
  2. Inicia sesión con tu cuenta de Facebook
  3. Crea una aplicación de tipo "Negocio"
  4. Añade el producto "Instagram Graph API"

Paso 2: Vincular la cuenta de Instagram Business

  1. Desde tu página de Facebook, entra a Configuración > Instagram
  2. Haz clic en Conectar cuenta
  3. Inicia sesión en Instagram y autoriza
  4. Verifica que la cuenta Business esté vinculada

Nota: Solo cuentas Business/Creator pueden acceder a la API. Convierte la cuenta desde Configuración de Instagram si es necesario.

Paso 3: Obtener tokens de acceso

Genera un token de acceso de usuario:

const FB_APP_ID = process.env.FB_APP_ID;
const FB_APP_SECRET = process.env.FB_APP_SECRET;
const FB_REDIRECT_URI = process.env.FB_REDIRECT_URI;

// Construye la URL de autorización
const getAuthUrl = (state) => {
  const params = new URLSearchParams({
    client_id: FB_APP_ID,
    redirect_uri: FB_REDIRECT_URI,
    scope: 'instagram_basic,instagram_content_publish,instagram_manage_comments,instagram_manage_insights,pages_read_engagement',
    state: state
  });

  return `https://www.facebook.com/v18.0/dialog/oauth?${params.toString()}`;
};
Enter fullscreen mode Exit fullscreen mode

Permisos requeridos

Permiso Descripción
instagram_basic Perfil básico, lista de medios
instagram_content_publish Publicar fotos, videos, carruseles
instagram_manage_comments Leer/escribir comentarios
instagram_manage_insights Acceso a analíticas
pages_read_engagement Acceso a la página conectada
pages_manage_posts Publicar en la página

Paso 4: Intercambiar token por uno de larga duración

Tokens de corta duración expiran en 1 hora. Intercambia por un token de 60 días:

const exchangeForLongLivedToken = async (shortLivedToken) => {
  const response = await fetch(
    `https://graph.facebook.com/v18.0/oauth/access_token?` +
    `grant_type=fb_exchange_token&` +
    `client_id=${FB_APP_ID}&` +
    `client_secret=${FB_APP_SECRET}&` +
    `fb_exchange_token=${shortLivedToken}`
  );

  const data = await response.json();
  return data;
};

// Uso
const longLivedToken = await exchangeForLongLivedToken(shortLivedToken);
console.log(`Token expira: ${new Date(longLivedToken.expires_at * 1000)}`);
Enter fullscreen mode Exit fullscreen mode

Paso 5: Obtener el ID de la cuenta de Instagram Business

const getInstagramAccountId = async (pageId, accessToken) => {
  const response = await fetch(
    `https://graph.facebook.com/v18.0/${pageId}?fields=instagram_business_account&access_token=${accessToken}`
  );

  const data = await response.json();
  return data.instagram_business_account.id;
};

// Uso
const igAccountId = await getInstagramAccountId('12345678', accessToken);
console.log(`Instagram Account ID: ${igAccountId}`);
Enter fullscreen mode Exit fullscreen mode

Paso 6: Realizar llamadas autenticadas a la API

Crea un cliente reutilizable:

const IG_BASE_URL = 'https://graph.facebook.com/v18.0';

const instagramRequest = async (endpoint, params = {}) => {
  const url = new URL(`${IG_BASE_URL}${endpoint}`);
  url.searchParams.append('access_token', process.env.INSTAGRAM_ACCESS_TOKEN);

  Object.entries(params).forEach(([key, value]) => {
    url.searchParams.append(key, value);
  });

  const response = await fetch(url.toString());

  if (!response.ok) {
    const error = await response.json();
    throw new Error(`Instagram API Error: ${error.error.message}`);
  }

  return response.json();
};

// Uso
const account = await instagramRequest(`/me`);
console.log(`Instagram Account: ${account.username}`);
Enter fullscreen mode Exit fullscreen mode

Publicación de contenido

Publicar una foto

const publishPhoto = async (igAccountId, photoData) => {
  // 1. Crear media container
  const containerResponse = await instagramRequest(`/${igAccountId}/media`, {
    method: 'POST',
    image_url: photoData.imageUrl,
    caption: photoData.caption,
    location_id: photoData.locationId, // Opcional
    is_carousel_item: 'false'
  });

  const creationId = containerResponse.id;

  // 2. Publicar el medio
  const publishResponse = await instagramRequest(`/${igAccountId}/media_publish`, {
    method: 'POST',
    creation_id: creationId
  });

  return publishResponse;
};

// Uso
const post = await publishPhoto({
  igAccountId: '17841400000000000',
  imageUrl: 'https://example.com/image.jpg',
  caption: '¡Nuevo producto! 🚀 #lanzamiento',
  locationId: '123456789' // Opcional
});
console.log(`Published media ID: ${post.id}`);
Enter fullscreen mode Exit fullscreen mode

Publicar un video

const publishVideo = async (igAccountId, videoData) => {
  // 1. Crear media container
  const containerResponse = await instagramRequest(`/${igAccountId}/media`, {
    method: 'POST',
    video_url: videoData.videoUrl,
    cover_url: videoData.coverUrl, // Miniatura opcional
    caption: videoData.caption,
    media_type: 'REELS', // o 'VIDEO' para feed
    share_to_feed: 'true'
  });

  const creationId = containerResponse.id;

  // Espera procesamiento del video
  await waitForVideoProcessing(creationId);

  // 2. Publicar
  const publishResponse = await instagramRequest(`/${igAccountId}/media_publish`, {
    method: 'POST',
    creation_id: creationId
  });

  return publishResponse;
};

const waitForVideoProcessing = async (creationId, maxAttempts = 30) => {
  for (let i = 0; i < maxAttempts; i++) {
    const status = await instagramRequest(`/${creationId}`);

    if (status.status_code === 'FINISHED') {
      return true;
    } else if (status.status_code === 'EXPIRED') {
      throw new Error('Video processing expired');
    }

    await new Promise(resolve => setTimeout(resolve, 2000));
  }
  throw new Error('Video processing timeout');
};
Enter fullscreen mode Exit fullscreen mode

Publicar un carrusel (múltiples imágenes/videos)

const publishCarousel = async (igAccountId, carouselData) => {
  const children = [];

  // 1. Crear cada item
  for (const item of carouselData.items) {
    const containerResponse = await instagramRequest(`/${igAccountId}/media`, {
      method: 'POST',
      [item.type === 'video' ? 'video_url' : 'image_url']: item.url,
      caption: item.caption || '',
      is_carousel_item: 'true'
    });

    children.push(containerResponse.id);
  }

  // 2. Crear el contenedor carrusel
  const carouselContainerResponse = await instagramRequest(`/${igAccountId}/media`, {
    method: 'POST',
    media_type: 'CAROUSEL',
    children: children.join(','),
    caption: carouselData.caption
  });

  const creationId = carouselContainerResponse.id;

  // 3. Publicar
  const publishResponse = await instagramRequest(`/${igAccountId}/media_publish`, {
    method: 'POST',
    creation_id: creationId
  });

  return publishResponse;
};

// Uso
const carousel = await publishCarousel('17841400000000000', {
  caption: 'Product showcase 2026',
  items: [
    { type: 'image', url: 'https://example.com/img1.jpg', caption: 'Producto 1' },
    { type: 'image', url: 'https://example.com/img2.jpg', caption: 'Producto 2' },
    { type: 'video', url: 'https://example.com/vid1.mp4', caption: 'Demo' }
  ]
});
Enter fullscreen mode Exit fullscreen mode

Tipos de medios

Tipo Parámetros Caso de uso
IMAGE image_url, caption Fotos
VIDEO video_url, cover_url, caption Video feed
REELS video_url, cover_url, caption, share_to_feed Reels
CAROUSEL children (array), caption Múltiples imágenes/videos

Recuperación de medios y estadísticas

Obtener medios del usuario

const getUserMedia = async (igAccountId, limit = 25) => {
  const response = await instagramRequest(`/${igAccountId}/media`, {
    fields: 'id,caption,media_type,media_url,permalink,timestamp,like_count,comments_count',
    limit: limit.toString()
  });

  return response;
};

// Uso
const media = await getUserMedia('17841400000000000');
media.data.forEach(item => {
  console.log(`${item.media_type}: ${item.caption}`);
  console.log(`Likes: ${item.like_count}, Comments: ${item.comments_count}`);
  console.log(`URL: ${item.permalink}`);
});
Enter fullscreen mode Exit fullscreen mode

Obtener estadísticas de medios

const getMediaInsights = async (mediaId) => {
  const response = await instagramRequest(`/${mediaId}/insights`, {
    fields: 'impressions,reach,engagement,saved,video_views,profile_visits,follows'
  });

  return response;
};

// Uso
const insights = await getMediaInsights('17890000000000000');
insights.data.forEach(metric => {
  console.log(`${metric.name}: ${metric.values[0].value}`);
});
Enter fullscreen mode Exit fullscreen mode

Métricas de estadísticas disponibles

Métrica Descripción Tipos de medios
impressions Vistas totales Todos
reach Cuentas únicas alcanzadas Todos
engagement Likes + comentarios + guardados Todos
saved Veces guardado Todos
video_views Vistas de video (3+ seg) Video, Reels
plays Reproducciones totales Video, Reels
profile_visits Visitas al perfil Todos
follows Seguidores desde la publicación Todos
comments Nº de comentarios Todos
like_count Nº de "Me gusta" Todos

Obtener estadísticas de la cuenta

const getAccountInsights = async (igAccountId, metricNames, since = null, until = null) => {
  const params = {
    metric: metricNames.join(','),
    period: 'day'
  };

  if (since) params.since = since;
  if (until) params.until = until;

  const response = await instagramRequest(`/${igAccountId}/insights`, params);

  return response;
};

// Uso: últimos 30 días
const accountInsights = await getAccountInsights(
  '17841400000000000',
  ['impressions', 'reach', 'profile_views', 'email_contacts', 'website_clicks'],
  '2026-02-23',
  '2026-03-25'
);

accountInsights.data.forEach(metric => {
  console.log(`${metric.name}:`);
  metric.values.forEach(value => {
    console.log(`  ${value.end_time}: ${value.value}`);
  });
});
Enter fullscreen mode Exit fullscreen mode

Métricas de cuenta

Métrica Descripción
impressions Vistas totales de perfil/contenido
reach Cuentas únicas alcanzadas
profile_views Visitas al perfil
website_clicks Clics en bio
email_contacts Taps en email
phone_call_clicks Taps en teléfono
text_message_clicks Taps en SMS
get_directions_clicks Clics en dirección
follower_count Total de seguidores
audience_city Ciudades de seguidores
audience_country Países de seguidores
audience_gender_age Demografía

Gestión de comentarios

Obtener comentarios

const getMediaComments = async (mediaId, limit = 50) => {
  const response = await instagramRequest(`/${mediaId}/comments`, {
    fields: 'id,text,timestamp,username,hidden',
    limit: limit.toString()
  });

  return response;
};

// Uso
const comments = await getMediaComments('17890000000000000');
comments.data.forEach(comment => {
  console.log(`@${comment.username}: ${comment.text}`);
  console.log(`Hidden: ${comment.hidden}`);
});
Enter fullscreen mode Exit fullscreen mode

Responder a comentarios

const replyToComment = async (mediaId, commentId, replyText) => {
  const response = await instagramRequest(`/${mediaId}/comments`, {
    method: 'POST',
    response_to: commentId,
    message: replyText
  });

  return response;
};

// Uso
const reply = await replyToComment(
  '17890000000000000',
  '17900000000000000',
  '¡Gracias por tu interés! Revisa tu DM.'
);
console.log(`Reply posted: ${reply.id}`);
Enter fullscreen mode Exit fullscreen mode

Ocultar comentarios

const hideComment = async (commentId) => {
  const response = await instagramRequest(`/${commentId}`, {
    method: 'POST',
    hide: 'true'
  });

  return response;
};

// Uso
await hideComment('17900000000000000');
console.log('Comment hidden');
Enter fullscreen mode Exit fullscreen mode

Eliminar comentarios

const deleteComment = async (commentId) => {
  await instagramRequest(`/${commentId}`, {
    method: 'DELETE'
  });

  console.log('Comment deleted');
};
Enter fullscreen mode Exit fullscreen mode

Webhooks

Configuración de webhooks

const subscribeToWebhooks = async (appId, pageId, accessToken) => {
  // Suscribirse a eventos de Instagram
  const response = await fetch(
    `https://graph.facebook.com/v18.0/${appId}/subscriptions`,
    {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        object: 'instagram',
        callback_url: 'https://myapp.com/webhooks/instagram',
        verify_token: process.env.WEBHOOK_VERIFY_TOKEN,
        access_token: accessToken,
        fields: ['comments', 'mentions', 'message_reactions']
      })
    }
  );

  return response.json();
};
Enter fullscreen mode Exit fullscreen mode

Manejo de webhooks

const express = require('express');
const app = express();

// Verificar suscripción
app.get('/webhooks/instagram', (req, res) => {
  const mode = req.query['hub.mode'];
  const token = req.query['hub.verify_token'];
  const challenge = req.query['hub.challenge'];

  if (mode === 'subscribe' && token === process.env.WEBHOOK_VERIFY_TOKEN) {
    console.log('Webhook verified');
    res.status(200).send(challenge);
  } else {
    res.status(403).send('Verification failed');
  }
});

// Recibir eventos
app.post('/webhooks/instagram', express.json(), async (req, res) => {
  const body = req.body;

  if (body.object !== 'instagram') {
    return res.status(404).send('Not found');
  }

  for (const entry of body.entry) {
    const igId = entry.id;
    const changes = entry.changes;

    for (const change of changes) {
      switch (change.field) {
        case 'comments':
          await handleNewComment(change.value);
          break;
        case 'mentions':
          await handleMention(change.value);
          break;
        case 'message_reactions':
          await handleReaction(change.value);
          break;
      }
    }
  }

  res.status(200).send('OK');
});

async function handleNewComment(data) {
  console.log(`Nuevo comentario en media ${data.media_id}`);
  console.log(`De: ${data.from_id}`);
  console.log(`Texto: ${data.text}`);

  // Auto-moderar
  if (isSpam(data.text)) {
    await hideComment(data.id);
  }
}
Enter fullscreen mode Exit fullscreen mode

Campos de webhook

Campo Activador
comments Nuevo comentario o respuesta
mentions Usuario menciona la cuenta
message_reactions Reacción a una historia
story_status Respuesta o vista a una historia

Limitación de tasa

Comprendiendo los límites

  • 200 llamadas/hora/app (compartidas entre usuarios)
  • Business Discovery: 200 llamadas/hora/usuario
  • Publicación de contenido: límites específicos por acción

Si excedes los límites, recibirás HTTP 400 con error 613.

Mejores prácticas

  1. Caché de respuestas: evita peticiones innecesarias.
  2. Solicitudes por lotes: usa expansión de campos.
  3. Webhooks: recibe cambios en tiempo real.
  4. Retroceso exponencial en errores 429.
const makeRateLimitedRequest = async (endpoint, params = {}, maxRetries = 3) => {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const response = await instagramRequest(endpoint, params);
      return response;
    } catch (error) {
      if (error.message.includes('429') && attempt < maxRetries) {
        const delay = Math.pow(2, attempt) * 1000;
        console.log(`Rate limited. Retrying in ${delay}ms...`);
        await new Promise(resolve => setTimeout(resolve, delay));
      } else {
        throw error;
      }
    }
  }
};
Enter fullscreen mode Exit fullscreen mode

Solución de problemas comunes

Problema: Token OAuth expirado

  • Síntoma: Error "Invalid OAuth access token".
  • Solución:
    1. Refresca el token antes de 60 días.
    2. Almacena la fecha de expiración y alerta al usuario.
    3. Reautentica si el token expiró.

Problema: Falla la publicación de medios

  • Síntoma: Error al publicar.
  • Solución:
    1. Asegúrate que la URL es pública.
    2. Revisa formato y tamaño (<8MB para imágenes, <1GB y <90s para videos).
    3. Espera procesamiento de video antes de publicar.

Problema: Estadísticas no disponibles

  • Síntoma: Datos vacíos en insights.
  • Solución:
    1. Verifica que la cuenta es Business/Creator.
    2. Espera 24-48h tras publicación.
    3. Asegura suficiente actividad en la cuenta.

Lista de verificación para la implementación en producción

Antes de lanzar:

  • [ ] Todas las cuentas en modo Business/Creator
  • [ ] OAuth 2.0 con tokens de larga duración
  • [ ] Tokens almacenados de forma segura (cifrado)
  • [ ] Actualización automática de tokens
  • [ ] Webhooks configurados sobre HTTPS
  • [ ] Limitación de tasa y colas de solicitudes
  • [ ] Manejo de errores completo
  • [ ] Registro de todas las llamadas API
  • [ ] Flujos de moderación de contenido
  • [ ] Pruebas con varios tipos de cuenta

Casos de uso en el mundo real

Herramienta de programación de redes sociales

Desafío: Publicación manual en 50+ cuentas de clientes

Solución: Publicación programada vía API

Resultado: 80% de ahorro de tiempo; horario consistente

  • Calendario de contenido drag & drop
  • Publicación automática de fotos, videos, carruseles
  • Sugerencias de hashtags inteligentes

Automatización del servicio al cliente

Desafío: Respuestas lentas a clientes

Solución: Auto-respuesta a preguntas comunes vía webhook

Resultado: 5 min de tiempo medio de respuesta, 90% satisfacción

  • Detección de keywords (precio, stock, envío)
  • Respuesta automática con links de producto
  • Escalado a agentes humanos para casos complejos

Conclusión

La API de Instagram Graph ofrece acceso completo a funciones de cuentas Business y Creator. Puntos clave:

  • Autenticación OAuth 2.0 (tokens de 60 días)
  • Publicación de fotos, videos, reels, carruseles
  • Insights de engagement, alcance y demografía
  • Webhooks para comentarios/menciones en tiempo real
  • Límite de 200 llamadas/hora/app: gestiona bien la tasa
  • Apidog agiliza pruebas y colaboración en equipos

Sección de Preguntas Frecuentes

¿Cómo obtengo acceso a la API de Instagram?

Crea una cuenta de desarrollador de Facebook, una app de negocios, añade Instagram Graph API y autentica vía Facebook Login con los permisos necesarios.

¿Puedo publicar en Instagram automáticamente?

Sí, usa la API de Publicación de Contenido para publicar en cuentas Business/Creator.

¿Qué tipos de cuentas son compatibles con la API?

Solo Business y Creator tienen acceso completo. Las cuentas personales están limitadas.

¿Cómo obtengo comentarios de Instagram?

Usa el endpoint de Comentarios (/{media-id}/comments). Los webhooks proporcionan notificaciones en tiempo real.

¿Cuáles son los límites de tasa de Instagram?

La API permite 200 llamadas/hora/app. Algunos endpoints tienen límites adicionales por usuario.

¿Puedo publicar Stories vía API?

Sí, las Stories se publican usando el mismo flujo de contenido que las publicaciones.

¿Cómo accedo a las estadísticas de Instagram?

Solicita el permiso instagram_manage_insights en OAuth. Usa el endpoint de Insights para obtener métricas.

¿Puedo responder a los comentarios automáticamente?

Sí, usa la API de Comentarios para responder. Muchas marcas lo usan para atención automatizada.

Top comments (0)