Matchai Docs

AuthenticationComing soon

Two ways to call the Matchai API: API keys for your own account, and Connect with Matchai (OAuth 2.1) for apps. Scopes, final actions and Energy limits.

Coming soon. This is documented ahead of launch so you can plan your integration; it is not available yet.

Every request to the Matchai API acts for one Matchai account. There are two ways to get the credential that proves it, and the right one depends on whose account you are working with.

Two ways in

API keysConnect with Matchai
Use it forYour own scripts and your own AI tools, on your own accountAn app that serves other professionals: a website builder, a CRM, an AI assistant
Who grants accessYou, when you create the keyThe professional, by pressing Allow
CredentialA key that starts with matchai_An OAuth 2.1 access token, with a refresh token
ScopesChosen when you create the keyRequested by your app and shown to the professional
Set-upCreate a key in MatchaiCreate a Matchai app, then run the OAuth flow
Ended byYou revoke the keyThe professional presses Disconnect

Both go in the same header:

Request header
Authorization: Bearer matchai_…

An OAuth access token is sent the same way, in place of the key.

Why every credential reaches one account only

A key or token is bound to the account that granted it, so it can never read another professional's listings, contacts or messages. An app that serves three brokers holds three connections, each with its own tokens, however it is built. This is also why a personal key may not be used to run a service for other people: serving other professionals goes through Connect with Matchai, where each one agrees to it.

What a request can do

A request can do what the account holder can do in Matchai, under the same rules and permissions, and nothing more. Two things narrow it further:

  • Scopes limit which parts of the account the credential can touch.
  • Final actions wait for the account holder's approval, unless they allowed your app to run them.

GET /v1/me/connection (getConnection) tells your app how it is connected: the app, the scopes granted, auth_type (api_key or oauth), approval_mode (ask_me or allowed) and whether the connection is in test mode.

Scopes

Each operation in the API reference lists the scopes it needs. Ask only for what your app uses: a professional is more likely to press Allow when the list is short and every line makes sense.

ScopeWhat it allows
profile:readRead the account's profile, language, time zone and Energy state
profile:writeChange the account's profile
listings:readRead listings, their photos, rooms, documents and translations
listings:writeCreate and edit listings, their photos, rooms and translations, and delete them
listings:publishPublish and unpublish listings
sites:readRead Matchai Sites and the listings on them
sites:writeCreate, edit and publish Matchai Sites, and choose their listings
page:readRead the Matchai Page and its links
page:writeEdit and publish the Matchai Page, its links and files
contacts:readRead contacts and lead details
contacts:writeAdd, edit, convert and delete contacts, and record website enquiries
messages:readRead conversations, messages and sent emails, mark conversations read or archive them, and draft replies
messages:sendSend messages and emails, and start conversations, in the account holder's name
calendar:readRead availability and appointments
calendar:writeChange availability, book and change appointments, and record visit requests
documents:readRead Matchai Cloud documents and drop links
documents:writeUpload, file, tag, share and trash documents, and create drop links
teams:readRead teams, their members and invitations
teams:writeCreate and manage teams, and invite or remove members
projects:readRead projects, their members, teams and listings
projects:writeCreate and manage projects, and invite or remove members
notifications:readRead notifications and notification preferences
notifications:writeMark notifications as read and change notification preferences
saved_listings:readRead the listings the account saved
saved_listings:writeSave and unsave listings
analytics:readRead listing analytics, including AI activity
webhooks:manageManage webhook subscriptions and read events

When a credential lacks a scope, the call fails with 403 and the code scope_missing, and the message names the scope. For a key, create a new key that has the scope and revoke the old one. For an OAuth connection, send the professional through your app's connect flow again, so they can agree to the longer list.

A few operations need no scope because they only work with what is already public, such as looking up a professional's published profile. They are marked Free in the reference, and a key or token is optional for them.

Final actions

Four kinds of action are final: sending something to another person, publishing something to the public, paying, and deleting the account's content. The Matchai Assistant always asks before it does any of them, and the API holds your app to the same rule. Each final action is marked Final action in the reference.

The account holder chooses how your app handles them, per connection:

SettingWhat happens when your app calls a final action
Ask me (the default)The call does not run. It returns 202 Accepted and waits for the account holder to approve it in Matchai.
AllowedThe call runs straight away and returns its usual response.

