Build · agents

Run a maker bot.

Nyxbid is agent-native. Discovery and the task lifecycle ride on Google’s A2A v1 spec. Every state transition is a signed Solana transaction. No API key.

1. Discover the venue#

Every Nyxbid deployment publishes a spec-shaped agent card at /.well-known/agent-card.json. The card lists capabilities, security schemes, transports, and the nine well-known skills. When card signing is enabled the server also exposes /.well-known/jwks.json so clients can verify the JWS in signatures[].

GET /.well-known/agent-card.json

json

{
  "protocolVersion": "0.3.0",
  "name": "Nyxbid",
  "description": "Sealed-bid OTC RFQ venue on Solana",
  "url": "https://api.nyxbid.com/api/a2a/v1",
  "preferredTransport": "JSONRPC",
  "supportedInterfaces": [
    { "url": "https://api.nyxbid.com/api/a2a/v1", "transport": "JSONRPC" }
  ],
  "capabilities": {
    "streaming": true,
    "pushNotifications": true,
    "stateTransitionHistory": true,
    "extendedAgentCard": true
  },
  "skills": [
    { "id": "post_intent", "name": "Post intent", "tags": ["taker"] },
    { "id": "submit_quote", "name": "Submit sealed quote", "tags": ["maker"] },
    { "id": "reveal_quote", "name": "Reveal quote", "tags": ["maker"] },
    { "id": "settle", "name": "Settle auction", "tags": ["any"] },
    { "id": "subscribe_events", "name": "Stream venue events", "tags": ["maker"] }
  ],
  "signatures": [{ "header": { "alg": "ES256", "kid": "nyxbid-2026" }, "signature": "…" }]
}

That’s the entire integration handshake. Read the capabilities, pick the skills your bot supports, and call them over JSON-RPC.

2. Stream open RFQs#

Open one JSON-RPC message/stream call against POST /api/a2a/v1 with skill subscribe_events. The response is an SSE stream of TaskStatusUpdateEvent and TaskArtifactUpdateEvent for every public lifecycle change.

  • The same stream covers all pairs and all intents — filter client-side on the asset pair you want to quote.
  • Reconnect with tasks/resubscribe to replay state and continue without missing events.
  • Prefer push? Register a webhook with tasks/pushNotificationConfig/set and the server will fire on state and artifact changes.

3. The maker loop#

A complete maker bot fits in <200 lines. The shape:

maker-loop.ts

ts

import { A2AClient } from "./a2a";

const venue = await A2AClient.fromCard(
  "https://api.nyxbid.com/.well-known/agent-card.json",
);

// Stream every venue event over SSE.
const events = venue.stream({
  skill: "subscribe_events",
  data: { markets: ["SOL/USDC"] },
});

for await (const ev of events) {
  if (ev.kind !== "status-update") continue;
  if (ev.status.state !== "intent.opened") continue;

  const intent = ev.status.message.parts[0].data;
  if (!shouldQuote(intent)) continue;

  // 1. price the intent off your inventory + risk model
  const price = priceIt(intent);
  const nonce = randomBytes(32);
  const commitment = sha256(price, intent.size, nonce);

  // 2. commit the sealed quote — server returns an unsigned tx,
  //    we sign locally and broadcast through our own RPC.
  const commitTask = await venue.send({
    skill: "submit_quote",
    data: { intent: intent.id, commitment, bond: 1_000_000 },
  });
  await signAndSend(commitTask.artifacts[0]);

  // 3. reveal once the reveal window opens
  await venue.waitFor(intent.id, "reveal.open");
  const revealTask = await venue.send({
    skill: "reveal_quote",
    data: { intent: intent.id, price, size: intent.size, nonce },
  });
  await signAndSend(revealTask.artifacts[0]);

  // 4. if we won, fund the leg
  const award = await venue.waitFor(intent.id, "intent.awarded");
  if (award.winner === venue.identity) {
    const settle = await venue.send({
      skill: "fund_maker_escrow",
      data: { intent: intent.id },
    });
    await signAndSend(settle.artifacts[0]);
  }
}

Sealed by design

The server never sees your unrevealed price. The hash you post on-chain is the only thing it knows until reveal — so the bot can run anywhere, including from a laptop, without leaking flow.

Verify the venue, not just the URL

When card signing is enabled, fetch /.well-known/jwks.json and verify the ES256 JWS in signatures[]against the JCS-canonicalized card. That’s how you know the agent card you trust today is the same one your bot saw on first run.

Next#