Skip to main content
RapidDev - Software Development Agency
retool-integrationsREST API Resource

How to Integrate Retool with Keap

Connect Retool to Keap (formerly Infusionsoft) using a REST API Resource with OAuth 2.0 authentication. Keap's REST API v2 provides endpoints for contacts, opportunities, emails, invoices, and automation tags. Build a small business CRM panel in Retool that combines contact management, sales pipeline visibility, email campaign tracking, and invoice management in a single interface faster than Keap's native UI.

What you'll learn

  • How to register a Keap developer application and configure OAuth 2.0 credentials
  • How to create a Keap REST API Resource in Retool with OAuth 2.0 authentication
  • How to query contacts, opportunities, email campaigns, and invoices via Keap's REST API v2
  • How to build a CRM dashboard combining Keap contact management with sales pipeline tracking
  • How to use JavaScript transformers to reshape Keap API responses for Retool Tables and Charts
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate14 min read30 minutesOtherLast updated April 2026RapidDev Engineering Team
TL;DR

Connect Retool to Keap (formerly Infusionsoft) using a REST API Resource with OAuth 2.0 authentication. Keap's REST API v2 provides endpoints for contacts, opportunities, emails, invoices, and automation tags. Build a small business CRM panel in Retool that combines contact management, sales pipeline visibility, email campaign tracking, and invoice management in a single interface faster than Keap's native UI.

Quick facts about this guide
FactValue
ToolKeap
CategoryOther
MethodREST API Resource
DifficultyIntermediate
Time required30 minutes
Last updatedApril 2026

Build a Keap CRM and Marketing Automation Panel in Retool

Keap combines CRM, email marketing, e-commerce, and invoicing in a single platform aimed at small businesses — but its native interface can feel cluttered for teams that primarily need rapid access to contacts, pipeline stages, or campaign metrics. Retool creates a focused, faster CRM panel by connecting directly to Keap's REST API v2, showing only the data your sales and operations team needs without navigating Keap's full product interface.

With a Retool-Keap integration, you can build a contact search and management panel that surfaces contact history, tags, and lead source in seconds, an opportunity pipeline dashboard that shows deals by stage with filters for assigned user and close date, an email campaign performance table with open and click rates, and an invoice management panel for tracking outstanding payments and generating new invoices. Because all queries route through Retool's server-side proxy, Keap OAuth tokens are never exposed in the browser even when shared internally.

Keap's API is structured around its core entities: Contacts, Opportunities, Emails, Tags, Orders, and Products. The API uses OAuth 2.0 which requires a brief one-time authorization flow during setup, but Retool handles token refresh automatically after the initial configuration. For teams running the legacy Infusionsoft XML-RPC API, Keap provides a parallel migration path to REST API v2 — Retool works exclusively with the REST API.

Integration method

REST API Resource

Keap's REST API v2 uses OAuth 2.0 for authentication, requiring a Client ID and Client Secret from a registered Keap developer application, plus an authorization flow to obtain access and refresh tokens. In Retool, you configure a REST API Resource with the Keap API base URL and OAuth 2.0 credentials, using Retool's built-in OAuth token management. Retool proxies all requests server-side, so credentials never reach the browser. Alternatively, you can use a service account access token for server-to-server integrations without the user-facing OAuth flow.

Prerequisites

  • A Keap account (Keap Pro, Max, or Max Classic) with API access enabled
  • A Keap developer application registered at https://keys.developer.keap.com/ to obtain Client ID and Client Secret
  • The OAuth 2.0 authorization flow completed to obtain an access token and refresh token
  • A Retool account with permission to create Resources
  • Basic familiarity with OAuth 2.0 authentication flows and Retool's Query Editor

Step-by-step guide

1

Register a Keap developer application

To connect Retool to Keap, you need OAuth 2.0 credentials from a registered developer application. Navigate to Keap's developer portal at https://keys.developer.keap.com/ and sign in with your Keap account. Click 'Create New Application' and fill in the application details: a name (e.g., 'Retool Integration'), a description, and your organization. For the Redirect URI field — which is required for the OAuth authorization code flow — enter the Retool OAuth callback URL. On Retool Cloud, this is https://oauth.retool.com/oauth/oauthcallback. If you are using self-hosted Retool, it is https://your-retool-instance.com/oauth/oauthcallback. Submit the application registration. Keap will display your Client ID and Client Secret — copy both values immediately. The Client Secret is shown only during registration; if you lose it you must regenerate it. Keep these credentials secure as they authorize full API access to your Keap account. Keap's OAuth scopes cover all standard operations (contacts, opportunities, emails) with a single application registration — you do not need to request individual scopes during app creation.

