consuming-endpoints-from-client-code

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Consuming endpoints from client code

从客户端代码调用端点

This skill is the caller-side counterpart to
creating-an-endpoint
. It helps integrate an existing endpoint into a separate codebase — a mobile app, server backend, customer dashboard, or downstream pipeline. No PostHog code is modified here.
本技能是
creating-an-endpoint
对应的调用端技能。它可帮助将现有端点集成到独立代码库中——如移动应用、服务器后端、客户仪表板或下游流水线。此过程无需修改PostHog代码。

When to use this skill

何时使用本技能

  • "How do I call my endpoint?" / "What does a request look like?"
  • "Generate a typed TypeScript / Python / Go client for this endpoint"
  • "I'm getting a 401 calling the endpoint" / auth questions
  • "The endpoint rejects my call when I omit
    user_id
    " → materialised-endpoint variable questions
  • "How do I handle rate limits?"
If the user is creating the endpoint, use
creating-an-endpoint
first.
  • “如何调用我的端点?” / “请求格式是什么样的?”
  • “为此端点生成TypeScript/Python/Go类型化客户端”
  • “调用端点时收到401错误” / 认证相关问题
  • “省略
    user_id
    时端点拒绝我的调用” → 物化端点变量相关问题
  • “如何处理速率限制?”
如果用户是要创建端点,请先使用
creating-an-endpoint
技能。

Available tools

可用工具

ToolPurpose
endpoint-get
Full config for a named endpoint, including the query shape and required variables
endpoint-openapi-spec
OpenAPI 3.0 spec for one endpoint, ready to feed to a code generator
endpoint-run
A live call against the endpoint — useful to confirm a payload works before sharing it with the user's app
工具名称用途
endpoint-get
获取指定端点的完整配置,包括查询结构和必填变量
endpoint-openapi-spec
获取单个端点的OpenAPI 3.0规范,可直接用于代码生成器
endpoint-run
对端点发起实时调用——在将请求体提供给用户应用前,可用于验证其有效性

The endpoint URL

端点URL

text
/api/projects/{team_id}/endpoints/{name}/run
  • team_id
    is the project ID (numeric). Available in PostHog under project settings, or via
    posthog-get-projects
    if the user doesn't know it.
  • name
    is the endpoint name — see
    endpoints-get-all
    if the user isn't sure.
  • The trailing
    /run
    is required.
POST
is the canonical method.
GET
also works for simple cases without a request body but POST is preferred — variables go in the body.
text
/api/projects/{team_id}/endpoints/{name}/run
  • team_id
    是项目ID(数字类型)。可在PostHog的项目设置中查看,若用户不知道,可通过
    posthog-get-projects
    获取。
  • name
    是端点名称——若用户不确定,可查看
    endpoints-get-all
    的结果。
  • 末尾的
    /run
    是必填项。
标准请求方法为
POST
。对于无请求体的简单场景,
GET
也可使用,但推荐使用
POST
——变量需放在请求体中。

Auth

认证

Endpoints are authenticated with a personal API key. The header is:
http
Authorization: Bearer <key>
Keys are scoped — for endpoints, the key needs at least
endpoint:read
. If the user gets a 403, they're usually missing the scope; if they get a 401, the key is missing or malformed.
Never put a personal API key in client-side code that's shipped to end users (mobile apps, browser JS). Personal API keys grant scoped account access. For customer-facing apps, route through the user's own backend, which holds the key.
端点通过个人API密钥进行认证,请求头格式如下:
http
Authorization: Bearer <key>
密钥具有权限范围——对于端点,密钥至少需要
endpoint:read
权限。若用户收到403错误,通常是缺少对应权限;若收到401错误,则是密钥缺失或格式错误。
切勿将个人API密钥放入交付给终端用户的客户端代码中(如移动应用、浏览器JS)。个人API密钥拥有账户的范围权限。面向客户的应用应通过用户自身的后端进行路由,由后端保管密钥。

