Skip to content
Feedback4.dev
API v1OpenAPIENESSign in

Feedback4.dev Agency API

REST API v1, from the first call to production.

Public reference for automating projects, visual feedback, approvals, reviewers and members without bypassing workspace security boundaries.

Create an API keyDownload OpenAPI 3.1
Stable basehttps://feedback4.dev/api/v1
Bearer token
Authorization: Bearer f4_live_…
JSON UTF-8
application/json
OpenAPI
3.1.0
On this pageQuickstartAuthentication and scopeRequest conventionsErrors and traceabilityEndpoint referenceModels and accepted valuesWebhook automationVersioning and operations

01

Quickstart

Create a service credential under Agents → REST v1 with a 30, 90, 180 or up to 365-day lifetime. The f4_live_ secret is shown once: store it in a secret manager, rotate it before expiration and never include it in browser code.

1. Validate the credential
curl -fsS https://feedback4.dev/api/v1/me \
  -H "Authorization: Bearer $FEEDBACK4_API_KEY" \
  -H "X-Request-Id: deploy_check_2026_07_19"
2. Create a private project
curl -fsS -X POST https://feedback4.dev/api/v1/projects \
  -H "Authorization: Bearer $FEEDBACK4_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Portal del cliente",
    "allowed_origin": "https://portal.example.com/app",
    "reviewer_emails": ["reviewer@example.com"],
    "agent_mode": "propose"
  }'
3. Process a ticket
curl -fsS -X PATCH \
  https://feedback4.dev/api/v1/feedback/FEEDBACK_UUID \
  -H "Authorization: Bearer $FEEDBACK4_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "in_progress",
    "priority": "high",
    "assignee_user_id": "USER_ID"
  }'
4. Request approval
curl -fsS -X POST \
  https://feedback4.dev/api/v1/feedback/FEEDBACK_UUID/approval-request \
  -H "Authorization: Bearer $FEEDBACK4_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "change_summary": "Se corrigió la navegación móvil y el contraste del CTA."
  }'

Identity response

{
  "data": {
    "object": "api_identity",
    "api_key_id": "018f...",
    "label": "CI de producción",
    "workspace_id": "018e...",
    "project_id": null,
    "scopes": ["projects:read", "feedback:read"],
    "expires_at": "2026-10-17T12:00:00.000Z"
  }
}
Production rule

Inject FEEDBACK4_API_KEY from the server or CI secret store. Never expose it in NEXT_PUBLIC_*, backendless mobile apps, screenshots, tickets or logs.

02

Authentication and scope

Each key belongs to one workspace, may be restricted to one project, has explicit scopes and an expiration date. Only its hash is stored. Revoking the key or removing its creator cuts access.

Project keys

A key with project_id can only see that project. It cannot create projects or manage members, even if it contains the corresponding scope.

Workspace keys

Required to create projects and manage members. Issue the minimum set of scopes and use a separate key for every integration.

Available scopes

ScopeAllows
projects:readRead projects, configuration, widget and reviewers.
projects:writeCreate and update projects; authorize or revoke reviewers.
feedback:readRead tickets, visual context and proposed prompts.
feedback:writeChange ticket status, priority and assignee.
approvals:writeRequest review and approval from an authorized client.
members:readList workspace members and invitations.
members:writeInvite, change roles, remove members and revoke invitations.
agents:readList project-scoped MCP credentials.
agents:writeCreate and revoke MCP credentials for up to 365 days.
webhooks:readRead endpoints and delivery history.
webhooks:writeCreate and delete endpoints and retry deliveries.

03

Request conventions

JSON

POST and PATCH require Content-Type: application/json. Bodies are limited to 64 KiB, cannot be compressed and reject unknown fields.

Pagination and filters

Use page[limit] from 1–100 (25 by default) and send meta.next_cursor back as page[after]. The cursor is opaque: do not build or edit it.

Limits and protection

