Build an integration with Lovelio Connect
Lovelio Connect is the self-serve developer platform. You register, create an integration, get a sandbox agency with a working API key, build and test against the real API, and submit for review without an onboarding call.
Building one integration for one agency - your own, or a client of yours? You do not need any of this. Ask them for an API key from Settings > API keys in their Lovelio account and call the V1 API directly with it. Connect is the route when you want other agencies to discover your app in the public directory and connect through Settings > Connected apps: that is what the OAuth client, the certification run and the review are for.
1. Register
Go to lovelio.ai/developers/portal and sign in with your work email. We email you a six-digit code; entering it proves you own a mailbox on your company's domain. The first person from your company founds the workspace and names it - teammates verify their email and wait for owner approval. Removed members need the owner to restore access. Free email providers are not accepted.
2. Tell Lovelio about your app
Click New integration. One form: your app's name, its website, one sentence on what it does, whether it writes anything back into Lovelio, and whether it shows or calculates money. Lovelio does the rest: it works out the access your sentence needs, drafts your listing, mints your client ID and secret, registers a placeholder callback, and creates your sandbox. From then on your integration's page is a log of what you did and what Lovelio did, with the one thing to do next in a box at the bottom. When the sandbox finishes you have:
- A complete Lovelio agency seeded with realistic data: 5 clients, 6 jobs, 18 candidates with full CVs, a pipeline across the agency stages, interviews, submissions and placements.
- One API key with full scopes, shown exactly once. Copy it immediately.
The key is 48 characters, starting sk_test_. After you close that box the portal shows the first 20 characters with the rest masked out: an identifier for the key, never the key itself. The portal never shows a saved key again. Lovelio keeps a protected copy for certification and recovery. If you lose it, Replace API key issues a new key, revokes the old key and keeps all your sandbox data.
The sandbox is a real Lovelio tenant. Every endpoint, webhook, permission check and rate limit behaves exactly as it will for a paying agency. Two guardrails are permanent: a sandbox can never email a real person, and it never appears in the marketplace.
# Use the Base URL from the Sandbox panel of the portal.
export LOVELIO_API_URL="https://us.lovelio.ai/api/v1"
curl "$LOVELIO_API_URL/jobs?limit=1" \
-H "Authorization: Bearer sk_test_..."
Your sandbox does not expire. Reset sandbox wipes it and provisions a fresh agency with a new key whenever you want a clean slate.
3. Build
Everything you need is public:
- API reference: /docs/api.md - every endpoint with its parameters, request body and responses, as plain markdown in one fetch. Narrow it with
?tag=Jobs, or get the endpoint list alone with?index=1. /docs/api is the same content rendered for humans; it draws in the browser, so fetch the.mdif you are not running JavaScript. - Error handling: /docs/agents/error-handling - the envelope, request IDs, retries, idempotency keys, rate-limit headers.
- Webhooks: /docs/agents/webhooks - subscribe with
POST /v1/webhooks, verify the HMAC-SHA256 signature, and read the event catalogue atGET /v1/webhooks/events. - Reference checks: /docs/agents/reference-checks - one end-to-end recipe from interview outcome and referee contacts to a completed report and candidate timeline activity.
- SDKs: /docs/agents/sdks - single-file TypeScript and Python clients.
- AI agents: point any MCP client at the Lovelio MCP server (/docs/mcp) using MCP OAuth consent. Open your sandbox first to approve the requested access as its admin. REST keys do not authenticate MCP directly.
Your integration's page is five steps on one page: Sign in, Get a sandbox, Write your listing, Request approval, Go live. Each shows a one-word status and the one that needs you is outlined. The page refreshes every 10 seconds while the tab is visible, and again when you return to the tab. Under the steps sit four panels: Keys and callback, Access, Sandbox and Usage. The Sandbox panel shows webhook activity for your sandbox: every subscription, every delivery, response codes and retries. Create a subscription, trigger an event (move a candidate's stage, create a job), and watch it arrive.
Browser apps and credential storage
Your browser app calls your own backend. That backend exchanges OAuth codes, stores each agency's tokens securely, and calls Lovelio. Keep keys, client secrets and refresh tokens out of JavaScript bundles, public environment variables, local storage, URLs, logs and source control. Public CORS access is not part of this architecture.
The client ID is public. Client secrets and API keys appear once when issued. Lovelio hashes normal API keys and client secrets for validation. It also stores encrypted sandbox keys for certification and recovery, and an encrypted internal credential for MCP. Save your own backend credentials in a secret manager or private server environment.
Documentation, the OpenAPI document and OAuth discovery metadata are public and readable without signing in or running JavaScript. The event catalogue is an authenticated REST endpoint requiring webhooks:read. Public documentation access does not grant access to agency data or the developer workspace. The public directory explains approved apps; agencies start connections from Settings > Connected apps inside Lovelio.
4. Let agencies connect your app
Lovelio has two developer credentials and they do different jobs. Never swap one for the other:
| Credential | What it is | What it opens |
|---|---|---|
API key (sk_test_...) | A Bearer token, minted with your sandbox | Your own sandbox agency, and nothing else |
Client ID + client secret (lc_client_..., lc_secret_...) | An OAuth 2.0 confidential client, created in the portal | Any agency that connects to your app, at the scopes they granted |
Writing a test script against your own sandbox? The API key is all you need - one header, no OAuth. Shipping to real agencies? Your app uses the OAuth client instead: an API key belongs to one tenant and can never be issued to anyone else. Lovelio minted your client the moment you created the integration, so there is no button to find; the Keys and callback panel holds it.
Your app ships against the connect flow, not against pasted API keys. In the Keys and callback panel you have:
- A client ID (
lc_client_...) you can publish. - A client secret (
lc_secret_...), shown exactly once when the integration was created, inside a ready-made.envblock with your other three values. Keep it server-side. Rotate it from the portal if it ever leaks; the old secret stops working the moment the new one appears.
The same panel holds the two ends of the round trip, together because they are the same kind of thing - a route on your own server, not a page anyone looks at:
- Your connect endpoint. Where Lovelio hands off when a signed-in agency starts a connection. It redirects them straight to the Lovelio approve screen, carrying your own state and PKCE challenge, which is why Lovelio cannot build that URL for you. The agency sees your product's name on the approve screen and nothing of your website.
- Your redirect URIs (HTTPS, or HTTP on localhost, 127.0.0.1 or [::1] while building). Register the exact URI your code sends, including the path, port and trailing slash. Where Lovelio sends the approved connection so your server can pick up its tokens.
/api/oauth/authorizerefuses anyredirect_urithat is not registered here. Send the agency back into Lovelio when you are done, and the whole thing reads as two clicks inside the app they were already in. Lovelio registered a placeholder callback at creation so the setup prompt has a real shape to work from; replace it with yours. A localhost URI is fine while building; step 2 reminds you it is registered so you add the real one before agencies connect.
The checks fetch both, skip a localhost one, and fail on a dead one, so a typo costs you a red run rather than a failed connection in front of a real agency.
You do not tick scopes off a list. The form you filled in at creation took one sentence on what your product does, then asked whether it writes anything back into Lovelio and whether it shows or calculates money. Lovelio worked out the smallest access set that supports that answer and switched it on. Saying it only reads bars every write outright. The Access panel shows what you have in plain English - "Placements: read" - with the technical scope names one disclosure away, and only the areas your integration uses; everything else is behind Ask for something else.
Take access away for free. Adding something your sentence did not call for costs a written reason, which the reviewer and every connecting agency both read. Nothing locks while your submission is in review: edit what you like and Lovelio looks again before deciding. Widening access after approval forces re-review (see below).
You do not have to write this flow yourself, or even read it. Step 2 of your integration's page leads with Copy setup prompt: one self-contained prompt, with your real client ID, callback and region in it, that an AI coding tool turns into both routes in your own stack. The prompt never carries your client secret - you paste that into your env file yourself. Not using an agent? /docs/connect-flow prints the same flow as plain code: a connect route and a callback route, in Node, Python, PHP, Go and cURL, with placeholders where your own values go. The four environment values the code reads (LOVELIO_API_URL, LOVELIO_CLIENT_ID, LOVELIO_CLIENT_SECRET, LOVELIO_REDIRECT_URI) are printed as one block at the moment the secret is issued, which is the only moment the secret exists in a browser; the Keys and callback panel prints the block again with the secret left for you to fill in.
The flow is standard OAuth 2.0 authorization code with PKCE (S256 only, a plain or absent challenge is refused), plus your client secret at the token endpoint:
- Your connect route makes a random
code_verifier, stores it against that browser, and redirects the agency admin to/api/oauth/authorizeon the agency's region domain (us, eu or anz.lovelio.ai) withresponse_type=code,client_id,redirect_uri,scope,state,code_challenge(base64url SHA-256 of the verifier) andcode_challenge_method=S256. - They sign in if needed, see "Your app wants access to their agency" with the scope list, and approve. Connecting takes an admin - other roles are asked to pass the link on.
- Your redirect URI receives
?code=...&state=.... Check the state, then exchange the code atPOST /api/oauth/tokenwithgrant_type=authorization_code, yourclient_id,client_secret, thecode_verifieryou stored, and the sameredirect_uri. The verifier is what proves the code came back to the server that started the connection, so a stolen code on its own is worth nothing. - You get an access token (
lc_at_..., one hour) and a refresh token (lc_rt_...). Call the V1 API withAuthorization: Bearer lc_at_...- the token carries exactly the scopes the agency granted, enforced on every request. Readscopeon the response rather than assuming: a granted set can be narrower than the one you asked for. Refresh withgrant_type=refresh_tokenplus your client credentials; refresh tokens rotate on every use and the window slides while the integration stays active.
The same endpoints, parameters and scopes are declared in the OpenAPI spec at /docs/api under the appOAuth2 security scheme, so a generated client can drive the connection without reading this page.
Webhook subscriptions your app creates with its token belong to the connection: the agency sees them under Settings > Connected apps, and disconnecting disables them and revokes every token immediately.
Test the whole flow before review: the consent screen works against your own sandbox from day one, no approval needed. Click Open sandbox in the portal to hand off into the sandbox agency, then open your authorize URL in the same browser and approve. The consent screen labels that agency as a sandbox; your developer portal session stays separate. Once the app is approved, any Lovelio agency can connect to it.
5. The checks run themselves
The platform diagnostics are information for you and for the reviewer, never a gate. There is no button. Once Lovelio has seen your code do the connect flow against your sandbox, the checks start on their own and step 2 shows the report under "Lovelio's own checks". Step 2 also counts what Lovelio has seen your code do against the sandbox ("Lovelio has seen 2 of 4 things your code needs to do"). "Seen" is the happy path only: consent completes and your server exchanges the code, then one API call works with the token (plus one write landing if you hold a write scope, and one signed webhook answered with a 2xx if you hold webhooks:write). You are never asked to fail on purpose. If your code asks /api/oauth/authorize for a scope the app does not have, the redirect back to your callback carries error=invalid_scope and an error_description naming the missing scopes, and the same line appears in step 2 with a button to Access.
What it checks:
- Auth: requests without a key and with a made-up key are refused; your sandbox key works.
- Error handling: errors carry the standard envelope (code, message, request ID) and writes demand an
Idempotency-Key. - Pagination: cursor pagination pages cleanly with no repeated rows.
- Webhook signing: it creates a subscription, fires the signed test ping, and verifies the HMAC-SHA256 signature end to end, then removes the subscription.
- Your public links: the connect endpoint and every redirect URI are fetched. A
404or a domain that does not resolve fails the run. A401,403or redirect passes because a sign-in wall on your connect endpoint is normal. Localhost and loopback callbacks are skipped, not failed. - Lovelio's connection path: your OAuth client exists and requests scopes, the token endpoint refuses a wrong client secret, Lovelio exercises its own sandbox connection path, a granted scope works and an ungranted one is refused, then temporary state is cleaned up.
A red run tells you exactly which platform diagnostic failed and why. Fix it and click Run checks again in step 2. A green run goes stale if you reset the sandbox, rotate the secret, change the scope set, or change either of your two links afterwards, because what was proven is no longer what would ship. The checks run again on their own after any of those.
A green platform result does not prove your partner callback or webhook handler; only Lovelio seeing your code do it in the sandbox does. Approval is a person's decision: the reviewer reads the diagnostics, the sandbox lines and your listing side by side, and nothing Lovelio saw switches Approve off on its own. If something is missing, you get a note asking for changes.
6. Request approval
Request approval in step 4 needs exactly two things: a name and one sentence an agency owner would understand. Lovelio drafted both from your form; read them in step 3 and edit if you like. Everything else can come later, including while the app is in review, because an edit during review is logged and the reviewer looks again. Step 3 holds the description, category, support link and privacy policy link, an "About your app" write-up (a few paragraphs: what it does, who it is for, why use it) and up to 3 screenshots or short videos - once approved, they make up your app's own page at lovelio.ai/integrations/your-slug. Lovelio never invents links: a support or privacy link it did not have stays blank for you to fill in. Your connect address is not asked for here - it lives in Keys and callback. The checks report and what Lovelio saw in your sandbox ride along to the reviewer as information.
We review by hand and reply by email:
- Approved - your integration goes live in the Lovelio integrations directory straight away.
- Changes requested - the note sits on step 4 and on the app list. Fix it and send it again.
- Rejected - the note says why.
7. After approval
A few rules keep the directory honest without slowing you down:
- Listing text publishes without re-review. Name, description, the About write-up, category, tagline, support and privacy links stay editable in the portal while the app is approved, and the public directory picks up a save straight away. Changing connection URLs or rotating the client secret sends the app back for review. Screenshots and videos are also reviewed: on an approved app they wait for a quick Lovelio review before going live, and your page keeps the current media until then.
- Adding scopes forces re-review; removing them is free. The scope set is what review approved, so asking for MORE takes the app off the directory and back to draft - request approval again to relist. Narrowing the set never costs review: the app stays approved and listed. Agencies that already connected keep the scopes they granted either way; only new connections wait for a re-approval. The API asks for
confirm_re_review: trueon a widening so it never happens by accident. - New apps start in a limited rollout. Approval sets a cap on active connections, sized by how much access the app requests (read-only apps get a high cap, apps touching email content, documents or marketplace writes a low one). Past the cap, an agency trying to connect sees an "app at capacity" page instead of the consent screen. When you are close, email hello@lovelio.ai and we raise or remove it - your approval email states your starting cap.
- Usage is visible in the portal. The Usage panel on your integration shows active connections against the cap, plus the last 30 days of API calls and webhook deliveries across every region your app lives in, sandbox included.
- Lovelio can suspend an app. If an integration misbehaves, suspension takes it off the directory and stops its credentials and webhooks everywhere at once - existing connections stop working until it is resolved. Unsuspending restores the connections exactly as they were.
Questions
Email hello@lovelio.ai. If your integration needs something the API does not cover yet, say so in the submission description - API gaps reported by partners get prioritised.