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

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 photo page at shipcaptaincrew.queenofsandiego.com/g/{event_id}. The integration requires obtaining an Instagram Graph API access token and storing two environment variables (IG_USER_ID and IG_ACCESS_TOKEN) in the Lambda function configuration.

Technical Details: Instagram Graph API Setup

Why Instagram Graph API (Not Basic Display)

The sailjada-social Meta app initially had the Messaging product added, which only grants Direct Message scopes. To read Instagram business account media, we need the Instagram Graph API product, which provides the instagram_basic scope. This scope allows reading media, captions, and metadata from a connected business/creator account.

Account Prerequisites

  • The @sailjada Instagram account must be a Business or Creator account (not a Personal account)
  • It must be linked to a Facebook Page in Meta Business Suite
  • The Meta app must be configured to allow Instagram account connection

Step 1: Add Instagram Graph API Product

Navigate to the Meta App Dashboard for sailjada-social:

  1. Go to developers.facebook.com/apps and select the sailjada-social app
  2. Click Add Product in the left sidebar
  3. Search for Instagram and select Instagram Graph API (not Basic Display)
  4. Complete setup — the product will appear in your sidebar

Step 2: Connect @sailjada Account

Within Instagram Graph API → API setup, click Add Instagram account and authenticate as @sailjada. This establishes the connection between the app and the business account.

Step 3: Generate a Short-Lived Access Token

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

  1. Visit developers.facebook.com/tools/explorer
  2. Select sailjada-social app from the dropdown
  3. Generate Access Token with scopes: instagram_basic, pages_show_list
  4. Select the Facebook Page linked to @sailjada

Obtaining IG_USER_ID and IG_ACCESS_TOKEN

Retrieve IG_USER_ID from Facebook Page

Using the short-lived token from Step 3, make two API calls to map your Facebook Page to the Instagram Business Account ID:

curl -s "https://graph.instagram.com/me/accounts?access_token=YOUR_SHORT_LIVED_TOKEN"

This returns your Facebook Page ID. Then query the Instagram business account linked to that page:

curl -s "https://graph.instagram.com/{PAGE_ID}?fields=instagram_business_account&access_token=YOUR_SHORT_LIVED_TOKEN"

The id field within the instagram_business_account object is your IG_USER_ID. Store this value securely.

Exchange for a Long-Lived Access Token

The short-lived token from the Explorer expires quickly. Exchange it for a long-lived token valid for 60 days using your app credentials:

curl -s "https://graph.instagram.com/oauth/access_token" \
  -d "grant_type=fb_exchange_token" \
  -d "client_id=YOUR_APP_ID" \
  -d "client_secret=YOUR_APP_SECRET" \
  -d "access_token=YOUR_SHORT_LIVED_TOKEN"

The returned access_token is your IG_ACCESS_TOKEN. This token is valid for 60 days and can be refreshed using the same endpoint before expiration.

Infrastructure: Lambda Environment Variables

Update the shipcaptaincrew Lambda function in us-east-1 with the two environment variables:

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_IG_ACCESS_TOKEN}"

These variables are referenced in the Lambda handler code. When both are present, the function's Instagram integration activates; previously, missing values caused it to return an empty array.

Key Decisions

Token Refresh Strategy

Rather than implement automatic token refresh within the Lambda (which would require storing the app secret in the function environment, a security anti-pattern), we chose a manual monthly refresh workflow. The 60-day token lifespan provides a two-month buffer before manual intervention is needed. For production, this could be automated via:

  • An EventBridge rule triggering a separate refresh Lambda every 30 days
  • A secrets management service (AWS Secrets Manager) storing the app secret securely
  • The refresh Lambda exchanging the current token for a fresh one and updating the function configuration

For now, the manual approach reduces operational complexity while maintaining functionality.

Scope Minimalism

We requested only instagram_basic and pages_show_list scopes rather than broader permissions. This follows the principle of least privilege—the Lambda only needs to read media from @sailjada's account, not manage it or access other resources.

Integration Verification

Once the environment variables are set, test the integration by visiting:

https://shipcaptaincrew.queenofsandiego.com/g/2026-04-29

The guest photo page should now display Instagram posts from @sailjada within the same date/time window as the uploaded guest photos. The Lambda handler queries the Instagram Graph API using the IG_USER_ID and IG_ACCESS_TOKEN, filters posts by timestamp, and merges them into the response.

What's Next

  • Implement automatic token refresh: Create an EventBridge rule and refresh Lambda to exchange tokens 45 days after deployment
  • Add error handling: Gracefully degrade if the Instagram API is unavailable or token is expired
  • Cache Instagram posts: Consider caching API responses in DynamoDB to reduce API calls and improve page load time
  • Monitor token expiration: Add CloudWatch alarms to alert when the access token is nearing expiration