Skip to main content
RapidDev - Software Development Agency
flutterflow-integrationsFlutterFlow API Call

Planoly

Connect FlutterFlow to Planoly by routing all API requests through a Firebase or Supabase proxy that holds your API token. Planoly's API is not self-serve — you must request access via planoly.com/developer. Once approved, build a 3-column GridView of scheduled-post thumbnails in FlutterFlow to mimic the Instagram grid preview your audience is familiar with.

What you'll learn

  • Why Planoly API access must be requested — not self-served — and how to initiate that process
  • How to deploy a Firebase Cloud Function or Supabase Edge Function as a secure proxy for your Planoly token
  • How to create a FlutterFlow API Call that targets your proxy and retrieves scheduled posts and media
  • How to build a 3-column GridView in FlutterFlow to replicate the Instagram grid preview layout
  • How to cache the scheduled-media list to avoid rate limits on frequent grid refreshes
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate17 min read45 minutesSocialLast updated July 2026RapidDev Engineering Team
TL;DR

Connect FlutterFlow to Planoly by routing all API requests through a Firebase or Supabase proxy that holds your API token. Planoly's API is not self-serve — you must request access via planoly.com/developer. Once approved, build a 3-column GridView of scheduled-post thumbnails in FlutterFlow to mimic the Instagram grid preview your audience is familiar with.

Quick facts about this guide
FactValue
ToolPlanoly
CategorySocial
MethodFlutterFlow API Call
DifficultyIntermediate
Time required45 minutes
Last updatedJuly 2026

Build a Mobile Instagram Grid Planner with Planoly and FlutterFlow

Planoly is built around one core visual metaphor: the Instagram grid preview. Instead of guessing how a new post will look next to existing content, Planoly shows you the 3-by-3 grid layout before anything goes live, letting you drag-and-arrange until the aesthetic is right. It also covers Pinterest and Stories scheduling. For FlutterFlow builders, the natural use-case is a mobile companion that mirrors this grid experience — showing the creator's upcoming scheduled posts as thumbnails in the same 3-column layout, so they can review and approve content from their phone.

Planoly's API is not openly self-serve in the way that most REST APIs are. Rather than generating a token from a dashboard toggle, you request developer access through planoly.com/developer or by contacting support. Access may be gated to Pro or Business plan holders, so confirming your tier first saves you from building an integration that cannot activate. Once approved, auth is a straightforward API token sent as a Bearer or header credential against Planoly's API. The exact base URL should be confirmed from Planoly's developer documentation at the time of your request, as it is not publicly fixed and is marked for verification.

Because FlutterFlow compiles to a Flutter client app running on the user's device, any token placed in an API Call header ships inside the app bundle and can be extracted with standard reverse-engineering tools. A token that grants access to a creator's content calendar and scheduled posts must never travel this path. The secure pattern is a Firebase Cloud Function or Supabase Edge Function that holds the token server-side, with your FlutterFlow app calling the proxy. This is a one-time setup that unlocks the full Planoly connection without ever exposing credentials to the client.

Integration method

FlutterFlow API Call

FlutterFlow sends API requests to a Firebase Cloud Function or Supabase Edge Function that holds your Planoly API token as a Bearer/header. The proxy forwards each request to the Planoly API and returns the response. This keeps the token out of the compiled app bundle, where it could be extracted by anyone who downloads the app.

Prerequisites

  • A Planoly account on a Pro or Business plan (API access may be plan-gated — verify with Planoly support)
  • Developer API access approved by Planoly (request at planoly.com/developer or via support)
  • A Firebase project with Cloud Functions enabled, or a Supabase project with Edge Functions enabled
  • A FlutterFlow project on a paid plan (API Calls and Custom Code require paid plans)
  • Basic familiarity with FlutterFlow's left-nav panels: API Calls and Custom Code

Step-by-step guide

1

Request Planoly API access and confirm your base URL

