Node Service: send and debug a request

Send a request. See the error in your Shinami dashboard. Look up what to do in our Error Guide.

You'll learn how to

  • Send a request to Aptos Node Service (both the REST API and GraphQL API)
  • View your requests and error codes in your Shinami dashboard
  • Get guidance on a specific error code in our Error guide.

Initial Setup

1. Create a Shinami account

You’ll need a Shinami account to follow this quick-start guide.

2. Create an API Access Key

To use Shinami's products, you need an API access key to authenticate your requests. Set up a Node Access key for Testnet as shown here in our Authentication and API Keys guide

Send a REST API Request

1. Make a request

Here is an example GET /accounts/address request that returns a not found error. We're producing the error by sending an address that doesn't exist. This is on purpose so we can show you how to use your dashboard and our error guide. We'll fix the request below.

The TypeScript example uses the Shinami Clients SDK.

curl https://api.shinami.com/aptos/node/v1/accounts/0x94db619929656f03fe42081c3d421cdd3caa3bf5346fe8cf22d49dbfda540ea \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_TESTNET_NODE_ACCESS_KEY"
import { createAptosClient } from "@shinami/clients/aptos";
const shinamiAptosClient = createAptosClient("YOUR_TESTNET_NODE_ACCESS_KEY");

const resp = await aptosClient.getAccountInfo({ accountAddress: "0x94db619929656f03fe42081c3d421cdd3caa3bf5346fe8cf22d49dbfda540ea0" });
console.log(resp);

Example Response

{
  "message":"Account not found by Address(0x94db619929656f03fe42081c3d421cdd3caa3bf5346fe8cf22d49dbfda540ea) and Ledger version(6190817592)",
  "error_code":"account_not_found",
  "vm_error_code":null
}
[AptosApiError]: Request to [Fullnode]: GET https://api.shinami.com/aptos/node/v1/accounts/0x094db619929656f03fe42081c3d421cdd3caa3bf5346fe8cf22d49dbfda540ea0 failed with: {"message":"Account not found by Address(0x94db619929656f03fe42081c3d421cdd3caa3bf5346fe8cf22d49dbfda540ea0) and Ledger version(6190822871)","error_code":"account_not_found","vm_error_code":null}
    at ... {
  url: 'https://api.shinami.com/aptos/node/v1/accounts/0x094db619929656f03fe42081c3d421cdd3caa3bf5346fe8cf22d49dbfda540ea0',
  status: 404,
  statusText: 'Not Found',
  data: {
    message: 'Account not found by Address(0x94db619929656f03fe42081c3d421cdd3caa3bf5346fe8cf22d49dbfda540ea) and Ledger version(6190822871)',
    error_code: 'account_not_found',
    vm_error_code: null
  },
  request: {
    url: 'https://api.shinami.com/aptos/node/v1',
    method: 'GET',
    originMethod: 'getInfo',
    path: 'accounts/0x094db619929656f03fe42081c3d421cdd3caa3bf5346fe8cf22d49dbfda540ea',
    contentType: undefined,
    acceptType: undefined,
    params: undefined,
    overrides: {
      API_KEY: 'aptos_testnet_b4511a5a676faaf92965d1228b9fc6cb',
      HEADERS: {}
    }
  }
}

2. View the request and error in your dashboard

Visit the "REST API Insights" tab of the Aptos Node Service page in your Shinami dashboard. Note that it can take a few minutes for a request to show up. If your request hasn't shown up yet, just keep reading this doc to learn about the metrics and error guide, then refresh the insights page when you're done.

  1. Each service has its own page with its own API insights.
  2. Some services, like Aptos Node Service, have tabs to choose between multiple sets of insights.
  3. Filters: I've chosen "Aptos Testnet" and "Last 60 minutes" to narrow down to this one error. You can also filter by a specific API key and by a specific method. The default is "All keys" and "All methods" as shown above.
  4. Summary metrics: a great place to get a quick overview of your integration health. If there's an issue - like a lot of rate-limit or other errors, you can scroll down to the graphs below to see more detail, like the time it occurred.
  5. Graphs: this is the first one, showing the request we've sent. If you sent more, you'll see those as well, grouped by request name.