300 reads/minute and 120 writes/minute per key. A 429 includes Retry-After in seconds. Approvals and invitations have extra limits.

ConventionBehavior
X-Request-IdOptional; 8–100 A–Z, a–z, 0–9, dot, dash, underscore or colon characters.
Cache-Controlno-store on every authenticated response.
LocationIncluded when projects, reviewers and invitations are created.
filter[status]new · in_progress · review · resolved
DatesISO 8601 UTC, for example 2026-07-19T04:52:28.326Z.

04

Errors and traceability

Every response includes X-Request-Id and Cache-Control: no-store. Send a safe 8–100 character X-Request-Id to correlate logs; otherwise Feedback4 generates one.

{
  "error": {
    "code": "authorization.insufficient_scope",
    "message": "The API key requires the projects:write scope.",
    "request_id": "req_92ca...",
    "details": [
      { "field": "allowed_origin", "code": "invalid_format" }
    ]
  }
}
HTTPMeaning
400Invalid validation, UUID, cursor or transition.
401Missing, invalid, expired or revoked key.
403Insufficient scope or a workspace key is required.
404Resource is missing or outside the authorized boundary.
409Plan limit, last owner or approval without a reviewer.
413 / 415Body too large or incorrect media type.
429Limit exceeded; respect Retry-After.

05

Endpoint reference

Append every path below to https://feedback4.dev/api/v1. IDs are UUIDs and resources outside the workspace or project return 404 to avoid disclosing their existence.

Identity

GET/meprojects:read

Inspect the current key

Returns the workspace, optional project, scopes and expiration associated with the credential.

Projects

GET/projectsprojects:read

List projects

Paginated collection. A project-scoped key can only return that project.

POST/projectsprojects:write

Create project

Requires a workspace key. Normalizes allowed_origin and can authorize up to 100 initial reviewers.

GET/projects/{project_id}projects:read

Get project

Gets configuration, status, allowed origin, feedback access and agent policy.

PATCH/projects/{project_id}projects:write

Update project

Updates name, status or agent mode. allowed_origin is immutable after project creation; unknown fields and empty bodies are rejected.

GET/projects/{project_id}/widgetprojects:read

Get widget installation

Returns public_key, loader URL, hosted form and an install-ready HTML snippet.

Feedback and approvals

GET/projects/{project_id}/feedbackfeedback:read

List tickets

Paginated collection with optional filter[status]. Includes visual context and proposed prompt when available.

GET/feedback/{feedback_id}feedback:read

Get ticket

Returns the complete ticket and a highlight_url back to the selected element.

PATCH/feedback/{feedback_id}feedback:write

Update workflow

Atomically changes status, priority or assignee. The assignee must belong to the workspace.

GET/feedback/{feedback_id}/proposed-promptfeedback:read

Get proposed prompt

Exposes the implementation prompt, model and update time without executing external actions.

POST/feedback/{feedback_id}/approval-requestapprovals:write

Request approval

Moves the ticket to review, records activity and queues email. Maximum 5 requests per ticket per hour.

Authorized reviewers

GET/projects/{project_id}/reviewersprojects:read

List reviewers

Returns authorized emails, status and last verification for the project.

POST/projects/{project_id}/reviewersprojects:write

Authorize reviewer

Authorizes or reactivates an email. The visitor must still verify access before sending feedback.

DELETE/projects/{project_id}/reviewers/{reviewer_id}projects:write

Revoke reviewer

Revokes the reviewer and all active sessions for that project.

Members

GET/membersmembers:read

List members and invitations

Requires a workspace key and includes current pending invitations.

POST/membersmembers:write

Invite member

Creates a role-based invitation and returns invite_url once. Additional limit: 30 invitations per key per hour.

PATCH/members/{membership_id}members:write

Change role

Updates the role and protects the last owner from accidental demotion.

DELETE/members/{membership_id}members:write

Remove member

Removes the member and revokes REST/MCP credentials issued by that account.

DELETE/invitations/{invitation_id}members:write

