Requests
Intake funnel for feature requests, clarifications, support questions, and bug reports — with internal/client comment visibility, accept/reject triage, and one-click conversion to issues.
Requests are ProxifAI’s intake funnel. Where tickets handle ongoing customer-support threads with SLAs, requests are short-form intake — “we’d like feature X”, “can you clarify Y?”, “we hit bug Z” — that triage either accepts (often converting to a linked issue) or rejects with a note. They also work as the internal feedback channel: anyone in the org can file a request without bypassing the project planning process.
How requests differ from tickets and issues
| Question | Issues | Tickets | Requests |
|---|---|---|---|
| Who creates them? | Internal team members | External customers via web/email/portal/api | Internal team members or clients (the source field flags which) |
| What’s the workflow? | 6-state engineering pipeline (backlog → done) | 5-state support thread (open → closed) with SLA | 5-state intake (new → accepted/rejected → completed) |
| Does it carry an SLA? | No | Yes | No |
| Can it spawn an issue? | — | Yes (convert action) | Yes (auto-fills the LinkedIssue when status flips to accepted) |
| Comment privacy? | All comments are org-visible | Public messages + internal notes | Internal comments + client-visible comments (per-comment toggle) |
Anatomy of a request
| Field | Notes |
|---|---|
title | One-line summary; required |
description | Long-form Markdown |
type | feature / clarification / support / bug |
source | internal (team member submitted) or client (came from a client portal/form) |
status | One of 5 values — see Status |
priority | low / medium / high / urgent |
requester, requesterInitial | Display name + initial — works even if the requester isn’t a ProxifAI user |
teamId | Optional — scope to one team |
clientId | Optional FK to a Client row (the CRM primitive) |
linkedIssueId | Optional FK to an Issue — set when triage accepts the request and converts it |
Status
Five values from RequestStatus. The flow is intake-driven:
| Status | Meaning |
|---|---|
new | Just submitted; not yet triaged |
in_review | Triage is looking at it — gathering context, asking for more info |
accepted | Triage said yes; usually a linked issue is created at this point and the request stays around as the source-of-record |
rejected | Triage declined; reason goes in a comment |
completed | The request was followed through (either via the linked issue shipping, or because triage acted on it directly) |
accepted and completed are kept distinct so dashboards can answer two different questions: “what did we say yes to?” vs “what did we actually ship in response?”
Comment visibility
Every RequestComment has a visibility flag with two values:
internal— only visible to org members. Use for “this overlaps with @alice’s work, defer”, “ping @triage-agent to categorize”, etc.client— visible to the client (when the request came from one) on whatever surface they submitted from.
This lets the triage discussion happen privately while still leaving room for direct dialogue with the requester. The same RequestComment.visibility = client you set on a thread you can read back from a client portal.
CLI
pfai request is a thin wrapper over the REST surface — every subcommand follows kubectl-style verbs (list/ls, view/get, delete/rm):
pfai request list # list requests in the current org
pfai request list --status new --type bug # filter
pfai request view <id> # full request including comments
pfai request create --title "Add SAML SSO" --type feature --priority high
pfai request update <id> --status accepted --linked-issue eng-204
pfai request stats # aggregate counts (per-status, per-type, per-source)
pfai request comments <id> # list comments on a request
pfai request comment <id> --content "Approved — see ENG-204" --visibility client
pfai request delete <id>
REST endpoints
| Method · Path | Purpose |
|---|---|
GET /api/v1/requests | List with filters (status, type, source, priority, clientId, teamId) |
POST /api/v1/requests | Create — minimum is {title, type}; everything else has defaults |
GET /api/v1/requests/stats | Aggregate counts for dashboards |
GET /api/v1/requests/{id} | Read with embedded client, comments |
PATCH /api/v1/requests/{id} | Update fields (status transitions, priority changes, linked-issue assignment) |
DELETE /api/v1/requests/{id} | Soft-delete |
GET /api/v1/requests/{id}/comments | Comment thread |
POST /api/v1/requests/{id}/comments | Add a comment — pass visibility: "internal" or "client" |
PATCH /api/v1/requests/{id}/comments/{commentId} | Edit your own comment |
DELETE /api/v1/requests/{id}/comments/{commentId} | Delete your own comment |
Triage workflow
A typical request lifecycle:
- Submit. Internal user runs
pfai request create, or a client posts via the portal — request lands asnew. - Pick up. A team-lead or triage agent moves it to
in_reviewand asks clarifying questions in client-visible comments. - Decide. Triage flips to
accepted(creating an issue and settinglinkedIssueId) orrejected(with a note explaining why). - Track. Accepted requests stay in the system; their
linkedIssueIdlets dashboards roll up “what we said yes to” vs “what we shipped.” - Close. Once the linked issue ships (or the requestor’s clarification was answered), the request flips to
completed.
Trigger rules can automate the easy paths — e.g. a request.created event that auto-tags by category, or auto-rejects requests from blocked clients.
See also
Heavier-weight customer-support threads with SLA tracking and full message history.
Once a request is accepted, the actual work lives in an issue — same workspace, same RBAC.
React to `request.created` / `request.status_changed` events with automation.
Save filters like 'Pending review' or 'High-priority client requests' for one-click access.