Integrating Instagram Graph API into Lambda: Adding Media Read Permissions to a Guest Photo Gallery
Context
The shipcaptaincrew Lambda function (us-east-1, account 782785212866) powers a guest photo gallery at shipcaptaincrew.queenofsandiego.com/g/{event_id} that displays approved guest-uploaded photos alongside Instagram posts from @sailjada captured during the same event window. The Instagram integration was scaffolded but dormant—returning an empty array when environment variables were missing. This post covers the exact steps to activate that integration using Instagram's Graph API.
What Was Done
We added the Instagram Graph API product to the existing sailjada-social Facebook app, generated appropriate access tokens with the correct scopes, and prepared the Lambda function to accept and use those credentials. The key blocker: the app already had the Instagram Messaging product configured, which grants DM-related permissions but not media read access. We needed to add Graph API as a separate product.
Why This Approach
Instagram Basic Display and Messaging products serve different use cases. Basic Display is read-only but limited in metadata. Graph API requires business/creator account status but provides richer media metadata, insights, and timestamps—essential for matching guest photos to Instagram posts within a time window. The shipcaptaincrew Lambda needed Graph API specifically to read media timestamps and filter by event date.
Technical Details: Step-by-Step Integration
Step 1: Add Instagram Graph API Product
Navigate to developers.facebook.com/apps and select the sailjada-social app. In the left sidebar, find "Add Product" and search for "Instagram." Select Instagram Graph API (not Basic Display or Messaging). This product grants access to the /ig_user and media endpoints needed to fetch posts and their metadata.
Step 2: Confirm @sailjada Account Status
Verify that @sailjada is configured as a Business or Creator account and is linked to a Facebook Page. Graph API requires this; personal accounts cannot use these endpoints. The @sailjada account must have a corresponding Facebook Page in the same Meta Business Suite.
Step 3: Connect the Instagram Account
Within the Instagram Graph API product settings, navigate to "API Setup" and click "Add Instagram Account." Log in with @sailjada credentials. Meta will prompt for authorization to link the account to your sailjada-social app.
Step 4: Generate a Short-Lived Access Token
Use the Graph API Explorer. From the dropdown, select the sailjada-social app. Generate an access token and request the following scopes:
instagram_basic— read Instagram account info and mediapages_show_list— enumerate Facebook Pages linked to your account
This short-lived token (valid ~2 hours) is used to fetch the Instagram User ID in the next step.
Step 5: Retrieve the Instagram User ID
Use the short-lived token to query the Facebook Graph API endpoint for the Page's linked Instagram business account:
curl -X GET "https://graph.instagram.com/v18.0/{PAGE_ID}?fields=instagram_business_account&access_token={SHORT_LIVED_TOKEN}"
Replace {PAGE_ID} with the Facebook Page ID linked to @sailjada (found in Page Settings → About). The response JSON contains an instagram_business_account object; extract its id field. This is your IG_USER_ID.
Step 6: Exchange for a Long-Lived Access Token
Short-lived tokens expire in ~2 hours. Use the Graph API token endpoint to exchange it for a long-lived token (valid 60 days):
curl -X GET "https://graph.instagram.com/access_token?grant_type=ig_refresh_token&access_token={SHORT_LIVED_TOKEN}"
The returned access_token is your IG_ACCESS_TOKEN. Store this securely in AWS Secrets Manager or your deployment secrets file.
Step 7: Token Refresh Strategy
Long-lived tokens expire after 60 days but can be refreshed using the same endpoint above. Implement a monthly refresh via AWS Lambda scheduled with EventBridge (cron: 0 0 1 * ? * for the first of each month) or manually refresh before expiration. The refresh call uses the existing long-lived token to generate a fresh one without requiring user re-authentication.
Infrastructure: Lambda Configuration
The shipcaptaincrew Lambda function expects two environment variables:
IG_USER_ID— the Instagram business account ID from Step 5IG_ACCESS_TOKEN— the long-lived token from Step 6
Update the function configuration using the AWS CLI:
aws lambda update-function-configuration \
--function-name shipcaptaincrew \
--region us-east-1 \
--environment Variables="{IG_USER_ID=12345...,IG_ACCESS_TOKEN=IGQVJy...}"
The Lambda handler (located at lambda_function.py in the deployment package) checks for these variables on invocation. If present, it calls the Instagram Graph API when processing a guest event:
GET https://graph.instagram.com/v18.0/{IG_USER_ID}/media?fields=id,caption,media_type,timestamp&access_token={IG_ACCESS_TOKEN}
Key Decisions
- Graph API over Basic Display: Basic Display lacks timestamp metadata, making time-window filtering impractical. Graph API requires business account status but grants the metadata we need.
- Long-lived tokens (60 days) vs. short-lived (2 hours): Storing a long-lived token avoids requiring a token exchange on every Lambda invocation, reducing latency and API calls. Monthly refresh is a reasonable operational cadence.
- Environment variables vs. Secrets Manager: For higher-security deployments, migrate
IG_ACCESS_TOKENto AWS Secrets Manager and update the Lambda handler to retrieve it at runtime. - Scopes:
instagram_basic+pages_show_list: Minimal scopes needed. Do not requestinstagram_manage_messagesor other elevated permissions unless your use case changes.
Verification
Once environment variables are set, visit shipcaptaincrew.queenofsandiego.com/g/2026-04-29 (or any event date with known Instagram posts). The page should now display both guest photos and @sailjada Instagram posts from that date, merged and sorted by timestamp.
What's Next
Monitor token expiration dates and automate monthly refresh via EventBridge. Consider adding error handling in the Lambda to gracefully degrade if the Instagram API is unreachable or the token expires. Log API calls to CloudWatch for debugging and