Integrating Instagram Graph API with AWS Lambda: Connecting @sailjada to Guest Photo Pages
We recently enabled Instagram media integration in our guest photo gallery system at shipcaptaincrew.queenofsandiego.com/g/{event_id}. The Lambda function was architecturally ready to fetch and display @sailjada Instagram posts alongside user-uploaded charter photos, but the integration was dormant—awaiting proper Graph API credentials. This post walks through the exact steps we took to activate it.
What Was Done
The shipcaptaincrew Lambda function (region: us-east-1, account: 782785212866) had hardcoded logic to fetch Instagram posts when environment variables IG_USER_ID and IG_ACCESS_TOKEN were present. We:
- Added the Instagram Graph API product to the existing
sailjada-socialapp in Meta Developer Dashboard - Generated a short-lived access token with
instagram_basicandpages_show_listscopes - Exchanged it for a long-lived token (60-day validity)
- Extracted the
IG_USER_IDfrom the Instagram business account linked to @sailjada - Updated the Lambda function configuration with both credentials
- Verified the integration by loading a guest photo page
Technical Details
Step 1: Add the Correct Product
The critical first blocker was product selection. Our app previously had "Messaging" added, which grants instagram_manage_messages scope but not instagram_basic—required to read media.
Process:
- Navigate to
developers.facebook.com/apps→sailjada-socialapp - Left sidebar → Add Product
- Search for Instagram → select Instagram Graph API (not Basic Display, not Messaging)
- Complete API setup flow; Instagram Graph API now appears in the product list
Why this matters: Meta's product matrix is granular. Each product grants a specific scope set. Messaging handles DM workflows; Graph API handles media, insights, and follower data. We needed Graph API.
Step 2: Verify @sailjada Account Status
@sailjada must be a Business or Creator account and linked to a Facebook Page for Graph API access. We confirmed:
- @sailjada account type: Business
- Linked to Facebook Page: Queen of San Diego (verified via Settings → Linked Accounts)
Step 3: Generate a Short-Lived Token
Using the Graph API Explorer at developers.facebook.com/tools/explorer:
- Selected app dropdown:
sailjada-social - Clicked Generate Access Token
- Authenticated as the account owning the Facebook Page
- Approved scopes:
instagram_basic,pages_show_list - Copied the resulting token (valid for ~2 hours)
Step 4: Extract IG_USER_ID
With the short-lived token, we made two API calls:
curl -s "https://graph.instagram.com/v18.0/me/accounts?access_token=SHORT_LIVED_TOKEN" \
| jq '.data[] | select(.name=="Queen of San Diego") | .id'
This returned the Facebook Page ID. Then:
curl -s "https://graph.instagram.com/v18.0/PAGE_ID?fields=instagram_business_account&access_token=SHORT_LIVED_TOKEN" \
| jq '.instagram_business_account.id'
The id field in the response is IG_USER_ID.
Step 5: Exchange for Long-Lived Token
Short-lived tokens expire in ~2 hours. For Lambda environment variables, we needed a long-lived token (60-day validity):
curl -s "https://graph.instagram.com/v18.0/oauth/access_token" \
-d "grant_type=fb_exchange_token" \
-d "client_id=APP_ID" \
-d "client_secret=APP_SECRET" \
-d "access_token=SHORT_LIVED_TOKEN" \
| jq '.access_token'
The returned access_token is IG_ACCESS_TOKEN. Both APP_ID and APP_SECRET are stored in the Meta Developer Dashboard (Settings → Basic).
Infrastructure: Lambda Configuration Update
With both credentials obtained, we updated the shipcaptaincrew Lambda function:
aws lambda update-function-configuration \
--function-name shipcaptaincrew \
--region us-east-1 \
--environment Variables="{IG_USER_ID=extracted_user_id,IG_ACCESS_TOKEN=long_lived_token}" \
--no-cli-pager
Note: Environment variables are encrypted at rest using Lambda's default KMS key (alias/aws/lambda). For production, consider a customer-managed KMS key and explicit IAM policies.
The Lambda execution role (shipcaptaincrew-role) requires no additional permissions—the function makes outbound HTTPS calls to graph.instagram.com, not AWS APIs.
Verification
After deployment, we loaded shipcaptaincrew.queenofsandiego.com/g/2026-04-29 and verified:
- Guest-uploaded photos render correctly
- Instagram posts from @sailjada on 2026-04-29 appear in the same gallery
- No Lambda errors in CloudWatch Logs (log group:
/aws/lambda/shipcaptaincrew)
Key Decisions & Rationale
- Long-lived tokens over short-lived: Short-lived tokens require monthly refresh logic. Long-lived tokens (60 days) reduce operational burden but still enforce regular rotation. We plan a monthly refresh job via EventBridge if future requirements demand it.
- Environment variables for credentials: Lambda environment variables are the standard pattern for non-sensitive config. For highly sensitive credentials (e.g., payment processors), AWS Secrets Manager would be preferable, but Instagram access tokens are scoped to a single account and regenerable.