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.
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 keys | Connect with Matchai | |
|---|---|---|
| Use it for | Your own scripts and your own AI tools, on your own account | An app that serves other professionals: a website builder, a CRM, an AI assistant |
| Who grants access | You, when you create the key | The professional, by pressing Allow |
| Credential | A key that starts with matchai_ | An OAuth 2.1 access token, with a refresh token |
| Scopes | Chosen when you create the key | Requested by your app and shown to the professional |
| Set-up | Create a key in Matchai | Create a Matchai app, then run the OAuth flow |
| Ended by | You revoke the key | The professional presses Disconnect |
Both go in the same header:
Authorization: Bearer matchai_…An OAuth access token is sent the same way, in place of the key.
API keys
Create, scope, rotate and revoke a key for your own account.
Create a Matchai app
Register the app that professionals will connect to.
Connect with Matchai
The OAuth 2.1 flow, the Allow page and a full code example.
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.
| Scope | What it allows |
|---|---|
profile:read | Read the account's profile, language, time zone and Energy state |
profile:write | Change the account's profile |
listings:read | Read listings, their photos, rooms, documents and translations |
listings:write | Create and edit listings, their photos, rooms and translations, and delete them |
listings:publish | Publish and unpublish listings |
sites:read | Read Matchai Sites and the listings on them |
sites:write | Create, edit and publish Matchai Sites, and choose their listings |
page:read | Read the Matchai Page and its links |
page:write | Edit and publish the Matchai Page, its links and files |
contacts:read | Read contacts and lead details |
contacts:write | Add, edit, convert and delete contacts, and record website enquiries |
messages:read | Read conversations, messages and sent emails, mark conversations read or archive them, and draft replies |
messages:send | Send messages and emails, and start conversations, in the account holder's name |
calendar:read | Read availability and appointments |
calendar:write | Change availability, book and change appointments, and record visit requests |
documents:read | Read Matchai Cloud documents and drop links |
documents:write | Upload, file, tag, share and trash documents, and create drop links |
teams:read | Read teams, their members and invitations |
teams:write | Create and manage teams, and invite or remove members |
projects:read | Read projects, their members, teams and listings |
projects:write | Create and manage projects, and invite or remove members |
notifications:read | Read notifications and notification preferences |
notifications:write | Mark notifications as read and change notification preferences |
saved_listings:read | Read the listings the account saved |
saved_listings:write | Save and unsave listings |
analytics:read | Read listing analytics, including AI activity |
webhooks:manage | Manage 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:
| Setting | What 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. |
| Allowed | The 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:
{
"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:
| Status | Meaning |
|---|---|
pending | Waiting for the account holder. Nothing has happened. |
approved | Approved, and Matchai has performed the call. result holds the outcome. |
declined | The account holder said no. Nothing happened. |
expired | Nobody answered before expires_at. Nothing happened. |
cancelled | Your 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:
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/mereturns its state:full,comfortable,loworempty. - A call that needs more than is left does nothing. It answers
402with the codeinsufficient_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
402with the codeenergy_limit_reached, andGET /v1/me/connectionreportsenergy_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.