OpenAI Agents API
Route Agents API required function calls to ActionBox for a durable human decision, then continue the same OpenAI session.
The OpenAI Agents API can pause a managed session when it needs a function
result. ActionBox can hold that pending call as a durable human request. After
the reviewer responds, your application returns the decision to the same
OpenAI session with the original turn_id and call_id.
Agents API and Agents SDK are different integrations
This page covers the managed Agents API and its required_actions contract.
If your application uses the Python Agents SDK and result.interruptions,
follow the OpenAI Agents SDK guide.
Ownership boundary
| Concern | Owner |
|---|---|
| Managed session, context, tools, and pending function call | OpenAI Agents API |
| Human request, reviewer access, typed response, and decision history | ActionBox |
| Function credentials, authorization checks, and real side effect | Your application |
| Execution result | Your application, optionally reported to ActionBox |
An ActionBox approval authorizes one attempt. It does not prove that a rollback, deployment, refund, or other operation succeeded.
Two ways to connect
Use the Agents API required_actions path when a particular function must stop
at an enforced application boundary. Use ActionBox MCP when the agent may
voluntarily ask a person for context or a decision.
| Need | Integration |
|---|---|
| Require approval for a selected function | agent.session.requires_action to an ActionBox Action |
| Let the agent ask a person a question | Hosted ActionBox MCP ask_human and get_action |
The MCP path is useful for human input, but the agent can choose whether to call it. Keep mandatory approval in the application or gateway that controls the protected function.
Handle a required function call
OpenAI emits agent.session.requires_action while streaming. A project webhook
uses the event name agent.session.action_required. In either case, retrieve
the session and read session.required_actions. Route only current
function_call entries. A historical function-call item does not prove that a
result is still pending.
The following example handles the propose_rollback function from OpenAI's SRE
pattern. It allowlists the fields shown to the reviewer instead of copying the
complete argument object.
import hashlib
import json
import os
from actionbox import Actionbox
from openai import OpenAI
def idempotency_key(session_id: str, turn_id: str, call_id: str) -> str:
identity = f"{session_id}\0{turn_id}\0{call_id}".encode()
return "openai-agents-api:" + hashlib.sha256(identity).hexdigest()
def route_rollback_approvals(
openai_client: OpenAI,
actionbox: Actionbox,
session_id: str,
) -> None:
session = openai_client.beta.agents.sessions.retrieve(session_id)
results = []
for pending in session.required_actions:
if pending.type != "function_call" or pending.name != "propose_rollback":
continue
arguments = pending.arguments
if isinstance(arguments, str):
arguments = json.loads(arguments)
review = {
"Service": arguments["service"],
"Current version": arguments.get("current_version", "Unknown"),
"Target version": arguments["target_version"],
"Reason": arguments["reason"],
}
action = actionbox.create(
title=f"Approve OpenAI agent: {pending.name}",
description=(
"The OpenAI Agents API paused this rollback proposal. "
"Review the selected service, version, and reason."
),
interaction={
"type": "boolean",
"label": "Allow this rollback proposal?",
"true_label": "Approve",
"false_label": "Reject",
},
context=[{
"type": "key_value",
"title": "Pending function call",
"items": review,
}],
metadata={
"framework": "openai_agents_api",
"openai_session_id": session_id,
"openai_turn_id": pending.turn_id,
"openai_call_id": pending.call_id,
},
idempotency_key=idempotency_key(
session_id,
pending.turn_id,
pending.call_id,
),
)
binding = (action.action_version, action.fingerprint)
response = action.wait(timeout=3600)
if response is None and action.status == "open":
actionbox.cancel(
action.id,
"Agents API approval timed out; rejected fail-closed.",
)
approved = (
action.status == "resolved"
and action.resolved_by == "user"
and (action.action_version, action.fingerprint) == binding
and isinstance(response, dict)
and response.get("type") == "boolean"
and response.get("value") is True
)
results.append({
"type": "agent.session.input.tool_result",
"turn_id": pending.turn_id,
"call_id": pending.call_id,
"success": True,
"output": json.dumps({
"decision": "approved" if approved else "rejected",
"executed": False,
"action_id": action.id,
}),
})
if results:
openai_client.beta.agents.sessions.events.create(
session_id,
events=results,
)
openai_client = OpenAI()
with Actionbox(os.environ["ACTIONBOX_API_KEY"]) as actionbox:
route_rollback_approvals(openai_client, actionbox, "session_id_here")The success: true field means your application returned a function result to
OpenAI. The human answer stays in output.decision. Keep executed: false
until the protected operation has actually run.
Receive the event through a webhook
For a process that should survive restarts, subscribe to
agent.session.action_required in the OpenAI project and verify the OpenAI
webhook signature before reading its body. Persist the session ID and ActionBox
Action ID. Repeated deliveries must map to the same Action through the stable
session, turn, and call identity.
Do not keep approval state only in a Slack message or process memory. OpenAI's SRE example explicitly leaves production implementations to persist approval records and verify the responder's identity and production access.
Connect ActionBox as an MCP server
The Agents API can call remote HTTP MCP servers from OpenAI. ActionBox's hosted
MCP endpoint is https://api.actionbox.cloud/mcp.
{
"type": "mcp",
"server_label": "actionbox",
"transport": {
"type": "http",
"server_url": "https://api.actionbox.cloud/mcp",
"authorization": "Bearer ACTIONBOX_SOURCE_KEY"
},
"connection_origin": "service",
"required": true,
"allowed_tools": [
"ask_human",
"get_action",
"update_action",
"cancel_action"
]
}Inject the Source key from a secret manager when creating the session, or use an
OpenAI vault credential. Never put the key in agent instructions, Action
content, logs, or a reusable agent definition. The restricted tool list omits
resolve_action so the agent cannot record a machine-selected answer as if it
were a human decision.
Production checks
- Route only explicitly allowlisted function names to the approval adapter.
- Validate the function arguments before creating the Action.
- Build a small review object from allowlisted fields. Do not publish raw tool arguments or private model state.
- Use the OpenAI session, turn, and call IDs for idempotency.
- Bind the decision to the Action version and fingerprint the reviewer saw.
- Treat rejection, expiry, malformed responses, and timeouts as non-approval.
- Verify the reviewer's role again in the system that owns the side effect.
- Record whether the approved operation succeeded or failed.
Reviewers can answer through the hosted web or mobile inbox. Slack review is an assisted Team beta and must be configured separately. See Slack for current availability and review limitations.
Official OpenAI references
- Agents API overview
- Agents API function tools
- SRE incident-response example
- Agents API MCP connections
Need help testing the adapter with a synthetic function call? Email info@actionbox.cloud with the function name and the review fields you plan to expose.
OpenAI and Agents API are referenced for interoperability. ActionBox is an independent product and is not endorsed by OpenAI.