Scroll down to view more graphs, including a breakdown by Aptos and HTTP error codes. These are grouped by error code across all requests that match the filter at the top of the page, so remember that you can filter by a specific method name if needed. You can learn more about the graphs on the page in our Help Center.

After taking the screenshot above, I sent two more failed requests, which is why there are now three entries:

3. See what the error means in our Error guide

Our Error guide has an overall section for all Shinami Services, as well as a specific section for each service, including Aptos REST API. If we go there you can see a sample error, as well as guidance on different HTTP and Aptos error codes. In this case, we can see the potential causes of our 404 account_not_found error.

4. Send a successful request

Our issue was a type. Let's update the request to ask for a address we know has already been initialized on Testnet.

Updated request

curl https://api.shinami.com/aptos/node/v1/accounts/0x94db619929656f03fe42081c3d421cdd3caa3bf5346fe8cf22d49dbfda540eae \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_TESTNET_NODE_ACCESS_KEY"
import { createAptosClient } from "@shinami/clients/aptos";
const shinamiAptosClient = createAptosClient("YOUR_TESTNET_NODE_ACCESS_KEY");

const resp = await aptosClient.getAccountInfo({ accountAddress: "0x94db619929656f03fe42081c3d421cdd3caa3bf5346fe8cf22d49dbfda540eae" });
console.log(resp);

Successful response

{
  "sequence_number":"5297769",
  "authentication_key":"0x94db619929656f03fe42081c3d421cdd3caa3bf5346fe8cf22d49dbfda540eae"
}
{
  sequence_number: '5297750',
  authentication_key: '0x94db619929656f03fe42081c3d421cdd3caa3bf5346fe8cf22d49dbfda540eae'
}

To read about what these return fields mean, see our API doc.

Send a GraphQL API Request

1. Make a request

Here is an example that queries the tokens currently owned by an account. However, something is wrong with it (on purpose so we can show you how to use your dashboard graphs - we'll fix it below).

Example Request

The TypeScript example uses the Shinami Clients SDK.

curl -X POST https://api.shinami.com/aptos/graphql/v1 \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TESTNET_NODE_ACCESS_KEY" \
-d '{ 
      "query":"query MyQuery {current_token_ownerships_v0( where: { owner_address: { _eq: \"0x3b1e399fb3e5362e57df0a8a7716974428a33fa8d3e391bf00d6acd2fa4a1c31\" }, amount: { _gt: \"0\" } } ) { current_token_data { token_uri token_standard token_properties token_name token_data_id supply maximum is_fungible_v2 description collection_id largest_property_version_v1 last_transaction_timestamp last_transaction_version decimals current_collection { collection_id collection_name collection_properties creator_address current_supply description max_supply}} amount is_fungible_v2 is_soulbound_v2 last_transaction_timestamp last_transaction_version token_standard token_properties_mutated_v1 token_data_id table_type_v1 storage_id property_version_v1 owner_address}}" 
    }' | json_pp


import { createAptosClient } from "@shinami/clients/aptos";
const shinamiAptosClient = createAptosClient("YOUR_TESTNET_NODE_ACCESS_KEY");

