Connect FlutterFlow to Agorapulse by routing all API calls through a Firebase Cloud Function or Supabase Edge Function that exchanges your OAuth client credentials for a Bearer token at Agorapulse's token endpoint. Confirm your Agorapulse plan supports API access before building — it is primarily available on Enterprise-tier accounts.
| Fact | Value |
|---|---|
| Tool | Agorapulse |
| Category | Social |
| Method | FlutterFlow API Call |
| Difficulty | Intermediate |
| Time required | 45 minutes |
| Last updated | July 2026 |
Agorapulse in FlutterFlow: Unified Social Inbox on Mobile
Agorapulse consolidates a brand's social channels — Twitter/X, Facebook, Instagram, LinkedIn, YouTube, TikTok — into a single inbox and publishing calendar. The FlutterFlow use-case is a mobile companion where community managers read and respond to incoming messages, approve scheduled posts, and check recent analytics without opening a browser. The API lives at `https://app.agorapulse.com/api` and uses OAuth 2.0 client-credentials flow: your app exchanges a client ID and client secret for a Bearer token that you include in every subsequent request.
The most important thing to sort out before writing code is plan access. Agorapulse's API is not available on Free or standard Pro plans — it is effectively an Enterprise-tier feature, and you must confirm with your Agorapulse account manager that the account has API access enabled. Attempting to call the API with a Free/Pro account returns 401 or 403 regardless of how correctly the OAuth flow is implemented. Save yourself hours of debugging by verifying plan access first.
The client secret must never appear in a FlutterFlow API Call header or Custom Action Dart code. FlutterFlow compiles to a Flutter app running on the user's phone; anything embedded in the binary can be extracted. A leaked Agorapulse client secret gives access to the entire brand's social presence — every connected channel's inbox, scheduling queue, and analytics. Deploy a Firebase Cloud Function or Supabase Edge Function to handle the token exchange and all API calls. Responses are rate-limited by plan tier (verify current limits with Agorapulse support), so cache inbox and analytics responses in the proxy for a few minutes rather than fetching on every screen navigation.
Integration method
FlutterFlow connects to Agorapulse via API Calls that hit a Firebase Cloud Function or Supabase Edge Function proxy. The proxy exchanges OAuth client credentials for a Bearer token at `app.agorapulse.com/api/oauth/token` and then calls inbox, publishing, and analytics endpoints on the Agorapulse API. The client secret and the Bearer token are held server-side — they never ship in the Flutter app bundle. FlutterFlow API Calls hit the proxy, which caches and forwards responses.
Prerequisites
- An Agorapulse account on a plan tier that includes API access (verify with your account manager — typically Enterprise)
- OAuth client credentials (client ID and client secret) from Agorapulse
- A Firebase project (Blaze plan) or Supabase project for the OAuth proxy
- A FlutterFlow project with API Calls configured
Step-by-step guide
Verify plan access and obtain OAuth client credentials
Before writing any code, confirm that your Agorapulse account tier includes API access. Log into Agorapulse and look for a developer or API section in account settings. If you do not see one, contact your Agorapulse account manager directly and ask whether your plan includes API access. Lower-tier plans (Free, Pro) typically do not have API access — you will receive 401 or 403 errors on correctly implemented code simply because the account is not authorized for API calls. Confirming this upfront saves significant debugging time. Once API access is confirmed, ask Agorapulse for your OAuth client credentials — a client ID and a client secret. These credentials identify your application to Agorapulse's OAuth server. The client ID is semi-public (it identifies the app but does not grant access on its own), but the client secret is sensitive and must be stored exclusively on the server side. Store the client secret in Firebase Functions environment config (using `firebase functions:secrets:set AGORAPULSE_CLIENT_SECRET`) or Supabase Edge Function secrets (`supabase secrets set AGORAPULSE_CLIENT_SECRET=...`). Do not place it in FlutterFlow App Values, Custom Actions, or API Call headers. Verify the base URL and token endpoint by checking the current Agorapulse API documentation — use `https://app.agorapulse.com/api` as the base and `https://app.agorapulse.com/api/oauth/token` for token exchange.
Pro tip: Ask your Agorapulse account manager for sandbox or test credentials if available — this lets you develop and test against non-production data without affecting real social channels.
Expected result: You have confirmed API access is enabled on the account. You have a client ID and client secret stored securely in Firebase Functions config or Supabase secrets.
Deploy a Firebase/Supabase proxy with OAuth token exchange
Deploy a server-side function that handles the OAuth token exchange and serves as the intermediary for all Agorapulse API calls. The function reads the client ID and secret from environment variables, exchanges them for a Bearer token, caches the token (Bearer tokens typically expire — check the Agorapulse documentation for the expiry time and refresh logic), and forwards data requests to the Agorapulse API. For a Firebase Cloud Function, create a function named `agorapulseProxy`. On cold start (or when the cached token is close to expiry), the function POSTs to `https://app.agorapulse.com/api/oauth/token` with `grant_type=client_credentials`, the client ID, and the client secret. The response includes an `access_token` which the proxy caches in memory (or in Firestore for multi-instance deployments). All subsequent requests to Agorapulse include `Authorization: Bearer {access_token}`. For each downstream route the FlutterFlow app needs — inbox items, publishing queue, analytics — the proxy adds the Authorization header and forwards the request to `app.agorapulse.com/api`. It returns the response JSON (or a shaped subset) to FlutterFlow. Adding a 3-to-5-minute response cache in the proxy (using an in-memory Map or a Firestore TTL document) prevents the app from hitting plan rate limits when users navigate between screens.
1// Firebase Cloud Function — agorapulseProxy (index.js)2const functions = require('firebase-functions');3const fetch = require('node-fetch');45const CLIENT_ID = process.env.AGORAPULSE_CLIENT_ID;6const CLIENT_SECRET = process.env.AGORAPULSE_CLIENT_SECRET;7const BASE = 'https://app.agorapulse.com/api';89let cachedToken = null;10let tokenExpiry = 0;1112async function getToken() {13 if (cachedToken && Date.now() < tokenExpiry) return cachedToken;14 const r = await fetch(`${BASE}/oauth/token`, {15 method: 'POST',16 headers: { 'Content-Type': 'application/json' },17 body: JSON.stringify({18 grant_type: 'client_credentials',19 client_id: CLIENT_ID,20 client_secret: CLIENT_SECRET21 })22 });23 const data = await r.json();24 cachedToken = data.access_token;25 // Refresh 60s before expiry (default assume 3600s if not specified)26 tokenExpiry = Date.now() + ((data.expires_in || 3600) - 60) * 1000;27 return cachedToken;28}2930exports.agorapulseProxy = functions.https.onRequest(async (req, res) => {31 res.set('Access-Control-Allow-Origin', '*');32 if (req.method === 'OPTIONS') { res.status(204).send(''); return; }3334 try {35 const token = await getToken();36 const path = req.query.path || '/inbox_items';37 const qs = new URLSearchParams(req.query);38 qs.delete('path');3940 const url = `${BASE}${path}${qs.toString() ? '?' + qs.toString() : ''}`;41 const r = await fetch(url, {42 method: req.method,43 headers: {44 'Authorization': `Bearer ${token}`,45 'Content-Type': 'application/json'46 },47 body: req.method !== 'GET' ? JSON.stringify(req.body) : undefined48 });49 const data = await r.json();50 res.status(r.status).json(data);51 } catch (e) {52 res.status(500).json({ error: e.message });53 }54});Pro tip: Cache the Bearer token in memory between function invocations (Cloud Functions can reuse warm instances). For multi-instance reliability, store the token in Firestore with a TTL — all proxy instances share the same fresh token.
Expected result: The proxy function is deployed and returns an Agorapulse API response when called with `?path=/inbox_items`. The Firebase Function logs show a successful token exchange on the first call and reuse of the cached token on subsequent calls.
Create a FlutterFlow API Group pointing to the proxy
In FlutterFlow, open the left navigation panel and click 'API Calls'. Click '+ Add' → 'Create API Group'. Name it 'Agorapulse Proxy' and set the base URL to your Firebase Cloud Function URL (e.g. `https://us-central1-yourproject.cloudfunctions.net/agorapulseProxy`). Do not add Authorization headers here — authentication is handled entirely by the proxy. Add the first API Call: click '+ Add API Call' inside the group. Name it 'Get Inbox Items'. Set the method to GET and the endpoint to `/?path=/inbox_items`. Click the Variables tab and add an optional variable `limit` (Integer, default 20) and `status` (String, default 'pending'). Update the endpoint to `/?path=/inbox_items&limit={{limit}}&status={{status}}`. Click 'Response & Test', press 'Test API Call', and paste a sample Agorapulse inbox response. Click 'Generate from Response' to auto-create JSON paths. Map key fields: `$[*].id`, `$[*].text` (message text), `$[*].author.name`, `$[*].profile.name` (which social channel), `$[*].created_at`, `$[*].type` (comment, mention, DM). Create a Data Type named 'InboxItem' with these fields. You will bind a ListView to a list of InboxItem objects populated by this API Call.
1{2 "api_group": "Agorapulse Proxy",3 "base_url": "https://us-central1-yourproject.cloudfunctions.net/agorapulseProxy",4 "calls": [5 {6 "name": "Get Inbox Items",7 "method": "GET",8 "endpoint": "/?path=/inbox_items&limit={{limit}}&status={{status}}",9 "variables": [10 { "name": "limit", "type": "Integer", "default": 20 },11 { "name": "status", "type": "String", "default": "pending" }12 ],13 "json_paths": {14 "ids": "$[*].id",15 "texts": "$[*].text",16 "authorNames": "$[*].author.name",17 "profileNames": "$[*].profile.name",18 "createdAt": "$[*].created_at",19 "types": "$[*].type"20 }21 },22 {23 "name": "Get Publishing Queue",24 "method": "GET",25 "endpoint": "/?path=/publishing_queue&limit={{limit}}",26 "variables": [27 { "name": "limit", "type": "Integer", "default": 20 }28 ]29 },30 {31 "name": "Get Analytics",32 "method": "GET",33 "endpoint": "/?path=/analytics&period={{period}}",34 "variables": [35 { "name": "period", "type": "String", "default": "last_7_days" }36 ]37 }38 ]39}Pro tip: Verify the exact Agorapulse API endpoint paths (inbox_items, publishing_queue, analytics) in the current Agorapulse API documentation — endpoint paths can change between API versions.
Expected result: Testing 'Get Inbox Items' in FlutterFlow returns real inbox data through the proxy. JSON paths are generated for message text, author name, and channel name.
Build the inbox screen and bind data
Create an 'Inbox' screen in FlutterFlow. Set 'Get Inbox Items' as the Backend Query for the page so inbox data loads automatically when the screen opens. In the Backend Query settings, set `limit` to 20 and `status` to 'pending'. Add a ListView to the screen. Inside the list item template, add a Column widget containing: a Row at the top with a Text widget for `authorName` (bold) and a Text widget for `profileName` (styled as a channel badge with a colored Container background — use conditional styling on the Container color based on `type` to differentiate Twitter/X, Facebook, Instagram); a Text widget for `text` set to max 2 lines with ellipsis overflow; a Row at the bottom with a small Text for `createdAt` formatted as a relative time. Add a 'Mark as Done' icon button in each list item's top-right corner. In its Action Flow, trigger a POST API Call to your proxy with `?path=/inbox_items/{{itemId}}/done`, where `itemId` is the current list item's `id`. On success, show a Snackbar and remove the item from the local Page State list. Enable pull-to-refresh on the ListView to reload the inbox. Store the fetched items in Page State to avoid redundant API calls when the user swipes between screens. For the publishing queue: create a separate 'Queue' screen with an identical structure but bound to 'Get Publishing Queue'.
Pro tip: Use a tab bar at the bottom of the screen with 'Inbox', 'Queue', and 'Analytics' tabs — each tab uses its own Backend Query and caches its response in Page State. Navigate between tabs without refetching if the data is less than 3 minutes old.
Expected result: The Inbox screen shows pending messages with author, channel, and message text. Pull-to-refresh reloads the list. Tapping 'Mark as Done' sends the action to the proxy and removes the item from the visible list.
Cache responses and handle rate limits
Agorapulse rate limits are plan-dependent — Enterprise plans get higher limits, lower plans have stricter caps (verify exact numbers with Agorapulse support or in current API documentation). Without caching, a mobile app that navigates between Inbox, Queue, and Analytics tabs can trigger multiple API calls per minute per screen, quickly hitting limits and returning 429 errors. Implement two layers of caching. In the proxy (Firebase Cloud Function), store each endpoint's response in a Firestore document (or in-memory if the function stays warm) with a TTL of 3–5 minutes. If the proxy receives a request for a path it fetched less than 3 minutes ago, it returns the cached Firestore data instead of calling Agorapulse. Update the cache on pull-to-refresh (FlutterFlow can pass a `forceRefresh=true` query parameter that the proxy uses to bypass the cache). In FlutterFlow, store page-level cached data in Page State. On tab switch, check whether the data in Page State is populated — if yes, use it immediately without triggering a new Backend Query call. Trigger a fresh Backend Query only on pull-to-refresh or when Page State is empty. If you hit a 429, the proxy should return the Agorapulse error code and a `Retry-After` header value if present. In FlutterFlow, add a conditional in the API Call action handler: if the response code is 429, show a Snackbar 'Too many requests — please wait a moment' and disable the refresh button for 30 seconds using a timer. If the plan-gate or rate-limit complexity is slowing you down, RapidDev's team builds FlutterFlow integrations like this every week — free scoping call at rapidevelopers.com/contact.
Pro tip: Add a `Last updated: X minutes ago` text below each list view to show users when the data was last fetched. This sets expectations that the inbox may not reflect changes made in the web dashboard in the last few minutes.
Expected result: Navigation between Inbox, Queue, and Analytics tabs does not trigger new API calls if cached data is less than 3 minutes old. Pull-to-refresh forces a fresh fetch. 429 errors display a user-friendly message instead of a broken screen.
Common use cases
Mobile social inbox for community managers
A FlutterFlow app that pulls unread inbox items from Agorapulse — comments, direct messages, and mentions across all connected social channels — into a unified mobile inbox. Community managers can read messages, mark them as done, and assign them to team members without opening the Agorapulse web dashboard.
Show my Agorapulse inbox with unread messages from all connected social channels. Each item should show the channel name, the message text, the sender name, and the received time. Include a 'Mark as done' button.
Copy this prompt to try it in FlutterFlow
Content calendar approval companion
A FlutterFlow app that shows scheduled posts pending approval across all connected Agorapulse channels. Editors review the post content, channel, and scheduled time on mobile and approve or reschedule directly from the app. The publishing endpoint updates the scheduled post status in Agorapulse.
Show my Agorapulse publishing queue with posts pending approval. Display the post content, scheduled time, and which social channel it's for. Include Approve and Reschedule buttons.
Copy this prompt to try it in FlutterFlow
Social analytics dashboard
A FlutterFlow analytics screen that fetches key social metrics from Agorapulse — reach, engagement rate, inbox volume — for the last 7 days across all connected profiles. The metrics are displayed in a card layout with trend indicators. Data is cached for 5 minutes to stay within rate limits.
Display my Agorapulse analytics for the last 7 days: total reach, total engagement, and inbox message count. Show a card per connected social channel with its individual stats.
Copy this prompt to try it in FlutterFlow
Troubleshooting
HTTP 401 or 403 on all API calls despite correct client credentials
Cause: The Agorapulse account plan does not include API access, or API access has not been enabled for the account. This is the most common issue — the plan gate returns 401/403 regardless of credential correctness.
Solution: Contact your Agorapulse account manager to confirm whether the plan includes API access. Ask them to enable API access if needed. Verify by testing the token endpoint directly: a successful token exchange should return an `access_token` field. If the token endpoint returns 403, the account does not have API access enabled.
HTTP 429 Too Many Requests — rate limit exceeded
Cause: The FlutterFlow app or proxy is requesting Agorapulse data more frequently than the plan tier allows. Common cause: no caching in the proxy, causing a fresh Agorapulse API call on every FlutterFlow screen navigation.
Solution: Add a 3–5 minute response cache in the Firebase/Supabase proxy. Store the latest response in Firestore or in-memory with a timestamp; return cached data unless `forceRefresh=true` is passed or the TTL has expired. In FlutterFlow, avoid triggering Backend Queries on every tab switch — use Page State caching instead.
Bearer token works initially but API calls start returning 401 after some time
Cause: The OAuth Bearer token has expired and the proxy is not refreshing it. Agorapulse tokens have a finite lifetime; using an expired token returns 401.
Solution: Update the proxy to check whether the cached token is within 60 seconds of expiry before each API call, and request a new token if so. Store the `expires_in` value from the token response and compute `tokenExpiry = Date.now() + (expires_in - 60) * 1000`. Verify the actual expiry time with the Agorapulse API documentation.
XMLHttpRequest error / CORS error when testing FlutterFlow web preview
Cause: The Firebase Cloud Function is not returning the required CORS headers for browser-origin requests. FlutterFlow's web preview runs in a browser and enforces CORS restrictions.
Solution: Ensure the proxy sets `res.set('Access-Control-Allow-Origin', '*')` before the first `res.send()` or `res.json()` call, and handles `OPTIONS` preflight requests with a 204 status. All responses including error responses must include the CORS header.
Best practices
- Verify API plan access with your Agorapulse account manager before writing any code — this is the most common reason for unexplained 401/403 errors.
- Store the OAuth client secret exclusively in Firebase Functions environment config or Supabase secrets — never in FlutterFlow API Calls, App Values, or Dart code.
- Cache proxy responses for 3–5 minutes in Firestore or in-memory to avoid hitting plan rate limits when users navigate between Inbox, Queue, and Analytics screens.
- Pass a `forceRefresh=true` parameter on pull-to-refresh so the proxy bypasses its cache and fetches fresh data only when the user explicitly requests it.
- Use a tab bar layout with Page State caching per tab — avoid triggering a new Backend Query on every tab switch if the data is still fresh.
- Display a 'Last updated X minutes ago' timestamp below each list to set user expectations about data freshness relative to the Agorapulse web dashboard.
- Handle 429 errors gracefully with a Snackbar and a temporary disable of the refresh button — do not retry immediately, as repeated requests will extend the rate-limit backoff period.
- Shape the Agorapulse API response in the proxy (filter to relevant fields, flatten nested objects) before returning to FlutterFlow to minimize JSON path complexity and payload size.
Alternatives
Later focuses on Instagram-first visual scheduling with a simpler access-token auth model; choose it over Agorapulse if you need media-grid planning rather than a unified social inbox.
Buffer is a multi-network scheduling queue available on lower-cost plans; choose it over Agorapulse if you need posting and analytics without the full inbox management features.
Mastodon is a free, decentralized open social network — choose it over Agorapulse if you want to connect directly to a specific Mastodon instance rather than managing mainstream social channels.
Frequently asked questions
Is Agorapulse API access available on the Free or Pro plan?
API access is primarily an Enterprise-tier feature. Free and standard Pro plans typically do not include API access, and attempting to use the API with these plans results in 401 or 403 errors even with valid credentials. Contact your Agorapulse account manager before building to confirm whether your plan supports API access.
Can I put the Agorapulse client secret in a FlutterFlow API Call header?
No. FlutterFlow compiles to a Flutter app running on the user's device, and any value in an API Call header is embedded in the compiled binary. The Agorapulse client secret must live exclusively in a Firebase Cloud Function or Supabase Edge Function — never in any FlutterFlow setting. A leaked client secret exposes the brand's entire connected social presence across all channels.
How often do Agorapulse OAuth tokens expire?
Bearer token expiry varies by Agorapulse configuration — check the `expires_in` field in the token exchange response and refresh the token proactively before it expires (subtract 60 seconds from the expiry time as a buffer). The proxy should handle token refresh automatically so the FlutterFlow app never encounters an expired-token error.
Does this integration support posting content from FlutterFlow to social channels?
Yes. Agorapulse's API includes publishing endpoints for creating and scheduling posts. Your proxy can expose a POST route that accepts post content and a profile ID, then calls the Agorapulse publishing API with the Bearer token. In FlutterFlow, build a compose screen with a TextArea, channel picker, and scheduled time picker, and trigger the proxy POST from the action flow.
What Agorapulse data can I show in a FlutterFlow app?
Through the Agorapulse API you can access inbox items (comments, mentions, DMs across all connected channels), the publishing queue (scheduled and draft posts), and analytics (reach, engagement, follower growth by profile). The exact available endpoints and response shapes depend on your plan tier and the current API version — check the Agorapulse API documentation for the full endpoint list.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation