From wallet to checkpoint.
Use a funded Solana mainnet wallet you control and an x402 V2 client. Your signing adapter stays outside the service. The examples are Node/TypeScript excerpts; they do not connect a wallet or spend funds from this website.
Install @x402/fetch, @x402/svm and the compatible @solana/kit peer dependency in your client project. Supply a wallet adapter with an address, raw Ed25519 signMessage(bytes), and a ClientSvmSigner. A wallet or remote signer may require explicit approval.
01. Request a challenge
Send your public wallet address to POST /v1/auth/challenge. The response contains nonce, message, expires_at, and signature_encoding: "base64". The challenge expires after five minutes and can be consumed once.
const api = "https://api.mantismesh.com";
const post = (path, body) => fetch(api + path, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body)
});
// wallet is your agent's external signing adapter.
const challengeResponse = await post("/v1/auth/challenge", {
wallet: wallet.address
});
if (!challengeResponse.ok) throw new Error("Challenge failed");
const { nonce, message } = await challengeResponse.json();02. Sign and establish a session
Sign the exact UTF-8 message bytes and submit the base64 signature to POST /v1/auth/verify. The returned bearer session lasts one hour. A signature is authentication, not an on-chain payment.
// Sign the exact UTF-8 message. Do not change its text.
const bytes = new TextEncoder().encode(message);
const signature = Buffer.from(
await wallet.signMessage(bytes)
).toString("base64");
const sessionResponse = await post("/v1/auth/verify", {
wallet: wallet.address,
nonce,
signature
});
if (!sessionResponse.ok) throw new Error("Sign-in failed");
const { token } = await sessionResponse.json();03. Call a paid endpoint
Set an expected receiver and explicit spend ceiling in your client policy before using this excerpt. Read the service’s public pricing and verify the x402 terms’ network, mint, recipient, and amount. For this 24-hour save, current advertised pricing is $0.010 USDC.
When payment is required, the API returns HTTP 402 with a PAYMENT-REQUIRED header. The official client builds the signed payment and resends the identical request with PAYMENT-SIGNATURE. Successful saves return 201, checkpoint_id, expires_at, retention, and a PAYMENT-RESPONSE receipt header.
import { x402Client, wrapFetchWithPayment } from "@x402/fetch";
import { ExactSvmScheme } from "@x402/svm/exact/client";
import { USDC_MAINNET_ADDRESS } from "@x402/svm";
const network = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp";
const EXPECTED_RECEIVER = "CASWpLcrvGrHwWepBFf3rGycrzb6eUnqtKJyV3CYLLab";
const MAX_PAYMENT_BASE_UNITS = BigInt("10000");
// wallet.signer implements @x402/svm's ClientSvmSigner.
const client = new x402Client().register(
network, new ExactSvmScheme(wallet.signer)
);
// Set the expected receiver from the service's payment terms.
// Choose your own maximum debit; amounts are USDC base units.
client.registerPolicy((_version, requirements) =>
requirements.filter(r =>
r.network === network &&
r.scheme === "exact" &&
r.asset === USDC_MAINNET_ADDRESS &&
r.payTo === EXPECTED_RECEIVER &&
BigInt(r.amount) <= MAX_PAYMENT_BASE_UNITS
)
);
const paidFetch = wrapFetchWithPayment(fetch, client);
const operationKey = crypto.randomUUID();
const body = JSON.stringify({
task_id: "research-042",
payload: { step: 7, next: "synthesize" },
retention: "24h"
});
const response = await paidFetch(api + "/v1/checkpoints", {
method: "POST",
headers: {
Authorization: "Bearer " + token,
"Content-Type": "application/json",
"Idempotency-Key": operationKey
},
body
});
if (response.status !== 201) {
throw new Error("Save returned " + response.status + "; inspect before retrying");
}
const { checkpoint_id } = await response.json();04. Retrieve and continue
Call GET /v1/checkpoints/{checkpointId} with your session and a new operation key. Retrieval is separately priced at $0.005. Your application decides how to resume execution from the returned payload.
// Retrieval is a separate paid operation with a fresh key.
const response = await paidFetch(
api + "/v1/checkpoints/" + encodeURIComponent(checkpoint_id),
{
headers: {
Authorization: "Bearer " + token,
"Idempotency-Key": crypto.randomUUID()
}
}
);
if (!response.ok) throw new Error("Read failed");
const checkpoint = await response.json();
// Feed checkpoint.payload back into your own runtime.Retries are operations, not guesses.
Generate one Idempotency-Key for each logical operation and keep it stable for retries. Preserve the HTTP method, path, JSON field order, and values. Protected GET requests also require this header. A replayed result includes Idempotency-Replayed: true.
| Response | Meaning |
|---|---|
401 | Missing, invalid, or expired wallet session |
402 | An enabled operation requires x402 payment |
409 | Quota, idempotency, lock, or pending-payment conflict |
410 | Expired or consumed object while its record remains; after cleanup it may be 404 |
413 | Request or payload exceeds the size limit |
429 | Rate limit exceeded |
503 | Paid operations paused, payment unavailable, or settlement requires review |