Alerts API · MCP

Pokemon restock alerts for AI agents

Give your agent, bot or app the same real-time Pokemon TCG restock alerts our app subscribers get — at the same moment. Connect over the Model Context Protocol, or receive signed webhooks on your own server.

Get a free key Live tier — $19.99/month

Free keys are issued instantly. No sales call, no waiting.

How it works

Endpointhttps://bujusjuj.us/mcp
ProtocolMCP over Streamable HTTP (JSON-RPC 2.0). Protocol versions 2025-06-18 and 2025-03-26. Stateless: every request stands alone.
AuthAuthorization: Bearer bjs_… on every request
Tools9 — see Tools
WebhooksOptional, HMAC-SHA256 signed — see Webhooks

Quickstart

1. Get a key

Go to bujusjujus.com/api-access, enter your email, and open the link we send you. Your developer console is there: take a free Reference key straight away, or subscribe to Live. You don't need an account first — we'll make one.

A key looks like bjs_ followed by 43 characters. It is shown once; we only store a hash, so save it somewhere safe. Lost one? Revoke it in the console and mint another.

2. Connect your agent

Claude Code

claude mcp add --transport http bujusjujus https://bujusjuj.us/mcp \
  --header "Authorization: Bearer $BUJUS_API_KEY"

Any MCP client that supports remote HTTP servers with custom headers (the exact file and key names vary by client):

{
  "mcpServers": {
    "bujusjujus": {
      "type": "http",
      "url": "https://bujusjuj.us/mcp",
      "headers": { "Authorization": "Bearer bjs_YOUR_KEY" }
    }
  }
}

For a client that only runs local (stdio) servers, bridge it with npx mcp-remote https://bujusjuj.us/mcp --header "Authorization: Bearer bjs_YOUR_KEY".

3. Ask

"What Pokemon products are in stock right now?" · "Tell me the moment a Pitch Black Elite Trainer Box drops at MSRP." · "Is $65 a fair price for that box?"

Or call it directly

Every call is a JSON-RPC POST. Tool results come back as JSON text in result.content[0].text.

curl -s https://bujusjuj.us/mcp \
  -H "Authorization: Bearer $BUJUS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call",
       "params":{"name":"get_in_stock_now","arguments":{"minutes":30}}}'

get_in_stock_now above is a Live tool. On a free Reference key it answers tier_required — try list_recent_drops instead, or call tools/list to see exactly what your key can reach.

Other methods: initialize, tools/list (full JSON Schemas for every tool) and ping. These three are free and are never metered.

The alert object

Every tool that returns alerts uses this shape:

{
  "id": "c108d9022699463c",          // stable, opaque; dedupe on this
  "detectedAt": "2026-09-23T21:00:12.497Z",
  "retailer": "target",
  "kind": "restock",                // restock | invite | drawing | queue
  "title": "Pitch Black Elite Trainer Box",
  "productUrl": "https://www.target.com/p/-/A-...",   // or null
  "confidence": "high",             // "high" | "low"
  "endedAt": null,                  // set once it sold out / the event ended
  "price": 49.99,                   // USD, or null
  "msrp": 49.99,                    // USD, or null
  "markupPct": 0                    // % over MSRP, or null
}

Tools

Arguments not listed are rejected (so a typo can't silently widen your results). Retailer values: amazon, bestbuy, costco, gamestop, hottopic, macys, pokemoncenter, samsclub, target, walmart.

get_in_stock_nowLive

What just came in stock, newest first. Returns { alerts, cursor }.

ArgumentDescription
minutesLook-back window, 1–60 (default 15)
retailerOnly this retailer
queryCase-insensitive product-name substring, e.g. "Pitch Black"
maxMarkupPctSkip alerts priced more than this % over MSRP (alerts with unknown MSRP are kept)
minConfidence"high" (default) or "low"
kind"restock" (default), "invite", "drawing", "queue" or "any"
limit1–100 (default 25)

wait_for_dropLive

A long-poll: the call stays open until a matching alert arrives or timeoutSec passes. Returns { alerts, cursor, timedOut }. A call that times out empty is not billed.

ArgumentDescription
cursorFrom your previous response. Omit to wait for the next new alert.
timeoutSec1–45 (default 30)
retailer, query, maxMarkupPct, minConfidence, kindSame filters as above

Loop on it, always passing back the returned cursor, so you never miss or repeat an alert:

let cursor;
for (;;) {
  const r = await callTool('wait_for_drop', { cursor, query: 'Pitch Black', maxMarkupPct: 10, timeoutSec: 45 });
  cursor = r.cursor;
  for (const alert of r.alerts) act(alert);   // dedupe on alert.id
}

Up to 5 waits per key can be open at once.

list_recent_dropsFree

Alert history, newest first, all kinds. retailer, sinceHours (1–2160, i.e. up to 90 days), minConfidence, kind, limit (1–200, default 50).

search_tracked_productsFree

The product catalogue we track, with MSRP. query, retailer, limit. Returns { name, retailer, msrp }. This is the tracked list, not a stock check.

get_product_msrpFree

MSRP for products matching query (required). Products without a known MSRP are left out, so an empty result means "unknown", not "free". Use specific names ("Pitch Black Elite Trainer Box") — a short query also matches packs and bundles.

get_retailer_statsFree

Drop counts per retailer over days (1–90, default 30), busiest first. Includes unverified reports, so read it as relative activity.

set_webhook · get_webhook · remove_webhookLive

Register, inspect or remove your webhook. See below.

Webhooks

For a server-side bot that shouldn't hold a connection open. Register one HTTPS endpoint per key:

{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"set_webhook",
  "arguments":{"url":"https://hooks.example.com/bujus","query":"Pitch Black","maxMarkupPct":10}}}

