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

How to Integrate Retool with Marketo

Connect Retool to Marketo by creating a REST API Resource using Marketo's client credentials OAuth flow. First exchange your client_id and client_secret for an access token via GET /identity/oauth/token, then use that token as a Bearer token in subsequent API calls to your Marketo instance URL (https://YOUR_MUNCHKIN_ID.mktorest.com). Build dashboards for lead management, campaign operations, and program reporting.

What you'll learn

  • How to create a Marketo API-only role and LaunchPoint service for API credentials
  • How to implement Marketo's client credentials OAuth token exchange in a Retool JavaScript query
  • How to build a REST API Resource that uses a dynamic access token from a state variable
  • How to query Marketo leads, programs, campaigns, and activity data with pagination
  • How to build a marketing operations dashboard for enterprise teams managing complex Marketo workflows
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Advanced15 min read45 minutesMarketingLast updated April 2026RapidDev Engineering Team
TL;DR

Connect Retool to Marketo by creating a REST API Resource using Marketo's client credentials OAuth flow. First exchange your client_id and client_secret for an access token via GET /identity/oauth/token, then use that token as a Bearer token in subsequent API calls to your Marketo instance URL (https://YOUR_MUNCHKIN_ID.mktorest.com). Build dashboards for lead management, campaign operations, and program reporting.

Quick facts about this guide
FactValue
ToolMarketo
CategoryMarketing
MethodREST API Resource
DifficultyAdvanced
Time required45 minutes
Last updatedApril 2026

Build a Marketo Marketing Operations Dashboard in Retool

Marketo is one of the most powerful enterprise marketing automation platforms, but its native UI is notoriously complex for operations work. Marketing ops teams regularly need to perform bulk operations — updating lead field values across a filtered segment, auditing program membership across multiple campaigns, reviewing lead scoring assignments — that require navigating multiple Marketo UI sections or running Marketo's Smart List exports. Retool provides a dramatically faster interface for these repetitive operational tasks.

Marketo's REST API provides comprehensive access to leads, activities, programs, campaigns, and smart lists. The authentication model is more complex than most APIs: you must first exchange API credentials (client_id and client_secret from a LaunchPoint service) for an access token via Marketo's identity endpoint, then use that token for all subsequent calls. Tokens expire after 3,600 seconds (1 hour), requiring periodic refresh.

The Marketo API also uses a unique instance URL structure — every Marketo account has a Munchkin ID (a 9-character alphanumeric code) that forms the subdomain of the API endpoint: https://YOUR_MUNCHKIN_ID.mktorest.com. All API paths are then appended to this base URL. This instance-specific URL, combined with the token refresh requirement, makes Marketo integration more involved than typical REST APIs — but the operational value of custom dashboards makes the setup worthwhile for enterprise marketing teams.

Integration method

REST API Resource

Marketo connects to Retool via a REST API Resource using a two-step authentication pattern: first, a JavaScript query exchanges your client_id and client_secret for a short-lived access token from Marketo's identity endpoint. That access token is stored in a Retool state variable and used as a Bearer token in all subsequent REST API queries. Token refresh must be handled explicitly since Marketo tokens expire after 3,600 seconds. The Marketo instance URL is unique per account (https://YOUR_MUNCHKIN_ID.mktorest.com) and all API calls target this endpoint.

Prerequisites

  • A Marketo account with API access enabled (requires an administrator to create an API-only role and LaunchPoint service)
  • Your Marketo Munchkin ID (9-character alphanumeric code found in Admin → Integration → Munchkin)
  • Marketo LaunchPoint API credentials: Client ID and Client Secret (created in Admin → Integration → LaunchPoint)
  • A Retool account with permission to create Resources and Configuration Variables
  • Familiarity with OAuth token exchange patterns and Retool's JavaScript query capabilities

Step-by-step guide

1

Create a Marketo API role and LaunchPoint service