Planoly's API is not a self-serve dashboard toggle. Before writing a single line of proxy code or configuring a FlutterFlow API Call, you need explicit approval from Planoly. Go to planoly.com/developer or contact Planoly support directly and request developer API access. Be ready to describe what you intend to build (a mobile FlutterFlow companion app), what endpoints you need (scheduled posts, media library), and which Planoly plan your account is on. This step can take anywhere from a day to a week depending on Planoly's current developer programme availability. Do not skip it — building the proxy and FlutterFlow screens before access is approved means you will be testing against an API that returns 401 or 403 errors no matter how correct your code is. Once approved, Planoly will provide you with an API token and the current base URL. The base URL is not publicly documented in a fixed location and may change, so always confirm the exact host from the documentation or communication you receive at approval time. Note both values down — you will need them for the proxy in the next step.

Pro tip: If you are not on a Pro or Business plan, ask Planoly support explicitly whether your plan tier qualifies for API access before investing build time.

Expected result: You have an active Planoly API token and a confirmed base URL from Planoly's developer programme.

2

Deploy a Firebase Cloud Function (or Supabase Edge Function) as the Planoly proxy

Because FlutterFlow compiles your app to run on the user's device, any credential placed in an API Call header is embedded in the compiled app bundle. Anyone who downloads your app can extract it with standard tools and use it to read or modify your entire Planoly content plan. The solution is a server-side proxy: a Firebase Cloud Function (Node.js) or Supabase Edge Function (Deno) that holds the token in an environment variable and forwards requests to Planoly on behalf of the app. For Firebase: open the Firebase console, navigate to Functions, and deploy a new HTTPS function. Store the Planoly API token in Firebase environment config or Secret Manager (not in the function source code). The function receives requests from your FlutterFlow app, validates the caller (e.g. checks a Firebase Auth token), adds the Planoly Bearer token to the Authorization header, and forwards the request to the Planoly base URL you confirmed in step 1. For Supabase: open the Supabase dashboard, go to Edge Functions, create a new function, and add the Planoly token as a Supabase secret. The Edge Function receives the FlutterFlow request, adds the token, and proxies to Planoly. The example below shows a Firebase Cloud Function pattern. Replace `YOUR_PLANOLY_BASE_URL` with the exact host confirmed at approval time, and store `PLANOLY_API_TOKEN` as an environment variable or secret — never hardcode it in the source.

index.js
1// Firebase Cloud Function: Planoly proxy
2// index.js (Node.js 18+)
3const functions = require('firebase-functions');
4const { https } = require('firebase-functions/v2');
5const fetch = require('node-fetch');
6
7const PLANOLY_BASE_URL = process.env.PLANOLY_BASE_URL || 'https://YOUR_PLANOLY_BASE_URL';
8const PLANOLY_TOKEN = process.env.PLANOLY_API_TOKEN;
9
10exports.planolyProxy = https.onRequest(async (req, res) => {
11 // Set CORS for web builds if needed
12 res.set('Access-Control-Allow-Origin', '*');
13 if (req.method === 'OPTIONS') {
14 res.set('Access-Control-Allow-Methods', 'GET, POST');
15 res.set('Access-Control-Allow-Headers', 'Content-Type, Authorization');
16 res.status(204).send('');
17 return;
18 }
19
20 const path = req.query.path || '/scheduled_posts';
21 const planolyUrl = `${PLANOLY_BASE_URL}${path}`;
22
23 try {
24 const response = await fetch(planolyUrl, {
25 method: req.method,
26 headers: {
27 'Authorization': `Bearer ${PLANOLY_TOKEN}`,
28 'Content-Type': 'application/json'
29 },
30 body: req.method !== 'GET' ? JSON.stringify(req.body) : undefined
31 });
32
33 const data = await response.json();
34 res.status(response.status).json(data);
35 } catch (err) {
36 res.status(500).json({ error: 'Proxy error', details: err.message });
37 }
38});

