Skip to content
API

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.

Speed
<1 s

Cached verdicts under a second, fresh reads under three.

Evidence
Solscan

Every flag links to the transaction or wallet behind it.

Endpoints
3

Coin verdicts, transaction checks and coin intel.

On this page
  1. Start here
  2. Authentication
  3. Pricing and limits
  4. POST /api/v1/check
  5. GET /api/v1/coin/{mint}
  6. GET /api/v1/usage
  7. Reading a verdict
  8. Errors
  9. TypeScript SDK
  10. OpenAPI

Start here

  1. 1. Sign in on the site (a message signature) and create your key on the dashboard. It is shown once.
  2. 2. Top up credits on the credits screen (coming soon). Every call is paid from them, in dollars.
  3. 3. Send { input } to POST /api/v1/check with the key as a Bearer token.
curlyour first check
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

CallPrice
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/usageFree

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:

HeaderMeaning
x-quota-reasonpaid
x-charged-usdDollars this call cost
x-credits-usdCredits left on the key's wallet, in dollars

Check a transaction, address or mint

POST/api/v1/check$0.10 a call
FieldTypeNotes
inputstring, requiredA base58 or base64 serialized transaction (signed or unsigned), a wallet or program address, or a token mint. Up to 256 KB.
signerstring, optionalThe 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.

curlwith an explicit signer
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

GET/api/v1/coin/{mint}?depth=from $0.10 a call

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.

depthPriceWhat it holds
basic$0.10 a callThe verdict, headline, top reasons, key stats, each check with its first proof. The default.
full$0.50 a callEvery proof on every check: every wallet, every transaction.
cluster$1.00 a callPlus the cluster map (insider rings, bundles), linked wallets and the dev's history in full.
case$2.00 a callPlus 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
curl -s "https://sentinellayer.tech/api/v1/coin/<mint>?depth=full" \
  -H "Authorization: Bearer $SENTINELLAYER_API_KEY"

Read your usage

GET/api/v1/usageAny valid key

Free to call. Credits left in dollars, this month's call count and the price of each call.

curl
curl -s https://sentinellayer.tech/api/v1/usage \
  -H "Authorization: Bearer $SENTINELLAYER_API_KEY"
json200 response
{
  "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.

No red flags found
"verdict": "safe"

None of the checks found a problem in the simulation or the lists. Never a guarantee: the reasons list what was checked.

Flagged
"verdict": "warn"

Sign only if every finding is expected: an unverified program, a first-time recipient, an approval, or a simulation that did not finish.

Denied
"verdict": "block"

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.

FieldWhat it holds
idCheck id, for sharing and support.
kindtransaction, address or token: how the input was read.
verdictsafe, warn or block (No red flags found, Flagged, Denied on the site). Fixed meaning, see above.
headlineOne 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).
simulationTransactions only: ok and error, signer, deltas (each asset leaving or entering, raw and formatted, with counterparty), solAtRiskLamports, programs (known, flagged), logs.
subjectAddresses and mints: the address, a label when we know it, and its type (wallet, token, program).
checkedAtWhen the check ran (ISO 8601, UTC).
msHow 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

StatuserrorWhen
400bad_input, bad_signer, bad_mintThe body or path is not a transaction, address or mint.
401api_key_required, api_key_invalidNo Bearer key, or the key is unknown or revoked.
400bad_depthdepth is not basic, full, cluster or case.
402no_creditsThe key's wallet has fewer credits than the call costs. The body carries priceUsd and balanceUsd.
429rate_limitedOver 5 requests a second for this key. Honor Retry-After.
503api_paused, checks_pausedPaused by the operators for a moment. Retry shortly.
502verdict_failedThe coin verdict could not be built. The call was refunded.
500internalOur side. Retry with backoff.

Every error is JSON with a stable error code and a plain message:

json402 no_credits
{
  "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.

tsguard a signature
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;
  }
}
tscoin verdict and usage
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 }
MethodCallsReturns
check(input, { signer? })POST /api/v1/checkCheckResult
scanCoin(mint)GET /api/v1/coin/{mint}The basic coin verdict
usage()GET /api/v1/usageUsage

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.