Advocates API

Read your advocates: their status, tags, public profile, and, with an extra permission, their contact details, address, and custom fields.

Requires the advocates permission. Personal data also requires advocates:pii. See Personal data.

Endpoint Returns
GET /api/v1/advocates A paginated list of advocates
GET /api/v1/advocates/:id One advocate

List advocates

GET https://integrations.stokedhq.com/api/v1/advocates

With no filters, the list contains every advocate in your community: pending, active, and inactive, including advocates who have been deleted or whose personal data has been erased. See Deleted and erased advocates.

Parameters

Parameter Description
filter[status] One or more of pending, active, inactive, separated by commas: filter[status]=pending,active
filter[created_since] Only advocates created at or after this time
filter[updated_since] Only advocates updated at or after this time. Use this for incremental syncing.
page[number] The page to return. Defaults to 1.
page[size] Advocates per page. Defaults to 50, maximum 200.

Time filters accept an ISO 8601 timestamp with a time zone (2026-09-01T00:00:00Z) or a date (2026-09-01, read as midnight UTC). Both are inclusive.

Any other parameter — including sort — returns a 400 error. Advocates always come back least recently updated first.

Request

GET /api/v1/advocates

cURL

curl -G "https://integrations.stokedhq.com/api/v1/advocates" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/vnd.api+json" \
--data-urlencode "filter[status]=active"

Ruby

require "net/http"
require "json"
uri = URI("https://integrations.stokedhq.com/api/v1/advocates")
uri.query = URI.encode_www_form("filter[status]" => "active")
request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer YOUR_API_KEY"
request["Accept"] = "application/vnd.api+json"
response = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(request) }
raise "HTTP #{response.code}: #{response.body}" unless response.is_a?(Net::HTTPSuccess)
puts JSON.parse(response.body)["data"]

Python

import requests
response = requests.get(
"https://integrations.stokedhq.com/api/v1/advocates",
headers={
"Authorization": "Bearer YOUR_API_KEY",
"Accept": "application/vnd.api+json",
},
params={"filter[status]": "active"},
)
response.raise_for_status()
print(response.json()["data"])

C#

using System.Net.Http.Headers;
using System.Text.Json;
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "YOUR_API_KEY");
client.DefaultRequestHeaders.Accept.ParseAdd("application/vnd.api+json");
using var response = await client.GetAsync("https://integrations.stokedhq.com/api/v1/advocates?filter[status]=active");
response.EnsureSuccessStatusCode();
using var document = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
Console.WriteLine(document.RootElement.GetProperty("data"));

JavaScript

const url = new URL("https://integrations.stokedhq.com/api/v1/advocates");
url.searchParams.set("filter[status]", "active");
const response = await fetch(url, {
headers: {
Authorization: "Bearer YOUR_API_KEY",
Accept: "application/vnd.api+json",
},
});
if (!response.ok) throw new Error(`HTTP ${response.status}: ${await response.text()}`);
const { data } = await response.json();
console.log(data);

Response

This key has both advocates and advocates:pii.

Response advocates-index.json Download
{
"data": [
{
"type": "advocates",
"id": "01k5exampleadv0cate0000001",
"attributes": {
"first_name": "Sarah",
"last_name": "Example",
"email": "sarah@example.com",
"phone_number": "+12025550100",
"handle": "sarah-e",
"profile_url": "https://example-bikes.stokedhq.com/sarah-e",
"status": "active",
"tags": [
"cargo-bike"
],
"headline": "Longtail owner, school-run veteran",
"description": "Ask me anything about carrying two kids and the groceries.",
"display_name": "Sarah",
"display_location": "Springfield, IL",
"address": {
"address_1": "123 Example St",
"address_2": null,
"city": "Springfield",
"state": "IL",
"postal_code": "62701",
"country_code": "USA"
},
"latitude": 39.8,
"longitude": -89.65,
"custom_fields": {
"bike_model": "Longtail",
"accessories": [
"Rain cover",
"Child seats"
]
},
"visible_on_map": true,
"conversations_count": 1,
"created_at": "2026-08-20T14:00:00Z",
"updated_at": "2026-09-01T15:00:00Z",
"deleted_at": null
},
"relationships": {
"conversations": {
"links": {
"related": "https://integrations.stokedhq.com/api/v1/conversations?filter%5Badvocate%5D=01k5exampleadv0cate0000001"
}
}
},
"links": {
"self": "https://integrations.stokedhq.com/api/v1/advocates/01k5exampleadv0cate0000001"
},
"meta": {
"pii": true
}
}
],
"links": {
"self": "https://integrations.stokedhq.com/api/v1/advocates?filter%5Bstatus%5D=active&page%5Bnumber%5D=1&page%5Bsize%5D=50",
"first": "https://integrations.stokedhq.com/api/v1/advocates?filter%5Bstatus%5D=active&page%5Bnumber%5D=1&page%5Bsize%5D=50",
"prev": null,
"next": null,
"last": "https://integrations.stokedhq.com/api/v1/advocates?filter%5Bstatus%5D=active&page%5Bnumber%5D=1&page%5Bsize%5D=50"
},
"meta": {
"page": 1,
"per_page": 50,
"total_count": 1,
"total_pages": 1
}
}

