API

Proof-of-work challenges

Create, solve, and validate site-bound challenges while keeping authorization on your backend.

On this page

Challenge lifecycle

  1. Your backend keeps the sensitive operation pending when the decision is challenge.
  2. Create a challenge using the same site, or use a challenge supplied with the decision.
  3. Solve in the browser and submit the nonce for verification.
  4. If proof validation succeeds, continue your application’s additional verification or review policy. Do not treat proof validity as a checkout approval.
typescript
const challenge = await bastion.createChallenge();
const proof = await bastion.solveChallenge(challenge);
if (!proof) {
  throw new Error('Challenge did not validate');
}
// The protected operation remains subject to your backend policy.

HTTP contract

json
{
  "challenge_id": "challenge_example",
  "prefix": "server_random_prefix",
  "difficulty": 4,
  "expires_at": "2026-10-14T12:05:00.000Z"
}

POST /challenge or /verify/challenge creates the challenge. POST /challenge/verify or /verify/challenge/verify accepts {challenge_id, nonce}. The nonce is a string; the browser solver uses base-36 strings. SHA-256(prefix + nonce) must begin with difficulty zero hexadecimal characters. Difficulty is bounded to 4–6.

Challenges expire after five minutes and are single-use and site-bound. Expired, replayed, or wrong-site proofs fail. Browser solving can be stopped by SDK teardown; provide a clear retry path for interrupted or expired work. Do not run an unbounded challenge loop in a server request handler.