PostHog API
Use the PostHog API via direct curl calls to manage product analytics, feature flags, experiments, insights, dashboards, cohorts, annotations, and surveys.
Official docs:
https://posthog.com/docs/api
When to Use
Use this skill when you need to:
- Manage feature flags - create, update, list, and toggle feature flags
- Run experiments - create and monitor A/B tests
- Query analytics - run HogQL queries for custom analytics
- Manage insights - create and retrieve saved insights (trends, funnels, retention)
- Manage dashboards - create and organize dashboards
- Track persons and events - query user data and event streams
- Manage cohorts - create and query user segments
- Create annotations - add timeline markers for deployments or incidents
- Manage surveys - create and monitor in-app surveys
Prerequisites
Discovering Your Project ID
Most endpoints require a project ID. Get it from the projects endpoint:
curl -s "https://us.posthog.com/api/projects/" --header "Authorization: Bearer $(printenv POSTHOG_TOKEN)" | jq '.results[] | {id, name}'
Verify Authentication
curl -s "https://us.posthog.com/api/users/@me/" --header "Authorization: Bearer $(printenv POSTHOG_TOKEN)" | jq '{uuid, first_name, email}'
How to Use
All examples below assume POSTHOG_TOKEN is set. Replace <project-id> with your actual project ID from the prerequisites step.
Base URL: https://us.posthog.com/api
Organizations
List Organizations
curl -s "https://us.posthog.com/api/organizations/" --header "Authorization: Bearer $(printenv POSTHOG_TOKEN)" | jq '.results[] | {id, name, slug, created_at}'
Get Organization Details
Replace <org-id> with your organization ID:
curl -s "https://us.posthog.com/api/organizations/<org-id>/" --header "Authorization: Bearer $(printenv POSTHOG_TOKEN)" | jq '{id, name, slug, created_at, membership_level}'
Projects
List Projects
curl -s "https://us.posthog.com/api/projects/" --header "Authorization: Bearer $(printenv POSTHOG_TOKEN)" | jq '.results[] | {id, name, timezone}'
Get Project Details
Replace <project-id> with your project ID:
curl -s "https://us.posthog.com/api/projects/<project-id>/" --header "Authorization: Bearer $(printenv POSTHOG_TOKEN)" | jq '{id, name, timezone, completed_snippet_onboarding, ingested_event}'
Feature Flags
List Feature Flags
curl -s "https://us.posthog.com/api/projects/<project-id>/feature_flags/" --header "Authorization: Bearer $(printenv POSTHOG_TOKEN)" | jq '.results[] | {id, key, name, active}'
Get Feature Flag Details
Replace <flag-id> with the feature flag ID:
curl -s "https://us.posthog.com/api/projects/<project-id>/feature_flags/<flag-id>/" --header "Authorization: Bearer $(printenv POSTHOG_TOKEN)" | jq '{id, key, name, active, filters, rollout_percentage}'
Create Feature Flag
Write to /tmp/posthog_request.json:
{
"key": "my-new-flag",
"name": "My New Feature Flag",
"active": true,
"filters": {
"groups": [
{
"properties": [],
"rollout_percentage": 100
}
]
}
}
curl -s -X POST "https://us.posthog.com/api/projects/<project-id>/feature_flags/" --header "Authorization: Bearer $(printenv POSTHOG_TOKEN)" --header "Content-Type: application/json" -d @/tmp/posthog_request.json | jq '{id, key, name, active}'
Update Feature Flag
Write to /tmp/posthog_request.json:
{
"active": false
}
Replace <flag-id> with the feature flag ID:
curl -s -X PATCH "https://us.posthog.com/api/projects/<project-id>/feature_flags/<flag-id>/" --header "Authorization: Bearer $(printenv POSTHOG_TOKEN)" --header "Content-Type: application/json" -d @/tmp/posthog_request.json | jq '{id, key, name, active}'
Delete Feature Flag
Replace <flag-id> with the feature flag ID:
curl -s -X DELETE "https://us.posthog.com/api/projects/<project-id>/feature_flags/<flag-id>/" --header "Authorization: Bearer $(printenv POSTHOG_TOKEN)"
Experiments
List Experiments
curl -s "https://us.posthog.com/api/projects/<project-id>/experiments/" --header "Authorization: Bearer $(printenv POSTHOG_TOKEN)" | jq '.results[] | {id, name, start_date, end_date, feature_flag_key}'
Get Experiment Details
Replace <experiment-id> with the experiment ID:
curl -s "https://us.posthog.com/api/projects/<project-id>/experiments/<experiment-id>/" --header "Authorization: Bearer $(printenv POSTHOG_TOKEN)" | jq '{id, name, description, start_date, end_date, feature_flag_key, parameters}'
Create Experiment
Write to /tmp/posthog_request.json:
{
"name": "Button Color Test",
"description": "Testing red vs blue button",
"feature_flag_key": "button-color-test",
"parameters": {
"feature_flag_variants": [
{"key": "control", "rollout_percentage": 50},
{"key": "test", "rollout_percentage": 50}
]
},
"filters": {
"events": [{"id": "$pageview", "name": "$pageview"}]
}
}
curl -s -X POST "https://us.posthog.com/api/projects/<project-id>/experiments/" --header "Authorization: Bearer $(printenv POSTHOG_TOKEN)" --header "Content-Type: application/json" -d @/tmp/posthog_request.json | jq '{id, name, feature_flag_key}'
Insights
List Saved Insights
curl -s "https://us.posthog.com/api/projects/<project-id>/insights/" --header "Authorization: Bearer $(printenv POSTHOG_TOKEN)" | jq '.results[] | {id, short_id, name, filters}'
Get Insight Details
Replace <insight-id> with the insight ID:
curl -s "https://us.posthog.com/api/projects/<project-id>/insights/<insight-id>/" --header "Authorization: Bearer $(printenv POSTHOG_TOKEN)" | jq '{id, short_id, name, description, filters, last_refresh}'
Create Trend Insight
Write to /tmp/posthog_request.json:
{
"name": "Daily Pageviews",
"filters": {
"insight": "TRENDS",
"events": [{"id": "$pageview", "name": "$pageview", "math": "total"}],
"date_from": "-30d"
}
}
curl -s -X POST "https://us.posthog.com/api/projects/<project-id>/insights/" --header "Authorization: Bearer $(printenv POSTHOG_TOKEN)" --header "Content-Type: application/json" -d @/tmp/posthog_request.json | jq '{id, short_id, name}'
Create Funnel Insight
Write to /tmp/posthog_request.json:
{
"name": "Signup Funnel",
"filters": {
"insight": "FUNNELS",
"events": [
{"id": "$pageview", "order": 0},
{"id": "signup_started", "order": 1},
{"id": "signup_completed", "order": 2}
],
"date_from": "-30d"
}
}
curl -s -X POST "https://us.posthog.com/api/projects/<project-id>/insights/" --header "Authorization: Bearer $(printenv POSTHOG_TOKEN)" --header "Content-Type: application/json" -d @/tmp/posthog_request.json | jq '{id, short_id, name}'
Delete Insight
Replace <insight-id> with the insight ID:
curl -s -X DELETE "https://us.posthog.com/api/projects/<project-id>/insights/<insight-id>/" --header "Authorization: Bearer $(printenv POSTHOG_TOKEN)"
Dashboards
List Dashboards
curl -s "https://us.posthog.com/api/projects/<project-id>/dashboards/" --header "Authorization: Bearer $(printenv POSTHOG_TOKEN)" | jq '.results[] | {id, name, description, created_at}'
Get Dashboard Details
Replace <dashboard-id> with the dashboard ID:
curl -s "https://us.posthog.com/api/projects/<project-id>/dashboards/<dashboard-id>/" --header "Authorization: Bearer $(printenv POSTHOG_TOKEN)" | jq '{id, name, description, tiles: [.tiles[] | {id, insight: .insight.name}]}'
Create Dashboard
Write to /tmp/posthog_request.json:
{
"name": "Engineering Dashboard",
"description": "Key engineering metrics"
}
curl -s -X POST "https://us.posthog.com/api/projects/<project-id>/dashboards/" --header "Authorization: Bearer $(printenv POSTHOG_TOKEN)" --header "Content-Type: application/json" -d @/tmp/posthog_request.json | jq '{id, name}'
Delete Dashboard
Replace <dashboard-id> with the dashboard ID:
curl -s -X DELETE "https://us.posthog.com/api/projects/<project-id>/dashboards/<dashboard-id>/" --header "Authorization: Bearer $(printenv POSTHOG_TOKEN)"
HogQL Queries
Run arbitrary analytics queries using HogQL (PostHog's SQL dialect).
Run a HogQL Query
Write to /tmp/posthog_request.json:
{
"query": {
"kind": "HogQLQuery",
"query": "SELECT event, count() as cnt FROM events GROUP BY event ORDER BY cnt DESC LIMIT 10"
}
}
curl -s -X POST "https://us.posthog.com/api/projects/<project-id>/query/" --header "Authorization: Bearer $(printenv POSTHOG_TOKEN)" --header "Content-Type: application/json" -d @/tmp/posthog_request.json | jq '{columns, results}'
Count Events by Day
Write to /tmp/posthog_request.json:
{
"query": {
"kind": "HogQLQuery",
"query": "SELECT toDate(timestamp) as day, count() as cnt FROM events WHERE timestamp > now() - INTERVAL 7 DAY GROUP BY day ORDER BY day DESC"
}
}
curl -s -X POST "https://us.posthog.com/api/projects/<project-id>/query/" --header "Authorization: Bearer $(printenv POSTHOG_TOKEN)" --header "Content-Type: application/json" -d @/tmp/posthog_request.json | jq '{columns, results}'
Query Persons
Write to /tmp/posthog_request.json:
{
"query": {
"kind": "HogQLQuery",
"query": "SELECT distinct_id, properties.$browser as browser, properties.$os as os FROM persons LIMIT 10"
}
}
curl -s -X POST "https://us.posthog.com/api/projects/<project-id>/query/" --header "Authorization: Bearer $(printenv POSTHOG_TOKEN)" --header "Content-Type: application/json" -d @/tmp/posthog_request.json | jq '{columns, results}'
Events
List Recent Events
curl -s "https://us.posthog.com/api/projects/<project-id>/events/?limit=10" --header "Authorization: Bearer $(printenv POSTHOG_TOKEN)" | jq '.results[] | {id, event, distinct_id, timestamp}'
Filter Events by Type
Replace $pageview with the event name you want to filter:
curl -s "https://us.posthog.com/api/projects/<project-id>/events/?event=%24pageview&limit=10" --header "Authorization: Bearer $(printenv POSTHOG_TOKEN)" | jq '.results[] | {id, event, distinct_id, timestamp, properties}'
Persons
List Persons
curl -s "https://us.posthog.com/api/projects/<project-id>/persons/" --header "Authorization: Bearer $(printenv POSTHOG_TOKEN)" | jq '.results[] | {id, distinct_ids, properties}'
Search Persons
curl -s "https://us.posthog.com/api/projects/<project-id>/persons/?search=user@example.com" --header "Authorization: Bearer $(printenv POSTHOG_TOKEN)" | jq '.results[] | {id, distinct_ids}'
Get Person Details
Replace <person-id> with the person ID:
curl -s "https://us.posthog.com/api/projects/<project-id>/persons/<person-id>/" --header "Authorization: Bearer $(printenv POSTHOG_TOKEN)" | jq '{id, distinct_ids, properties, created_at}'
Cohorts
List Cohorts
curl -s "https://us.posthog.com/api/projects/<project-id>/cohorts/" --header "Authorization: Bearer $(printenv POSTHOG_TOKEN)" | jq '.results[] | {id, name, count, created_at}'
Create Cohort
Write to /tmp/posthog_request.json:
{
"name": "Power Users",
"groups": [
{
"properties": [
{
"key": "$pageview",
"type": "behavioral",
"value": "performed_event",
"event_type": "events",
"time_value": 7,
"time_interval": "day",
"total_periods": 3
}
]
}
]
}
curl -s -X POST "https://us.posthog.com/api/projects/<project-id>/cohorts/" --header "Authorization: Bearer $(printenv POSTHOG_TOKEN)" --header "Content-Type: application/json" -d @/tmp/posthog_request.json | jq '{id, name}'
Annotations
List Annotations
curl -s "https://us.posthog.com/api/projects/<project-id>/annotations/" --header "Authorization: Bearer $(printenv POSTHOG_TOKEN)" | jq '.results[] | {id, content, date_marker, scope}'
Create Annotation
Write to /tmp/posthog_request.json:
{
"content": "Deployed v2.1.0",
"date_marker": "2026-03-10T00:00:00Z",
"scope": "organization"
}
curl -s -X POST "https://us.posthog.com/api/projects/<project-id>/annotations/" --header "Authorization: Bearer $(printenv POSTHOG_TOKEN)" --header "Content-Type: application/json" -d @/tmp/posthog_request.json | jq '{id, content, date_marker}'
Delete Annotation
Replace <annotation-id> with the annotation ID:
curl -s -X DELETE "https://us.posthog.com/api/projects/<project-id>/annotations/<annotation-id>/" --header "Authorization: Bearer $(printenv POSTHOG_TOKEN)"
Actions
List Actions
curl -s "https://us.posthog.com/api/projects/<project-id>/actions/" --header "Authorization: Bearer $(printenv POSTHOG_TOKEN)" | jq '.results[] | {id, name, steps}'
Create Action
Write to /tmp/posthog_request.json:
{
"name": "Clicked Sign Up",
"steps": [
{
"event": "$autocapture",
"properties": [
{"key": "$element_text", "value": "Sign Up", "type": "element"}
]
}
]
}
curl -s -X POST "https://us.posthog.com/api/projects/<project-id>/actions/" --header "Authorization: Bearer $(printenv POSTHOG_TOKEN)" --header "Content-Type: application/json" -d @/tmp/posthog_request.json | jq '{id, name}'
Surveys
List Surveys
curl -s "https://us.posthog.com/api/projects/<project-id>/surveys/" --header "Authorization: Bearer $(printenv POSTHOG_TOKEN)" | jq '.results[] | {id, name, type, start_date, end_date}'
Create Survey
Write to /tmp/posthog_request.json:
{
"name": "NPS Survey",
"type": "popover",
"questions": [
{
"type": "rating",
"question": "How likely are you to recommend us?",
"display": "number",
"scale": 10,
"lowerBoundLabel": "Not likely",
"upperBoundLabel": "Very likely"
}
]
}
curl -s -X POST "https://us.posthog.com/api/projects/<project-id>/surveys/" --header "Authorization: Bearer $(printenv POSTHOG_TOKEN)" --header "Content-Type: application/json" -d @/tmp/posthog_request.json | jq '{id, name, type}'
Event Definitions
List Event Definitions
Discover what events are tracked in your project:
curl -s "https://us.posthog.com/api/projects/<project-id>/event_definitions/" --header "Authorization: Bearer $(printenv POSTHOG_TOKEN)" | jq '.results[] | {name, volume_30_day, query_usage_30_day}'
Property Definitions
List Property Definitions
Discover what properties are available:
curl -s "https://us.posthog.com/api/projects/<project-id>/property_definitions/" --header "Authorization: Bearer $(printenv POSTHOG_TOKEN)" | jq '.results[] | {name, property_type, is_numerical}'
Guidelines
- Discover project ID first: Call the projects endpoint to get your project ID before using other endpoints
- Pagination: Responses use
count,next, andpreviousfields. Use?limit=N&offset=Mfor pagination - HogQL for complex queries: Use the query endpoint with HogQL for custom analytics that go beyond the standard endpoints
- Rate limits: PostHog has rate limits; implement backoff for 429 responses
- US vs EU: Use
us.posthog.comfor US Cloud oreu.posthog.comfor EU Cloud - Event names: PostHog built-in events start with
$(e.g.,$pageview,$autocapture). URL-encode the$as%24in query parameters