Comptes historiques
getHistoricalTokenAccountsByOwner
Répertoriez les comptes SPL Token et Token-2022 qu’un portefeuille Solana possédait à un slot passé ou juste après une transaction spécifique, avec des filtres par mint et la pagination.
POST
/
getHistoricalTokenAccountsByOwner
curl --request POST \
--url 'https://mainnet.helius-rpc.com/?api-key=' \
--header 'Content-Type: application/json' \
--data '
{
"jsonrpc": "2.0",
"id": "1",
"method": "getHistoricalTokenAccountsByOwner",
"params": [
"86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY",
{
"slot": 445000000
},
{
"encoding": "jsonParsed",
"limit": 2
}
]
}
'import requests
url = "https://mainnet.helius-rpc.com/?api-key="
payload = {
"jsonrpc": "2.0",
"id": "1",
"method": "getHistoricalTokenAccountsByOwner",
"params": [
"86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY",
{ "slot": 445000000 },
{
"encoding": "jsonParsed",
"limit": 2
}
]
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
jsonrpc: '2.0',
id: '1',
method: 'getHistoricalTokenAccountsByOwner',
params: [
'86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY',
{slot: 445000000},
{encoding: 'jsonParsed', limit: 2}
]
})
};
fetch('https://mainnet.helius-rpc.com/?api-key=', 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://mainnet.helius-rpc.com/?api-key=",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'jsonrpc' => '2.0',
'id' => '1',
'method' => 'getHistoricalTokenAccountsByOwner',
'params' => [
'86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY',
[
'slot' => 445000000
],
[
'encoding' => 'jsonParsed',
'limit' => 2
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://mainnet.helius-rpc.com/?api-key="
payload := strings.NewReader("{\n \"jsonrpc\": \"2.0\",\n \"id\": \"1\",\n \"method\": \"getHistoricalTokenAccountsByOwner\",\n \"params\": [\n \"86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY\",\n {\n \"slot\": 445000000\n },\n {\n \"encoding\": \"jsonParsed\",\n \"limit\": 2\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://mainnet.helius-rpc.com/?api-key=")
.header("Content-Type", "application/json")
.body("{\n \"jsonrpc\": \"2.0\",\n \"id\": \"1\",\n \"method\": \"getHistoricalTokenAccountsByOwner\",\n \"params\": [\n \"86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY\",\n {\n \"slot\": 445000000\n },\n {\n \"encoding\": \"jsonParsed\",\n \"limit\": 2\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://mainnet.helius-rpc.com/?api-key=")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"jsonrpc\": \"2.0\",\n \"id\": \"1\",\n \"method\": \"getHistoricalTokenAccountsByOwner\",\n \"params\": [\n \"86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY\",\n {\n \"slot\": 445000000\n },\n {\n \"encoding\": \"jsonParsed\",\n \"limit\": 2\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"jsonrpc": "2.0",
"id": "1",
"result": {
"context": {
"slot": 468129571
},
"value": {
"accounts": [
{
"pubkey": "EKyGnXReqmmXyqBHmMjV2CKCLafJS47xyhXXZ5WuFMxD",
"account": {
"lamports": 531589475273,
"owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"data": [
"<string>"
],
"executable": false,
"rentEpoch": 123,
"space": 82,
"lastUpdatedAt": {
"slot": 444999837,
"transactionIndex": 700
}
}
}
],
"paginationKey": "11112zAgXhc6hGfdfr5anSY91mq7Cs4HHpSVEQc4ASG:EKyGnXReqmmXyqBHmMjV2CKCLafJS47xyhXXZ5WuFMxD"
}
}
}{
"jsonrpc": "2.0",
"error": {
"code": -32602,
"message": "Paramètres non valides"
},
"id": "1"
}{
"jsonrpc": "2.0",
"error": {
"code": -32001,
"message": "Non autorisé"
},
"id": "1"
}{
"jsonrpc": "2.0",
"error": {
"code": -32005,
"message": "Trop de requêtes"
},
"id": "1"
}{
"jsonrpc": "2.0",
"error": {
"code": -32603,
"message": "Erreur interne"
},
"id": "1"
}{
"jsonrpc": "2.0",
"error": {
"code": -32002,
"message": "Service indisponible"
},
"id": "1"
}{
"jsonrpc": "2.0",
"error": {
"code": -32003,
"message": "Délai d’attente de la passerelle dépassé"
},
"id": "1"
}getHistoricalTokenAccountsByOwner est en version bêta. Les paramètres, la tarification, les formats de réponse et la couverture des données peuvent changer.Présentation
getHistoricalTokenAccountsByOwner renvoie les comptes SPL Token et Token-2022 qu’un portefeuille possédait à un slot passé, ou immédiatement après une transaction spécifique de ce slot. Il s’agit d’une méthode RPC exclusive à Helius. La méthode standard getTokenAccountsByOwner renvoie uniquement l’état actuel.
Avec l’encodage jsonParsed, les montants des jetons utilisent le nombre de décimales de chaque mint à la position demandée. Les soldes reflètent donc ce que le portefeuille détenait à ce moment-là.
L’historique est disponible à partir du slot 444,959,999 (7 septembre 2026), qui correspond à l’état au début de l’époque 1030.
getHistoricalTokenAccountsByOwner est disponible sur le mainnet pour les offres Business et supérieures. Chaque appel coûte 0 crédit pendant la période bêta. La tarification est susceptible de changer.
Différences avec getTokenAccountsByOwner
- Le filtre par mint ou par programme est facultatif. Sans filtre, vous obtenez tous les comptes de jetons que le portefeuille possédait. Pour affiner les résultats, définissez soit
mint, soitprogramIddans l’objet de configuration (le troisième paramètre), mais pas les deux. - Le deuxième paramètre est l’objet de requête qui sélectionne la position dans l’historique, et non un filtre par mint ou par programme.
result.valueest un objet contenantaccountsetpaginationKey, et non un tableau.
Choisir une position dans l’historique
Le deuxième paramètre est un objet de requête :- Omis ou
{}: le dernier slot indexé, limité au niveau d’engagement demandé. { "slot": 445000000 }: la fin du slot 445,000,000.{ "slot": 445000000, "transactionIndex": 10 }: immédiatement après l’exécution de la transaction d’index 10 dans ce slot.
Exemple de requête
Cette requête renvoie les comptes de jetons USDC du portefeuille à la fin du slot 445,000,000 :curl https://mainnet.helius-rpc.com/?api-key=YOUR_API_KEY \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": "1",
"method": "getHistoricalTokenAccountsByOwner",
"params": [
"86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY",
{ "slot": 445000000 },
{ "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", "encoding": "jsonParsed" }
]
}'
Parcourir tous les comptes de jetons avec la pagination
Les résultats sont triés d’abord par mint, puis par adresse de compte de jetons. Chaque réponse renvoievalue.accounts et value.paginationKey, un curseur au format <mint>:<tokenAccount>. Transmettez-le dans la requête suivante jusqu’à ce qu’il soit égal à null.
Une page peut contenir peu de résultats, voire être vide, tout en incluant un
paginationKey. Seul un paginationKey égal à null signifie que vous avez atteint la fin.slot explicite lorsque vous utilisez la pagination. Si vous l’omettez, chaque page lit le dernier slot indexé. Les pages peuvent donc provenir de différents moments.
const url = `https://mainnet.helius-rpc.com/?api-key=${process.env.HELIUS_API_KEY}`;
async function getTokenAccountsAt(owner: string, slot: number) {
const accounts = [];
let paginationKey: string | null = null;
do {
const response = await fetch(url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
jsonrpc: "2.0",
id: "1",
method: "getHistoricalTokenAccountsByOwner",
params: [
owner,
{ slot },
{ encoding: "jsonParsed", limit: 1000, ...(paginationKey && { paginationKey }) },
],
}),
});
const { result, error } = await response.json();
if (error) throw new Error(`${error.code}: ${error.message}`);
accounts.push(...result.value.accounts);
paginationKey = result.value.paginationKey;
} while (paginationKey);
return accounts;
}
const tokenAccounts = await getTokenAccountsAt("86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY", 445000000);
Lire la réponse
Chaque entrée devalue.accounts contient le pubkey du compte de jetons et un objet account. L’objet du compte possède les mêmes champs que getAccountInfo, ainsi que lastUpdatedAt :
lastUpdatedAt.slotetlastUpdatedAt.transactionIndexidentifient l’écriture qui a produit cet état.- Un
lastUpdatedAt.slotégal à 444,959,999 avec untransactionIndexégal ànullsignifie que le compte de jetons n’a pas changé depuis le début de la couverture historique. context.slotest le dernier slot que Helius avait indexé au moment de traiter la requête, et non le slot interrogé.
Erreurs
| Code | Signification |
|---|---|
-32018 | Le slot est antérieur au début de la couverture historique (slot 444,959,999) |
-32004 | Le slot est plus récent que ne l’autorise le niveau d’engagement demandé. Utilisez confirmed ou interrogez un slot plus ancien |
-32602 | Paramètres non valides, par exemple mint et programId définis simultanément, un programId qui n’est pas un programme de jetons, ou un paginationKey dont le mint ne correspond pas à mint |
-32601 | Méthode introuvable. Appelez votre endpoint mainnet Helius ou Gatekeeper ; la méthode n’est pas disponible sur le devnet |
Méthodes associées
Historical Accounts Guide
Découvrez le fonctionnement des positions, de la couverture et de lastUpdatedAt pour les méthodes de comptes historiques
getHistoricalAccountInfo
Lisez un compte unique à un slot passé
getTransactionsForAddress
Trouvez le slot et le transactionIndex des transactions que vous souhaitez examiner
getTokenAccountsByOwnerV2
Parcourez les comptes de jetons actuels d’un portefeuille avec la pagination
Paramètres de la requête
Adresse encodée en base 58 du portefeuille qui possédait les comptes de jetons. Transmettez le portefeuille propriétaire, et non un compte de jetons.
Slot auquel lire l’état. Renvoie le compte tel qu’il était à la fin de ce slot. Le premier slot pris en charge est 444959999, soit l’état au début de l’époque 1030. Si ce paramètre est omis, lit le dernier slot indexé, limité au niveau d’engagement demandé.
Position d’une transaction dans le slot. Renvoie l’état du compte immédiatement après l’exécution de cette transaction, plutôt qu’à la fin du slot. Nécessite slot.
Renvoie uniquement les comptes de jetons correspondant à ce mint. Ne peut pas être combiné avec programId.
Renvoie uniquement les comptes de jetons détenus par ce programme de jetons. Ne peut pas être combiné avec mint.
TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DATokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb
Format d’encodage des données du compte. Avec jsonParsed, les montants des jetons utilisent le nombre de décimales du mint à la position demandée. base58 et binary ne sont pas pris en charge.
base64base64+zstdjsonParsed
Renvoie uniquement une tranche des données de chaque compte. S’applique aux encodages base64 et base64+zstd.
Curseur provenant du paginationKey de la réponse précédente, au format
<mint>:<tokenAccount>. Si vous définissez également mint, le mint du curseur doit lui correspondre.Niveau d’engagement. processed n’est pas pris en charge.
finalizedconfirmed
Autorisations
Votre clé API Helius. Vous pouvez en obtenir une gratuitement dans le tableau de bord.
Corps
application/json
Tableau contenant l’adresse du portefeuille propriétaire, un objet de requête facultatif qui sélectionne la position dans l’historique et un objet de configuration facultatif.
Required array length:
1 - 3 elementsAdresse encodée en base 58 du portefeuille qui détenait les comptes de jetons. Transmettez le portefeuille propriétaire, et non un compte de jetons.
Exemple:
"86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY"
Cette page vous a-t-elle été utile ?
⌘I
getHistoricalTokenAccountsByOwner
curl --request POST \
--url 'https://mainnet.helius-rpc.com/?api-key=' \
--header 'Content-Type: application/json' \
--data '
{
"jsonrpc": "2.0",
"id": "1",
"method": "getHistoricalTokenAccountsByOwner",
"params": [
"86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY",
{
"slot": 445000000
},
{
"encoding": "jsonParsed",
"limit": 2
}
]
}
'import requests
url = "https://mainnet.helius-rpc.com/?api-key="
payload = {
"jsonrpc": "2.0",
"id": "1",
"method": "getHistoricalTokenAccountsByOwner",
"params": [
"86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY",
{ "slot": 445000000 },
{
"encoding": "jsonParsed",
"limit": 2
}
]
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
jsonrpc: '2.0',
id: '1',
method: 'getHistoricalTokenAccountsByOwner',
params: [
'86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY',
{slot: 445000000},
{encoding: 'jsonParsed', limit: 2}
]
})
};
fetch('https://mainnet.helius-rpc.com/?api-key=', 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://mainnet.helius-rpc.com/?api-key=",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'jsonrpc' => '2.0',
'id' => '1',
'method' => 'getHistoricalTokenAccountsByOwner',
'params' => [
'86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY',
[
'slot' => 445000000
],
[
'encoding' => 'jsonParsed',
'limit' => 2
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://mainnet.helius-rpc.com/?api-key="
payload := strings.NewReader("{\n \"jsonrpc\": \"2.0\",\n \"id\": \"1\",\n \"method\": \"getHistoricalTokenAccountsByOwner\",\n \"params\": [\n \"86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY\",\n {\n \"slot\": 445000000\n },\n {\n \"encoding\": \"jsonParsed\",\n \"limit\": 2\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://mainnet.helius-rpc.com/?api-key=")
.header("Content-Type", "application/json")
.body("{\n \"jsonrpc\": \"2.0\",\n \"id\": \"1\",\n \"method\": \"getHistoricalTokenAccountsByOwner\",\n \"params\": [\n \"86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY\",\n {\n \"slot\": 445000000\n },\n {\n \"encoding\": \"jsonParsed\",\n \"limit\": 2\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://mainnet.helius-rpc.com/?api-key=")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"jsonrpc\": \"2.0\",\n \"id\": \"1\",\n \"method\": \"getHistoricalTokenAccountsByOwner\",\n \"params\": [\n \"86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY\",\n {\n \"slot\": 445000000\n },\n {\n \"encoding\": \"jsonParsed\",\n \"limit\": 2\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"jsonrpc": "2.0",
"id": "1",
"result": {
"context": {
"slot": 468129571
},
"value": {
"accounts": [
{
"pubkey": "EKyGnXReqmmXyqBHmMjV2CKCLafJS47xyhXXZ5WuFMxD",
"account": {
"lamports": 531589475273,
"owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"data": [
"<string>"
],
"executable": false,
"rentEpoch": 123,
"space": 82,
"lastUpdatedAt": {
"slot": 444999837,
"transactionIndex": 700
}
}
}
],
"paginationKey": "11112zAgXhc6hGfdfr5anSY91mq7Cs4HHpSVEQc4ASG:EKyGnXReqmmXyqBHmMjV2CKCLafJS47xyhXXZ5WuFMxD"
}
}
}{
"jsonrpc": "2.0",
"error": {
"code": -32602,
"message": "Paramètres non valides"
},
"id": "1"
}{
"jsonrpc": "2.0",
"error": {
"code": -32001,
"message": "Non autorisé"
},
"id": "1"
}{
"jsonrpc": "2.0",
"error": {
"code": -32005,
"message": "Trop de requêtes"
},
"id": "1"
}{
"jsonrpc": "2.0",
"error": {
"code": -32603,
"message": "Erreur interne"
},
"id": "1"
}{
"jsonrpc": "2.0",
"error": {
"code": -32002,
"message": "Service indisponible"
},
"id": "1"
}{
"jsonrpc": "2.0",
"error": {
"code": -32003,
"message": "Délai d’attente de la passerelle dépassé"
},
"id": "1"
}