API Reference — Rev. 2026-07-13

Beyond DM Automation — Endpoint Spec

Every endpoint involved in the creator login, profile, and DM automation flow: method, full URL, who calls it, and exact request/response shapes. Hand this directly to frontend/backend for integration.

Base URL  https://app.gobeyond.now Format  JSON unless noted Auth  Bearer session token on all /api/* and utility endpoints
2026-07-13: all OAuth callbacks (/oauth/callback, /oauth/fb-callback, /instagram-demo/auth/callback) changed from returning plain JSON to a popup postMessage handoff — open the login flow with window.open(), listen for a message event on the opener, and the popup closes itself once it posts the result. Falls back to rendering JSON on the page if there's no opener (e.g. testing by clicking the link directly). targetOrigin is your app's FRONTEND_URL, not '*' — make sure that env var matches your real deployed origin before going to production, or the message won't be delivered.
Migrated 2026-07-11: this app now lives entirely on DigitalOcean + Supabase — Railway is fully decommissioned, do not use the old web-production-13038.up.railway.app URL anywhere. Session-token auth also shipped the same day: creator_id is no longer accepted from the client on any protected endpoint — it's derived server-side from the Authorization: Bearer <token> header instead. Get a token by completing the login flow below.
Method key GETread POSTcreate / action PUTupdate DELETEremove METAcalled by Meta, not your app CHANGEDresponse shape changed recently
01

Login & OAuth

Browser redirects — not fetch/XHR calls
MethodEndpointPurposeCallerRequest / ResponseNotes
GET /oauth/login Start creator login — Instagram Login scope set, via Facebook's OAuth dialog despite the name. Prefer /instagram-demo/auth?flow=instagram below for genuine native Instagram Login. Frontend (popup or redirect)

Request

No params

Response

HTTP 302 → Meta consent dialog
(no JSON body)
Open via window.open() for the popup flow
GET /oauth/fb-login Start creator login — Facebook Login scope set. Confirmed working end-to-end. Frontend (popup or redirect)

Request

No params

Response

HTTP 302 → Meta consent dialog
(no JSON body)
Both flows converge to the same creator record
GET /instagram-demo/auth?flow=instagram Start creator login via genuine native Instagram Login — instagram.com's own OAuth page, no linked Facebook Page required. Dedicated Instagram app, not the main Meta app. Frontend (popup or redirect)

Request

Query param flow=instagram

Response

HTTP 302 → instagram.com consent dialog
(no JSON body)
flow is carried as the OAuth state param internally
META CHANGED /oauth/callback Meta's redirect target after consent. Exchanges the code, saves the creator + profile, subscribes for webhooks, issues a session token. Meta only

Query params

code    (required, from Meta)
ref     (optional referral code)

Response

HTML page for a popup: if window.opener
exists, posts { success, flow, session_token,
profile } (or { success:false, error }) via
postMessage(payload, FRONTEND_URL) and calls
window.close(). No opener → renders the same
JSON on the page instead (direct-link testing).
Was a plain JSON response before 2026-07-13. Must match OAUTH_REDIRECT_URI + Meta's allowlist
META CHANGED /oauth/fb-callback Meta's redirect target for the Facebook Login flow. Same behavior as /oauth/callback. Meta only

Query params

code    (required)
ref     (optional)

Response

Same popup/postMessage handoff as /oauth/callback
Was a plain JSON response before 2026-07-13. Must match FB_OAUTH_REDIRECT_URI + Meta's allowlist
META /instagram-demo/auth/callback Redirect target for both /instagram-demo/auth flows. For the native Instagram flow: exchanges the code at api.instagram.com (a genuinely different token model than everything else here), fetches profile from graph.instagram.com/me, subscribes webhooks on the IG user directly (no Facebook Page in this flow), saves the creator, issues a session token. Meta only

Query params

code    (required, from Meta)
state   (instagram or facebook - which flow this is)

Response

Same popup/postMessage handoff as /oauth/callback
facebook_page_id is null in profile for the native Instagram flow
02

Creator Profile

Avatar, follower count, bio — for the dashboard
MethodEndpointPurposeCallerRequest / ResponseNotes
GET CHANGED /api/creator/profile Read the authenticated creator's persisted profile snapshot for dashboard rendering. Frontend

Request

Header: Authorization: Bearer <token>
No query params - creator comes from the token

Response 200

{
  "instagram_user_id": "17841476371030327",
  "instagram_username": "buildwithbeyond",
  "display_name": "Beyond",
  "profile_picture_url": "https://...",
  "followers_count": 3,
  "follows_count": 6,
  "media_count": 3,
  "biography": "Building tomorrow's influence.",
  "website": "http://gobeyond.now",
  "is_active": true,
  "automations_paused": false,
  "profile_synced_at": "2026-07-10T11:17:57Z"
}

