curl --request GET \
--url https://production-api.joinrings.com/v1/persons \
--header 'x-api-key: <api-key>'import requests
url = "https://production-api.joinrings.com/v1/persons"
headers = {"x-api-key": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'x-api-key': '<api-key>'}};
fetch('https://production-api.joinrings.com/v1/persons', 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://production-api.joinrings.com/v1/persons",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"x-api-key: <api-key>"
],
]);
$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://production-api.joinrings.com/v1/persons"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("x-api-key", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://production-api.joinrings.com/v1/persons")
.header("x-api-key", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://production-api.joinrings.com/v1/persons")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["x-api-key"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"items": [
{
"company_name": "<string>",
"email": "<string>",
"job_title": "<string>",
"last_activity_date": "<string>",
"linkedin_url": "<string>",
"name": "<string>",
"uuid": "<string>",
"city": "<string>",
"company_pathpower": {
"meta": {},
"score": 123,
"strength_label": "<string>"
},
"country": "<string>",
"current_company": {
"company_name": "<string>",
"logo_url": "<string>",
"uuid": "<string>",
"job_type": "<string>",
"source": "<string>"
},
"current_company_domain": "<string>",
"current_company_name": "<string>",
"current_job_title": "<string>",
"custom_fields": {},
"description": "<string>",
"email_3": "<string>",
"email_3_last_seen": "<string>",
"email_4": "<string>",
"email_4_last_seen": "<string>",
"email_5": "<string>",
"email_5_last_seen": "<string>",
"email_last_seen": "<string>",
"employment_history": [
{
"company_domain": "<string>",
"company_industry": "<string>",
"company_linkedin_url": "<string>",
"company_logo_url": "<string>",
"company_name": "<string>",
"company_tenure_months": 123,
"company_uuid": "<string>",
"duration_months": 123,
"ended_at": "<string>",
"function": "<string>",
"is_current": true,
"level": "<string>",
"location": "<string>",
"started_at": "<string>",
"title": "<string>"
}
],
"entity_lists": [
{
"name": "<string>",
"uuid": "<string>"
}
],
"facebook_url": "<string>",
"investor_types": [
"<string>"
],
"is_primary_company_recommended": true,
"job_changed_at": "<string>",
"last_activity": "<string>",
"last_contact_at": "<string>",
"logo_url": "<string>",
"my_next_meeting_at": "<string>",
"my_next_meeting_title": "<string>",
"next_meeting_at": "<string>",
"next_meeting_title": "<string>",
"next_meeting_with_user_uuid": "<string>",
"pathpower": {
"meta": {},
"score": 123,
"strength_label": "<string>"
},
"phone_numbers": [
"<string>"
],
"previous_job_ended_at": "<string>",
"priority_management": {
"rq": 123,
"rq_manual": 123,
"rq_math": 123
},
"secondary_email": "<string>",
"secondary_email_last_seen": "<string>",
"state": "<string>",
"strongest_relationships": [
{
"internal_user_person_uuid": "<string>",
"internal_user_uuid": "<string>",
"last_engaged_at": "<string>",
"name": "<string>",
"path_power_score": 123
}
],
"twitter_url": "<string>"
}
],
"page": 123,
"per_page": 123,
"total": 123,
"has_more": true,
"next_cursor": "<string>"
}List persons
Returns a paginated list of people visible to the tenant. All filter parameters are optional — omitting all of them returns all persons.
Filter parameters:
- name: Case-insensitive substring match on person’s display name
- email: Matches any of the person’s emails (case/whitespace-insensitive)
- linkedin_url: Case-insensitive substring match on LinkedIn profile URL
- company_uuid: Matches persons whose current/primary company is this company UUID
- job_title: Case-insensitive substring match on job title
- city: Case-insensitive substring match on city
- state: State/region name (scoped to
countrywhen provided) - country: Country name or ISO code
- modified_since: ISO 8601 timestamp — return only persons modified at or after this time (e.g. ‘2025-01-01T00:00:00Z’)
Sort parameters:
- sort_by: name | last_activity_date (default: unsorted)
- order: asc | desc (default: asc)
Pagination:
- page: Page number (default: 1)
- per_page: Results per page, max 50 (default: 10)
- after: Opaque cursor from a previous response’s
next_cursor. Resumes immediately after that response’s last record, so concurrent writes can’t shift rows between pages the waypageallows.totalis not computed on this path — usehas_more.
Every response carries next_cursor, including page-numbered ones, so a
caller can start with page and switch to cursors mid-scan.
curl --request GET \
--url https://production-api.joinrings.com/v1/persons \
--header 'x-api-key: <api-key>'import requests
url = "https://production-api.joinrings.com/v1/persons"
headers = {"x-api-key": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'x-api-key': '<api-key>'}};
fetch('https://production-api.joinrings.com/v1/persons', 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://production-api.joinrings.com/v1/persons",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"x-api-key: <api-key>"
],
]);
$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://production-api.joinrings.com/v1/persons"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("x-api-key", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://production-api.joinrings.com/v1/persons")
.header("x-api-key", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://production-api.joinrings.com/v1/persons")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["x-api-key"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"items": [
{
"company_name": "<string>",
"email": "<string>",
"job_title": "<string>",
"last_activity_date": "<string>",
"linkedin_url": "<string>",
"name": "<string>",
"uuid": "<string>",
"city": "<string>",
"company_pathpower": {
"meta": {},
"score": 123,
"strength_label": "<string>"
},
"country": "<string>",
"current_company": {
"company_name": "<string>",
"logo_url": "<string>",
"uuid": "<string>",
"job_type": "<string>",
"source": "<string>"
},
"current_company_domain": "<string>",
"current_company_name": "<string>",
"current_job_title": "<string>",
"custom_fields": {},
"description": "<string>",
"email_3": "<string>",
"email_3_last_seen": "<string>",
"email_4": "<string>",
"email_4_last_seen": "<string>",
"email_5": "<string>",
"email_5_last_seen": "<string>",
"email_last_seen": "<string>",
"employment_history": [
{
"company_domain": "<string>",
"company_industry": "<string>",
"company_linkedin_url": "<string>",
"company_logo_url": "<string>",
"company_name": "<string>",
"company_tenure_months": 123,
"company_uuid": "<string>",
"duration_months": 123,
"ended_at": "<string>",
"function": "<string>",
"is_current": true,
"level": "<string>",
"location": "<string>",
"started_at": "<string>",
"title": "<string>"
}
],
"entity_lists": [
{
"name": "<string>",
"uuid": "<string>"
}
],
"facebook_url": "<string>",
"investor_types": [
"<string>"
],
"is_primary_company_recommended": true,
"job_changed_at": "<string>",
"last_activity": "<string>",
"last_contact_at": "<string>",
"logo_url": "<string>",
"my_next_meeting_at": "<string>",
"my_next_meeting_title": "<string>",
"next_meeting_at": "<string>",
"next_meeting_title": "<string>",
"next_meeting_with_user_uuid": "<string>",
"pathpower": {
"meta": {},
"score": 123,
"strength_label": "<string>"
},
"phone_numbers": [
"<string>"
],
"previous_job_ended_at": "<string>",
"priority_management": {
"rq": 123,
"rq_manual": 123,
"rq_math": 123
},
"secondary_email": "<string>",
"secondary_email_last_seen": "<string>",
"state": "<string>",
"strongest_relationships": [
{
"internal_user_person_uuid": "<string>",
"internal_user_uuid": "<string>",
"last_engaged_at": "<string>",
"name": "<string>",
"path_power_score": 123
}
],
"twitter_url": "<string>"
}
],
"page": 123,
"per_page": 123,
"total": 123,
"has_more": true,
"next_cursor": "<string>"
}Authorizations
Query Parameters
Page number, 1-indexed. Clamped to >= 1.
Results per page (default 10). Clamped to the range 1-50 (values outside are silently capped, not rejected).
Opaque cursor from a previous response's next_cursor. When supplied, the page starts immediately after the last record of that response and page is ignored — unlike page, this cannot skip or repeat records when the data changes mid-scan. Filters and sort must stay identical for the whole scan; changing one is a 400. Not supported by every list endpoint — those that support it return next_cursor.
Filter to persons whose primary company affiliation is this company UUID. Matches the response's current_company.uuid.
Filter to persons whose current job title contains this text. Persons without a recorded job title are excluded.
Case-insensitive substring on the person's city (e.g. 'Los Angeles'). Pass the full city name, not an abbreviation — 'LA' is matched as a substring and hits Dallas and Cleveland, not Los Angeles.
Person's state/region. A full name ('Florida') works on its own; a two-letter code ('FL', 'NY') is ISO 3166-2 and requires country, since unscoped 'CA' means Alberta and 'FL' means Flintshire, GB. Returns 400 if it does not resolve, rather than an empty page that reads as 'nobody there'.
Person's country, name or ISO code ('US', 'United States'). Required next to a two-letter state. Returns 400 if unrecognized.
Return only persons modified at or after this ISO 8601 timestamp (e.g. '2025-01-01T00:00:00Z'). Tracks the last time Rings updated the record, from any source.
Field to sort by. Valid values: 'name', 'last_activity_date'
name, last_activity_date Sort order. Valid values: 'asc' (ascending) or 'desc' (descending)
asc, desc Case-insensitive substring match on the person's current job title.
Case-insensitive substring match on the person's current company name.
Exact match on the person's current company domain (e.g. 'acme.com').
ISO 8601 timestamp — filter to persons whose current role started at or after this date (job_changed_at >= value).
ISO 8601 timestamp — filter to persons whose current role started at or before this date (job_changed_at <= value).
ISO 8601 timestamp — filter to persons whose most-recent prior job ended at or after this date.
ISO 8601 timestamp — filter to persons whose most-recent prior job ended at or before this date.
Comma-separated list of person UUIDs to fetch. When set, only these persons are returned (subject to other filters).