Get an advocate

GET https://integrations.stokedhq.com/api/v1/advocates/:id

Returns the same record as the list. An ID that doesn’t exist in your community returns 404.

The id is the same value a conversation gives you in relationships.advocate, and that relationship’s links.related is this URL.

Request

GET /api/v1/advocates/01k5exampleadv0cate0000001

cURL

curl "https://integrations.stokedhq.com/api/v1/advocates/01k5exampleadv0cate0000001" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/vnd.api+json"

Ruby

require "net/http"
require "json"
uri = URI("https://integrations.stokedhq.com/api/v1/advocates/01k5exampleadv0cate0000001")
request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer YOUR_API_KEY"
request["Accept"] = "application/vnd.api+json"
response = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(request) }
raise "HTTP #{response.code}: #{response.body}" unless response.is_a?(Net::HTTPSuccess)
puts JSON.parse(response.body)["data"]

Python

import requests
response = requests.get(
"https://integrations.stokedhq.com/api/v1/advocates/01k5exampleadv0cate0000001",
headers={
"Authorization": "Bearer YOUR_API_KEY",
"Accept": "application/vnd.api+json",
},
)
response.raise_for_status()
print(response.json()["data"])

C#

using System.Net.Http.Headers;
using System.Text.Json;
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "YOUR_API_KEY");
client.DefaultRequestHeaders.Accept.ParseAdd("application/vnd.api+json");
using var response = await client.GetAsync("https://integrations.stokedhq.com/api/v1/advocates/01k5exampleadv0cate0000001");
response.EnsureSuccessStatusCode();
using var document = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
Console.WriteLine(document.RootElement.GetProperty("data"));

JavaScript

const url = new URL("https://integrations.stokedhq.com/api/v1/advocates/01k5exampleadv0cate0000001");
const response = await fetch(url, {
headers: {
Authorization: "Bearer YOUR_API_KEY",
Accept: "application/vnd.api+json",
},
});
if (!response.ok) throw new Error(`HTTP ${response.status}: ${await response.text()}`);
const { data } = await response.json();
console.log(data);

Response

Response advocates-show.json Download
{
"data": {
"type": "advocates",
"id": "01k5exampleadv0cate0000001",
"attributes": {
"first_name": "Sarah",
"last_name": "Example",
"email": "sarah@example.com",
"phone_number": "+12025550100",
"handle": "sarah-e",
"profile_url": "https://example-bikes.stokedhq.com/sarah-e",
"status": "active",
"tags": [
"cargo-bike"
],
"headline": "Longtail owner, school-run veteran",
"description": "Ask me anything about carrying two kids and the groceries.",
"display_name": "Sarah",
"display_location": "Springfield, IL",
"address": {
"address_1": "123 Example St",
"address_2": null,
"city": "Springfield",
"state": "IL",
"postal_code": "62701",
"country_code": "USA"
},
"latitude": 39.8,
"longitude": -89.65,
"custom_fields": {
"bike_model": "Longtail",
"accessories": [
"Rain cover",
"Child seats"
]
},
"visible_on_map": true,
"conversations_count": 1,
"created_at": "2026-08-20T14:00:00Z",
"updated_at": "2026-09-01T15:00:00Z",
"deleted_at": null
},
"relationships": {
"conversations": {
"links": {
"related": "https://integrations.stokedhq.com/api/v1/conversations?filter%5Badvocate%5D=01k5exampleadv0cate0000001"
}
}
},
"links": {
"self": "https://integrations.stokedhq.com/api/v1/advocates/01k5exampleadv0cate0000001"
},
"meta": {
"pii": true
}
}
}

Personal data

Attributes marked advocates:pii below are only returned to a key that has the advocates:pii permission as well as advocates.

Without it, those attributes are left out of the response entirely rather than set to null, so null always means “no value” and never “not permitted”. Each record’s meta.pii tells you which kind of response you received.

