Integrating Instagram Graph API with AWS Lambda: Connecting @sailjada Media to Guest Photo Pages

What Was Done

We integrated the Instagram Graph API into the shipcaptaincrew Lambda function (us-east-1, account 782785212866) to enable dynamic fetching of @sailjada Instagram posts alongside guest-uploaded charter photos. The guest photo page system at shipcaptaincrew.queenofsandiego.com/g/{event_id} previously had dormant Instagram integration that returned empty arrays due to missing environment variables. This post documents the complete setup process, key architectural decisions, and the token lifecycle management strategy.

Technical Details: The Integration Architecture

Why Instagram Graph API (Not Basic Display)

The Instagram Graph API was chosen over Basic Display because we needed to:

  • Read media metadata (captions, timestamps, media types)
  • Query a business/creator account (@sailjada) associated with a Facebook Page
  • Access the instagram_business_account edge to retrieve media feeds programmatically

Basic Display is limited to recently-published media and doesn't support business account querying. The Messaging API was initially added but doesn't grant the instagram_basic scope required for media reads—it's designed for inbox management only.

OAuth Token Flow

Instagram's token lifecycle requires a two-stage approach:

  1. Short-lived Access Token (1 hour): Generated via the Graph API Explorer with scopes instagram_basic and pages_show_list
  2. Long-lived Access Token (60 days): Exchanged using your app credentials, stored in Lambda environment variables

The long-lived token is what gets stored as IG_ACCESS_TOKEN in the Lambda function configuration. This avoids the need for user re-authentication every hour.

Step-by-Step Setup Process

Step 1: Add the Correct Product

Navigate to the Meta App Dashboard at developers.facebook.com/apps:

  • Select the sailjada-social app
  • Click Add Product (bottom of left sidebar)
  • Search for and select Instagram Graph API
  • Choose the Graph API access type (not Basic Display or Messaging)

Instagram Graph API will now appear in your left sidebar under Products.

Step 2: Connect @sailjada

Inside Instagram Graph APIAPI setup with Instagram login:

  • Click Add Instagram account
  • Authenticate as @sailjada (the Instagram account must be a Business or Creator account)
  • Authorize the app to access the account's data
  • Confirm that @sailjada is linked to a Facebook Page (this relationship is required for the Graph API to work)

Step 3: Generate a Short-lived Token

Use the Graph API Explorer at developers.facebook.com/tools/explorer:

  • Select the sailjada-social app from the dropdown
  • Click Generate Access Token
  • When prompted, select the Facebook Page linked to @sailjada
  • In the permissions dialog, enable instagram_basic and pages_show_list
  • Copy the resulting access token (valid for ~1 hour)

Step 4: Retrieve IG_USER_ID

Execute the following request in the Graph API Explorer (replace TOKEN with your short-lived token):

GET /me/accounts?fields=id,name
Authorization: Bearer TOKEN

The response lists all Facebook Pages your account manages. Identify your charter business page and note its id. Then execute:

GET /{PAGE_ID}?fields=instagram_business_account
Authorization: Bearer TOKEN

Extract the id from the instagram_business_account object—this is your IG_USER_ID.

Step 5: Exchange for a Long-lived Token

Use a script or curl command to exchange your short-lived token for a 60-day token. This step requires your app's APP_ID and APP_SECRET (stored in a secure secrets manager, not in this example):

GET /oauth/access_token?grant_type=ig_refresh_token
  &access_token=SHORT_LIVED_TOKEN
  &redirect_uri=https://shipcaptaincrew.queenofsandiego.com/callback

Or via Python using boto3 (if calling from Lambda after initial setup):

import requests

url = "https://graph.instagram.com/oauth/access_token"
params = {
    "grant_type": "ig_refresh_token",
    "access_token": SHORT_LIVED_TOKEN
}
response = requests.get(url, params=params)
long_lived_token = response.json()["access_token"]

The returned access_token is your IG_ACCESS_TOKEN.

Step 6: Update Lambda Environment Variables

Once you have both values, update the Lambda function configuration:

aws lambda update-function-configuration \
  --region us-east-1 \
  --function-name shipcaptaincrew \
  --environment Variables="{
    IG_USER_ID=123456789,
    IG_ACCESS_TOKEN=IGQVJxMDE...,
    existing_var=value
  }"

The Lambda function's existing code checks for these variables and will now populate the guest photo page with Instagram posts from the matching day/time window.

Infrastructure & Key Resources

  • Lambda Function: shipcaptaincrew (us-east-1, account 782785212866)
  • Meta App: sailjada-social (registered in Meta App Dashboard)
  • Guest Photo Page: shipcaptaincrew.queenofsandiego.com/g/{event_id} (e.g., /g/2026-04-29)
  • Instagram Account: @sailjada (Business/Creator account)

Key Architectural Decisions

  • Environment Variables vs. Secrets Manager: While environment variables work, storing sensitive tokens in AWS Secrets Manager would be more secure for production. Consider migrating IG_ACCESS_TOKEN to Secrets Manager and updating the Lambda IAM role to permit secretsmanager:GetSecretValue.
  • Token Refresh Strategy: The 60-day token requires monthly refresh. Set up an EventBridge rule to trigger a Lambda refresh function on day 50, preventing expiration during active event seasons.
  • Error Handling: If