The request payload

请求体

json
{
  "variables": { "code_name_1": value, "code_name_2": value },
  "limit": 100,
  "offset": 0,
  "refresh": "cache"
}
FieldNotes
variables
Keyed by
code_name
for HogQL endpoints; for insight endpoints with breakdowns, key is the breakdown property name
limit
Max rows returned.
offset
Skip rows. Only HogQL endpoints
refresh
"cache"
(return cached results if fresh enough),
"force"
(always recalculate),
"direct"
(bypass materialisation, materialised endpoints only). Default is
"cache"
Call
endpoint-get
to see the exact variable shape. The response includes the query definition with declared variables — each variable's
code_name
is what the client should send.
json
{
  "variables": { "code_name_1": value, "code_name_2": value },
  "limit": 100,
  "offset": 0,
  "refresh": "cache"
}
字段说明
variables
对于HogQL端点,键为
code_name
;对于带细分的洞察端点,键为细分属性名称
limit
返回的最大行数。
offset
跳过的行数。仅适用于HogQL端点
refresh
可选值:
"cache"
(若缓存足够新则返回缓存结果)、
"force"
(始终重新计算)、
"direct"
(绕过物化,仅适用于物化端点)。默认值为
"cache"
调用
endpoint-get
可查看确切的变量结构。响应结果包含带声明变量的查询定义——客户端应发送每个变量的
code_name

Materialised endpoints: all variables are required

物化端点:所有变量均为必填项

If
endpoint-get
shows
is_materialized: true
on the current version, the endpoint requires every declared variable to be passed on each call. This is a security boundary — without filters, a single call would return the entire pre-aggregated dataset.
Common symptom: the user's app worked when the endpoint was unmaterialised, then started returning 400 errors after materialisation was enabled. The error message lists which variables are missing.
Optional/partial variables on materialised endpoints are a known limitation the PostHog team plans to lift. If requiring every variable is blocking the user's use case, send a note via the
agent-feedback
tool — that demand signal is how the team prioritises it.
endpoint-get
显示当前版本的
is_materialized: true
,则该端点要求每次调用都必须传入所有声明的变量。这是一个安全边界——若没有过滤器,单次调用会返回整个预聚合数据集。
常见问题:用户的应用在端点未物化时正常工作,但启用物化后开始返回400错误。错误消息会列出缺失的变量。
物化端点不支持可选/部分变量是PostHog团队已知的限制,计划后续解除。若要求传入所有变量阻碍了用户的使用场景,请通过
agent-feedback
工具提交反馈——这类需求信号是团队优先处理的依据。

Generating a typed client

生成类型化客户端

The endpoint exposes its own OpenAPI 3.0 spec via
endpoint-openapi-spec
. Feed that into a code generator:
LanguageToolCommand shape
TypeScript
@hey-api/openapi-ts
openapi-ts -i spec.json -o ./generated
TypeScript
openapi-generator-cli
openapi-generator-cli generate -i spec.json -g typescript-fetch -o ./generated
Python
openapi-generator-cli
openapi-generator-cli generate -i spec.json -g python -o ./generated
Go
oapi-codegen
oapi-codegen -package=client spec.json > client.go
The generated client gives the user types for the variables payload and the response shape. Re- generate when the endpoint's query changes (each new version may have different variables).
If the user has multiple endpoints, generate a spec per endpoint and either combine them, or generate one client per endpoint and use them side-by-side.
端点通过
endpoint-openapi-spec
暴露自身的OpenAPI 3.0规范。可将其输入到代码生成器中:
语言工具名称命令格式
TypeScript
@hey-api/openapi-ts
openapi-ts -i spec.json -o ./generated
TypeScript
openapi-generator-cli
openapi-generator-cli generate -i spec.json -g typescript-fetch -o ./generated
Python
openapi-generator-cli
openapi-generator-cli generate -i spec.json -g python -o ./generated
Go
oapi-codegen
oapi-codegen -package=client spec.json > client.go
生成的客户端可为用户提供变量请求体和响应结构的类型定义。当端点查询发生变化时(每个新版本可能有不同的变量),需重新生成客户端。
若用户有多个端点,可为每个端点生成一份规范,要么合并它们,要么为每个端点生成一个客户端并并行使用。