Pro tip: Register the developer application under a company/team account rather than a personal Keap account. If the account that registered the app is deactivated, the OAuth credentials become invalid and the integration will stop working.

Expected result: You have a Keap Client ID and Client Secret from the developer portal, and you have recorded the Retool OAuth callback URL.

2

Create the Keap REST API Resource in Retool with OAuth 2.0

In Retool, navigate to the Resources tab and click Add Resource. Select REST API from the resource type list. Name the resource 'Keap CRM'. In the Base URL field, enter https://api.infusionsoft.com/crm/rest/v2 — note that Keap's REST API uses the infusionsoft.com domain despite the product being renamed to Keap. Scroll to the Authentication section and select OAuth 2.0 from the dropdown. Configure the OAuth 2.0 settings with these values: Authorization URL: https://accounts.infusionsoft.com/app/oauth/authorize, Token URL: https://api.infusionsoft.com/token, Client ID: your application's Client ID, Client Secret: your application's Client Secret, Scopes: leave empty (Keap grants all scopes on OAuth authorization), and Authorization Code in: Header. Under 'Token storage', select 'Server-side' for security. Click 'Connect' to initiate the OAuth authorization flow — Retool will open a popup window redirecting you to Keap's authorization page where you log in with your Keap credentials and authorize the application. After authorization, Retool receives and stores the access and refresh tokens automatically. Add a default header for Content-Type: application/json. Click Save Changes. Retool will auto-refresh the access token using the refresh token whenever it expires, so you do not need to manually re-authorize.

Pro tip: If you prefer service account (server-to-server) authentication without the user OAuth flow, Keap supports generating a personal access token from your Keap Developer Portal. Use this as a Bearer token in a header instead of configuring OAuth 2.0 in the resource. Personal tokens are simpler to set up but do not auto-refresh.

Expected result: The Keap CRM resource shows a connected OAuth status with green indicator. A test GET query to /contacts returns contact data from your Keap account.

3

Query contacts with search and filtering

In your Retool app's Code panel, click + to create a new query named 'getContacts'. Select your Keap CRM resource. Set Method to GET and Path to /contacts. Keap's contacts endpoint supports several query parameters for filtering and searching. In URL Parameters, add: 'limit' set to {{ pagination.pageSize || 25 }}, 'offset' set to {{ (pagination.page - 1) * (pagination.pageSize || 25) }}, 'given_name' set to {{ nameSearch.value?.split(' ')[0] || '' }} for first name search, 'family_name' set to {{ nameSearch.value?.split(' ')[1] || '' }} for last name search, 'email' set to {{ emailSearch.value || '' }} for email search, and 'tag_id' set to {{ tagFilter.value || '' }} to filter by Keap tag. The response from Keap's contacts endpoint includes a 'contacts' array directly (not JSON:API format, unlike some CMSs). Each contact has an 'id', 'given_name', 'family_name', 'email_addresses', 'job_title', 'company', 'tag_ids', 'date_created', and 'last_updated' fields. Add a transformer to flatten the contacts array and extract the primary email address from the email_addresses array. Set the query to run on app load and re-run when search input values change (set the query's trigger to 'On change' of the search inputs).

contacts_transformer.js
1// Transformer: flatten Keap contacts response
2const contacts = data.contacts || [];
3return contacts.map(contact => ({
4 id: contact.id,
5 name: [contact.given_name, contact.family_name].filter(Boolean).join(' ') || '(No Name)',
6 email: contact.email_addresses?.[0]?.email || '',
7 company: contact.company?.company_name || '',
8 job_title: contact.job_title || '',
9 tags: (contact.tag_ids || []).join(', '),
10 owner: contact.owner_id || '',
11 created: contact.date_created ? new Date(contact.date_created).toLocaleDateString() : '',
12 updated: contact.last_updated ? new Date(contact.last_updated).toLocaleDateString() : ''
13}));

