# Functions API

Deploy and invoke functions.

Deploy and invoke functions.

These endpoints cover standard functions only. [Durable functions](https://docs.volcano.dev/platform/functions/durable-functions.md) are a separate collection under `/projects/{projectId}/durable-functions`, and a durable function's id answers `404` here. Their executions, [approvals](https://docs.volcano.dev/platform/functions/durable-approvals.md), and [messages](https://docs.volcano.dev/platform/functions/durable-messages.md) are documented with them.

## List Functions

```http
GET /projects/{projectId}/functions
Authorization: Bearer <platform_token>
```

**Query Parameters:**

- `page`, `limit` - Pagination

**Response:**

```json
{
  "data": [
    {
      "id": "func-uuid",
      "name": "my-function",
      "status": "active",
      "visibility": "private",
      "is_public": false,
      "invocation_mode": "rpc",
      "http_auth_mode": "volcano",
      "openapi_spec": null,
      "invoke_url": "https://func-uuid.functions.volcano.run/",
      "deployed_regions": ["us-east-1", "us-west-2"],
      "runtime": "nodejs24.x",
      "handler": "handler",
      "created_at": "2024-01-01T00:00:00Z",
      "updated_at": "2024-01-01T00:00:00Z"
    }
  ]
}
```

## Get Function

```http
GET /projects/{projectId}/functions/{functionId}
Authorization: Bearer <platform_token>
```

The response is a `Function` resource and includes `invoke_url`, `created_at`, and `updated_at` when available.

## List Runtimes

```http
GET /functions/runtimes
```

Lists every runtime a function can deploy on. The endpoint needs no authentication.

**Response:**

```json
{
  "runtimes": [
    {
      "name": "python3.14",
      "label": "Python 3.14",
      "language": "python",
      "default": false,
      "durable_capable": true,
      "deployment": {
        "file_extensions": [".py"],
        "entrypoint": "main.py",
        "handler": "handler",
        "dependency_manifests": ["requirements.txt"]
      }
    }
  ]
}
```

- `name` - the value to pass as `runtime` when you deploy
- `label` - display name for a runtime picker; show it rather than formatting `name`
- `language` - language family, such as `nodejs`, `python`, or `ruby`
- `default` - whether this is the default runtime for its language
- `durable_capable` - whether a [durable function](https://docs.volcano.dev/platform/functions/durable-functions.md) can run on it
- `deployment` - the entry file, handler, source extensions, and dependency manifests the runtime expects

## Create or Update Function Code

```http
POST /projects/{projectId}/functions
Authorization: Bearer <platform_token>
Content-Type: multipart/form-data
```

**Request:**

```bash
curl -X POST "https://api.volcano.dev/projects/$PROJECT_ID/functions" \
  -H "Authorization: Bearer $PLATFORM_TOKEN" \
  -F "name=my-function" \
  -F "runtime=nodejs24.x" \
  -F "handler=handler" \
  -F "code=@function.zip"
```

**Parameters:**

- `name` (required) - DNS-safe function name (max 63 characters, lowercase letters/numbers/hyphens, cannot start or end with hyphen)
- `code` (required) - ZIP or `tar.gz` archive containing function source code plus dependency manifests/lockfiles
- `runtime` (required) - Runtime environment
- `handler` (optional) - Function name to invoke; defaults to `handler`
- `visibility` (optional) - `private`, `authenticated`, or `public`; defaults to `private` for a new function, and a redeploy without it keeps the current level
- `is_public` (optional, deprecated) - `true` means `public`, `false` means `authenticated`; must agree with `visibility` when both are sent
- `invocation_mode` (optional) - `rpc` (default) or `http`
- `http_auth_mode` (optional) - `volcano` (default) or `none`; `none` requires a public HTTP function
- `openapi_spec` (optional) - JSON-encoded OpenAPI 3.0 or 3.1 document for HTTP-mode metadata

Cloud deploys install Node.js, Python, and Ruby dependencies during the function compile build. Upload source and manifests such as `package.json`, `requirements.txt`, or `Gemfile`; do not upload installed dependency directories such as `node_modules`, `python_deps`, `.venv`, or `vendor`.

Python dependencies are staged outside application source and exposed to the
build through `PYTHONPATH` and `PATH`. The build command therefore does not see
installed packages copied into its source tree, and application source wins
publish-time file collisions.

The top-level path `.volcano-dependencies` is reserved for dependency staging.
An uploaded function containing that path is accepted asynchronously, then its
compile build fails with a reserved-path validation error.

Direct API clients may upload ZIP or `tar.gz`; the API stores a normalized `tar.gz` source archive. Uploaded source archives cannot contain symlink entries. The API limits uploaded and normalized source archives to 256 MB. The CLI uploads `tar.gz` and does not enforce its own source archive size limit.

After dependencies are installed and the final image is built, the build rejects an image larger than 4096 MB.

For direct API uploads, Volcano generates `.volcano/function-build.json` automatically. It infers `function_root` from the single runtime entry file (`index.js`/`index.mjs`, `main.py`, or `main.rb`), or from the only top-level directory when the archive has one. It selects `install_root` from the closest dependency manifest directory containing the effective handler module, relative to `function_root`. When no manifest contains the module and `function_root` is `.`, the fallback selects the longest nested manifest directory path. With no containing manifest or applicable fallback, installation uses `function_root`. See [direct-upload layout inference](https://docs.volcano.dev/platform/functions/upload-api.md#direct-upload-layout-inference) for handler resolution and tie-breaking.

**Runtimes** ([List Runtimes](#list-runtimes) returns the current set):

- `nodejs22.x`, `nodejs24.x`
- `python3.10`, `python3.11`, `python3.12`, `python3.13`, `python3.14`
- `ruby3.3`, `ruby3.4`, `ruby4.0`

`python3.10` is deprecated: Python 3.10 reached end of life in October 2026. It still deploys, and Volcano will remove it before 2027-08-31. Move functions to a newer Python runtime.

**Response:** 201 Created

If a function with the same name already exists, the same endpoint updates that
function's runtime, handler, and source bundle and returns `200 OK`. A redeploy
that would take a function with Frontend Function routes out of `public` or
HTTP mode answers `409` before anything deploys; see
[Update Function Invocation Settings](#update-function-invocation-settings).

Deployment and code update are asynchronous. A deployment that starts
immediately returns `status: provisioning`, then transitions to `active` or
`failed`. If another deployment is running, the function keeps its current
status and exposes the queued deployment as `pending_deployment_id`.

For an existing function, the last known-good runtime continues serving traffic
while the update provisions. A failed update leaves that runtime available and
records the attempted deployment as failed.

Only one deployment runs for a given function. A newer deploy is accepted and
queued; it supersedes any older queued deploy and starts when the running
deployment finishes. Different functions and projects deploy concurrently.
Deployment history reports waiting work as `queued` and replaced work as
`superseded`.

**Limit:** Each project can contain up to 10,000 standard functions. Creating a new function over this cap returns `403 Forbidden`. Durable functions have their own cap of the same size, counted separately.

## Deploy Multiple Functions

```http
POST /projects/{projectId}/functions/batch
Authorization: Bearer <platform_token>
Content-Type: multipart/form-data
```

The `functions` multipart field is a JSON array describing each function (`name`, `runtime`, optional `handler`, and `file_field`). Each `file_field` points to a multipart file field containing that function's ZIP or `tar.gz` source bundle. The response includes a shared `batch_id` and the accepted function resources. Each function still runs its own cloud compile/publish workflow concurrently. The Volcano CLI automatically splits `functions deploy --all` into multiple 100-function batch requests when needed.

One batch request can include up to 100 functions. Submit multiple batch requests for larger projects.

If one function fails before its workflow starts, the API keeps already-started function deployments running and returns the failure in a `failed` array. Failed new functions are deleted; failed updates are rolled back to their previous metadata/status where possible.

Batch deploys follow the same source-bundle rules as single-function deploys: upload source and dependency manifests, not installed dependencies.

## Invoke Function

RPC functions can be invoked in two ways:

- DNS endpoint (recommended, geo-routed): the function's `invoke_url`, which in
  production reads `https://{functionId}.functions.volcano.run/`
- API endpoint (direct invocation): `POST https://api.volcano.dev/functions/{functionId}/invoke`

The two live on different domains, and the DNS endpoint differs between
deployments. Send requests to `invoke_url` as returned rather than building the
host yourself.

```http
POST /functions/{functionId}/invoke
Authorization: Bearer <service_key_or_access_token_or_anon_key>
Content-Type: application/json
```

CORS preflight for invocation only allows:

```http
Access-Control-Allow-Methods: POST, OPTIONS
```

HTTP-mode DNS endpoints accept `GET`, `HEAD`, `POST`, `PUT`, `PATCH`, and
`DELETE` on `/` and nested paths. Their preflight response advertises:

```http
Access-Control-Allow-Methods: GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS
```

DNS equivalent:

```http
POST <invoke_url>
Authorization: Bearer <service_key_or_access_token_or_anon_key>
Content-Type: application/json
```

**Token behavior:**

- Service key: always allowed
- Auth user access token: allowed when the function is `authenticated` or
  `public`; `404` on a `private` function, the same answer as a missing one
- Anon key: needs the `functions.invoke` permission (`403` without it, before
  the function is looked up). Allowed on a `public` function; `403` on an
  `authenticated` one; `404` on a `private` one

SDK calls by name resolve the name first, and
[resolve](#resolve-function-name) answers `404` to an anon key on any function
that isn't `public`, so they see `404` where a call by id sees `403`.

For an HTTP function with `http_auth_mode: none`, the DNS endpoint does not
require a Volcano token. This mode is valid only with `visibility: public` and is
intended for webhooks that validate provider signatures inside the function.
The direct `/functions/{functionId}/invoke` RPC endpoint remains authenticated.

**Request:**

```json
{
  "payload": {
    "action": "process",
    "data": "value"
  }
}
```

**With service key:**

```json
// Function receives
{
  "action": "process",
  "data": "value"
}
```

**With Auth User Token:**

```json
// Function receives
{
  "action": "process",
  "data": "value",
  "__volcano_auth": {
    "user_id": "uuid",
    "email": "user@example.com",
    "project_id": "project-uuid",
    "role": "authenticated",
    "access_token": "eyJhbGci..."
  }
}
```

**Response:**

```json
{
  // Raw function response body
}
```

The HTTP status code and headers are forwarded from the function response, except
for the platform-owned ones (`X-Volcano-Version`, `X-Volcano-Region`,
`X-Volcano-Health`, `X-Volcano-Function-Invoked`, `X-Volcano-Proxy-Ms`,
`X-Volcano-Proxy-Handler-Ms`, `X-Volcano-Compute-Ms`) and
Volcano's internal headers, which are dropped.  
All successful function invocations include `X-Volcano-Version` (`<version>` in production, `<env>-<version>` in non-production environments), `X-Volcano-Region`, `X-Volcano-Proxy-Ms` (milliseconds spent preparing the call, from your request arriving until your function ran), `X-Volcano-Proxy-Handler-Ms` (the part of that spent in the invoke endpoint itself), and `X-Volcano-Compute-Ms` (milliseconds spent running your function).

The JavaScript, Python, and Ruby SDKs can recover a rejected user credential
before dispatch: they refresh the captured session once per resolution or
invocation stage and retry with the original payload. They preserve explicit
session replacement and never replay a function's own HTTP response, a platform
403, or an ambiguous network failure. See the [JavaScript](https://docs.volcano.dev/sdk/js/functions.md),
[Python](https://docs.volcano.dev/sdk/python/functions.md), and [Ruby](https://docs.volcano.dev/sdk/ruby/functions.md) guides for native
response and error handling.

## Resolve Function Name

Resolves a function name to function ID and invocation URL in the caller's project.  
Used by SDKs before DNS invocation. Invoke the returned `invoke_url` as-is; it is
not derivable from the API host. It is omitted in local development, where you
invoke through `POST /functions/{functionId}/invoke` instead.

```http
GET /functions/resolve?name={functionName}
Authorization: Bearer <service_key_or_access_token_or_anon_key>
```

**Token behavior:**

- Service key: allowed
- Auth user access token: allowed when the function is `authenticated` or
  `public`; `404` on a `private` function, the same answer as a missing one
- Anon key: needs the `functions.invoke` permission (`403` without it), and the
  function must be `public`; any other answers `404`, as if it did not exist.

**Response:**

```json
{
  "name": "my-function",
  "function_id": "3cd3e058-e3ff-42a5-ae4d-650ef9b45746",
  "invoke_url": "https://3cd3e058-e3ff-42a5-ae4d-650ef9b45746.functions.volcano.run/",
  "cache_ttl_seconds": 300
}
```

## Get Function Logs

```http
POST /projects/{projectId}/logs/search
Authorization: Bearer <platform_token>
Content-Type: application/json
```

These are runtime invocation logs. Set `resource.type` to `function`; omit
`resource.ids` to list logs across all functions or include one or more function
IDs for selected functions. The optional `q` field runs a free-text search. When
`q` is omitted or blank, the endpoint returns stored logs using structured
filters only. Use `invocation.id` in `q` to select one function invocation.
Deployment build logs use the resource deployment selector below. Authenticate
with the project owner's platform token or a project access token; `read_only`
is sufficient. Project end-user sessions cannot read these logs.

See the [logs guide](https://docs.volcano.dev/platform/functions/logs.md) for query syntax and SDK examples.

**Request Body Fields:**

- `resource.type` - Required. Use `function`
- `resource.ids` - Optional function IDs
- `q` - Optional free-text query
- `limit` - Max events (default: 100, max: 1000)
- `cursor` - Opaque pagination cursor
- `start_time` - Inclusive lower bound as an RFC3339 timestamp
- `end_time` - Inclusive upper bound as an RFC3339 timestamp
- Filter levels, regions, and invocation IDs through fields in `q`.

**Example:**

```json
{
  "resource": {
    "type": "function",
    "ids": ["550e8400-e29b-41d4-a716-446655440000"]
  },
  "q": "body:checkout_failed invocation.id:01JZ8QK9V6X3P5T7N2M4R8C0AB level:(warn OR error) region:us-east-1",
  "limit": 50
}
```

**Response:**

```json
{
  "data": [
    {
      "id": "log/us-east-1/01HKG3W9M0A5V7R2J6Z0Q6Y4S9",
      "timestamp": "2024-01-01T12:00:00Z",
      "level": "info",
      "body": "Log message",
      "resource": {
        "type": "function",
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "my-function"
      },
      "region": "us-east-1"
    }
  ],
  "limit": 100,
  "has_more": true,
  "next_cursor": "eyJwayI6..."
}
```

## Function Deployment Build Logs

```http
POST /projects/{projectId}/logs/search
Authorization: Bearer <platform_token>
```

Returns runtime and deployment logs through the common project log search API.
For deployment build logs, send `resource.type=function`,
`resource.ids=[functionId]`, and
`resource.deployments.ids=[deploymentId]`. The platform token must belong to
the owner of `{projectId}`.

## List Function Deployments

```http
GET /projects/{projectId}/functions/{functionId}/deployments
Authorization: Bearer <platform_token>
```

Returns deployment history for a function, including workflow status and build log metadata.

## Delete Function

```http
DELETE /projects/{projectId}/functions/{functionId}
Authorization: Bearer <platform_token>
```

**Response:** 202 Accepted

Function deletion is asynchronous. If another deployment is running, list/get
responses keep the function's current status and expose the queued deletion as
`pending_deployment_id`. The status changes to `deleting` when cleanup starts.
When cleanup finishes, the function no longer appears in lists and
`GET /projects/{projectId}/functions/{functionId}` returns `404`.

Deletion is queued behind a running deployment and supersedes queued deploys.
After deletion is requested, later deploys return `409 Conflict` until deletion
finishes.

## Update Function Invocation Settings

```http
PATCH /projects/{projectId}/functions/{functionId}
Authorization: Bearer <platform_token>
Content-Type: application/json
```

**Request:**

```json
{
  "visibility": "public",
  "invocation_mode": "http",
  "http_auth_mode": "none",
  "openapi_spec": {
    "openapi": "3.1.0",
    "info": { "title": "Webhook", "version": "1.0.0" },
    "paths": {}
  }
}
```

- `visibility: private` (default for new functions): service keys and schedulers only
- `visibility: authenticated`: also your project's signed-in users
- `visibility: public`: also anon keys with `functions.invoke`
- `is_public` (deprecated): `true` means `public`, `false` means `authenticated`
- `invocation_mode: rpc`: POST-only `{ "payload": ... }` contract
- `invocation_mode: http`: HTTP request-event contract on the DNS endpoint
- `http_auth_mode: volcano`: Volcano token authentication
- `http_auth_mode: none`: no Volcano token; requires `visibility: public` and HTTP mode
- `openapi_spec`: optional OpenAPI 3.0/3.1 JSON metadata, up to 256 KiB; send `null` to clear

While a [Frontend Function route](https://docs.volcano.dev/platform/frontends/function-routes.md) targets the
function, it must stay `public` and in HTTP mode. An update or redeploy that
changes either answers `409`: `remove attached Frontend Function routes before
making the function non-public`, or `remove attached Frontend Function routes
before changing invocation mode`. A redeploy is checked before it starts, so a
refused one deploys nothing.

> **Security note:** Treat a `public` function as internet-facing. An anon key
> ships in browser code, a [Frontend Function route](https://docs.volcano.dev/platform/frontends/function-routes.md)
> forwards requests with no credential, and `http` + `none` serves its DNS
> endpoint without a token.

## Function Status

- `provisioning` - Being deployed
- `active` - Ready to invoke
- `failed` - Deployment failed

Useful deployment fields in responses:

- `invoke_url` - canonical DNS invoke URL for this function
- `deployed_regions` - regions where the function is currently deployed

## See Also

- [Creating Functions](https://docs.volcano.dev/platform/functions/creating-functions.md)
- [Invoking Functions](https://docs.volcano.dev/platform/functions/invoking-functions.md)
- [Function Logs](https://docs.volcano.dev/platform/functions/logs.md)
- [Durable Functions](https://docs.volcano.dev/platform/functions/durable-functions.md)