Setting up Marketo API access requires administrator privileges. In Marketo, navigate to Admin → Security → Roles. Create a new role named 'Retool API' with the following permissions enabled under API Access: Read-Only Lead, Read-Write Lead (if you need write access), Read-Only Activity, Read-Only Assets, and Read-Only Campaign (add Read-Write Campaign for write operations). Next, go to Admin → Security → Users. Create a new user named 'Retool API User' with an API-Only designation checked. Assign the Retool API role. Note that API-Only users cannot log into the Marketo UI — they exist solely for API authentication. Now create the API credentials. Navigate to Admin → Integration → LaunchPoint. Click New → New Service. Fill in: - Display Name: Retool Integration - Service: Custom - Description: API service for Retool dashboards - API Only User: select the 'Retool API User' you created Click Create. In the LaunchPoint services list, click View Details next to 'Retool Integration'. You will see the Client ID and Client Secret — copy both values immediately. Your Munchkin ID is in Admin → Integration → Munchkin. It's a 9-character code like 'AAA-BBB-123'. Your Marketo API base URL is: https://AAA-BBB-123.mktorest.com (replace with your actual Munchkin ID). Store these in Retool Settings → Configuration Variables: - MARKETO_CLIENT_ID (your Client ID — not secret, but keep private) - MARKETO_CLIENT_SECRET (your Client Secret — mark as secret) - MARKETO_BASE_URL (https://YOUR_MUNCHKIN_ID.mktorest.com)

Pro tip: The Client ID and Client Secret are both shown only in the LaunchPoint 'View Details' dialog. Copy them immediately — if you close the dialog, you can view them again by clicking View Details, but you cannot recover a lost secret without regenerating credentials.

Expected result: You have Marketo LaunchPoint credentials (Client ID and Client Secret), your Munchkin ID, and the API base URL all stored in Retool Configuration Variables.

2

Create the Marketo REST API Resource and token exchange

In Retool, navigate to the Resources tab and click Add Resource. Select REST API. Name: Marketo API Base URL: {{ retoolContext.configVars.MARKETO_BASE_URL }}/rest Note: The /rest path prefix is part of the base URL — all Marketo REST API paths start with /rest. Do not include it in individual query paths. Headers: - Key: Content-Type | Value: application/json Authentication: None (we will handle auth via a dynamic token in each query) Click Create Resource. Now create a JavaScript query named getMarketoToken that exchanges credentials for an access token. This query calls the identity endpoint (which uses a different path prefix than /rest): Create a second REST API resource named 'Marketo Identity' with base URL: {{ retoolContext.configVars.MARKETO_BASE_URL }}/identity Create a query named getAccessToken using the Marketo Identity resource: - Method: GET - Path: /oauth/token - Parameters: - grant_type: client_credentials - client_id: {{ retoolContext.configVars.MARKETO_CLIENT_ID }} - client_secret: {{ retoolContext.configVars.MARKETO_CLIENT_SECRET }} The response includes access_token and expires_in (3600 seconds). Store the token in a Retool state variable named marketoToken using an On Success event handler: marketoToken.setValue(data.access_token). Set this query to run on page load. Now all other Marketo API queries can use: Bearer {{ marketoToken.value }} in their Authorization header.

token_transformer.js
1// getAccessToken query response transformer
2// Verify the token response has the expected fields
3if (!data.access_token) {
4 throw new Error('Token response missing access_token: ' + JSON.stringify(data));
5}
6return {
7 access_token: data.access_token,
8 token_type: data.token_type,
9 expires_in: data.expires_in,
10 expires_at: new Date(Date.now() + data.expires_in * 1000).toISOString()
11};

Pro tip: Add a query named refreshTokenIfNeeded that checks if the token is older than 55 minutes and re-runs getAccessToken if so. Call this query at the start of any complex workflow to avoid token expiry mid-operation.

Expected result: The getAccessToken query runs on page load, fetches a Marketo access token, and stores it in the marketoToken state variable. Subsequent API queries can use this token in their Authorization header.

3

Fetch leads and build the lead search panel

Create a query named searchLeads. Set the resource to Marketo API, method to GET, and path to /leads.json. Required parameters for lead lookup by email: - filterType: email - filterValues: {{ textInput_email.value }} — comma-separated list of emails to look up - fields: id,firstName,lastName,email,company,leadScore,leadStatus,updatedAt,createdAt (comma-separated list of field API names) Headers for this query: - Authorization: Bearer {{ marketoToken.value }} The response includes a result array of lead objects matching the filter, and a success boolean. Always check success === true before processing results. If success is false, the errors array contains error codes and messages. Marketo's API returns field names using API field names (camelCase like firstName) rather than display names. The field names are configurable and may differ between Marketo instances — check Admin → Field Management for your account's field API names. For searches by name or other non-unique fields, use Marketo's Filter endpoint with a Smart List: POST /leads/filter.json with the filter criteria. This is more complex but supports rich filtering. Create a transformer that maps the lead objects to display-friendly rows, formatting dates and handling null values. Bind to a Table named table_leads.

