[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6GNQTHPFC3VBGRRG1C14K84":3,"skill-same:01M6GNQTHPFC3VBGRRG1C14K84":209},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":31,"publishedAt":53,"linkOnly":54,"markdownContent":55,"markdownBody":56,"frontMatter":57,"refName":141,"commitSha":142,"skillDirectory":143,"forksCount":144,"repositoryHtmlUrl":145,"repositoryHomepageUrl":6,"ownerHtmlUrl":146,"ownerBlogUrl":147,"ownerDescription":148,"updatedAt":149,"install":150,"resources":162},"01M6GNQTHPFC3VBGRRG1C14K84","santiment-api",null,"Query the Santiment GraphQL API for on-chain, financial, social, and development crypto metrics across 2,000+ assets","jiayaoqijia\u002Fcryptoskill","jiayaoqijia","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F1453879?v=4","01M6GMYTX7Q7S504VC6E756ENR","YQ","01M6GMYV1QKJ1CC75MTTGT9PR0",81,"AGPL-3.0","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fai-crypto\u002Fxspoonai-official-santiment-api\u002FSKILL.md",[18,23,28],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000010","后端与接口","SCENARIO","使用场景",{"categoryNo":24,"categoryName":25,"taxonomyType":26,"taxonomyTypeDesc":27},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",{"categoryNo":29,"categoryName":30,"taxonomyType":26,"taxonomyTypeDesc":27},"01JBSEEDCAT000000000000033","数据分析师",[32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52],"api","santiment api","whale","analysis","santiment","flows","now","expression","chain","false","cardano","iso","end","get","discover","volume","time","query","social","usd","fetch","2026-11-10 10:12:30",false,"---\nname: santiment-api\ndescription: Query the Santiment GraphQL API for on-chain, financial, social, and development crypto metrics across 2,000+ assets\nversion: 1.1.5\nauthor: Santiment \u003Csupport@santiment.net>\ntags: [santiment, crypto, graphql, on-chain, metrics, blockchain, defi, exchange-flows, social-sentiment, mvrv, whale-tracking]\n\ntriggers:\n  - type: keyword\n    keywords: [santiment, crypto metrics, on-chain data, exchange flows, mvrv, nvt, social volume, whale tracking, active addresses, crypto analytics, token age, exchange inflow, exchange outflow, dev activity]\n    priority: 90\n  - type: pattern\n    patterns:\n      - \"(?i)(query|fetch|get)\\\\s+(santiment|crypto|on-chain)\"\n      - \"(?i)santiment\\\\s+api\"\n      - \"(?i)(mvrv|nvt|exchange.*(inflow|outflow|balance))\"\n      - \"(?i)(daily.active.addresses|social.volume|dev.activity)\"\n    priority: 85\n  - type: intent\n    intent_category: crypto_data_analysis\n    priority: 95\n\nparameters:\n  - name: metric\n    type: string\n    required: false\n    description: Santiment metric name (e.g., price_usd, daily_active_addresses, mvrv_usd)\n  - name: slug\n    type: string\n    required: false\n    description: Asset identifier (e.g., bitcoin, ethereum, cardano)\n  - name: from\n    type: string\n    required: false\n    description: Start of time range (ISO 8601 or relative expression like utc_now-7d)\n  - name: to\n    type: string\n    required: false\n    description: End of time range (ISO 8601 or relative expression like utc_now)\n  - name: interval\n    type: string\n    required: false\n    default: \"1d\"\n    description: Data granularity (5m, 1h, 1d, 7d)\n\nprerequisites:\n  env_vars:\n    - SANTIMENT_API_KEY\n  skills: []\n\ncomposable: true\npersist_state: false\n\nscripts:\n  enabled: true\n  working_directory: .\u002Fscripts\n  definitions:\n    - name: santiment_query\n      description: Execute a Santiment GraphQL query for any metric, asset, and time range\n      type: python\n      file: santiment_query.py\n      timeout: 30\n    - name: santiment_discovery\n      description: Discover available metrics and asset slugs from the Santiment API\n      type: python\n      file: santiment_discovery.py\n      timeout: 30\n\nmetadata:\n  openclaw:\n    emoji: \"?\"\n    requires:\n      env: [SANTIMENT_API_KEY]\n    primaryEnv: SANTIMENT_API_KEY\n---\n\n# Santiment GraphQL API\n\nQuery the Santiment API — a GraphQL platform providing 750+ metrics for 2,000+ crypto assets across 12 blockchains. Fetch on-chain, financial, social, and development data for the cryptocurrency market.\n\n## Endpoint and Authentication\n\n- **GraphQL endpoint:** `https:\u002F\u002Fapi.santiment.net\u002Fgraphql`\n- **Interactive explorer:** `https:\u002F\u002Fapi.santiment.net\u002Fgraphiql`\n\nEvery request requires an API key in the `Authorization` header (`Authorization: Apikey \u003CKEY>`). The user must provide their own key — never hardcode or assume one. If `$SANTIMENT_API_KEY` is set in the environment, use it directly. Otherwise, ask the user for their key (free tier available at https:\u002F\u002Fapp.santiment.net\u002Faccount#api-keys).\n\nAll requests are HTTP `POST` with `Content-Type: application\u002Fjson`. **Use GraphQL variables** to separate the query template from runtime values — this avoids quote-escaping errors. In curl, use a heredoc with a quoted delimiter (`\u003C\u003C 'QUERY'`) so the shell doesn't interpret `$variable` as environment variables.\n\n```bash\ncurl -s -X POST https:\u002F\u002Fapi.santiment.net\u002Fgraphql \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -H \"Authorization: Apikey $SANTIMENT_API_KEY\" \\\n  -d @- \u003C\u003C 'QUERY'\n{\n  \"query\": \"query($metric: String!, $slug: String, $from: DateTime!, $to: DateTime!, $interval: interval) { getMetric(metric: $metric) { timeseriesData(slug: $slug, from: $from, to: $to, interval: $interval) { datetime value } } }\",\n  \"variables\": {\n    \"metric\": \"price_usd\",\n    \"slug\": \"bitcoin\",\n    \"from\": \"utc_now-7d\",\n    \"to\": \"utc_now\",\n    \"interval\": \"1d\"\n  }\n}\nQUERY\n```\n\n### Variable Types\n\nUse these GraphQL types in `query(...)` variable declarations:\n\n| Parameter | Type |\n|---|---|\n| `metric` | `String!` |\n| `slug` | `String` |\n| `selector` | `MetricTargetSelectorInputObject` |\n| `from` \u002F `to` | `DateTime!` |\n| `interval` | `interval` |\n| `aggregation` | `Aggregation` |\n| `transform` | `TimeseriesMetricTransformInputObject` |\n\n## Core Query: `getMetric`\n\nNearly all data flows through `getMetric`. Pass a metric name string and then select one sub-field that determines the shape of the response data.\n\n### Sub-fields\n\nChoose exactly one sub-field per `getMetric` call:\n\n| Sub-field | Returns | When to use |\n|---|---|---|\n| `timeseriesData` | `[{datetime, value}]` | Default choice — returns a time series with explicit field selection. Use for charting, trend analysis, or any case where individual data points matter. |\n| `timeseriesDataJson` | Pre-formatted JSON string | Quick dump without specifying return fields. Useful for rapid prototyping but less control over output shape. |\n| `timeseriesDataPerSlugJson` | JSON object keyed by slug | Fetch the same metric for multiple assets in a single API call. Pass `selector: { slugs: [\"bitcoin\", \"ethereum\"] }`. This counts as one API call, making it much more efficient than separate queries per asset. |\n| `aggregatedTimeseriesData` | Single numeric value | Need one summary number (average, sum, last value) over a time range. Lowest complexity, most quota-friendly. |\n| `histogramData` | Array of bucketed ranges | Distribution data — e.g., how much ETH was bought at each price range. Less commonly needed. |\n| `metadata` | Metric metadata object | Discover available slugs, aggregations, selectors, intervals, and data type for a metric. Call this before querying an unfamiliar metric. |\n| `availableSince` | ISO 8601 date string | Check how far back data exists for a given metric and slug. Prevents wasted calls on empty time ranges. A return value of `1970-01-01T00:00:00Z` means the metric has **never been computed** for this slug. |\n| `lastDatetimeComputedAt` | ISO 8601 timestamp | Check data freshness — when the metric was last computed for a slug. |\n\n### Parameters\n\nThese parameters are passed to the sub-field, not to `getMetric` itself:\n\n| Parameter | Type | Description | Example |\n|---|---|---|---|\n| `slug` | String | Asset identifier. Use for single-asset queries. | `\"bitcoin\"`, `\"ethereum\"` |\n| `selector` | Object | Advanced selection. Use instead of `slug` when you need multi-asset queries, or filtering by `owner`, `label`, `holdersCount`, or `source`. | `{ slug: \"bitcoin\", source: \"cryptocompare\" }` |\n| `from` | String | Start of time range. Accepts ISO 8601 timestamps or relative expressions. | `\"2024-01-01T00:00:00Z\"`, `\"utc_now-30d\"` |\n| `to` | String | End of time range. Same format as `from`. | `\"utc_now\"` |\n| `interval` | String | Time granularity between data points. | `\"5m\"`, `\"1h\"`, `\"1d\"`, `\"7d\"` |\n| `aggregation` | Enum | Override the default aggregation method. Options: `AVG`, `SUM`, `LAST`, `FIRST`, `MEDIAN`, `MAX`, `MIN`, `ANY`. | `AVG` |\n| `transform` | Object | Post-processing transform applied to the result. | See Transforms section. |\n\n**Important:** `slug` and `selector` are mutually exclusive. Use `slug` for simple single-asset queries. Use `selector` when querying multiple slugs at once (`{ slugs: [...] }`) or when a metric requires additional selector fields like `holdersCount` or `owner`.\n\n### Relative Time Expressions\n\nThe `from` and `to` fields accept relative expressions: `utc_now-\u003CN>\u003Cunit>` where unit is `d` (day), `w` (week), `m` (month), or `y` (year). Preferred over hardcoded dates.\n\n- `\"utc_now\"` — current time\n- `\"utc_now-7d\"` — 7 days ago\n- `\"utc_now-1m\"` — 1 month ago\n- `\"utc_now-1y\"` — 1 year ago\n\n### Transforms\n\nApply transforms directly in the query to post-process data server-side. Pass the `transform` parameter to `timeseriesData`:\n\n| Transform | Effect | Use case |\n|---|---|---|\n| `{type: \"moving_average\", movingAverageBase: N}` | Replace each value with the average of the preceding N values | Smooth noisy metrics like MVRV, social volume |\n| `{type: \"consecutive_differences\"}` | Replace each value with the difference from the prior value | Compute daily change from a cumulative metric |\n| `{type: \"percent_change\"}` | Replace each value with the percent change from the prior value | Normalize changes across metrics with different scales |\n\nTransforms reduce the number of returned data points by N-1 for moving averages. Request a slightly wider time range to compensate.\n\n## Dynamic Discovery\n\nWhen you don't know the exact metric name for a user's request, follow this 3-step workflow. Always prefer dynamic discovery over hardcoded values.\n\n### Step 1 — Fetch the metric list\n\n```graphql\n{\n  getAvailableMetrics\n}\n```\n\nReturns 1,000+ `snake_case` strings. **The response is large** — save to a file with `-o` and read it directly (e.g., `open()` in Python). Do not pipe the contents through stdin at any stage — neither from curl nor when processing the file afterward:\n\n```bash\ncurl -s -X POST https:\u002F\u002Fapi.santiment.net\u002Fgraphql \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -H \"Authorization: Apikey \u003CYOUR_API_KEY>\" \\\n  -d '{\"query\": \"{ getAvailableMetrics }\"}' \\\n  -o \u002Ftmp\u002Fsantiment-metrics.json\n```\n\nFilter by plan with `getAvailableMetrics(product: SANAPI, plan: BUSINESS_PRO)`.\n\n### Step 2 — Search by keywords\n\nSearch the saved file for keywords matching user intent. Example: whale activity → search for `holder`, `top`, `whale`, `supply`, `amount_in`. See `references\u002Fmetrics-catalog.md` for intent-to-keyword mappings.\n\n### Step 3 — Inspect metadata before querying\n\nOnce you have candidate metrics, fetch metadata to confirm compatibility:\n\n```graphql\n{\n  getMetric(metric: \"amount_in_top_holders\") {\n    metadata {\n      availableSlugs\n      availableAggregations\n      availableSelectors\n      dataType\n      defaultAggregation\n      minInterval\n    }\n  }\n}\n```\n\nThis reveals required selectors (e.g., `holdersCount`), supported slugs, and minimum interval. Requesting a smaller interval than `minInterval` returns an error. See `examples\u002Fquery-patterns.md` example 5 for a worked example.\n\n### Find a project's slug\n\nLook up a specific project by slug to verify it exists and see its details:\n\n```graphql\n{\n  projectBySlug(slug: \"bitcoin\") {\n    slug\n    name\n    ticker\n    infrastructure\n  }\n}\n```\n\nBrowse all projects paginated (useful when the user provides a token name or ticker instead of a slug):\n\n```graphql\n{\n  allProjects(page: 1, pageSize: 50) {\n    slug\n    name\n    ticker\n  }\n}\n```\n\n### Check data availability for a metric and slug\n\nBefore making a large timeseries query, verify that data exists for the desired metric-slug combination and check freshness:\n\n```graphql\n{\n  getMetric(metric: \"daily_active_addresses\") {\n    availableSince(slug: \"ethereum\")\n    lastDatetimeComputedAt(slug: \"ethereum\")\n  }\n}\n```\n\n### Check access restrictions for your plan\n\nUnderstand what historical range your API key can access for each metric. Call this to avoid wasted queries that would return restriction errors:\n\n```graphql\n{\n  getAccessRestrictions(product: SANAPI, plan: BUSINESS_PRO, filter: METRIC) {\n    name\n    isAccessible\n    isRestricted\n    restrictedFrom\n    restrictedTo\n    minInterval\n  }\n}\n```\n\n## Error Handling\n\nThe API always returns HTTP **200**, even for errors. Always parse the JSON and check for the `errors` array.\n\nA typical error response:\n\n```json\n{\n  \"data\": { \"getMetric\": null },\n  \"errors\": [\n    {\n      \"message\": \"The metric 'nonexistent_metric' is not a valid metric.\",\n      \"locations\": [{ \"line\": 2, \"column\": 3 }]\n    }\n  ]\n}\n```\n\nWhen `data` contains `null` and `errors` is present, the query failed. Common errors:\n\n| Error | Cause | Fix |\n|---|---|---|\n| Invalid metric name | Metric string doesn't exist | Verify with `getAvailableMetrics` |\n| Invalid slug | Asset slug not recognized | Verify with `allProjects` or `projectBySlug` |\n| Interval too small | Requested interval below minimum for this metric or plan | Check `metadata { minInterval }` |\n| Time range restricted | Historical range exceeds plan allowance | Check `getAccessRestrictions` |\n| Complexity too high | Query requests too many data points | Reduce time range, increase interval, or fetch fewer fields |\n| HTTP 429 | Rate limit exceeded | Back off exponentially and retry after a delay |\n| Empty timeseries (no error) | On-chain metric not computed for this asset's chain | Check `availableSince` for epoch, then `projectBySlug { infrastructure }`. See `references\u002Fmetrics-catalog.md` Ghost Data section. |\n\n**Empty data is not the same as zero data.** When `timeseriesData` returns `[]` without errors, do NOT tell the user there is no activity. On-chain metrics are only computed for indexed chains. Check `references\u002Fmetrics-catalog.md` Ghost Data section for the diagnostic flow.\n\nThe one exception to the HTTP 200 rule is rate limiting: HTTP **429** means the account's quota is exhausted. See `references\u002Frate-limits.md` for details.\n\n## Quick Reference: Building a Query\n\nFollow these steps to construct any Santiment API query:\n\n1. **Pick a metric** — use directly if known, otherwise follow Discovery Workflow.\n2. **Pick a slug** — resolve names\u002Ftickers via `projectBySlug` or `allProjects`.\n3. **Pick a time range** — relative expressions preferred. Check `availableSince` first.\n4. **Pick an interval** — `\"1d\"`, `\"1h\"`, `\"7d\"`. Larger intervals reduce complexity.\n5. **Pick a sub-field** — `timeseriesData` for series, `aggregatedTimeseriesData` for single value, `timeseriesDataPerSlugJson` for multi-asset.\n6. **Optionally add** — `transform`, `selector` (instead of `slug`), or `aggregation` override.\n7. **If data is empty** — check `availableSince` for epoch. If epoch, the metric isn't computed for this slug's chain. Report unavailability and suggest alternative metrics.\n\nExecute via curl with the user's API key and parse the JSON response. Always check for the `errors` array before processing `data`.\n\n## Additional Resources\n\nConsult these reference files for detailed information:\n\n- **Metrics catalog** — `references\u002Fmetrics-catalog.md` — keyword-to-metric mapping for translating user intent into search terms, plus 20 curated quick-reference metrics and naming conventions\n- **Rate limits** — `references\u002Frate-limits.md` — tier limits, complexity scoring, and optimization strategies to avoid quota exhaustion\n- **Query patterns** — `examples\u002Fquery-patterns.md` — 6 worked examples with both GraphQL and curl, including discovery workflow and ghost data diagnostics\n","# Santiment GraphQL API\n\nQuery the Santiment API — a GraphQL platform providing 750+ metrics for 2,000+ crypto assets across 12 blockchains. Fetch on-chain, financial, social, and development data for the cryptocurrency market.\n\n## Endpoint and Authentication\n\n- **GraphQL endpoint:** `https:\u002F\u002Fapi.santiment.net\u002Fgraphql`\n- **Interactive explorer:** `https:\u002F\u002Fapi.santiment.net\u002Fgraphiql`\n\nEvery request requires an API key in the `Authorization` header (`Authorization: Apikey \u003CKEY>`). The user must provide their own key — never hardcode or assume one. If `$SANTIMENT_API_KEY` is set in the environment, use it directly. Otherwise, ask the user for their key (free tier available at https:\u002F\u002Fapp.santiment.net\u002Faccount#api-keys).\n\nAll requests are HTTP `POST` with `Content-Type: application\u002Fjson`. **Use GraphQL variables** to separate the query template from runtime values — this avoids quote-escaping errors. In curl, use a heredoc with a quoted delimiter (`\u003C\u003C 'QUERY'`) so the shell doesn't interpret `$variable` as environment variables.\n\n```bash\ncurl -s -X POST https:\u002F\u002Fapi.santiment.net\u002Fgraphql \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -H \"Authorization: Apikey $SANTIMENT_API_KEY\" \\\n  -d @- \u003C\u003C 'QUERY'\n{\n  \"query\": \"query($metric: String!, $slug: String, $from: DateTime!, $to: DateTime!, $interval: interval) { getMetric(metric: $metric) { timeseriesData(slug: $slug, from: $from, to: $to, interval: $interval) { datetime value } } }\",\n  \"variables\": {\n    \"metric\": \"price_usd\",\n    \"slug\": \"bitcoin\",\n    \"from\": \"utc_now-7d\",\n    \"to\": \"utc_now\",\n    \"interval\": \"1d\"\n  }\n}\nQUERY\n```\n\n### Variable Types\n\nUse these GraphQL types in `query(...)` variable declarations:\n\n| Parameter | Type |\n|---|---|\n| `metric` | `String!` |\n| `slug` | `String` |\n| `selector` | `MetricTargetSelectorInputObject` |\n| `from` \u002F `to` | `DateTime!` |\n| `interval` | `interval` |\n| `aggregation` | `Aggregation` |\n| `transform` | `TimeseriesMetricTransformInputObject` |\n\n## Core Query: `getMetric`\n\nNearly all data flows through `getMetric`. Pass a metric name string and then select one sub-field that determines the shape of the response data.\n\n### Sub-fields\n\nChoose exactly one sub-field per `getMetric` call:\n\n| Sub-field | Returns | When to use |\n|---|---|---|\n| `timeseriesData` | `[{datetime, value}]` | Default choice — returns a time series with explicit field selection. Use for charting, trend analysis, or any case where individual data points matter. |\n| `timeseriesDataJson` | Pre-formatted JSON string | Quick dump without specifying return fields. Useful for rapid prototyping but less control over output shape. |\n| `timeseriesDataPerSlugJson` | JSON object keyed by slug | Fetch the same metric for multiple assets in a single API call. Pass `selector: { slugs: [\"bitcoin\", \"ethereum\"] }`. This counts as one API call, making it much more efficient than separate queries per asset. |\n| `aggregatedTimeseriesData` | Single numeric value | Need one summary number (average, sum, last value) over a time range. Lowest complexity, most quota-friendly. |\n| `histogramData` | Array of bucketed ranges | Distribution data — e.g., how much ETH was bought at each price range. Less commonly needed. |\n| `metadata` | Metric metadata object | Discover available slugs, aggregations, selectors, intervals, and data type for a metric. Call this before querying an unfamiliar metric. |\n| `availableSince` | ISO 8601 date string | Check how far back data exists for a given metric and slug. Prevents wasted calls on empty time ranges. A return value of `1970-01-01T00:00:00Z` means the metric has **never been computed** for this slug. |\n| `lastDatetimeComputedAt` | ISO 8601 timestamp | Check data freshness — when the metric was last computed for a slug. |\n\n### Parameters\n\nThese parameters are passed to the sub-field, not to `getMetric` itself:\n\n| Parameter | Type | Description | Example |\n|---|---|---|---|\n| `slug` | String | Asset identifier. Use for single-asset queries. | `\"bitcoin\"`, `\"ethereum\"` |\n| `selector` | Object | Advanced selection. Use instead of `slug` when you need multi-asset queries, or filtering by `owner`, `label`, `holdersCount`, or `source`. | `{ slug: \"bitcoin\", source: \"cryptocompare\" }` |\n| `from` | String | Start of time range. Accepts ISO 8601 timestamps or relative expressions. | `\"2024-01-01T00:00:00Z\"`, `\"utc_now-30d\"` |\n| `to` | String | End of time range. Same format as `from`. | `\"utc_now\"` |\n| `interval` | String | Time granularity between data points. | `\"5m\"`, `\"1h\"`, `\"1d\"`, `\"7d\"` |\n| `aggregation` | Enum | Override the default aggregation method. Options: `AVG`, `SUM`, `LAST`, `FIRST`, `MEDIAN`, `MAX`, `MIN`, `ANY`. | `AVG` |\n| `transform` | Object | Post-processing transform applied to the result. | See Transforms section. |\n\n**Important:** `slug` and `selector` are mutually exclusive. Use `slug` for simple single-asset queries. Use `selector` when querying multiple slugs at once (`{ slugs: [...] }`) or when a metric requires additional selector fields like `holdersCount` or `owner`.\n\n### Relative Time Expressions\n\nThe `from` and `to` fields accept relative expressions: `utc_now-\u003CN>\u003Cunit>` where unit is `d` (day), `w` (week), `m` (month), or `y` (year). Preferred over hardcoded dates.\n\n- `\"utc_now\"` — current time\n- `\"utc_now-7d\"` — 7 days ago\n- `\"utc_now-1m\"` — 1 month ago\n- `\"utc_now-1y\"` — 1 year ago\n\n### Transforms\n\nApply transforms directly in the query to post-process data server-side. Pass the `transform` parameter to `timeseriesData`:\n\n| Transform | Effect | Use case |\n|---|---|---|\n| `{type: \"moving_average\", movingAverageBase: N}` | Replace each value with the average of the preceding N values | Smooth noisy metrics like MVRV, social volume |\n| `{type: \"consecutive_differences\"}` | Replace each value with the difference from the prior value | Compute daily change from a cumulative metric |\n| `{type: \"percent_change\"}` | Replace each value with the percent change from the prior value | Normalize changes across metrics with different scales |\n\nTransforms reduce the number of returned data points by N-1 for moving averages. Request a slightly wider time range to compensate.\n\n## Dynamic Discovery\n\nWhen you don't know the exact metric name for a user's request, follow this 3-step workflow. Always prefer dynamic discovery over hardcoded values.\n\n### Step 1 — Fetch the metric list\n\n```graphql\n{\n  getAvailableMetrics\n}\n```\n\nReturns 1,000+ `snake_case` strings. **The response is large** — save to a file with `-o` and read it directly (e.g., `open()` in Python). Do not pipe the contents through stdin at any stage — neither from curl nor when processing the file afterward:\n\n```bash\ncurl -s -X POST https:\u002F\u002Fapi.santiment.net\u002Fgraphql \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -H \"Authorization: Apikey \u003CYOUR_API_KEY>\" \\\n  -d '{\"query\": \"{ getAvailableMetrics }\"}' \\\n  -o \u002Ftmp\u002Fsantiment-metrics.json\n```\n\nFilter by plan with `getAvailableMetrics(product: SANAPI, plan: BUSINESS_PRO)`.\n\n### Step 2 — Search by keywords\n\nSearch the saved file for keywords matching user intent. Example: whale activity → search for `holder`, `top`, `whale`, `supply`, `amount_in`. See `references\u002Fmetrics-catalog.md` for intent-to-keyword mappings.\n\n### Step 3 — Inspect metadata before querying\n\nOnce you have candidate metrics, fetch metadata to confirm compatibility:\n\n```graphql\n{\n  getMetric(metric: \"amount_in_top_holders\") {\n    metadata {\n      availableSlugs\n      availableAggregations\n      availableSelectors\n      dataType\n      defaultAggregation\n      minInterval\n    }\n  }\n}\n```\n\nThis reveals required selectors (e.g., `holdersCount`), supported slugs, and minimum interval. Requesting a smaller interval than `minInterval` returns an error. See `examples\u002Fquery-patterns.md` example 5 for a worked example.\n\n### Find a project's slug\n\nLook up a specific project by slug to verify it exists and see its details:\n\n```graphql\n{\n  projectBySlug(slug: \"bitcoin\") {\n    slug\n    name\n    ticker\n    infrastructure\n  }\n}\n```\n\nBrowse all projects paginated (useful when the user provides a token name or ticker instead of a slug):\n\n```graphql\n{\n  allProjects(page: 1, pageSize: 50) {\n    slug\n    name\n    ticker\n  }\n}\n```\n\n### Check data availability for a metric and slug\n\nBefore making a large timeseries query, verify that data exists for the desired metric-slug combination and check freshness:\n\n```graphql\n{\n  getMetric(metric: \"daily_active_addresses\") {\n    availableSince(slug: \"ethereum\")\n    lastDatetimeComputedAt(slug: \"ethereum\")\n  }\n}\n```\n\n### Check access restrictions for your plan\n\nUnderstand what historical range your API key can access for each metric. Call this to avoid wasted queries that would return restriction errors:\n\n```graphql\n{\n  getAccessRestrictions(product: SANAPI, plan: BUSINESS_PRO, filter: METRIC) {\n    name\n    isAccessible\n    isRestricted\n    restrictedFrom\n    restrictedTo\n    minInterval\n  }\n}\n```\n\n## Error Handling\n\nThe API always returns HTTP **200**, even for errors. Always parse the JSON and check for the `errors` array.\n\nA typical error response:\n\n```json\n{\n  \"data\": { \"getMetric\": null },\n  \"errors\": [\n    {\n      \"message\": \"The metric 'nonexistent_metric' is not a valid metric.\",\n      \"locations\": [{ \"line\": 2, \"column\": 3 }]\n    }\n  ]\n}\n```\n\nWhen `data` contains `null` and `errors` is present, the query failed. Common errors:\n\n| Error | Cause | Fix |\n|---|---|---|\n| Invalid metric name | Metric string doesn't exist | Verify with `getAvailableMetrics` |\n| Invalid slug | Asset slug not recognized | Verify with `allProjects` or `projectBySlug` |\n| Interval too small | Requested interval below minimum for this metric or plan | Check `metadata { minInterval }` |\n| Time range restricted | Historical range exceeds plan allowance | Check `getAccessRestrictions` |\n| Complexity too high | Query requests too many data points | Reduce time range, increase interval, or fetch fewer fields |\n| HTTP 429 | Rate limit exceeded | Back off exponentially and retry after a delay |\n| Empty timeseries (no error) | On-chain metric not computed for this asset's chain | Check `availableSince` for epoch, then `projectBySlug { infrastructure }`. See `references\u002Fmetrics-catalog.md` Ghost Data section. |\n\n**Empty data is not the same as zero data.** When `timeseriesData` returns `[]` without errors, do NOT tell the user there is no activity. On-chain metrics are only computed for indexed chains. Check `references\u002Fmetrics-catalog.md` Ghost Data section for the diagnostic flow.\n\nThe one exception to the HTTP 200 rule is rate limiting: HTTP **429** means the account's quota is exhausted. See `references\u002Frate-limits.md` for details.\n\n## Quick Reference: Building a Query\n\nFollow these steps to construct any Santiment API query:\n\n1. **Pick a metric** — use directly if known, otherwise follow Discovery Workflow.\n2. **Pick a slug** — resolve names\u002Ftickers via `projectBySlug` or `allProjects`.\n3. **Pick a time range** — relative expressions preferred. Check `availableSince` first.\n4. **Pick an interval** — `\"1d\"`, `\"1h\"`, `\"7d\"`. Larger intervals reduce complexity.\n5. **Pick a sub-field** — `timeseriesData` for series, `aggregatedTimeseriesData` for single value, `timeseriesDataPerSlugJson` for multi-asset.\n6. **Optionally add** — `transform`, `selector` (instead of `slug`), or `aggregation` override.\n7. **If data is empty** — check `availableSince` for epoch. If epoch, the metric isn't computed for this slug's chain. Report unavailability and suggest alternative metrics.\n\nExecute via curl with the user's API key and parse the JSON response. Always check for the `errors` array before processing `data`.\n\n## Additional Resources\n\nConsult these reference files for detailed information:\n\n- **Metrics catalog** — `references\u002Fmetrics-catalog.md` — keyword-to-metric mapping for translating user intent into search terms, plus 20 curated quick-reference metrics and naming conventions\n- **Rate limits** — `references\u002Frate-limits.md` — tier limits, complexity scoring, and optimization strategies to avoid quota exhaustion\n- **Query patterns** — `examples\u002Fquery-patterns.md` — 6 worked examples with both GraphQL and curl, including discovery workflow and ghost data diagnostics\n",{"name":5,"tags":58,"author":69,"scripts":70,"version":84,"metadata":85,"triggers":91,"composable":71,"parameters":120,"description":7,"persist_state":54,"prerequisites":138},[36,59,60,61,62,63,64,65,66,67,68],"crypto","graphql","on-chain","metrics","blockchain","defi","exchange-flows","social-sentiment","mvrv","whale-tracking","Santiment \u003Csupport@santiment.net>",{"enabled":71,"definitions":72,"working_directory":83},true,[73,79],{"file":74,"name":75,"type":76,"timeout":77,"description":78},"santiment_query.py","santiment_query","python",30,"Execute a Santiment GraphQL query for any metric, asset, and time range",{"file":80,"name":81,"type":76,"timeout":77,"description":82},"santiment_discovery.py","santiment_discovery","Discover available metrics and asset slugs from the Santiment API",".\u002Fscripts","1.1.5",{"openclaw":86},{"emoji":87,"requires":88,"primaryEnv":90},"?",{"env":89},[90],"SANTIMENT_API_KEY",[92,108,116],{"type":93,"keywords":94,"priority":107},"keyword",[36,95,96,97,67,98,99,100,101,102,103,104,105,106],"crypto metrics","on-chain data","exchange flows","nvt","social volume","whale tracking","active addresses","crypto analytics","token age","exchange inflow","exchange outflow","dev activity",90,{"type":109,"patterns":110,"priority":115},"pattern",[111,112,113,114],"(?i)(query|fetch|get)\\s+(santiment|crypto|on-chain)","(?i)santiment\\s+api","(?i)(mvrv|nvt|exchange.*(inflow|outflow|balance))","(?i)(daily.active.addresses|social.volume|dev.activity)",85,{"type":117,"priority":118,"intent_category":119},"intent",95,"crypto_data_analysis",[121,125,128,131,134],{"name":122,"type":123,"required":54,"description":124},"metric","string","Santiment metric name (e.g., price_usd, daily_active_addresses, mvrv_usd)",{"name":126,"type":123,"required":54,"description":127},"slug","Asset identifier (e.g., bitcoin, ethereum, cardano)",{"name":129,"type":123,"required":54,"description":130},"from","Start of time range (ISO 8601 or relative expression like utc_now-7d)",{"name":132,"type":123,"required":54,"description":133},"to","End of time range (ISO 8601 or relative expression like utc_now)",{"name":135,"type":123,"default":136,"required":54,"description":137},"interval","1d","Data granularity (5m, 1h, 1d, 7d)",{"skills":139,"env_vars":140},[],[90],"main","3df1d0d67b30ff15236561f8c0f9f06d33f42dfd","skills\u002Fai-crypto\u002Fxspoonai-official-santiment-api",17,"https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia","https:\u002F\u002Feth2030.com","Hardcore infra. Building @alt-research and applied cryptography.","2026-11-14 02:27:51",{"source":8,"skillName":5,"commands":151,"prompt":161,"zipAvailable":71},[152,155,158],{"tool":153,"command":154},"npx","npx skills add jiayaoqijia\u002Fcryptoskill --skill santiment-api",{"tool":156,"command":157},"bunx","bunx skills add jiayaoqijia\u002Fcryptoskill --skill santiment-api",{"tool":159,"command":160},"pnpm","pnpm dlx skills add jiayaoqijia\u002Fcryptoskill --skill santiment-api","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fai-crypto\u002Fxspoonai-official-santiment-api\u002FSKILL.md",[163,169,173,177,181,187,191,197,201,205],{"path":164,"resourceType":165,"resourceTypeDesc":166,"sizeBytes":167,"sourceHtmlUrl":168},"examples\u002Fquery-patterns.md","REFERENCE","参考文档",9544,"https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fai-crypto\u002Fxspoonai-official-santiment-api\u002Fexamples\u002Fquery-patterns.md",{"path":170,"resourceType":165,"resourceTypeDesc":166,"sizeBytes":171,"sourceHtmlUrl":172},"README.md",6514,"https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fai-crypto\u002Fxspoonai-official-santiment-api\u002FREADME.md",{"path":174,"resourceType":165,"resourceTypeDesc":166,"sizeBytes":175,"sourceHtmlUrl":176},"references\u002Fmetrics-catalog.md",7578,"https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fai-crypto\u002Fxspoonai-official-santiment-api\u002Freferences\u002Fmetrics-catalog.md",{"path":178,"resourceType":165,"resourceTypeDesc":166,"sizeBytes":179,"sourceHtmlUrl":180},"references\u002Frate-limits.md",1679,"https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fai-crypto\u002Fxspoonai-official-santiment-api\u002Freferences\u002Frate-limits.md",{"path":182,"resourceType":183,"resourceTypeDesc":184,"sizeBytes":185,"sourceHtmlUrl":186},"screenshots\u002F01-query-daa.png","ASSET","资产文件",206681,"https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fai-crypto\u002Fxspoonai-official-santiment-api\u002Fscreenshots\u002F01-query-daa.png",{"path":188,"resourceType":183,"resourceTypeDesc":184,"sizeBytes":189,"sourceHtmlUrl":190},"screenshots\u002F02-discovery-exchange.png",420683,"https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fai-crypto\u002Fxspoonai-official-santiment-api\u002Fscreenshots\u002F02-discovery-exchange.png",{"path":192,"resourceType":193,"resourceTypeDesc":194,"sizeBytes":195,"sourceHtmlUrl":196},"scripts\u002Fsantiment_discovery.py","SCRIPT","脚本",6343,"https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fai-crypto\u002Fxspoonai-official-santiment-api\u002Fscripts\u002Fsantiment_discovery.py",{"path":198,"resourceType":193,"resourceTypeDesc":194,"sizeBytes":199,"sourceHtmlUrl":200},"scripts\u002Fsantiment_query.py",6853,"https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fai-crypto\u002Fxspoonai-official-santiment-api\u002Fscripts\u002Fsantiment_query.py",{"path":202,"resourceType":165,"resourceTypeDesc":166,"sizeBytes":203,"sourceHtmlUrl":204},"SOURCE.md",372,"https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fai-crypto\u002Fxspoonai-official-santiment-api\u002FSOURCE.md",{"path":206,"resourceType":165,"resourceTypeDesc":166,"sizeBytes":207,"sourceHtmlUrl":208},"TRUST.auto.yaml",2186,"https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fai-crypto\u002Fxspoonai-official-santiment-api\u002FTRUST.auto.yaml",[210,238,260,278,291,301],{"skillNo":211,"name":212,"nameZh":6,"description":213,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":214,"licenseFileUrl":215,"sourceHtmlUrl":216,"categories":217,"keywords":218,"publishedAt":53},"01M712C436EQYE43342Q4E7GG1","recipe-performance","Diagnose a specific MetaMask user flow's real-app performance and Sentry critical-user-flow telemetry with deterministic mm-harness recipes. Use for CUF boundaries, cold\u002Fwarm\u002Fbackground-resume behavior, latency regressions, lifecycle tags, duplicate or blocking network requests, long tasks, layout\u002Fpaint cost, screen redraws, React rerenders, or browser trace analysis where tests alone cannot prove the real app.","MIT","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fwallets\u002Fmetamask-official-recipe-performance\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fwallets\u002Fmetamask-official-recipe-performance\u002FSKILL.md",[],[219,220,221,222,223,224,225,226,227,228,229,230,35,231,232,233,234,235,236,237],"performance","recipe performance","recipe","mm","sentry","harness","app","deterministic","recipes","flow","cold","critical","tasks","react","browser","layout","screen","network","metamask",{"skillNo":239,"name":240,"nameZh":6,"description":241,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":242,"licenseFileUrl":243,"sourceHtmlUrl":244,"categories":245,"keywords":246,"publishedAt":53},"01M70XT2F8A5CQZ81JBP98KSW3","mexc-spot-websocket","MEXC Spot WebSocket workflows for public streams, protobuf handling, depth maintenance, listen keys, and private streams without exposing API keys.","Apache-2.0","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fexchanges\u002Fmncrftfrcnm-mexc-spot-websocket\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fexchanges\u002Fmncrftfrcnm-mexc-spot-websocket\u002FSKILL.md",[],[247,248,249,32,250,251,252,253,254,255,256,257,258,259],"mexc spot websocket","spot","websocket","workflows","public","listen","streams","depth","keys","for","api keys","maintenance","protobuf",{"skillNo":261,"name":262,"nameZh":6,"description":263,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":242,"licenseFileUrl":264,"sourceHtmlUrl":265,"categories":266,"keywords":267,"publishedAt":53},"01M70XT0MBXN3WZY1BKN0CPNKR","mexc-spot-rest","MEXC Spot REST workflows for public data, signed account requests, orders, wallet\u002Fadmin actions, and secure signing without exposing API keys.","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fexchanges\u002Fmncrftfrcnm-mexc-spot-rest\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fexchanges\u002Fmncrftfrcnm-mexc-spot-rest\u002FSKILL.md",[],[268,248,269,270,271,272,273,257,256,255,274,275,276,251,277,250,32],"mexc spot rest","REST","admin","signing","Wallet","requests","actions","secure","data","orders",{"skillNo":279,"name":280,"nameZh":6,"description":281,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":242,"licenseFileUrl":282,"sourceHtmlUrl":283,"categories":284,"keywords":285,"publishedAt":53},"01M70XSYSVZ2N0N91XCAR2CAK0","mexc-futures-websocket","MEXC Futures WebSocket workflows for public streams, private account\u002Forder\u002Fposition streams, ping\u002Fpong, subscriptions, and depth maintenance.","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fexchanges\u002Fmncrftfrcnm-mexc-futures-websocket\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fexchanges\u002Fmncrftfrcnm-mexc-futures-websocket\u002FSKILL.md",[],[286,287,249,288,289,258,256,290,254,253,251,250],"mexc futures websocket","futures","position","ping","subscriptions",{"skillNo":292,"name":293,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":214,"licenseFileUrl":294,"sourceHtmlUrl":295,"categories":296,"keywords":297,"publishedAt":53},"01M6H0ZWHVE5W04WG2DKQE2SQC","0xklen-version-and-refresh-sanctions-lists","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fpayments\u002F0xklen-version-and-refresh-sanctions-lists\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fpayments\u002F0xklen-version-and-refresh-sanctions-lists\u002FSKILL.md",[],[298,299,300],"refresh","0xklen version and refresh sanctions lists","version",{"skillNo":302,"name":303,"nameZh":6,"description":304,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":214,"licenseFileUrl":305,"sourceHtmlUrl":306,"categories":307,"keywords":308,"publishedAt":53},"01M6H0Z28Q3R8J0S799GJQWXM3","verify-tests-cover-changed-lines","Use when a PR adds code that the existing suite may not exercise. Measures patch coverage — the share of newly changed lines hit by tests — before approving.","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fpayments\u002F0xklen-verify-tests-cover-changed-lines\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fpayments\u002F0xklen-verify-tests-cover-changed-lines\u002FSKILL.md",[],[309,310,311,312,313,314,315,316,317,318,319],"tests","cover","verify tests cover changed lines","verify","coverage","pr","exercise","use","patch","code","share"]