Response shape

响应结构

A typical successful response:
json
{
  "results": [[...], [...]],
  "columns": ["col_a", "col_b"],
  "types": ["Int64", "String"],
  "hasMore": false,
  "name": "endpoint_name",
  "endpoint_version": 4,
  "endpoint_version_created_at": "2026-01-15T..."
}
  • results
    is an array of rows; each row is an array of cell values in the order of
    columns
    .
  • endpoint_version
    tells the client which version actually ran — useful for logging and for pinning to a known version with
    ?version=N
    .
For insight endpoints, the response shape depends on the query kind (
TrendsQuery
,
LifecycleQuery
,
RetentionQuery
) — the OpenAPI spec captures the right shape for the current version. Insight kinds that can't be materialised (e.g.
FunnelsQuery
) still return their inline result shape.
典型的成功响应:
json
{
  "results": [[...], [...]],
  "columns": ["col_a", "col_b"],
  "types": ["Int64", "String"],
  "hasMore": false,
  "name": "endpoint_name",
  "endpoint_version": 4,
  "endpoint_version_created_at": "2026-01-15T..."
}
  • results
    是行数组;每行是按
    columns
    顺序排列的单元格值数组。
  • endpoint_version
    告知客户端实际运行的端点版本——便于日志记录,也可通过
    ?version=N
    固定到已知版本。
对于洞察端点,响应结构取决于查询类型(
TrendsQuery
LifecycleQuery
RetentionQuery
)——OpenAPI规范会捕获当前版本的正确结构。无法物化的洞察类型(如
FunnelsQuery
)仍返回其内置结果结构。

Calling from the PostHog CLI

使用PostHog CLI调用

For local testing, scripts, or CI, the repo's
posthog-cli
calls endpoints without hand-rolling HTTP:
  • posthog-cli exp endpoints run
    — execute an endpoint (from a local YAML definition)
  • posthog-cli exp endpoints {list,get,pull,push,diff}
    — inspect endpoints, or manage them as YAML files in version control (GitOps-style)
Auth uses the same personal API key, via
posthog-cli login
or the
POSTHOG_CLI_API_KEY
/
POSTHOG_CLI_PROJECT_ID
/
POSTHOG_CLI_HOST
env vars. (These live under
exp
— experimental, may change.)
对于本地测试、脚本或CI流程,仓库中的
posthog-cli
可无需手动编写HTTP代码即可调用端点:
  • posthog-cli exp endpoints run
    —— 执行端点(基于本地YAML定义)
  • posthog-cli exp endpoints {list,get,pull,push,diff}
    —— 查看端点,或通过版本控制(GitOps风格)将其作为YAML文件管理
认证使用相同的个人API密钥,可通过
posthog-cli login
POSTHOG_CLI_API_KEY
/
POSTHOG_CLI_PROJECT_ID
/
POSTHOG_CLI_HOST
环境变量配置。(这些功能位于
exp
下——属于实验性功能,可能会变更。)

Error responses to handle

需要处理的错误响应

StatusWhenHandling
400Missing required variable on a materialised endpoint, or invalid variable typeSurface the error message; fix the call
401Missing / wrong personal API keyCheck the Authorization header
403Key lacks
endpoint:read
scope, or endpoint is in another project
Adjust key scopes
404Endpoint name typo, or endpoint not activeConfirm name; check
is_active
429Rate limited — limits are per team, not per endpoint (see note below)Exponential backoff; cache responses client-side if possible
5xxQuery execution failure (ClickHouse error, timeout, etc.)Retry with backoff. If persistent, hand off to
diagnosing-endpoint-performance
状态码触发场景处理方式
400物化端点缺少必填变量,或变量类型无效显示错误消息;修正调用请求
401缺少/错误的个人API密钥检查Authorization请求头
403密钥缺少
endpoint:read
权限,或端点属于其他项目
调整密钥权限
404端点名称拼写错误,或端点未激活确认名称;检查
is_active
状态
429触发速率限制——限制是按团队而非端点设置(见下方说明)指数退避重试;尽可能在客户端缓存响应
5xx查询执行失败(ClickHouse错误、超时等)退避重试。若问题持续,移交至
diagnosing-endpoint-performance
技能处理

