curl --request GET \
--url https://server.codeium.com/api/v2alpha/analytics/tools \
--header 'Authorization: Bearer <token>'import requests
url = "https://server.codeium.com/api/v2alpha/analytics/tools"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://server.codeium.com/api/v2alpha/analytics/tools', 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://server.codeium.com/api/v2alpha/analytics/tools",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://server.codeium.com/api/v2alpha/analytics/tools"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://server.codeium.com/api/v2alpha/analytics/tools")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://server.codeium.com/api/v2alpha/analytics/tools")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"data": [
{
"user_id": "user_abc123",
"user_email": "alice@example.com",
"tool": "RUN_COMMAND",
"calls": 1842
},
{
"user_id": "user_abc123",
"user_email": "alice@example.com",
"tool": "SEARCH_WEB",
"calls": 57
}
],
"pagination": {
"next_page_cursor": null
},
"metadata": {
"data_freshness": "2026-10-20T02:00:00Z",
"query_time_ms": 1104,
"team_id": "team_abc123"
}
}Get Devin Agent Tool Calls
Count agent tool calls, such as web search or run command, made by your team in Devin Desktop and the Devin CLI, grouped by tool, user, model, IDE, or OS.
curl --request GET \
--url https://server.codeium.com/api/v2alpha/analytics/tools \
--header 'Authorization: Bearer <token>'import requests
url = "https://server.codeium.com/api/v2alpha/analytics/tools"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://server.codeium.com/api/v2alpha/analytics/tools', 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://server.codeium.com/api/v2alpha/analytics/tools",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://server.codeium.com/api/v2alpha/analytics/tools"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://server.codeium.com/api/v2alpha/analytics/tools")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://server.codeium.com/api/v2alpha/analytics/tools")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"data": [
{
"user_id": "user_abc123",
"user_email": "alice@example.com",
"tool": "RUN_COMMAND",
"calls": 1842
},
{
"user_id": "user_abc123",
"user_email": "alice@example.com",
"tool": "SEARCH_WEB",
"calls": 57
}
],
"pagination": {
"next_page_cursor": null
},
"metadata": {
"data_freshness": "2026-10-20T02:00:00Z",
"query_time_ms": 1104,
"team_id": "team_abc123"
}
}Authentication
This endpoint uses Bearer token authentication. Include your token in theAuthorization header:
Authorization: Bearer <your_token>
cascade_tool_usage
data source, this endpoint accepts Devin service user API keys, so teams on the Cognition platform can
report tool usage without a Windsurf service key.
Metrics
Themetric query parameter is required and currently accepts only calls, the number of tool calls
the agent made. It appears as an integer calls field on every row. Requests without metric, or
naming another metric, fail with 400.
Tool calls are counted when the agent invokes a tool in Devin Desktop
or the Devin CLI (including the CLI running as an agent inside other editors), from any model.
The product parameter is also required and currently accepts only agent.
Tools
Group bytool to break calls down by tool category. Each row then includes a tool field with one of
the following values:
| Tool | Description |
|---|---|
SEARCH_WEB | Web search, web fetch, and browser use |
RUN_COMMAND | Shell commands and interacting with running processes |
VIEW_FILE | Reading files and notebooks |
CODE_ACTION | Editing, writing, and patching files |
GREP_SEARCH | Searching file contents and code |
FIND | Finding files by name |
LIST_DIRECTORY | Listing directories |
MCP_TOOL | Calling MCP server tools and listing MCP servers, tools, or resources |
SKILL | Listing, searching, and invoking skills |
ASK_USER_QUESTION | Asking the user a question |
MEMORY | Reading and writing memories |
PROPOSE_CODE | Proposing code changes |
PROXY_WEB_SERVER | Browser preview of a local web server |
DEPLOY_WEB_APP | Deploying a web app |
MQUERY | Codebase search (Riptide) |
DEEPWIKI | DeepWiki requests |
CODEMAP_GENERATION, CODEMAP_SUGGESTIONS | Codemaps requests |
OTHER | Devin CLI tools not in the categories above |
LIST_DIRECTORY, MEMORY, PROPOSE_CODE,
PROXY_WEB_SERVER, DEPLOY_WEB_APP, and MQUERY are recorded for the Devin Desktop agent, while new
Devin CLI tools that have not been assigned a category are counted under OTHER.
Grouping and Granularity
Usegranularity and group_by to control the shape of returned data:
- No granularity or grouping — returns a single aggregated row for the entire date range
granularity=daily— each row includes atimestampinYYYY-MM-DDformatgranularity=monthly— each row includes atimestampinYYYY-MMformatgroup_by=tool— each row includes atool(see Tools above)group_by=user— each row includes auser_id, plus auser_emailwhen one is recorded for that usergroup_by=model_uid— each row includes amodel_uidgroup_by=ide— each row includes anidegroup_by=ide,ide_version— each row includesideandide_version(grouping byide_versionrequiresideto also be included)group_by=os— each row includes anos, such asdarwin(macOS),windows, orlinux
group_by=user,tool reports how often each user invoked each
tool. The session and source dimensions from Get Output
are not supported here. The same models, group_id, and user_id filters as
Get Consumption apply, plus a tool filter that
restricts the count to one tool category (for example tool=SEARCH_WEB). tool is only accepted by
this endpoint; passing it to another Analytics API v2 endpoint fails with 400.
Example
Count web searches per user for a week:curl "https://server.codeium.com/api/v2alpha/analytics/tools?metric=calls&product=agent&start_date=2026-10-13&end_date=2026-10-19&group_by=user&tool=SEARCH_WEB" \
-H "Authorization: Bearer $DEVIN_API_KEY"
SEARCH_WEB count. Drop the tool filter and add group_by=user,tool to see every
category per user instead.
Pagination
Results are paginated with a default page size of 1,000 rows (max 10,000). When more results are available, the response includes anext_page_cursor in the pagination object. Pass it as the page_cursor query
parameter on a request that otherwise repeats the original query parameters. Cursors are bound to the endpoint that issued them; a cursor from /consumption or /output
is rejected with 400.
Page cursors expire after 24 hours. A follow-up page request does not count as a new query against your rate limit.
Rate Limits
This endpoint is rate-limited to 10 requests per hour per team. If you exceed this limit, the server returns429 Too Many Requests with a Retry-After header.
Paginating an earlier query (following a next_page_cursor) does not count against this limit —
only the initial query for each report does. The low limit reflects that this endpoint is for
periodic reporting, not real-time usage monitoring.Authorizations
A service key with Analytics Read permission, passed as a Bearer token in the Authorization header.
Create a service key in your team settings under the "Service Keys" section.
Query Parameters
Metric to return; appears as a field on every row. Supported metrics:
calls— number of tool calls the agent made
Start of the date range (inclusive) in YYYY-MM-DD format.
End of the date range (inclusive) in YYYY-MM-DD format. The range must not exceed 90 days.
Product to query tool calls for.
agent Time granularity for grouping results. When specified, each row includes a timestamp field.
If omitted, results are aggregated across the entire date range.
daily, monthly Comma-separated list of dimensions to group results by. Supported dimensions:
tool— includestoolin each row (the tool category, such asSEARCH_WEBorRUN_COMMAND)user— includesuser_idin each row, plususer_emailwhen one is recorded for the usermodel_uid— includesmodel_uidin each rowide— includesidein each rowide_version— includeside_versionin each row; requiresideto also be includedos— includesosin each row
Comma-separated list of model UIDs to filter results to.
Restrict the count to one tool category, such as SEARCH_WEB or RUN_COMMAND (exact match).
Only accepted by this endpoint.
Filter results to users in a specific group. The service key must have access to this group. Not supported with Devin service user API keys.
Filter results to a specific user (auth UID).
Maximum number of rows to return per page.
1 <= x <= 10000Opaque cursor from a previous response's pagination.next_page_cursor to fetch the next page. Pass the same metric as the request that issued it; cursors issued by other endpoints are rejected.

