Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions specification/DigitalOcean-public.v2.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,65 @@ tags:
- **Users** and **end user limits** show and limit activity per end
user, identified by a session's `actorId`.

To find and call tools in a session, use the
[Action Gateway Data Plane](#tag/Action-Gateway-Data-Plane) endpoints or
connect an MCP client to the session's `mcpUrl`.

- name: Action Gateway Data Plane
description: |-
The Action Gateway data plane finds and runs tools in a session. These
endpoints are the REST forms of the session's MCP meta tools:

- `POST /tools/search` is `action_search`.
- `POST /tools/invoke` is `action_invoke`.
- `POST /code/execute` is `action_code`.

`GET /tools` lists the tools that a session can call, and the
`/approvals` endpoints approve or deny calls waiting for approval.

**Note:** The data plane uses a separate base URL,
`https://actions.do-ai.run`, the same host as a session's `mcpUrl`. It
is independent of the control-plane API at `https://api.digitalocean.com`.

### Authentication and Sessions

Authenticate with a DigitalOcean personal access token in the
`Authorization: Bearer` header. Custom-scoped tokens need the
`action_gateway:execute` scope. Every request also acts in one session.
Create the session with the
[Create a Session](https://docs.digitalocean.com/reference/api/digitalocean/#tag/Action-Gateway/operation/sessions_create)
endpoint, then send its UUID
in the `X-Session-Id` header or in the request path. The UUID is the value
at the end of the session's `sessionUrn` and `mcpUrl`.

The token must belong to the user who created the session, in the
session's team. The session's `tools` selection limits which tools are
available, and its `policy` decides whether each call is allowed, needs
approval, or is denied. Policy is enforced the same way on these endpoints
and on the session's MCP URL. Tools that use connections run with the
connections of the session's `actorId`.

### Results and Errors

Successful requests to `/tools/search` and `/code/execute` return a tool
result. Check `status` before reading `output`. `/tools/invoke` returns one
tool result per call, and a well-formed request returns `200` even when
some calls fail.

Failed requests return the same shape with `status` set to `failed` and
an `error` object. Branch on `error.class`, `error.retriable`, and
`error.recovery_hint` rather than on `error.message`. Request bodies are
limited to 1 MiB.

### Approvals

When a session policy sets `ask` for a call, the call does not run.
Instead, its result fails with `_meta.status` set to `requires_approval`,
an `approval_id`, an `expires_at` time, and a `decide` object describing
the approval request. The session owner sends that request with their own
token. The caller then repeats the call with the same arguments. Over MCP,
clients that support elicitation can approve the call while it waits.

- name: Agent Platform API
description: |-
The API lets you build GPU-powered AI agents with pre-built or custom foundation models, function and agent routes, and RAG pipelines with knowledge bases.
Expand Down Expand Up @@ -770,6 +829,7 @@ x-tagGroups:
- Actions
- Add-Ons
- Action Gateway
- Action Gateway Data Plane
- Agent Platform API
- Apps
- Billing
Expand Down Expand Up @@ -983,6 +1043,30 @@ paths:
get:
$ref: "resources/action_gateway/users_get.yml"

/tools:
get:
$ref: "resources/action_gateway/gatewayTools_list.yml"

/tools/search:
post:
$ref: "resources/action_gateway/gatewayTools_list_search.yml"

/tools/invoke:
post:
$ref: "resources/action_gateway/gatewayTools_run.yml"

/code/execute:
post:
$ref: "resources/action_gateway/gatewayCode_run.yml"

/approvals/session/{session_id}/{approval_id}:
post:
$ref: "resources/action_gateway/gatewaySessionApprovals_update.yml"

/approvals/{approval_id}:
post:
$ref: "resources/action_gateway/gatewayApprovals_update.yml"

/v2/1-clicks:
get:
$ref: "resources/1-clicks/oneClicks_list.yml"
Expand Down
202 changes: 202 additions & 0 deletions specification/resources/action_gateway/data_plane_responses.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
bad_request:
description: >-
The request is invalid: the body is not valid JSON, a required field is
missing, or a value is out of range.
content:
application/json:
schema:
$ref: models/data_plane.yml#/tool_result_error
example:
status: failed
error:
class: invalid_argument
message: Request is invalid. Fix request arguments and retry.
retriable: false
recovery_hint: fix_args
call_id: call_8b7c6d5e-4f3a-4b2c-9d1e-0f9a8b7c6d5e

payment_required:
description: Your team must add prepayment before it can make more tool calls.
content:
application/json:
schema:
$ref: models/data_plane.yml#/tool_result_error
example:
status: failed
error:
class: forbidden
message: Prepayment is required before additional tool calls can be made.
retriable: false
recovery_hint: contact_support
call_id: call_8b7c6d5e-4f3a-4b2c-9d1e-0f9a8b7c6d5e

unauthorized:
description: >-
The token is missing, invalid, or expired. This response uses the standard
DigitalOcean API error format.
content:
application/json:
schema:
$ref: ../../shared/models/error.yml
example:
id: unauthorized
message: Unable to authenticate you.

forbidden:
description: >-
The token or session cannot be used for this request. Tokens without the
`action_gateway:execute` scope, and accounts that are not in good
standing, are rejected with the standard DigitalOcean API error format.
Session failures return a tool result: the session ID is missing or
invalid, the session belongs to another user or team, the session has no
policy, or the session policy denies the operation.
content:
application/json:
schema:
oneOf:
- $ref: models/data_plane.yml#/tool_result_error
- $ref: ../../shared/models/error.yml
example:
status: failed
error:
class: forbidden
message: A valid session ID is required to invoke tools.
retriable: false
recovery_hint: fix_args
call_id: ''

not_found:
description: >-
The approval does not exist or belongs to another session. Approvals for
other callers are reported as not found.
content:
application/json:
schema:
$ref: models/data_plane.yml#/tool_result_error
example:
status: failed
error:
class: invalid_argument
message: The requested route is not supported.
retriable: false
recovery_hint: fix_args
call_id: ''

conflict:
description: >-
The approval was already decided or has expired. Repeat the tool call to
request a new approval.
content:
application/json:
schema:
$ref: models/data_plane.yml#/tool_result_error
example:
status: failed
error:
class: invalid_argument
message: The approval is no longer pending. Re-invoke the tool to request a new approval.
retriable: false
recovery_hint: fix_args
call_id: ''

precondition_failed:
description: >-
Your team is not enabled for Action Gateway, or the session or its
connection is not set up for this call. For example, the session needs an
`actorId` for OAuth tools, an OAuth connection must be reconnected, or the
connection's private network does not match what the MCP server requires.
content:
application/json:
schema:
$ref: models/data_plane.yml#/tool_result_error
example:
status: failed
error:
class: forbidden
message: Your team is not enabled for Action Gateway. Contact support to request access.
retriable: false
recovery_hint: contact_support
call_id: ''

payload_too_large:
description: The request body is larger than 1 MiB.
content:
application/json:
schema:
$ref: models/data_plane.yml#/tool_result_error
example:
status: failed
error:
class: invalid_argument
message: Request body is too large.
retriable: false
recovery_hint: fix_args
call_id: ''

too_many_requests:
description: >-
A rate limit was exceeded. Wait for the number of seconds in `Retry-After`,
when present, before retrying.
headers:
Retry-After:
description: The number of seconds to wait before retrying.
schema:
type: integer
example: 30
content:
application/json:
schema:
$ref: models/data_plane.yml#/tool_result_error
example:
status: failed
error:
class: rate_limited
message: Rate limit exceeded. Retry after the indicated delay.
retriable: true
recovery_hint: retry_later
call_id: call_8b7c6d5e-4f3a-4b2c-9d1e-0f9a8b7c6d5e

server_error:
description: The gateway failed to process the request. Retry later.
content:
application/json:
schema:
$ref: models/data_plane.yml#/tool_result_error
example:
status: failed
error:
class: unavailable
message: The server failed to process the request.
retriable: true
recovery_hint: retry_later
call_id: call_8b7c6d5e-4f3a-4b2c-9d1e-0f9a8b7c6d5e

service_unavailable:
description: The gateway or a service it depends on is temporarily unavailable. Retry later.
content:
application/json:
schema:
$ref: models/data_plane.yml#/tool_result_error
example:
status: failed
error:
class: unavailable
message: Gateway is temporarily unavailable. Retry later.
retriable: true
recovery_hint: retry_later
call_id: call_8b7c6d5e-4f3a-4b2c-9d1e-0f9a8b7c6d5e

gateway_timeout:
description: The code did not finish within the execution time limit.
content:
application/json:
schema:
$ref: models/data_plane.yml#/tool_result_error
example:
status: failed
error:
class: timeout
message: Tool execution timed out.
retriable: true
recovery_hint: retry_later
call_id: call_8b7c6d5e-4f3a-4b2c-9d1e-0f9a8b7c6d5e
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
lang: cURL
source: |-
curl -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $DIGITALOCEAN_TOKEN" \
-H "X-Session-Id: $SESSION_ID" \
-d '{"decision":"deny"}' \
"https://actions.do-ai.run/approvals/$APPROVAL_ID"
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
lang: cURL
source: |-
curl -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $DIGITALOCEAN_TOKEN" \
-H "X-Session-Id: $SESSION_ID" \
-d '{"code":"print(\"hello from Action Gateway\")"}' \
"https://actions.do-ai.run/code/execute"
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
lang: cURL
source: |-
curl -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $DIGITALOCEAN_TOKEN" \
-d '{"decision":"approve"}' \
"https://actions.do-ai.run/approvals/session/$SESSION_ID/$APPROVAL_ID"
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
lang: cURL
source: |-
curl -X GET \
-H "Authorization: Bearer $DIGITALOCEAN_TOKEN" \
-H "X-Session-Id: $SESSION_ID" \
"https://actions.do-ai.run/tools?page_size=20"
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
lang: cURL
source: |-
curl -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $DIGITALOCEAN_TOKEN" \
-H "X-Session-Id: $SESSION_ID" \
-d '{"queries":[{"use_case":"search the public web for current information"}],"limit":3}' \
"https://actions.do-ai.run/tools/search"
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
lang: cURL
source: |-
curl -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $DIGITALOCEAN_TOKEN" \
-H "X-Session-Id: $SESSION_ID" \
-d '{"rationale":"Find current information about DigitalOcean.","tools":[{"tool":"exa_web_search","arguments":{"query":"DigitalOcean cloud computing","max_results":1}}]}' \
"https://actions.do-ai.run/tools/invoke"
Loading
Loading