Skip to main content
RapidDev - Software Development Agency
replit-integrationsStandard API Integration

How to Integrate Replit with Autopilot

To integrate Replit with Autopilot, generate an API key from your Autopilot account, store it in Replit Secrets (lock icon πŸ”’), and call the Autopilot REST API from your server-side Python or Node.js code to manage contacts, trigger journey enrollments, and sync smart segments. Use Autoscale deployment for web apps that feed contacts into marketing journeys.

What you'll learn

  • How to generate an Autopilot API key and configure Replit Secrets
  • How to add and update contacts with custom fields using Python and Node.js
  • How to enroll contacts in Autopilot journeys programmatically from your Replit app
  • How to manage smart segment membership via the Autopilot API
  • How to receive Autopilot webhook events in your deployed Replit server
Book a free consultation
4.9Clutch rating ⭐
600+Happy partners
17+Countries served
190+Team members
Intermediate15 min read25 minutesMarketingMarch 2026RapidDev Engineering Team
TL;DR

To integrate Replit with Autopilot, generate an API key from your Autopilot account, store it in Replit Secrets (lock icon πŸ”’), and call the Autopilot REST API from your server-side Python or Node.js code to manage contacts, trigger journey enrollments, and sync smart segments. Use Autoscale deployment for web apps that feed contacts into marketing journeys.

Why Connect Replit to Autopilot?

Autopilot's strength is its visual journey builder β€” marketers can map out multi-step customer experiences across email, SMS, in-app messages, and direct mail without writing code. The REST API unlocks the other half: letting your application feed real behavioral data into those journeys automatically. When a user upgrades their plan, completes a workflow, or crosses a usage threshold in your Replit app, you can immediately update their Autopilot contact record and enroll them in the matching nurture journey.

The most powerful pattern is using Replit as the data bridge between your product and Autopilot. Your app tracks the events that matter β€” first login, feature adoption, inactivity β€” and translates them into Autopilot contact properties, segment memberships, and journey triggers. Marketers then design the journeys in Autopilot's visual canvas without needing to ask engineers to change code every time a new campaign launches.

Replit's Secrets system (lock icon πŸ”’ in the sidebar) keeps your Autopilot API key encrypted and inaccessible from Git history or client-side code. Because the API key grants full read/write access to your entire contact database and all journeys, it must only be used in server-side code. Never expose it in a frontend React or Vue component.

Integration method

Standard API Integration

You connect Replit to Autopilot by generating an API key in your Autopilot account settings, storing it in Replit Secrets, and calling the Autopilot REST API from your backend Python or Node.js server. All requests are authenticated with an autopilotapikey header. Your Replit app can add contacts, update custom fields, enroll contacts in journeys, and manage segment membership without touching the Autopilot UI.

Prerequisites

  • A Replit account with a Python or Node.js project created
  • An Autopilot account (trial or paid) with at least one journey created
  • Basic familiarity with REST APIs and HTTP headers
  • Node.js 18+ or Python 3.10+ (both available on Replit by default)
  • Your Autopilot journey IDs and any custom contact field names you plan to use

Step-by-step guide

1

Generate an Autopilot API Key and Store It in Replit Secrets

Log in to your Autopilot account and click the gear icon in the top-right corner to open Settings. Navigate to 'Autopilot API' in the left sidebar. On the API page, your API key is displayed β€” it is a long alphanumeric string. If you do not see one, click 'Generate API Key'. Copy the key immediately, as Autopilot may not display it again after you navigate away. Next, open your Replit project and click the lock icon πŸ”’ in the left sidebar to open the Secrets pane. Click 'Add a new secret' and enter AUTOPILOT_API_KEY as the key and your copied API key as the value. Click 'Add Secret' to save it. Replit encrypts this value with AES-256 encryption and injects it as an environment variable at runtime β€” it will never appear in your file tree or Git history. You should also note your journey IDs from the Autopilot journey list (visible in the URL when you open a journey: /journeys/{journey_id}). Store any journey IDs you plan to use as additional secrets like AUTOPILOT_ONBOARDING_JOURNEY_ID for cleaner code. In Python, access the key with os.environ['AUTOPILOT_API_KEY']; in Node.js, use process.env.AUTOPILOT_API_KEY.

