API Reference — Rev. 2026-07-13
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.
/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.
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 | Endpoint | Purpose | Caller | Request / Response | Notes |
|---|---|---|---|---|---|
| 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 |
| 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 |
| 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 |
| /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 |
| Method | Endpoint | Purpose | Caller | Request / Response | Notes |
|---|---|---|---|---|---|
| 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 |
| Method | Endpoint | Purpose | Caller | Request / Response | Notes |
|---|---|---|---|---|---|
| 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" } |
| Method | Endpoint | Purpose | Caller | Request / Response | Notes |
|---|---|---|---|---|---|
| /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 | |
| /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 |
| Method | Endpoint | Purpose | Caller | Request / Response | Notes |
|---|---|---|---|---|---|
| GET | /health | Uptime / health check. | Monitoring / DevOps |
Response { "status": "ok", "version": "2" } |