Workflow

工作流程

  1. Confirm endpoint name. If unknown, list them with
    execute-sql
    on
    system.data_modeling_endpoints
    (or
    endpoints-get-all
    ).
  2. endpoint-get
    to see the full shape: variables, materialisation status, query kind.
  3. Decide the auth posture: personal API key on a server, never client-side.
  4. If the user wants generated types, call
    endpoint-openapi-spec
    , hand them the spec, and recommend a generator for their language.
  5. Build a sample request payload from the variable declarations and walk through a test call.
  6. Optionally call
    endpoint-run
    from this skill to confirm the payload works.
  7. Wrap up with handling notes: the materialised-variables rule, the rate-limit shape, and pinning to a version with
    ?version=N
    .
  1. 确认端点名称。若未知,可通过在
    system.data_modeling_endpoints
    上执行
    execute-sql
    (或
    endpoints-get-all
    )列出所有端点。
  2. 调用
    endpoint-get
    查看完整结构:变量、物化状态、查询类型。
  3. 确定认证方式:个人API密钥仅用于服务器端,绝不能用于客户端。
  4. 若用户需要生成类型,调用
    endpoint-openapi-spec
    获取规范,提供给用户,并为其推荐对应语言的生成器。
  5. 根据变量声明构建示例请求体,并引导用户完成测试调用。
  6. 可选:使用本技能调用
    endpoint-run
    验证请求体是否有效。
  7. 收尾时告知注意事项:物化变量规则、速率限制机制,以及通过
    ?version=N
    固定版本的方法。

Example interaction

交互示例

text
User: "I want to call monthly_active_users from my Node.js backend.
       Can you help me wire it up with types?"

Agent steps:
- endpoint-get monthly_active_users → HogQL, variables: lookback_days
  (int, default 30), org_id (string, no default), is_materialized: true
- "Two things to know upfront:
   1. This endpoint is materialised, so both lookback_days and org_id
      must be passed on every call. Calls without them will be rejected.
   2. You'll need a personal API key with endpoint:read scope. Set it
      as PH_API_KEY in your server env — never ship it in client code."

- endpoint-openapi-spec monthly_active_users → returns spec

- "Here's the spec. Drop it in your repo and run:
     pnpm dlx @hey-api/openapi-ts -i spec.json -o ./generated/posthog
   That gives you typed client functions.

   A minimum call looks like:
     POST /api/projects/12345/endpoints/monthly_active_users/run
     Authorization: Bearer <PH_API_KEY>
     Content-Type: application/json

     { 'variables': { 'org_id': 'acme', 'lookback_days': 30 } }

   The response includes columns and rows — your client will pick that
   up from the generated types.

   Want me to do a sample call to verify the payload works?"
text
用户:“我想从Node.js后端调用monthly_active_users端点。你能帮我接入并添加类型吗?”

Agent步骤:
- 调用endpoint-get monthly_active_users → 结果为HogQL类型,变量:lookback_days(整数,默认30)、org_id(字符串,无默认值),is_materialized: true
- “有两点需要提前说明:
   1. 该端点已物化,因此每次调用必须同时传入lookback_days和org_id。缺少任一变量的调用都会被拒绝。
   2. 你需要一个拥有endpoint:read权限的个人API密钥。将其设置为服务器环境变量PH_API_KEY——切勿将其嵌入客户端代码中。”