The response includes a signing secret (whsec_…), shown once. Calling set_webhook again replaces the URL and filters and issues a new secret. get_webhook shows status, failures and the last error (never the secret).

What we send

POST https://hooks.example.com/bujus
Content-Type: application/json
User-Agent: bujusjujus-alerts-webhook/1
X-Bujus-Signature: t=1790197212,v1=5b3f…

{"type":"alert","cursor":179019721200000,"sentAt":"2026-09-23T21:00:13.004Z","alert":{ …alert object… }}

Verify every request

The signature is HMAC-SHA256(secret, "<t>.<raw body>") as hex. Use the raw request bytes, compare in constant time, and reject a t more than 5 minutes old.

// Node.js
const crypto = require('crypto');
function verify(secret, rawBody, header) {
  const p = Object.fromEntries(header.split(',').map(kv => kv.split('=')));
  if (Math.abs(Date.now() / 1000 - Number(p.t)) > 300) return false;
  const want = crypto.createHmac('sha256', secret).update(`${p.t}.${rawBody}`).digest();
  const got = Buffer.from(p.v1 || '', 'hex');
  return got.length === want.length && crypto.timingSafeEqual(got, want);
}
# Python
import hmac, hashlib, time
def verify(secret: str, raw_body: bytes, header: str) -> bool:
    p = dict(kv.split("=", 1) for kv in header.split(","))
    if abs(time.time() - int(p.get("t", 0))) > 300:
        return False
    want = hmac.new(secret.encode(), p["t"].encode() + b"." + raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(want, p.get("v1", ""))

Limits

LimitValue
Daily quotaLive: 20,000 tool calls per UTC day. Reference: 5,000. Webhook deliveries count; empty wait_for_drop timeouts, initialize, tools/list and ping don't.
Per key120 requests per minute
Per IP600 requests per minute with a key; 20 per minute without one
Concurrent waits5 open wait_for_drop calls per key
Request size64 KB

When limited you get HTTP 429 with a Retry-After header. Back off and retry.

Errors

HTTPMeaning
401missing_key, invalid_key or key_revoked (see error.data.error)
403account_inactive — the subscription behind the key has ended
429Rate limit or daily quota — honour Retry-After
400Unsupported MCP-Protocol-Version header

A tool that runs but refuses returns HTTP 200 with result.isError: true and a text of the form code: message: invalid_arguments, unknown_tool, too_many_waits, invalid_webhook, busy or tool_failed. Refused calls are not billed.

Security

Tiers

Reference — freeLive — $19.99/month
Alert dataSame rows, 5 minutes laterThe moment we see it, no holdback
Toolslist_recent_drops, search_tracked_products, get_product_msrp, get_retailer_statsThose four plus get_in_stock_now, wait_for_drop and the three webhook tools
Webhooks—Signed, with retries
Calls per day5,00020,000
IssuedInstantlyInstantly, on payment

A five-minute-old restock signal is not a substitute for a live one — Target drops have sold out in around 78 seconds — so Reference is for building and testing against real data, not for running on.

Get a key

Enter your email, open the link we send, and take a key. Live subscriptions renew monthly until cancelled; cancel any time at bujusjujus.com/account-help and the key keeps working until the end of the paid period.

The API is sold for business use. Issuing a key is automatic and implies no approval or endorsement of what you build — use of it is governed by the Alerts API Terms and the Terms of Service, and you are responsible for how you use the data, including following each retailer's terms and purchase limits.

Support

Email [email protected] — a real person reads it.