Pro tip: Keap's API returns a maximum of 1000 contacts per request. For large contact databases, use the 'offset' parameter with a Pagination component, or use the 'since' parameter with a Date Picker to show only contacts created or updated after a specific date — this is more practical than paginating through thousands of records.

Expected result: The getContacts query returns a flattened array of contact objects displayed in the Results panel, with name, email, company, and tag data.

4

Build the contact management and CRM dashboard UI

In the Retool canvas, drag a Table component and set its Data to {{ getContacts.data }}. Configure visible columns: name, email, company, job_title, tags, created. Add a row above the table with two Text Input components — one for name search (named 'nameSearch') and one for email search (named 'emailSearch'), and a Select component for tag filtering (named 'tagFilter', populated by a separate query to GET /tags that returns all tags in the Keap account). Add a Pagination component below the table. Create a Contact Detail side panel: add a Container to the right of the table, bind a Text component to show the selected contact's name as a heading, and add individual Text fields for email, phone, company, and address drawn from a second query named 'getContactDetail' that calls GET /contacts/{{ contactsTable.selectedRow.id }} and returns the full contact object including custom fields and address details. Below the detail data, create a Tags section showing current tags with a Remove button per tag (DELETE /contacts/{{ selectedId }}/tags/{{ tagId }}), and an Add Tag section with a Select dropdown and an Apply button (POST /contacts/{{ selectedId }}/tags with body { tagIds: [tagSelect.value] }). Add an Edit Contact Form with fields for first name, last name, job title, and company that submits a PATCH request to /contacts/{{ contactsTable.selectedRow.id }} to update the contact record.

update_contact_config.json
1{
2 "method": "PATCH",
3 "path": "/contacts/{{ contactsTable.selectedRow.id }}",
4 "body": {
5 "given_name": "{{ firstNameInput.value }}",
6 "family_name": "{{ lastNameInput.value }}",
7 "job_title": "{{ jobTitleInput.value }}",
8 "company": {
9 "company_name": "{{ companyInput.value }}"
10 }
11 }
12}

Pro tip: Use Retool's 'Editable Table' feature for inline contact editing instead of a separate Form component. Enable inline editing on the name, email, and company columns, and configure a PATCH query that fires on the Table's 'On save' event — this is faster for bulk contact corrections than opening a form for each record.

Expected result: A functional contact management panel shows searchable contacts with a detail panel for tag management and field updates.

5

Add opportunity pipeline and campaign performance views

Create a query named 'getOpportunities' with GET method and path /opportunities. Add URL parameters: 'limit' set to {{ pagination.pageSize || 50 }}, 'stage_name' set to {{ stageFilter.value || '' }}, and 'user_id' set to {{ ownerFilter.value || '' }}. The response includes an 'opportunities' array where each opportunity has title, contact (with id and full_name), stage (with name and id), estimated_close_date, projected_revenue_low, projected_revenue_high, and user fields. Add a transformer to flatten this and calculate a midpoint revenue estimate. Add a second query named 'getEmailCampaigns' with GET method and path /campaigns — note that Keap refers to sequences and campaigns differently; the /campaigns endpoint returns broadcast campaigns. Apply a transformer to extract campaign name, status, sent count, open rate, and click rate from each campaign. Build the Retool app with a Tab component: the first tab shows the Contacts table and detail panel from the previous step, the second tab shows the Opportunities pipeline with a summary Chart (Bar chart of total projected_revenue by stage_name), and the third tab shows the Campaigns table. For the Opportunities tab, add a total pipeline value metric at the top using a Text component bound to {{ getOpportunities.data?.reduce((sum, opp) => sum + (opp.revenue_estimate || 0), 0).toLocaleString('en-US', {style: 'currency', currency: 'USD'}) }}. For complex CRM automations connecting Keap with your internal databases or ERP systems, RapidDev's team can help architect and build your Retool solution.

opportunities_transformer.js
1// Transformer: flatten Keap opportunities with revenue midpoint
2const opps = data.opportunities || [];
3return opps.map(opp => ({
4 id: opp.id,
5 title: opp.opportunity_title || '',
6 contact_name: opp.contact?.full_name || '',
7 contact_id: opp.contact?.id || '',
8 stage: opp.stage?.name || '',
9 close_date: opp.estimated_close_date ? new Date(opp.estimated_close_date).toLocaleDateString() : '',
10 revenue_estimate: Math.round(((opp.projected_revenue_low || 0) + (opp.projected_revenue_high || 0)) / 2),
11 owner: opp.user?.first_name + ' ' + (opp.user?.last_name || ''),
12 next_action: opp.next_action_notes || ''
13}));

