```html

Integrating Instagram Graph API with AWS Lambda for Guest Photo Aggregation

We recently enabled Instagram media integration in our guest photo page system at shipcaptaincrew.queenofsandiego.com/g/{event_id}. This post documents the technical approach to connecting the Instagram Graph API to our Lambda function, the architectural decisions behind token management, and the setup process we implemented.

What Was Done

The shipcaptaincrew Lambda function (us-east-1, account 782785212866) now pulls Instagram posts from the @sailjada business account and displays them alongside guest-uploaded charter photos within a 24-hour event window. Previously, the Instagram integration code existed but remained dormant due to missing credentials. We implemented a complete token acquisition and refresh strategy to activate this feature.

Technical Architecture

Instagram Graph API Product Setup

The critical first step was adding the correct product to our Facebook app (sailjada-social). While the app previously had the Messaging product configured (for direct message use cases), that product type does not grant the instagram_basic scope required to read media objects. The solution involved:

  • Navigating to developers.facebook.com/apps and selecting the sailjada-social app
  • Adding the Instagram Graph API product (distinct from Basic Display and Messaging variants)
  • Connecting the @sailjada business account via the Instagram Graph API setup flow in the app dashboard

Why this approach: The Instagram Graph API product is designed for server-to-server interactions with business accounts and grants the minimal scopes needed for media read operations. This is more secure than broad permissions and follows the principle of least privilege.

Token Acquisition Workflow

We implemented a two-stage token exchange process:

  1. Short-lived token generation: Using the Graph API Explorer at developers.facebook.com/tools/explorer, we generated a short-lived access token (valid ~hours) with scopes instagram_basic and pages_show_list. This token is bound to the user who generated it and is unsuitable for long-term server use.
  2. IG_USER_ID retrieval: With the short-lived token, we made two API calls:
    curl "https://graph.instagram.com/v18.0/me/accounts?access_token=SHORT_LIVED_TOKEN"
    This returned the Facebook Page ID linked to @sailjada. A subsequent call extracted the Instagram Business Account ID:
    curl "https://graph.instagram.com/v18.0/{PAGE_ID}?fields=instagram_business_account&access_token=SHORT_LIVED_TOKEN"
    The id field within instagram_business_account became our IG_USER_ID environment variable.
  3. Long-lived token exchange: We exchanged the short-lived token for a long-lived token (60-day validity) using the OAuth token exchange endpoint with our app's credentials:
    curl -X GET "https://graph.instagram.com/v18.0/oauth/access_token?grant_type=ig_refresh_token&access_token=SHORT_LIVED_TOKEN&client_id=APP_ID&client_secret=APP_SECRET"
    The returned access_token became our IG_ACCESS_TOKEN Lambda environment variable.

Lambda Environment Configuration

The shipcaptaincrew function's configuration was updated with two new environment variables:

  • IG_USER_ID — the Instagram Business Account ID extracted in step 2
  • IG_ACCESS_TOKEN — the long-lived token from the OAuth exchange

These were applied via the AWS Lambda update command (credentials redacted):

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

The Lambda code already contained conditional logic to return an empty array if these variables were undefined, so activation required only environment variable injection—no function code changes.

Key Architectural Decisions

Token Lifespan and Refresh Strategy

We chose 60-day long-lived tokens over indefinite tokens because:

  • Security rotation: Automatic expiration forces periodic credential rotation, limiting blast radius if a token leaks.
  • Operational simplicity: A monthly EventBridge rule can trigger a Lambda that calls the token exchange endpoint and updates the function's environment variables. This avoids manual intervention while respecting the 60-day window.
  • Instagram API design: Long-lived tokens are the documented pattern for server-side integrations and are the only choice if immediate user login isn't feasible.

Business Account Requirement

We confirmed that @sailjada is configured as a Business or Creator account (not a Consumer account). Only business accounts have an associated Instagram Graph API ID and can be accessed server-side. This is an Instagram platform constraint, not an implementation choice, but it's worth noting for any future account changes.

Scopes and Permissions

We requested only instagram_basic and pages_show_list scopes. The instagram_basic scope grants access to media objects, media fields, and user information. pages_show_list allows enumeration of Facebook pages linked to the authenticating user. This combination is the minimum required to fetch a list of media from @sailjada without requesting write or insights permissions.

Verification and Next Steps

After environment variable deployment, the Lambda became active. We verified functionality by visiting shipcaptaincrew.queenofsandiego.com/g/2026-04-29 (or any recent event date) and confirming that Instagram posts from @sailjada within the 24-hour window appear alongside guest photos.

The token refresh strategy should be formalized via an EventBridge rule that triggers a helper Lambda monthly. This helper would:

  • Call the Instagram token exchange endpoint with the current IG_ACCESS_TOKEN
  • Write the new token back to the shipcaptaincrew function's environment
  • Log the operation for audit trails

Until this is implemented, manual token refresh is required every 60 days, so calendar reminders should be set for the token expiration date (which can be decoded from the JWT if needed).

Summary

The Instagram Graph API integration is now live. The key lesson was understanding that different Facebook app products grant different scopes—choosing the right product at setup time saved significant troubleshooting. The two-stage token flow (short-lived → long-lived) balances security and operational convenience for server-side integrations. Moving forward, automating the token refresh will eliminate manual maintenance and ensure the feature remains active indefinitely.

```