/api/public. Get an API key, read Authorization, and use Ad accounts to find ad_account_id before you start. The examples use sample UUIDs. Replace them with your own IDs. Each curl block has a copy control.
List metrics
GET /api/public/custom-metrics
Set the required ad_account_id. You can filter by query, status (active, archived, or all), or entity_level. Use limit (1–100, default 50) and cursor for more pages.
Request
next_cursor.
Create a metric
POST /api/public/custom-metrics
Send a unique Idempotency-Key header and the metric definition. The account UUID comes from Ad accounts.
Request
Get a metric
GET /api/public/custom-metrics/{metric_id}
Set the metric UUID in the path and ad_account_id in the query.
Request
Edit a metric
PATCH /api/public/custom-metrics/{metric_id}
Send ad_account_id and the last updated_at from a read. This prevents an edit from overwriting a newer definition. You can change the label, description, input levels, or status.
Request
updated_at returns a conflict. Read the metric again before you retry.
Download the CSV template
GET /api/public/custom-metrics/template.csv
Set ad_account_id. This route returns the current CSV format and metric keys for that account. Save the response as a file before you prepare a CSV import.
Request
Prepare JSON rows
POST /api/public/custom-metric-imports
Send an account UUID, an idempotency key, and up to 1,000 daily rows. value is a decimal string. Use a closed date in the account time zone.
Request
"0"; a missing row leaves a stored value unchanged.
Prepare a CSV file
POST /api/public/custom-metric-imports/file
Send the current CSV template with rows as multipart form data. The account and idempotency key are form fields.
Request
List imports
GET /api/public/custom-metric-imports
Set ad_account_id. Use limit (1–100, default 50) and cursor to read more tasks.
Request
Get an import
GET /api/public/custom-metric-imports/{import_id}
Use the task_id from a prepare response as import_id. Set ad_account_id. You can send error_cursor to read more validation errors.
Request
status is completed or failed. A failed task can have some values applied; check counts and progress.
Commit an import
POST /api/public/custom-metric-imports/{import_id}/commit
Commit a valid prepared task after you check its preview. Set ad_account_id in the query.
Request
Create a CSV upload grant
POST /api/public/custom-metric-upload-grants
Use this route if your client cannot send a multipart file. Send the file name, exact byte size, content type, account, and idempotency key.
Request
authorization value out of logs. Use the returned URL and header for the upload.
Upload CSV bytes
PUT /api/public/custom-metric-uploads/{upload_id}
Send raw CSV bytes to the exact upload_url from the grant. Use its authorization value, not the team API key. The uploaded file prepares an import task.
Request
Query metric values
POST /api/public/metrics/query
Send an account UUID, entity level, metric references, and date range. Use custom:<metric_uuid> for a custom metric. grain is daily or period. The response can also include supported provider metrics.
Request
cursor and limit for more rows. A missing metric value stays null. Reads can include corrections from an active or failed import.
See Import custom metrics for the app flow and Custom metric MCP tools for agent calls.