Pro tip: If you are using RapidDev to build this integration, they handle the proxy deployment and FlutterFlow wiring as part of their standard FlutterFlow integration service — see rapidevelopers.com/contact for a free scoping call.

Expected result: Your proxy function is deployed and returns Planoly data when called with a `path` query parameter. Test it directly in the browser or with a tool like Postman before connecting FlutterFlow.

3

Create a FlutterFlow API Group pointing to your proxy

Now that your proxy is running, you configure FlutterFlow to call it — not the Planoly API directly. In FlutterFlow, click API Calls in the left navigation panel. Click the blue + Add button and choose Create API Group. Name the group something descriptive like `PlanolyProxy`. Set the Base URL to your deployed proxy URL — for example, `https://us-central1-your-project.cloudfunctions.net/planolyProxy` (Firebase) or `https://your-project.supabase.co/functions/v1/planoly-proxy` (Supabase). You do not need to add any authentication headers in the FlutterFlow API Group — those are handled in the proxy. You may optionally add a query parameter variable named `path` so individual API Calls in the group can specify different Planoly endpoints (e.g. `/scheduled_posts`, `/media`). Click Save to save the API Group. With the group saved, click + Add again inside the group and choose Add API Call. Name it `GetScheduledPosts`. Set the Method to GET. In the Variables tab, add a variable named `path` with the default value `/scheduled_posts` (or the specific endpoint path provided by Planoly). In the URL field, confirm that the variable is referenced as `?path={{ path }}`. Click the Response & Test tab, paste a sample JSON response from Planoly (you can get one from a direct proxy call), and click Generate JSON Paths. FlutterFlow will automatically generate JSON path extractors for each field in the response — for example `$.posts[0].thumbnail_url`, `$.posts[0].scheduled_time`, `$.posts[0].caption`. Name these paths clearly so you can bind them to widgets later.

typescript
1// Example API Call config (reference for understanding the setup)
2{
3 "api_group": "PlanolyProxy",
4 "base_url": "https://us-central1-YOUR-PROJECT.cloudfunctions.net/planolyProxy",
5 "call_name": "GetScheduledPosts",
6 "method": "GET",
7 "query_params": {
8 "path": "/scheduled_posts"
9 },
10 "json_paths": {
11 "postsList": "$.posts",
12 "firstThumbnail": "$.posts[0].thumbnail_url",
13 "firstCaption": "$.posts[0].caption",
14 "firstScheduledTime": "$.posts[0].scheduled_time"
15 }
16}

Pro tip: Use the Response & Test tab in FlutterFlow to paste a real Planoly response and auto-generate JSON paths. This saves significant manual field-mapping work.

Expected result: The API Group `PlanolyProxy` exists with at least one API Call (`GetScheduledPosts`). The Response & Test tab shows a successful response and generated JSON paths for the scheduled-post fields.

4

Create a Data Type for scheduled posts and parse responses

Before binding Planoly data to widgets, create a FlutterFlow Data Type to represent a scheduled post cleanly. Go to the Data Types section in the left nav (the database icon), click + Add Data Type, and name it `PlanolyPost`. Add fields that match the JSON paths you generated: `thumbnailUrl` (String), `caption` (String), `scheduledTime` (String or DateTime), `platform` (String for Instagram/Pinterest), and any other relevant fields like `postId` (String) or `mediaType` (String for image/video/story). Back in the API Call settings, map the JSON paths to a list of `PlanolyPost` objects. In FlutterFlow's Response tab, set the Response Type to `List of PlanolyPost` and map each path to the corresponding field. This means your widget tree can bind to a typed list of posts rather than raw JSON, which makes the GridView binding in the next step much cleaner. For the scheduled time field, if Planoly returns a Unix timestamp or an ISO 8601 string, FlutterFlow's DateTime type and formatting functions can convert it to a human-readable format for display. Store it as String if the format is uncertain — you can always format it in the widget with a conditional expression. Also create a second API Call in the same group called `GetMediaLibrary` for fetching the media library, if you intend to support media browsing in addition to the schedule view. The same proxy path-variable approach works for any additional Planoly endpoint you need.