- 调用endpoint-openapi-spec monthly_active_users → 返回规范

- “这是规范文件。将其放入你的仓库并运行:
     pnpm dlx @hey-api/openapi-ts -i spec.json -o ./generated/posthog
   运行后会得到类型化的客户端函数。

   最简调用示例如下:
     POST /api/projects/12345/endpoints/monthly_active_users/run
     Authorization: Bearer <PH_API_KEY>
     Content-Type: application/json

     { 'variables': { 'org_id': 'acme', 'lookback_days': 30 } }

   响应结果包含columns和rows——生成的类型会自动识别这些结构。

   需要我发起一次示例调用来验证请求体是否有效吗?”

Important notes

重要说明

  • Personal API keys are server-side only. Never ship them in mobile apps or browser JS.
  • Re-generate the client when the query changes. Each new endpoint version may add or remove variables — keep types in sync by re-fetching the spec.
  • Materialised endpoints reject calls missing variables. This is intentional. If the user reports a 400 after materialisation was enabled, the fix is in the call, not in the endpoint.
  • Pin to a version — don't rely on "latest". Always call with
    ?version=N
    . Without it the latest active version runs, so a future query edit (which cuts a new version) can silently change a caller's results. Bump the pinned version deliberately once you've validated the new one.
  • Caching on the client side is fair game. The endpoint already caches via
    data_freshness_seconds
    , but the client can layer another cache on top for hot paths. Be mindful of total staleness (endpoint cache + client cache).
  • Rate limits are per team, by category — not per endpoint. Calls to non-materialised endpoints share the team-wide API-query budget (~240/min burst, ~2400/hour sustained) with all other query traffic; materialised endpoints draw on a separate, higher shared bucket (~1200/min, ~12000/hour). There is no per-endpoint-name limit, so hammering one endpoint can starve others on the same team. Heavy callers should batch where possible and back off on 429.
  • Pricing. Calling endpoints isn't billed today, but it will be once endpoints ship alongside the managed warehouse. Flag this to the user if they're planning high-volume usage so the future cost isn't a surprise.
  • Tell PostHog what's missing. If an error, a limit, or a missing capability gets in the way, use the
    agent-feedback
    tool — it's the main signal the team uses to improve endpoints and these tools.
  • 个人API密钥仅可用于服务器端。切勿将其嵌入移动应用或浏览器JS中。
  • 查询变更时重新生成客户端。每个端点新版本可能添加或移除变量——通过重新获取规范保持类型同步。
  • 物化端点会拒绝缺少变量的调用。这是有意设计的。若用户反馈启用物化后收到400错误,需修正调用请求,而非修改端点。
  • 固定版本——不要依赖“最新版”。调用时务必加上
    ?version=N
    。若不指定,会运行最新的激活版本,因此未来的查询编辑(会生成新版本)可能会悄然改变调用方的结果。验证新版本无误后,再主动更新固定的版本号。
  • 客户端缓存是可行的。端点已通过
    data_freshness_seconds
    实现缓存,但客户端可在热门路径上再添加一层缓存。需注意总过期时间(端点缓存+客户端缓存)。
  • 速率限制按团队、按类别设置——而非按端点。非物化端点的调用与其他所有查询流量共享团队级别的API查询配额(突发约240次/分钟,持续约2400次/小时);物化端点使用单独的、更高的共享配额(约1200次/分钟,约12000次/小时)。没有按端点名称设置的限制,因此频繁调用某个端点可能会影响团队内其他端点的使用。高调用量的场景应尽可能批量处理,并在收到429错误时退避重试。
  • 定价说明。目前调用端点不收费,但当端点与托管数据仓库一同推出后,将会收费。若用户计划高频率使用,需告知此信息,避免未来产生意外成本。
  • 告知PostHog缺失的功能。若遇到错误、限制或缺失的功能阻碍了使用,请使用
    agent-feedback
    工具提交反馈——这是团队改进端点及相关工具的主要信号。