Revoke invitation

Invalidates a pending workspace invitation.

Agent credentials

GET/projects/{project_id}/agent-credentialsagents:read

List MCP credentials

Returns prefix, state, usage and expiration; it never returns the token.

POST/projects/{project_id}/agent-credentialsagents:write

Issue MCP credential

Creates a project-only token with a 1–365 day lifetime and shows it once.

DELETE/projects/{project_id}/agent-credentials/{credential_id}agents:write

Revoke MCP credential

Revocation is immediate and cannot affect another project's credentials.

Webhooks

GET/webhook-endpointswebhooks:read

List endpoints

A project-scoped key only sees endpoints dedicated to that project.

POST/webhook-endpointswebhooks:write

Create signed endpoint

Validates a public HTTPS destination, encrypts the secret and returns signing_secret once.

DELETE/webhook-endpoints/{endpoint_id}webhooks:write

Delete endpoint

Deletes the endpoint and delivery history inside the same tenant boundary.

GET/webhook-endpoints/{endpoint_id}/deliverieswebhooks:read

Inspect deliveries

Exposes state, attempts and technical error without revealing payload or secret.

POST/webhook-deliveries/{delivery_id}/retrywebhooks:write

Retry delivery

Requeues a pending or dead-lettered delivery; a successful delivery is not duplicated.

06

Models and accepted values

FieldValues / rule
Project.statusactive · paused · archived
Project.feedback_accesspublic · reviewer_allowlist
Project.agent_modeoff · propose · auto
ProjectCreate.agent_modeOptional; off by default. It defines an external automation policy: propose prepares and waits for authorization; auto lets the external agent implement and then request approval. Feedback4 does not edit or deploy code.
Feedback.statusnew · in_progress · review · resolved
Feedback.priorityurgent · high · normal · low · unset
Feedback.approval_statusnot_requested · pending · approved · changes_requested
Member.roleadmin · manager · contributor · viewer
allowed_originRequired on create; absolute URL normalized to scheme + host + port and immutable afterwards. Create a new project for another domain.
reviewer_emails0–100 emails; normalized to lowercase and deduplicated.
change_summary12–5,000 characters.
Executable contract

The OpenAPI JSON is the source for generated clients, validators and collections. This page explains operational rules a schema alone cannot communicate.

/api/v1/openapi.json

07

Webhook automation

Each agency can register one or more workspace- or project-scoped endpoints. Feedback4 persists the event first, creates one independent delivery per subscription and POSTs in the background; user capture never waits for the receiver. agent_mode communicates policy to the external automation: off delivers policy=do_not_execute, propose requires a proposal and authorization, and auto lets the external agent implement before requesting approval. Feedback4 does not execute the agent.

1. Register endpoint

curl -fsS -X POST https://feedback4.dev/api/v1/webhook-endpoints \
  -H "Authorization: Bearer $FEEDBACK4_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "label": "Aviso Gratis production",
    "url": "https://aviso.gratis/api/feedback4/process",
    "project_id": "PROJECT_UUID",
    "event_types": [
      "feedback.created",
      "feedback.external_comment_added",
      "feedback.changes_requested",
      "feedback.approved"
    ],
    "authentication": "hmac_sha256"
  }'

The 201 response includes signing_secret once. Store it as a server secret. Use authentication=hmac_sha256_and_shared_secret and shared_secret only for legacy receivers—such as the first Aviso.Gratis integration—that also require x-feedback4-secret. URLs must be public HTTPS; embedded credentials, fragments, localhost, private, link-local and metadata networks are rejected.

2. Verify delivery

