TxShield API
Pre-flight transaction intelligence for Solana mainnet. Drop unsigned transactions in, get back an approve · warn · block verdict with the per-vector breakdown — typically in under 80 ms.
Overview
TxShield is a single-purpose API: simulate every Solana transaction before it broadcasts. We run 14 detection vectors in parallel — MEV, slippage, rug-pull, program safety, priority fees, balance changes, and more — and return one verdict envelope. Wallets, trading bots, DEX frontends and exchanges drop us in front of every send call.
Base URL: https://txshield.dev. All endpoints under /api/v1/. JSON in, JSON out. UTF-8. ISO 8601 timestamps in UTC.
You only need one endpoint to ship.
POST /api/v1/solana/tx/simulate drives every vector in this guide. Webhooks, batching and streaming are convenience layers over the same call.
01Quickstart
Five minutes from npm install to your first verdict.
1. Get an API key
Sign in to the dashboard and create a key under Settings → API keys. Each key is scoped to one project, lives in one of three modes (test, live, internal) and can be rotated or revoked at any time.
Never put a live key in client-side code.
Use scoped session tokens for browser/mobile origins. They expire after 15 minutes and are bound to a single user wallet.
2. Install the SDK
npm install @txshield/sdkbun add @txshield/sdk # or pnpm / yarn
pip install txshielduv add txshield # or poetry
# nothing to install — just curl + your keyexport TXSHIELD_KEY="txshield_live_..."
3. First request
import { TxShield } from "@txshield/sdk";const tx = new TxShield({ key: process.env.TXSHIELD_KEY! });const v = await tx.solana.simulate({ transaction: unsignedB64, // VersionedTransaction.serialize() → base64});if (v.risk.risk_level === "critical") { throw new Error(`refused: ${v.failure_reason}`);}
from txshield import TxShieldtx = TxShield(key=os.environ["TXSHIELD_KEY"])v = tx.solana.simulate(transaction=unsigned_b64)if v.risk.risk_level == "critical": raise RuntimeError(f"refused: {v.failure_reason}")
curl -X POST "https://txshield.dev/api/v1/solana/tx/simulate" \ -H "X-API-Key: $TXSHIELD_KEY" \ -H "Content-Type: application/json" \ -d '{"transaction": "<base64-versioned-tx>"}'
4. Read the verdict
The response envelope is the same shape on every chain.
{
"success": true,
"compute_units": 28104,
"suggested_compute_limit": 31000,
"fee_estimate_sol": 0.0000125,
"priority_fees": {
"low": 1000, "medium": 10000,
"high": 100000, "very_high": 1000000,
"samples": 312
},
"slippage": { "bps": 7, "route": "jupiter-v6" },
"risk": {
"mev_score": 0.04, "mev_level": "none", "mev_type": null,
"has_blacklisted_program": false,
"blacklisted_programs": [],
"dex_programs": ["JUP6L…AG4"],
"token_risk": null,
"risk_level": "low"
},
"recommendations": [],
"program_breakdown": […],
"call_tree": […]
}
02Authentication
Two ways to authenticate, picked by call site:
- API keys (
X-API-Key: txshield_live_…) — for server-to-server traffic. Created via the dashboard orPOST /api/v1/api-keys. Three modes:test,live,internal. - JWT bearer tokens (
Authorization: Bearer eyJ…) — for the dashboard SPA itself and any human-driven flow. 24h expiry on access, 30d on refresh. Issued byPOST /auth/login.
Both authenticate the same endpoints. Where you use which is a security choice — never put an API key in client-side code.
Scoped session tokens (browser-safe)
For wallet/mobile origins, mint a short-lived session token server-side and hand it to the client. Tokens expire after 15 minutes and are bound to a single user wallet so leakage has a tiny blast radius.
03Solana — single simulation
POST/api/v1/solana/tx/simulateThe core of the product. Submit one unsigned VersionedTransaction serialized as base64. We simulate it against mainnet state, run the 14 detection vectors in parallel, and return a single envelope.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
| transaction | string · base64 | required | Serialized VersionedTransaction (or legacy Transaction) — the bincode produced by tx.serialize(), base64-encoded. Signature slots may be empty/zero; we don't verify them. |
| vectors[] | string[] | optional | Restrict which detection vectors run. Default: all. Common subsets: ["mev","slippage","rug","program"]. |
| timeout_ms | int | optional | Server-side timeout cap. Default 800. Anything below 80 will fall back to cached priority-fee data only. |
Response — top-level fields
| Field | Type | Required | Description |
|---|---|---|---|
| success | bool | required | Did the inner Solana simulateTransaction succeed? false just means the tx would revert — the verdict envelope is still useful. |
| compute_units | int? | optional | CU consumed during the simulated execution. Null if the tx didn't reach execution. |
| suggested_compute_limit | int? | optional | CU limit we recommend you set on the real submit (typically compute_units × 1.1). |
| fee_estimate_sol | float? | optional | Estimated fee in SOL at current cluster prices, including priority fees. |
| priority_fees | object | required | P25/P50/P75/P95 of getRecentPrioritizationFees for the programs touched. Use medium as a default tip; jump to high when latency matters. |
| slippage | object? | optional | Worst-case slippage in basis points, plus the route used. Populated when a DEX program is detected. |
| risk | object | required | Per-vector breakdown — see Detection vectors. |
| recommendations[] | array | required | Concrete actions you can take (e.g. add a priority fee, increase slippage tolerance, switch route). Empty when nothing's wrong. |
| program_breakdown | array | optional | Per-program CU + invocation count, useful for cost attribution and debugging. |
| call_tree | array | optional | CPI tree extracted from simulation logs. Helpful when a tx fails mid-flight. |
| failure_reason | string? | optional | Human-readable explanation of why success is false (when applicable). |
Solana — batch simulation
POST/api/v1/solana/tx/simulate-batchUp to 50 transactions in one round-trip. Use it when your bot evaluates multiple candidate routes per block — saves the round-trip latency on N-1 of them.
Order is preserved.
Results return in the same order as the input array. No partial-failure quirks — if one tx errors, only that index's success is false; others continue.
Solana — streaming verdicts
WSwss://txshield.dev/api/v1/solana/tx/simulate-streamWebSocket connection for sub-50 ms verdicts. Send a JSON envelope per line; receive verdicts as they finish. Authenticate with the ?api_key=… query param at connect time. Connection idle-timeout 60s — send a ping if you've gone quiet.
Simulation history
GET/api/v1/solana/simulationsPaginated list of past simulations on this account. Query params: limit (default 25, max 200), cursor (opaque string from previous page), since/until (ISO 8601), risk_level, has_blacklisted_program.
Retention: 90 days by default; up to 7 years for volume customers (negotiated per tenant).
Aggregate stats
GET/api/v1/solana/simulations/statsPre-computed aggregates for the dashboard widget: total sims, 24h count, success rate, P50/P95/P99 latency. Refreshed every 60s.
04Detection · MEV / sandwich
Detects front-run + back-run pairs against monitored Solana DEX programs (Jupiter, Raydium, Orca, Meteora, Lifinity). Returns:
risk.mev_score— float 0.00–1.00. Aggregate likelihood the tx will be sandwiched at submit-time.risk.mev_level— bucketed:none,low,medium,high,critical.risk.mev_type— concrete pattern when high:"sandwich","jit","backrun_only".
Treat high/critical as a hard refusal in production. medium usually means you should re-route through a private mempool or wait for the next block.
Detection · Rug-pull / honeypot
Engaged when the tx touches an SPL-token program. Checks:
- Mint authority + freeze authority status (active = high risk).
- LP-lock duration; lock unlocks < 7 days fire
medium. - Top-10 holder concentration. > 80% fires
high. - Sell-test simulation — would a sell tx revert? If yes →
criticalhoneypot.
Detection · Slippage overflow
Pulls live route quotes from Jupiter Price API at submit-time priority fees — not the stale UI estimate. Returns slippage.bps as worst-case basis points and slippage.route as the chosen route. Use recommendations to surface alternative routes when bps > your threshold.
Detection · Program safety
Curated and customer-submitted blacklist of malicious programs anywhere in the CPI tree. Categories:
| Category | What it means |
|---|---|
drainer | Known wallet drainers — auto-block on every account. |
rug_deployer | Programs that have rugged at least once historically. |
fake_token | Counterfeit USDC/USDT/etc. minted to mimic legitimate tokens. |
honeypot | Sell-disabled programs (catch buyers who can't exit). |
phishing | Programs used by phishing kits (drain on sign). |
compromised | Once-legitimate programs whose authority has been compromised. |
Per-tenant overrides for volume customers — extend the list with your own blocklist/allowlist.
Detection · Priority fee
Live getRecentPrioritizationFees sampling per program. Returned as p25/p50/p75/p95 inside priority_fees. Use the medium percentile as the default tip; jump to high when landing latency matters more than fee cost.
Detection · Pre-flight simulation
The basis for everything else. Solana simulateTransaction with full pre-execution against mainnet state. Returns balance changes, CPI call tree, per-program compute units, and revert reasons in compute_units, program_breakdown, call_tree, failure_reason.
05Webhooks
POST/api/v1/solana/simulations/webhooksRegister a URL to receive verdict events in real-time. We POST a JSON payload to your URL whenever a sim with risk_level ≥ your configured threshold lands. Default delivery latency: < 200 ms after the verdict.
Signature verification
Every webhook delivery carries an X-TxShield-Signature header — HMAC-SHA256 over the raw body, signed with your endpoint's secret. Verify in your handler before trusting the payload:
import { createHmac, timingSafeEqual } from "node:crypto";function verify(rawBody: Buffer, signature: string, secret: string) { const expected = createHmac("sha256", secret).update(rawBody).digest("hex"); return timingSafeEqual(Buffer.from(expected), Buffer.from(signature));}
Retry policy
If your endpoint returns a non-2xx status (or doesn't respond within 8s), we retry with exponential backoff: 30s, 2m, 10m, 1h, 6h. After the 5th attempt we mark the delivery as failed; you can manually replay it from the dashboard. Idempotency: each delivery carries a stable delivery_id in the body — use it to dedupe on your side.
06API keys
GET/api/v1/api-keys POST/api/v1/api-keys DEL/api/v1/api-keys/{id} POST/api/v1/api-keys/{id}/rotateManage keys programmatically or via the dashboard. The cleartext key is only returned once — at creation. After that you only see the prefix (e.g. txshield_live_) and metadata (requests_count, last_used_at, created_at).
Rotation is graceful: the new key activates immediately, the old one stays valid for 24h, then auto-revokes. No downtime.
07Billing
Pure pay-as-you-go. 1,000 simulations per day on the house, then €0.01 per simulation past that, billed at the end of the calendar month. No tiers, no monthly fee, no commitment, no feature gating — every account gets every detection vector, webhooks, batch and WebSocket from day one.
| Free quota | Metered (after card added) | |
|---|---|---|
| Price | €0 | €0.01 per simulation past the daily free tier |
| Daily allowance | 1,000 sims / day · resets 00:00 UTC | Same 1,000 / day still free, then metered |
| Rate limit | 10 rps | 100 rps · burst 250 |
| Behaviour past quota | 429 with Retry-After | Continues serving · €0.01 per call |
| Detection vectors | All 14 | All 14 |
| Features | Webhooks · WebSocket · batch | Webhooks · WebSocket · batch · custom rules · per-tenant blocklist |
| SLA | Best-effort | P50 ≤ 80 ms · 99.9 % uptime |
| Support | Community Discord | Email + Slack · 24h response |
Above ~5M sims / month? Volume customers get a negotiated per-call rate, a dedicated regional cluster (99.99% SLA), SOC 2 / ISO 27001 evidence pack, and Slack-Connect with 1-hour pager response. Email hello@txshield.dev.
Endpoints:
GET/api/v1/billing/usage GET/api/v1/billing/subscription POST/api/v1/billing/checkout POST/api/v1/billing/portalcheckout creates a Stripe Checkout session for the metered subscription and returns a redirect URL. portal creates a Customer Portal session for managing payment methods, invoices, and cancellation. Adding a card just lifts the throttle — you're never charged for the first 1,000/day.
08Errors
HTTP status codes are load-bearing. Read them.
| Code | Meaning | What to do |
|---|---|---|
| 200 | OK | Read the verdict envelope. |
| 400 | Bad request | Validation error in request shape — check error.message. |
| 401 | Unauthenticated | Missing or invalid API key / JWT. |
| 403 | Forbidden | Plan-gated feature (e.g. custom rules on Free tier). |
| 404 | Not found | Resource doesn't exist or isn't visible to your account. |
| 409 | Conflict | Idempotency conflict — same key, different body. |
| 422 | Unprocessable | Request shape OK but content is invalid (e.g. tx fails to deserialize). |
| 429 | Rate limited | Backoff — see Rate limits. Honour Retry-After header. |
| 500 | Server error | Our problem — automatic alert fires. Retry with backoff. |
| 503 | Service unavailable | Region failover in progress. Retry with backoff. |
All error responses share a JSON shape:
{
"error": {
"code": "invalid_transaction",
"message": "failed to deserialize VersionedTransaction: …",
"request_id": "req_01HVZX9P3J4D2TJYP91D"
}
}
09Rate limits
Per-API-key rate limits, enforced at the edge. Burst window: 1 second.
| Steady-state | Burst | Behaviour | |
|---|---|---|---|
| Free quota | 10 rps | 25 rps | Throttle — 429 with Retry-After. |
| Metered (card on file) | 100 rps | 250 rps | Throttle past burst. |
| Volume | Negotiated | Negotiated | Per-tenant. |
Headers on every response:
X-RateLimit-Limit— your steady-state cap.X-RateLimit-Remaining— calls left in the current second.X-RateLimit-Reset— Unix epoch when the bucket refills.Retry-After— seconds to wait (only on 429).
10SDKs
Both SDKs are generated from the OpenAPI 3.1 spec. Same field names, same types, same idempotency keys.
- TypeScript —
npm install @txshield/sdk. ESM + CJS.fetch-based, runs in Node 18+, Bun, Deno, Cloudflare Workers, Vercel Edge. - Python —
pip install txshield. Sync + async clients. Type-stubs included. Runs on 3.10+. - curl — every endpoint is doc-equivalent to a one-line curl. See request examples above.
Other languages: use the OpenAPI spec at /openapi.json with your generator of choice (we test against openapi-typescript, openapi-python-client, and oapi-codegen for Go).
11Changelog
- 2026-05-06 — Pricing simplified to pure pay-as-you-go: 1,000 sims/day free, €0.01/sim past that. No tiers, no monthly fee. Stripe metered billing live.
- 2026-05-05 — Dashboard SPA migrated to its own niso package; nginx routing fixed via panel-proxy.
- 2026-04-24 — TxShield API adopted into niso package management. No customer impact.
- 2026-04-21 — Helius RPC degradation incident (9 min, partial latency increase). Resolved.
- 2026-04-09 — Webhook delivery backlog (22 min, no drops). Improved retry backoff curve.