Pro tip: Keap's opportunity stages are customizable per account. Load your actual stages from GET /opportunityStages and use the results to populate the stage filter dropdown rather than hardcoding stage names — this keeps the filter in sync as your team adds or renames pipeline stages.

Expected result: The app has three tabs for Contacts, Opportunities, and Campaigns, each with relevant data, filters, and summary metrics from the Keap account.

Common use cases

Build a contact search and management panel

Create a Retool panel that lets sales reps search Keap contacts by name, email, company, or tag with instant results. Display a contact detail view showing full contact history (emails sent, appointments, purchases), currently applied tags, and the assigned opportunity stage. Include quick-action buttons for adding tags, updating contact fields, and sending one-off emails from within the Retool panel.

Retool Prompt

Build a Retool contact panel querying Keap's /contacts endpoint with a search input bound to the query parameter. Show a Table of matching contacts with name, email, company, tags, lead source, and owner. Selecting a row shows contact history in a detail panel with buttons to Add Tag and Update Stage.

Copy this prompt to try it in Retool

Build a sales opportunity pipeline dashboard

Create a Retool pipeline view that shows all Keap opportunities grouped by stage, with filters for assigned sales rep, close date range, and estimated value threshold. Include a summary row showing total pipeline value by stage, average days in each stage, and a Chart of new opportunities created over the last 30 days to help sales managers identify pipeline health issues early.

Retool Prompt

Build a Retool dashboard querying Keap's /opportunities endpoint. Show a Table with deal title, contact name, stage, estimated close date, projected revenue, and assigned user. Include a Bar Chart of total pipeline value by stage and a metric row showing total pipeline value, average deal size, and this month's closed-won count.

Copy this prompt to try it in Retool

Build an invoice and payment tracking panel

Create a Retool invoicing dashboard for operations teams showing all Keap invoices with their status (draft, sent, paid, overdue), amounts, due dates, and associated contacts. Include aged receivables filtering (30/60/90+ days overdue), a total outstanding balance metric, and quick actions to mark invoices as paid or trigger a follow-up email to the contact from within the Retool interface.

Retool Prompt

Build a Retool invoice panel querying Keap's /orders or /invoices endpoint. Display a Table with invoice number, contact name, total amount, amount due, creation date, due date, and status. Include an 'Overdue Only' toggle filter and summary metrics for total outstanding, 30/60/90-day aging buckets, and a Mark as Paid button.

Copy this prompt to try it in Retool

Troubleshooting

OAuth authorization popup opens but redirects back with an error

Cause: The Redirect URI registered in the Keap developer application does not match the Retool OAuth callback URL. Keap strictly validates the redirect URI and rejects mismatches with an authorization error.

Solution: In Keap's developer portal (https://keys.developer.keap.com/), open your application settings and verify the Redirect URI matches exactly: https://oauth.retool.com/oauth/oauthcallback for Retool Cloud, or https://your-retool-hostname.com/oauth/oauthcallback for self-hosted. The URL must match character-for-character including trailing slashes. Update the registered URI if it differs.

API returns 401 after a period of working correctly

Cause: Keap access tokens expire after a set period (typically 24 hours). If Retool's token refresh fails — due to a revoked refresh token, changed application credentials, or network issues — subsequent requests fail with 401.

Solution: In the Retool Resource settings for Keap, click 'Reconnect' or 'Re-authorize' to initiate the OAuth flow again and obtain fresh tokens. If the refresh token was invalidated (e.g., the user changed their Keap password or the application was revoked in Keap settings), complete the full OAuth authorization flow again.

Contact search returns no results even for existing contacts

Cause: Keap's search parameters are exact-match or prefix-match, not substring-match. Searching for 'John' may not return 'Johnson' depending on the parameter used. Additionally, the 'given_name' and 'family_name' parameters are separate — combining them in a single search field requires splitting by space.

