curl --request GET \
--url https://app.sideshift.app/api/oauth/v1/analytics/accounts \
--header 'Authorization: Bearer <token>'import requests
url = "https://app.sideshift.app/api/oauth/v1/analytics/accounts"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://app.sideshift.app/api/oauth/v1/analytics/accounts', 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://app.sideshift.app/api/oauth/v1/analytics/accounts",
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://app.sideshift.app/api/oauth/v1/analytics/accounts"
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://app.sideshift.app/api/oauth/v1/analytics/accounts")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.sideshift.app/api/oauth/v1/analytics/accounts")
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": {
"data": [
{
"handle": "@janecreator",
"platform": "tiktok",
"contractorId": "prog_abc123",
"contractorName": "Spring TikTok Push",
"isGhostHandle": true,
"totalPosts": 3,
"totalViews": 3,
"totalLikes": 3,
"totalComments": 3,
"totalShares": 3,
"totalBookmarks": 3,
"totalEngagement": 3,
"engagementRate": 5,
"averageViewsPerPost": 123,
"averageEngagementPerPost": 123,
"contracts": [
"string"
],
"programs": [
"string"
],
"contractCount": 3,
"programCount": 3,
"firstPostDate": 1786597707000,
"lastPostDate": 1786597707000
}
],
"page": 3,
"limit": 3,
"total": 3,
"totalPages": 3,
"summary": {
"totalAccounts": 3,
"totalPosts": 3,
"totalViews": 3,
"totalLikes": 3,
"totalEngagement": 3,
"averageEngagementRate": 5,
"platformBreakdown": {},
"ghostHandles": 123,
"realHandles": 123
},
"filters": {
"sortBy": "string",
"sortOrder": "string",
"excludeDeletedVideos": false
}
}
}{
"error": {
"code": "unauthorized",
"message": "Missing bearer access token",
"requestId": "req_..."
}
}{
"error": {
"code": "insufficient_scope",
"message": "Requires scope 'campaigns:write'",
"requestId": "req_..."
}
}{
"error": {
"code": "not_found",
"message": "Resource not found",
"requestId": "req_..."
}
}{
"error": {
"code": "rate_limited",
"message": "Rate limit exceeded",
"requestId": "req_..."
}
}Tracked account analytics
Tracked social accounts (grouped by creator:platform) with per-account analytics and a cross-account summary, for the request’s effective company. Requires the analytics:read scope.
curl --request GET \
--url https://app.sideshift.app/api/oauth/v1/analytics/accounts \
--header 'Authorization: Bearer <token>'import requests
url = "https://app.sideshift.app/api/oauth/v1/analytics/accounts"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://app.sideshift.app/api/oauth/v1/analytics/accounts', 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://app.sideshift.app/api/oauth/v1/analytics/accounts",
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://app.sideshift.app/api/oauth/v1/analytics/accounts"
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://app.sideshift.app/api/oauth/v1/analytics/accounts")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.sideshift.app/api/oauth/v1/analytics/accounts")
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": {
"data": [
{
"handle": "@janecreator",
"platform": "tiktok",
"contractorId": "prog_abc123",
"contractorName": "Spring TikTok Push",
"isGhostHandle": true,
"totalPosts": 3,
"totalViews": 3,
"totalLikes": 3,
"totalComments": 3,
"totalShares": 3,
"totalBookmarks": 3,
"totalEngagement": 3,
"engagementRate": 5,
"averageViewsPerPost": 123,
"averageEngagementPerPost": 123,
"contracts": [
"string"
],
"programs": [
"string"
],
"contractCount": 3,
"programCount": 3,
"firstPostDate": 1786597707000,
"lastPostDate": 1786597707000
}
],
"page": 3,
"limit": 3,
"total": 3,
"totalPages": 3,
"summary": {
"totalAccounts": 3,
"totalPosts": 3,
"totalViews": 3,
"totalLikes": 3,
"totalEngagement": 3,
"averageEngagementRate": 5,
"platformBreakdown": {},
"ghostHandles": 123,
"realHandles": 123
},
"filters": {
"sortBy": "string",
"sortOrder": "string",
"excludeDeletedVideos": false
}
}
}{
"error": {
"code": "unauthorized",
"message": "Missing bearer access token",
"requestId": "req_..."
}
}{
"error": {
"code": "insufficient_scope",
"message": "Requires scope 'campaigns:write'",
"requestId": "req_..."
}
}{
"error": {
"code": "not_found",
"message": "Resource not found",
"requestId": "req_..."
}
}{
"error": {
"code": "rate_limited",
"message": "Rate limit exceeded",
"requestId": "req_..."
}
}Authorizations
OAuth 2.1 authorization code + PKCE (S256). Tokens are tenant-bound (company_id) and scoped. Discover endpoints via /.well-known/oauth-authorization-server.
Headers
OAuth human grants and scoped Platform API keys can act on one direct agency sub-account included in their explicit delegation. Current parent relationship, authorizing person access, child scope ceiling, and subscription eligibility are checked. Omit this header to act on the connected company. Machine client_credentials tokens do not carry delegation. Query parameters such as companyId, company_id, client, and subaccountId are not general tenant selectors where an endpoint does not explicitly document them.
Query Parameters
1-based page number.
x >= 1Page size. Values above 100 are clamped to 100.
1 <= x <= 100Field to sort accounts by.
Sort direction.
asc, desc Restrict results to these campaigns. Repeat the parameter to pass several ids. program is the legacy alias and is only consulted when programId is absent.
Legacy alias for programId. Ignored when programId is present.
Restrict results to these creators. Repeat the parameter to pass several ids. creator is the legacy alias and is only consulted when creatorId is absent.
Legacy alias for creatorId. Ignored when creatorId is present.
Restrict results to these platforms. Repeat the parameter for several.
Restrict to campaigns in this state. Unrecognised values are ignored.
active, all, archived Inclusive start of the date window, YYYY-MM-DD, interpreted at 00:00:00Z.
Inclusive end of the date window, YYYY-MM-DD, interpreted at 23:59:59Z.
Whether unclaimed (ghost) handles are counted. Defaults to all when omitted.
all, include, exclude Pass true to drop posts that have since been deleted. Any other value is false.
Restrict to posts in this review state.
all, approved, rejected, unreviewed Only include posts with at least this many views. A value of 0 is a no-op.
x >= 0Only include posts with at most this many views. A value of 0 is a no-op.
x >= 0Restrict to creators in these account groups. Repeat the parameter for several. Combined with creatorId as an intersection, so passing both with no overlap matches nothing.
Response
Success. Returns the resource envelope.
Show child attributes
Show child attributes