Skip to content

API overview

Read and manage your My Journey Analytics data from your own code, with personal API keys, scopes and project IDs.

The My Journey Analytics API lets your own systems do what you do in the app: run queries, read and update people and cohorts, manage insights and more.

There are two kinds of API, and they authenticate differently.

APIWhat it is forHow it authenticates
Capture APISending events from your servers and appsYour public project token
Private API (everything under /api/)Reading data and managing your projectsA personal API key, or an OAuth access token

The project token is safe to publish in your website's code. A personal API key is a secret: keep it on your servers, never in a browser or app.

Base URL

Send API requests to the app's address:

https://app.myjourneyanalytics.com

Event capture also works through your custom tracking domain, if you have one. The private API does not: always call the app's address for it.

Create a personal API key

  1. In the app, open Settings → Account → Personal API keys.
  2. Select Create personal API key.
  3. Give the key a Label, for example "Reports bot".
  4. Choose which organizations or projects it can reach: All access, Organizations or Projects.
  5. Choose its Scopes, or pick a preset such as Performing analytics queries.
  6. Select Create key, then copy the key.

For security reasons the key is shown only once. If you lose it, roll the key or create a new one.

A key can never do more than your own account can. If your role in a project only lets you view, a key with write scopes still cannot change anything there.

Organization admins can see which members' keys can reach the organization, and their scopes, under Settings → Organization → Security → Personal API key access.

Scopes

Each scope is an object and an access level, written object:read or object:write. Write includes read. The scopes used most often in these guides are:

ScopeLets the key
query:readRun queries and list events
person:read, person:writeRead, update and delete persons
cohort:read, cohort:writeRead and manage cohorts
insight:read, insight:writeRead and manage insights
endpoint:readRun saved endpoints
project:readList projects and read their settings

If a key is missing a scope, the request fails with 403 and the response names the scope that is needed.

Authenticate requests

Send the key in the Authorization header as a bearer token:

bash
curl https://app.myjourneyanalytics.com/api/projects/ \
  -H "Authorization: Bearer <personal API key>"
js
const response = await fetch("https://app.myjourneyanalytics.com/api/projects/", {
  headers: { Authorization: `Bearer ${process.env.MJ_PERSONAL_API_KEY}` },
});
const projects = await response.json();

Use the header rather than putting the key in a URL, so it does not end up in logs or browser history.

Project IDs

Most endpoints belong to a project, and their paths start with /api/projects/<project ID>/. To find a project's ID:

  • open Settings → Project → General, where Project token & ID shows both values, or
  • look at the app's address: in https://app.myjourneyanalytics.com/project/12345/insights the ID is 12345, or
  • list your projects with GET /api/projects/ (needs project:read).

The project token and the project ID are different things. The token identifies the project when sending events; the ID goes in API paths.

Pagination

List endpoints return one page at a time:

json
{
  "count": 250,
  "next": "https://app.myjourneyanalytics.com/api/projects/12345/cohorts/?limit=100&offset=100",
  "previous": null,
  "results": []
}

Most lists return 100 results per page. Use limit and offset to choose a page, or simply follow next until it is null. Some lists, such as events, page by time instead and give only a next link.

js
async function listAll(url) {
  const results = [];
  while (url) {
    const page = await fetch(url, {
      headers: { Authorization: `Bearer ${process.env.MJ_PERSONAL_API_KEY}` },
    }).then((r) => r.json());
    results.push(...page.results);
    url = page.next;
  }
  return results;
}

To read large amounts of data, use the query API instead of paging through lists.

Errors

Errors come back as JSON with a type, a code, a human-readable detail and, for validation errors, the attr (field) at fault:

json
{
  "type": "validation_error",
  "code": "required",
  "detail": "This field is required.",
  "attr": "name"
}
StatusMeaning
400The request is invalid; detail and attr say why
401The key is missing, mistyped or deleted
403The key lacks a scope, cannot reach this project, or your account lacks permission
404The project or object does not exist, or the key cannot see it
429Too many requests, or too many queries running at once: wait, then retry more slowly

When a 429 response includes a Retry-After header, wait that many seconds before trying again.

Keep keys safe

  • Store keys in your server's secret store or environment variables, never in source code.
  • Never use a personal API key in a website or mobile app; use the JavaScript library and its project token there.
  • If a key may have leaked, roll or delete it straight away in Settings → Account → Personal API keys.

Guides

Can't find what you need? Contact support