Pro tip: Autopilot API keys do not expire, but you should rotate them if a team member with access leaves or if the key is accidentally logged. Generate a new key in Settings > Autopilot API and update your Replit Secret immediately.

Expected result: The AUTOPILOT_API_KEY Secret appears in the Replit Secrets pane and is accessible as an environment variable in your code.

2

Add and Update Contacts with Custom Fields in Python

The Autopilot REST API base URL is https://api2.autopilothq.com/v1. All requests require the autopilotapikey header set to your API key and Content-Type: application/json for POST/PATCH requests. The contact object uses a specific structure where custom fields are prefixed with 'string--', 'integer--', 'float--', or 'boolean--' followed by the field name β€” this prefix tells Autopilot the data type. To add or update a contact, use POST /contact with the contact data. If the email already exists, Autopilot updates the existing record (upsert behavior). You can also trigger a journey enrollment in the same request by including the trigger field. The API is synchronous β€” a successful 200 response means the contact was created or updated. The Python code below shows how to add a contact with custom fields, check if a contact exists, and update individual fields without overwriting the entire record. The requests library is sufficient β€” no third-party Autopilot SDK is needed.

autopilot_client.py
1import os
2import requests
3
4API_KEY = os.environ["AUTOPILOT_API_KEY"]
5BASE_URL = "https://api2.autopilothq.com/v1"
6
7HEADERS = {
8 "autopilotapikey": API_KEY,
9 "Content-Type": "application/json"
10}
11
12def add_or_update_contact(email: str, first_name: str = "", last_name: str = "",
13 custom_fields: dict = None) -> dict:
14 """Add a new contact or update an existing one by email."""
15 contact_data = {
16 "contact": {
17 "Email": email,
18 "FirstName": first_name,
19 "LastName": last_name
20 }
21 }
22 # Add custom fields with correct type prefix
23 if custom_fields:
24 for key, value in custom_fields.items():
25 if isinstance(value, bool):
26 contact_data["contact"][f"boolean--{key}"] = value
27 elif isinstance(value, int):
28 contact_data["contact"][f"integer--{key}"] = value
29 elif isinstance(value, float):
30 contact_data["contact"][f"float--{key}"] = value
31 else:
32 contact_data["contact"][f"string--{key}"] = str(value)
33
34 response = requests.post(
35 f"{BASE_URL}/contact",
36 json=contact_data,
37 headers=HEADERS
38 )
39 response.raise_for_status()
40 return response.json()
41
42def get_contact(email: str) -> dict:
43 """Retrieve a contact record by email address."""
44 import urllib.parse
45 encoded_email = urllib.parse.quote(email)
46 response = requests.get(
47 f"{BASE_URL}/contact/{encoded_email}",
48 headers=HEADERS
49 )
50 if response.status_code == 404:
51 return None
52 response.raise_for_status()
53 return response.json()
54
55def enroll_in_journey(journey_id: str, contact_email: str) -> dict:
56 """Trigger a contact's enrollment into a specific journey."""
57 data = {"contact": {"Email": contact_email}}
58 response = requests.post(
59 f"{BASE_URL}/journey/{journey_id}/contact",
60 json=data,
61 headers=HEADERS
62 )
63 response.raise_for_status()
64 return response.json()
65
66def add_to_list(list_id: str, contact_email: str) -> dict:
67 """Add a contact to a smart segment/list."""
68 data = {"contact": {"Email": contact_email}}
69 response = requests.post(
70 f"{BASE_URL}/list/{list_id}/subscriber",
71 json=data,
72 headers=HEADERS
73 )
74 response.raise_for_status()
75 return response.json()
76
77# Example usage
78if __name__ == "__main__":
79 result = add_or_update_contact(
80 email="user@example.com",
81 first_name="Jane",
82 last_name="Doe",
83 custom_fields={
84 "plan_type": "pro",
85 "signup_source": "organic",
86 "trial_days_remaining": 14
87 }
88 )
89 print(f"Contact created/updated: {result}")
90
91 journey_id = os.environ.get("AUTOPILOT_ONBOARDING_JOURNEY_ID", "")
92 if journey_id:
93 enroll_in_journey(journey_id, "user@example.com")
94 print("Enrolled in onboarding journey")

