Three endpoints tell your integration what it is connected to: GET /v1 checks that a credential works, GET /v1/sites lists the help centers it can act on, and GET /v1/account returns the account, the plan and what the credential may do. Call them when you connect a new API key or OAuth token, before you touch any content.
Endpoints
Method and path | What it does | Scope |
|---|---|---|
| Checks that a credential is valid | Any valid credential |
| Lists the help centers the credential can act on |
|
| Returns the account, plan and capabilities behind the credential | Any valid credential |
Every API key holds content.read, so all three work with any key. An OAuth token without content.read can call GET /v1 and GET /v1/account, and gets 403 Forbidden with "code": "insufficient_scope" from GET /v1/sites. See Scopes.
Check a credential
/v1Check that an API key or OAuth token is valid.
A 200 OK means the key or token is valid. The banner needs no scope, so a Read only key and a Read & write key get the same answer. To find out what a credential may do, call GET /v1/account (below) and read kb.capabilities.
Every /v1 endpoint that takes a key or token answers 401 Unauthorized with {"status": "unauthorized"} when the apikey header is missing, when the key is mistyped or deleted, when the person who created the key no longer has a HelpCenter.io account, and when an OAuth token is expired, revoked or malformed. The body never says which of these it was.
The API's root, https://api.helpcenter.io/, answers the same message with no credential at all. A 200 from it proves nothing about your key, so always check /v1.
The site object
A help center, as GET /v1/sites returns it:
Field | Type | Description |
|---|---|---|
| integer | The help center's id. With an OAuth token, send it in the |
| string | A stable public identifier. Export pages and webhook deliveries carry the same value as |
| string | The help center's name. |
| string | The name in its |
| string | Where readers find it: the custom domain when one is live, otherwise |
| string |
|
| string | The default language code, for example |
| string |
|
| boolean |
|
| array of strings | The default language first, then every additional language. These are the keys the API accepts in per-language maps such as an article's |
| string | When the help center was created, in UTC, as |
List help centers
/v1/sitesList the help centers this credential can act on.
What you get depends on the credential:
An API key belongs to one help center, so the list holds exactly that one. The
X-HCio-Siteheader and thesitequery parameter are ignored for API keys.An OAuth token sees only the help centers that meet both conditions: the HelpCenter.io account of the person who approved your app owns them, and the person shared them with your app, on the consent screen or later in Connected Apps. The API checks both on every request, so a change shows in the list on your next request. Use each
idinX-HCio-Site, as described in Choose which help center a request acts on.
The list is ordered by id and has no pages: meta.items_count is its length.
Get the account
/v1/accountGet the account, plan and capabilities behind this credential.
The response has three blocks:
Field | Type | Description |
|---|---|---|
| object | The HelpCenter.io account the credential acts for: |
| string | Always |
| object | The account's plan. See the next table. |
| integer | How many help centers this credential can act on. |
| array of integers | Their ids, the same ones |
| boolean |
|
| boolean |
|
The plan block:
Field | Type | Description |
|---|---|---|
| string | The plan's identifier, for example |
| string | The plan's display title, or its |
| boolean |
|
| boolean |
|
| boolean |
|
| object | Feature flags of the plan, such as |
| string | Where the active plan comes from: |
| boolean, object or null |
|
Read kb.capabilities.write before your integration offers to create or change content, so a Read only key gets a clear message instead of a 403 halfway through a job.
This script prints the help centers a key reaches and whether it can write:
// Check which help centers a key reaches and whether it can write.
const API = 'https://api.helpcenter.io/v1';
const headers = { apikey: process.env.HELPCENTER_API_KEY, Accept: 'application/json' };
async function get(path) {
const res = await fetch(API + path, { headers });
if (!res.ok) throw new Error(`${path}: HTTP ${res.status}`);
return res.json();
}
async function main() {
const account = await get('/account');
const { sites } = await get('/sites');
for (const site of sites) {
console.log(`${site.name} (${site.url}), languages: ${site.languages.join(', ')}`);
}
const canWrite = account.kb.capabilities.write;
console.log(canWrite
? 'This key can create and change content.'
: 'This key can only read.');
}
main().catch((err) => {
console.error(err);
process.exit(1);
});
# Check which help centers a key reaches and whether it can write.
import json
import os
import urllib.request
API = "https://api.helpcenter.io/v1"
HEADERS = {"apikey": os.environ["HELPCENTER_API_KEY"], "Accept": "application/json"}
def get(path):
request = urllib.request.Request(API + path, headers=HEADERS)
with urllib.request.urlopen(request) as response:
return json.load(response)
account = get("/account")
for site in get("/sites")["sites"]:
print(f"{site['name']} ({site['url']}), languages: {', '.join(site['languages'])}")
if account["kb"]["capabilities"]["write"]:
print("This key can create and change content.")
else:
print("This key can only read.")
<?php
// Check which help centers a key reaches and whether it can write.
$api = 'https://api.helpcenter.io/v1';
$headers = ['apikey: ' . getenv('HELPCENTER_API_KEY'), 'Accept: application/json'];
function get(string $url, array $headers): array
{
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => $headers,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
if ($status !== 200) {
throw new RuntimeException("$url: HTTP $status");
}
return json_decode($body, true);
}
$account = get("$api/account", $headers);
foreach (get("$api/sites", $headers)['sites'] as $site) {
$languages = implode(', ', $site['languages']);
echo "{$site['name']} ({$site['url']}), languages: $languages\n";
}
echo $account['kb']['capabilities']['write']
? "This key can create and change content.\n"
: "This key can only read.\n";
For the Acme help center in the examples on this page and a Read & write key, it prints Acme (https://acme.helpcenter.io), languages: en, de and This key can create and change content.