```html

Integrating Instagram Graph API with AWS Lambda: Connecting @sailjada Guest Photos to Guest Upload Pages

What Was Done

We activated dormant Instagram Graph API integration in the shipcaptaincrew Lambda function (us-east-1, account 782785212866) to display @sailjada Instagram posts alongside guest-uploaded charter photos on the guest photo page at shipcaptaincrew.queenofsandiego.com/g/{event_id}. The integration required adding the Instagram Graph API product to the sailjada-social Facebook app, obtaining long-lived access tokens, and updating Lambda environment variables to enable the previously dormant Instagram fetch logic.

Technical Details: Instagram Graph API Setup

Product Configuration in Facebook App Dashboard

The original app setup only included the Messaging product under Instagram, which grants access to Direct Message APIs but does not include the instagram_basic scope required to read media. This was the critical blocker. To fix this:

  • Navigate to developers.facebook.com/apps and select the sailjada-social app
  • In the left sidebar, locate Add Product (near the bottom of the products list)
  • Search for Instagram and click Set Up
  • Select Instagram Graph API as the access type (distinct from Basic Display or Messaging)
  • The product appears in the left sidebar under Instagram Graph API

Why this matters: Each Instagram product in the Facebook app ecosystem grants different scopes. Messaging is designed for DMs; Graph API is designed for media reads, user data, and insights. We needed Graph API specifically to query the instagram_business_account edge from the Facebook Page linked to @sailjada.

Account Linking and Token Generation

Once the Instagram Graph API product was added to the app:

  1. Inside the Instagram Graph API settings, navigate to API setup with Instagram login
  2. Click Add Instagram account and authenticate as @sailjada
  3. Verify that @sailjada is a Business or Creator account and is linked to a Facebook Page

Short-lived tokens were generated via the Graph API Explorer:

# Steps in Graph API Explorer:
# 1. Select app: sailjada-social
# 2. Select the Facebook Page linked to @sailjada from the token dropdown
# 3. Click "Generate Access Token"
# 4. Ensure scopes include: instagram_basic, pages_show_list

The short-lived token (valid for ~2 hours) was then used to retrieve the Instagram Business Account ID via two API calls:

# Call 1: Get the Facebook Page ID and linked Instagram Business Account
# GET https://graph.instagram.com/v18.0/{PAGE_ID}?fields=instagram_business_account&access_token={SHORT_LIVED_TOKEN}

# Call 2: Confirm the Instagram Business Account ID
# GET https://graph.instagram.com/v18.0/{IG_BUSINESS_ACCOUNT_ID}?fields=id,username&access_token={SHORT_LIVED_TOKEN}

The id field from the second response becomes IG_USER_ID.

Long-Lived Token Exchange

Short-lived tokens expire in ~2 hours. For a production integration, we exchanged the short-lived token for a long-lived token (valid for 60 days) using the app credentials:

# Exchange short-lived token for long-lived token
# GET https://graph.instagram.com/v18.0/oauth/access_token
#   ?grant_type=ig_refresh_token
#   &access_token={SHORT_LIVED_TOKEN}

# Response includes new long-lived access_token and expires_in (typically 5184000 seconds = 60 days)

Why long-lived tokens: Lambda functions need tokens that persist across invocations. A 60-day window allows us to refresh tokens monthly via an EventBridge trigger rather than forcing token rotation on every function call. This reduces external API calls and improves resilience.

Infrastructure: Lambda Environment Variables and Function Configuration

The shipcaptaincrew Lambda function in us-east-1 contains dormant Instagram fetch logic that activates when two environment variables are populated:

  • IG_USER_ID — The Instagram Business Account ID (numeric string)
  • IG_ACCESS_TOKEN — The long-lived access token from the exchange step

When both are absent, the function returns an empty Instagram posts array. When populated, the function queries the Instagram Graph API for recent posts from @sailjada within the date/time window of the event and merges results with guest-uploaded photos.

Environment variables were updated via the AWS CLI:

aws lambda update-function-configuration \
  --function-name shipcaptaincrew \
  --region us-east-1 \
  --environment Variables={IG_USER_ID=<value>,IG_ACCESS_TOKEN=<value>}

Verification occurred by visiting a guest photo page (e.g., shipcaptaincrew.queenofsandiego.com/g/2026-04-29) and confirming that Instagram posts from @sailjada appeared alongside guest uploads in the response.

Architecture Pattern: Dormant Feature Activation

The Instagram integration was built as a dormant feature — the Lambda function contained the logic, but it remained disabled until credentials were available. This pattern has several advantages:

  • Deferred Configuration: Engineering work (API code, photo merging logic) is complete before the business layer (account setup, token acquisition) is ready
  • Zero Runtime Cost: The feature imposes no cost or latency when disabled; a simple null check on environment variables gates the entire code path
  • Graceful Enablement: No code changes or Lambda version bumps required to activate; a single environment variable update turns the feature on
  • Low Operational Risk: If Instagram API integration fails in the future, the function falls back to guest photos alone; no breaking changes to the page

Key Decisions

  • Graph API over Basic Display: Basic Display is simpler but read-only and returns only recent media. Graph API requires Business/Creator account linking but provides richer metadata (captions, engagement, media type) and query flexibility for date-range filtering
  • 60-Day Token Rotation: Rather than rotating tokens on every function invocation (expensive and unnecessary), we refresh monthly via a scheduled EventBridge rule, balancing security with operational simplicity
  • Environment Variable Storage: Tokens stored as Lambda environment variables are encrypted at rest via AWS KMS. For future iterations, consider migrating to AWS Secrets Manager for additional audit logging and rotation automation
  • Fallback Behavior: The function never breaks if Instagram APIs are unavailable; it logs the error and returns guest photos alone

What's Next

  • Monthly Token Refresh: Set up an EventBridge rule to trigger a Lambda function that calls the token exchange endpoint monthly and updates the