X-RAY Documentation

X-RAY developer docs: REST API reference, MCP integration for Claude, and guides for querying live Web3 labor-market data.

All pages

  1. Platform
  2. Watchlist Dashboards
  3. API Reference
  4. Quick Start
  5. Authentication
  6. Rate Limits & Pagination
  7. Errors & Status Codes
  8. Vacancies
  9. Introduction
  10. Watchlist vs Global Dashboard
  11. Global Dashboard
  12. TL;DR
  13. Data Pipeline
  14. Companies
  15. Creating a Dashboard
  16. Filter Model
  17. Adding & Removing Companies
  18. Skills, Languages & Benefits
  19. Core Definitions
  20. Market Stats
  21. Tabs and Charts — Formulas
  22. Code Examples
  23. Compare Mode
  24. Determinism, Caching, Stability
  25. Embedded Charts
  26. FAQ
  27. What is Intentionally Not Here
  28. Reproducing a Number
  29. Tab: Overview
  30. Glossary
  31. Time Range Controls & Meta Line
  32. Tab: Activity
  33. Tab: Compensation
  34. Tab: Skills
  35. Tab: Roles
  36. Tab: Compare
  37. Benchmark Control
  38. Role Filters
  39. Hiring Intelligence Metrics

Platform

Platform

How the X-Ray product works from a user's point of view — dashboards, filters, watchlists, and the live data feed. Pick a section in the sidebar to get started.

Watchlist Dashboards

Watchlist Dashboards

A Watchlist Dashboard is your own private dashboard scoped to a list of companies you care about — your direct competitors, your portfolio, a prospect list, or anything else.

Every chart, KPI, and table that exists on the Global Dashboard re-runs against just that list, so you cut out the rest of the market and look only at what matters to you.

You can create as many watchlists as you like. Each one keeps its own benchmark settings and its own role filters, so a "L1 incumbents" dashboard and a "Q4 prospects" dashboard never get in each other's way.

API Reference

API Reference

The X-Ray REST API gives paid plans programmatic access to the same dataset that powers the dashboard — vacancies, companies, skills, and top-line stats.

The API is strictly read-only. There is no endpoint to create, update, or delete anything, and there never will be.

---

Base URL


https://x-ray.me/api

Every call is a GET request that picks a resource via the type query parameter:


?type=vacancies | companies | skills | stats

Authentication

Every request must carry a Bearer API key issued from Settings → API Keys in your dashboard.


Authorization: Bearer YOUR_API_KEY

Keys are shared across your workspace and require an active paid subscription or a standalone API plan. They're revoked automatically when a workspace downgrades.

Read-only

Only GET is accepted. Any other HTTP verb returns 405 Method Not Allowed.

Response envelope

Successful responses:


{ "success": true, "data": [ /* rows */ ], "total": 1234, "limit": 100, "offset": 0 }

Errors:


{ "success": false, "error": "Human-readable message" }

| Status | Meaning | |---|---| | 200 | OK | | 400 | Invalid type parameter | | 401 | Missing or invalid API key | | 403 | No active paid / API subscription | | 405 | Non-GET method | | 500 | Internal error (a generic message; details are logged on our side) |

Pagination

List endpoints accept limit (default 100, max 1000) and offset (default 0). The total field in the response is the unfiltered row count for your filter set.

Rate limits

There's no hard per-request rate limit. The fair-use ceiling is about 60 requests per minute per key. Sustained abuse will result in a key being revoked. See Rate Limits for tier-specific numbers.

Quick Start

Quick Start

From zero to your first API call in under five minutes.

1. Get an API key

  1. Open Settings → API Keys in your dashboard.
  2. Click Create API key, label it (e.g. local-dev), and copy the secret. The full key is shown once — store it somewhere safe.
  3. Keys are workspace-scoped: every member of your workspace shares the same key pool.

2. Set environment variables


export API_KEY="xrk_live_…"
export BASE="https://x-ray.me/api"

3. Verify the key


curl -G "$BASE?type=stats" \
  -H "Authorization: Bearer $API_KEY"

A 200 with success: true confirms your key is active.

4. Pull a page of vacancies


curl -G "$BASE" \
  -H "Authorization: Bearer $API_KEY" \
  --data-urlencode "type=vacancies" \
  --data-urlencode "status=active" \
  --data-urlencode "limit=100"

Walk pages by increasing offset until you reach total.

5. Mirror the dataset (optional)

A complete mirror of every active role plus its company is around 5 MB and refreshes hourly:


