To integrate Autopilot (now Ortto) with Lovable, create a Supabase Edge Function that proxies requests to the Autopilot/Ortto API using your API key stored in Cloud Secrets. The Edge Function syncs contacts, logs custom activities, and triggers journey entries. Your Lovable app events — signups, feature uses, purchases — flow into Ortto to power automated customer journeys.
Power Ortto Customer Journeys with Real-Time Lovable App Data
Ortto (formerly Autopilot) positions itself as a mid-market alternative to Marketo and HubSpot — easier to use than Marketo, more automation-focused than HubSpot. Its visual journey builder lets marketers map out multi-channel customer sequences using a drag-and-drop canvas, triggering emails, SMS, in-app messages, and sales tasks based on contact behavior. The challenge is that many Ortto journeys are only as good as the data flowing into them — and for SaaS or app businesses, the richest behavioral data lives in the application itself.
Connecting your Lovable app to Ortto via a Supabase Edge Function solves this by streaming app events directly into Ortto's contact and activity model. When a user signs up, their profile syncs immediately. When they upgrade to a paid plan, that event triggers a different nurture sequence. When they stop logging in, a churn-prevention journey activates. These are the kinds of event-driven journeys that drive real business outcomes but are impossible to build in Ortto without reliable application data.
Ortto's API is straightforward: contacts are upserted via a single endpoint with merge fields for email, name, and custom attributes. Custom activities can be created with any schema and logged against contacts by email. Journey triggers can be invoked via API for contacts who meet entry conditions. All these operations require only an API key in the Authorization header, making the Edge Function proxy pattern clean and minimal.
Integration method
Ortto (formerly Autopilot) uses a REST API with API key authentication. A Supabase Edge Function stores your Ortto API key in Cloud Secrets, accepts event data from your Lovable frontend, and forwards contact upserts and custom activity events to the Ortto API. This enables customer journeys to be triggered by real-time app behavior.
Prerequisites
- A Lovable project with Lovable Cloud enabled and Supabase Auth configured
- An Ortto account (formerly Autopilot) at ortto.com
- Your Ortto API key from Ortto Settings → API
- Basic familiarity with Ortto's Contact and Activity model (read Ortto's API docs at help.ortto.com/developer)
Step-by-step guide
Get your Ortto API key
Get your Ortto API key
Log in to your Ortto account at ortto.com and navigate to Settings (gear icon in the top right). In the Settings menu, look for the API section or Integrations → API. Your API key is displayed on this page as a long string. If you have not yet generated an API key, click Generate New Key. Ortto may show multiple API keys if you have created more than one — use the one labeled for your primary workspace. The API key is passed in the Authorization header as 'Bearer {api-key}' for all Ortto API requests. Ortto's API base URL is https://api.ap3api.com for the Autopilot (legacy) endpoints or https://api.ortto.com for newer Ortto API endpoints. Check your account's documentation section to confirm which base URL applies to your account — older Autopilot accounts may use the legacy URLs. Copy your API key and do not share it publicly.
Pro tip: If your Ortto account was previously an Autopilot account, check whether you need to use the legacy Autopilot API endpoints (https://api2.autopilothq.com) or the newer Ortto endpoints (https://api.ortto.com). The account migration status determines which API URL applies.
Expected result: You have your Ortto API key ready to store in Cloud Secrets.
Store the API key in Cloud Secrets
Store the API key in Cloud Secrets
In your Lovable project, click the plus (+) icon next to the preview panel to open the side panels. Click the Cloud tab and scroll to the Secrets section. Click Add Secret. In the Name field, enter ORTTO_API_KEY. Paste your Ortto API key into the Value field. Click Save. The key is now encrypted and only accessible from Edge Functions. Lovable's security system actively prevents API keys from being hardcoded into frontend code — approximately 1,200 keys are blocked daily from being committed to application code — and using Cloud Secrets is the correct pattern. Never paste your Ortto API key into Lovable's chat interface, as on the free plan chat history is publicly accessible.
Pro tip: If your Ortto account uses a specific API region (some enterprise accounts have region-specific endpoints), also store ORTTO_API_BASE_URL as a secret so your Edge Function does not hardcode the URL.
Expected result: ORTTO_API_KEY appears in the Cloud Secrets panel with its value masked.
Create the Ortto proxy Edge Function
Create the Ortto proxy Edge Function
Create the Edge Function that proxies contact and activity operations to Ortto. The function accepts POST requests with a JSON body specifying the operation type (upsert_contact, log_activity), the contact email, and relevant data fields. For contact upserts, it calls Ortto's person/merge endpoint. For activity logging, it calls the activity endpoint. Include proper error handling for Ortto API errors and CORS headers for browser requests. The function uses the Ortto API key from Cloud Secrets in the Authorization header for all calls. Ortto's person merge endpoint accepts fields like email, first_name, last_name, and any custom fields defined in your Ortto account. Custom activities require an activity type name (which must be created in Ortto's activity catalog first) and can include arbitrary key-value attributes.
Create a Supabase Edge Function at supabase/functions/ortto-proxy/index.ts that accepts POST requests. Based on an 'operation' field in the body, either: (1) upsert a contact to Ortto with fields email, first_name, last_name, and any custom_fields, or (2) log a custom activity with activity_name and activity_attributes against a contact email. Use the ORTTO_API_KEY secret in the Authorization header. Return Ortto's response with CORS headers.
Paste this in Lovable chat
1import { serve } from 'https://deno.land/std@0.168.0/http/server.ts'23const corsHeaders = {4 'Access-Control-Allow-Origin': '*',5 'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',6}78const ORTTO_BASE = 'https://api.ap3api.com'910serve(async (req) => {11 if (req.method === 'OPTIONS') return new Response('ok', { headers: corsHeaders })1213 try {14 const apiKey = Deno.env.get('ORTTO_API_KEY')15 if (!apiKey) throw new Error('ORTTO_API_KEY not configured')1617 const { operation, email, first_name, last_name, custom_fields, activity_name, activity_attributes } = await req.json()1819 let orttoUrl: string20 let orttoBody: any2122 if (operation === 'upsert_contact') {23 orttoUrl = `${ORTTO_BASE}/v1/person/merge`24 orttoBody = {25 people: [{26 fields: {27 'str::email': email,28 'str::first': first_name || '',29 'str::last': last_name || '',30 ...(custom_fields || {}),31 },32 async: false,33 }],34 merge_by: ['str::email'],35 merge_strategy: 1,36 find_strategy: 0,37 }38 } else if (operation === 'log_activity') {39 orttoUrl = `${ORTTO_BASE}/v1/activities/create`40 orttoBody = {41 activities: [{42 activity_id: `act:cm:${activity_name.toLowerCase().replace(/\s+/g, '-')}`,43 attributes: {44 'str::email': email,45 ...(activity_attributes || {}),46 },47 }],48 }49 } else {50 return new Response(51 JSON.stringify({ error: 'Unknown operation. Use upsert_contact or log_activity.' }),52 { status: 400, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }53 )54 }5556 const response = await fetch(orttoUrl, {57 method: 'POST',58 headers: {59 'Authorization': `Bearer ${apiKey}`,60 'Content-Type': 'application/json',61 },62 body: JSON.stringify(orttoBody),63 })6465 const data = await response.json()66 return new Response(JSON.stringify(data),67 { headers: { ...corsHeaders, 'Content-Type': 'application/json' } })68 } catch (error) {69 return new Response(JSON.stringify({ error: error.message }),70 { status: 500, headers: { ...corsHeaders, 'Content-Type': 'application/json' } })71 }72})Pro tip: Ortto field names use a naming convention like 'str::email', 'str::first', 'str::last' for built-in fields. Custom fields use formats like 'str::custom-field-name'. Check your Ortto account's field catalog for exact field identifiers.
Expected result: The ortto-proxy Edge Function is deployed. Test upsert_contact by sending a POST with operation='upsert_contact' and an email. The contact should appear in your Ortto contact database.
Integrate contact sync into your app's user lifecycle
Integrate contact sync into your app's user lifecycle
With the Edge Function deployed, wire it into key user lifecycle events in your Lovable app. The three most important events to capture are: signup (call upsert_contact when a user registers), key feature activation (call log_activity when a user first uses an important feature), and plan change (call upsert_contact with updated plan attributes when a user upgrades or downgrades). For each of these, call the ortto-proxy Edge Function using Supabase's functions.invoke() method with the appropriate operation and data. These calls should be fire-and-forget — do not await them in user-facing code paths so they do not slow down the user experience. Add them in a useEffect or event handler that runs asynchronously after the primary action completes successfully.
In our app's signup flow, after Supabase Auth creates the user, fire-and-forget call our ortto-proxy Edge Function with operation='upsert_contact' and the user's email, first name, last name. Also log a 'signup' activity immediately after. Do not await the call in a way that blocks the user's navigation to the dashboard.
Paste this in Lovable chat
1import { supabase } from '@/integrations/supabase/client'23export const syncToOrtto = (operation: string, data: Record<string, any>) => {4 // Fire-and-forget — never awaited in user-facing code5 supabase.functions.invoke('ortto-proxy', { body: { operation, ...data } })6 .then(({ error }) => { if (error) console.warn('Ortto sync failed:', error) })7 .catch(e => console.warn('Ortto sync error:', e))8}910// Usage in signup handler:11// syncToOrtto('upsert_contact', { email, first_name, last_name })12// syncToOrtto('log_activity', { email, activity_name: 'App Signup', activity_attributes: { plan: 'free' } })Pro tip: Create a simple ortto.ts utility module (like above) so any component or hook in your app can log an Ortto activity with a single function call, without repeating the Edge Function invocation boilerplate.
Expected result: User signups and key app events are appearing in Ortto as contacts and activities in near real-time. You can verify by searching for test email addresses in Ortto's People section.
Common use cases
Onboarding journey triggered by app signup
When a new user registers in your Lovable app, sync their contact to Ortto and trigger an onboarding email journey. The journey sends setup tips, checks in after 3 days if they haven't completed key actions, and escalates to a sales touch for high-value accounts.
After a user signs up in our Lovable app, call our ortto-proxy Edge Function to create or update their Ortto contact with email, first name, last name, and signup date. Then log a custom activity 'App Signup' against their contact. Show no UI indication to the user that this is happening.
Copy this prompt to try it in Lovable
Feature adoption tracking for lifecycle campaigns
Log a custom Ortto activity every time a user uses a key feature for the first time. These activities feed into journey conditions like 'Has activated Feature X within 7 days of signup', enabling targeted campaigns that guide users toward the features most correlated with retention.
Create a hook in our Lovable app that logs a custom Ortto activity whenever a user first uses any of our three key features (export, share, integrate). Call our ortto-proxy Edge Function with activity type 'Feature Activated', the feature name as an activity attribute, and the user's email. Only log the activity once per feature per user.
Copy this prompt to try it in Lovable
Churn prevention journey based on inactivity
Build a scheduled check that identifies users who have not logged in for 14 days and sends their emails to Ortto with an 'Inactive User' activity. This triggers a win-back journey with re-engagement content and a discount offer.
Create a Supabase scheduled Edge Function that runs daily and finds users who haven't logged in for 14 days. For each inactive user, call our ortto-proxy Edge Function to log an 'Account Inactive' activity in Ortto. Use this to trigger a win-back journey in Ortto that sends re-engagement emails.
Copy this prompt to try it in Lovable
Troubleshooting
Ortto API returns 401 Unauthorized from the Edge Function
Cause: The ORTTO_API_KEY secret is missing, incorrectly named, or the key has been revoked in Ortto settings.
Solution: Open Cloud → Secrets and verify the secret is named exactly ORTTO_API_KEY with no extra characters. Re-copy the API key from Ortto Settings → API and update the secret value. Also check that you are using the correct authorization format: 'Bearer {api_key}' not just the raw key.
1// Verify auth header format2headers: {3 'Authorization': `Bearer ${apiKey}`, // Must include 'Bearer '4 'Content-Type': 'application/json',5}Contact upsert returns 200 but the contact does not appear in Ortto
Cause: The field name format for email or other fields does not match Ortto's expected field identifiers, so the contact is created with no identifiable email.
Solution: Verify field names against your Ortto account's field catalog. The standard email field is 'str::email' — if your account uses a different field identifier for email, the contact will be created but without an email address and will not be findable by email lookup. Check Ortto Settings → Data → Fields for the exact identifiers.
Activity logging returns an error about unknown activity type
Cause: Custom activities in Ortto must be created in the activity catalog before they can be logged via the API. Activities do not auto-create from API calls.
Solution: In Ortto, go to Settings → Activities and create the custom activity type with the name and attributes you plan to log. The activity_id in your API call must match the identifier generated by Ortto for this activity type. Check the activity catalog for the correct ID format.
The ortto-proxy Edge Function works in testing but activities are not triggering journeys in Ortto
Cause: The Ortto journey may require the activity to be logged against a contact that already exists, or the journey entry trigger may have additional conditions that are not being met.
Solution: In Ortto's journey builder, check the entry trigger conditions — the contact must exist before the activity is logged for the journey to trigger. Ensure the upsert_contact call happens before (or simultaneously with) the first activity log. Also check that the journey is published and active, not in draft mode.
Best practices
- Always call upsert_contact before log_activity for new users — Ortto needs the contact to exist before activities can be logged and journeys triggered
- Use fire-and-forget pattern for all Ortto API calls from user-facing flows — never block the UI waiting for Ortto to respond
- Create a centralized ortto.ts utility module in your Lovable app so all components can log activities with a single consistent function call
- Map your Lovable app's key user actions to Ortto custom activities thoughtfully — activities should represent meaningful moments in the user journey, not every click
- Use custom contact fields in Ortto to store app-specific attributes like plan type, signup source, and feature adoption status for better journey personalization
- Create all custom activity types in Ortto's activity catalog before attempting to log them via API — activities do not auto-create from API calls
- Test your journey triggers with real email addresses before launch — Ortto's journey preview mode shows which contacts would enter the journey based on current conditions
- Keep your Ortto API key rotated periodically and update the Cloud Secret immediately when rotating
Alternatives
Marketo is Adobe's enterprise platform with more complex lead scoring and revenue attribution, while Ortto/Autopilot is a mid-market tool with a more intuitive visual journey builder and simpler setup.
Klaviyo is focused on e-commerce email and SMS marketing with deep Shopify integration, while Ortto/Autopilot is broader across SaaS and B2B use cases with multi-channel journey automation.
ConvertKit is a creator-focused email platform with simpler automation, while Ortto/Autopilot offers more sophisticated multi-channel journey logic suitable for SaaS customer lifecycle management.
Frequently asked questions
Is Autopilot the same as Ortto?
Yes. Autopilot rebranded to Ortto in 2022. The product is the same journey automation platform, but the interface, API endpoints, and documentation have been updated under the Ortto brand. Some older Autopilot API endpoints (api2.autopilothq.com) still work, but new integrations should use the Ortto API endpoints. If your account predates the rebrand, check Ortto's migration documentation for your specific API URL.
Does Ortto have a free plan?
Ortto offers a free trial but does not have a permanent free tier. Paid plans start at approximately $99/month for the Starter plan. API access is available on all paid plans. The pricing is contact-based, so costs increase as your contact database grows.
How do I create custom activity types in Ortto before logging them via API?
In Ortto, navigate to Settings → Activities (or Data → Activities). Click Add Activity and define the activity name and any custom attributes you want to track (e.g., 'plan_name' as a string attribute for a 'Plan Upgraded' activity). Ortto generates an activity_id for each activity type — use this ID in your API calls. Activities must be created manually; they cannot be auto-created from API calls.
Can I use Ortto journeys to send transactional emails from my Lovable app?
Ortto is designed for marketing automation rather than transactional emails (like order confirmations or password resets). For transactional emails, use Resend or Lovable's built-in email capabilities via Supabase Edge Functions. Ortto journeys work best for lifecycle sequences: onboarding, re-engagement, upsell, and retention campaigns triggered by behavioral events.
What is the rate limit for the Ortto API?
Ortto's API rate limits depend on your plan but are generally generous for typical SaaS use cases — hundreds of requests per minute. For high-volume event tracking (like logging an activity for every page view), consider batching activities or using a queue pattern where events are collected in a Supabase table and flushed to Ortto in batches every few minutes.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation