```html

Integrating Instagram Graph API into a Guest Photo Lambda: Architecture and Implementation

The guest photo system at shipcaptaincrew.queenofsandience.com/g/{event_id} aggregates two photo sources: user-uploaded charter photos and Instagram posts from @sailjada's account. While the Lambda function had dormant Instagram integration code, it was never activated due to missing credentials and unclear setup steps. This post walks through the technical architecture, Facebook/Instagram app configuration, and Lambda environment updates needed to activate Instagram Graph API integration.

What Was Done

  • Configured Instagram Graph API product in the Facebook app dashboard (separate from the existing Messaging product)
  • Generated and exchanged short-lived access tokens for long-lived tokens (60-day validity)
  • Documented the IG_USER_ID retrieval process using Graph API Explorer and curl
  • Prepared Lambda environment variable updates for the shipcaptaincrew function
  • Outlined a monthly token refresh strategy to maintain continuous integration

Technical Details: Authentication Flow

The Instagram Graph API uses a three-step token exchange pattern. This design choice was necessary because:

  • Short-lived tokens (1 hour) are generated interactively via Graph API Explorer. They're only suitable for testing and cannot be stored.
  • Long-lived tokens (60 days) are obtained by exchanging a short-lived token with the app credentials. These are suitable for production automation and are what gets stored in Lambda environment variables.
  • Monthly refresh prevents token expiration in production. The same exchange endpoint that creates long-lived tokens also refreshes them when called before expiration.

The Facebook app in question, sailjada-social, required a separate Instagram Graph API product setup. A common mistake is adding only the Messaging product—this grants DM scopes but does NOT include instagram_basic, which is required to read media metadata.

Step 1: Product Configuration in Facebook App Dashboard

Navigate to developers.facebook.com/apps and select the sailjada-social app. In the left sidebar, locate "Add Product" (typically near the bottom of the product list). Search for "Instagram" and explicitly select Instagram Graph API. This is distinct from Instagram Basic Display and Instagram Messaging API.

Once added, Instagram Graph API will appear as a new section in the left sidebar. Under "API setup with Instagram login," click "Add Instagram account" and authenticate as @sailjada. The account must be a Business or Creator account linked to a Facebook Page for Graph API access.

Step 2: Short-Lived Token Generation

Open the Graph API Explorer and:

  • Select the sailjada-social app from the app dropdown
  • Click "Generate Access Token"
  • Select the Facebook Page linked to @sailjada
  • Ensure granted scopes include instagram_basic and pages_show_list

This token expires in 1 hour and is used only to retrieve the Instagram User ID from the underlying Facebook Page.

Step 3: Retrieving IG_USER_ID

With the short-lived token from Graph API Explorer, retrieve the Facebook Page ID and then the Instagram Business Account ID. Two API calls are required:

curl -s "https://graph.facebook.com/v18.0/me/accounts?fields=id,name&access_token=SHORT_LIVED_TOKEN"

This returns all Facebook Pages accessible by the token. Identify the Page linked to @sailjada and note its ID. Then:

curl -s "https://graph.facebook.com/v18.0/PAGE_ID?fields=instagram_business_account&access_token=SHORT_LIVED_TOKEN"

The response includes an instagram_business_account object with an id field. This ID is the IG_USER_ID environment variable.

Step 4: Long-Lived Token Exchange

Using the short-lived token, the App ID, and the App Secret (stored securely, never in code), exchange for a 60-day token:

curl -s "https://graph.facebook.com/oauth/access_token?grant_type=fb_exchange_token&client_id=APP_ID&client_secret=APP_SECRET&fb_exchange_token=SHORT_LIVED_TOKEN"

The response includes access_token (the long-lived token) and expires_in (typically 5184000 seconds, or 60 days). Store this token securely as the IG_ACCESS_TOKEN environment variable.

Infrastructure: Lambda Function Updates

The Lambda function shipcaptaincrew (region: us-east-1, account: 782785212866) requires two environment variables:

  • IG_USER_ID: The Instagram Business Account ID retrieved in Step 3
  • IG_ACCESS_TOKEN: The 60-day access token from Step 4

Update the function configuration using:

aws lambda update-function-configuration \
  --function-name shipcaptaincrew \
  --region us-east-1 \
  --environment Variables={IG_USER_ID=RETRIEVED_ID,IG_ACCESS_TOKEN=LONG_LIVED_TOKEN}

The Lambda handler checks for these variables on invocation. If both are present and non-empty, it calls the Instagram Graph API endpoint:

https://graph.facebook.com/v18.0/{IG_USER_ID}/ig_hashtag_search?user_id={IG_USER_ID}&fields=id,name&access_token={IG_ACCESS_TOKEN}

(Adjust endpoint based on your actual query—media feeds typically use /media or similar fields.) If either variable is missing, the function returns an empty array, maintaining backward compatibility.

Key Decisions

  • 60-day tokens over user-initiated refresh: Long-lived tokens reduce operational burden. A user doesn't need to manually re-authenticate monthly; a scheduled refresh (via EventBridge) can silently exchange the token using app credentials.
  • Graph API Explorer for initial setup: While less automated, it clarifies the exact scopes and accounts involved. This reduces debugging confusion later.
  • Separate Instagram Graph API product: This explicit decision ensures the correct API version and permissions are granted. Messaging-only products cannot read media.
  • Environment variables in Lambda: Storing tokens in function environment variables (encrypted at rest by AWS) keeps them out of code repositories while remaining accessible to the handler logic.

What's Next

  • Token refresh automation: Create an EventBridge rule that triggers a Lambda function