The direct answer
Give every time-sensitive AI-agent write an absolute latest dispatch time derived from the business operation. Bind that deadline to the exact request a person reviews, reject an already-expired proposal, check the time again when the owner approves, and make one final check immediately before any credentialed network send. If the deadline has passed, close the job without dispatching it. Do not let a late click turn an obsolete proposal into a live API call.
An approval timeout is not a substitute for exact-request review, optimistic concurrency, idempotency, or a provider request timeout. Those controls answer different questions:
- Did the person approve this exact connection version, destination, method, path, query, and body?
- Is this still the provider resource version the agent examined?
- Is this the same logical submission the client already made?
- Is it still acceptable to start the write now?
- What should happen if the request was sent but its result is unknown?
For a write routed through ActionDock, the optional integration.execute field input.executeBefore supplies that latest-dispatch boundary. It is checked at submission, approval, and again just before dispatch. It does not cancel a request that has already been sent.
An exact approval can still arrive too late
Suppose an operations agent prepares a PATCH to release an inventory hold before a same-day cutoff. The proposed path and JSON body do not change. The reviewer opens the notification after the cutoff and clicks approve.
The approval may be authentic and the request may still match its preview, yet the business intent is stale. The relevant question is no longer only “Did a person approve these bytes?” It is also “Was this write allowed to begin at this time?”
This resembles a check-to-use gap, but it is not necessarily the TOCTOU race condition classified as CWE-367. MITRE defines that time-of-check time-of-use weakness as a product checking a resource before use, where the resource can change between the check and use and invalidate the check. In an approval workflow, several things can become stale while the request waits:
| What became stale | Control that addresses it |
|---|---|
| Connection version, destination, method, path, query, or body | Bind approval to the exact request and connection version |
| Provider resource state | Use a strong ETag with If-Match when the provider enforces it |
| Business time window | Enforce a latest-dispatch deadline |
| Client submission | Reuse a stable idempotency key for the same proposal |
| Outcome after a possible send | Stop and reconcile instead of retrying blindly |
These controls complement one another. A deadline cannot detect that another operator edited the target record. An ETag cannot tell you that a maintenance window ended. Exact approval does not make an old business instruction current again.
Approval timeout, dispatch deadline, and request timeout are different clocks
“Timeout” is often used for several unrelated boundaries. Treating them as one number creates gaps.
1. Reviewer waiting time
This is how long a proposal may remain undecided. Other approval systems make this boundary explicit. GitHub documents that a job referencing an environment configured with required reviewers automatically fails if it is not approved within 30 days. Google Cloud Privileged Access Manager says an unscheduled grant expires after 24 hours without a decision, while a scheduled grant expires at its activation time; after expiry, the requester must create a new grant request.
Those are platform-specific rules, not a universal standard and not ActionDock integrations. They demonstrate a useful principle: silence should not turn into indefinite authority.
2. Latest dispatch time
This is the last instant at which the system may start sending the approved request. It should reflect the proposal’s business meaning: a cutoff, a maintenance window, a temporary hold, or another externally defined boundary.
The deadline must be enforced at the final execution gate, not only when the request enters the approval queue. Otherwise policy evaluation, DNS work, queue delay, or scheduler contention can consume the remaining window after the owner clicks approve.
3. Provider execution or transport timeout
This clock starts after work begins. AWS Step Functions, for example, defines TimeoutSeconds as the maximum time a task may run and says the count begins when the task starts. That is useful for bounding an in-flight task, but it does not answer whether a delayed task should have started in the first place.
4. Credential lifetime
Token expiry determines whether a credential remains valid. The OAuth JWT access-token profile requires the resource server’s current time to be before the token’s exp claim, with a small allowance permitted for clock skew. A valid token does not mean the business instruction is still timely, and an expired token is not a reliable way to expire one particular proposal.
5. Business completion objective
A workflow may also have a service-level objective such as “the downstream record must be updated by noon.” A latest-dispatch check can refuse to start too late. It cannot guarantee provider completion by noon, prove the resulting business state, or roll back a slow operation.
Design a deadline that fails closed
A useful latest-dispatch deadline has seven properties.
- The caller derives it from the operation. Do not apply one arbitrary TTL to every write. A routine case assignment and a maintenance-window change have different windows.
- It is an absolute server-readable time. Relative phrases such as “in ten minutes” become ambiguous across retries, queues, and clocks. Use UTC and include seconds.
- It is part of the reviewed request. The owner must see the deadline. Adding, extending, shortening, or removing it changes the proposal.
- It is validated more than once. Check it at submission, at approval, and at the last safe point before dispatch.
- Expiry is terminal for that proposal. Preserve the record, release reserved capacity, and emit an explicit failure event. Do not silently refresh the timer.
- The dispatch race is resolved atomically. Expiry and queue claim must not both win. A request already claimed and sent needs its real outcome; a request not yet sent must stay unsent.
- Recovery creates fresh intent. Re-read any relevant state, recalculate the change, choose a new deadline, use a new idempotency key, and request approval again.
The server executing the write must be the time authority for the gate. A laptop clock can help the client choose a window, but it cannot be trusted to decide whether the server may dispatch.
Set executeBefore on an ActionDock write
ActionDock accepts an optional input.executeBefore on integration.execute. The value must be a future UTC ISO 8601 timestamp with seconds and no more than three fractional digits, such as 2026-10-01T12:00:00Z or 2026-10-01T12:00:00.250Z.
This HTTP example also uses If-Match so the proposal has both time freshness and resource-version freshness:
curl https://actiondock.app/v1/actions/integration.execute \
-H "Authorization: Bearer $ACTIONDOCK_API_KEY" \
-H "Idempotency-Key: inventory-hold-42-release-v1" \
-H "Content-Type: application/json" \
-d '{
"workflowId": "inventory-hold-42",
"workflowName": "Time-bounded inventory hold release",
"input": {
"connectionId": "<connection UUID from list_connections>",
"method": "PATCH",
"path": "/inventory-holds/42",
"ifMatch": "\"version-7\"",
"executeBefore": "2026-10-01T12:00:00Z",
"body": {"status":"released"}
}
}'
Choose the timestamp from the real cutoff; do not copy the example date. The deadline appears in the owner email and dashboard preview and is bound to the exact proposal and any runtime AI policy proof. Read the live executeBefore contract before implementing the client.
ActionDock checks the deadline when the proposal is submitted, when the signed-in workspace owner approves it, and immediately before the provider request is sent. The final check happens after policy evaluation and DNS work. Approval is not the final step before network I/O.
What happens at each state
| Situation | ActionDock behavior | Client response |
|---|---|---|
| Deadline is missing | Existing approval behavior remains; the deadline feature adds no business expiry | Decide explicitly whether the operation is genuinely timeless |
| Deadline is at or before server time on submission | Proposal is refused as expired | Re-read, recompute, and submit a current proposal if still needed |
Deadline passes while awaiting_approval |
Job becomes failed; nothing is dispatched |
Do not treat the result as owner rejection or success |
| Owner approves after the deadline | Approval is refused | Create a new proposal, key, deadline, and approval request |
| Owner approves in time, but the deadline passes while queued or during pre-send checks | Job becomes failed; the final gate blocks dispatch |
Investigate the delay before deciding whether to propose again |
| Request starts before the deadline and finishes after it | The real provider result is retained | Evaluate the returned job state; the deadline was not a completion timer |
| Request starts before the deadline, but the response is lost | Job becomes execution_unknown |
Reconcile authoritative provider state before any new write |
Expired pending or queued ActionDock writes release their processing reservation and produce the existing job.failed event. When the workspace has an enabled callback, that event queues a signed delivery. Background cleanup runs on startup and every five seconds in batches of 100, so the visible job status can briefly lag the clock under load. The immediate pre-dispatch check remains authoritative: cleanup lag does not permit a late send.
The original preview remains available. Reusing its idempotency key returns the original job, including its failed state; it does not create a refreshed attempt. Extending or removing executeBefore requires a new proposal, a new idempotency key, and a new owner approval.
Combine time freshness with version freshness
Consider the inventory-hold example again. Two independent changes can invalidate it:
- the cutoff passes; or
- another process modifies the account before dispatch.
Use executeBefore for the first condition. For a provider that documents strong ETags and conditional writes, read the resource with integration.fetch, preserve the quoted ETag, and submit it as input.ifMatch for the second. ActionDock binds both values to the approval preview and forwards the condition as If-Match.
If the provider normally reports 412 Precondition Failed, stop, read the current resource, and request a new decision. Do not remove the condition to make the write succeed. The detailed ETag and If-Match guide covers that branch and its provider-dependent limits.
The idempotency key has another job: it deduplicates the same ActionDock submission. It does not extend the deadline, guarantee exactly-once execution inside an arbitrary provider, or prove the provider’s final state.
Recover from expiry without replaying old intent
When a deadline expires, treat the proposal as historical evidence, not a paused command.
- Read the authoritative provider state again if the decision depends on it.
- Confirm that the business operation is still allowed and useful.
- Recompute the smallest necessary change from current evidence.
- Set a new deadline based on the new business window.
- Create a new idempotency key.
- Ask the owner to review the entire new preview.
Do not clone the old body automatically. The reason for waiting may also be the reason the request is no longer appropriate.
This recovery path differs from a post-dispatch timeout. If ActionDock reports execution_unknown, the provider may already have applied the write. The correct next step is authoritative readback and operator reconciliation, not a fresh deadline and immediate resubmission. See the idempotency and unknown-outcome guide for that distinction.
Test the boundary before production
Use a disposable environment and retain evidence for each branch:
| Test | Expected result |
|---|---|
| Submit an already-expired timestamp | Request is rejected before a job can dispatch |
| Let the deadline pass while waiting for the owner | Job fails and the provider receives no request |
| Approve shortly before expiry, then delay queue execution | Final dispatch gate blocks the late request |
| Make policy or DNS work cross the deadline | Nothing is sent after the final check |
| Replay the same payload and idempotency key | Original expired job is returned |
| Submit a later deadline with a new key | A distinct proposal requires owner approval |
| Start before expiry and make the provider respond afterward | Real response is recorded; the job is not retroactively expired |
| Apply the write but withhold the response | Job becomes execution_unknown; no automatic provider retry occurs |
ActionDock’s free sandbox lets you exercise the approval loop against disposable built-in records without reaching an external provider. It does not offer every timing fault above. Use a controlled provider staging API or proxy for late-response and lost-response cases; queue, policy, and DNS deadline races require a controlled ActionDock test deployment or test harness. The broader pre-production testing guide explains how to separate sandbox, provider staging, and production canary evidence.
Know what a deadline cannot do
executeBefore controls only a compatible API write routed through ActionDock. It cannot stop an agent that also has a direct provider credential, browser session, terminal, database connection, or alternate tool. Remove or separately govern those bypass paths.
It is also not:
- a cancellation signal for an already-sent request;
- a provider completion guarantee;
- a resource-version check;
- a rollback or compensating transaction;
- a whole-agent kill switch;
- independent proof of the provider’s final business state.
Without executeBefore, ActionDock’s processing reservation can be renewed when an owner approves after the original reservation expires. That operational reservation is not a business deadline. If the write becomes unsafe after a specific time, the caller must supply that time.
Start with the exact-request approval design, then add a deadline only where the business operation has a real temporal boundary. The safe rule is simple: approval authorizes one reviewed request, and a deadline says how long that authorization remains eligible to begin execution.
