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

SharpSpring

Connect FlutterFlow to SharpSpring using a single POST FlutterFlow API Call to SharpSpring's v1.2 JSON-RPC-style endpoint, where the method (getLeads, getCampaigns) lives in the POST body rather than in separate URL paths. Auth is accountID and secretKey as URL query parameters. Route all calls through a Firebase Cloud Function proxy because the credentials grant full account access and cannot ship inside the compiled app.

What you'll learn

  • How SharpSpring's unusual POST-only JSON-RPC-style API differs from standard REST and how to model it in FlutterFlow
  • How to create a single FlutterFlow API Call that serves getLeads, getCampaigns, and other SharpSpring methods via body variables
  • How to detect SharpSpring API errors that return inside an HTTP 200 response body
  • How to handle SharpSpring's silent 100-row result limit with limit and offset parameters
  • How to protect accountID and secretKey with a Firebase Cloud Function proxy
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate16 min read45 minutesCRM & SalesLast updated July 2026RapidDev Engineering Team
TL;DR

Connect FlutterFlow to SharpSpring using a single POST FlutterFlow API Call to SharpSpring's v1.2 JSON-RPC-style endpoint, where the method (getLeads, getCampaigns) lives in the POST body rather than in separate URL paths. Auth is accountID and secretKey as URL query parameters. Route all calls through a Firebase Cloud Function proxy because the credentials grant full account access and cannot ship inside the compiled app.

Quick facts about this guide
FactValue
ToolSharpSpring
CategoryCRM & Sales
MethodFlutterFlow API Call
DifficultyIntermediate
Time required45 minutes
Last updatedJuly 2026

Build a Mobile Agency Marketing Dashboard with FlutterFlow and SharpSpring

SharpSpring is a marketing automation platform built for digital agencies and their clients. It handles leads from multiple campaigns, tracks deal pipelines, and sends automated email sequences. Connecting FlutterFlow to SharpSpring lets agency teams build a mobile dashboard where account managers can review lead counts, monitor campaign performance, and check deal stages for multiple clients — all from their phones without logging into the SharpSpring web interface.

SharpSpring's API has a genuinely unusual design that you need to understand before building a single FlutterFlow widget: every API operation is a POST request to the same single URL endpoint. There are no GET /leads or GET /campaigns paths. Instead, you POST a JSON body that contains a method field (like 'getLeads' or 'getCampaigns') alongside a params object with your filters. This is the JSON-RPC pattern, and it means in FlutterFlow you model the entire SharpSpring API as one POST API Call with parameterized body fields. Auth is two URL query parameters — accountID and secretKey — appended to the base URL on every request.

Two critical gotchas to know before you start. First, SharpSpring silently caps result sets at 100 rows by default. There is no error, no warning, no extra field in the response telling you there are more records — the response simply contains 100 results and stops. You must pass limit and offset values in the params body and implement pagination yourself. Second, SharpSpring returns API errors inside a 200 HTTP response as an error object in the JSON body — FlutterFlow treats the HTTP 200 as success and will not flag the error state automatically. Your action flow must inspect the response body for an error field and handle it explicitly.

Integration method

FlutterFlow API Call

SharpSpring's API is a POST-only JSON-RPC-style endpoint at a single URL — every action (getLeads, getCampaigns, getDealStages) is a POST with the method name inside the request body, not a separate REST path. In FlutterFlow, you create one POST API Call and parameterize the method and params body fields using variables, so the same API Call configuration serves all SharpSpring operations. Because accountID and secretKey grant full account-wide access and travel as URL query parameters, they must live in a Firebase Cloud Function proxy — never in the client-side API Call configuration that ships inside the compiled Flutter binary.

Prerequisites

  • A SharpSpring account on a paid agency or business plan (the API requires a paid subscription)
  • Your SharpSpring API credentials: accountID and secretKey (found in SharpSpring → Settings → API Settings → Generate)
  • A Firebase project set up for Cloud Functions (required for the security proxy)
  • A FlutterFlow project with at least one screen ready to display lead or campaign data
  • Basic familiarity with FlutterFlow's API Calls panel and action flow editor

Step-by-step guide

1

Generate your SharpSpring API credentials

