---
title: "Deploy a function"
method: POST
path: "/functions"
tags: ["Functions"]
---

# Deploy a function

`POST /functions`

Creates and deploys a new function. The handler must be a single
ESM module whose default export is an object with an async
`fetch(request, env)` method (Workers-style). Primitive signs
each delivery and forwards the `Primitive-Signature` header to
the handler. Verify the raw request body with
`PRIMITIVE_WEBHOOK_SECRET` before parsing JSON; after verification
the request body parses to a webhook event whose `event` field is
`email.received` for normal inbound mail, or a machine-mail type
(`email.bounced`, `email.tls_report`, `email.dmarc_report`,
`email.dmarc_failure`) for bounces and reports. Code is bundled
before being uploaded; ship a single self-contained file rather
than relying on external imports.

**Code limits.** `code` is capped at 1 MiB UTF-8. `sourceMap`
(optional) is capped at 5 MiB UTF-8, stored with each deployment
attempt, and sent to the runtime so stack traces can resolve to
original source files.

**Routing.** On successful deploy, the function code is live
in the runtime, but inbound mail will not reach it until at
least one route is bound. Routes are managed from the Primitive
dashboard. A `deploy_status` of `deployed` means the script is
installed, not that the function is receiving mail. The
internal runtime URL is not returned by the API and is not a
customer-facing integration surface.

**Secrets.** New functions ship with the managed secrets
(`PRIMITIVE_WEBHOOK_SECRET`, `PRIMITIVE_API_KEY`,
`PRIMITIVE_API_BASE_URL`) already bound. Add user-set secrets via
`POST /functions/{id}/secrets`; secret writes only land in the
running handler on the next redeploy.

## Headers

- `Idempotency-Key` string

## Request body

- object
  - `name` string, required — Slug-style name. Lowercase letters, digits, hyphens, and underscores. 1 to 64 characters. Must be unique within the org; a 409 is returned on collision.
  - `code` string — Pre-built handler as a single ESM module. Up to 1 MiB UTF-8. Must export a default `{ async fetch(req, env, ctx) { ... } }` object. Provide either `code` or `files`, not both.
  - `sourceMap` string — Optional source map for the bundle. Up to 5 MiB UTF-8. Stored with the deployment attempt and sent to the runtime to symbolicate stack traces in the function's logs. Only valid with `code`.
  - `files` object — Source files for a managed build, as a map of path to file contents (for example {"package.json": "...", "src/index.ts": "..."}). Provide this INSTEAD of `code` to have the server install dependencies and bundle the source for the Workers runtime before deploying. Include a package.json (its `dependencies` are installed). Provide either `code` or `files`, not both.

## Response `201`

Function created and deployed

- object
  - `success` true, required
  - `data` object, required — Returned by POST /functions on a successful deploy.
    - `id` string, uuid, required
    - `name` string, required
    - `deploy_status` 'pending' | 'deployed' | 'failed', required — Lifecycle state of the latest deploy attempt: * `pending` — deploy in flight; the runtime has not yet confirmed the new bundle is live. * `deployed` — the running edge handler is the latest code. * `failed` — the most recent deploy attempt failed; the previously-live code (if any) is still running. The `deploy_error` field carries the error message.

## Other responses

- `400` — Invalid request parameters
- `401` — Invalid or missing API key
- `409` — The request conflicts with the current state of the resource
- `424` — The operation depends on another service or step that failed.
- `429` — Rate limit exceeded
- `503` — Primitive is temporarily unable to process the request

---

[API](https://skmtc.dev/primitive/apis/primitive-api.md) · [All operations](https://skmtc.dev/primitive/apis/primitive-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/primitive/primitive-api/revisions/c2299d28022c/schema)