Pro tip: Keep the Data Type fields simple and flat — avoid nested objects. If Planoly's response includes nested media or platform objects, flatten them in the proxy before returning to the app.

Expected result: A `PlanolyPost` Data Type exists with fields for thumbnail URL, caption, scheduled time, and platform. The `GetScheduledPosts` API Call is mapped to return a `List of PlanolyPost`.

5

Build the 3-column Instagram grid preview GridView

The signature FlutterFlow build for Planoly is the 3-column thumbnail grid that mimics the Instagram grid preview. In FlutterFlow's canvas, open the screen where you want to show the grid. In the widget panel, add a GridView widget. In the Properties panel on the right, set the Cross Axis Count to 3 (this creates three columns). Set the Cross Axis Spacing and Main Axis Spacing to a small value like 2 to mimic the thin gaps between Instagram grid tiles. Set the Child Aspect Ratio to 1.0 so each cell is square. Inside the GridView, add an Image widget as the child. In the Image widget's source property, choose Network Image and bind it to the `thumbnailUrl` field of each `PlanolyPost` in your list. To power the GridView with data, select the GridView widget and click the Generate Dynamic Children button (or use the widget's Backend Query settings). Set it to use the `GetScheduledPosts` API Call. FlutterFlow will pass each item in the returned `List of PlanolyPost` into the child widget as a variable, so the Image source becomes `currentPost.thumbnailUrl`. For lazy loading, enable the Image widget's caching option (FlutterFlow sets this with `fit: BoxFit.cover` and standard Flutter image caching by default — images are cached once downloaded and don't re-fetch on scroll). Add an InkWell or GestureDetector around the Image widget to handle taps, opening a detail screen that shows the full caption and scheduled time. The scheduled time display can use FlutterFlow's text widget with a DateTime format function applied to `currentPost.scheduledTime`. To refresh the grid, add a Refresh button (an IconButton with a refresh icon in the AppBar) that triggers the `GetScheduledPosts` API Call action and updates the page state variable holding the posts list.

Pro tip: Set the GridView's `physics` to ClampingScrollPhysics and wrap it in an Expanded widget if the grid is inside a Column, to avoid unbounded height errors that are common with GridView in FlutterFlow.

Expected result: A screen shows a 3-column grid of square post thumbnails. Scrolling loads more. Tapping a thumbnail opens a detail view with the caption and scheduled time. A refresh button reloads the list from the proxy.

6

Cache the media list and handle rate limits

The Instagram grid preview screen is likely to be the most-viewed screen in your app — users will open it frequently to check their upcoming posts. Without caching, every screen open fires a new API Call through your proxy to Planoly, increasing the risk of hitting per-account rate limits and adding noticeable load time to each grid open. The caching strategy is simple: store the fetched post list in a FlutterFlow App State variable (a `List of PlanolyPost`) and track the last-fetched timestamp in a second App State variable (a DateTime). On screen open, check the App State timestamp. If the last fetch was more than a few minutes ago (3-5 minutes is a reasonable starting point for a content calendar that doesn't change by the second), fire the `GetScheduledPosts` API Call and update both the posts list and the timestamp. If the last fetch was recent, render the App State list directly without making a network call. In FlutterFlow, implement this with a Conditional Action in the page's On Page Load action block: first check `(currentTime - lastFetchedAt) > 3 minutes`, then branch to either a fresh API call or a no-op. For the proxy side, you can also add a short server-side cache: store the Planoly response in Firestore or Supabase with a TTL, so that if two users of the same account open the app simultaneously, both get the cached response rather than firing duplicate Planoly API calls. This is especially useful in a team scenario where multiple team members use the app to review the same content calendar. Monitor your Planoly API usage in the developer portal after launch to confirm the caching interval is keeping calls well within the allowed rate.

Pro tip: Start with a 5-minute client-side cache and adjust based on how often your team updates the schedule. For a solo creator posting a few times a week, a 15-minute cache is perfectly fine.

Expected result: The app loads the post grid instantly on subsequent opens by serving from App State. A network call to the proxy only fires when the cache interval has expired. The refresh button bypasses the cache to force a fresh fetch.

Common use cases

Instagram grid planner for solo creators

A creator uses the app to see their upcoming scheduled posts arranged in the 3-column Instagram grid layout, drag to reorder before publishing, and check that the visual flow looks right. FlutterFlow's GridView widget renders the post thumbnails in order, fetched from the Planoly scheduled-media endpoint through the proxy.

FlutterFlow Prompt

Build a screen that shows my Planoly scheduled posts in a 3-column grid of square thumbnails, ordered exactly as they will appear on my Instagram profile, with a tap-to-preview action on each one.

Copy this prompt to try it in FlutterFlow

Team content-approval workflow companion

A social media manager at a small brand uses the app to review scheduled posts that are pending approval, mark them as approved or flag them for revision, and see which posts are going live in the next 48 hours. The FlutterFlow screen shows a list of upcoming posts with scheduled times, captions, and thumbnail previews pulled from the Planoly proxy.

FlutterFlow Prompt

Create a content calendar screen that lists the next 10 scheduled posts from Planoly, showing the post thumbnail, caption, scheduled date and time, and an Approve / Flag button for each one.

Copy this prompt to try it in FlutterFlow

Pinterest and Stories scheduling dashboard

A brand's content team uses the app to see Pinterest pins and Instagram Stories queued in Planoly alongside feed posts, giving them a unified view of all scheduled content types. The FlutterFlow app fetches multi-format scheduled media and groups them by type in a tabbed layout.

FlutterFlow Prompt

Design a tabbed screen with three tabs — Feed Posts, Pinterest, and Stories — each showing the scheduled media for that content type pulled from Planoly, with thumbnails and scheduled timestamps.

Copy this prompt to try it in FlutterFlow

Troubleshooting

API returns 401 Unauthorized or 403 Forbidden even though the token looks correct

Cause: Either the Planoly API access has not been approved for your account, the token was entered incorrectly in the proxy environment variable, or the account tier does not qualify for API access.

Solution: Confirm with Planoly support that your account's API access is approved and active. Double-check that the token is set correctly in the Firebase Secret Manager or Supabase secrets — copy it fresh from the Planoly approval communication. Verify that the base URL matches exactly what Planoly specified at approval; an incorrect host returns auth-looking errors.

Images in the GridView do not load or show broken image icons

Cause: The thumbnail URLs returned by Planoly may require an authorization header to serve, or the URLs are time-limited signed URLs that expired before the image widget fetched them.

Solution: Check whether the Planoly API returns public CDN URLs or authenticated signed URLs for thumbnails. If they are signed URLs with a short expiry, refresh the post list more frequently (every 1-2 minutes) or have the proxy pre-fetch and re-sign the URLs before returning them to the app. For CORS issues on FlutterFlow web builds, add the appropriate CORS headers in your proxy response.

GridView shows posts out of order compared to the Planoly grid preview

Cause: The Planoly API may return posts sorted by creation time rather than scheduled grid order, or the response pagination is mixing up the ordering.

Solution: Check the API response for a sort field or ordering parameter (such as a grid position index or scheduled_at timestamp). Sort the post list in the proxy before returning it, using the same ordering logic Planoly uses to render the grid. If Planoly provides a `grid_position` field, sort by that ascending in the proxy response.

XMLHttpRequest error in FlutterFlow web preview when calling the proxy

Cause: Your Firebase Cloud Function or Supabase Edge Function is not returning CORS headers, so the browser blocks the response in FlutterFlow's web Run mode.

Solution: Add CORS headers to your proxy function. In the Firebase Cloud Function, add `res.set('Access-Control-Allow-Origin', '*')` before any response, and handle the OPTIONS preflight request by returning 204 with the Allow headers. The example proxy code in Step 2 already includes this pattern. Native mobile builds (Android/iOS) are not affected by CORS.

Best practices

  • Never place the Planoly API token in a FlutterFlow API Call header — it ships inside the compiled app bundle and can be extracted by anyone who downloads the app.
  • Request API access before writing any code. Planoly's developer access is not a dashboard toggle, and building the integration without approval leads to 401/403 errors regardless of how correct the code is.
  • Confirm the exact base URL from Planoly's developer documentation or approval communication at the time of setup — the host is not publicly fixed and may change.
  • Cache the scheduled-posts list on the client (App State) with a 3-5 minute TTL to avoid rate limits on a screen that users open frequently.
  • Flatten nested post objects in the proxy before returning them to FlutterFlow. Deeply nested JSON is harder to bind to widgets and prone to null-safety errors in Dart.
  • Sort the post list by grid order or scheduled time in the proxy so the 3-column GridView matches the Planoly preview without client-side sorting logic.
  • Lazy-load post thumbnails and use FlutterFlow's built-in Flutter image caching to avoid re-fetching images on every grid scroll.
  • Monitor proxy call volume after launch and adjust the cache interval if Planoly rate limits trigger. A short-lived server-side cache in Firestore or Supabase protects against burst traffic from multiple users accessing the same account simultaneously.

Alternatives

Frequently asked questions

Can I place the Planoly API token directly in a FlutterFlow API Call header?

No. FlutterFlow compiles to a Flutter client app. Any value in an API Call header ships inside the compiled app bundle and can be extracted by reverse-engineering the binary. The Planoly token grants access to your full content calendar and scheduled posts — it must stay in a server-side proxy (Firebase Cloud Function or Supabase Edge Function) where only your backend code can read it.

How do I get a Planoly API token?

Planoly's API is not self-serve. You need to request developer access through planoly.com/developer or by contacting Planoly support. Describe the app you are building and the endpoints you need. Access may be gated to Pro or Business plan holders. Once approved, Planoly provides the token and the current API base URL. Build time: allow up to a week for approval.

Will this integration work on FlutterFlow's web platform as well as mobile?

Yes, with one caveat. Native mobile builds (Android and iOS) are not affected by CORS restrictions. Web builds running in a browser will trigger CORS preflight requests to your proxy function. Make sure your Firebase Cloud Function or Supabase Edge Function returns the correct `Access-Control-Allow-Origin` header (set it to `*` or your app's domain) and handles OPTIONS preflight requests. The example proxy code in Step 2 of this tutorial includes the CORS headers.

How do I build the Instagram grid preview layout in FlutterFlow?

Use a GridView widget with Cross Axis Count set to 3, Cross Axis Spacing of 2, Main Axis Spacing of 2, and Child Aspect Ratio of 1.0 (square cells). Power the GridView with the `GetScheduledPosts` API Call and bind the child Image widget to `currentPost.thumbnailUrl`. This replicates the 3-column square-tile layout of an Instagram grid.

Can FlutterFlow receive Planoly webhook notifications when a post is published?

FlutterFlow cannot receive webhooks directly — it has no server runtime. If Planoly supports publish webhooks, point them at your Firebase Cloud Function or Supabase Edge Function. The function receives the notification, updates the post status in Firestore or Supabase, and the FlutterFlow app reads the updated status from the database on the next screen load or via a Firestore real-time stream.

What happens if Planoly changes their base URL or API structure after I launch?

Because all API calls go through your proxy function — not directly from FlutterFlow — you only need to update the proxy code when Planoly changes something. Your FlutterFlow app keeps calling the same proxy URL unchanged. This is one of the key advantages of the proxy pattern: API changes at the vendor side require only a single backend deployment, not a new app release.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Integrations are where projects stall

We wire FlutterFlow integrations like this one every week — auth, webhooks, edge cases included. Fixed-price builds from $13K, delivered in 6–10 weeks.

Talk to an integration engineer

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.