```html

Integrating Instagram Graph API with AWS Lambda: Building Photo Gallery Sync for Charter Events

What Was Done

We integrated Facebook's Instagram Graph API into an existing AWS Lambda function that powers a guest photo gallery system. The shipcaptaincrew Lambda function (deployed in us-east-1, account 782785212866) now has the infrastructure in place to fetch @sailjada Instagram posts and merge them with user-uploaded charter photos, displayed on dynamic event pages at the pattern /g/{event_id} (e.g., /g/2026-04-29).

The integration was previously dormant—the Lambda contained graph API fetch logic but returned empty arrays when environment variables were missing. This walkthrough documents the configuration needed to activate it.

Technical Architecture: Why This Approach

Rather than implementing a custom OAuth flow or building a separate photo sync service, we leveraged Facebook's application-level authentication model. This decision was driven by several factors:

  • Long-lived token model: Instagram Graph API supports 60-day access tokens that can be refreshed server-to-server without user interaction. This eliminates the need to ask @sailjada to re-authenticate monthly.
  • Business Account requirement: @sailjada must be a Business or Creator account (not a personal account) to expose the Instagram Graph API surface. This aligns with the brand's professional use case.
  • Page-to-Account linkage: Instagram business accounts are accessed through their linked Facebook Page. The Graph API traversal is: Facebook App → Page → instagram_business_account node → media endpoint.
  • Lambda environment variables: Storing IG_USER_ID and IG_ACCESS_TOKEN as Lambda environment variables keeps the function stateless and allows token rotation without code redeploy.

Infrastructure Setup: Exact Steps

Step 1: Add Instagram Graph API Product

The app sailjada-social (app ID: 1688884572116630) already had a "Messaging" product configured. This grants messaging-related scopes but does NOT grant instagram_basic, which is required to read media. The fix is to add a separate product:

  • Navigate to developers.facebook.com/apps → select the sailjada-social app
  • Click Add Product in the left sidebar (near the bottom)
  • Search for "Instagram" and select Instagram Graph API (not "Basic Display")
  • Complete setup—this adds the product to your app's sidebar

Step 2: Connect @sailjada Account

Inside the newly added Instagram Graph API product:

  • Go to Instagram Graph APIAPI setup with Instagram login
  • Click Add Instagram account
  • Log in with @sailjada credentials
  • This links the business account to your app and allows API calls on its behalf

Step 3: Generate Short-Lived Access Token

Use the Graph API Explorer to generate a token with the correct scopes:

  • Go to developers.facebook.com/tools/explorer
  • In the top-left dropdown, select the sailjada-social app
  • Click Generate Access Token
  • Select the Facebook Page linked to @sailjada
  • In the Permissions panel, ensure these scopes are selected:
    • instagram_basic
    • pages_show_list
  • Generate and copy the token (valid for ~2 hours)

Step 4: Retrieve IG_USER_ID

Use the short-lived token to query your page and extract the Instagram business account ID:

curl -s "https://graph.instagram.com/me/accounts?fields=instagram_business_account&access_token=YOUR_SHORT_LIVED_TOKEN" | jq '.'
# Returns: { "data": [ { "instagram_business_account": { "id": "..." }, ... } ] }

# Extract the ID, then call:
curl -s "https://graph.instagram.com/{PAGE_ID}?fields=instagram_business_account&access_token=YOUR_SHORT_LIVED_TOKEN" | jq '.instagram_business_account.id'
# This is your IG_USER_ID

Step 5: Exchange for Long-Lived Token

The short-lived token is only valid for 2 hours. Exchange it for a 60-day token:

curl -s "https://graph.instagram.com/oauth/access_token" \
  -d "grant_type=fb_exchange_token" \
  -d "client_id=1688884572116630" \
  -d "client_secret=YOUR_APP_SECRET" \
  -d "access_token=YOUR_SHORT_LIVED_TOKEN" | jq '.access_token'
# Returns: a 60-day access token (IG_ACCESS_TOKEN)

Step 6: Update Lambda Environment Variables

Configure the shipcaptaincrew function with the two values obtained above:

aws lambda update-function-configuration \
  --function-name shipcaptaincrew \
  --region us-east-1 \
  --environment Variables="{IG_USER_ID=YOUR_IG_USER_ID,IG_ACCESS_TOKEN=YOUR_60_DAY_TOKEN}"

The Lambda function (file: /Users/cb/Documents/repos/sites/queenofsandiego.com/tools/shipcaptaincrew/lambda_function.py) checks for these variables on each invocation. If present, it fetches Instagram media within the event's time window and merges results with the guest photo database.

Key Decision: Token Refresh Strategy

Instagram's 60-day tokens must be refreshed periodically. Rather than implement a separate cron-based Lambda, we use a simple, human-driven refresh:

  • Set a calendar reminder for day 55 of each cycle
  • Re-run steps 3–5 above (generate short-lived token, exchange for long-lived)
  • Update the environment variable with a single CLI command

This approach avoids additional Lambda functions, DynamoDB state tracking, or EventBridge rules. For higher-scale use cases, a dedicated refresh Lambda triggered by EventBridge would be warranted.

Testing & Verification

Once the environment variables are set, test the integration by visiting an event gallery page:

curl -s "https://shipcaptaincrew.queenofsandiego.com/g/2026-04-29" | grep -i "instagram\|sailjada"

If Instagram posts appear in the HTML or in the JSON response, the API is working. Check CloudWatch Logs for the Lambda function to debug any permission or API errors:

aws logs tail /aws/lambda/shipcaptaincrew --region us-east-1 --follow