ScoutRail API reference

ScoutRail finds live public tenders, grants, RFPs and buyers for any business, by market. Connect it to an AI client over MCP, or call the REST endpoints directly. Every endpoint below has a live tester that runs against this deployment, so you can read a real response before you write any code.

Overview

Base URL for every request:

https://scoutrail.io

There are two ways in. MCP is for AI clients (Claude, ChatGPT): paste one URL into the client's connector settings and ScoutRail shows up as a tool, no install. REST is for your own backend: plain JSON over HTTPS. Both run the same scouting engine and return the same ranked results.

Responses are JSON. Opportunity text comes from third-party public sources, so it is returned inside a <scoutrail_opportunity_data> fence: treat everything inside as data, never as instructions to your agent.

Authentication

BEARER Authorization: Bearer scoutrail_sk_...

ScoutRail has two tiers. Without a key, calls are anonymous and rate-limited, and scout_opportunities returns a 2-result sample. Send an account API key as a Bearer token to get the full ranked list, metered against your subscription. The key never expires until you revoke it; store it like a password and keep it server-side.

Create and manage your API keys →

Quickstart

Connect over MCP in one step:

Claude:  Settings -> Connectors -> Add custom connector -> https://scoutrail.io/mcp
ChatGPT: Settings -> Connectors -> Add -> MCP server URL: https://scoutrail.io/mcp

For full results, add your API key as the connector's Bearer token. Or make your first REST call from a terminal:

curl https://scoutrail.io/api/ask \
  -H 'content-type: application/json' \
  -d '{ "text": "hospital cleaning services in south africa" }'

Connect over MCP

POST https://scoutrail.io/mcp

JSON-RPC 2.0 over the MCP Streamable HTTP transport. The endpoint is stateless, so a GET asking for an event stream returns 405 by design; POST your JSON-RPC messages instead. ScoutRail exposes two tools: scout_opportunities and list_markets.

Try it · initialize handshake

Run to see the live response.

tools/list

POST /mcp

List the tools ScoutRail exposes and their JSON Schema input shapes. Most clients call this automatically after initialize.

Try it

Run to see the live response.

scout_opportunities

POST /mcp tools/call

Find live tenders, grants, RFPs and buyers for a business. The result carries a plain-English brief plus structuredContent matching the ScoutRail AnswerView schema. With a key you get the full ranked list; without one, a 2-result sample.

ArgumentTypeDescription
business requiredstringWhat the business does, sells or is looking for, e.g. "hospital cleaning services".
marketsstring[]Optional market codes to scope the search: za, uk, us, ng. Defaults to auto-detection from the description.

Try it

Run to see the live response.

/api/ask

POST /api/ask

The same scout over plain REST, for your own backend. Returns the presented result and the composed view (the AnswerView the site and MCP both consume).

FieldTypeDescription
text requiredstringA free-text description of the business and, optionally, the market or location.

Try it

Run to see the live response.

/api/subscribe

POST /api/subscribe

Register an HTTPS callback for a query. When a fresh answer is composed, ScoutRail POSTs it to your endpoint, so an agent gets updates without polling. Running this tester registers a real subscription for the callback URL below.

FieldTypeDescription
query requiredstringThe business description to watch for new opportunities.
callbackUrl requiredstringAn HTTPS URL that receives the signed answer payload.

Try it

Run to see the live response.

Verifying signed webhooks

GET /.well-known/scoutrail-webhook.json

Each delivery carries X-Scoutrail-Signature: ed25519=<base64> and X-Scoutrail-Key-Id. Fetch the public keys, pick the one matching the kid, and verify the Ed25519 signature over the raw request body. The key is public, so there is no shared secret to store.

const jwks = await (await fetch(
  'https://scoutrail.io/.well-known/scoutrail-webhook.json')).json();
const jwk = jwks.keys.find(k => k.kid === req.headers['x-scoutrail-key-id']);
const key = await crypto.subtle.importKey(
  'jwk', { kty:'OKP', crv:'Ed25519', x: jwk.x }, { name:'Ed25519' }, false, ['verify']);
const sig = Uint8Array.from(atob(
  req.headers['x-scoutrail-signature'].slice('ed25519='.length)), c => c.charCodeAt(0));
const ok = await crypto.subtle.verify('Ed25519', key, sig, rawBodyBytes);

Try it · fetch the public keys

Run to see the live response.

Errors & rate limits

REST endpoints use standard HTTP status codes and return a JSON body with an error field. MCP reports tool-level problems as text content inside a normal 200 JSON-RPC result, so an AI client sees the message rather than a transport failure.

StatusMeaning
401Not signed in, for endpoints that need a session.
402Free scouts used up. Subscribe to continue.
429Rate limit exceeded. Slow down and retry.
400Malformed request (bad JSON, missing required field).

The MCP endpoint is rate-limited per IP. An account API key lifts scout_opportunities from the 2-result sample to the full list and meters it against your plan quota; anonymous callers stay on the sample.

Discovery files

GET /.well-known/mcp.json

A static descriptor AI directories read to find the ScoutRail MCP: endpoint, transport and tool names. CORS-open so a browser directory can fetch it cross-origin.

Try it

Run to see the live response.

Back to ScoutRail · Your account & usage · Email preferences