---
title: "Review a public publish enablement request"
method: POST
path: "/projects/public-publishing-requests/{requestId}/reviews"
tags: ["Approval requests"]
---

# Review a public publish enablement request

`POST /projects/public-publishing-requests/{requestId}/reviews`

## Request

- Base URL: `https://api.replit.com/v1`
- URL: `https://api.replit.com/v1/projects/public-publishing-requests/{requestId}/reviews`
- Auth: HTTP bearer

Approve or deny one pending public publish enablement request owned by this
Account. The API key's creator must retain approval-management access for
the Account. Requests remain reviewable by the Account that received them
after a Project moves.

Approval grants a Project-specific public publishing override; it does not
create or publish a deployment. If the Project's current Account differs
from the request's Account, approval records `fulfillment_failed` rather
than granting the override. Other eligibility failures return 409
(`conflict`) and leave the request pending. Projects that are no longer
available for review return 404 (`not_found`).

Send the list item's `reviewEtag` or the detail response's complete opaque
`ETag` unchanged in `If-Match`. Reload after an ownership change
and use the new tag, even if no new request event was recorded.

A missing header returns 428 (`precondition_required`); a malformed or weak
value returns 400 (`invalid_request`); a tag made stale by a new request
event or a change to the visible Workspace returns 412
(`precondition_failed`); and a current tag on a request that is no longer
pending returns 409 (`request_already_resolved`).

A successful review returns 200 with the updated request, its ordered
public event history, a new ETag, and `Cache-Control: no-store, no-transform`.
Check `data.status` to distinguish `fulfilled` from `fulfillment_failed`;
an accepted approval does not guarantee that the override was granted.

A read made immediately after a review can briefly return the request's
previous state. If the response is lost, wait briefly and read the
request again. If it is resolved, do not
retry; if still pending, retry only with the latest read's ETag. The
returned ETag changes with the request's event history or visible Workspace,
but not with every change to other response fields.

## Path parameters

- `requestId` string, uuid, required

## Headers

- `If-Match` string, required

## Request body

- union
  - object
    - `outcome` 'approved', required
  - object
    - `outcome` 'denied', required
    - `reason` string: Public denial reason returned in the request event history. Do not include confidential internal notes.

## Response `200`

Reviewed public publish enablement request.

- PublicPublishEnablementRequestResponse
  - `data` PublicPublishEnablementRequestWithEvents, required
    - `id` string, uuid, required
    - `status` 'pending' | 'approved' | 'fulfillment_started' | 'fulfilled' | 'fulfillment_failed' | 'denied' | 'canceled', required
    - `workspaceId` string, nullable, required: Current workspace in this Account, or null when the Project no longer belongs to this Account.
    - `projectId` string, uuid, required
    - `requesterUserId` string, required
    - `version` integer, required: Increments with every recorded event. Use the ETag header, not this field, for conditional requests. A change to the visible Workspace can change the ETag without a new event.
    - `createdAt` string, date-time, required
    - `updatedAt` string, date-time, required
    - `events` PublicPublishEnablementRequestEvent[], required
      - `sequence` integer, required
      - `eventType` 'request_started' | 'request_approved' | 'request_denied' | 'request_canceled' | 'request_fulfillment_started' | 'request_fulfilled' | 'request_fulfillment_failed', required
      - `fromStatus` 'pending' | 'approved' | 'fulfillment_started' | 'fulfilled' | 'fulfillment_failed' | 'denied' | 'canceled', required
      - `toStatus` 'pending' | 'approved' | 'fulfillment_started' | 'fulfilled' | 'fulfillment_failed' | 'denied' | 'canceled', required
      - `actor` union, required
        - object
          - `type` 'user', required
          - `userId` string, required
        - object
          - `type` 'api_key', required
          - `apiKeyId` string, uuid, required
        - object
          - `type` 'system', required
          - `systemId` string, required
      - `publicNote` string, nullable, required
      - `occurredAt` string, date-time, required

## Other responses

- `400`: The request parameters are invalid.
- `401`: The API key is missing, malformed, unknown, revoked, or expired.
- `403`: The API key lacks the required scope or Account entitlement.
- `404`: The requested resource does not exist or is not visible to this key.
- `409`: The request cannot accept the decision, or a required update is in progress.
- `412`: The If-Match precondition failed for the current request. Reload the request and retry.
- `428`: The request requires an If-Match header with the strong ETag from the latest read.
- `429`: The API key or operation exceeded its rate limit.
- `500`: The server encountered an unexpected error.
- `503`: A required API dependency is temporarily unavailable.

## Changes

- **2026-09-19** `ba193431df44`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/replit/apis/replit-api/changes/projects/public-publishing-requests/:requestId/reviews/post.md)

---

[API](https://skmtc.dev/replit/apis/replit-api.md) - [All operations](https://skmtc.dev/replit/apis/replit-api/llms.txt) - [OpenAPI document](https://skmtc.dev/replit/apis/replit-api/revisions/03b316f7e71a?raw)