Log in to your SharpSpring account. In the left navigation menu, click Settings (gear icon). Scroll down to the API section and click API Settings. If you have not generated API credentials before, click the Generate button. SharpSpring will display your accountID (a numeric string representing your account) and your secretKey (a long alphanumeric token). Copy both values and store them securely — do not paste them into a FlutterFlow API Call directly, as they will be visible in the compiled app. Note that these credentials grant full read and write access to your entire SharpSpring account, including all leads, campaigns, contacts, and deal data. If an employee leaves or credentials are compromised, regenerating them invalidates all existing keys immediately. Before proceeding, verify the credentials by making a test request — you can use a tool like Postman or the curl command below. A successful response will contain a result object with lead data; an auth error returns an error object inside a 200 HTTP response (not a 401 status code).

test_credentials.sh
1# Test SharpSpring credentials with curl
2curl -X POST \
3 'https://api.sharpspring.com/pubapi/v1.2/?accountID=YOUR_ACCOUNT_ID&secretKey=YOUR_SECRET_KEY' \
4 -H 'Content-Type: application/json' \
5 -d '{
6 "method": "getLeads",
7 "params": { "where": {}, "limit": 1, "offset": 0 },
8 "id": "1"
9 }'
10
11# Expected success: { "result": { "lead": [...] }, "error": null, "id": "1" }
12# Auth failure: { "result": null, "error": { "code": -32000, "message": "..." }, "id": "1" }

Pro tip: SharpSpring returns auth failures inside a 200 HTTP response with a non-null error object — not a 401 status code. When testing credentials, look at the error field in the JSON body, not just the HTTP status.

Expected result: You have your accountID and secretKey confirmed working via a test request, and you have them stored securely ready to put into Firebase Functions config (not in FlutterFlow directly).

2

Build a Firebase Cloud Function proxy for SharpSpring

Because SharpSpring's accountID and secretKey grant full account-wide read and write access, they cannot be stored in a FlutterFlow API Call that compiles into the client app. The correct pattern is a Firebase Cloud Function that holds both credentials as environment config and accepts requests from FlutterFlow, then forwards them to SharpSpring server-side. In Firebase Console, go to your project → Functions → Get started. Create a new file functions/index.js with the code shown below. Deploy it using the Firebase CLI. Once deployed, you will receive a URL like https://us-central1-{your-project}.cloudfunctions.net/sharpspringProxy. Set your credentials as Firebase environment config using the CLI commands shown — never paste them into the function file itself. The function accepts a JSON body with method and params fields and forwards them to SharpSpring, adding the credentials as URL query parameters server-side. It also inspects the SharpSpring response for an error object and returns it as a proper HTTP 400 if one is found, so FlutterFlow can detect failures through the standard HTTP status mechanism. If setting up a Cloud Function feels complex, the RapidDev team configures FlutterFlow proxy patterns like this regularly — book a free scoping call at rapidevelopers.com/contact.

index.js
1// Firebase Cloud Function: functions/index.js
2const functions = require('firebase-functions');
3const axios = require('axios');
4
5const ACCOUNT_ID = functions.config().sharpspring.account_id;
6const SECRET_KEY = functions.config().sharpspring.secret_key;
7const SS_URL = 'https://api.sharpspring.com/pubapi/v1.2/';
8
9exports.sharpspringProxy = functions.https.onRequest(async (req, res) => {
10 res.set('Access-Control-Allow-Origin', '*');
11 if (req.method === 'OPTIONS') {
12 res.set('Access-Control-Allow-Methods', 'POST');
13 res.set('Access-Control-Allow-Headers', 'Content-Type');
14 return res.status(204).send('');
15 }
16
17 const { method, params } = req.body;
18 if (!method) {
19 return res.status(400).json({ error: 'method is required' });
20 }
21
22 try {
23 const response = await axios.post(
24 `${SS_URL}?accountID=${ACCOUNT_ID}&secretKey=${SECRET_KEY}`,
25 { method, params: params || {}, id: '1' },
26 { headers: { 'Content-Type': 'application/json' } }
27 );
28
29 // SharpSpring errors return inside a 200 response
30 if (response.data.error) {
31 return res.status(400).json({ error: response.data.error });
32 }
33
34 return res.json(response.data.result);
35 } catch (err) {
36 return res.status(500).json({ error: err.message });
37 }
38});
39
40// Setup & deploy:
41// firebase functions:config:set sharpspring.account_id="123456" sharpspring.secret_key="abc..."
42// firebase deploy --only functions

Pro tip: The proxy re-surfaces SharpSpring's error objects as HTTP 400 responses. This lets FlutterFlow's standard error handling in action flows detect failures without you needing to manually inspect the response body in your widget logic.