let offset = 0;
const all = [];
for (;;) {
  const r = await fetch(`${BASE}?type=vacancies&limit=1000&offset=${offset}`, {
    headers: { Authorization: `Bearer ${API_KEY}` }
  }).then(r => r.json());
  all.push(...r.data);
  if (r.data.length < 1000) break;
  offset += 1000;
}

What you cannot do

The API is read-only. There is no endpoint to create, update, or delete anything. Any non-GET request returns 405.

Authentication

Authentication

Every API request needs a Bearer token in the Authorization header:


Authorization: Bearer YOUR_API_KEY

Key types

| Key type | Where it comes from | Scope | |---|---|---| | User API key | Generated by a member of your workspace under Settings → API Keys | Shared across the workspace; read-only; auto-deactivated if the workspace's plan stops covering API access | | Admin key | Provisioned by X-Ray for partner integrations | Same read-only surface; no subscription check |

Plan gating

A user-issued key only works if the workspace has either:

  • An active API plan, or
  • A paid subscription that hasn't expired.

If neither holds, the API returns 403 with one of:

  • "No active subscription"
  • "API access requires an active paid subscription or API plan"
  • "Subscription expired"

Rotating a key

Create a new key, deploy it everywhere, then delete the old key from the dashboard. There's no grace period — deleting a key takes effect immediately.

Hygiene

  • Never embed an API key in browser JavaScript or any mobile app you ship to users.
  • Never commit a key to source control.
  • Every request updates the key's "last used" timestamp. Keys idle for 90+ days are flagged for review.

Rate Limits & Pagination

Rate Limits & Pagination

Rate limits

There's no hard per-request rate limit today. The fair-use ceilings are:

| Tier | Suggested ceiling | |---|---| | Paid workspace | 60 requests/min · 5,000 requests/day | | API plan add-on | 120 requests/min · 20,000 requests/day | | Admin key (partners) | Uncapped |

Sustained traffic above these ceilings can result in a key being revoked. If you need more throughput, talk to us through the Connect page — we have bulk export options for legitimate use cases.

Pagination

All list endpoints (type=vacancies, type=companies, type=skills) accept:

| Parameter | Default | Max | |---|---|---| | limit | 100 | 1000 | | offset | 0 | — |

Pages are stable while you're walking them as long as the filters don't change. To mirror the full dataset, page with limit=1000 and increment offset until data.length < limit.

Errors & Status Codes

Errors & Status Codes

| Status | Body | Why | |---|---|---| | 200 | { success: true, data, total, limit, offset } | Success | | 400 | { success: false, error: "Invalid type…" } | type is missing or not one of vacancies / companies / skills / stats | | 401 | { success: false, error: "Missing API key" } | No Authorization header | | 401 | { success: false, error: "Invalid or inactive API key" } | Key not recognised or revoked | | 403 | { success: false, error: "No active subscription" } | Workspace has no paid plan and no API plan | | 403 | { success: false, error: "API access requires an active paid subscription or API plan" } | Workspace tier doesn't cover the API | | 403 | { success: false, error: "Subscription expired" } | Paid subscription has lapsed | | 405 | { success: false, error: "Method not allowed" } | Any non-GET verb | | 500 | { success: false, error: "Internal server error" } | Unhandled error on our side (details are logged) |

All responses are Content-Type: application/json with permissive CORS — the API key, not the origin, is the trust boundary.

Vacancies

Endpoint: Vacancies


GET /api?type=vacancies

Returns vacancies joined to their company (id, name, logo), newest first.

Query parameters

| Parameter | Type | Description | |---|---|---| | limit | int (≤1000) | Page size, default 100 | | offset | int | Pagination offset, default 0 | | status | string | active or closed | | category | string | Role category (e.g. Engineering, Design) | | region | string | Continental region | | country | string | Country name | | company_id | string | Restrict to a single company | | role_grade | string | Junior / Mid / Senior / Lead / Principal | | date_from | ISO date | Earliest posting date (inclusive) | | date_to | ISO date | Latest posting date (inclusive) |

Example


curl -G "$BASE" \
  -H "Authorization: Bearer $API_KEY" \
  --data-urlencode "type=vacancies" \
  --data-urlencode "status=active" \
  --data-urlencode "role_grade=Senior" \
  --data-urlencode "limit=50"

Response


{
  "success": true,
  "data": [
    {
      "id": "…",
      "title": "Senior Solidity Engineer",
      "category": "Engineering",
      "role_grade": "Senior",
      "country": "Germany",
      "region": "Europe",
      "location": "Berlin",
      "salary_min": 120000,
      "salary_max": 180000,
      "employee_count": 85,
      "status": "active",
      "date_added": "2026-05-12T10:14:00Z",
      "date_removed": null,
      "company": { "id": "…", "name": "Aave", "logo": "https://…/aave.png" }
    }
  ],
  "total": 18420,
  "limit": 50,
  "offset": 0
}