Pro tip: Custom field names in Autopilot are case-sensitive and must exactly match the field names defined in your Autopilot account. Check the field names in Settings > Custom Contact Fields before using them in your code.

Expected result: Running the script adds a test contact to Autopilot with custom fields and logs a success response. The contact should appear in your Autopilot contacts list within a few seconds.

3

Build a Node.js Express Server for Journey Automation

For Node.js applications, the Autopilot API is called with the node-fetch or axios library β€” no official SDK exists. The Express server below exposes POST /contacts/register for adding new contacts and POST /contacts/event for updating behavioral properties that trigger journey conditions. The server demonstrates the most common integration pattern: an app event triggers an Autopilot contact update, which in turn fires a journey action. For example, when a user upgrades from a free to a paid plan, the app sends a PATCH to update the 'plan_type' custom field, and an Autopilot journey condition on that field automatically sends a welcome-to-paid email without any further code. The 'unsubscribe all' endpoint is also important for compliance β€” if a user requests deletion or opts out of all marketing, you can immediately unsubscribe them from all journeys and lists by setting OptOut to true on the contact record. Deploy this server on Replit with Autoscale for reliable handling of registration-driven journey enrollments. Autoscale ensures the server is available when users sign up at unexpected times without paying for always-on resources.

server.js
1const express = require('express');
2const axios = require('axios');
3
4const app = express();
5app.use(express.json());
6
7const API_KEY = process.env.AUTOPILOT_API_KEY;
8const BASE_URL = 'https://api2.autopilothq.com/v1';
9const ONBOARDING_JOURNEY_ID = process.env.AUTOPILOT_ONBOARDING_JOURNEY_ID;
10
11const autopilot = axios.create({
12 baseURL: BASE_URL,
13 headers: {
14 'autopilotapikey': API_KEY,
15 'Content-Type': 'application/json'
16 }
17});
18
19// Add or update a contact (upsert by email)
20app.post('/contacts/register', async (req, res) => {
21 const { email, firstName, lastName, plan, source } = req.body;
22 if (!email) return res.status(400).json({ error: 'email is required' });
23
24 try {
25 const payload = {
26 contact: {
27 Email: email,
28 FirstName: firstName || '',
29 LastName: lastName || '',
30 'string--plan_type': plan || 'free',
31 'string--signup_source': source || 'direct',
32 'integer--signup_timestamp': Math.floor(Date.now() / 1000)
33 }
34 };
35
36 const { data } = await autopilot.post('/contact', payload);
37
38 // Enroll in onboarding journey if configured
39 if (ONBOARDING_JOURNEY_ID) {
40 await autopilot.post(`/journey/${ONBOARDING_JOURNEY_ID}/contact`, {
41 contact: { Email: email }
42 });
43 }
44
45 res.json({ success: true, contactId: data.contact_id });
46 } catch (err) {
47 console.error('Autopilot error:', err.response?.data || err.message);
48 res.status(500).json({ error: err.message });
49 }
50});
51
52// Update a contact property (e.g., plan upgrade event)
53app.post('/contacts/event', async (req, res) => {
54 const { email, event, properties } = req.body;
55 if (!email || !event) return res.status(400).json({ error: 'email and event required' });
56
57 try {
58 // Build contact update with typed custom fields
59 const contactFields = { Email: email };
60 if (properties) {
61 for (const [key, value] of Object.entries(properties)) {
62 const prefix = typeof value === 'number' ? 'integer--' : 'string--';
63 contactFields[`${prefix}${key}`] = value;
64 }
65 }
66 // Add the event name as a custom field for journey triggering
67 contactFields['string--last_event'] = event;
68 contactFields['integer--last_event_timestamp'] = Math.floor(Date.now() / 1000);
69
70 await autopilot.post('/contact', { contact: contactFields });
71 res.json({ success: true });
72 } catch (err) {
73 console.error('Event update error:', err.response?.data || err.message);
74 res.status(500).json({ error: err.message });
75 }
76});
77
78// Unsubscribe a contact from all marketing
79app.post('/contacts/unsubscribe', async (req, res) => {
80 const { email } = req.body;
81 if (!email) return res.status(400).json({ error: 'email is required' });
82
83 try {
84 await autopilot.post('/contact', {
85 contact: { Email: email, unsubscribed: true }
86 });
87 res.json({ success: true });
88 } catch (err) {
89 res.status(500).json({ error: err.message });
90 }
91});
92
93app.listen(3000, '0.0.0.0', () => {
94 console.log('Autopilot integration server running on port 3000');
95});

