Skip to main content
The TypeScript SDK is WIP. Today, poll GET /intent-details/:intentId directly. Webhooks are planned but not yet shipped.
After submission, an intent moves through a small set of states. Today, you track via polling; the SDK’s subscribe is a thin polling helper, and webhook delivery is on the roadmap.

States

These come from the relayer’s IntentDetails.status field:
StateMeaningWhat’s happening behind the scenes
pendingIntent created on-chain, awaiting solver bidsRelayer has included the intent in a batched plaintext broadcast to solvers; the auction is running
solvingA solver has won the auction and is fulfilling on the destination chainRelayer has re-encrypted the recipient bundle to the winning solver; solver is delivering to stealth address(es)
settledDestination delivery confirmed; settlement on source chain in flightRelayer is finalizing on source chain to release the solver’s reward
completedSource-chain settlement complete. Lifecycle terminal.settleTxHash is populated
State transitions are forward-only: once completed, the intent is final.

Poll

Direct API:
const res = await fetch(`${RELAYER_URL}/intent-details/${intentId}`);
const { intent } = await res.json();
console.log(intent.status, intent.solveTxHash);
SDK (when published):
const intent = await tachyon.intent.status(intentId);
For interactive UIs, poll every 2–5 seconds while the intent is live (pending or solving).

Subscribe (polling helper)

const unsubscribe = tachyon.intent.subscribe(intentId, (intent) => {
  if (intent.status === "completed") {
    console.log("done:", intent.settleTxHash);
    unsubscribe();
  }
}, { intervalMs: 3000 });
Under the hood this is a polling loop against GET /intent-details/:intentId. When webhooks ship, this method will switch to a long-lived connection automatically.

Webhooks (planned)

WIP. The planned shape is shown for forward compatibility, none of these calls work today.
await tachyon.webhooks.register({
  url: "https://your-app.example.com/tachyon/webhook",
  events: ["intent.solving", "intent.settled", "intent.completed"],
  secret: process.env.WEBHOOK_SECRET,
});
Each callback will be signed with HMAC using secret:
import { verifyTachyonSignature } from "@tachyon/sdk/webhooks";

app.post("/tachyon/webhook", express.raw({ type: "*/*" }), (req, res) => {
  const ok = verifyTachyonSignature(req.body, req.headers["x-tachyon-signature"], process.env.WEBHOOK_SECRET);
  if (!ok) return res.status(401).end();

  const event = JSON.parse(req.body.toString());
  switch (event.type) {
    case "intent.completed":
      markCompleted(event.intentId, event.settleTxHash);
      break;
  }
  res.status(200).end();
});
TODO: confirm webhook event names, payload shape, signature header, and retry policy before publish.

Choosing a method (today)

MethodWhen to use
Poll GET /intent-details/:intentIdBackend job, batch worker, or any server flow
SDK subscribe (polling helper)Interactive UI, same as poll, just less code
WebhooksWill be the recommended server-to-server option once shipped

Idempotency (when webhooks ship)

Webhook deliveries can repeat on retries. Use the eventId in each callback to deduplicate before applying side effects.

Failure semantics

If a solver does not fulfill, the user is refunded via the on-chain escape mechanism on BridgeIntentV2, funds are not at risk. The intent stays in pending until either solved or refunded; you can watch for the absence of progress and surface it to the user.

Recipient flow: claiming funds

How recipients sweep settled stealth-address balances.