The role description is intentionally not returned in list responses to keep payloads small. Fetch the full description through the dashboard UI where it's sanitised.

Introduction

Welcome to X-Ray

X-Ray is a market intelligence terminal for Web3 hiring. It tells you who is hiring, what they pay, which skills are in demand, and where companies are growing or going quiet — based on real job postings from across the industry.

These docs walk you through what the product can do and how to use it.

---

What you can do here

  • Data Stream — a live feed of the latest open roles across Web3. Filter, search, and dig into any single posting. Lives at /data-stream.
  • Global Dashboard — the whole market in one view: hiring trends, sectors, compensation, skills, geography. Lives at Dashboard → Global Data.
  • Watchlist Dashboards — your own private dashboards focused on a custom list of companies (competitors, portfolio, prospects). Lives at Dashboard → Watchlist.
  • Insights — editorial deep dives and market reports written by us. Lives at /insights.
  • API — pull the same data into your own tools. Available on paid plans.

---

How to read these docs

  • The sidebar on the left is a tree — open a section to see its pages.
  • Code samples have a one-click Copy button.
  • Callouts (like the one below) flag things worth slowing down for.

> [!TIP] > Brand new? Skim Global Dashboard → TL;DR first to understand what you're looking at, then dive into whichever section matches your use case.

---

Need help?

Use the Get in Touch form in your dashboard. A real person reads every message and we usually reply within a business day.

Watchlist vs Global Dashboard

Watchlist vs Global Dashboard

The Global Dashboard shows the entire Web3 hiring market. A Watchlist Dashboard shows only the companies you picked.

| | Global Dashboard | Watchlist Dashboard | |---|---|---| | Companies shown | Everyone we track | The ones you added | | Filters available | Sector, Sub-sector, Location, Blockchain, plus role-side filters | Role-side only: Role Category, Role Grade, Job Location | | Tabs | Overview, Hiring Trends, Sectors, Compensation, Skills & Tech, Geography, Companies, Vacancies | Overview, Activity, Compensation, Skills, Roles, Compare | | Benchmark control | n/a | Per-company peer pool, by sector | | Saved? | Stateless — every visit is fresh | Saved to your account, visible to your workspace |

Everything else — time-range chips (7d / 30d / 90d / All / Custom / Compare), the meta line in the header, embed buttons — works the same way in both places.

Global Dashboard

Global Dashboard

The Global Dashboard is the whole Web3 hiring market in one place — every company we track, every role they've posted, every salary, every skill.

This section walks through what each tab shows you, how the filters work, what the KPIs really mean, and how to read Compare mode.

---

Reading order

If you're new, walk these in order. If you're coming back for a specific number, jump straight to the page you need.

| Page | What it covers | |---|---| | TL;DR | The 60-second version. | | Data Pipeline | Where the data comes from and how fresh it is. | | Time Range Controls & Meta Line | The chips and the dataset info shown in the header. | | Filter Model | The two filter groups and how they combine. | | Core Definitions | Active vs closed vs added — what each one means. | | Tabs and Charts | What each chart on each tab is showing. | | Compare Mode | How to read primary vs compare. | | Determinism, Caching, Stability | Why numbers stay stable across refreshes. | | Embedded Charts | Embedding a chart on your own site. | | What is Intentionally Not Here | Things we will not add, and why. | | Reproducing a Number | How to double-check any KPI on the screen. | | Glossary | Plain-language definitions of every term. |

TL;DR

TL;DR

The Global Dashboard takes every job posting across the companies we track and turns it into trends, KPIs, and breakdowns — by sector, by skill, by location, by company.

What you can answer with it

  • Who is hiring right now, and how aggressively?
  • Which sectors and chains are heating up or cooling down?
  • What salaries do roles at a given seniority command?
  • Which skills are in demand and which are fading?
  • Where, geographically, is the hiring happening?

What we explicitly don't do

No AI-written summaries. No "market sentiment" narratives. No predictions about the future. The dashboard shows you what happened — interpretation is up to you.

> [!IMPORTANT] > Two people looking at the same dashboard with the same filters should always see identical numbers. If you ever see something that looks off, refresh the page first (it bypasses the cache), then tell us through the Get in Touch form.

X-RAY · Data Stream · Insights · Docs · Pricing