curl --request GET \
--url https://api.growi.io/api/public/v1/stats/query_ambassadors \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.growi.io/api/public/v1/stats/query_ambassadors"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.growi.io/api/public/v1/stats/query_ambassadors', 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://api.growi.io/api/public/v1/stats/query_ambassadors",
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://api.growi.io/api/public/v1/stats/query_ambassadors"
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://api.growi.io/api/public/v1/stats/query_ambassadors")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.growi.io/api/public/v1/stats/query_ambassadors")
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": [
{
"campaign_affiliate_id": 456,
"user_id": 789,
"email": "ambassador@example.com",
"first_name": "John",
"last_name": "Doe",
"creator_name": "John Doe",
"revenue": 5000.5,
"commission": 500.05,
"orders_count": 45,
"clicks": 1500,
"joined_campaign_date": "01/15/2024"
}
],
"meta": {
"total_ambassadors": 150,
"current_page": 1,
"per_page": 20,
"total_pages": 8,
"start_date": "09/01/2025",
"end_date": "09/30/2025",
"campaign_id": "123"
}
}{
"error": "<string>",
"message": "<string>"
}{
"error": "<string>",
"message": "<string>"
}{
"error": "Rate limit exceeded. Please wait 2 seconds between requests.",
"retry_after": 2
}Get Ambassador Stats
Retrieves aggregated statistics for campaign ambassadors, grouped by individual affiliate. This endpoint provides performance metrics including revenue, commission, order counts, and clicks for ambassadors within a specified date range.
curl --request GET \
--url https://api.growi.io/api/public/v1/stats/query_ambassadors \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.growi.io/api/public/v1/stats/query_ambassadors"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.growi.io/api/public/v1/stats/query_ambassadors', 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://api.growi.io/api/public/v1/stats/query_ambassadors",
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://api.growi.io/api/public/v1/stats/query_ambassadors"
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://api.growi.io/api/public/v1/stats/query_ambassadors")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.growi.io/api/public/v1/stats/query_ambassadors")
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": [
{
"campaign_affiliate_id": 456,
"user_id": 789,
"email": "ambassador@example.com",
"first_name": "John",
"last_name": "Doe",
"creator_name": "John Doe",
"revenue": 5000.5,
"commission": 500.05,
"orders_count": 45,
"clicks": 1500,
"joined_campaign_date": "01/15/2024"
}
],
"meta": {
"total_ambassadors": 150,
"current_page": 1,
"per_page": 20,
"total_pages": 8,
"start_date": "09/01/2025",
"end_date": "09/30/2025",
"campaign_id": "123"
}
}{
"error": "<string>",
"message": "<string>"
}{
"error": "<string>",
"message": "<string>"
}{
"error": "Rate limit exceeded. Please wait 2 seconds between requests.",
"retry_after": 2
}Request Parameters
| Parameter | Type | Description | Required |
|---|---|---|---|
start_date | String | Start date in MM/DD/YYYY format | Yes |
end_date | String | End date in MM/DD/YYYY format | Yes |
campaign_id | Integer | ID of the campaign to query | Yes |
page | Integer | Page number for pagination. Default is 1. | No |
per_page | Integer | Number of results per page. Default is 20. Maximum is 100. | No |
include_clicks | String | Set to true to include click data. Default is false. | No |
search | String | Search across email, first name, last name, or full name | No |
email | String | Filter by ambassador email(s). Supports comma-separated values | No |
first_name | String | Filter by ambassador first name (case-insensitive, partial match) | No |
last_name | String | Filter by ambassador last name (case-insensitive, partial match) | No |
Request Examples
Basic Request
curl -X GET "https://api.growi.io/api/public/v1/stats/query_ambassadors?start_date=09/01/2025&end_date=09/30/2025&campaign_id=123&page=1&per_page=20" \
-H "Authorization: Bearer YOUR_PUBLIC_API_KEY" \
-H "Content-Type: application/json"
With Clicks
curl -X GET "https://api.growi.io/api/public/v1/stats/query_ambassadors?start_date=09/01/2025&end_date=09/30/2025&campaign_id=123&include_clicks=true" \
-H "Authorization: Bearer YOUR_PUBLIC_API_KEY" \
-H "Content-Type: application/json"
With Clicks
curl -X GET "https://api.growi.io/api/public/v1/stats/query_ambassadors?start_date=09/01/2025&end_date=09/30/2025&campaign_id=123&include_clicks=true" \
-H "Authorization: Bearer YOUR_PUBLIC_API_KEY"
Response Example
{
"data": [
{
"campaign_affiliate_id": 456,
"user_id": 789,
"email": "ambassador@example.com",
"first_name": "John",
"last_name": "Doe",
"creator_name": "John Doe",
"revenue": 5000.5,
"commission": 500.05,
"orders_count": 45,
"clicks": 1500,
"refund_amount": 150.25,
"joined_campaign_date": "01/15/2024"
}
],
"meta": {
"total_ambassadors": 150,
"current_page": 1,
"per_page": 20,
"total_pages": 8,
"start_date": "09/01/2025",
"end_date": "09/30/2025",
"campaign_id": "123"
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
data | Array | Array of ambassador statistics objects |
data[].campaign_affiliate_id | Integer | Unique identifier for the campaign affiliate relationship |
data[].user_id | Integer | Unique identifier for the user/ambassador |
data[].email | String | Ambassador’s email address |
data[].first_name | String | Ambassador’s first name |
data[].last_name | String | Ambassador’s last name |
data[].creator_name | String | Full name of the ambassador (first + last) |
data[].revenue | Number | Total revenue generated in dollars (for the specified date range) |
data[].commission | Number | Total commission earned in dollars |
data[].orders_count | Integer | Total number of completed orders |
data[].clicks | Integer | Total number of unique link clicks. Default is 0 unless include_clicks=true |
data[].refund_amount | Number | Total refunded/canceled order amount in dollars |
data[].joined_campaign_date | String | Date the ambassador joined the campaign (MM/DD/YYYY format) |
meta | Object | Pagination and query metadata |
meta.total_ambassadors | Integer | Total number of ambassadors matching the query (across all pages) |
meta.current_page | Integer | Current page number |
meta.per_page | Integer | Number of results per page |
meta.total_pages | Integer | Total number of pages available |
meta.start_date | String | Query start date |
meta.end_date | String | Query end date |
meta.campaign_id | String | Campaign ID queried |
Filter Examples
Search Filter
Thesearch parameter searches across email, first name, last name, and full name:
curl -X GET "https://api.growi.io/api/public/v1/stats/query_ambassadors?start_date=09/01/2025&end_date=09/30/2025&campaign_id=123&search=john" \
-H "Authorization: Bearer YOUR_PUBLIC_API_KEY"
Email Filter (Single)
Filter by a specific ambassador email:curl -X GET "https://api.growi.io/api/public/v1/stats/query_ambassadors?start_date=09/01/2025&end_date=09/30/2025&campaign_id=123&email=john@example.com" \
-H "Authorization: Bearer YOUR_PUBLIC_API_KEY"
Email Filter (Multiple - Comma Separated)
Filter by multiple ambassador emails using comma-separated values:curl -X GET "https://api.growi.io/api/public/v1/stats/query_ambassadors?start_date=09/01/2025&end_date=09/30/2025&campaign_id=123&email=john@example.com,jane@example.com,bob@example.com" \
-H "Authorization: Bearer YOUR_PUBLIC_API_KEY"
First Name Filter
Filter by ambassador first name (case-insensitive, partial match):curl -X GET "https://api.growi.io/api/public/v1/stats/query_ambassadors?start_date=09/01/2025&end_date=09/30/2025&campaign_id=123&first_name=John" \
-H "Authorization: Bearer YOUR_PUBLIC_API_KEY"
Last Name Filter
Filter by ambassador last name (case-insensitive, partial match):curl -X GET "https://api.growi.io/api/public/v1/stats/query_ambassadors?start_date=09/01/2025&end_date=09/30/2025&campaign_id=123&last_name=Smith" \
-H "Authorization: Bearer YOUR_PUBLIC_API_KEY"
Combined Filters
You can combine multiple filters:curl -X GET "https://api.growi.io/api/public/v1/stats/query_ambassadors?start_date=09/01/2025&end_date=09/30/2025&campaign_id=123&first_name=John&last_name=Doe&include_clicks=true" \
-H "Authorization: Bearer YOUR_PUBLIC_API_KEY"
Pagination
# Get first page (20 results by default)
curl -X GET "https://api.growi.io/api/public/v1/stats/query_ambassadors?start_date=09/01/2025&end_date=09/30/2025&campaign_id=123&page=1" \
-H "Authorization: Bearer YOUR_PUBLIC_API_KEY"
# Get second page
curl -X GET "https://api.growi.io/api/public/v1/stats/query_ambassadors?start_date=09/01/2025&end_date=09/30/2025&campaign_id=123&page=2" \
-H "Authorization: Bearer YOUR_PUBLIC_API_KEY"
# Get 50 results per page
curl -X GET "https://api.growi.io/api/public/v1/stats/query_ambassadors?start_date=09/01/2025&end_date=09/30/2025&campaign_id=123&per_page=50" \
-H "Authorization: Bearer YOUR_PUBLIC_API_KEY"
Important Notes
Time Periods
All metrics (revenue, commission, orders, clicks, refunds) are filtered by the specified date range. Thestart_date and end_date parameters filter tracking events by their occurred_at timestamp (when the sale or click happened), not by when the ambassador joined the campaign.
To analyze different time periods, make separate API calls with different date ranges:
- This Month:
start_date=12/01/2024&end_date=12/31/2024 - Last Month:
start_date=11/01/2024&end_date=11/30/2024 - Year to Date:
start_date=01/01/2024&end_date=12/31/2024 - Custom Range: Any range you specify
Pagination
- Default: 20 results per page
- Maximum: 100 results per page
- Performance: Always use pagination for campaigns with many ambassadors
- All ambassadors shown: Even ambassadors with 0 sales appear in results if they match filters
- Use
total_pagesin the meta response to iterate through all pages
Error Responses
400 Bad Request - Missing Required Parameters
{
"error": "Missing required parameter(s): start_date, end_date, campaign_id"
}
401 Unauthorized - Invalid API Key
{
"error": "Not Authenticated"
}
429 Too Many Requests - Rate Limit Exceeded
{
"error": "Rate limit exceeded. Please wait 2 seconds between requests.",
"retry_after": 2
}
Rate Limiting
This endpoint is subject to the standard Public API rate limits:- Frequency Limit: 2-second minimum interval between requests
- Hourly Limit: 40 requests per hour (default, configurable per organization)
Performance Tips
To ensure fast response times:- Use Pagination: Always paginate for campaigns with many ambassadors
- Apply Filters: Use email/name filters to narrow results
- Clicks: Only add
include_clicks=truewhen you specifically need click data
Integration Examples
JavaScript/Node.js
const axios = require("axios");
async function getAmbassadorStats(
apiKey,
campaignId,
startDate,
endDate,
filters = {}
) {
try {
const params = {
campaign_id: campaignId,
start_date: startDate,
end_date: endDate,
...filters,
};
const response = await axios.get(
"https://api.growi.io/api/public/v1/stats/query_ambassadors",
{
headers: { Authorization: `Bearer ${apiKey}` },
params,
}
);
return response.data;
} catch (error) {
console.error("Error:", error.response?.data || error.message);
throw error;
}
}
// Usage examples
// Fast - without clicks
const stats = await getAmbassadorStats(
"growi-sk-YOUR_API_KEY",
123,
"09/01/2025",
"09/30/2025"
);
// With clicks (requires index for good performance)
const statsWithClicks = await getAmbassadorStats(
"growi-sk-YOUR_API_KEY",
123,
"09/01/2025",
"09/30/2025",
{ include_clicks: "true" }
);
// With email filter
const filtered = await getAmbassadorStats(
"growi-sk-YOUR_API_KEY",
123,
"09/01/2025",
"09/30/2025",
{ email: "john@example.com" }
);
// With multiple emails
const multiFiltered = await getAmbassadorStats(
"growi-sk-YOUR_API_KEY",
123,
"09/01/2025",
"09/30/2025",
{ email: "john@example.com,jane@example.com", include_clicks: "true" }
);
console.log(`Total Ambassadors: ${stats.meta.total_ambassadors}`);
stats.data.forEach((ambassador) => {
console.log(
`${ambassador.creator_name}: $${ambassador.revenue} revenue, ${ambassador.orders_count} orders, ${ambassador.clicks} clicks, $${ambassador.refund_amount} refunded`
);
});
Python
import requests
def get_ambassador_stats(api_key, campaign_id, start_date, end_date, **filters):
url = 'https://api.growi.io/api/public/v1/stats/query_ambassadors'
headers = {'Authorization': f'Bearer {api_key}'}
params = {
'campaign_id': campaign_id,
'start_date': start_date,
'end_date': end_date,
**filters
}
response = requests.get(url, headers=headers, params=params)
response.raise_for_status()
return response.json()
# Usage examples
# Fast - without clicks
stats = get_ambassador_stats(
'growi-sk-YOUR_API_KEY',
123,
'09/01/2025',
'09/30/2025'
)
# With clicks
stats_with_clicks = get_ambassador_stats(
'growi-sk-YOUR_API_KEY',
123,
'09/01/2025',
'09/30/2025',
include_clicks='true'
)
# With filters
filtered_stats = get_ambassador_stats(
'growi-sk-YOUR_API_KEY',
123,
'09/01/2025',
'09/30/2025',
email='john@example.com,jane@example.com',
first_name='John',
include_clicks='true'
)
print(f"Total Ambassadors: {stats['meta']['total_ambassadors']}")
for ambassador in stats['data']:
print(f"{ambassador['creator_name']}: ${ambassador['revenue']} revenue, "
f"{ambassador['orders_count']} orders, {ambassador['clicks']} clicks, "
f"${ambassador['refund_amount']} refunded")
Ruby
require 'net/http'
require 'json'
require 'cgi'
def get_ambassador_stats(api_key, campaign_id, start_date, end_date, filters = {})
uri = URI('https://api.growi.io/api/public/v1/stats/query_ambassadors')
params = {
campaign_id: campaign_id,
start_date: start_date,
end_date: end_date
}.merge(filters)
uri.query = URI.encode_www_form(params)
request = Net::HTTP::Get.new(uri)
request['Authorization'] = "Bearer #{api_key}"
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
JSON.parse(response.body)
end
# Usage examples
# Fast - without clicks
stats = get_ambassador_stats(
'growi-sk-YOUR_API_KEY',
123,
'09/01/2025',
'09/30/2025'
)
# With clicks
stats_with_clicks = get_ambassador_stats(
'growi-sk-YOUR_API_KEY',
123,
'09/01/2025',
'09/30/2025',
include_clicks: 'true'
)
# With multiple emails
filtered = get_ambassador_stats(
'growi-sk-YOUR_API_KEY',
123,
'09/01/2025',
'09/30/2025',
email: 'john@example.com,jane@example.com',
include_clicks: 'true'
)
puts "Total Ambassadors: #{stats['meta']['total_ambassadors']}"
stats['data'].each do |ambassador|
puts "#{ambassador['creator_name']}: $#{ambassador['revenue']} revenue, " \
"#{ambassador['orders_count']} orders, #{ambassador['clicks']} clicks, " \
"$#{ambassador['refund_amount']} refunded"
end
Filtering Best Practices
Multiple Emails
When filtering by multiple emails, use comma-separated values without spaces (or with spaces - both work):?email=user1@example.com,user2@example.com,user3@example.com
- Split on commas
- Trim whitespace
- Convert to lowercase for case-insensitive matching
Search vs Specific Filters
- Use
searchfor broad queries across all name/email fields - Use
email,first_name, orlast_namefor precise filtering
Including Clicks
By default, clicks are not included to ensure fast response times. To include click data:?include_clicks=true
Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Query Parameters
Start date in MM/DD/YYYY format
End date in MM/DD/YYYY format
ID of the campaign to query
Page number for pagination. Default is 1.
Number of results per page. Default is 20. Maximum is 100.
x <= 100Search across email, first name, last name, or full name
Filter by ambassador email(s). Supports comma-separated values
Filter by ambassador first name (case-insensitive, partial match)
Filter by ambassador last name (case-insensitive, partial match)
Filter by tracking event status
all, paid, pending, canceled, due