transformer_leads.js
1// Transformer for Marketo leads
2const leads = data.result || [];
3if (!data.success) {
4 const errMsg = (data.errors || []).map(e => e.message).join(', ');
5 throw new Error('Marketo API error: ' + errMsg);
6}
7return leads.map(lead => ({
8 id: lead.id,
9 first_name: lead.firstName || '',
10 last_name: lead.lastName || '',
11 full_name: `${lead.firstName || ''} ${lead.lastName || ''}`.trim(),
12 email: lead.email || '',
13 company: lead.company || '',
14 lead_score: lead.leadScore ?? 0,
15 lead_status: lead.leadStatus || '',
16 updated: lead.updatedAt ? new Date(lead.updatedAt).toLocaleDateString() : '',
17 created: lead.createdAt ? new Date(lead.createdAt).toLocaleDateString() : ''
18}));

Pro tip: Marketo lead field API names vary by instance and customization. If your query returns empty results for a field, check Admin → Field Management in Marketo to find the exact API Name for that field.

Expected result: The lead search panel returns matching leads from Marketo with name, email, company, lead score, and status — displayed in a sortable Table.

4

Fetch programs and campaign data

Create a query named getPrograms. Set method to GET and path to /assets/v1/programs.json. Query parameters: - offset: {{ pagination.offset || 0 }} - maxReturn: 20 (max 200 per request) - filterType: programType (optional — filter to specific program types) - filterValues: email,nurture,engagement,event (comma-separated program types) - earliestUpdatedAt: {{ dateRange.start?.toISOString() || '' }} Headers: Authorization: Bearer {{ marketoToken.value }} Marketo's Assets API (path prefix /rest/assets/v1/) is separate from the Lead Database API (/rest/v1/). Both use the same Marketo API resource and the same access token, but the path structure differs — this is a common source of confusion. The response includes a result array of program objects with id, name, type, channel, status, workspace, tags, and description. For program membership details, create a getProgramMembers query: GET /v1/leads/programs/{{ table_programs.selectedRow?.data?.id }}/members.json - fields: id,firstName,lastName,email,membershipDate,progressionStatus,isExhausted,reachedSuccess - batchSize: 200 — pagination batch size - nextPageToken: {{ nextPageToken || '' }} — for cursor-based pagination Marketo uses a nextPageToken cursor for pagination on large result sets. Store the token from each response in a state variable to enable 'Load More' functionality.

transformer_programs.js
1// Transformer for Marketo programs
2const programs = data.result || [];
3return programs.map(p => ({
4 id: p.id,
5 name: p.name || '(Unnamed)',
6 type: p.type || '',
7 channel: p.channel || '',
8 status: p.status || '',
9 workspace: p.workspace || 'Default',
10 created: p.createdAt ? new Date(p.createdAt).toLocaleDateString() : '',
11 updated: p.updatedAt ? new Date(p.updatedAt).toLocaleDateString() : '',
12 url: p.url || '',
13 tags: (p.tags || []).map(t => `${t.tagType}: ${t.tagValue}`).join(', ')
14}));

Pro tip: Marketo's API has a daily rate limit of 50,000 calls per day and a concurrent request limit. For large-scale operations with many leads or programs, implement pagination carefully and avoid running dashboard queries on auto-refresh intervals shorter than 5 minutes.

Expected result: The programs Table shows all Marketo programs with type, channel, status, and workspace. Selecting a program populates a members table showing lead progression statuses.

5

Handle token expiry and build bulk operations

Marketo tokens expire after exactly 3,600 seconds (1 hour). Queries will start returning 601 errors ('Access token invalid') when the token expires. Build automatic token refresh handling. Create a JavaScript query named ensureValidToken: 1. Check when the token was last fetched (store the fetch time in a state variable tokenFetchedAt) 2. If current time - tokenFetchedAt > 55 minutes (3,300 seconds), call getAccessToken again 3. On success, update both marketoToken and tokenFetchedAt For bulk lead updates, Marketo provides a batch endpoint: POST /v1/leads.json with an action parameter: - action: createOrUpdate (upsert) | createOnly | updateOnly | createDuplicate - lookupField: email (the field to match existing leads on) - input: array of lead objects to create/update (max 300 per request) Build a bulk update form in Retool where users paste or upload a CSV of leads to update. Use a File Upload component for CSV input, parse it in a JavaScript query using Retool's built-in CSV parsing, then batch the updates in groups of 300. For complex Marketo implementations involving custom field management, program cloning automation, or multi-program reporting, RapidDev's team can help architect the full Retool solution with appropriate error handling and rate limit management.

