Partner apps and OAuth

For software companies that connect to many pros. A pro connecting their own tools uses an API key instead.

Access levels

SandboxVerified
WhenAs soon as you create the appAfter we check your company
Can connectYour own pro account and test accountsAny pro who taps Allow
Rate limit600 requests an hour per pro3,000 an hour per pro
ScopesAllAll

To get verified, open your app at /partners and tap Ask for verification. We check your company and website, your privacy policy, your contact, and what you said the app does with pros' data. We can suspend an app at any time; suspending stops every token at once.

1. Create the app

At /partners: name, company, website, privacy policy, contact email, what the app does, redirect addresses (https; http only for localhost) and scopes. You get a client ID (lmc_...) and a client secret (lms_..., shown once; you can make a new one).

2. Send the pro to Connect

https://lead-marketplace.mcrdminted.workers.dev/connect
  ?response_type=code
  &client_id=lmc_...
  &redirect_uri=https://your-app.example.com/oauth/callback
  &scope=leads:read leads:write messages:read messages:write
  &state=<random value you check later>
  &code_challenge=<BASE64URL(SHA256(code_verifier))>
  &code_challenge_method=S256

(URL-encode the values. The address moves to the brand domain at launch.) The pro signs in, sees your app, your company, verified or sandbox, and each thing you ask for in plain words, then taps Allow or Cancel. Leave out scope to ask for every scope your app has. PKCE with S256 is required.

We send the pro back to redirect_uri?code=lma_...&state=..., or ?error=access_denied&state=.... Check state. An unknown app or an unregistered redirect_uri is shown as an error on our page and never redirected.

3. Swap the code for tokens

POST https://zqawbbylldymdfzineqq.supabase.co/functions/v1/pro-api/oauth/token
Content-Type: application/x-www-form-urlencoded
Authorization: Basic base64(client_id:client_secret)

grant_type=authorization_code&code=lma_...&redirect_uri=https://your-app.example.com/oauth/callback&code_verifier=...

(client_id and client_secret may go in the body instead of Basic.)

{"access_token":"lmo_...","token_type":"Bearer","expires_in":3600,"refresh_token":"lmr_...","scope":"leads:read leads:write messages:read messages:write","business_id":"0d3b7c4e-..."}

Codes last 10 minutes and work once. Using a code twice fails and revokes the tokens issued from it. Store tokens per business_id.

4. Call the API

Authorization: Bearer lmo_... on any endpoint, limited to the granted scopes.

5. Refresh

grant_type=refresh_token&refresh_token=lmr_...

Returns a new access token and a new refresh token; the old refresh token stops working. Refresh tokens last 180 days from issue.

Revoke

POST /oauth/revoke     token=<access or refresh token>     (client authentication as above)

A pro can also disconnect your app in Settings, Connect your software, Connected apps; your tokens stop at once and calls return 401.

Your app's webhook

Set one webhook address on your app at /partners. You get events for every pro who connected your app, each with business_id, only for what that pro allowed (for example message.* needs messages:read, charge.* and credit.* need billing:read). Signed with your app's own secret, same format as pro webhooks. After about 3 days of failures it turns off and we email your contact address.

Errors

Token errors follow OAuth 2.0: invalid_client (401), invalid_grant, unauthorized_client, access_denied, unsupported_grant_type (400), with error_description where useful.