Solution: Split the search input value to populate given_name and family_name separately: {{ nameSearch.value?.split(' ')[0] || '' }} for given_name and {{ nameSearch.value?.split(' ')[1] || '' }} for family_name. For email searches, the 'email' parameter performs a begins-with match. For full-text contact search, use Keap's contact search endpoint at POST /contacts/search with a JSON body for more flexible filtering.

Tags array in contact response shows only IDs, not tag names

Cause: Keap's contacts endpoint returns tag_ids as an array of numeric IDs, not tag names. A separate API call to /tags is required to resolve ID-to-name mapping.

Solution: Create a separate query named 'getAllTags' that calls GET /tags and runs on app load. In your contacts transformer, join the tag IDs to the tags lookup: const tagMap = Object.fromEntries((getAllTags.data?.tags || []).map(t => [t.id, t.name])); then use tagMap[tagId] to resolve each tag name in the contacts map function.

typescript
1// In contacts transformer, after loading getAllTags.data
2const tagMap = Object.fromEntries(
3 (getAllTags.data?.tags || []).map(t => [t.id, t.name])
4);
5// Then in the map:
6tags: (contact.tag_ids || []).map(id => tagMap[id] || `Tag ${id}`).join(', ')

Best practices

  • Use OAuth 2.0 with server-side token storage rather than personal access tokens — Retool's automatic token refresh eliminates the need to manually rotate credentials and prevents integration outages from token expiration
  • Store Client ID and Client Secret in Retool's Configuration Variables as secrets, not hardcoded in Resource settings, to enable credential rotation without Resource reconfiguration
  • Load tag names in a separate query on app load and create a JavaScript lookup map in your contacts transformer — this avoids N+1 API calls for resolving tag IDs to human-readable names
  • Use server-side filtering (given_name, family_name, email, tag_id URL parameters) instead of fetching all contacts and filtering in the browser — large Keap accounts can have hundreds of thousands of contacts
  • Build opportunity pipeline views using chart transformers that aggregate by stage name, since Keap's API returns individual opportunity records rather than aggregated stage counts
  • Implement Retool Workflows for automated Keap tasks — schedule workflows to send follow-up email sequences to contacts that haven't been touched in 30 days, pulling contact IDs from Keap and triggering the appropriate email sequence via POST /contacts/{id}/sequences
  • Add Confirm Modal dialogs before bulk tag operations or contact deletions to prevent accidental mass changes to your Keap CRM data

Alternatives

Frequently asked questions

What is the difference between Keap and Infusionsoft in terms of API?

Keap (formerly Infusionsoft) offers two APIs: the legacy Infusionsoft XML-RPC API and the modern Keap REST API v2. The REST API v2 (at api.infusionsoft.com/crm/rest/v2/) uses OAuth 2.0 and standard JSON, and is the recommended approach for new integrations. The XML-RPC API still works but is not being extended with new features. This Retool integration guide covers the REST API v2.

Does Retool have a native Keap connector?

No, Retool does not have a native Keap connector. You connect via a REST API Resource with OAuth 2.0 authentication. Despite the manual setup, this approach provides full access to Keap's REST API v2 endpoints including contacts, opportunities, tags, email campaigns, orders, and custom fields.

Can I create contacts and send emails from Retool to Keap?

Yes. Create contacts using POST /contacts with a JSON body containing given_name, family_name, email_addresses, and other fields. Send broadcast emails by POST-ing to Keap's email endpoints, or trigger email sequences by POST-ing to /contacts/{id}/sequences/{sequenceId}/execute. Both operations require appropriate Keap account permissions on the authorized OAuth user.

How do I handle Keap's API rate limits in Retool?

Keap enforces API rate limits that vary by plan (typically 3-6 requests per second). For Retool dashboards accessed by multiple users simultaneously, enable query caching in the Advanced tab (cache read queries for 30-60 seconds) to reduce duplicate API calls. For bulk operations, use Retool Workflows with sequential block execution rather than parallel requests to stay within rate limits.

Can I access Keap custom fields from Retool?

Yes. Keap contacts support custom fields that appear in the API response as a 'custom_fields' array on each contact object. Each custom field has a 'id', 'content', and 'field_value' structure. Query GET /contacts/model first to retrieve the custom field schema (field IDs and their display names), then use those IDs to extract values from individual contact records in your transformer.

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 Retool 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.