The same advocate, read with a key that has only advocates:

Response advocates-show-without-pii.json Download
{
"data": {
"type": "advocates",
"id": "01k5exampleadv0cate0000001",
"attributes": {
"handle": "sarah-e",
"profile_url": "https://example-bikes.stokedhq.com/sarah-e",
"status": "active",
"tags": [
"cargo-bike"
],
"headline": "Longtail owner, school-run veteran",
"description": "Ask me anything about carrying two kids and the groceries.",
"visible_on_map": true,
"conversations_count": 1,
"created_at": "2026-08-20T14:00:00Z",
"updated_at": "2026-09-01T15:00:00Z",
"deleted_at": null
},
"relationships": {
"conversations": {
"links": {
"related": "https://integrations.stokedhq.com/api/v1/conversations?filter%5Badvocate%5D=01k5exampleadv0cate0000001"
}
}
},
"links": {
"self": "https://integrations.stokedhq.com/api/v1/advocates/01k5exampleadv0cate0000001"
},
"meta": {
"pii": false
}
}
}

headline and description are not gated: they are text the advocate wrote for their public profile, already shown on your community site. Note that an advocate is free to write their own name into either one.

handle and profile_url are not gated either, because the profile page is public. Handles are usually built from the advocate’s name and city (naomi-in-alexandria), so treat them as identifying. Use id, which is a random identifier, to match advocates against your own records.


Advocate attributes

Records with "type": "advocates".

Attribute Type Requires Description
first_name string advocates:pii  
last_name string or null advocates:pii  
email string or null advocates:pii  
phone_number string or null advocates:pii In E.164 format, for example +12025550100
handle string   The advocate’s unique handle, the last part of their profile URL. Usually built from their name and city.
profile_url string or null   The advocate’s public profile on your community site.
status string   pending, active, or inactive
tags array of strings   Names of the advocate’s tags, in the order set in Settings
headline string or null   The headline on their public profile
description string or null   The bio on their public profile
display_name string advocates:pii The name shown publicly: their custom display name, or their first name
display_location string or null advocates:pii The location shown publicly, for example “Springfield, IL”
address object or null advocates:pii The advocate’s address. null if none is on file.
latitude number or null advocates:pii Map coordinates of the address
longitude number or null advocates:pii  
custom_fields object advocates:pii Your community’s custom fields. See The custom_fields object.
visible_on_map boolean   Whether the advocate has chosen to appear on your community map
conversations_count integer   Number of conversations the advocate has been part of
created_at timestamp   When the advocate was added
updated_at timestamp   When the advocate last changed. See What changes updated_at.
deleted_at timestamp or null   When the advocate was removed from your community. null for current advocates. Removed advocates stay in the API so your copy can mark them, and removing one updates updated_at.

The address object

Field Type Description
address_1 string or null Street address
address_2 string or null Apartment, suite, or unit
city string or null  
state string or null State, province, or region
postal_code string or null  
country_code string Three-letter ISO 3166-1 country code, for example USA

The custom_fields object

One key per custom field defined in Settings > Advocate Custom Fields, named by the field’s identifier (the same name the CSV export uses after custom_field_). Every field is present for every advocate; the value is null when the advocate hasn’t answered.

Values are strings, formatted as they are in the CSV export (a checkbox is "Yes" or "No"), except multiple-select fields, which are arrays of the selected options — an empty array when unanswered.

Relationships

Relationship Description
conversations links.related is the conversations list filtered to this advocate (filter[advocate]). Reading it requires the conversations permission.

What changes updated_at

An advocate’s updated_at moves forward whenever anything in their API record changes:

  • Their name, contact details, handle, or status changes
  • Their profile, address, or map location is edited
  • A custom field value changes, or a custom field is added, renamed, or deleted (every advocate carries a key for every field, so all of them change)
  • A tag is added, removed, renamed, or reordered
  • A conversation with them is started
  • They are deleted, or their personal data is erased

It can also move when something outside the API record changes, such as their avatar. Updating by id makes the repeat harmless.

Deleted and erased advocates

Deleting an advocate in the admin portal keeps their record so their conversations still make sense, and the API keeps returning it. When an advocate’s personal data is erased (for example, after a privacy request), their record stays too, with the personal data overwritten: first_name becomes [redacted], other contact fields become null or a placeholder, and the address and custom field values are removed.

Erasure moves updated_at, so your next incremental sync receives the redacted record. Apply it to your copy like any other update so the personal data is removed from your systems too.


© 2024-2026 Stoked — Real conversations. Real trust.