Expected result: Your Firebase Cloud Function is deployed and returns SharpSpring lead data when you POST { method: 'getLeads', params: { where: {}, limit: 5, offset: 0 } } to the function URL.

3

Create the SharpSpring API Group and POST API Call in FlutterFlow

Open your FlutterFlow project. Click API Calls in the left navigation bar. Click + Add → Create API Group. Name it SharpSpring and set the Base URL to your Firebase Cloud Function URL — for example, https://us-central1-{your-project}.cloudfunctions.net/sharpspringProxy. Add a Content-Type: application/json header to the API Group. Click Save. Now click + Add API Call inside the SharpSpring group. Name it CallSharpSpring. Set the method to POST. Leave the endpoint blank (the proxy URL is the full path). Click the Body tab and set the body type to JSON. Add the following body structure: { "method": "{{ss_method}}", "params": { "where": {}, "limit": {{limit}}, "offset": {{offset}} } } Click the Variables tab and add three variables: ss_method (String, no default), limit (Integer, default 50), offset (Integer, default 0). This single API Call configuration now serves every SharpSpring operation by changing the ss_method variable value: pass 'getLeads' to list leads, 'getCampaigns' to list campaigns, 'getDealStages' to list pipeline stages. Click Response & Test. In the test form, set ss_method to 'getLeads', limit to 5, offset to 0. Click Test API. You should see a response containing a lead array. Click Generate JSON Paths to create path variables. For leads, key paths include $[:].lead (if the proxy returns the array directly) or look for the array root. Inspect the actual response structure and adjust paths accordingly.

api_call_config.json
1{
2 "group": "SharpSpring",
3 "name": "CallSharpSpring",
4 "method": "POST",
5 "endpoint": "",
6 "body_type": "JSON",
7 "body": {
8 "method": "{{ss_method}}",
9 "params": {
10 "where": {},
11 "limit": "{{limit}}",
12 "offset": "{{offset}}"
13 }
14 },
15 "variables": [
16 { "name": "ss_method", "type": "String" },
17 { "name": "limit", "type": "Integer", "default": 50 },
18 { "name": "offset", "type": "Integer", "default": 0 }
19 ]
20}

Pro tip: To call different SharpSpring methods from different screens, simply pass a different ss_method value when triggering the API Call in your action flow. Use 'getLeads' on the leads screen, 'getCampaigns' on the campaigns screen, and 'getDealStages' on the pipeline screen — all using the same CallSharpSpring API Call configuration.

Expected result: The CallSharpSpring API Call is saved and returns SharpSpring lead data when tested with ss_method set to 'getLeads'. The single API Call configuration is ready to serve all SharpSpring operations.

4

Bind getLeads results to a ListView and implement pagination

Open your leads screen in FlutterFlow. Add a Page State variable called currentOffset (Integer, default 0) and a second one called leads (list of JSON or dynamic, default empty). Select the ListView widget on the screen and open its Backend Query. Add an API Call query pointing to SharpSpring → CallSharpSpring. Set ss_method to 'getLeads', limit to 50, offset to currentOffset. Enable Trigger on Page Load. For the ListView child template, add a Card with three Text widgets. Bind the first Text to the lead's firstName and lastName fields (check the exact JSON path from your test response — SharpSpring lead fields include firstName, lastName, emailAddress, leadScore, and accountName). Bind the second Text to emailAddress. Bind the third to leadScore and add a color conditional: score above 80 = green, 40-80 = orange, below 40 = red. Below the ListView, add a Row with a 'Load more' Button. Wire the button's action flow to: 1) Set currentOffset Page State to currentOffset + 50, 2) Re-trigger the CallSharpSpring API Call with the new offset, 3) Append the new results to the existing leads list in App State. This pagination pattern is critical because SharpSpring silently returns at most 100 results per call with no indication that more exist. Without pagination, a database with 500 leads appears to have only 50-100 in your app. Always implement the 'Load more' pattern from the start.

Pro tip: SharpSpring lead fields use camelCase naming (firstName, lastName, emailAddress, companyName, leadScore). Double-check the exact field names from your test response JSON before creating your widget bindings — copying a wrong field name results in null values with no error.

Expected result: Your leads screen displays a ListView of SharpSpring leads with name, email, and color-coded lead score. A 'Load more' button fetches the next batch of 50 leads using offset pagination.

5