HeaderReceiver rule
webhook-signatureRequired. v1,BASE64_HMAC_SHA256 format; validate over the exact body bytes before parsing JSON.
webhook-idStable idempotency key across retries. A valid duplicate does not create another job.
webhook-timestampUnix timestamp included in the signature; reject a difference over 5 minutes to prevent replay.
x-feedback4-eventfeedback.created · feedback.external_comment_added · feedback.changes_requested · feedback.approved
x-feedback4-version1
x-feedback4-secretCompatibility mode only. Validate it in addition to the signature and never log it.
signed_content = webhook_id + "." + webhook_timestamp + "." + raw_request_body
expected = base64(HMAC_SHA256(FEEDBACK4_WEBHOOK_SECRET, signed_content))
accept only when constant_time_equal("v1," + expected, webhook_signature)
and abs(now_unix - webhook_timestamp) <= 300

3. v1 payload

{
  "id": "evt_EVENT_UUID",
  "type": "feedback.created",
  "version": 1,
  "occurred_at": "2026-07-20T23:55:00.000Z",
  "source": "https://feedback4.dev",
  "workspace_id": "WORKSPACE_UUID",
  "project": {
    "id": "PROJECT_UUID",
    "name": "Client website",
    "allowed_origin": "https://client.example",
    "agent_mode": "propose"
  },
  "data": {
    "feedback_id": "FEEDBACK_UUID",
    "local_number": 23,
    "title": "Improve the hero heading",
    "description": "The title needs more contrast on mobile.",
    "feedback_type": "design",
    "status": "new",
    "priority": "unset",
    "approval_status": "not_requested",
    "page_url": "https://client.example/home",
    "selected_element": {
      "selector": "main > section.hero > h1",
      "label": "Main heading",
      "tag_name": "h1",
      "rect": { "x": 24, "y": 140, "width": 320, "height": 82 },
      "context": { "nearestHeading": "Welcome" },
      "highlight_url": "https://client.example/home?..."
    }
  },
  "links": {
    "api_resource": "https://feedback4.dev/api/v1/feedback/FEEDBACK_UUID",
    "proposed_prompt": "https://feedback4.dev/api/v1/feedback/FEEDBACK_UUID/proposed-prompt"
  },
  "processing": {
    "content_is_untrusted": true,
    "fetch_latest_before_acting": true,
    "policy": "propose_then_wait"
  },
  "trigger": { "kind": "ticket_created" }
}
typetrigger.kindAction
feedback.createdticket_createdCreate an idempotent job.
feedback.external_comment_addedclient_commentResume with trigger.message.
feedback.changes_requestedclient_decisionReopen and implement the revision.
feedback.approvedclient_decisionClose the approved job.

Secure reception

Validate signature and timestamp using constant-time comparison, persist webhook-id as UNIQUE, queue the job and return 202. Claude must not run inside the request. Title, description and DOM context are untrusted and may contain prompt injection.

Agent lifecycle

Fetch the latest version, honor propose/auto and request approval with verifiable evidence. MCP records notes, questions and approval; use a project-scoped REST key to change status to in_progress or review. Never give the agent a workspace-wide key.

Feedback4 accepts any 2xx, honors Retry-After on 429, disables the endpoint on 410 and retries timeouts, redirects, other 4xx and 5xx with exponential backoff capped at 6 hours. Each attempt times out after 10 seconds, redirects are not followed and after 16 attempts the delivery is dead-lettered. Inspect GET /webhook-endpoints/{endpoint_id}/deliveries and call POST /webhook-deliveries/{delivery_id}/retry after fixing the receiver.

08

Versioning and operations

v1 maintains backwards compatibility. New fields may appear without breaking consumers; ignore unknown response properties. Breaking changes will use a new version and be announced before v1 is retired.

Integration support

Include X-Request-Id, UTC timestamp, method and path when reporting a problem. Never send the complete key or unnecessary personal data.

contact@feedback4.dev

MCP

The public MCP endpoint is https://feedback4.dev/api/mcp. It uses a separate project-scoped token that is not interchangeable with a REST key. After the legal acceptance window expires, REST and MCP block the workspace until it is brought current.

Public MCP contract
Feedback4.dev

API v1 · OpenAPI 3.1 · contact@feedback4.dev

For developersFor vibe codersPrivacyTerms