Pro tip: Install axios with 'npm install axios' in the Replit shell. Alternatively, use the built-in fetch API available in Node.js 18+ without any additional packages.

Expected result: The Express server starts on port 3000. A POST to /contacts/register with a valid email returns a contactId and the contact appears in Autopilot's contact list.

4

Receive Autopilot Webhook Events and Deploy

Autopilot can send webhook notifications to your Replit server when contacts reach specific points in a journey β€” for example, when a contact clicks a link, replies to an email, or completes a journey. Setting up webhooks allows your app to react to marketing engagement data in real time without polling the API. To configure webhooks in Autopilot, open a journey in the visual canvas and add a 'Notify via webhook' action from the actions panel. Enter your deployed Replit URL as the webhook endpoint (e.g., https://your-app.replit.app/autopilot/webhook). Autopilot sends a POST request with a JSON body containing the contact's details and the journey action context. Webhooks require a deployed URL β€” not a development session URL. In Replit, click 'Deploy' and choose Autoscale for apps that serve a web frontend alongside webhook handling, or Reserved VM if webhook processing is the primary workload and you need guaranteed sub-second response times. After deployment, copy the stable URL from the Deployments panel and register it in Autopilot. Test the webhook by manually triggering a journey action for a test contact.

webhook_server.py
1from flask import Flask, request, jsonify
2import os
3import json
4
5app = Flask(__name__)
6
7@app.route('/autopilot/webhook', methods=['POST'])
8def autopilot_webhook():
9 try:
10 data = request.get_json(force=True)
11 if not data:
12 return jsonify({'error': 'No JSON body'}), 400
13
14 # Extract contact information from the webhook payload
15 contact = data.get('contact', {})
16 email = contact.get('Email', '')
17 first_name = contact.get('FirstName', '')
18 journey_name = data.get('journey_name', 'unknown')
19 action_type = data.get('type', 'unknown')
20
21 print(f"Autopilot event: {action_type} in journey '{journey_name}' for {email}")
22
23 # Process different event types
24 if action_type == 'journey_completed':
25 # Handle journey completion β€” e.g., update CRM, notify sales team
26 print(f"Contact {email} completed journey: {journey_name}")
27 # update_crm_lead_score(email, points=50)
28
29 elif action_type == 'email_clicked':
30 link_url = data.get('link_url', '')
31 print(f"Contact {email} clicked: {link_url}")
32 # track_engagement_event(email, 'email_click', link_url)
33
34 elif action_type == 'unsubscribed':
35 print(f"Contact {email} unsubscribed")
36 # mark_user_unsubscribed(email)
37
38 return jsonify({'status': 'received', 'email': email}), 200
39
40 except Exception as e:
41 print(f"Webhook error: {e}")
42 return jsonify({'error': str(e)}), 500
43
44@app.route('/health', methods=['GET'])
45def health():
46 return jsonify({'status': 'ok'}), 200
47
48if __name__ == '__main__':
49 app.run(host='0.0.0.0', port=3000)

Pro tip: Autopilot does not sign webhook payloads with a signature header. To protect your endpoint, add a secret token parameter to the webhook URL (e.g., /autopilot/webhook?token=yourSecretToken) and validate it in your handler using a value stored in Replit Secrets.

Expected result: Your deployed Replit server logs incoming Autopilot journey events. The health endpoint at /health returns a 200 response to confirm the server is live.

Common use cases

Sync New App Signups to Autopilot Journeys

When a user registers in your Replit web application, automatically add them as a contact in Autopilot with custom fields reflecting their plan, signup source, and intent. Enroll them in an onboarding journey immediately so they receive the right sequence of welcome emails and activation nudges without any manual effort from your marketing team.

Replit Prompt

Build a Flask endpoint that receives new user registration data, adds the user as an Autopilot contact with custom fields for plan type and signup date using AUTOPILOT_API_KEY from Replit Secrets, and enrolls them in the onboarding journey by journey ID.

Copy this prompt to try it in Replit

Behavioral Segment Updates Based on Product Events

As users interact with your product β€” hitting usage milestones, going dormant, or reaching upgrade triggers β€” your Replit backend updates their Autopilot contact properties and moves them between smart segments. Autopilot journeys respond to segment membership changes automatically, firing the right message at the right moment in the customer lifecycle.

Replit Prompt

Write a Node.js script that queries your database for users who have been inactive for 14 days, updates their Autopilot contact with a 'last_active_days' custom field, and adds them to a re-engagement segment via the Autopilot API.

Copy this prompt to try it in Replit

Lead Scoring Webhook Receiver

Deploy a Replit server that receives Autopilot webhook events when contacts reach journey milestones β€” such as opening three emails or clicking a pricing page link. Your server writes the lead score back to your CRM or database, allowing your sales team to see which Autopilot-nurtured leads are ready for outreach without switching between tools.

Replit Prompt

Create an Express server with a POST /autopilot/webhook endpoint that receives Autopilot journey completion events, extracts the contact email and journey name, and updates a lead score field in a PostgreSQL database.

Copy this prompt to try it in Replit

Troubleshooting

API returns 401 Unauthorized on every request

Cause: The autopilotapikey header is missing, misspelled, or contains extra whitespace. Autopilot uses a custom header name β€” unlike most APIs that use Authorization: Bearer, Autopilot's header is literally autopilotapikey (all lowercase).

Solution: Verify the header name is exactly 'autopilotapikey' with no capital letters or spaces. In Replit Secrets, confirm the key value has no leading or trailing spaces. Print the first and last 4 characters of the key to verify it loaded correctly without exposing the full key.

typescript
1# Python: verify header is set correctly
2headers = {
3 'autopilotapikey': os.environ['AUTOPILOT_API_KEY'].strip(),
4 'Content-Type': 'application/json'
5}
6# Sanity check (never log the full key)
7print(f"Key starts: {os.environ['AUTOPILOT_API_KEY'][:4]}...")

Contact is created but custom fields are not saved

Cause: Custom field names must include the data type prefix (string--, integer--, float--, boolean--) and must match the field names defined in your Autopilot account exactly, including case. Fields not defined in Autopilot settings are silently dropped.

Solution: Open Autopilot Settings > Custom Contact Fields and verify your field names. In the API payload, prepend the correct type prefix: 'string--plan_type', 'integer--trial_days', 'boolean--is_premium'. Mismatched case (e.g., 'string--Plan_Type' vs 'string--plan_type') will cause fields to be ignored silently.

typescript
1# Correct custom field format
2contact_data = {
3 "contact": {
4 "Email": "user@example.com",
5 "string--plan_type": "pro", # string prefix
6 "integer--login_count": 5, # integer prefix
7 "boolean--email_verified": True # boolean prefix
8 }
9}

Journey enrollment returns 404 Not Found

Cause: The journey ID in the URL is incorrect or the journey is in Draft status. Autopilot only allows enrollments into Published journeys. Draft journeys return a 404 when you try to enroll contacts.

Solution: In Autopilot, open the journey and click 'Publish' to make it active. Copy the journey ID from the URL (/journeys/{id}) and update your AUTOPILOT_ONBOARDING_JOURNEY_ID Secret in Replit. Journey IDs are case-sensitive alphanumeric strings.

Webhook events are not being received by the Replit server

Cause: The webhook URL is pointing to a development Replit session URL that is only active when the IDE is open. Development URLs stop serving traffic when the Replit session closes.

Solution: Deploy your Replit app using the 'Deploy' button to get a permanent URL at https://your-app.replit.app. Update the webhook URL in the Autopilot journey canvas with this deployed URL. Test the webhook using Autopilot's built-in send-test feature after saving the webhook action.

Best practices

  • Store your Autopilot API key in Replit Secrets (lock icon πŸ”’) β€” never hardcode it in source files or include it in client-side JavaScript.
  • Define all custom contact fields in Autopilot Settings before using them in the API β€” fields not defined in the account are silently dropped and will cause data loss.
  • Use upsert behavior (POST /contact) rather than separate create/update logic β€” Autopilot automatically updates existing contacts and creates new ones based on email address.
  • Always include the correct type prefix (string--, integer--, boolean--, float--) on custom field names or the API will ignore the fields without returning an error.
  • Publish journeys in Autopilot before attempting to enroll contacts β€” Draft journeys return 404 errors and failed enrollments are not retried automatically.
  • Deploy your Replit app before registering webhook URLs β€” use your stable replit.app deployment URL, not the temporary development URL.
  • Implement a token parameter on your webhook endpoint URL and validate it from Replit Secrets, since Autopilot does not sign webhook payloads.
  • Use Autoscale deployment for apps that enroll contacts during peak signup times, and Reserved VM for dedicated webhook processors that require zero cold-start latency.

Alternatives

Frequently asked questions

How do I store my Autopilot API key in Replit?

Click the lock icon πŸ”’ in the left sidebar of your Replit project to open the Secrets pane. Add a new secret with key AUTOPILOT_API_KEY and paste your Autopilot API key as the value. Access it in Python with os.environ['AUTOPILOT_API_KEY'] or in Node.js with process.env.AUTOPILOT_API_KEY. Never put the key directly in your source code.

Does Replit work with Autopilot on the free tier?

Yes. The Autopilot API is accessible from any Replit project including free tier. Outbound API calls to Autopilot work without restrictions. However, you will need Replit's paid plan for always-on deployments required for reliable webhook reception, since free tier Replit projects go to sleep when inactive.

Why are my Autopilot custom fields not saving?

Custom fields must include a data type prefix in the field name: 'string--', 'integer--', 'float--', or 'boolean--'. The field must also be defined in your Autopilot account under Settings > Custom Contact Fields. Fields sent to the API that are not defined in the account are silently ignored without any error response.

Can I enroll contacts in multiple Autopilot journeys from Replit?

Yes. Make a separate POST request to /journey/{journey_id}/contact for each journey you want to enroll the contact in. Each enrollment is independent. Make sure each journey is Published (not Draft) or the enrollment will return a 404 error.

How do I connect Replit to Autopilot for real-time events?

Add a 'Notify via webhook' action in your Autopilot journey canvas, pointing to your deployed Replit server URL. The server must be deployed (not just running in development) to have a stable URL. Autopilot sends a JSON POST to your endpoint whenever a contact triggers that action in the journey.

RapidDev

Talk to an Expert

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

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation β€” no strings attached.

Book a free consultation

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.