The direct answer
Test an AI agent’s API write as a stateful transaction, not as a prompt that eventually returns 200 OK. Before production, prove that disallowed requests stop before execution, a pending or rejected request changes nothing, and approval releases only the exact reviewed request. Also prove that stale data fails safely, duplicate submissions do not create duplicate jobs, callbacks can be authenticated, and an ambiguous provider outcome stops for reconciliation instead of triggering a blind retry.
Use three stages:
- A harmless built-in API to test the agent, policy, approval, execution, and receipt loop without touching an external system.
- A disposable provider staging environment to test a staging-only credential, the provider’s real authentication and network path, conditional-write behavior, rate limits, callbacks, and fault handling.
- A narrow production canary with one method, one path family, one accountable reviewer, and an explicit stop rule.
Do not promote the workflow because its happy path worked once. Promote it only when every safety claim has an observable negative test and retained evidence.
Test the trajectory, not only the final response
An agent can reach the right final state through the wrong route. It might select an overly broad tool, submit the same intent twice, skip a read, discard a version condition, or report success while a job is still waiting for approval. A test that checks only the final JSON object misses those failures.
Google’s production-ready agent guide, published in February and updated in September 2026, recommends unit tests for individual components, analysis of the full decision-and-action trajectory, and staged rollout from sandbox to canary to production. That sequence is especially important for write-enabled agents: the side effect, the evidence, and the recovery branch all matter.
Recent platform changes show the same separation in other automation domains. GitHub’s September 18 release of stage-only npm tokens lets automation stage a package but requires a maintainer with 2FA to release it. This is an architectural analogy, not an ActionDock integration or a universal API standard. The useful principle is that preparing a change and authorizing its release should be separately testable capabilities.
Be precise about what “sandbox” means
The word sandbox often describes two different controls:
- A compute or network sandbox isolates untrusted code and restricts files, processes, credentials, and egress.
- A test-data sandbox provides harmless records and endpoints so a workflow can exercise real control states without changing a business system.
You may need both. This guide focuses on the second: testing a proposed API write from submission through approval and receipt. The separate guide to AI-agent egress control explains why a compute sandbox, destination allowlist, and supervised API gateway solve different problems.
ActionDock’s free sandbox is a test-data environment. It creates a real ActionDock workspace with one fixed connection to a built-in records API. The agent can read test supplier records and propose POST or PATCH requests under /records; the write follows the same ActionDock job and manual-approval path used elsewhere in the product. Nothing reaches an external provider.
That boundary is useful because it lets you test the control plane without confusing a synthetic record with production evidence.
A failure-first test matrix for agent writes
Write the expected evidence before running the test. “The agent behaved” is not evidence; a job state, policy decision, unchanged readback, provider response, signed callback, or event record is.
| Case | Test | Pass condition | Best environment |
|---|---|---|---|
| Disallowed method or path | Ask the agent to submit a request outside the configured scope | The request is denied before provider execution; the target remains unchanged | Built-in sandbox and provider staging |
| Pending approval | Submit an allowed write, but take no owner action | Job remains awaiting_approval; a fresh read shows no mutation |
Built-in sandbox |
| Rejection | Have the signed-in owner reject the exact proposal | Job becomes rejected; readback is unchanged |
Built-in sandbox |
| Stale preview | Edit the connection policy after the proposal is created | The old preview cannot release a request under the changed configuration | ActionDock test workspace |
| Duplicate submission | Repeat the same logical submission with the same idempotency key and payload | The client gets the existing ActionDock job rather than a second job | Built-in sandbox |
| Current version | Read a record, preserve its strong ETag, and submit the write with If-Match |
The approved write succeeds and a post-read returns the intended state, with a new validator when the provider contract advances it | Built-in sandbox and provider staging |
| Stale version | Prepare two writes from the same version, approve one, then release the other | The second write fails under the provider’s documented precondition contract and is not retried automatically | Built-in sandbox and provider staging |
| Callback replay | Deliver the same authenticated terminal delivery more than once | Signature and timestamp checks pass, while an atomic claim on X-ActionDock-Delivery prevents duplicate downstream work |
Callback-receiver staging |
| Response lost after commit | Make the staging provider apply a write and then drop or delay the response | Workflow records execution_unknown, ActionDock performs no automatic provider retry, and the client submits nothing further until authoritative readback |
Fault-injectable provider staging |
| Bypass path | Try the agent’s direct provider credential, browser session, or alternate connector | The route is unavailable or separately restricted; otherwise the supervised path is optional | Architecture and access review |
The callback-replay and lost-response cases cannot be proven by a polished demo. Callback replay needs a receiver you control. An unknown-outcome test needs a provider or proxy that can commit a request and then withhold the response. ActionDock’s built-in records API does not offer that fault-injection mode, so do not claim the free sandbox proves it.
AWS’s September 17 walkthrough for defense-in-depth authorization on MCP tools demonstrates a related testing discipline: prepare users with different roles, then validate allowed and restricted paths independently. The implementation is AWS-specific, but the lesson transfers—an authorization test suite needs identities and requests that should fail, not only an administrator who should succeed.
Run the first loop in the ActionDock sandbox
The core loop is a rejection followed by an approved conditional write. It proves more than a single happy-path run and leaves clear before-and-after evidence. A stale-version conflict is the next extension.
1. Create the isolated workspace
Open the ActionDock sandbox and request a sign-in link. It requires an email address and no card. The workspace has one fixed Sandbox records API connection, a one-off allowance of about 200 standard actions, and no monthly reset.
The connection is intentionally constrained to the built-in records service. You cannot repoint it to your own destination or add another connection. This is not a free production plan.
2. Connect the agent without giving it the target credential
Create a workspace API key in the dashboard and connect an MCP client to https://actiondock.app/mcp, following the MCP setup. The agent can list the connection and learn its allowed methods and path scope. It does not receive the records API credential.
Keep the agent’s instructions narrow: choose one existing test record, describe the intended field change, and require a read before any proposal. Do not ask it to “clean up all suppliers” or infer a batch policy from natural language.
3. Read first and keep the validator
Call integration.fetch for one record under /records. Save the returned strong quoted ETag with the representation used to prepare the change.
For an API that enforces conditional writes, this connects the proposal to the version the agent actually examined. The full ETag and If-Match guide explains the provider-specific limits.
4. Submit, observe, and reject
Call integration.execute with the exact method, path, small JSON body, the quoted ETag in input.ifMatch, and a stable idempotency key for this logical proposal. The expected result is awaiting_approval, not success.
Before reviewing it, read the record again. It must be unchanged. Then sign in as the workspace owner, compare the resolved target, method, body, connection version, and If-Match value, and reject the proposal. Wait for the terminal state and read the record once more. It must still be unchanged.
This test catches two dangerous client behaviors: treating awaiting_approval as completion and continuing the workflow or submitting another write after an explicit rejection. Read how exact human approval works before automating either branch.
5. Submit a fresh proposal and approve it
Read the record again, build a fresh proposal from the current representation, and use a new idempotency key. Approve that exact request in the owner dashboard. The agent should wait for that newly submitted job rather than creating another one.
After the job succeeds, compare three pieces of evidence:
- the approved request preview;
- the bounded execution receipt and events ActionDock observed; and
- a fresh read from the built-in records API.
The post-read should contain the intended test change and a newer ETag. Keep the distinction clear: an ActionDock succeeded write job means ActionDock completed the job after receiving a 2xx provider response. It is not independent proof of a wider downstream business process.
The recorded ActionDock demo shows this read, propose, approve, execute, and receipt sequence with real sandbox payloads. It is a static record of one run, not a live test runner and not evidence about your agent.
6. Force a stale-version conflict
Read one record and prepare two proposals using the same ETag. Approve the first. Once it changes the record and advances the validator, approve the second proposal.
The second request should fail because its If-Match value is stale. Keep the failed job, read the current record, and decide whether the second intent is still valid. Do not remove the condition and do not reuse the old approval. This verifies that a state change leads back to fresh evidence and a fresh decision.
What the free sandbox proves—and what it cannot
| The sandbox can demonstrate | It cannot establish |
|---|---|
| A real ActionDock API key can submit through MCP or HTTP | A third-party provider will accept its own credential or request format |
| Configured method and path policy is evaluated | Private-network, OAuth-only, browser-only, or provider-specific connectivity |
| A write waits for a signed-in owner decision | Whether your production reviewer has enough domain context or capacity |
| Rejection leaves the built-in record unchanged | That every alternate production write path has been removed |
A strong ETag can be approval-bound and sent as If-Match |
That another provider supports or correctly enforces the same condition |
| ActionDock submission idempotency returns the existing job | Exactly-once execution inside an arbitrary provider |
| ActionDock retains the submitted request, current job state, separate event records, and bounded provider response | Independent proof of the provider’s final business state |
Sandbox records are in-process test data, not durable storage. They reset after a process restart or deployment, and the least-recently-used workspace’s in-memory record set can be evicted when the in-memory limit is reached. Treat them as disposable fixtures. Keep durable evidence in the job and event records, while recognizing that those records describe what ActionDock observed.
Repeat provider-specific tests in disposable staging
The built-in loop lets you validate one run of the supervision machinery against ActionDock’s own test API. It cannot validate the destination you intend to use in production. Create a provider staging tenant or a purpose-built test API with data that can be discarded, then repeat the relevant matrix.
- Use a staging-only credential. Scope it to the smallest service, tenant, methods, and paths the workflow needs. Never make the test dependent on a production token.
- Match the real wire contract. Exercise the provider’s actual payload limits, version headers, pagination, errors, rate limits, and authentication behavior. A mock that always returns
200hides the important branches. - Test policy before execution. Submit denied methods and neighboring paths and verify that the provider never sees them. GitHub’s new workflow execution protections include an evaluate mode for seeing what policy would block before enforcement. ActionDock does not claim that GitHub feature; the transferable rollout pattern is to inspect policy impact before relying on it.
- Verify callbacks as hostile input. Check the signature over the raw body, enforce the timestamp window, atomically deduplicate on
X-ActionDock-Delivery, and make downstream processing idempotent. Use the detailed AI-agent callback verification guide. - Inject failures on both sides of commit. Drop a request before the provider applies it, then run a separate case where the provider applies it but the response is lost. The second case must lead to readback and reconciliation, not an automatic fresh submission. The retry and unknown-outcome guide covers that boundary.
- Retain evidence for every branch. Record the proposed request, decision, timestamps, provider response when available, post-read, callback event and delivery IDs, and operator conclusion. Do not put secrets or unnecessary personal data in test evidence.
Google’s September 18 account of using agents to secure infrastructure code describes per-change pre-submit checks, deterministic structural validation, a second nightly layer, and agent-proposed fixes that still go through human review. This is a software-security system, not a business API gateway. Its relevant lesson is narrower: test each small change with deterministic evidence, then add an independent later layer instead of relying on one model judgment.
Define the production promotion gate
Before the first production write, require a named owner to answer yes to every item:
- Does the agent have one documented write purpose rather than general administrator access?
- Are destination, method, and path restrictions enforced outside the model?
- Are provider credentials unavailable to the agent and limited at the provider too?
- Did pending and rejected jobs leave provider state unchanged?
- Does approval bind the resolved destination, method, path, query, body, connection version, and any
If-Matchcondition? - Did a duplicate submission return the existing job?
- Did a stale version fail without an unconditional fallback?
- Can the callback consumer authenticate and deduplicate repeated events?
- Did a lost-response exercise produce
execution_unknown, with no automatic retry or client resubmission before authoritative readback? - Are direct credentials, browser sessions, and alternate connectors removed or separately governed?
- Can an operator distinguish the execution receipt from proof of the final business outcome?
- Is there a written stop, rollback, or compensating-action procedure for the first canary?
If any answer is “not tested,” keep the workflow out of production. A prompt promise is not a substitute for an enforced boundary.
For the first canary, keep manual approval, limit the workflow to one path family, and cap volume at a level a reviewer can inspect. Compare every approved request with provider readback. Expand only after the expected failures are routine, visible, and recoverable.
Start with a test that is allowed to fail
The best pre-production test is not a flawless demo. It is a small workflow that proves what happens when policy denies, a person rejects, state changes, delivery becomes uncertain, or an event arrives twice.
Create the free sandbox to test the ActionDock control loop against disposable built-in records. Then repeat the provider-specific cases in an isolated staging environment before any production canary. The goal is not to prove that an AI agent never makes a mistake. It is to prove that one mistaken proposal cannot silently become an uncontrolled write.
