API and MCP

Call Hashike's research directly from your own systems and AI tools. Every account gets a small monthly allowance to try it; the Research and Intelligence plans raise the limits.

What this is

A research interface, not a database dump interface. There is no endpoint that returns everything and no bulk export. Every response carries its population, sources, filters and limitations, so a figure can be checked wherever it ends up.

Authentication

Create a key in account settings and send it as a bearer token. The secret is shown once and cannot be retrieved afterwards. A key is a credential, not an entitlement: every call re-checks the subscription behind it, so a key outliving its plan stops working.

curl https://hashike.io/api/v1/opportunities?status=open&limit=5 \
  -H "Authorization: Bearer hsk_live_..."

Endpoints

PathToolMetered asMax rows
/api/v1/opportunitiessearch_opportunitiesFind US federal contract opportunities performed in Japan, by category, buying agency, prefecture, status (open, closed, or notice — see the status field) and optional free-text query (title or solicitation number). Returns a bounded page plus the total number matching.records50
/api/v1/opportunities/{id}get_opportunityRetrieve one opportunity notice by id, with its official English title, Japanese translation where available, dates, place of performance and source link.records1
/api/v1/companies/{corporateNumber}supplier_profileAward history for one Japanese supplier by corporate number (法人番号): exact award count and value over a rolling 60-month window, the ministries and agencies that bought from them, contract methods, recent awards, and gBizINFO company facts where cached.records21
/api/v1/buyers/{ministryCode}buyer_profileWhat one Japanese central-government ministry buys: award count, total value in JPY, distinct suppliers, contract-method mix and recent awards over a rolling 60-month window. Covers Japanese central-government ministries only (award count, JPY value, suppliers, contract methods from Procurement Portal (調達ポータル) award results). For a US federal buyer, use us_buyer_profile instead — it covers navy, army, air-force, dla and state, including a per-contracting-office slice, which is the profile for US federal contracting offices this tool does not provide.records21
/api/v1/awardsfind_comparable_awardsSearch Japanese central-government award results by ministry, Japanese fiscal year and procurement name. At least one filter is required; there is no unfiltered listing.records25
/api/v1/markets/{market}explain_marketSummarize a market: pass "japan-government" for Japanese central-government procurement (awards, value, suppliers, buying ministries), or a category id for US federal opportunities performed in Japan. Returns aggregates only.analysis—
/api/v1/locations/japan/{prefecture}location_profileProcurement activity at one Japanese prefecture: tracked and open opportunities, the categories bought there and the buying organizations. Aggregates only.analysis—
/api/v1/researchresearch_briefThe full comparable-market analysis for a NAICS or PSC scope: populations, award-value distribution, competition, supplier and buyer concentration, demand, trend, geography and data quality. Individual comparable awards are withheld unless includeSampleAwards is set.analysis25
/api/v1/buyers/us/{agency}us_buyer_profileA first-class profile of one US federal buyer's Japan-performed contracting: award count and value in USD, activity-date window, sub-agency and contracting-office breakdown, and supplier concentration — all from the same precomputed market brief the signed-in buyer pages read. Covers the Navy, Army, Air Force, DLA and the State Department (agency: navy, army, air-force, dla or state), the buyers with verified Japan-performed award volume. Pass office to narrow to one contracting office's slice. Aggregates only, no individual award records.analysis—

How usage is counted

Requests are not the unit — records returned are. A source row exposed verbatim counts as one record. An analytical response that exposes no individual rows counts as one analysis instead, which makes the question-shaped calls the cheap ones. A derived response that does expose rows (research_brief with includeSampleAwards) is charged one analysis plus one record per row exposed.

"usage": { "records": 0, "analyses": 1 }   // an aggregate
"usage": { "records": 21, "analyses": 0 }  // a profile with 20 awards
"usage": { "records": 5, "analyses": 1 }   // a research brief with 5 sample awards

GET /api/v1/usage — current allowance. Never metered.

Limits

  • Free: Monthly allowance: 200 records · 4 analyses per month. General rate limit: 5 requests per minute. Analytical rate limit: 1 analytical request per minute.
  • Research: Monthly allowance: 1,000 records · 20 analyses per month. General rate limit: 20 requests per minute. Analytical rate limit: 4 analytical requests per minute.
  • Intelligence: Monthly allowance: 4,000 records · 80 analyses per month. General rate limit: 60 requests per minute. Analytical rate limit: 12 analytical requests per minute.

Allowances are the total of the subscription rows in your organization, identified by email domain, that currently grant API access, and reset on the 1st (UTC). Additional API keys do not increase them. Accounts with no row that currently grants API access receive the Free allowance.

See pricing →

Unavailable is not empty

When no brief has been computed for a scope, the response is status: unavailable with a reason, never an empty object. An empty result reads as “there is no market here”, which is a different and usually false claim. The same applies to a location outside coverage or an unrecognised buyer code.

{
  "status": "unavailable",
  "reason": "no_precomputed_brief",
  "message": "No research brief has been computed for this scope...",
  "scope": { "naics": "336611" },
  "usage": { "records": 0, "analyses": 0 }
}

Response shape

