Integrating Instagram Graph API with AWS Lambda: Connecting @sailjada Media to Guest Photo Pages
What Was Done
We integrated Instagram Graph API into the shipcaptaincrew Lambda function (us-east-1, account 782785212866) to dynamically fetch and display @sailjada Instagram posts on guest photo pages. The system now pulls media from the same day/time window as guest-uploaded charter photos, enriching the user experience at shipcaptaincrew.queenofsandiego.com/g/{event_id} (e.g., /g/2026-04-29).
Previously, the Instagram integration was dormant—returning empty arrays when environment variables were missing. This walkthrough establishes the credential exchange flow, token lifecycle management, and Lambda configuration needed to activate the feature.
Technical Details: Token Exchange Flow
Instagram Graph API uses a two-token architecture. Understanding this flow is critical before implementation:
- Short-lived tokens (1 hour): Generated via the Graph API Explorer or OAuth dialog. These are human-initiated and scoped narrowly (e.g.,
instagram_basic,pages_show_list). - Long-lived tokens (60 days): Exchanged server-side using your App ID and App Secret. These survive the short-lived token's expiration and are suitable for Lambda environment variables.
Why this matters: The Messaging use case in the Meta App Dashboard grants different scopes (e.g., instagram_manage_messages) and will not allow you to read media. You must explicitly add the Instagram Graph API product, not rely on Messaging.
Step 1: Add the Correct Product
In the Meta App Dashboard for sailjada-social:
- Navigate to Add Product (left sidebar, near the bottom)
- Search for and select Instagram Graph API
- Choose Instagram Graph API as the access type (not Basic Display, not Messaging)
This gives you access to the /ig_user/media endpoint needed to fetch posts for a Business or Creator account.
Step 2: Connect the Instagram Account
Inside Instagram Graph API settings:
- Go to API Setup
- Select Add Instagram Account
- Log in as
@sailjada(the account must be a Business or Creator account, not Personal) - Authorize the app
Step 3: Generate a Short-Lived Token
Visit developers.facebook.com/tools/explorer:
- Select app:
sailjada-social - Click Generate Access Token
- Select the Facebook Page linked to
@sailjada - Request these scopes:
instagram_basic,pages_show_list - Copy the token (valid for ~1 hour)
Step 4: Retrieve the Instagram User ID
Using the short-lived token, make two API calls:
# First, get the page ID and instagram_business_account
curl -s "https://graph.instagram.com/v18.0/me?fields=instagram_business_account&access_token=SHORT_LIVED_TOKEN"
# Response will include a page_id under instagram_business_account
# Then fetch the IG_USER_ID using that account ID
curl -s "https://graph.instagram.com/v18.0/{INSTAGRAM_BUSINESS_ACCOUNT_ID}?fields=id,name&access_token=SHORT_LIVED_TOKEN"
# The "id" field is your IG_USER_ID (store this permanently)
Why two calls: The Graph API requires you to traverse from the logged-in user → Facebook Page → Instagram Business Account. This three-step relationship is by design in Meta's permission model.
Step 5: Exchange for a Long-Lived Token
Call the token-exchange endpoint:
curl -X GET "https://graph.instagram.com/v18.0/access_token" \
-d "grant_type=fb_exchange_token" \
-d "client_id=YOUR_APP_ID" \
-d "client_secret=YOUR_APP_SECRET" \
-d "access_token=SHORT_LIVED_TOKEN"
The response includes a new access_token valid for 60 days. This is your IG_ACCESS_TOKEN environment variable.
Infrastructure: Lambda Configuration
Update the shipcaptaincrew Lambda function with environment variables:
aws lambda update-function-configuration \
--function-name shipcaptaincrew \
--region us-east-1 \
--environment Variables="{
IG_USER_ID=YOUR_INSTAGRAM_USER_ID,
IG_ACCESS_TOKEN=YOUR_LONG_LIVED_TOKEN
}"
The Lambda code (already in place) reads these variables on invocation. When both are present, it queries the Instagram Graph API:
GET https://graph.instagram.com/v18.0/{IG_USER_ID}/media
?fields=id,caption,media_type,media_url,timestamp
&access_token={IG_ACCESS_TOKEN}
Key Decisions
- Long-lived tokens over short-lived: Lambda is stateless and doesn't handle OAuth redirects. A 60-day token stored in environment variables is the practical choice for this architecture.
- Graph API over Basic Display: Basic Display restricts you to hashtag and user search. Graph API gives direct access to a Business Account's media, required for filtering by timestamp.
- No EventBridge initially: The 60-day token window is sufficient for manual monthly refresh. If you need automation, EventBridge can trigger a Lambda refresh function, but that's secondary.
- Date/time window filtering in Lambda: The API returns all media; the Lambda code filters by event date (e.g.,
2026-04-29) and merges with guest photos in-memory before rendering.
Verification
Once Lambda is updated, test at:
https://shipcaptaincrew.queenofsandiego.com/g/2026-04-29
The guest photo page should now display both guest uploads and any @sailjada posts from that day. Check CloudWatch Logs for the shipcaptaincrew function if posts don't appear:
aws logs tail /aws/lambda/shipcaptaincrew --follow
What's Next
- Token refresh automation: Create a
refresh-instagram-tokenLambda function that exchanges the token monthly, triggered by EventBridge.