API

Last updated:

|Edit this page

PostHog has a powerful API that enables you to capture, evaluate, create, update, and delete nearly all of your information in PostHog. You can use it to pull information into your app, update metadata programmatically, capture events from any language that can send HTTP requests, and more.

The API is available for all users and instances. It contains two types of endpoints:

  1. Public POST-only endpoints such as capture and decide are used for capturing events, batching events, updating person or group information, and evaluating feature flags. These don't require authentication, but use your project API key to handle the request.

  2. Private GET, POST, PATCH, DELETE endpoints are used for querying, creating, updating, or deleting nearly all data in PostHog. They give the same access as if you were logged into your PostHog instance, but require authentication with your personal API key.

You must make API requests to the correct domain. On US Cloud, these are https://us.i.posthog.com for public endpoints and https://us.posthog.com for private ones. On EU Cloud, these are https://eu.i.posthog.com for public endpoints and https://eu.posthog.com for private ones. For self-hosted instances, use your self-hosted domain. Confirm yours by checking your PostHog instance URL.

Private endpoint authentication

Personal API keys can enable full access to your account, like logging in with your email and password. You can create multiple, give them different scopes, and each can be invalidated individually. This improves the security of your PostHog account. Personal API keys need to be kept private and shouldn't be used in the frontend.

How to obtain a personal API key

  1. Go to the Personal API keys section in your account settings

  2. Click + Create a personal API Key.

  3. Give your key a label - this is just for you, usually to describe the key's purpose.

  4. Choose the scopes for your key. We recommended selecting only the scopes required for the API endpoints you really need. This is a security best practice. You can always modify the scopes later if you need to.

  5. At the top of the list, you should see your brand new key. Immediately copy its value, as you'll never see it again after refreshing the page.

You can create as many keys as you like.

How to create an api key

How to authenticate using the personal API key

There are three options:

  1. Use the Authorization header and Bearer authentication, like so:
    JavaScript
    const headers = {
    Authorization: `Bearer ${POSTHOG_PERSONAL_API_KEY}`
    }
  2. Put the key in request body, like so:
    JavaScript
    const body = {
    personal_api_key: POSTHOG_PERSONAL_API_KEY
    }
  3. Put the key in query string, like so:
    JavaScript
    const url = `<ph_app_host>/api/event/?personal_api_key=${POSTHOG_PERSONAL_API_KEY}`

Any one of these methods works, but only the value encountered first (in the order above) will be used for authentication.

Rate limiting

Private GET, POST, PATCH, DELETE endpoints are rate limited. Public POST-only endpoints are not rate limited. A rule of thumb for whether rate limits apply is if the personal API key is used for authentication.

There are separate limits for different kinds of resources.

  • For all analytics endpoints (such as calculating insights, retrieving persons, or retrieving session recordings), the rate limits are 240/minute and 1200/hour.

  • The query endpoint has a rate limit of 120/hour. This counts queries, rather than returned results. For large or regular exports of events, use batch exports.

  • For feature flag local evaluation (which is enabled in SDKs when you input a personal API key), the rate limit is 600/minute.

  • For the rest of the create, read, update, and delete endpoints, the rate limits are 480/minute and 4800/hour.

  • For public POST-only endpoints like event capture (/capture) and feature flag evaluation (/decide), there are no rate limits.

These limits apply to the entire team (i.e. all users within your PostHog organization). For example, if a script requesting feature flag metadata hits the rate limit, and another user, using a different personal API key, makes a single request to the persons API, this gets rate limited as well.

Want to use the PostHog API beyond these limits? Email us at sales@posthog.com.

Responses

Status code: 200

Response:

JSON
{
"status": 1
}

Meaning: A 200: OK response means we have successfully received the payload, it is in the correct format, and the project API key (api_key) is valid. It does not imply that events are valid and will be ingested. As mentioned in invalid events, certain event validation errors may cause an event not to be ingested.

Status code: 400

Responses:

JSON
{
"type": "validation_error",
"code": "invalid_project",
"detail": "Invalid Project ID.",
"attr": "project_id"
}

Meaning: We were unable to determine the project to associate the events with.

JSON
{
"type": "validation_error",
"code": "invalid_payload",
"detail": "Malformed request data",
"attr": null
}

Meaning: Request payload data formatted incorrectly.

Status code: 401

Responses:

