---
title: "Publish project"
method: POST
path: "/v1/projects/{project_id}/publish"
tags: ["deploy-domains"]
---

# Publish project

`POST /v1/projects/{project_id}/publish`

**Plan:** `All plans`

Builds and deploys the project. Asynchronous: returns 202 with a deployment_id; poll GET /v1/projects/{project_id}/publish/{deployment_id} until status is completed or error. Optionally sets who can view the published app first: public (anyone with the link), workspace (workspace members only), or custom (only the groups/users in audience). Omit visibility to keep the current setting. Visibility changes apply to the currently published version immediately, before the new deployment finishes.

## Path parameters

- `project_id` string, required — Project ID

## Request body

- PublicV1PublishProjectInputBody
  - `audience` PublicV1PublishAudienceTarget[], nullable — Complete set of group/user grants for visibility 'custom': replaces existing group and user grants, an empty list removes them all, omit to keep the current audience. Grants managed in the UI (org access, email invites) are preserved. Only valid with visibility 'custom'.
    - `id` string, required — Group ID or workspace member user ID
    - `type` 'group' | 'user', required — Audience target type
  - `name` string — Project slug for the published URL
  - `visibility` 'public' | 'workspace' | 'custom' — Who can view the published app: public (anyone with the link), workspace (workspace members only), or custom (only the groups/users in audience). Omit to keep the project's current setting. Clients must tolerate new values.

## Response `200`

OK

- PublicV1PublishProjectResponse
  - `deployment_id` string — Deployment ID
  - `status` string, required — Deployment status
  - `url` string — Published project URL
  - `visibility` string, required — Resolved visibility of the published app

## Other responses

- `202` — Accepted
- `401` — Missing or invalid API key.
- `402` — This operation or requested configuration requires a workspace plan that includes this feature.
- `403` — The key or caller lacks the required scope or permission.
- `406` — The Accept header excludes every media type this endpoint produces.
- `429` — Too many requests. Retry after the interval in Retry-After when present.
- `default` — Error. The response body uses the standard error envelope; status matches the HTTP status code and type is a machine-readable error code.

---

[API](https://skmtc.net/lovable/apis/lovable-api.md) · [All operations](https://skmtc.net/lovable/apis/lovable-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/lovable/lovable-api/revisions/aa8d44585147/schema)
