curl --request GET \
--url https://api.openagent.to/api/v1/transactions/holders \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.openagent.to/api/v1/transactions/holders"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.openagent.to/api/v1/transactions/holders', 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.openagent.to/api/v1/transactions/holders",
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.openagent.to/api/v1/transactions/holders"
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.openagent.to/api/v1/transactions/holders")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.openagent.to/api/v1/transactions/holders")
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": {
"docs": [
{
"_id": {
"accountId": "507f1f77bcf86cd799439011",
"address": "0x1111111111111111111111111111111111111111",
"securityId": "507f191e810c19729de860ea"
},
"accountType": "individual",
"address": "0x1111111111111111111111111111111111111111",
"investorName": "John Doe",
"lastActivityDate": "2026-09-01T00:00:00.000Z",
"ownershipPercent": 100,
"securityId": "507f191e810c19729de860ea",
"securityName": "Acme Preferred Equity",
"shares": 45000,
"status": "active"
}
],
"hasNextPage": true,
"hasPrevPage": true,
"limit": 0,
"nextPage": 0,
"page": 0,
"pagingCounter": 0,
"prevPage": 0,
"summary": {
"asOfDate": null,
"securityId": null,
"securityName": "Acme Preferred Equity",
"totalHolders": 1,
"totalOutstanding": 45000,
"totalOutstandingBySecurity": {
"507f191e810c19729de860ea": 45000
},
"totalSecurityCount": 1
},
"totalDocs": 0,
"totalPages": 0
},
"message": "Success",
"meta": {
"timestamp": "2026-09-01T09:15:32.104Z",
"requestId": "3f1c9d2e-6b7a-4f18-9c53-0a2b6d4e8f10"
},
"statusCode": 200,
"success": true
}{
"error": {
"code": "Validation error",
"details": [
{
"field": "email",
"message": "Invalid email format",
"allowedValues": [
"<string>"
]
}
]
},
"message": "Validation error",
"meta": {
"timestamp": "2026-09-01T09:15:32.104Z",
"requestId": "3f1c9d2e-6b7a-4f18-9c53-0a2b6d4e8f10"
},
"statusCode": 422,
"success": false
}{
"error": {
"code": "Validation error",
"details": [
{
"field": "email",
"message": "Invalid email format",
"allowedValues": [
"<string>"
]
}
]
},
"message": "Validation error",
"meta": {
"timestamp": "2026-09-01T09:15:32.104Z",
"requestId": "3f1c9d2e-6b7a-4f18-9c53-0a2b6d4e8f10"
},
"statusCode": 422,
"success": false
}{
"error": {
"code": "Validation error",
"details": [
{
"field": "email",
"message": "Invalid email format",
"allowedValues": [
"<string>"
]
}
]
},
"message": "Validation error",
"meta": {
"timestamp": "2026-09-01T09:15:32.104Z",
"requestId": "3f1c9d2e-6b7a-4f18-9c53-0a2b6d4e8f10"
},
"statusCode": 422,
"success": false
}{
"error": {
"code": "Validation error",
"details": [
{
"field": "email",
"message": "Invalid email format",
"allowedValues": [
"<string>"
]
}
]
},
"message": "Validation error",
"meta": {
"timestamp": "2026-09-01T09:15:32.104Z",
"requestId": "3f1c9d2e-6b7a-4f18-9c53-0a2b6d4e8f10"
},
"statusCode": 422,
"success": false
}List holder positions
Returns a page of holder positions plus a summary block alongside docs — the only endpoint in the API whose page carries extra fields. The summary is computed over the whole filtered set, not the current page, so it does not change while paging. Issuer scoping: an issuer_admin sees only its own issuer’s records, and is refused with 403 if its token carries no valid issuer id. ta_admin and audit_user see everything. Numbers differ here. shares, ownershipPercent and every summary total are JSON numbers, not the decimal strings the rest of this domain returns, so they are exact only below 2^53 and ownershipPercent is rounded for presentation. Do not reconcile these against quantity without converting deliberately. _id is a composite object — account, security and address — not an id string. This endpoint ignores sort and fields (its service paginates itself), and its page size defaults to 10, not 20. asOfDate returns positions as at that instant. Requires the holder:read permission.
curl --request GET \
--url https://api.openagent.to/api/v1/transactions/holders \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.openagent.to/api/v1/transactions/holders"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.openagent.to/api/v1/transactions/holders', 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.openagent.to/api/v1/transactions/holders",
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.openagent.to/api/v1/transactions/holders"
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.openagent.to/api/v1/transactions/holders")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.openagent.to/api/v1/transactions/holders")
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": {
"docs": [
{
"_id": {
"accountId": "507f1f77bcf86cd799439011",
"address": "0x1111111111111111111111111111111111111111",
"securityId": "507f191e810c19729de860ea"
},
"accountType": "individual",
"address": "0x1111111111111111111111111111111111111111",
"investorName": "John Doe",
"lastActivityDate": "2026-09-01T00:00:00.000Z",
"ownershipPercent": 100,
"securityId": "507f191e810c19729de860ea",
"securityName": "Acme Preferred Equity",
"shares": 45000,
"status": "active"
}
],
"hasNextPage": true,
"hasPrevPage": true,
"limit": 0,
"nextPage": 0,
"page": 0,
"pagingCounter": 0,
"prevPage": 0,
"summary": {
"asOfDate": null,
"securityId": null,
"securityName": "Acme Preferred Equity",
"totalHolders": 1,
"totalOutstanding": 45000,
"totalOutstandingBySecurity": {
"507f191e810c19729de860ea": 45000
},
"totalSecurityCount": 1
},
"totalDocs": 0,
"totalPages": 0
},
"message": "Success",
"meta": {
"timestamp": "2026-09-01T09:15:32.104Z",
"requestId": "3f1c9d2e-6b7a-4f18-9c53-0a2b6d4e8f10"
},
"statusCode": 200,
"success": true
}{
"error": {
"code": "Validation error",
"details": [
{
"field": "email",
"message": "Invalid email format",
"allowedValues": [
"<string>"
]
}
]
},
"message": "Validation error",
"meta": {
"timestamp": "2026-09-01T09:15:32.104Z",
"requestId": "3f1c9d2e-6b7a-4f18-9c53-0a2b6d4e8f10"
},
"statusCode": 422,
"success": false
}{
"error": {
"code": "Validation error",
"details": [
{
"field": "email",
"message": "Invalid email format",
"allowedValues": [
"<string>"
]
}
]
},
"message": "Validation error",
"meta": {
"timestamp": "2026-09-01T09:15:32.104Z",
"requestId": "3f1c9d2e-6b7a-4f18-9c53-0a2b6d4e8f10"
},
"statusCode": 422,
"success": false
}{
"error": {
"code": "Validation error",
"details": [
{
"field": "email",
"message": "Invalid email format",
"allowedValues": [
"<string>"
]
}
]
},
"message": "Validation error",
"meta": {
"timestamp": "2026-09-01T09:15:32.104Z",
"requestId": "3f1c9d2e-6b7a-4f18-9c53-0a2b6d4e8f10"
},
"statusCode": 422,
"success": false
}{
"error": {
"code": "Validation error",
"details": [
{
"field": "email",
"message": "Invalid email format",
"allowedValues": [
"<string>"
]
}
]
},
"message": "Validation error",
"meta": {
"timestamp": "2026-09-01T09:15:32.104Z",
"requestId": "3f1c9d2e-6b7a-4f18-9c53-0a2b6d4e8f10"
},
"statusCode": 422,
"success": false
}Authorizations
Staff access token. Sent as Authorization: Bearer <token>, or — when that header is absent — read from the accessToken cookie, which is how the admin app authenticates. Tokens carry a tokenVersion; logout and password reset bump it, revoking every outstanding token for that account.
Query Parameters
1-based page number. Defaults to 1.
x <= 9007199254740991Records per page, 1-100. Defaults to 10 here, not 20.
x <= 100Restricts the holder list to one security. Also narrows the summary.
^[a-f\d]{24}$Positions as at this instant, ISO 8601. Omit for current positions.
Case-insensitive substring matched against the holder name.

