How to Use the Help Scout API (2026): OAuth2, Endpoints, Limits and Examples
The Help Scout API authenticates with OAuth2: you exchange an app's client ID and secret for a two-day Bearer token and call https://api.helpscout.net/v2/, with no API access on the Free plan. Below are the token flows, the endpoints you'll use, HAL pagination, plan rate limits, signed webhooks, and working curl, Python and Node examples.
Key takeaways
- The Help Scout API uses OAuth2 instead of a static API key, exchanging an app's client ID and secret for a Bearer token at https://api.helpscout.net/v2/oauth2/token.
- A Help Scout access token lasts 172,800 seconds, two days, and an expired token shows up as HTTP 401 until the integration requests a new one.
- Help Scout's API rate limit is shared per account: up to 200 calls a minute on Standard, 400 on Plus and 800 on Pro, and the Free plan has no API access.
- Help Scout write requests (POST, PUT, PATCH, DELETE) count as 2 toward the per-minute limit, and a 429 response carries an X-RateLimit-Retry-After header.
- Help Scout's List Conversations endpoint returns 25 items a page while other list endpoints return 50, so integrations should follow _links.next.href until it disappears.
To use the Help Scout API, create an OAuth2 app under Your Profile → My apps, POST its client ID and secret to https://api.helpscout.net/v2/oauth2/token, and send the returned access token (valid for 172,800 seconds, two days) as a Bearer header on calls to https://api.helpscout.net/v2/. There is no static API key, and the Free plan has no API access at all: you need Standard, Plus or Pro. Details below are checked against Help Scout's developer docs and its Inbox API plan article on September 24, 2026. If you're new to the product, start with what is Help Scout; if you'd rather connect tools than write code, the best Help Scout integrations is the companion piece.
| Item | Value |
|---|---|
| Base URL | https://api.helpscout.net/v2/ |
| Authentication | OAuth2 (client credentials or authorization code), Bearer token |
| Token lifetime | 172,800 seconds (2 days); expiry shows as HTTP 401 |
| Plans with API access | Standard, Plus, Pro (not Free) |
| Rate limit per account | 200/min Standard, 400/min Plus, 800/min Pro; writes count as 2 |
| Page size | 25 for List Conversations, 50 for other list endpoints |
| Webhook verification | X-HelpScout-Signature (HMAC-SHA1 of the payload) |
What is the Help Scout Mailbox API v2?
The Help Scout API is a RESTful, JSON-over-HTTPS API. You make standard HTTP requests (GET to read, POST to create, PUT/PATCH to update, DELETE to remove) against resource URLs, and you get JSON back. HTTPS is required; there's no plain-HTTP fallback. API access comes with the Standard, Plus and Pro plans; Help Scout's plan article states that "the Free plan does not include access to the API or integrations."
The current version is v2, and it's the one to build against. One naming wrinkle: Help Scout has been rebranding "Mailbox" to "Inbox" across its product and docs (you'll see "Inbox API 2.0" and "inboxes" where older material says "Mailbox API" and "mailboxes"). The underlying API is the same: the URL path is still /v2/, and request bodies still use a field called mailboxId. Most developers still search for the "Help Scout Mailbox API," so we use both terms here for the same v2 surface.
The base URL is a single, fixed host (there's no per-account subdomain like some help desks use):
https://api.helpscout.net/v2/
So the conversations endpoint is https://api.helpscout.net/v2/conversations, the customers endpoint is https://api.helpscout.net/v2/customers, and so on.
How does Help Scout API authentication work?
Help Scout uses OAuth2, unlike help desks that hand you a single API key. There's no static, long-lived API key you copy from a settings page. Instead you register an app to get a client ID and client secret, then exchange those for a short-lived access token that you send on every request.
Step 1: create an app for your credentials
Log in, go to Your Profile → My apps, and click Create My App. You'll get an Application ID (client ID) and Application Secret (client secret). Treat the secret like a password: keep it out of client-side code, repos and logs, and store it in an environment variable or secrets manager.
There are two OAuth2 flows, and which one you pick depends on who the integration is for:
- Client Credentials: for internal integrations: a script, a sync job, or a backend service acting as your own account. This is what most people building against their own Help Scout want, and it's the simplest. No user redirect, no browser.
- Authorization Code: for apps meant to be installed by other Help Scout accounts (e.g. a public integration you distribute). The flow needs a redirection URL set on the app. The account owner is redirected to Help Scout to grant access, and you exchange the returned
codefor tokens. You also get a refresh token to renew access without sending them through the flow again.
Step 2: get an access token (client credentials)
For an internal integration, POST your credentials to the token endpoint:
curl -X POST https://api.helpscout.net/v2/oauth2/token \
--data "grant_type=client_credentials" \
--data "client_id=YOUR_APP_ID" \
--data "client_secret=YOUR_APP_SECRET"
The response is a JSON object with the token and its lifetime in seconds:
{
"token_type": "bearer",
"access_token": "369dbb08be58430086d2f8bd832bc1eb",
"expires_in": 172800
}
That expires_in of 172,800 seconds is two days. When the token expires, requests start returning HTTP 401, and you request a fresh token. Help Scout's docs ask you to create a new client-credentials token only after the existing one expires, so cache it and refresh on a 401. Store it in a variable-length field: Help Scout warns that token lengths will change over time.
Step 3: call the API with a Bearer token
Send the access token in the Authorization header as a Bearer token on every request:
curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
https://api.helpscout.net/v2/users/me
GET /v2/users/me returns the resource owner, a handy first call to confirm your token works.
Authorization-code and refresh flows (for distributable apps)
If you're building an app for other accounts, redirect the user to Help Scout's authorize URL, then exchange the returned code:
curl -X POST https://api.helpscout.net/v2/oauth2/token \
--data "code=THE_RETURNED_CODE" \
--data "client_id=YOUR_APP_ID" \
--data "client_secret=YOUR_APP_SECRET" \
--data "grant_type=authorization_code"
This returns both an access_token and a refresh_token. When the access token expires, swap the refresh token for a new pair without another redirect:
curl -X POST https://api.helpscout.net/v2/oauth2/token \
--data "refresh_token=YOUR_REFRESH_TOKEN" \
--data "client_id=YOUR_APP_ID" \
--data "client_secret=YOUR_APP_SECRET" \
--data "grant_type=refresh_token"
Which Help Scout API endpoints will you use most?
Help Scout exposes a resource for nearly every object in the product. The ones you'll reach for most:
- Conversations:
/v2/conversations. The center of gravity for almost every integration: create, read, update, list and delete conversations (Help Scout's term for a ticket/email thread). - Threads:
/v2/conversations/{id}/threads. A thread is an individual message within a conversation: a customer message, a reply, or an internal note. This is how you post a response or note programmatically. - Customers:
/v2/customers. The people you support, with their emails, phones, social handles and addresses. Create and sync them from your own systems. - Inboxes (mailboxes):
/v2/mailboxes. Your shared inboxes, plus their custom fields and saved replies. You'll need an inbox'sidto create conversations. - Users:
/v2/users. Your team members, useful for routing and reporting. - Reports:
/v2/reports/.... Company, conversations, productivity, happiness and user metrics for analytics pipelines. Reporting endpoints are not available on the Standard plan; Plus and Pro get all endpoints.
A quick map of HTTP verbs to common actions:
| Action | Method | Example endpoint |
|---|---|---|
| List conversations | GET | /v2/conversations |
| Get one conversation | GET | /v2/conversations/{id} |
| Create a conversation | POST | /v2/conversations |
| Update a conversation | PATCH | /v2/conversations/{id} |
| Add a reply/note (thread) | POST | /v2/conversations/{id}/threads |
| List customers | GET | /v2/customers |
| Get current user | GET | /v2/users/me |
How do you create a conversation with curl?
Creating a conversation requires a few fields: a subject, a customer (identified by id or email), the mailboxId of the inbox it belongs to, a type (email, chat or phone), a status (active, closed or pending), and at least one thread in the threads array.
curl -X POST https://api.helpscout.net/v2/conversations \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"subject": "Payment failed at checkout",
"customer": { "email": "[email protected]" },
"mailboxId": 85,
"type": "email",
"status": "active",
"threads": [
{
"type": "customer",
"customer": { "email": "[email protected]" },
"text": "Customer reports a 502 when paying with card."
}
]
}'
A successful create returns HTTP 201 with no body. The new conversation's ID comes back in the response headers: a Resource-ID header and a Location header (https://api.helpscout.net/v2/conversations/{id}). Read those rather than expecting a JSON payload.
How do you list conversations in Python?
Here's a minimal Python script using requests. It fetches a token, then reads a page of conversations. By default the list endpoint returns active conversations sorted by createdAt (newest first); pass status, sortField, sortOrder, mailbox, or a query to filter.
import os
import requests
CLIENT_ID = os.environ["HELPSCOUT_CLIENT_ID"]
CLIENT_SECRET = os.environ["HELPSCOUT_CLIENT_SECRET"]
BASE = "https://api.helpscout.net/v2"
# 1) Get an access token (client credentials)
tok = requests.post(f"{BASE}/oauth2/token", data={
"grant_type": "client_credentials",
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET,
})
tok.raise_for_status()
token = tok.json()["access_token"]
# 2) Call the API with a Bearer token
headers = {"Authorization": f"Bearer {token}"}
resp = requests.get(f"{BASE}/conversations",
headers=headers,
params={"status": "active", "page": 1})
resp.raise_for_status()
data = resp.json()
convos = data["_embedded"]["conversations"]
print(f"Page {data['page']['number']} of {data['page']['totalPages']} "
f"— {data['page']['totalElements']} total")
for c in convos:
print(c["id"], c.get("subject"), "|", c.get("status"))
How do you create a conversation in Node?
The same idea in Node using the built-in fetch (Node 18+):
const BASE = "https://api.helpscout.net/v2";
// 1) Get a token
const tokRes = await fetch(`${BASE}/oauth2/token`, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
grant_type: "client_credentials",
client_id: process.env.HELPSCOUT_CLIENT_ID,
client_secret: process.env.HELPSCOUT_CLIENT_SECRET,
}),
});
const { access_token } = await tokRes.json();
// 2) Create a conversation
const res = await fetch(`${BASE}/conversations`, {
method: "POST",
headers: {
"Authorization": `Bearer ${access_token}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
subject: "API test conversation",
customer: { email: "[email protected]" },
mailboxId: 85,
type: "email",
status: "active",
threads: [{ type: "customer",
customer: { email: "[email protected]" },
text: "Created from Node." }],
}),
});
if (!res.ok) throw new Error(`Help Scout error ${res.status}: ${await res.text()}`);
console.log("Created conversation:", res.headers.get("Resource-ID"));
How does Help Scout API pagination work?
Help Scout list endpoints return results in HAL (Hypertext Application Language) format. Two properties matter:
_embeddedholds the records; for example_embedded.conversationsis the array of conversation objects._linksholds navigation URLs:self,first,last,previousandnext. Not every link appears in every response; on the last page there is nonext.
There's also a page object summarizing the result set:
{
"_embedded": { "conversations": [ /* ... */ ] },
"_links": {
"self": { "href": "https://api.helpscout.net/v2/conversations?page=1" },
"next": { "href": "https://api.helpscout.net/v2/conversations?page=2" },
"first": { "href": "https://api.helpscout.net/v2/conversations?page=1" },
"last": { "href": "https://api.helpscout.net/v2/conversations?page=4" }
},
"page": { "number": 1, "size": 25, "totalElements": 100, "totalPages": 4 }
}
List Conversations returns 25 items a page; every other list endpoint returns 50. The cleanest way to walk results is to follow the _links.next.href URL until it's no longer present. Alternatively, increment the page query parameter up to page.totalPages.
What are the Help Scout API rate limits?
Help Scout's rate limit is plan-tiered and per account: all users associated with the same account count against the same limit, so multiple integrations on one account draw from one pool. Help Scout's plan article lists these ceilings:
| Plan | Requests per minute (per account) |
|---|---|
| Free | No API access |
| Standard | Up to 200/min (no reporting endpoints) |
| Plus | Up to 400/min |
| Pro | Up to 800/min |
Write requests count double. A POST, PUT, PATCH or DELETE counts as 2 requests toward the per-minute limit, while a GET counts as 1. So a job that creates conversations burns through the budget twice as fast as a read-only sync.
Help Scout also returns headers so you can throttle before you are cut off: X-RateLimit-Limit-Minute (your per-minute ceiling) and X-RateLimit-Remaining-Minute (how many requests you have left in the current window). Watch the remaining count and slow down before you hit zero.
When you do exceed the limit, Help Scout returns HTTP 429 with an X-RateLimit-Retry-After header telling you how many seconds to wait. The correct pattern is to back off for exactly that long, then retry, ideally with exponential backoff and jitter if you run many workers. Build this in from day one; a sync job without it fails the first time it backfills. (The header behavior is documented in Help Scout's rate-limiting docs.)
How do Help Scout webhooks work?
If you want to react to events rather than poll for them, use webhooks (/v2/webhooks). You register an endpoint URL and subscribe to events such as convo.created, convo.assigned, convo.status and convo.customer.reply.created, and Help Scout POSTs a JSON payload to your URL when they happen. Each request carries an X-HelpScout-Event header and an X-HelpScout-Signature header: compute a base64 HMAC-SHA1 of the raw payload with your webhook secret key and compare it to the header to confirm the request came from Help Scout. Webhooks are the right call for near-real-time sync; reserve polling for backfills and reconciliation, where they keep you well inside the rate limit.
When would you use an AI agent layer instead of the raw API?
The API is the right tool when you want deterministic, programmatic control: syncing data, wiring Help Scout into your own stack, or creating conversations from other systems. But a growing share of "API projects" are really "I want conversations triaged and answered automatically," which is a different shape of problem. Writing and maintaining that logic (classify the message, look up the customer, draft a reply, decide whether it's safe to send) is a real engineering commitment, and it gets brittle as your product and policies change.
An AI agent layer covers that job. Macha is an AI agent layer that runs on top of Zendesk, Freshdesk, Gorgias, Front, HubSpot or Intercom, and it does not currently integrate with Help Scout, so on Help Scout it isn't a drop-in option today. We mention it only because the pattern is relevant: rather than scripting triage-and-reply against an API by hand, an agent layer reads from your help desk plus a connected knowledge base to triage, draft and resolve routine conversations, leaving anything it can't confidently handle as a normal ticket for a human. (See Macha on your help desk for the desks it does connect to.) The honest trade-offs are the same everywhere: it's another integration to configure, it's only as good as the knowledge you feed it, and billing is per ticket (one conversation, charged once however many steps it takes), from $299 a month for 750 tickets, never per resolution. On a supported help desk, the trial is $50 of free usage with no credit card. For Help Scout specifically, the right path today is the API above or an off-the-shelf connector from the best Help Scout integrations.
Frequently asked questions
What is the Help Scout API base URL? Every request goes to a single host: https://api.helpscout.net/v2/. So conversations live at https://api.helpscout.net/v2/conversations. Unlike some help desks, there's no per-account subdomain.
Does Help Scout use an API key or OAuth? OAuth2; there's no static API key to copy. You register an app under Your Profile → My apps to get a client ID and secret, then exchange them for a short-lived access token that you send as Authorization: Bearer {token} on every request.
How do I get a Help Scout access token? For an internal integration, POST to https://api.helpscout.net/v2/oauth2/token with grant_type=client_credentials, your client_id and client_secret. You get back an access_token valid for about two days (expires_in: 172800); request a new one when calls start returning 401. For apps used by other accounts, use the authorization-code flow and renew with the refresh token.
What's the difference between the "Mailbox API" and "Inbox API"? They're the same thing. Help Scout is rebranding "Mailbox" to "Inbox" in its product and docs, but the API path is still /v2/ and request bodies still use mailboxId. Search results use both names.
What are the Help Scout API rate limits? The limit is tiered by plan, per account (shared across all of that account's tokens and apps): up to 200/min on Standard, 400/min on Plus and 800/min on Pro, with no API access on Free. Write requests (POST/PUT/PATCH/DELETE) count as 2 each; reads count as 1. Use the X-RateLimit-Limit-Minute and X-RateLimit-Remaining-Minute response headers to throttle proactively, and on a 429, wait the number of seconds in the X-RateLimit-Retry-After header before retrying.
Can I use the Help Scout API on the Free plan? No. Help Scout's plan article says the Free plan does not include access to the API or integrations. Standard gets up to 200 calls a minute without reporting endpoints; Plus and Pro get every endpoint.
How do I paginate Help Scout API results? Responses use HAL: records are in _embedded, and navigation URLs are in _links. Follow _links.next.href until it's absent, or increment the page parameter up to page.totalPages. List Conversations returns 25 items a page; other list endpoints return 50.
What usually breaks a Help Scout API integration?
Three things: the OAuth flow (there's no static API key), the HAL pagination (follow _links.next, and remember conversations page at 25 while other lists page at 50), and the rate limit (200/min on Standard, 400/min on Plus, 800/min on Pro, per account, with writes counting double). Cache your token, handle 401 by requesting a new one, handle 429 by honoring X-RateLimit-Retry-After, and verify webhook signatures before trusting a payload. From here, see what Help Scout is for the product overview, or the best Help Scout integrations if you'd rather connect a tool than write code.
Help Scout Inbox API 2.0 details checked against developer.helpscout.com and docs.helpscout.com on September 24, 2026. Confirm endpoints, limits and field values in the live docs before relying on them.
Resolve tickets automatically with AI agents
Macha's AI agents work on top of the help desk you already use — no code.

