From 66f1337be05bebd149e4463fb921215119edd0dd Mon Sep 17 00:00:00 2001 From: AmineAfia Date: Mon, 6 Jan 2025 23:38:49 +0000 Subject: [PATCH] Add llms.txt file to insight docs (#5887) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- title: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes" --- If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000): ## Notes for the reviewer Anything important to call out? Be sure to also clarify these in your comments. ## How to test Unit tests, playground, etc. --- ## PR-Codex overview This PR focuses on enhancing the documentation and functionality related to `Agents & LLMs` within the `thirdweb Insight` API, including new links, improved examples, and standardized usage instructions for better integration with AI tools. ### Detailed summary - Added a new link for `llms.txt` in `sidebar.tsx`. - Updated documentation in `page.mdx` to clarify API usage for `Agents & LLMs`. - Revised code examples to use template literals for dynamic values. - Simplified `ChainId` type to a number. - Enhanced error handling and response structure in API examples. - Included detailed instructions on authentication and API endpoints. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` --- .../insight/agents-and-llms/llmstxt/page.mdx | 400 ++++++++++++++++++ .../src/app/insight/agents-and-llms/page.mdx | 146 +++---- apps/portal/src/app/insight/sidebar.tsx | 6 + 3 files changed, 469 insertions(+), 83 deletions(-) create mode 100644 apps/portal/src/app/insight/agents-and-llms/llmstxt/page.mdx diff --git a/apps/portal/src/app/insight/agents-and-llms/llmstxt/page.mdx b/apps/portal/src/app/insight/agents-and-llms/llmstxt/page.mdx new file mode 100644 index 00000000000..f2a7063262c --- /dev/null +++ b/apps/portal/src/app/insight/agents-and-llms/llmstxt/page.mdx @@ -0,0 +1,400 @@ +import { createMetadata } from "@doc"; + +export const metadata = createMetadata({ + title: "thirdweb Insight For Agents & LLMs", + description: + "thirdweb Insight query documentation formatted for use with LLMs and agents", + image: { + title: "Insight", + icon: "insight", + }, +}); + +# Thirdweb Insight +Insight is a powerful tool that lets you retrieve blockchain data from any EVM chain, enrich it with metadata, and transform it using custom logic. Whether you're building a gaming inventory system, tracking DeFi metrics, or analyzing NFT collections, Insight makes it easy to get the data you need with simple API calls. + +## Things to Keep in Mind + +- **Rate Limiting**: The API has rate limits based on your authentication tier. Monitor your usage and implement appropriate retry logic. + +- **Pagination**: When retrieving large datasets, use pagination parameters (`page` and `limit`) to avoid timeouts and manage response sizes effectively. + +- **Chain Selection**: Always verify you're querying the correct chain ID. Using an incorrect chain ID will return a 404 error. + +- **Data Freshness**: There may be a slight delay between on-chain events and their availability in the API due to block confirmation times. + +- **Error Handling**: Implement proper error handling for both HTTP errors (400/500) and network issues. Consider implementing retries for transient failures. + +- **Query Optimization**: + - Use specific filters to reduce response size and improve performance + - Avoid overly broad date ranges when possible + - Consider using aggregations for large datasets + +- **Authentication**: Keep your authentication credentials secure and don't expose them in client-side code. + +- **Response Processing**: Some numeric values are returned as strings to maintain precision. Convert them appropriately in your application. + + +## API URL + +```typescript +const baseUrl = `https://{{chainId}}.insight.thirdweb.com`; +``` + +## Authentication + +The API supports three authentication methods: + +```typescript +// 1. Header Authentication +const headers = { + "x-client-id": "{{clientId}}", // thirdweb Client ID +}; + +// 2. Query Parameter +const url = `https://{{chainId}}.insight.thirdweb.com/v1/events?clientId={{clientId}}`; + +// 3. Bearer Token +const headers = { + Authorization: "Bearer {{jwtToken}}", +}; + +// Example using fetch with header auth +async function getEvents() { + const response = await fetch(`https://{{chainId}}.insight.thirdweb.com/v1/events`, { + headers: { + "x-client-id": "{{clientId}}", + }, + }); + return await response.json(); +} +``` + +## Core Concepts + +### Chain IDs + +The API supports chain IDs in the following format: + +```typescript +interface ChainConfig { + chainId: number; // Chain ID of the network you want to query +} + +// Example: Using a specific chain +const chainId = "{{chainId}}"; // Replace with your desired chain ID +const baseUrl = `https://{{chainId}}.insight.thirdweb.com`; +``` + +### Base Response Structure + +```typescript +interface BaseResponse { + data: T[]; + meta: { + chain_id: number; // Required + page: number; // Required + limit: number; // Required + total_items: number; // Required + total_pages: number; // Required + address?: string; // Optional + signature?: string; // Optional + } +} + +// Example response from getting events +{ + "data": [ + { + "chain_id": 1, + "block_number": "17859301", + "transaction_hash": "0x123...", + "address": "0x456...", + "data": "0x789...", + "topics": ["0xabc..."] + } + ], + "meta": { + "chain_id": 1, + "page": 0, + "limit": 20, + "total_items": 150, + "total_pages": 8 + } +} +``` + +## API Examples + +### Events API + +```typescript +// 1. Get All Events +async function getAllEvents(): Promise> { + const response = await fetch(`https://{{chainId}}.insight.thirdweb.com/v1/events`, { + headers: { "x-client-id": "{{clientId}}" }, + }); + return await response.json(); +} + +// 2. Get Contract Events with Filtering +async function getContractEvents(contractAddress: string): Promise> { + const params = new URLSearchParams({ + filter_block_number_gte: "{{blockNumber}}", + sort_by: "block_timestamp", + sort_order: "desc", + limit: "50", + }); + + const url = `https://{{chainId}}.insight.thirdweb.com/v1/events/${contractAddress}?${params}`; + const response = await fetch(url, { + headers: { "x-client-id": "{{clientId}}" }, + }); + return await response.json(); +} +``` + +### Token Balance API + +```typescript +// 1. Get ERC20 Balances +async function getERC20Balances(ownerAddress: string): Promise { + const response = await fetch( + `https://{{chainId}}.insight.thirdweb.com/v1/tokens/erc20/${ownerAddress}`, + { headers: { "x-client-id": "{{clientId}}" } }, + ); + const data = await response.json(); + // Example response: + // { + // "data": [ + // { + // "tokenAddress": "0x123...", + // "balance": "1000000000000000000" + // } + // ] + // } + return data; +} + +// 2. Get NFT Balances +async function getNFTBalances(ownerAddress: string) { + const response = await fetch( + `https://{{chainId}}.insight.thirdweb.com/v1/tokens/erc721/${ownerAddress}`, + { headers: { "x-client-id": "{{clientId}}" } }, + ); + const data = await response.json(); + // Example response: + // { + // "data": [ + // { + // "collectionAddress": "0x456...", + // "tokenId": "1", + // "balance": "1" + // } + // ] + // } + return data; +} +``` + +### Using Filters + +```typescript +// Example: Get events with complex filtering +async function getFilteredEvents() { + const params = new URLSearchParams({ + // Block filters + filter_block_number_gte: "{{startBlock}}", + filter_block_number_lte: "{{endBlock}}", + + // Time filters + filter_block_timestamp_gte: "{{startTimestamp}}", + + // Transaction filters + filter_from_address: "{{fromAddress}}", + filter_value_gte: "{{minValue}}", // 1 ETH + + // Pagination + page: "0", + limit: "20", + + // Sorting + sort_by: "block_timestamp", + sort_order: "desc", + }); + + const response = await fetch( + `https://{{chainId}}.insight.thirdweb.com/v1/events?${params}`, + { headers: { "x-client-id": "{{clientId}}" } }, + ); + return await response.json(); +} +``` + +### Error Handling + +```typescript +async function safeApiCall() { + try { + const response = await fetch(`https://{{chainId}}.insight.thirdweb.com/v1/events`, { + headers: { "x-client-id": "{{clientId}}" }, + }); + + if (!response.ok) { + const errorData = await response.json(); + // Example error response: + // { "error": "Invalid client ID" } + throw new Error(errorData.error); + } + + return await response.json(); + } catch (error) { + console.error("API Error:", error.message); + throw error; + } +} +``` + +## API Reference + +### Events API + +1. **Get All Events** + +```typescript +GET https://{{chainId}}.insight.thirdweb.com/v1/events +``` + +2. **Get Contract Events** + +```typescript +GET https://{{chainId}}.insight.thirdweb.com/v1/events/:contractAddress +``` + +3. **Get Specific Event Type** + +```typescript +GET https://{{chainId}}.insight.thirdweb.com/v1/events/:contractAddress/:signature +``` + +### Transactions API + +1. **Get All Transactions** + +```typescript +GET https://{{chainId}}.insight.thirdweb.com/v1/transactions +``` + +2. **Get Contract Transactions** + +```typescript +GET https://{{chainId}}.insight.thirdweb.com/v1/transactions/:contractAddress +``` + +3. **Get Specific Transaction Type** + +```typescript +GET https://{{chainId}}.insight.thirdweb.com/v1/transactions/:contractAddress/:signature +``` + +### Token Balance API + +1. **ERC20 Balances** + +```typescript +GET https://{{chainId}}.insight.thirdweb.com/v1/tokens/erc20/:ownerAddress + +interface ERC20Response { + data: ERC20Balance[]; +} + +interface ERC20Balance { + tokenAddress: string; + balance: string; +} +``` + +2. **ERC721 & ERC1155 Balances** + +```typescript +GET https://{{chainId}}.insight.thirdweb.com/v1/tokens/erc721/:ownerAddress +GET https://{{chainId}}.insight.thirdweb.com/v1/tokens/erc1155/:ownerAddress + +interface TokenBalance { + data: NFTBalance[]; +} + +interface NFTBalance { + collectionAddress: string; + tokenId: string; + balance: string; +} +``` + +## Query Parameters + +### Common Parameters + +```typescript +interface CommonQueryParams { + page?: number; // Default: 0 + limit?: number; // Default: 20, must be > 0 + sort_by?: "block_number" | "block_timestamp" | "transaction_index"; + sort_order?: "asc" | "desc"; + group_by?: string; + aggregate?: string[]; +} +``` + +### Filter Types + +1. **Block Filters** + +```typescript +interface BlockFilters { + filter_block_number?: number; // Example: 1000000 + filter_block_number_gte?: number; // Example: 1000000 + filter_block_number_gt?: number; // Example: 1000000 + filter_block_number_lte?: number; // Example: 1000000 + filter_block_number_lt?: number; // Example: 1000000 + filter_block_hash?: string; // Example: "0x3a1fba5..." +} +``` + +2. **Time Filters** + +```typescript +interface TimeFilters { + filter_block_timestamp?: number; // Example: 1715222400 + filter_block_timestamp_gte?: number; // Example: 1715222400 + filter_block_timestamp_gt?: number; // Example: 1715222400 + filter_block_timestamp_lte?: number; // Example: 1715222400 + filter_block_timestamp_lt?: number; // Example: 1715222400 +} +``` + +3. **Transaction Filters** + +```typescript +interface TransactionFilters { + filter_transaction_index?: number; + filter_transaction_hash?: string; + filter_from_address?: string; + filter_value?: number; + filter_gas_price?: number; + filter_gas?: number; + // Additional gte, gt, lte, lt variants for numeric fields +} +``` + +## Error Handling + +All endpoints return standard error responses for 400 and 500 status codes: + +```typescript +// 400 Bad Request +// 500 Internal Server Error +interface ErrorResponse { + error: string; // Required +} +``` diff --git a/apps/portal/src/app/insight/agents-and-llms/page.mdx b/apps/portal/src/app/insight/agents-and-llms/page.mdx index d72b904c726..b228a052896 100644 --- a/apps/portal/src/app/insight/agents-and-llms/page.mdx +++ b/apps/portal/src/app/insight/agents-and-llms/page.mdx @@ -12,14 +12,23 @@ export const metadata = createMetadata({ # For Agents & LLMs -The schema below can be copied and pasted into the AI assistant of your choice. Feed this to your assistant, then ask your assistant to construct Insight queries on your behalf, asking it for certain onchain information. + +Insight is a powerful tool that can be used to power AI agents and LLMs with blockchain data. To use the API in your AI agent you can use the llms.txt file bellow. + + +- [llms.txt file](/insight/agents-and-llms/llmstxt) +- For developers who prefer working with OpenAPI specifications, our complete API documentation is available in OpenAPI format [here](https://insight.thirdweb.com/openapi.json). + +If you prefer to use the API in an LLM prompt, the schema below can be copied and pasted into the AI assistant of your choice. Feed this to your assistant, then ask your assistant to construct Insight queries on your behalf, asking it for certain onchain information. ````markdown # ATTENTION LLMs - API Usage Instructions ## API URL -https://{chain-id}.insight.thirdweb.com +```typescript +const baseUrl = `https://{{chainId}}.insight.thirdweb.com`; +``` ## Authentication @@ -28,22 +37,22 @@ The API supports three authentication methods: ```typescript // 1. Header Authentication const headers = { - "x-client-id": "YOUR_CLIENT_ID", // thirdweb Client ID + "x-client-id": "{{clientId}}", // thirdweb Client ID }; // 2. Query Parameter -const url = "https://1.insight.thirdweb.com/v1/events?clientId=YOUR_CLIENT_ID"; +const url = "https://{{chainId}}.insight.thirdweb.com/v1/events?clientId={{clientId}}"; // 3. Bearer Token const headers = { - Authorization: "Bearer YOUR_JWT_TOKEN", + Authorization: "Bearer {{jwtToken}}", }; // Example using fetch with header auth async function getEvents() { - const response = await fetch("https://1.insight.thirdweb.com/v1/events", { + const response = await fetch("https://{{chainId}}.insight.thirdweb.com/v1/events", { headers: { - "x-client-id": "YOUR_CLIENT_ID", + "x-client-id": "{{clientId}}", }, }); return await response.json(); @@ -54,49 +63,11 @@ async function getEvents() { ### Chain IDs -The API supports the following chain IDs (with 1 as default): - ```typescript -type ChainId = - | "1" - | "2039" - | "30" - | "98865" - | "42793" - | "1952959480" - | "98864" - | "466" - | "37714555429" - | "8008135" - | "55244" - | "42019" - | "8453" - | "480" - | "84532" - | "888888888" - | "43113" - | "19934" - | "7897" - | "2040" - | "37111" - | "33139" - | "80002" - | "8333" - | "660279" - | "42161" - | "11155111" - | "421614" - | "994873017" - | "42026" - | "43114" - | "1946" - | "31" - | "41455" - | "1993" - | "98985"; +type ChainId = number; // Chain ID of the network you want to query (e.g., 1 for Ethereum mainnet) // Example: Using a specific chain -const chainId = "1"; // Ethereum Mainnet +const chainId = 1; // Ethereum mainnet const baseUrl = `https://${chainId}.insight.thirdweb.com`; ``` @@ -121,11 +92,11 @@ interface BaseResponse { "data": [ { "chain_id": 1, - "block_number": "17859301", - "transaction_hash": "0x123...", - "address": "0x456...", - "data": "0x789...", - "topics": ["0xabc..."] + "block_number": "{{blockNumber}}", + "transaction_hash": "{{transactionHash}}", + "address": "{{contractAddress}}", + "data": "{{data}}", + "topics": ["{{topic}}"] } ], "meta": { @@ -145,8 +116,8 @@ interface BaseResponse { ```typescript // 1. Get All Events async function getAllEvents() { - const response = await fetch("https://1.insight.thirdweb.com/v1/events", { - headers: { "x-client-id": "YOUR_CLIENT_ID" }, + const response = await fetch("https://{{chainId}}.insight.thirdweb.com/v1/events", { + headers: { "x-client-id": "{{clientId}}" }, }); return await response.json(); } @@ -154,15 +125,15 @@ async function getAllEvents() { // 2. Get Contract Events with Filtering async function getContractEvents(contractAddress: string) { const params = new URLSearchParams({ - filter_block_number_gte: "17000000", + filter_block_number_gte: blockNumber, sort_by: "block_timestamp", sort_order: "desc", - limit: "50", + limit: "{{limit}}", }); - const url = `https://1.insight.thirdweb.com/v1/events/${contractAddress}?${params}`; + const url = `https://{{chainId}}.insight.thirdweb.com/v1/events/{{contractAddress}}?${params}`; const response = await fetch(url, { - headers: { "x-client-id": "YOUR_CLIENT_ID" }, + headers: { "x-client-id": "{{clientId}}" }, }); return await response.json(); } @@ -174,8 +145,8 @@ async function getContractEvents(contractAddress: string) { // 1. Get ERC20 Balances async function getERC20Balances(ownerAddress: string) { const response = await fetch( - `https://1.insight.thirdweb.com/v1/tokens/erc20/${ownerAddress}`, - { headers: { "x-client-id": "YOUR_CLIENT_ID" } }, + `https://{{chainId}}.insight.thirdweb.com/v1/tokens/erc20/${ownerAddress}`, + { headers: { "x-client-id": "{{clientId}}" } }, ); const data = await response.json(); // Example response: @@ -193,8 +164,8 @@ async function getERC20Balances(ownerAddress: string) { // 2. Get NFT Balances async function getNFTBalances(ownerAddress: string) { const response = await fetch( - `https://1.insight.thirdweb.com/v1/tokens/erc721/${ownerAddress}`, - { headers: { "x-client-id": "YOUR_CLIENT_ID" } }, + `https://{{chainId}}.insight.thirdweb.com/v1/tokens/erc721/${ownerAddress}`, + { headers: { "x-client-id": "{{clientId}}" } }, ); const data = await response.json(); // Example response: @@ -218,28 +189,28 @@ async function getNFTBalances(ownerAddress: string) { async function getFilteredEvents() { const params = new URLSearchParams({ // Block filters - filter_block_number_gte: "17000000", - filter_block_number_lte: "17859301", + filter_block_number_gte: blockNumberStart, + filter_block_number_lte: blockNumberEnd, // Time filters - filter_block_timestamp_gte: "1715222400", + filter_block_timestamp_gte: "{{timestamp}}", // Transaction filters - filter_from_address: "0x123...", - filter_value_gte: "1000000000000000000", // 1 ETH + filter_from_address: "{{fromAddress}}", + filter_value_gte: "{{value}}", // 1 ETH // Pagination - page: "0", - limit: "20", + page: "{{page}}", + limit: "{{limit}}", // Sorting - sort_by: "block_timestamp", - sort_order: "desc", + sort_by: "{{sortBy}}", + sort_order: "{{sortOrder}}", }); const response = await fetch( - `https://1.insight.thirdweb.com/v1/events?${params}`, - { headers: { "x-client-id": "YOUR_CLIENT_ID" } }, + `https://{{chainId}}.insight.thirdweb.com/v1/events?${params}`, + { headers: { "x-client-id": "{{clientId}}" } }, ); return await response.json(); } @@ -250,8 +221,8 @@ async function getFilteredEvents() { ```typescript async function safeApiCall() { try { - const response = await fetch("https://1.insight.thirdweb.com/v1/events", { - headers: { "x-client-id": "YOUR_CLIENT_ID" }, + const response = await fetch("https://{{chainId}}.insight.thirdweb.com/v1/events", { + headers: { "x-client-id": "{{clientId}}" }, }); if (!response.ok) { @@ -276,7 +247,12 @@ async function safeApiCall() { 1. **Get All Events** ```typescript -GET /v1/events; +GET /v1/events + +interface EventsResponse { + data: Event[]; + meta: MetaData; +} ``` 2. **Get Contract Events** @@ -296,7 +272,7 @@ GET /v1/events/:contractAddress/:signature 1. **Get All Transactions** ```typescript -GET / v1 / transactions; +GET /v1/transactions ``` 2. **Get Contract Transactions** @@ -332,7 +308,7 @@ interface ERC20Response { GET /v1/tokens/erc721/:ownerAddress GET /v1/tokens/erc1155/:ownerAddress -interface TokenBalance { +interface TokenBalanceResponse { data: { collectionAddress: string; // Required tokenId: string; // Required @@ -347,12 +323,12 @@ interface TokenBalance { ```typescript interface CommonQueryParams { - page?: number; // Default: 0 - limit?: number; // Default: 20, must be > 0 + page?: number; // Default: 0 + limit?: number; // Default: 20, must be > 0 sort_by?: "block_number" | "block_timestamp" | "transaction_index"; sort_order?: "asc" | "desc"; - group_by?: string; - aggregate?: string[]; + group_by?: string; // Group results by a specific field + aggregate?: string[]; // Apply aggregate functions (count, sum, avg, etc.) to grouped results } ``` @@ -390,7 +366,11 @@ interface TransactionFilters { filter_transaction_index?: number; filter_transaction_hash?: string; filter_from_address?: string; - filter_value?: number; + filter_value?: string; // Value in wei (e.g., "1000000000000000000" for 1 ETH) + filter_value_gte?: string; + filter_value_gt?: string; + filter_value_lte?: string; + filter_value_lt?: string; filter_gas_price?: number; filter_gas?: number; // Additional gte, gt, lte, lt variants for numeric fields diff --git a/apps/portal/src/app/insight/sidebar.tsx b/apps/portal/src/app/insight/sidebar.tsx index 40027e80201..ae45ab9a374 100644 --- a/apps/portal/src/app/insight/sidebar.tsx +++ b/apps/portal/src/app/insight/sidebar.tsx @@ -28,6 +28,12 @@ export const sidebar: SideBar = { { name: "Agents & LLMs", href: `${insightSlug}/agents-and-llms`, + links: [ + { + name: "llms.txt", + href: `${insightSlug}/agents-and-llms/llmstxt`, + }, + ], }, { name: "API Reference",