Anything that is not a final action runs under the credential's scopes, as the same edit would in the app: reads, drafts, and changes to the account holder's own records. Removing your own app's configuration, such as a webhook subscription, is not a final action either.

Write your app for both settings. The account holder can change the setting at any time, so never assume which one you will get.

Follow an approval

A final action under Ask me answers 202 and does nothing yet:

Response (202)
{
  "status": "pending_approval",
  "approval_id": "1e2f3a4b-5c6d-4e7f-8a8b-9c0d1e2f3a4b",
  "approval_url": "https://matchai.co/approvals/1e2f3a4b-5c6d-4e7f-8a8b-9c0d1e2f3a4b",
  "expires_at": "2026-10-25T13:05:00Z",
  "summary": "Send a message to Julien Bouchard"
}

Tell the person. Matchai notifies the account holder, who approves or declines on a page that describes the action in plain words. Show summary in your own interface and link to approval_url, so the person can answer from where they are.

Wait for the outcome. The approval.resolved webhook arrives when the request is answered, or when it lapses. You can also poll GET /v1/approvals/{approval_id} (getApproval). Webhooks are the better choice: nobody has to guess how long a person takes.

Read the result. When the request is approved, Matchai has performed the call exactly as you sent it, and the result holds the status and body the call returned. Send the exact text the person saw. Never rewrite a draft they approved.

An approval has one of five statuses:

StatusMeaning
pendingWaiting for the account holder. Nothing has happened.
approvedApproved, and Matchai has performed the call. result holds the outcome.
declinedThe account holder said no. Nothing happened.
expiredNobody answered before expires_at. Nothing happened.
cancelledYour app withdrew the request with POST /v1/approvals/{approval_id}/cancel (cancelApproval).

GET /v1/approvals (listApprovals) lists the requests your connection has made, and takes a status filter.

Send an Idempotency-Key with every final action. If your request times out and you repeat it with the same key, you get the same pending approval back instead of a second one.

This example publishes a listing and handles both settings:

publish.mjs
import { randomUUID } from 'node:crypto';

const response = await fetch(`https://api.matchai.co/v1/listings/${listingId}/publish`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.MATCHAI_API_KEY}`,
    'Idempotency-Key': randomUUID(),
  },
});

if (response.status === 202) {
  // Ask me: nothing has happened yet.
  const pending = await response.json();
  console.log(`Waiting: ${pending.summary}`);
  console.log(`The account holder can answer at ${pending.approval_url}`);
} else if (response.ok) {
  // Allowed: the listing is published now.
  const listing = await response.json();
  console.log(`Published at ${listing.url}`);
} else {
  const { error } = await response.json();
  throw new Error(`${error.code}: ${error.message}`);
}

Energy limits

Some actions spend Matchai Energy, the way the AI features do in the app: writing a listing with AI, editing photos, translating, drafting with AI, sending an email, and messages that go out by text. The reference marks each of them, and says how heavy the action is: light, moderate, heavy, or it varies.

  • The API never shows Energy as a number. GET /v1/me returns its state: full, comfortable, low or empty.
  • A call that needs more than is left does nothing. It answers 402 with the code insufficient_energy, and nothing is spent.
  • The account holder can set an Energy limit for each connection, so a runaway script stops at a ceiling they chose. When your connection reaches it, calls that spend Energy answer 402 with the code energy_limit_reached, and GET /v1/me/connection reports energy_limit_reached: true.

Show the message of a 402 to the person: it says what happened and what to do next. See errors.

Ending a connection

A connection ends in one of three ways, and each one stops every credential that belongs to it:

  • The professional presses Disconnect on the Connectors page.
  • You revoke an API key.
  • Your app calls DELETE /v1/me/connection (disconnect). It ends the connection as if the professional had pressed Disconnect, and deletes nothing in the account.

After a connection ends, its webhook subscriptions are turned off and its requests answer 401. Treat that as "connect again", not as an outage.

Test mode

An app that is connected only to its own developer's account is in test mode. Test connections are not billed, and the events they produce carry test_mode: true. Create a Matchai app explains how it works, and who pays once other professionals connect.

On this page