bulk_update_body.json
1// Bulk lead update request body
2{
3 "action": "createOrUpdate",
4 "lookupField": "email",
5 "input": {{ JSON.stringify(
6 csvData.slice(batchStart, batchStart + 300).map(row => ({
7 firstName: row.firstName,
8 lastName: row.lastName,
9 email: row.email,
10 company: row.company,
11 leadScore: parseInt(row.leadScore) || 0
12 }))
13 ) }}
14}

Pro tip: Marketo's bulk update endpoint returns a result array with status per lead ('created', 'updated', 'skipped'). Always parse this response and surface any 'skipped' leads to the user with the reason — common reasons include duplicate email across leads or invalid field values.

Expected result: The dashboard handles token expiry gracefully with automatic refresh, and bulk lead operations work correctly for batches up to 300 leads at a time with per-record status feedback.

Common use cases

Build a lead management and scoring dashboard

Create a Retool panel for marketing ops: search leads by email or name, view full lead records (all field values, list memberships, activity history), update lead fields, and trigger campaign membership assignments. Operations teams can perform lead management tasks that normally require navigating multiple Marketo screens from a single unified view.

Retool Prompt

Build a Retool Marketo lead management panel. Include a search input for lead email or name. Show matching leads in a Table with: name, email, company, lead score, lead status, and last modified date. When a lead is selected, display their complete field values in a detail panel on the right. Include a form to update lead fields and a button to add the lead to a specific static list.

Copy this prompt to try it in Retool

Build a program performance and membership dashboard

Create a Retool dashboard showing Marketo program metrics: member counts, success rates, progression statuses, and program costs. Marketing managers can compare program performance across campaigns, identify programs with low conversion rates, and audit program membership for specific audience segments.

Retool Prompt

Build a Retool Marketo program dashboard. Show all programs in a Table with: name, type, status, member count, success count, and cost. When a program is selected, show member progression statuses in a Chart (pie chart of status distribution). Add a date range filter. Include stat components for total program spend, total members, and average success rate.

Copy this prompt to try it in Retool

Build a campaign schedule and activity monitor

Create a Retool operations panel showing all scheduled Marketo campaigns, their trigger conditions, and recent activity. Marketing ops teams can view what campaigns are actively running, identify campaigns with errors, review campaign membership queues, and trigger or abort campaigns from a centralized control panel without navigating Marketo's campaign scheduling UI.

Retool Prompt

Build a Retool Marketo campaign monitor. Show a Table of all trigger campaigns with: name, status, last modified, trigger type, and member count. Add a filter for Active vs Draft status. When a campaign is selected, show its recent leads in the queue. Include buttons to Activate and Deactivate selected campaigns with confirmation modals.

Copy this prompt to try it in Retool

Troubleshooting

All API requests return error code 601 'Access token invalid'

Cause: The Marketo access token has expired (tokens expire after 3,600 seconds / 1 hour). Marketo does not return a 401 status code for expired tokens — it returns 200 with error code 601 in the response body.

Solution: Run the getAccessToken query again to obtain a fresh token. Update the marketoToken state variable. To prevent this from happening mid-session, implement automatic token refresh: add a query that checks if the stored token is older than 55 minutes and refreshes it proactively. You can also add an On Failure event handler to any query that detects 601 errors and triggers token refresh before retrying.

typescript
1// Check for Marketo 601 error in query response
2// Add this check in a transformer or On Success handler:
3if (data.errors && data.errors.some(e => e.code === '601')) {
4 // Trigger token refresh
5 await getAccessToken.trigger();
6 throw new Error('Token refreshed - retry the query');
7}

Lead search returns empty results for known leads

Cause: The filterValues parameter must exactly match the stored field value. Email searches are case-insensitive, but other field types may be case-sensitive. Additionally, the filterType must match a valid, searchable field — not all Marketo fields are indexed for API filtering.

Solution: Verify the email address is correct and exists in Marketo by testing in Marketo's Lead Database directly. Confirm the filterType is a valid Marketo filter field (email, id, and custom indexed fields are valid; arbitrary fields are not). Check the Marketo API documentation for the list of supported filterType values for your instance.

