Explained decisions · early preview
Why was it denied?
Every refusal carries a reason code. Each code below says what it means and how the agent or the site can fix it. Default deny never loosens: these hints tell you how to ask properly, not how to get around a rule. The same text is in the explain field of every refusal from /v1/verify and at /v1/explain.
action.forbiddenoperator can usually fixAction explicitly forbidden
A forbid rule names this action.
- Choose a different action.
- nothing to change on your side
action.not_allowedoperator can usually fixAction not in the license
The license does not list this action.
- Ask for a license that includes this action.
- If the action should be allowed, add it to the profile's allowed_actions.
agent.frozenoperator can usually fixPassport frozen
The operator froze this agent. Nothing is allowed until it is unfrozen.
- Ask your operator to unfreeze the agent.
- nothing to change on your side
agent.revokedoperator can usually fixPassport revoked
This passport was revoked. The id is permanent and cannot be reused.
- Register a new agent; a revoked passport cannot be restored.
- nothing to change on your side
agent.unknownagent can usually fixUnknown agent
The Signature-Agent value does not match any registered passport.
- Register a passport first (POST /v1/agents) or check the Signature-Agent URL for typos.
- nothing to change on your side
approval.action_mismatchhuman can usually fixApproval is for a different action
An approval covers one exact action only.
- Get an approval for exactly this license, amount and counterparty.
- nothing to change on your side
approval.always_for_actionshuman can usually fixThis action always needs approval
The rules list this action as always needing a person.
- Ask the owner to approve this exact action.
- nothing to change on your side
approval.cumulative_abovehuman can usually fixRunning total needs approval
Purchases in the period add up to more than the approval line, so a person must approve.
- Ask the owner to approve this purchase.
- Raise profile.approval.cumulative_above if it triggers too often.
approval.expiredhuman can usually fixApproval expired
The approval window ended.
- Request a fresh approval.
- nothing to change on your side
approval.invalidhuman can usually fixApproval not valid
The approval was not signed by the operator's active key.
- Have the operator sign again.
- nothing to change on your side
approval.lifetime_too_longhuman can usually fixApproval window too long
Approvals may only live a short time.
- Sign with a shorter expiry (see max_age_s).
- nothing to change on your side
approval.presence_requiredhuman can usually fixPasskey presence required
This license or step-up needs a fresh passkey confirmation from the human.
- Complete the passkey presence flow and send its token with the approval.
- nothing to change on your side
approval.replayedhuman can usually fixApproval already used
Approvals are single use.
- Request a new approval.
- nothing to change on your side
approval.require_presencehuman can usually fixA person must be present
This action needs a fresh passkey presence check by the owner.
- Ask the owner to confirm with their passkey, then retry with the presence token.
- Use profile.risk.require_presence only where you want that friction.
approval.requiredhuman can usually fixA human must approve this
The amount or action crosses an approval threshold (or the risk engine asked for a step-up).
- Show the approval_request to your operator; send the signed approval back with the same request.
- Lower or raise profile.approval.required_above to tune how often this happens.
approval.required_abovehuman can usually fixAmount needs approval
The amount is above the line where a person must approve.
- Ask the owner to approve this exact action.
- Raise profile.approval.required_above if it triggers too often.
audience.mismatchagent can usually fixWrong site
The request or license is for a different origin than the site that is checking it.
- Use a license issued for this site, and send the request to the origin it names.
- nothing to change on your side
content_digest.body_invalidagent can usually fixBody does not match its content-digest
The request body sent differs from the digest the agent signed.
- Compute Content-Digest over the exact bytes you send and sign it.
- Pass the raw, unparsed body text to the checker.
content_digest.body_requiredsite can usually fixBody not forwarded
The signature covers a digest but the site did not forward the body.
- nothing to change on your side
- Pass the raw body text to the checker.
content_digest.mismatchagent can usually fixBody changed in transit
The body the site received does not match the signed digest.
- Send the body you signed, byte for byte.
- Check a proxy is not rewriting the body before the checker sees it.
content_digest.missingagent can usually fixBody digest missing
A request with a body must carry a signed Content-Digest.
- Add Content-Digest (sha-256) and sign it.
- nothing to change on your side
counterparties.allowoperator can usually fixCounterparty not on the allow list
The license limits which merchants or counterparties the agent may deal with, and this one is not listed.
- Ask for a license that names this counterparty.
- nothing to change on your side
counterparties.denyoperator can usually fixCounterparty is blocked
The license or profile explicitly blocks this counterparty.
- Choose a different counterparty.
- Remove it from the deny list only if that is intended.
counterparty.deniedoperator can usually fixCounterparty blocked
The counterparty is on a deny list.
- Do not transact with that counterparty.
- nothing to change on your side
counterparty.missingsite can usually fixCounterparty missing
An allow list exists but the request names no counterparty.
- nothing to change on your side
- Pass intent.counterparty.
counterparty.not_allowedoperator can usually fixCounterparty not on the allow list
Only listed counterparties are permitted.
- Use an allowed counterparty or ask for a wider license.
- nothing to change on your side
delegation.max_depthoperator can usually fixDelegation too deep
The chain of sub-licenses is longer than the parent allows.
- Reduce the delegation depth.
- nothing to change on your side
delegation.not_allowedoperator can usually fixDelegation not allowed
The parent license forbids sub-licenses.
- Ask for a license with delegation enabled.
- nothing to change on your side
environment.action.not_allowedsite can usually fixAction not allowed by the site
The site's rule profile does not allow this action at all.
- This site does not offer that action to agents.
- Add the action to profile.allowed_actions if you want to allow it.
environment.disabledsite can usually fixSite switched off
The site owner turned the environment off (kill switch) or its ownership is contested.
- Retry later; nothing you can change on the agent side.
- Re-enable with POST /v1/environments/:id/enable once it is safe.
environment.operator_level_insufficientoperator can usually fixOwner not verified enough
This site requires a higher verified-owner level (L0 to L3) than your operator has.
- Raise the operator's owner level (domain proof for L1, identity check for L2, passkey for L3).
- Lower profile.min_operator_level if that level is stricter than you need.
environment.ownership_lapsedsite can usually fixSite ownership lapsed
The registry could not re-confirm that the site controls its origin, so it is suspended.
- Retry later.
- Re-publish the ownership challenge and call recheck-ownership.
environment.ownership_unprovensite can usually fixSite ownership not proven
The site has not yet proven control of its origin.
- Retry later.
- Prove control with the DNS TXT record or the .well-known file, then re-check.
environment.spend.not_permittedsite can usually fixSite permits no spending
The site's profile has no spend rule, so any amount is refused.
- This site does not accept agent payments.
- Add profile.spend (currency, per_txn_max, period_max) to allow purchases.
environment.unregisteredsite can usually fixSite not registered
This site has no registered environment, so default deny applies.
- Tell the site owner you need them to register an environment.
- Register the site: POST /v1/environments with your origin and a rule profile.
geo.denyoperator can usually fixCountry is blocked
The request's country is on a deny list.
- Operate from a permitted country.
- Adjust profile.geo.deny_countries if this is too broad.
geo.not_allowedoperator can usually fixCountry not allowed
The request's country is not permitted.
- Operate from an allowed country or ask for a license that includes it.
- Adjust profile.geo if this country should be allowed.
geo.unknownsite can usually fixCountry not provided
A country rule exists but the site did not say where the request came from.
- nothing to change on your side
- Pass intent.country (for example from your CDN geo header).
intent.invalidsite can usually fixIntent invalid
The intent object was malformed.
- nothing to change on your side
- Send intent {action, resource, amount?, country?, counterparty?}.
kb.aud_mismatchagent can usually fixBinding for another site
The key-binding token names a different site.
- Create the key-binding token for this request's origin.
- nothing to change on your side
kb.expiredagent can usually fixKey-binding token too old
The key-binding token is older than two minutes.
- Create it fresh for each request.
- nothing to change on your side
kb.invalidagent can usually fixKey-binding token invalid
The key-binding token's signature did not verify.
- Sign it with the presentation key that the license is bound to.
- nothing to change on your side
kb.missingagent can usually fixKey-binding token missing
A license must be presented with a fresh key-binding token proving possession.
- Append ~<kb-jwt> to the license; the SDK does this for you.
- nothing to change on your side
kb.nonce_mismatchagent can usually fixBinding for another request
The key-binding token's nonce does not match the request signature nonce.
- Use the same nonce in the signature and in the key-binding token.
- nothing to change on your side
kb.sd_hash_mismatchagent can usually fixBinding for another license
The key-binding token does not cover this license.
- Hash the exact license text you present.
- nothing to change on your side
key.expiredoperator can usually fixKey expired
The signing key's grace window ended.
- Sign with the current key.
- nothing to change on your side
key.revokedoperator can usually fixKey revoked
The signing key was revoked.
- Rotate to a new key and sign with it.
- nothing to change on your side
key.unknownagent can usually fixKey not recognised
The signing key is not registered for this agent.
- Register the key or sign with a key listed on the passport.
- nothing to change on your side
license.environment_mismatchoperator can usually fixLicense is for another site
A license only works at the environment it was issued for.
- Request a license for this site's environment id.
- nothing to change on your side
license.expiredoperator can usually fixLicense expired
The license is past its expiry.
- Ask your operator for a renewed license (a new version; the passport stays the same).
- nothing to change on your side
license.key_mismatchoperator can usually fixLicense key mismatch
The key bound in the license is not an active presentation key of this agent.
- Ask for a license bound to your current presentation key (it may have been rotated).
- nothing to change on your side
license.malformedagent can usually fixMalformed license
The Agent-License value could not be parsed.
- Send <license>~<key-binding JWT> exactly as issued.
- nothing to change on your side
license.missingoperator can usually fixNo license presented
Your passport proves who you are, but a passport alone permits nothing here. No Agent-License header came with the request.
- Ask your operator for a license for this exact site (environment).
- Send it in the Agent-License header, bound to this request with a fresh key-binding token.
- If this agent should be allowed, tell its operator which environment id to request a license for.
license.not_yet_validagent can usually fixLicense not valid yet
The license has a start time in the future.
- Wait until the license's not-before time or request one that starts now.
- nothing to change on your side
license.revokedoperator can usually fixLicense revoked
The operator revoked this license.
- Ask for a new license if access should continue.
- nothing to change on your side
license.subject_mismatchagent can usually fixLicense belongs to another agent
The license names a different agent than the one signing.
- Use the license that was issued to this passport.
- nothing to change on your side
license.suspendedoperator can usually fixLicense suspended
The license is paused.
- Ask the operator to resume it.
- nothing to change on your side
license.unknownoperator can usually fixLicense not registered
This license id is not in the registry.
- Register the license (POST /v1/licenses) before presenting it.
- nothing to change on your side
license.unregistered_variantagent can usually fixLicense variant not registered
The presented license text differs from the registered one.
- Present the license exactly as registered.
- nothing to change on your side
nonce.replayedagent can usually fixReplay refused
This exact signed request was already seen.
- Use a new random nonce for every request. Never resend a signed request.
- nothing to change on your side
operator.suspendedoperator can usually fixOperator suspended
The accountable operator used the panic switch or was suspended; every agent under it is refused.
- Ask the operator to resume once the incident is resolved.
- nothing to change on your side
owner.level_insufficientoperator can usually fixLicense needs a higher owner level
The license itself demands a verified-owner level the operator does not have.
- Verify the owner to the level the license names, or ask for a license without that requirement.
- nothing to change on your side
region.outside_licenseoperator can usually fixOutside the license's regions
The license is only valid in other regions.
- Ask for a license that covers this region.
- nothing to change on your side
region.unknownsite can usually fixRegion unknown
The license is limited to regions and the site did not state its region.
- nothing to change on your side
- Set profile.region or pass intent.country.
resource.missingsite can usually fixResource missing
The check needs the target URL.
- nothing to change on your side
- Include intent.resource when calling /v1/verify.
resource.not_allowedoperator can usually fixResource outside scope
The URL is outside the allowed resource patterns.
- Stay inside the patterns the license lists.
- Widen profile.resources if the path should be reachable.
risk.suspendedoperator can usually fixTemporarily held by the risk engine
Unusual activity (bursts, probing, a sudden spend spike or a new region) paused this agent at this site for a short time.
- Stop the burst, check the agent for loops or compromise, and retry after the hold ends.
- Review the signals at /v1/environments/:id/risk; release the hold early if it was a false alarm.
signature.alg_unsupportedagent can usually fixUnsupported algorithm
Only ed25519 request signatures are accepted.
- Use an Ed25519 request key.
- nothing to change on your side
signature.components_missingagent can usually fixSignature does not cover enough
The signature must cover @authority, @method, @path, signature-agent (and the license and body digest when present).
- Add the missing components to Signature-Input.
- nothing to change on your side
signature.expiredagent can usually fixSignature expired
The signature's expiry time has passed.
- Sign right before sending; keep the lifetime at 60 seconds or less.
- nothing to change on your side
signature.invalidagent can usually fixSignature did not verify
The signature does not match the request or the agent's registered key.
- Check you sign the exact method, authority, path and query you send; check the key was not rotated.
- nothing to change on your side
signature.lifetime_invalidagent can usually fixSignature lifetime too long
Signatures may live at most 60 seconds.
- Set expires = created + 60 or less.
- nothing to change on your side
signature.malformedagent can usually fixMalformed signature headers
The signature headers could not be parsed.
- Follow RFC 9421 structured field syntax.
- nothing to change on your side
signature.missingagent can usually fixNo request signature
The request carries no Web Bot Auth signature.
- Sign the request (RFC 9421) with Signature-Agent, Signature-Input and Signature headers; the SDK does this.
- nothing to change on your side
signature.not_yet_validagent can usually fixSignature from the future
The created time is ahead of the registry clock.
- Fix the agent's clock.
- nothing to change on your side
signature.params_missingagent can usually fixSignature parameters missing
created, expires, keyid and nonce are all required.
- Include all four parameters.
- nothing to change on your side
signature_agent.missingagent can usually fixSignature-Agent missing
The Signature-Agent header (your passport URL) is required.
- Send Signature-Agent: "https://<registry>/agents/<id>".
- nothing to change on your side
spend.amount_requiredagent can usually fixAmount required
Payment actions must state an amount.
- Add intent.amount for pay: actions.
- Always send intent.amount for payment actions.
spend.cap_exceededagent can usually fixBudget cap hit
A parallel purchase used the remaining budget first.
- Retry after other reservations settle or roll back.
- nothing to change on your side
spend.currencyoperator can usually fixNarrowed license changes currency
A delegated license may not switch currency.
- Keep the parent's currency when delegating.
- nothing to change on your side
spend.currency_mismatchagent can usually fixWrong currency
The amount's currency differs from the permitted one.
- Use the currency the license names.
- nothing to change on your side
spend.invalid_amountagent can usually fixInvalid amount
The amount must be a positive decimal string with at most 2 decimals.
- Send amounts like "20.00".
- nothing to change on your side
spend.not_granted_by_parentoperator can usually fixParent license grants no spending
A child license cannot spend if its parent could not.
- Ask for a parent license that includes spending.
- nothing to change on your side
spend.not_permittedoperator can usually fixSpending not permitted
The license or the site's profile allows no spending.
- Ask for a license with a spend limit.
- Add profile.spend if spending should be possible here.
spend.per_txn_maxoperator can usually fixDelegated purchase limit is higher than the parent
A delegated license can only narrow limits, never widen them.
- Set a per-purchase limit at or below the parent's.
- nothing to change on your side
spend.per_txn_max_exceededoperator can usually fixAmount over the per-purchase limit
A single purchase may not exceed the limit.
- Reduce the amount or request a higher per-purchase limit.
- Raise profile.spend.per_txn_max if it is too low.
spend.period_maxoperator can usually fixDelegated period limit is higher than the parent
A delegated license can only narrow limits.
- Set a period limit at or below the parent's.
- nothing to change on your side
spend.period_max_exceededagent can usually fixDaily or period limit reached
The agent has spent its limit for this period.
- Wait until the period resets, or ask for a higher limit.
- nothing to change on your side
spend.total_maxoperator can usually fixDelegated total budget is higher than the parent
A delegated license can only narrow limits.
- Set a total budget at or below the parent's.
- nothing to change on your side
spend.total_max_exceededoperator can usually fixLifetime budget used up
The license's total budget is exhausted.
- Ask for a new license with a fresh budget.
- nothing to change on your side
spend.total_max_exceeds_remainingoperator can usually fixDelegated budget exceeds what remains
The parent license does not have that much budget left.
- Delegate no more than the parent's remaining budget.
- nothing to change on your side
window.closedoperator can usually fixTime window closed
The permitted period has ended.
- Ask for a license or profile window that is still open.
- Extend profile.window.not_after.
window.day_not_allowedagent can usually fixNot allowed on this day
The action is outside the permitted days.
- Retry on an allowed day.
- Adjust profile.window.days.
window.daysagent can usually fixNot an allowed day
The license only works on certain days of the week.
- Retry on an allowed day.
- nothing to change on your side
window.hours_localagent can usually fixOutside allowed hours
The license only works during certain local hours.
- Retry during the allowed hours.
- nothing to change on your side
window.hours_not_allowedagent can usually fixOutside allowed hours
The action is outside the permitted hours.
- Retry inside the allowed hours.
- Adjust profile.window.hours_local if the hours are wrong.
window.invalid_tzsite can usually fixBad time zone
The window names a time zone that cannot be read.
- nothing to change on your side
- Use an IANA name like America/Los_Angeles.
window.not_afteroperator can usually fixWindow has ended
The license validity window is over.
- Ask for a new license.
- nothing to change on your side
window.not_beforeagent can usually fixWindow has not started
The license is not valid yet.
- Retry after the license start time.
- nothing to change on your side
window.not_yet_openagent can usually fixTime window not open yet
The permitted period has not started.
- Retry after the window opens.
- nothing to change on your side