Add a getCampaigns call and handle SharpSpring error responses

On your campaigns screen, wire a backend query to CallSharpSpring with ss_method set to 'getCampaigns' and appropriate limit/offset values. Campaign fields in the response include id, campaignName, status, openRate, clickRate, and sentCount. Bind these to a ListView of campaign cards showing the campaign name, status badge (active/paused/draft), and performance metrics. More importantly, you must handle SharpSpring's error response pattern in your action flows. Because the Cloud Function proxy translates SharpSpring's error objects into HTTP 400 responses, you can now use FlutterFlow's standard API Call error handling. In the Action Flow Editor for any SharpSpring API Call action, expand the On Error branch and add a Show Alert Dialog action with the error message text. This gives users a clear error message rather than a silently empty screen. Also add an explicit check for the 100-result silent cap: in your action flow, after the API Call succeeds, check if the number of returned items equals your limit value. If result count equals limit, there may be more records — show the 'Load more' button. If result count is less than limit, you have reached the end — hide the 'Load more' button and optionally show a 'All leads loaded' message. This prevents users from tapping 'Load more' on an already-complete list and getting a confusing empty response.

Pro tip: SharpSpring's API errors include specific error codes that are worth logging: -32000 means authentication failure, -32600 means invalid request format, -32601 means method not found. Log the error code alongside the message in your Cloud Function's error response to make debugging faster.

Expected result: The campaigns screen shows a ListView of SharpSpring campaigns with name, status, and performance metrics. Error responses from the Cloud Function display a user-friendly alert dialog rather than a silent empty screen.

Common use cases

Agency lead-dashboard app for account managers

Build a FlutterFlow screen that calls SharpSpring's getLeads method with an accountID variable to list leads captured in the last 30 days for a client account. Account managers can filter by lead source or campaign, see lead scores alongside contact details, and quickly identify which campaigns are converting best — all without opening SharpSpring in a browser.

FlutterFlow Prompt

A FlutterFlow screen showing a list of SharpSpring leads from the last 30 days, each card with lead name, email, lead score, and source campaign, with a filter dropdown for campaign.

Copy this prompt to try it in FlutterFlow

Campaign performance monitoring app

Build a FlutterFlow screen that calls getCampaigns to list active email campaigns with their send count, open rate, and click rate for a selected date range. Agency managers can review campaign health for multiple clients in a single mobile view, spot underperforming campaigns early, and log notes for team review.

FlutterFlow Prompt

A FlutterFlow screen with a client selector and a list of SharpSpring email campaigns showing campaign name, status, open rate, and click rate for each.

Copy this prompt to try it in FlutterFlow

Deal-stage pipeline tracker for client accounts

Build a FlutterFlow Kanban-style screen that calls getDealStages to fetch the pipeline stages and then getOpportunities to list deals in each stage for a client's SharpSpring account. Sales managers can see how many deals are at each stage of the funnel and tap into individual deals to view contact info and deal value.

FlutterFlow Prompt

A FlutterFlow screen showing a horizontal scrollable pipeline view of SharpSpring deal stages, with deal cards in each stage column showing deal name, value, and close date.

Copy this prompt to try it in FlutterFlow

Troubleshooting

SharpSpring API Call returns a 200 response but the leads list is empty

Cause: SharpSpring errors return inside a 200 HTTP response as an error object, not as a 4xx HTTP status. If auth is wrong or the method name is misspelled, the response body contains { error: { code: -32000, message: 'Invalid credentials' } } and result is null — FlutterFlow sees HTTP 200 and reports success while the data is absent.

Solution: Check the actual response body in FlutterFlow's API Call Test tab, not just the HTTP status. Look for an error field in the response. The Cloud Function proxy in Step 2 translates these into HTTP 400 responses to make them detectable. If you are calling SharpSpring directly (without the proxy), add a response body check in your action flow: inspect the error field and show an alert if it is non-null.

Only 100 leads appear even though the SharpSpring account has thousands

Cause: SharpSpring silently caps all result sets at 100 rows per request without any error, warning, or pagination metadata in the response. The response looks exactly the same whether you have 100 leads total or 10,000 leads with only 100 returned.

Solution: Always pass limit and offset in the params body and implement pagination. Set limit to 100 (the maximum) and increment offset by 100 after each successful call to fetch the next page. Build a 'Load more' button that triggers the next page load and appends results to your running list in App State. Check if the returned count equals your limit value to determine whether more pages exist.