JSON
{
"type": "authentication_error",
"code": "invalid_api_key",
"detail": "Project API key invalid. You can find your project API key in PostHog project settings."
}

Meaning: The project API key you provided is invalid.

JSON
{
"type": "authentication_error",
"code": "invalid_personal_api_key",
"detail": "Invalid Personal API key."
}

Meaning: The personal API key you used for authentication is invalid.

Status code: 503 (Deprecated)

Response:

JSON
{
"type": "server_error",
"code": "fetch_team_fail",
"detail": "Unable to fetch team from database."
}

Meaning: (Deprecated) This error only occurs in self-hosted Postgres instances if the database becomes unavailable. On ClickHouse-backed instances database failures cause events to be added to a dead letter queue, from which they can be recovered.

Pagination

Requests are paginated if the results are higher than the limit, usually 100 (sometimes 500 or 1000). Pagination happens in the following format:

JSON
{
"next": "<ph_app_host>/api/person/?cursor=cD0yMjgxOTA2",
"previous": null,
"results": [
// ...
]
}

You can then just call the "next" URL to get the next set of results.

Tips

  • When logged in, you can view and download the API schema using the following options:

  • The /users/@me/ endpoint gives you useful information about the current user.

  • The /api/event_definition/ and /api/property_definition endpoints provide the possible event names and properties you can use throughout the rest of the API.

  • The maximum size of a POST request body is governed by settings.DATA_UPLOAD_MAX_MEMORY_SIZE, and is 20MB by default.

  • By default, the PostHog API returns results from the last project you visited in the UI. To override this behavior, you can pass in your project API key as a query parameter in the request like api/event/?token=my_project_api_key.