Response 401 / 404

{ "detail": "Missing or malformed Authorization header" }
{ "detail": "Creator with ID {id} not found" }
Snapshot only, not live — see profile_synced_at
POST CHANGED /oauth/resync-profile Manually refresh the profile snapshot from Graph API, without a full re-login. Frontend ("Refresh" button)

Request

Header: Authorization: Bearer <token>
No body, no path param (was {instagram_user_id})

Response 200

{
  "success": true,
  "profile": {
    "instagram_username": "buildwithbeyond",
    "display_name": "Beyond",
    "profile_picture_url": "https://...",
    "followers_count": 3,
    "follows_count": 6,
    "media_count": 3,
    "biography": "...",
    "website": "http://gobeyond.now"
  }
}

Response 401 / 502

{ "detail": "Missing or malformed Authorization header" }
{ "detail": "Could not fetch profile from Graph API" }
Always acts on the token's own creator now
03

Automations

comment_to_dm · story_to_dm · message_to_dm
MethodEndpointPurposeCallerRequest / ResponseNotes
GET CHANGED /api/automations List all automations for the authenticated creator, plus the global pause state. Frontend

Request

Header: Authorization: Bearer <token>
No query params (was ?creator_id=...)

Response 200

{
  "automations_paused": false,
  "automations": [
    {
      "id": "10bf6d9e-...",
      "creator_id": "17841476371030327",
      "automation_type": "comment_to_dm",
      "keyword": "link",
      "reply_message": "Here's the link: {link}",
      "link": "https://gobeyond.now",
      "is_active": true,
      "created_at": "2026-07-10T09:05:05Z",
      "updated_at": "2026-07-10T09:05:05Z"
    }
  ]
}
POST CHANGED /api/automations Create a new keyword-triggered automation for the authenticated creator. Frontend

Request

Header: Authorization: Bearer <token>
{
  "automation_type": "comment_to_dm",
  "keyword": "link",
  "reply_message": "Here's the link: {link}",
  "link": "https://gobeyond.now"
}
(creator_id field REMOVED - do not send it)

Response 201 / 404 / 400

201: full automation object (see above)
404: { "detail": "Creator with ID {id} not found" }
400: { "detail": "Automation with keyword '...' already exists" }
keyword auto-lowercased · link may be null
GET /api/automations/{automation_id} Fetch a single automation by ID — only if it belongs to the authenticated creator. Frontend

Request

Header: Authorization: Bearer <token>

Response

200: automation object
404: { "detail": "Automation not found" }
(also 404 if it belongs to a different creator)
PUT /api/automations/{automation_id} Update an automation's message, link, or active status — only if it belongs to the authenticated creator. Frontend

Request (all optional)

Header: Authorization: Bearer <token>
{
  "reply_message": "Updated: {link}",
  "link": "https://newlink.com",
  "is_active": false
}

Response

200: updated automation object
400: { "detail": "No fields to update" }
404: { "detail": "Automation not found" }
keyword & automation_type are immutable
DELETE /api/automations/{automation_id} Permanently delete an automation — only if it belongs to the authenticated creator. Frontend

Request

Header: Authorization: Bearer <token>

Response

200: { "success": true, "message": "Automation deleted successfully" }
404: { "detail": "Automation not found" }
Confirm before calling — irreversible
POST CHANGED /api/automations/pause-all Pause all automations for the authenticated creator — one global kill switch. Frontend

Request

Header: Authorization: Bearer <token>
No body (creator_id field REMOVED)

Response

200: { "success": true, "automations_paused": true,
       "message": "All automations paused" }
Individual is_active state is preserved underneath
POST CHANGED /api/automations/resume-all Resume all automations — undoes pause-all. Frontend

Request

Header: Authorization: Bearer <token>
No body (creator_id field REMOVED)

Response

200: { "success": true, "automations_paused": false,
       "message": "All automations resumed" }
04

Webhooks

Called by Meta only — informational, never call these from the app
MethodEndpointPurposeCallerRequest / ResponseNotes
META /webhooks/instagram One-time webhook URL verification handshake, run once when registering the URL. Meta only

Query params from Meta

hub.mode, hub.verify_token, hub.challenge

Response

200: plaintext echo of hub.challenge
403: verify_token mismatch
GET
META /webhooks/instagram Meta delivers real-time comment / DM / story-reply events here, which trigger automations. Meta only, signed

Request

Meta's Instagram webhook payload
Header: X-Hub-Signature-256 (required)

Response

200: { "status": "ok" }
403: { "detail": "Invalid or missing signature" }
POST — unsigned requests are rejected
05

System

MethodEndpointPurposeCallerRequest / ResponseNotes
GET /health Uptime / health check. Monitoring / DevOps

Response

{ "status": "ok", "version": "2" }