GET request to SharpSpring returns nothing or an error

Cause: SharpSpring's v1.2 API only accepts POST requests. Every operation, including data retrieval like getLeads and getCampaigns, must be a POST with the method name in the JSON body. A GET to the SharpSpring API URL returns either an error or an empty response.

Solution: Ensure your FlutterFlow API Call is set to POST method, not GET. The body must contain the method field (e.g. 'getLeads') and a params object. There are no GET endpoints in SharpSpring's v1.2 API — this is a fundamental design choice of the JSON-RPC pattern that SharpSpring uses.

XMLHttpRequest error in FlutterFlow web preview when calling the SharpSpring proxy

Cause: If your Firebase Cloud Function does not set the Access-Control-Allow-Origin header, the browser in FlutterFlow's web Run mode will block the request with a CORS error. Native mobile builds are not affected by CORS.

Solution: Ensure the Cloud Function in Step 2 includes res.set('Access-Control-Allow-Origin', '*') at the start of the handler and handles OPTIONS preflight requests with a 204 response. If you see this error on native device builds (not web preview), the issue is likely a network connectivity problem rather than CORS.

Best practices

  • Never put SharpSpring accountID or secretKey in a FlutterFlow API Call URL or body that ships in the client app — they grant full account access and must stay server-side in a Firebase Cloud Function proxy.
  • Always pass limit and offset in every SharpSpring API call and implement pagination UI — the default 100-row silent cap with no error or warning will silently truncate large datasets without any indication to users.
  • Check the error field in every SharpSpring response body, not just the HTTP status code — SharpSpring returns all errors inside a 200 HTTP response, making them invisible to standard FlutterFlow error handling without explicit inspection.
  • Model all SharpSpring operations as one parameterized POST API Call with the method name as a variable, rather than creating separate API Calls per method — this significantly reduces configuration duplication in FlutterFlow.
  • Map SharpSpring's camelCase field names (firstName, emailAddress, leadScore) carefully when setting up JSON paths — a wrong field name silently returns null with no error in FlutterFlow's binding layer.
  • Use the Firebase Cloud Function proxy to translate SharpSpring's error-in-200 pattern into proper HTTP 4xx responses, so FlutterFlow's standard On Error action flow branches can catch and display errors to users.
  • Scope your SharpSpring API calls to date ranges using the where parameter (e.g. where: { updateTimestamp: { after: '2026-01-01' } }) to avoid fetching the entire database on every app load — this keeps response times fast and reduces result-set sizes.

Alternatives

Frequently asked questions

Does SharpSpring have a free tier or trial for API access?

SharpSpring is an agency-tier marketing automation platform with subscription-based pricing — there is no free tier. API access requires an active paid subscription. Check SharpSpring's current pricing page for plan details, as pricing is agency-negotiated and may vary based on contact count and features.

Why does SharpSpring use POST for everything including data retrieval?

SharpSpring's API follows the JSON-RPC 2.0 convention, which uses POST requests exclusively. The 'method' field in the JSON body serves the same purpose as different URL paths or HTTP verbs in a REST API — it specifies which operation to perform. This is a deliberate architectural choice, not a bug. Every FlutterFlow API Call to SharpSpring must use HTTP POST.

Can I write leads back to SharpSpring from FlutterFlow, such as creating a new lead from a form?

Yes. SharpSpring's createLeads method accepts a POST body with an objects array containing lead field objects. In your Cloud Function proxy, add a branch for action: 'createLeads' that builds the correct SharpSpring payload and POSTs it to the API. In FlutterFlow, create a lead-capture form and wire the Submit button to call the proxy with the lead data from form fields.

How do I search for specific leads in SharpSpring rather than fetching all of them?

Use the where parameter in the params body to filter results. For example, to search by email: params: { where: { emailAddress: 'user@example.com' }, limit: 10, offset: 0 }. SharpSpring supports where filters on most lead fields using exact-match or comparison operators. Pass the filter value as a variable in your FlutterFlow API Call body so users can search from a text input on the screen.

What is the SharpSpring API rate limit?

SharpSpring does not publish a specific per-minute API rate limit in their documentation. The practical limit is 100 results per request, and extremely high-frequency polling may be throttled by their infrastructure. For mobile app usage patterns (refresh on load, not continuous polling), you are unlikely to hit rate limits. If you receive repeated errors under normal usage, contact SharpSpring support to confirm your plan's API limits.

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.