const data = await aptosClient.queryIndexer({
  query: {
    query: `query MyQuery {
  current_token_ownerships_v0(
    where: { 
    owner_address: {
     _eq: "0x3b1e399fb3e5362e57df0a8a7716974428a33fa8d3e391bf00d6acd2fa4a1c31" 
     }, 
     amount: { _gt: "0" } }
  ) {
    current_token_data {
      token_uri
      token_standard
      token_properties
      token_name
      token_data_id
      supply
      maximum
      is_fungible_v2
      description
      collection_id
      largest_property_version_v1
      last_transaction_timestamp
      last_transaction_version
      decimals
      current_collection {
        collection_id
        collection_name
        collection_properties
        creator_address
        current_supply
        description
        max_supply
      }
    }
    amount
    is_fungible_v2
    is_soulbound_v2
    last_transaction_timestamp
    last_transaction_version
    token_standard
    token_properties_mutated_v1
    token_data_id
    table_type_v1
    storage_id
    property_version_v1
    owner_address
  }
}`
  }
});

console.log(data);

Example Response

{
   "errors" : [
      {
         "extensions" : {
            "code" : "validation-failed",
            "path" : "$.selectionSet.current_token_ownerships_v0"
         },
         "message" : "field 'current_token_ownerships_v0' not found in type: 'query_root'"
      }
   ]
}
[AptosApiError]: Request to [Indexer]: POST https://api.shinami.com/aptos/graphql/v1 failed with: field 'current_token_ownerships_v0' not found in type: 'query_root'
    at ... {
  url: 'https://api.shinami.com/aptos/graphql/v1',
  status: 200,
  statusText: 'OK',
  data: {
    errors: [
      {
        message: "field 'current_token_ownerships_v0' not found in type: 'query_root'",
        extensions: {
          path: '$.selectionSet.current_token_ownerships_v0',
          code: 'validation-failed'
        }
      }
    ]
  },
  request: {
    url: 'https://api.shinami.com/aptos/graphql/v1',
    method: 'POST',
...
}

2. View the request and error in your dashboard

Visit the "GraphQL API Insights" tab of the Aptos Node Service page in your Shinami dashboard. Note that it can take a few minutes for a request to show up. If your request hasn't shown up yet, just keep reading this doc to learn about the metrics and error guide, then refresh the insights page when you're done.

  1. Each service has its own page with its own API insights.
  2. Some services, like Aptos Node Service, have tabs to choose between multiple sets of insights.
  3. Filters: I've chosen "Aptos Testnet" and "Last 60 minutes" to narrow down to our request. You can also filter by a specific API key. The default is "All keys" as shown above.
  4. Summary metrics: a great place to get a quick overview of your integration health. If there's an issue - like a lot of rate-limit or other errors, you can scroll down to the graphs below to see more detail, like the time it occurred.
  5. Graphs: this is the first one, showing the count of HTTP requests sent.

Scroll down to view more graphs, including the Root Field Metrics as shown below. "Request Metrics" are at the level of HTTP request. Since a GraphQL request could have more than root field (top-level query), we provide these metrics also.

  1. You can toggle to only show requests with one root field present. This is especially useful for the latency graphs at the bottom of the page. You can learn more about this and see an example request with two root fields in our Help Center.
  2. When you send a root field we don't recognize, we map it to q:_other , where q means query. If you sent one we did recognize, like current_token_ownerships_v2, it would show up as q:current_token_ownerships_v2.
  3. The error ratio for q:_other is 100% in the minute I sent the event, as expected - 1/1 requests had an error. Note that this shows HTTP 200s, meaning the error in question is not an HTTP error but a GraphQL error.

3. Understanding and fixing the error

Our GraphQL API can return HTTP and GraphQL errors, as summarized in our Error Reference. The error we received was a GraphQL error that tells us that the validation failed with message "field 'current_token_ownerships_v0' not found in type: 'query_root'".

Indeed, current_token_ownerships_v0 is not a table you can look things up in. What we want is current_token_ownerships_v2. You can see the available tables and fields we support querying, and create and run sample queries, using Hasura's graphqurl as shown here. Here is an image below showing the relevant table (screenshot of my localhost running graphqurl):

4. Send a successful a request

Below, we updated the requests to use the valid field current_token_ownerships_v2. Note the addition of a new tab: "Shinami TypeScript SDK: built-in method". Using the built in SDK methods will help avoid running into some naming issues because it will populate names for you. It may be good to start with these and write custom queries when you need more flexibility.

Example Request

The TypeScript example uses the Shinami Clients SDK.

import { createAptosClient } from "@shinami/clients/aptos";
const shinamiAptosClient = createAptosClient("YOUR_TESTNET_NODE_ACCESS_KEY");

let walletAddress = "0x3b1e399fb3e5362e57df0a8a7716974428a33fa8d3e391bf00d6acd2fa4a1c31";
const data: GetAccountOwnedTokensQueryResponse = await aptosClient.getAccountOwnedTokens({
  accountAddress: walletAddress
});
console.log(data);
import { createAptosClient } from "@shinami/clients/aptos";
const shinamiAptosClient = createAptosClient("YOUR_TESTNET_NODE_ACCESS_KEY");

const data = await aptosClient.queryIndexer({
  query: {
    query: `query MyQuery {
  current_token_ownerships_v2(
    where: { 
    owner_address: {
     _eq: "0x3b1e399fb3e5362e57df0a8a7716974428a33fa8d3e391bf00d6acd2fa4a1c31" 
     }, 
     amount: { _gt: "0" } }
  ) {
    current_token_data {
      token_uri
      token_standard
      token_properties
      token_name
      token_data_id
      supply
      maximum
      is_fungible_v2
      description
      collection_id
      largest_property_version_v1
      last_transaction_timestamp
      last_transaction_version
      decimals
      current_collection {
        collection_id
        collection_name
        collection_properties
        creator_address
        current_supply
        description
        max_supply
      }
    }
    amount
    is_fungible_v2
    is_soulbound_v2
    last_transaction_timestamp
    last_transaction_version
    token_standard
    token_properties_mutated_v1
    token_data_id
    table_type_v1
    storage_id
    property_version_v1
    owner_address
  }
}`
  }
});

console.log(data);
curl -X POST https://api.shinami.com/aptos/graphql/v1 \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TESTNET_NODE_ACCESS_KEY" \
-d '{ 
      "query":"query MyQuery {current_token_ownerships_v2( where: { owner_address: { _eq: \"0x3b1e399fb3e5362e57df0a8a7716974428a33fa8d3e391bf00d6acd2fa4a1c31\" }, amount: { _gt: \"0\" } } ) { current_token_data { token_uri token_standard token_properties token_name token_data_id supply maximum is_fungible_v2 description collection_id largest_property_version_v1 last_transaction_timestamp last_transaction_version decimals current_collection { collection_id collection_name collection_properties creator_address current_supply description max_supply}} amount is_fungible_v2 is_soulbound_v2 last_transaction_timestamp last_transaction_version token_standard token_properties_mutated_v1 token_data_id table_type_v1 storage_id property_version_v1 owner_address}}" 
    }' | json_pp

