```html

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-social app in Meta Developer Dashboard
  • Generated a short-lived access token with instagram_basic and pages_show_list scopes
  • Exchanged it for a long-lived token (60-day validity)
  • Extracted the IG_USER_ID from 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/appssailjada-social app
  • 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.