Developer API
One call returns Denied, Flagged or No red flags found, with the reasons.
CA: coming soon. Paid API calls are coming soon: they switch on when $SENTINEL launches.
Cached verdicts under a second, fresh reads under three.
Every flag links to the transaction or wallet behind it.
Coin verdicts, transaction checks and coin intel.
On this page
Start here
- 1. Sign in on the site (a message signature) and create your key on the dashboard. It is shown once.
- 2. Top up credits on the credits screen (coming soon). Every call is paid from them, in dollars.
- 3. Send
{ input }toPOST /api/v1/checkwith the key as a Bearer token.
curl -s https://sentinellayer.tech/api/v1/check \
-H "Authorization: Bearer $SENTINELLAYER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"input": "<base64 transaction, address or mint>"}'Authentication
Every request carries Authorization: Bearer sentinel_.... Keys start with sentinel_, are stored only as a hash and are shown once when created. There is one key per wallet: rotating issues a new key and the old one stops at once; revoking stops it without a replacement.
Any signed-in wallet can create a key. Calls are paid from that wallet's credits; when they run short, calls answer 402 no_credits and usage still answers so you can see why. Keep the key on your server. Never ship it to a browser or an app bundle.
Pricing and limits
| Call | Price |
|---|---|
POST /api/v1/check | $0.10 a call |
GET /api/v1/coin/{mint} depth=basic | $0.10 a call |
GET /api/v1/coin/{mint} depth=full | $0.50 a call |
GET /api/v1/coin/{mint} depth=cluster | $1.00 a call |
GET /api/v1/coin/{mint} depth=case | $2.00 a call |
GET /api/v1/usage | Free |
Prices are in dollars, paid from credits you top up with $SENTINEL. Credits are stored in dollars, so they do not change when the token price moves. A malformed input is refused before anything is charged, and a call that cannot run is refunded. The operators can change prices; the live list is on the pricing page and in GET /api/v1/usage.
Throttle: 5 requests a second per key, burst 10. Every paid call carries these headers:
| Header | Meaning |
|---|---|
x-quota-reason | paid |
x-charged-usd | Dollars this call cost |
x-credits-usd | Credits left on the key's wallet, in dollars |
Check a transaction, address or mint
| Field | Type | Notes |
|---|---|---|
input | string, required | A base58 or base64 serialized transaction (signed or unsigned), a wallet or program address, or a token mint. Up to 256 KB. |
signer | string, optional | The wallet whose balance changes you want measured, for transactions with several signers. Defaults to the fee payer. |
Your custom rules from the dashboard run after the built-in checks on every API call, exactly as on the site.
curl -s https://sentinellayer.tech/api/v1/check \
-H "Authorization: Bearer $SENTINELLAYER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"input": "<unsigned base64 transaction>", "signer": "<wallet that would sign>"}'Read a coin verdict
The same verdict as the coin page on the site (RUG, RUG LIKELY, INSIDER RING, BUNDLED, LINKED HOLDERS, DUMP RISK, DEAD, No red flags found), cut to the depth you pay for. Every flag cites on-chain evidence with a Solscan link.
| depth | Price | What it holds |
|---|---|---|
basic | $0.10 a call | The verdict, headline, top reasons, key stats, each check with its first proof. The default. |
full | $0.50 a call | Every proof on every check: every wallet, every transaction. |
cluster | $1.00 a call | Plus the cluster map (insider rings, bundles), linked wallets and the dev's history in full. |
case | $2.00 a call | Plus caseFile: the creator's case file (fund trace, operator cluster, record). |
withheld says what the chosen depth left out, so you can decide whether a deeper call is worth it.
curl -s "https://sentinellayer.tech/api/v1/coin/<mint>?depth=full" \
-H "Authorization: Bearer $SENTINELLAYER_API_KEY"Read your usage
Free to call. Credits left in dollars, this month's call count and the price of each call.
curl -s https://sentinellayer.tech/api/v1/usage \
-H "Authorization: Bearer $SENTINELLAYER_API_KEY"{
"period": "2026-10",
"calls": 1832,
"balanceUsd": 41.5,
"prices": { "check": 0.1, "coinBasic": 0.1, "coinTier1": 0.5, "coinTier2": 1, "coinTier3": 2 }
}Reading a verdict
The verdict field is always one of safe, warn or block. On the site the same three read as No red flags found, Flagged and Denied. No red flags found means none of the checks found a problem, never a guarantee: show your users that wording, not the raw value.
None of the checks found a problem in the simulation or the lists. Never a guarantee: the reasons list what was checked.
Sign only if every finding is expected: an unverified program, a first-time recipient, an approval, or a simulation that did not finish.
Do not sign. A finding means you lose funds or control: an authority hand-over, a drain to a flagged address, a known scam program.
| Field | What it holds |
|---|---|
id | Check id, for sharing and support. |
kind | transaction, address or token: how the input was read. |
verdict | safe, warn or block (No red flags found, Flagged, Denied on the site). Fixed meaning, see above. |
headline | One sentence you can show your user as is. |
reasons[] | Every finding: code (stable), severity (info, low, medium, high, critical), title, detail and evidence (label, value, optional link). |
simulation | Transactions only: ok and error, signer, deltas (each asset leaving or entering, raw and formatted, with counterparty), solAtRiskLamports, programs (known, flagged), logs. |
subject | Addresses and mints: the address, a label when we know it, and its type (wallet, token, program). |
checkedAt | When the check ran (ISO 8601, UTC). |
ms | How long the check took, in milliseconds. |
Never show a verdict without its reasons. A warn for an unverified program is a different conversation from a warn for a first-time recipient; the reason codes let you branch on that.
Errors
| Status | error | When |
|---|---|---|
| 400 | bad_input, bad_signer, bad_mint | The body or path is not a transaction, address or mint. |
| 401 | api_key_required, api_key_invalid | No Bearer key, or the key is unknown or revoked. |
| 400 | bad_depth | depth is not basic, full, cluster or case. |
| 402 | no_credits | The key's wallet has fewer credits than the call costs. The body carries priceUsd and balanceUsd. |
| 429 | rate_limited | Over 5 requests a second for this key. Honor Retry-After. |
| 503 | api_paused, checks_paused | Paused by the operators for a moment. Retry shortly. |
| 502 | verdict_failed | The coin verdict could not be built. The call was refunded. |
| 500 | internal | Our side. Retry with backoff. |
Every error is JSON with a stable error code and a plain message:
{
"error": "no_credits",
"message": "This call costs $0.50 and the key's wallet has $0.20 in credits. Top up at /credits.",
"priceUsd": 0.5,
"balanceUsd": 0.2
}TypeScript SDK
@sentinellayer/sdk has no dependencies and uses the global fetch (Node 18+, Deno, Bun). It retries throttles and server errors with backoff, honors Retry-After, and throws SentinelLayerError with status, code and the error body.
import { SentinelLayer, SentinelLayerError } from "@sentinellayer/sdk";
const sl = new SentinelLayer({
apiKey: process.env.SENTINELLAYER_API_KEY!, // server side only
baseUrl: "https://sentinellayer.tech",
});
export async function guard(txBase64: string, signer: string) {
try {
const r = await sl.check(txBase64, { signer });
if (r.verdict === "block") {
throw new Error(r.reasons.map((x) => x.title).join("; "));
}
return r;
} catch (e) {
if (e instanceof SentinelLayerError && e.code === "no_credits") {
// e.body.priceUsd and e.body.balanceUsd: top up credits on the site
}
throw e;
}
}const coin = await sl.scanCoin(mint); // the basic coin verdict
console.log(coin.line, coin.headline);
const u = await sl.usage(); // { period, calls, balanceUsd, prices }| Method | Calls | Returns |
|---|---|---|
check(input, { signer? }) | POST /api/v1/check | CheckResult |
scanCoin(mint) | GET /api/v1/coin/{mint} | The basic coin verdict |
usage() | GET /api/v1/usage | Usage |
Options: apiKey, baseUrl, timeoutMs (default 60 s), retries (default 2), fetch.
OpenAPI
The full description is served at /api/v1/openapi.json (OpenAPI 3.1, public, CORS open), ready for code generators and API clients.