CLI¶
The command is withfeedback.
Signing in¶
Create one under Account → API Tokens, then either:
or store it in the OS keychain:
Resolution order for every command: --token flag, then
WITHFEEDBACK_TOKEN, then the keychain.
Commands¶
withfeedback testimonials list --team <ID> --project <ID> [--status pending|approved|rejected|spam] [--rating N] [--q text] [--json]
withfeedback testimonials approve <SUBMISSION_ID> --team <ID>
withfeedback testimonials reject <SUBMISSION_ID> --team <ID>
withfeedback testimonials create --team <ID> --project <ID> --text "..." [--rating N] [--name ..] [--email ..] [--consent]
withfeedback import csv FILE --team <ID> --project <ID> --text-col COL [--rating-col COL] [--name-col COL] [--email-col COL] [--consent]
withfeedback surveys list --team <ID> --project <ID>
withfeedback nps summary --team <ID> --project <ID>
withfeedback widgets list --team <ID> --project <ID>
withfeedback usage --team <ID>
Human-readable tables by default. --json gives you the raw API response, with
errors still on stderr — so | jq works and a failure still fails.
Importing a CSV¶
withfeedback import csv reviews.csv \
--team <TEAM_ID> --project <PROJECT_ID> \
--text-col "Testimonial" --rating-col "Stars" \
--name-col "Author" --email-col "Email" --consent
The file is validated locally first — headers and row count — before anything is
uploaded, so a wrong --text-col fails in a second instead of after the upload.
Rows are processed asynchronously and land as pending; the command prints the
batch id and a URL to poll.
--consent is a factual claim
Pass it only when display consent was genuinely collected for those rows. It is the flag that decides whether these testimonials may appear on your site, and nobody downstream can check it for you.
In CI¶
- name: Import weekly reviews
env:
WITHFEEDBACK_TOKEN: ${{ secrets.WITHFEEDBACK_TOKEN }}
run: |
uvx withfeedback import csv reviews.csv \
--team $TEAM --project $PROJECT --text-col Review --json
Give the CI token only write:feedback plus the job scopes. A token that cannot
approve is a token that cannot publish something nobody read.