Questions?

  • Ariel
    8 days ago

    Personal api key v/s api key

    The feature flag panel says that the secure api key replaces personal api keys for local evaluation: https://us.posthog.com/settings/environment-feature-flags

    The code however still expects and uses a personal_api_key argument passed to the Client.

    Attempting to use the secure api key as if it were a personal_api_key results in:

    Error loading feature flags: To use feature flags, please set a valid personal_api_key. More information: https://posthog.com/docs/api/overview
  • Nuno
    16 days ago

    Changes to the Response?

    Hey there!

    This info seems wrong - https://posthog.com/docs/api#responses "status": 1

    We're currently receiving a "status": "OK"

    Could you please double check and update the docs?

    • Nuno
      Author10 days ago

      Thank you @shao wei

  • Jack
    2 months ago

    When accessing live.us.posthog.com with API key, I'm unauthorized.

    When hitting https://live.us.posthog.com/stats with an all-access API key, I get the error 401: wrong token claims. How can I access this data?

  • Felix
    2 months ago

    Permission Denied When Creating Hog Functions via API

    What I'm trying to do I'm attempting to programmatically create a new transformation (Hog Function) in PostHog using the API. Specifically, I'm trying to install the "Filter Out Plugin" via a POST request to the endpoint:

    /api/projects/1/hog_functions/

    I'm using a small node script to communicate with the self-hosted posthog instance:

    axios({
    method: 'post',
    url: apiUrl,
    headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${apiKey}`
    },
    data: payload
    })

    The error I'm getting

    Response status: 403
    Response data: {
    type: 'authentication_error',
    code: 'permission_denied',
    detail: 'This action does not support Personal API Key access',
    attr: null
    }

    What I've tried

    I've verified that my Personal API Key is valid and works for other API endpoints I've confirmed I have the correct project ID I've checked that the request payload is properly formatted

    My question

    Is there a way to create Hog Functions via the API? The error suggests that Personal API Keys don't have permission for this specific action, but I'm not sure what alternative authentication method to use. Is there another approach I should be taking to automate the creation of transformations?

    Any guidance would be greatly appreciated!

    • Meikel
      2 months ago

      hey,

      can you try running:

      curl --location '${baseurl}/api/environments/:project_id/hog_functions' \
      --header 'Content-Type: application/json' \
      --header 'Authorization: Bearer <POSTHOG_PERSONAL_API_KEY>' \
      --data '{
      "type": "transformation",
      "name": "Filter Out Plugin",
      "inputs": {},
      "enabled": true,
      "template_id": "plugin-posthog-filter-out-plugin"
      }'

      using curl to see if it works in the terminal?

      another question would be if you are running the latest version of posthog since you mentioned that you are using our hobby deployment.

      cheers, meikel

  • Jonathan
    6 months ago

    API Limits

    I have a question regarding API limits. As indicated in the documentation page of the endpoint https://posthog.com/docs/api/query#post-api-projects-project_id-query, there is a limit of 10000 records per hour, those records are those that are returned or those that are processed, that is if we make a call to return a count of the types of events that have occurred in the last month, assuming that there have been a total of 20 different events, which would be taken into account for the limit, those 20 records that have returned the call to the endpoint, or all records that have been processed for the count?

    • Pawel
      3 months ago

      The limit is 10000 returned rows per 1 query.

      Query may process millions rows. You can run up to 120 queries per hour

  • Vishal
    8 months ago

    API to get Active users with N days (Last 30 Days, Last7Days etc)

    Is there an API to get the Active users with N days (Last 30 Days, Last7Days etc) ?

  • Marcos
    8 months ago

    Check schema has a minor error with version

    If you try to import the schema into Postman, it fails because the version needs to be a string. The same issue is shown when validating with Swagger Editor:

    Structural error at info.version
    should be string
  • Jeff
    10 months ago

    Is there a way to get the set of scopes available to a given api key?

    I would like to be able to adjust the way I use the API based on which scopes are available to the API key, and to ideally be able to do this without having to test each API to see whether I can access it or not. Write scopes in particular could be potentially destructive just to try to test for.

    Something like /api/keyscopes would be super handy for this purpose, thank you!

    • Kiran
      10 months ago

      Is there any plans for this? I would love to have some way to check for the scopes.

  • Denis
    10 months ago

    No "next" field in json response for query.

    Hi, I don't see any "next" field. Maybe I need to add a parameter to the query? query = "select uuid, event, distinct_id, toDate(timestamp) as event_date from events" Screenshot 2024-08-12 102912.png

  • tristan
    a year ago

    I am getting 403 error but I am sure the API key is correct

    Could it be caused by this code? It runs on first load. Before anything else. I am not calling any other posthog resources except for feature flags which don't work now

    if (PUBLIC_NODE_ENV !== Environment.PRODUCTION) {
    config = {
    autocapture: false,
    loaded: function (ph: any) {
    ph.opt_out_capturing();
    },
    };
    } else {
    config = {
    api_host: "https://eu.i.posthog.com",
    loaded: function (ph: PostHog) {
    ph.identify(curUser.email, {
    email: curUser.email,
    });
    ph.group("company", orgs[0]);
    },
    };
    }
    posthog.init(PUBLIC_POSTHOG_API_TOKEN, config);
    • tristan
      Authora year ago

      OMG.... 401 not 403...

    • tristan
      Authora year agoSolution

      Nevermind. I figured it all out.....

      1. Have to add this since I am in the eu api_host: "https://eu.i.posthog.com" (wasn't there in the testing environment)
      2. was not identifying the users in local environments so no feature flags enabled by group.
  • Kimmy
    a year ago

    Override feature flag returned value?

    First of all, I'm using the PHP SDK. In my case, users might not be logged in when viewing the pages, and they can log in at any time. This means that during the initial feature flag check, the value might be false, but after they log in (I call alias after they log in), the feature flag might be true. Is there a way to override? Will it affect the rollout?

  • Matthew
    a year ago

    HogQL queries don't see "next"

    Hi, I was trying to access Pagination for the HogQL queries, but even though there is a "hasMore" entry which is true, I don't see the "next" or "previous" fields documented here. Any suggestions?

    • Petr
      4 months ago

      Hello, Has anyone solved this problem? I also don't see the "next" when using HogQLQuery. Even though I'm 100% sure that the result should display more records than the set limit.

  • George
    3 years ago

    OpenAPI spec

    Is there a hosted OpenAPI spec somewhere? I found one in the Github repo but pointing a client builder at it uses Github as the host :(

Was this page useful?

Next article

Capture and batch API endpoints

The capture and batch endpoints are the main way to send events to PostHog. Beyond user behavior, they are also used to identify users, update person or group properties, migrate from other platforms, and more. Our SDKs handle the different event types for you, but with the API, you need to send the right type of event (listed below) to trigger the functionality you want. Both are POST-only public endpoints that use your project API key and do not return any sensitive data from your…

Read next article

PostHog.com doesn't use third party cookies - only a single in-house cookie.

No data is sent to a third party.

Ursula von der Leyen, President of the European Commission