Example Response

[
  {
    token_standard: 'v2',
    token_properties_mutated_v1: null,
    token_data_id: '0xc799faf2d8d6d8ce02a01aaf3d7e935d09306064fc434c407e44516059297c31',
    table_type_v1: null,
    storage_id: '0xc799faf2d8d6d8ce02a01aaf3d7e935d09306064fc434c407e44516059297c31',
    property_version_v1: 0,
    owner_address: '0x3b1e399fb3e5362e57df0a8a7716974428a33fa8d3e391bf00d6acd2fa4a1c31',
    last_transaction_version: 6606854092,
    last_transaction_timestamp: '2025-01-28T00:14:19.793008',
    is_soulbound_v2: false,
    is_fungible_v2: null,
    amount: 1,
    current_token_data: {
      collection_id: '0xd4c0c251a38a7af47dc3d1c0868cd0b494efcf72792f945ffe083b5ba04a55c1',
      description: 'A basic sword to help in battle.',
      is_fungible_v2: false,
      largest_property_version_v1: null,
      last_transaction_timestamp: '2025-01-28T00:14:19.793008',
      last_transaction_version: 6606854092,
      maximum: null,
      supply: null,
      token_data_id: '0xc799faf2d8d6d8ce02a01aaf3d7e935d09306064fc434c407e44516059297c31',
      token_name: 'basic sword',
      token_properties: [Object],
      token_standard: 'v2',
      token_uri: 'https://increasing-indigo-platypus.myfilebase.com/ipfs/QmT6RCAd8DJntUT7HGSHYvKSAniSXmMU37hUSRycREj4MV',
      decimals: 0,
      current_collection: [Object]
    }
  }
]
{
  current_token_ownerships_v2: [
    {
      current_token_data: [Object],
      amount: 1,
      is_fungible_v2: null,
      is_soulbound_v2: false,
      last_transaction_timestamp: '2025-01-28T00:14:19.793008',
      last_transaction_version: 6606854092,
      token_standard: 'v2',
      token_properties_mutated_v1: null,
      token_data_id: '0xc799faf2d8d6d8ce02a01aaf3d7e935d09306064fc434c407e44516059297c31',
      table_type_v1: null,
      storage_id: '0xc799faf2d8d6d8ce02a01aaf3d7e935d09306064fc434c407e44516059297c31',
      property_version_v1: 0,
      owner_address: '0x3b1e399fb3e5362e57df0a8a7716974428a33fa8d3e391bf00d6acd2fa4a1c31'
    }
  ]
}
{
   "data" : {
      "current_token_ownerships_v2" : [
         {
            "amount" : 1,
            "current_token_data" : {
               "collection_id" : "0xd4c0c251a38a7af47dc3d1c0868cd0b494efcf72792f945ffe083b5ba04a55c1",
               "current_collection" : {
                  "collection_id" : "0xd4c0c251a38a7af47dc3d1c0868cd0b494efcf72792f945ffe083b5ba04a55c1",
                  "collection_name" : "Epic Figtherz Battlez Collection",
                  "collection_properties" : null,
                  "creator_address" : "0x6335b680887e0f09d84dbd31941c412ad5e85308e549f30d88544e8512d82fd6",
                  "current_supply" : 4,
                  "description" : "Items fo the best game in the world",
                  "max_supply" : 1000
               },
               "decimals" : 0,
               "description" : "A basic sword to help in battle.",
               "is_fungible_v2" : false,
               "largest_property_version_v1" : null,
               "last_transaction_timestamp" : "2025-01-28T00:14:19.793008",
               "last_transaction_version" : 6606854092,
               "maximum" : null,
               "supply" : null,
               "token_data_id" : "0xc799faf2d8d6d8ce02a01aaf3d7e935d09306064fc434c407e44516059297c31",
               "token_name" : "basic sword",
               "token_properties" : {
                  "durability" : "100",
                  "power" : "80"
               },
               "token_standard" : "v2",
               "token_uri" : "https://increasing-indigo-platypus.myfilebase.com/ipfs/QmT6RCAd8DJntUT7HGSHYvKSAniSXmMU37hUSRycREj4MV"
            },
            "is_fungible_v2" : null,
            "is_soulbound_v2" : false,
            "last_transaction_timestamp" : "2025-01-28T00:14:19.793008",
            "last_transaction_version" : 6606854092,
            "owner_address" : "0x3b1e399fb3e5362e57df0a8a7716974428a33fa8d3e391bf00d6acd2fa4a1c31",
            "property_version_v1" : 0,
            "storage_id" : "0xc799faf2d8d6d8ce02a01aaf3d7e935d09306064fc434c407e44516059297c31",
            "table_type_v1" : null,
            "token_data_id" : "0xc799faf2d8d6d8ce02a01aaf3d7e935d09306064fc434c407e44516059297c31",
            "token_properties_mutated_v1" : null,
            "token_standard" : "v2"
         }
      ]
   }
}

Next step: build on Aptos! 🏗