Programs endpoint returns 404 Not Found

Cause: Marketo has two separate API namespaces: the Lead Database API (/rest/v1/) and the Asset API (/rest/assets/v1/). Mixing paths between these namespaces causes 404 errors. Programs are in the Asset API, not the Lead Database API.

Solution: Verify your query path is /assets/v1/programs.json and NOT /v1/programs.json. If your Retool resource base URL ends with /rest, then the full path should be: /assets/v1/programs.json. Do not include /rest in the query path — it is already in the resource base URL.

API calls work but Marketo returns rate limit errors after many requests

Cause: Marketo enforces a daily limit of 50,000 API calls and a concurrent request limit per 20-second window. Dashboards with many auto-refreshing queries or bulk operations can exhaust these limits.

Solution: Reduce auto-refresh intervals on dashboard queries to no less than 5 minutes. Implement caching (query Advanced settings) for read-heavy queries like getPrograms. For bulk operations, add delays between batches using: await new Promise(resolve => setTimeout(resolve, 500)). Monitor your daily API usage in Marketo Admin → Integration → Web Services.

Best practices

  • Store Marketo credentials (Client ID, Client Secret, Munchkin ID) in Retool Configuration Variables with the Client Secret marked as secret — never include credentials directly in resource or query configurations visible to other builders.
  • Implement proactive token refresh by tracking the token fetch timestamp in a state variable and refreshing at 55 minutes — this prevents the jarring experience of dashboard queries failing mid-session due to token expiry.
  • Always check the success field in Marketo API responses before processing results — Marketo returns HTTP 200 even for API errors, with success: false and an errors array containing error codes and messages.
  • Use the fields query parameter to request only the lead fields you display in your dashboard — Marketo returns all field values by default, and large lead records with hundreds of custom fields significantly impact query performance.
  • Batch lead updates in groups of 300 (the Marketo API maximum per request) and add a 500ms delay between batches to stay within rate limits — Marketo's daily 50,000 call limit can be exhausted quickly by poorly optimized bulk operations.
  • Create a minimal-permission LaunchPoint service specifically for Retool — use read-only permissions unless your dashboard explicitly needs write access, and document which Marketo operations the Retool integration performs.
  • Cache program and campaign list queries for at least 5 minutes — program structures change infrequently, and repeated reads contribute to the daily API call limit without providing fresh data.

Alternatives

Frequently asked questions

Does Retool have a native Marketo connector?

No, Retool does not have a native Marketo connector. You connect via a REST API Resource using Marketo's client credentials OAuth token exchange. The setup is more involved than simple API key integrations — you need to create a LaunchPoint service in Marketo, implement token exchange logic in a Retool query, and handle token refresh. The total setup time is approximately 45 minutes.

Why does Marketo use a different authentication model than most APIs?

Marketo uses OAuth 2.0 client credentials flow, which requires exchanging a Client ID and Client Secret for a short-lived access token before making API calls. This design provides better security than static API keys because tokens expire after 1 hour, limiting the exposure window if a token is ever intercepted. The tradeoff is more complex integration setup requiring token refresh logic.

What is a Munchkin ID and where do I find it?

The Munchkin ID is Marketo's unique account identifier — a 9-character alphanumeric string like 'AAA-BBB-123'. It forms the subdomain of your Marketo instance URL (https://AAA-BBB-123.mktorest.com) and must be included in all API endpoints. Find your Munchkin ID in Marketo under Admin → Integration → Munchkin. Every Marketo account has a unique Munchkin ID.

What are Marketo's API rate limits?

Marketo enforces a daily API call limit of 50,000 calls per account per day, resetting at midnight Pacific time. There is also a concurrent limit of 10 requests per 20-second window. Exceeding either limit results in error code 606 (daily limit) or 615 (concurrent limit). Monitor your daily usage in Admin → Integration → Web Services. For dashboards, implement query caching and avoid auto-refresh intervals shorter than 5 minutes.

How do I update lead fields in bulk from a Retool dashboard?

Use Marketo's lead upsert endpoint: POST /rest/v1/leads.json with action: 'createOrUpdate', lookupField: 'email', and an input array of up to 300 lead objects. In Retool, accept a CSV file upload, parse it in a JavaScript query, then batch the updates in groups of 300 with a small delay between batches. The response includes a per-lead status array showing whether each record was created, updated, or skipped with a reason.

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.