Management APIs
Annotations
Mark important events in your charts
POST
/
api
/
app
/
projects
/
{projectId}
/
annotations
Annotations
curl --request POST \
--url https://mixpanel.com/api/app/projects/{projectId}/annotations \
--header 'Content-Type: application/json' \
--data '
{
"date": "<string>",
"description": "<string>",
"tags": [
{}
]
}
'import requests
url = "https://mixpanel.com/api/app/projects/{projectId}/annotations"
payload = {
"date": "<string>",
"description": "<string>",
"tags": [{}]
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({date: '<string>', description: '<string>', tags: [{}]})
};
fetch('https://mixpanel.com/api/app/projects/{projectId}/annotations', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://mixpanel.com/api/app/projects/{projectId}/annotations",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'date' => '<string>',
'description' => '<string>',
'tags' => [
[
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://mixpanel.com/api/app/projects/{projectId}/annotations"
payload := strings.NewReader("{\n \"date\": \"<string>\",\n \"description\": \"<string>\",\n \"tags\": [\n {}\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://mixpanel.com/api/app/projects/{projectId}/annotations")
.header("Content-Type", "application/json")
.body("{\n \"date\": \"<string>\",\n \"description\": \"<string>\",\n \"tags\": [\n {}\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://mixpanel.com/api/app/projects/{projectId}/annotations")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"date\": \"<string>\",\n \"description\": \"<string>\",\n \"tags\": [\n {}\n ]\n}"
response = http.request(request)
puts response.read_bodyAnnotations API
Create and manage annotations to mark important events in your Mixpanel charts.Base URL
https://mixpanel.com/api/app/projects/{projectId}/annotations
Authentication
Use Service Account credentials with HTTP Basic Auth.List Annotations
Get all annotations in a project.number
required
Your Mixpanel project ID
string
Filter annotations from this date (
YYYY-MM-DD HH:mm:ss)string
Filter annotations to this date (
YYYY-MM-DD HH:mm:ss)Example Request
curl "https://mixpanel.com/api/app/projects/123/annotations" \
-u SERVICE_ACCOUNT_USERNAME:SERVICE_ACCOUNT_SECRET
import requests
from requests.auth import HTTPBasicAuth
response = requests.get(
'https://mixpanel.com/api/app/projects/123/annotations',
auth=HTTPBasicAuth('SERVICE_ACCOUNT_USERNAME', 'SERVICE_ACCOUNT_SECRET')
)
annotations = response.json()
print(f"Total annotations: {len(annotations['results'])}")
Create Annotation
Create a new annotation.number
required
Your Mixpanel project ID
string
required
Date and time in
YYYY-MM-DD HH:mm:ss formatExample: 2024-01-15 12:00:00string
required
The text to display for this annotationExample:
Product launch - v2.0array
Array of tag IDs to associate with the annotation
Example Request
curl "https://mixpanel.com/api/app/projects/123/annotations" \
-X POST \
-u SERVICE_ACCOUNT_USERNAME:SERVICE_ACCOUNT_SECRET \
-H "Content-Type: application/json" \
-d '{
"date": "2024-01-15 12:00:00",
"description": "Launched new homepage design",
"tags": [1, 2]
}'
import requests
from requests.auth import HTTPBasicAuth
response = requests.post(
'https://mixpanel.com/api/app/projects/123/annotations',
auth=HTTPBasicAuth('SERVICE_ACCOUNT_USERNAME', 'SERVICE_ACCOUNT_SECRET'),
json={
'date': '2024-01-15 12:00:00',
'description': 'Launched new homepage design',
'tags': [1, 2]
}
)
annotation = response.json()
print(f"Created annotation ID: {annotation['results']['id']}")
Response
{
"status": "ok",
"results": {
"id": 12345,
"date": "2024-01-15 12:00:00",
"description": "Launched new homepage design",
"user": {
"id": 789,
"first_name": "John",
"last_name": "Doe"
},
"tags": [
{"id": 1, "name": "Product"},
{"id": 2, "name": "Launch"}
]
}
}
Get Annotation
Retrieve details of a specific annotation.number
required
Your Mixpanel project ID
number
required
The ID of the annotation
Example Request
curl "https://mixpanel.com/api/app/projects/123/annotations/12345" \
-u SERVICE_ACCOUNT_USERNAME:SERVICE_ACCOUNT_SECRET
Update Annotation
Update an existing annotation.number
required
Your Mixpanel project ID
number
required
The ID of the annotation to update
string
Updated description text
array
Updated array of tag IDs
Example Request
curl "https://mixpanel.com/api/app/projects/123/annotations/12345" \
-X PATCH \
-u SERVICE_ACCOUNT_USERNAME:SERVICE_ACCOUNT_SECRET \
-H "Content-Type: application/json" \
-d '{
"description": "Updated: Launched new homepage with A/B test",
"tags": [1, 2, 3]
}'
import requests
from requests.auth import HTTPBasicAuth
response = requests.patch(
'https://mixpanel.com/api/app/projects/123/annotations/12345',
auth=HTTPBasicAuth('SERVICE_ACCOUNT_USERNAME', 'SERVICE_ACCOUNT_SECRET'),
json={
'description': 'Updated: Launched new homepage with A/B test',
'tags': [1, 2, 3]
}
)
print(response.json())
Delete Annotation
Permanently delete an annotation.number
required
Your Mixpanel project ID
number
required
The ID of the annotation to delete
Example Request
curl "https://mixpanel.com/api/app/projects/123/annotations/12345" \
-X DELETE \
-u SERVICE_ACCOUNT_USERNAME:SERVICE_ACCOUNT_SECRET
import requests
from requests.auth import HTTPBasicAuth
response = requests.delete(
'https://mixpanel.com/api/app/projects/123/annotations/12345',
auth=HTTPBasicAuth('SERVICE_ACCOUNT_USERNAME', 'SERVICE_ACCOUNT_SECRET')
)
result = response.json()
print(f"Deleted annotation ID: {result['results']['id']}")
Manage Annotation Tags
List All Tags
curl "https://mixpanel.com/api/app/projects/123/annotations/tags" \
-u SERVICE_ACCOUNT_USERNAME:SERVICE_ACCOUNT_SECRET
Create Tag
curl "https://mixpanel.com/api/app/projects/123/annotations/tags" \
-X POST \
-u SERVICE_ACCOUNT_USERNAME:SERVICE_ACCOUNT_SECRET \
-H "Content-Type: application/json" \
-d '{"name": "Marketing Campaign"}'
import requests
from requests.auth import HTTPBasicAuth
response = requests.post(
'https://mixpanel.com/api/app/projects/123/annotations/tags',
auth=HTTPBasicAuth('SERVICE_ACCOUNT_USERNAME', 'SERVICE_ACCOUNT_SECRET'),
json={'name': 'Marketing Campaign'}
)
tag = response.json()
print(f"Created tag ID: {tag['id']}")
Best Practices
Use meaningful descriptions
Use meaningful descriptions
Include context about what happened:
{
"description": "Product Launch: v2.0 - New checkout flow",
"date": "2024-01-15 14:00:00"
}
Tag annotations for filtering
Tag annotations for filtering
Create tags for different categories:
- Product launches
- Marketing campaigns
- Bug fixes
- Infrastructure changes
Automate annotation creation
Automate annotation creation
Create annotations programmatically during deployments:
import requests
import os
def create_deployment_annotation(version):
requests.post(
f'https://mixpanel.com/api/app/projects/{os.getenv("PROJECT_ID")}/annotations',
auth=(os.getenv("MP_USERNAME"), os.getenv("MP_SECRET")),
json={
'date': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
'description': f'Deployed version {version}'
}
)
Annotations
curl --request POST \
--url https://mixpanel.com/api/app/projects/{projectId}/annotations \
--header 'Content-Type: application/json' \
--data '
{
"date": "<string>",
"description": "<string>",
"tags": [
{}
]
}
'import requests
url = "https://mixpanel.com/api/app/projects/{projectId}/annotations"
payload = {
"date": "<string>",
"description": "<string>",
"tags": [{}]
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({date: '<string>', description: '<string>', tags: [{}]})
};
fetch('https://mixpanel.com/api/app/projects/{projectId}/annotations', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://mixpanel.com/api/app/projects/{projectId}/annotations",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'date' => '<string>',
'description' => '<string>',
'tags' => [
[
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://mixpanel.com/api/app/projects/{projectId}/annotations"
payload := strings.NewReader("{\n \"date\": \"<string>\",\n \"description\": \"<string>\",\n \"tags\": [\n {}\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://mixpanel.com/api/app/projects/{projectId}/annotations")
.header("Content-Type", "application/json")
.body("{\n \"date\": \"<string>\",\n \"description\": \"<string>\",\n \"tags\": [\n {}\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://mixpanel.com/api/app/projects/{projectId}/annotations")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"date\": \"<string>\",\n \"description\": \"<string>\",\n \"tags\": [\n {}\n ]\n}"
response = http.request(request)
puts response.read_body