Smart Contract Scanner API
API paths that contain tenant keep that word for compatibility. In the product it means your workspace.
Use this API when your team wants a repeatable, workspace-scoped way to review EVM smart contracts before approving, funding, trading, integrating, or escalating them.
This page is written for customers and integrators. If you only remember one thing, remember this:
A Smart contract review can return either an immediate cached final result or a queued review that you poll until the final result is ready.
What this API is for
Use the Contract Scanner API to answer questions like:
- "Should our treasury interact with this contract?"
- "Is this token controlled, upgradeable, or opaque?"
- "Does this contract have admin, proxy, or token-control risk we should understand first?"
- "Can we export a stable record of what Dralvia saw at the time of review?"
Authentication
- Use a workspace API key from
https://dralvia.tech/#/api-keys. - Preferred header:
Authorization: Api-Key <key> - Legacy header:
X-API-KEY: <key> - Optional bearer token:
Authorization: Bearer <token>if your environment already uses Dralvia session auth. - Optional
X-Actorheader if you want to label automation runs.
Base URL
For workspace use:
https://dralvia.tech/api/tenant
POST /contractscan
Submit a contract address and chain name.
Request body
{
"address": "0x1234567890abcdef1234567890abcdef12345678",
"chain": "Ethereum"
}
What can happen next
The response depends on whether Dralvia already has a recent final result.
Expected timing:
- cached final result: usually immediate
- fresh queued review: usually
~1-2 minuteswhen warm and uncontended - fresh deep review under real queue or service pressure:
~2-5 minutesis still normal
Case 1: recent final result exists
If Dralvia already has a recent final result for the same (address, chain) pair, it returns the final review immediately with 200.
Typical shape:
{
"address": "0x1234...5678",
"chain": "Ethereum",
"risk_score": 72,
"risk_level": "Avoid",
"summary": "Proxy shell is upgradeable and active admin control remains in place.",
"decision_model_version": "web3-decision-v1",
"review_state": {
"state": "final_result",
"label": "Final result",
"headline": "Final review ready",
"message": "The contract review is complete and ready for a tenant decision."
},
"finality": {
"is_final": true
},
"decision_bundle": {
"contract_posture": { "score": 72, "band": "high" },
"action_risk": { "score": 81, "band": "high" },
"confidence": { "score": 67, "band": "medium" },
"transparency": { "score": 46, "band": "partial", "confidence_label": "low" },
"final_decision": { "recommended_action": "review", "severity": "high" }
},
"transparency": {
"score": 46,
"confidence": "low",
"abi_verified": false,
"requires_deeper_review": true
},
"evidencepack": { "...": "..." },
"transparency_index": 99,
"scanned_at": "2026-03-28T09:15:00Z"
}
Case 2: fresh review is needed
If a fresh review is needed, Dralvia queues the work and returns 202.
Typical shape:
{
"scan_id": 1842,
"address": "0x1234...5678",
"chain": "Ethereum",
"status": "queued",
"queued_at": "2026-03-28T09:15:00Z",
"updated_at": "2026-03-28T09:15:00Z",
"queue_age_seconds": 0,
"review_state": {
"state": "queued",
"label": "Queued",
"headline": "Review queued",
"message": "Dralvia accepted the contract review and is waiting to start the deeper on-chain checks."
},
"finality": {
"is_final": false,
"recommended_wait_seconds": 90
},
"workflow": {
"mode": "async",
"surface": "web3_contract",
"selection_label": "Full contract review",
"stages": [
{ "stage": "queue", "status": "queued" },
{ "stage": "contract_review", "status": "pending" }
]
},
"analysis": {
"profile": "full",
"requested_profile": "full",
"requested_mode": "full",
"result_state": "pending",
"selection_label": "Full contract review"
}
}
When you receive 202, your next step is to poll the status endpoint.
Queue behavior
- Full contract reviews are asynchronous by design.
- Contract reviews enter Dralvia's interactive async lane, and queue workers now consume that lane directly instead of leaving it stranded behind default backlog listeners.
- A healthy queue usually transitions from
queuedtorunningquickly, but deeper reviews can still take a few minutes when workers are busy. - Queued contract reviews run through Dralvia's isolated
web3-analysisservice instead of the API worker doing unbounded local review work. If the deeper service path cannot finish, the job now fails cleanly instead of sitting inrunningforever. - If a queued job becomes stale, Dralvia now re-dispatches it from the worker side and also when the same review is requested again or when the status endpoint is polled. That stale recovery consumes the same bounded retry budget as the queue worker, so orphaned jobs cannot loop forever.
- Guest clients only reuse global cached contract results. Workspace clients first reuse their own fresh cached result, then safely fall back to a fresh global cached result for the same
(address, chain)pair. This keeps public-chain reviews fast without exposing workspace-scoped overlays to guests. - If the same workspace submits the same contract while an async review is already
queuedorrunning, Dralvia reuses the activescan_idinstead of intentionally creating a second deep review for that same workspace/address/chain. - Internal analyst-review candidate logging is best-effort. If that internal sidecar path is unavailable, the contract review still completes and returns its normal final result.
GET /contractscan_status/<scan_id>
Poll the queued review until it reaches a final state.
Authentication during long polls
Because a deep review can run for several minutes, your client must present a credential that remains valid for the entire poll window. Recommended:
- Programmatic integrations: send your workspace
X-API-KEY(orAuthorization: Api-Key …) on every poll. API keys do not expire mid-scan. - Interactive browser clients (for example the Dralvia dashboard): keep the signed-in session fresh before polling, or attach a still-valid workspace API key as a fallback. An expired session can be rejected with
401 Unauthorized.
If your polling loop receives a 401 on a previously-working scan, obtain a fresh token (or use an API key) and retry the same scan_id: the review continues server-side regardless of client auth hiccups.
Server-side recovery sweep
Dralvia workers run a periodic sweep that reclaims contract-scan jobs left in queued or running past the staleness threshold and re-dispatches them. This means a client that disconnects mid-review (closed tab, dropped network, paused polling) can resume progress simply by polling the same scan_id again. The server does not require the client to stay attached for recovery to happen.
While the review is actively running, workers also heartbeat the claimed job so the stale sweep does not falsely requeue a healthy deep review just because it is taking longer than the fast path.
Terminal states remain terminal: done, failed, and dead_letter are never re-dispatched.
If the isolated smart contract review hits a deterministic sandbox budget failure such as wall_clock_budget_exceeded, Dralvia now returns a terminal dead_letter outcome instead of repeatedly requeueing the same expensive contract review.
A slow start is a different outcome and is deliberately not terminal. If the isolated review process does not finish starting up in time, the request returns HTTP 503 with:
{
"error": "sandbox_process_startup_timeout",
"detail": "sandbox subprocess startup did not complete in time (61000>60000 ms); the job never ran",
"startup": {"code": "sandbox_process_startup_timeout", "limit": 60000, "observed": 61000, "metric": "startup_ms"}
}
The review never began, so nothing was learned about the contract and retrying is
the correct response. This is distinct from wall_clock_budget_exceeded (HTTP 422),
which means the review ran and took too long.
Example
curl -H "Authorization: Api-Key $DRALVIA_API_KEY" \
"https://dralvia.tech/api/tenant/contractscan_status/1842"
Typical in-progress response
{
"scan_id": 1842,
"address": "0x1234...5678",
"chain": "Ethereum",
"status": "running",
"queued_at": "2026-03-28T09:15:00Z",
"updated_at": "2026-03-28T09:15:08Z",
"review_state": {
"state": "deep_review_in_progress",
"label": "Deep review in progress",
"headline": "Deep review in progress",
"message": "Dralvia is still reviewing bytecode, control paths, and on-chain activity for this contract."
},
"finality": {
"is_final": false,
"recommended_wait_seconds": 90
},
"workflow": {
"mode": "async",
"surface": "web3_contract",
"selection_label": "Full contract review",
"stages": [
{ "stage": "queue", "status": "completed" },
{
"stage": "contract_review",
"status": "running",
"detail": "Dralvia is still reviewing bytecode, control surfaces, and on-chain activity for this contract."
}
]
},
"analysis": {
"profile": "full",
"requested_profile": "full",
"requested_mode": "full",
"result_state": "pending",
"selection_label": "Full contract review"
}
}
If the client keeps polling and the review still does not complete in a reasonable window for your environment, keep polling the same scan_id and surface the last review_state to the operator. Do not impose a fixed local timeout and convert an in-progress review into a client-side failure.
Dralvia still uses the status call as a recovery point for stranded queued jobs, but worker-side stale recovery also runs independently so the review can continue even if the browser tab closes for a while.
If a deeper review cannot complete through the isolated smart contract service, expect a bounded degraded or failed outcome instead of indefinite polling. Client integrations should treat failed and dead_letter as terminal states and surface the returned message directly.
Typical completed response
When the review is done, status becomes done and the response includes:
- a compact
resultsummary for quick polling - the full final payload in
result_payload review_stateandfinalityso your client can tell whether the review is still in progress or fully complete
That result_payload is the same final contract review you would have received directly in a cached 200 response.
How to read the final result
You do not need to memorize every field. Start with these.
1. summary
This is the fastest human-readable explanation of what Dralvia found.
2. risk_score and risk_level
These remain useful for dashboards, alerts, exports, and quick triage.
3. decision_bundle
This is the most important newer structure for serious usage.
It separates:
contract_posture: the contract’s own risk postureaction_risk: the risk of interacting with itconfidence: how strong the evidence istransparency: how much of the logic was visiblefinal_decision: what Dralvia recommends next
In practice, this helps you avoid overreacting to low transparency alone while still escalating opaque contracts that keep meaningful control surfaces.
The scales do not all point the same way
Every dimension scores 0-100, but two of them rise with danger and two rise
with what Dralvia could see. Read band with its direction, never on its own:
| Dimension | score rises with | band values (low to high score) |
|---|---|---|
contract_posture | risk | minimal, guarded, elevated, high, severe |
action_risk | risk | minimal, guarded, elevated, high, severe |
confidence | certainty | low, medium, high |
transparency | visibility | opaque, limited, partial, substantial, full |
transparency.band previously reused the risk vocabulary, so a fully
transparent contract (score: 100) was reported as band: "severe" and an
opaque one as band: "minimal" -- inverted. It now uses the visibility
vocabulary above. transparency.score and transparency.confidence_label are
unchanged. If you branch on transparency.band, update those branches.
confidence also carries uncertainty_level. It is the confidence score run
through the same thresholds, inverted (high confidence == low uncertainty),
so it adds no information beyond band. It is kept for compatibility, and the
result page no longer prints both.
These are the contract scanner's scales. A URL result's risk_score is a
different scale, and the two numbers are not comparable.
4. transparency
This section explains whether Dralvia had:
- verified source
- readable ABI
- bytecode-only visibility
- enough evidence for a strong decision
If transparency is low, that does not automatically mean the contract is malicious. It means the workspace should weigh uncertainty more carefully.
5. evidencepack and transparency_index
Use these when another team, ticket, or auditor needs the same decision context later.
6. simulation_summary
Wallet-risk previews can include simulation_summary when transaction evidence is available.
Typical shape:
{
"schema_version": "pre-sign-simulation-v1",
"status": "simulated",
"degraded_reason": null,
"impact": "assets_leave_wallet",
"balance_deltas": [
{
"asset_type": "native",
"direction": "outflow",
"from": "0xWallet",
"to": "0xContract",
"amount": { "raw": "10000000000000000", "known": true },
"immediate": true,
"delegated": false,
"source": "decoded_call",
"confidence": "high"
}
],
"approval_changes": [
{
"kind": "erc20_approval",
"spender": "0xSpender",
"amount": { "raw": "115792089237316195423570985008687907853269984665640564039457584007913129639935", "known": true },
"unlimited": true,
"source": "decoded_call",
"confidence": "high"
}
],
"totals": {
"balance_delta_count": 1,
"approval_change_count": 1,
"immediate_outflow_count": 1,
"delegated_movement_count": 0,
"unlimited_approval_count": 1,
"operator_change_count": 0
},
"unknowns": [],
"explanations": [
{
"kind": "asset_leaves_wallet",
"severity": "high",
"title": "Assets can leave the wallet",
"detail": "The action can move 10000000000000000 native value to 0xContract.",
"source": "decoded_call",
"confidence": "high"
},
{
"kind": "approval_expanded",
"severity": "high",
"title": "Spending approval changes",
"detail": "Spender 0xSpender can receive unlimited spending authority.",
"source": "decoded_call",
"confidence": "high"
}
]
}
status can be simulated, decoded_only, or degraded. simulated means Dralvia completed the single-call provider check and the response can include block_number, chain_id, result_hash, result_bytes, timeout_seconds, and duration_ms inside the simulation metadata. decoded_only means the preview used calldata decoding without a provider-backed state check. A degraded result can still be useful, but clients should not present it as complete proof. Show the degraded_reason, preserve the unknowns, and require human review for sensitive approvals. Degraded reasons can include provider_timeout, provider_unavailable, unsupported_chain, reverted_call, missing_state, opaque_delegatecall, and provider_error.
Use explanations for user-facing copy. The stable kind values include asset_leaves_wallet, asset_enters_wallet, delegated_asset_movement, approval_changed, approval_expanded, operator_rights_changed, ownership_rights_changed, and unknown_state_change.
The Dralvia workspace renders this object as a Simulation Summary panel in the wallet-risk Full Review. API clients should follow the same pattern: show status and degraded reason first, then the practical impact, counters, explanations, balance deltas, approval changes, and unresolved unknowns.
When a saved ticket already carries a transaction graph or pre-sign preview, client UIs should treat that stored payload as a ready transaction readout. The reviewer should be able to move from page context to transaction detail to full review without rerunning simulation just to see evidence that was already captured.
When a wallet action wraps calls inside a recoverable bytes[] batch or a targeted wrapper with a target address plus inner call data, the transaction graph can include nested_calls. Wallet-risk preview insights mirror those records as tx_nested_calls so saved previews can render the same grouped story without re-reading the raw graph. Each nested call records its selector, decoded signature when known, decode source, capabilities, decoded arguments, target contract when available, and any approval or asset movement Dralvia can recover. Clients should show nested approvals and transfers as part of the same wallet action, not as separate unrelated findings.
EvidencePack (Dralvia's exportable evidence report) exports that include a pre-sign simulation summary also include signed metadata.pre_sign_simulation_export. Use it when a ticket, auditor, or downstream workflow needs to replay the review context. The field records the simulation status, degraded reason, impact, fallback path, replay input, provider mode, chain ID, block number, result hash, timeout, duration, and nested-call count. Client UIs should display these signed fields near the review summary when they are present so reviewers can validate which chain state and fallback path supported the exported decision.
Dralvia validates the wallet-risk path against routine swaps, drainer-style approvals, approval-only flows, reverted calls, and provider degradation so clients can treat these cases consistently in API automation.
7. approval_graph and tx_approval_graph
Transaction graph insights can include approval_graph when Dralvia decodes approval or operator evidence. Pre-sign preview insights mirror the same object as tx_approval_graph so saved previews can expose the normalized path without requiring clients to parse the raw transaction graph.
Typical shape:
{
"schema_version": "web3-approval-graph-v1",
"nodes": [
{
"id": "owner:0xwallet",
"role": "owner",
"address": "0xWallet"
},
{
"id": "asset_contract:0xtoken",
"role": "asset_contract",
"address": "0xToken"
},
{
"id": "effective_spender:0xspender",
"role": "effective_spender",
"address": "0xSpender",
"family": "erc20_approval"
}
],
"edges": [
{
"source": "owner:0xwallet",
"target": "effective_spender:0xspender",
"type": "allowance_authority",
"asset_contract": "0xToken",
"path_id": "approval:0",
"scope": {
"type": "limited",
"amount": 42
}
}
],
"paths": [
{
"id": "approval:0",
"path_type": "allowance",
"family": "erc20_approval",
"asset_contract": "0xToken",
"owner": "0xWallet",
"effective_spender": "0xSpender",
"scope": {
"type": "limited",
"amount": 42
},
"source": "erc20_approval",
"confidence": "high",
"trace": {
"path_type": "nested_call",
"wrapper_signature": "multicall(bytes[])",
"nested_index": 0,
"nested_signature": "approve(address,uint256)",
"hops": [
{
"role": "wrapper",
"signature": "multicall(bytes[])"
},
{
"role": "inner_call",
"index": 0,
"signature": "approve(address,uint256)",
"decode_source": "selector_fallback"
}
]
}
}
],
"summary": {
"approval_path_count": 1,
"operator_path_count": 0,
"unlimited_path_count": 0,
"has_unknown_spender": false
}
}
path_type can be allowance, permit, permit2_allowance, permit2_transfer, or operator_grant. scope.type can be limited, unlimited, toggle, delegated_transfer, operator, or unknown. Permit2 transfer paths can also include recipient and a delegated-transfer amount inside scope.
Use effective_spender for the final spender or operator Dralvia could identify from the decoded evidence. For Permit2 single-approval payloads, Dralvia can recover the tuple spender, approved token, amount, expiration, nonce, and deadline when the calldata is complete enough to decode. Permit2 batch approval payloads can produce one approval path per recovered token scope, with the shared spender and deadline copied onto each path. For Permit2 transfer payloads, Dralvia can recover the approved token, owner, recipient, requested amount, nonce, and deadline. Some Permit2 transfer shapes do not encode the spender directly, so summary.has_unknown_spender can remain true even when the token movement details are recovered. If a wallet action wraps approval evidence inside a recoverable batch, router-style target call, or proxy call with inner data, a path can include trace with wrapper, target-contract, and inner-call hops. Targeted wrappers also let the graph use the decoded target as the approved asset contract when that target receives the inner approval call. If summary.has_unknown_spender is true, treat the graph as partial and keep the lower-level decoded call evidence available for review. The graph is omitted when no approval or operator path is decoded.
Clients that need a compact review row can use approval_path_summary in transaction insights; pre-sign previews mirror it as tx_approval_path_summary. Each summary path shows the approval target, effective spender when known, approved asset, scope, duration, blast-radius level, and confidence.
Typical shape:
{
"schema_version": "web3-approval-path-summary-v1",
"summary": {
"approval_path_count": 1,
"high_or_critical_path_count": 1,
"unknown_spender_count": 0
},
"paths": [
{
"approval_target": "0xSpender",
"effective_spender": "0xSpender",
"approved_asset": "0xToken",
"scope": { "type": "unlimited" },
"duration": { "type": "not_recorded", "known": false },
"blast_radius": { "level": "critical", "score": 88 },
"confidence": "high"
}
]
}
Use this summary for UI rows and ticket handoffs. Use the full approval_graph, approval_blast_radius_review, and approval_revocation_guidance objects when a reviewer needs edge details, trace hops, evidence gaps, or follow-up limitations.
Standard token approvals can also include approval_safety_review in transaction insights, and pre-sign previews mirror it as tx_approval_safety_review. This review helps clients identify nonzero approval changes that did not include a same-batch zero reset for the same spender.
Typical shape:
{
"schema_version": "web3-approval-safety-review-v1",
"risk_level": "medium",
"summary": {
"approval_path_count": 1,
"reset_zero_count": 0,
"nonzero_approval_count": 1,
"reset_bypass_count": 1,
"reset_protected_count": 0
},
"indicators": [
{
"id": "approval_reset_bypass_possible",
"severity": "medium",
"detail": "Nonzero ERC20 approval was decoded without a same-batch zero reset for the same spender."
}
]
}
If a recoverable batch first sets the same spender allowance to 0 and then sets the intended amount, reset_protected_count increases and no reset-bypass indicator is added for that second approval. If the reset is not visible in the reviewed transaction, treat approval_reset_bypass_possible as a review signal. It does not prove the previous allowance was nonzero; it means the safer reset pattern was not observed in the same signing flow.
Approval paths can also include approval_blast_radius_review in transaction insights, and pre-sign previews mirror it as tx_approval_blast_radius_review. This review estimates how broad the decoded approval or operator path is, using the evidence Dralvia can prove from the wallet action.
Typical shape:
{
"schema_version": "web3-approval-blast-radius-v1",
"risk_level": "high",
"summary": {
"blast_radius_path_count": 1,
"critical_path_count": 1,
"unlimited_path_count": 1,
"operator_path_count": 0,
"collection_exposure_count": 0,
"unknown_value_count": 1
},
"paths": [
{
"level": "critical",
"score": 88,
"token_type": "erc20",
"asset_contract": "0xToken",
"effective_spender": "0xSpender",
"allowance_size": {
"kind": "unlimited"
},
"wallet_collection_exposure": {
"scope": "token_scope",
"known": false
},
"value_context": {
"token_value_known": false,
"existing_holdings_known": false,
"evidence_gaps": ["token_value", "existing_wallet_holdings"]
},
"factors": ["unlimited_allowance"]
}
],
"indicators": [
{
"id": "approval_blast_radius_high",
"severity": "high",
"detail": "Decoded approval path can expose a broad asset scope or high-impact delegated-spend surface."
}
]
}
Use paths[].level and paths[].factors to explain why the approval is broad. Dralvia considers token type, allowance size, operator or collection-wide scope, delegated movement, spender resolution, counterparty review, and contract control-surface signals that are visible in the transaction graph. If token value or current wallet holdings are not available in the evidence, the review marks them as evidence gaps instead of guessing. A high or medium blast-radius review adds approval_blast_radius to risk_packs; high blast-radius paths can also add approval_blast_radius_high to warnings.
Risky approval paths can also include approval_revocation_guidance in transaction insights, and pre-sign previews mirror it as tx_approval_revocation_guidance. This object gives generic follow-up data for reducing or revoking decoded spender authority. It does not promise that a specific wallet, marketplace, or approval-management tool supports the action.
Typical shape:
{
"schema_version": "web3-approval-revocation-guidance-v1",
"summary": {
"revocation_path_count": 1,
"allowance_reset_candidate_count": 1,
"operator_revoke_candidate_count": 0,
"permit2_allowance_candidate_count": 0,
"signature_scope_review_count": 0
},
"paths": [
{
"action_type": "set_erc20_allowance_to_zero",
"method_hint": "approve(spender,0)",
"wallet_specific": false,
"persistent_authority_known": true,
"asset_contract": "0xToken",
"effective_spender": "0xSpender",
"token_type": "erc20",
"limitations": [
"wallet-specific support is not assumed",
"verify the chain, asset contract, spender, and decoded method before signing a revocation transaction",
"this guidance does not prove the approval has already been revoked"
]
}
]
}
Use paths[].action_type to decide the reviewer workflow. Standard token allowances can recommend setting an allowance to zero. Collection-wide operator paths can recommend revoking operator approval. Permit2 allowance paths can recommend using the correct chain approval manager to reduce or expire the allowance. Delegated transfer signatures are treated as signature-scope review because they may not represent persistent allowance state. Always verify the current on-chain approval state before and after any revocation attempt.
Permit-style approvals can also include permit_replay_review in transaction insights, and pre-sign previews mirror it as tx_permit_replay_review. This review summarizes replay-related permit evidence without requiring the client to recalculate timestamps or nonce visibility.
For wallet-action simulation requests, clients can optionally include typed_data_domain when they have the signed-message domain from the wallet request. Dralvia compares chainId and verifyingContract against the reviewed transaction chain and permit contract. If the domain object is not provided, Dralvia keeps the domain binding as calldata-only ambiguity instead of claiming proof it does not have.
Example simulation body with typed-data domain evidence:
{
"chain": "Ethereum",
"to": "0x000000000022d473030f116ddee9f6b43ac78ba3",
"data": "0x...",
"from": "0x2222222222222222222222222222222222222222",
"typed_data_domain": {
"chainId": 1,
"verifyingContract": "0x000000000022d473030f116ddee9f6b43ac78ba3"
}
}
Typical shape:
{
"schema_version": "web3-permit-replay-review-v1",
"risk_level": "high",
"summary": {
"permit_path_count": 1,
"expired_deadline_count": 1,
"expired_expiration_count": 1,
"nonce_visible_count": 1,
"domain_ambiguous_count": 1,
"domain_verified_count": 0,
"domain_mismatch_count": 0,
"cross_chain_replay_count": 0
},
"indicators": [
{
"id": "expired_deadline",
"severity": "high",
"detail": "Permit signature deadline is already expired."
},
{
"id": "typed_data_domain_unverified",
"severity": "low",
"detail": "Typed-data domain and chain binding cannot be fully proven from transaction calldata alone."
}
]
}
Review risk_level, then inspect indicators. High indicators include expired permit deadlines, expired Permit2 allowance expirations, typed-data chain mismatch, verifying-contract mismatch, and cross-chain replay risk. Medium indicators include missing deadlines, missing Permit2 expirations, nonce ambiguity, missing typed-data chain id, or missing typed-data verifying contract. Low typed-data indicators mean the transaction calldata alone cannot prove every domain or chain binding detail.
A high or medium replay review adds permit_replay_risk to risk_packs and can add warnings such as permit_deadline_expired, permit_expiration_expired, permit_deadline_missing, permit_nonce_ambiguous, permit_domain_chain_mismatch, permit_domain_contract_mismatch, permit_domain_chain_missing, or permit_domain_contract_missing.
Common workspace questions
Why did my scan return 202 instead of a score?
Because Dralvia needed a fresh review and queued it instead of forcing one long fragile HTTP request.
Does that mean the scan failed?
No. 202 means the review was accepted and is still running. Poll the status endpoint until status becomes done or failed.
Why can two contracts with similar scores still need different actions?
Because Dralvia separates:
- posture
- action risk
- confidence
- transparency
Two contracts can end up with similar top-line scores for very different reasons.
What if the contract is unverified?
Dralvia still reviews bytecode, selectors, proxy behavior, admin surfaces, token behavior, and related context. Unverified source lowers transparency, but it does not automatically force a malicious verdict.
Error responses
Common cases:
400- missing address
- missing chain
- invalid address
- unsupported chain configuration
401- workspace context missing or invalid
429- plan quota reached
- smart contract rate limit reached
- queue overloaded
503- queue unavailable
- upstream simulation/review dependency temporarily unavailable
500- unexpected internal error
Best practices for integrations
- Treat
202as normal for fresh reviews. - Poll the status endpoint rather than retrying
POST /contractscanin a loop. - Use the final payload, not only the compact polling summary, when storing evidence.
- Preserve
decision_model_versionif you archive results for audit or analytics. - Store
address,chain,scanned_at,summary,risk_score,final_decision, andtransparency_indextogether.
CLI and automation
You can also trigger contract reviews from automation with the Dralvia API or the Python SDK.
Example (REST API):
curl -sS "https://dralvia.tech/api/tenant/contract/scan" \
-H "X-API-KEY: $DRALVIA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"contract": "0x1234...5678", "chain": "Ethereum"}'