```html

Integrating Instagram Graph API with Lambda: Bridging Social Media into Guest Photo Galleries

What Was Done

We activated the dormant Instagram integration in the shipcaptaincrew Lambda function (us-east-1, account 782785212866) to display @sailjada Instagram posts alongside guest-uploaded charter photos on the guest gallery page at shipcaptaincrew.queenofsandiego.com/g/{event_id}. The integration required proper Instagram Graph API product setup, long-lived token generation, and Lambda environment variable configuration.

The Problem: Why Integration Was Dormant

The Lambda function contained conditional logic that returned an empty media array when IG_USER_ID or IG_ACCESS_TOKEN environment variables were missing. Additionally, the Facebook app sailjada-social had the wrong product configured—it included "Manage Messaging" (designed for Direct Message automation) instead of "Instagram Graph API," which is required to read media and user data.

Why this mattered: The Messaging use case grants different OAuth scopes (designed for DM automation) and cannot request the instagram_basic scope needed to fetch media. This is a common integration mistake when setting up social connectors on Facebook's developer platform.

Technical Architecture: How It Works

The integration follows a three-tier authentication and data flow pattern:

  • Tier 1 (Setup): Generate a short-lived access token via the Facebook Graph API Explorer with appropriate scopes
  • Tier 2 (Exchange): Exchange the short-lived token for a long-lived token (60-day validity) using app credentials
  • Tier 3 (Runtime): Lambda reads IG_USER_ID and IG_ACCESS_TOKEN from environment variables and queries Instagram's media endpoint during guest gallery page loads

Data Flow

When a user visits /g/2026-04-29, the Lambda handler executes this sequence:

1. Parse event_id from path (2026-04-29)
2. Query DynamoDB for approved guest photos matching event date
3. Check if IG_USER_ID and IG_ACCESS_TOKEN are set
4. If both present: call Instagram Graph API endpoint
   GET /ig_user_id/media?fields=id,caption,media_type,media_url,timestamp&access_token=TOKEN
5. Filter results by timestamp window matching event date
6. Merge guest photos + Instagram posts in response JSON
7. Frontend renders combined gallery

Step-by-Step Implementation

Step 1: Add the Correct Product to Facebook App

  1. Navigate to developers.facebook.com/apps
  2. Select the sailjada-social app
  3. In the left sidebar, scroll to the bottom and click + Add Product
  4. Search for "Instagram" in the product catalog
  5. Click Set Up on the Instagram Graph API card (not "Basic Display" or "Messaging")
  6. Select Instagram Graph API when prompted for access type

Why Instagram Graph API specifically: This product grants the instagram_basic scope, which permits reading user profiles, media, and insights. The Messaging product is for automating DM workflows and doesn't grant media read permissions.

Step 2: Verify @sailjada is Business/Creator Account

Confirm that @sailjada is linked to a Facebook Business Page. This is a Facebook Graph prerequisite—personal Instagram accounts cannot use the Graph API for media reads. The account must be switched to Creator or Business mode in Instagram settings.

Step 3: Connect @sailjada via Instagram Login

  1. In your app dashboard, go to Instagram Graph APIAPI Setup with Instagram Login
  2. Click Add Instagram Account
  3. Log in with @sailjada credentials
  4. Authorize the app to access Instagram data

Step 4: Generate Short-Lived Token via Graph API Explorer

  1. Open developers.facebook.com/tools/explorer
  2. In the top dropdown, select sailjada-social app
  3. Click Generate Access Token
  4. Select the Facebook Page linked to @sailjada
  5. When prompted for permissions, ensure these scopes are checked:
    • instagram_basic (read media, user profile)
    • pages_show_list (enumerate pages)
  6. Copy the generated token for the next step

Step 5: Retrieve IG_USER_ID from Facebook Page

The Instagram Graph API requires the numeric Business Account ID, not the @username. Retrieve it via two API calls:

# Call 1: Get Facebook Page ID and linked Instagram account
curl -s "https://graph.instagram.com/v18.0/me/instagram_business_accounts?access_token=YOUR_SHORT_LIVED_TOKEN" | jq '.data[0].id'

# Call 2: Extract and store the returned id as IG_USER_ID
# Example output: "17841401234567890"

Step 6: Exchange Short-Lived Token for Long-Lived Token

Short-lived tokens expire quickly. Exchange it for a long-lived token (valid ~60 days) using your app credentials:

curl -s -X GET \
  "https://graph.instagram.com/v18.0/oauth/access_token" \
  -d "grant_type=ig_refresh_token" \
  -d "access_token=YOUR_SHORT_LIVED_TOKEN" | jq '.access_token'

The returned access_token is your IG_ACCESS_TOKEN environment variable.

Infrastructure Changes

Lambda Environment Variables

Update the shipcaptaincrew Lambda function configuration via AWS CLI:

aws lambda update-function-configuration \
  --function-name shipcaptaincrew \
  --region us-east-1 \
  --environment "Variables={IG_USER_ID=YOUR_NUMERIC_ID,IG_ACCESS_TOKEN=YOUR_LONG_LIVED_TOKEN}" \
  --profile default

No infrastructure resources were created. This is a configuration change only. Environment variables are stored encrypted at rest in Lambda's internal configuration store and decrypted at runtime.

Lambda Function Code Context

The shipcaptaincrew function's handler (likely index.handler in Node.js or lambda_handler in Python) contains conditional logic:

if IG_USER_ID and IG_ACCESS_TOKEN:
    instagram_media = fetch_instagram_media(