Every tool publishes a JSON Schema for its own output (outputSchema). MCP's tools/list returns it alongside inputSchema, and tools/call returns the same payload two ways: the usual text block, and structuredContent, so a client does not have to parse JSON out of text. What result contains differs by tool; status, scope, provenance and usage have the same shape on every tool.

Toolresult fields
search_opportunitiesmatches, totalMatching
get_opportunityid, title, titleJa, agency, noticeType, solicitationNumber, naics, psc, postedDate, responseDeadline, placeOfPerformance, prefecture, categories, status, deadlineStated, sourceUrl, hashikeUrl, summaryJa, deadlineConflict
supplier_profilecorporateNumber, name, awardCount, totalAwardedJpy, currency, firstAward, lastAward, ministries, contractMethods, ministryCount, recentAwards, registry, hashikeUrl
buyer_profileministryCode, nameJa, nameEn, awardCount, totalJpy, currency, distinctSuppliers, firstAward, lastAward, contractMethods, recentAwards, hashikeUrl
find_comparable_awardsawards, totalMatching, currency
explain_marketmarket, awardCount, totalJpy, currency, distinctSuppliers, ministryCount, contractMethods, topBuyersByValue, hashikeUrl — or — market, name, trackedOpportunities, openOpportunities, buyers, prefectures, hashikeUrl
location_profilecountry, prefecture, prefectureJa, trackedOpportunities, openOpportunities, categories, buyers, hashikeUrl
research_briefscopeKind, code, populations, primaryPopulationId, awardValue, competition, supplierConcentrationByValue, buyerConcentration, demand, annualTrend, recurrence, geography, depth, evidence, quality, questions, sampleAwards, sampleAwardsWithheld, computedAt
us_buyer_profileagency, agencyNameEn, agencyNameJa, currency, analyzed, examined, awardValue, subAgencies, offices, supplierConcentration, office, knownOfficeCount, computedAt

Errors

400invalid_params — the call did not match the tool's inputSchema
401missing_credentials / invalid_key
402plan_required — the plan does not include API access
404unknown_endpoint / unknown_tool
405method_not_allowed — the API is read-only
429rate_limited / quota_exhausted
503quota_unavailable — metering is down; retry

MCP

The same tools are served over the Model Context Protocol. Point your AI client at the endpoint below and Hashike's research sits alongside your own documents — you keep working in the tool you already use instead of in someone else's chat window. Limits and metering are shared with the API.

https://hashike.io/api/mcp

Transport : JSON-RPC 2.0 over POST
Auth      : Authorization: Bearer hsk_live_...
Methods   : initialize · tools/list · tools/call · ping

This endpoint supports OAuth, which is what the MCP specification prefers for a remote server. A client registers itself, sends you to a consent screen in your browser, and receives an access token scoped to your own account — there is no API key to paste, and access is tied to you rather than to a shared secret. API keys still work as bearer tokens, for clients that do not speak OAuth.

Tool results arrive as JSON with their provenance attached, and each carries your remaining allowance so an agent can pace itself. A result with status: "unavailable" is not an error — it means that scope has not been computed or is outside coverage.

Connect from Claude.ai, Claude Desktop, Cowork or Claude Code →

Webhooks

Still in development. The endpoint-registration section will not appear in account settings until this is enabled. What follows is the specification for once it is.

Event types: opportunity.created / opportunity.updated / award.created

{
  "id": "opportunity:ABC123:9f2c...",   // dedupe identity — key your idempotency on this
  "eventId": 48213,
  "type": "opportunity.updated",
  "entityType": "opportunity",
  "entityId": "ABC123",
  "data": { "opportunityId": "ABC123", "title": "...", "responseDeadline": "2026-11-01" },
  "ts": "2026-09-20T04:31:00.000Z"
}

Delivery is at-least-once: the same event can arrive more than once. Build your handler to be idempotent, keyed on payload.id — the event's dedupe identity.

Retries

A failed delivery is retried with exponential backoff: 1m, 5m, 30m, 2h, 6h, 12h, 24h. After the final attempt a delivery is recorded as failed and is not retried again.

Verifying signatures

Every request carries X-Hashike-Signature and X-Hashike-Timestamp headers. The signing key is SHA-256 of the secret shown once at creation — not the secret string itself. Hash your secret, use that hash as an HMAC-SHA256 key over `<timestamp>.<raw body>`, and compare the result to the header in constant time. Reject the request if the timestamp is far from the current time (a replay).

const crypto = require("node:crypto");

function verify(secret, timestamp, rawBody, signatureHeader) {
  const signingKey = crypto.createHash("sha256").update(secret).digest("hex");
  const expected = crypto
    .createHmac("sha256", signingKey)
    .update(`${timestamp}.${rawBody}`)
    .digest("hex");

  const a = Buffer.from(expected, "utf8");
  const b = Buffer.from(signatureHeader, "utf8");
  const signatureOk = a.length === b.length && crypto.timingSafeEqual(a, b);

  const ageSeconds = Math.abs(Date.now() / 1000 - Number(timestamp));
  return signatureOk && ageSeconds <= 300; // reject anything older than 5 minutes
}