message. Responses with
status 403 also carry a machine-readable code.
Branch on code, not on message. Messages are prose written for a person
reading a stack trace, and they get reworded. code is API surface and is
treated as such.
A 403 is not an authentication failure
This trips people up, so it is worth stating plainly: a bad, missing, expired, or revoked API key returns401. If you got a 403, your credentials were
accepted. Something else stopped the request.
403 covers several unrelated situations:
policy_denied is Declaw working
The other codes are problems. policy_denied is the product doing its job — an
agent attempted something the operator forbade, and it was stopped.
That distinction matters for how you handle it. A policy_denied is usually not
an error in your integration; it is an event your users may want to see:
code too — it is applied as the response leaves
the host, so you get the same envelope regardless of which layer made the
decision.
Denials are audited
Most policy denials are recorded in the audit trail, so you can reconstruct what was blocked without parsing error strings. Command, PTY, and stdio denials also carry the compliance control IDs that fired — both in the audit entry and on theX-Declaw-Policy-Controls response header — so you can see which governance
control each denial satisfied.
Not every denial produces an audit entry today; a request refused because the
sandbox has public traffic disabled, for example, does not.
See Audit logging for retrieval.
Other statuses
Revoking an API key takes effect within about 60 seconds — credentials are
cached briefly. Plan for that window if key revocation is part of your incident
response.