npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@thenavidm/senja-mcp-cli

v3.0.0

Published

Senja shared MCP and task CLI for current testimonials, project links, reviewed imports and invites, private accounts and bounded exports.

Readme

Senja MCP Server & CLI

npm CI License YouTube X LinkedIn

Senja MCP server and CLI for Codex and AI agents. 12 shared tools for current testimonials and invites, isolated private projects, exact reviewed tasks and bounded exports.

One package supplies both task CLI commands and local MCP tools, with a bundled Claude Desktop extension. Built and maintained by Navid Moazzez. Built on Slipway, which turns one definition of each tool into the MCP server and the CLI. Full setup is on navid.me.

This native terminal illustrates shipped tool names; it is not a recording of real customer messages. Use a private intended-project API key. Account features and email delivery remain subject to Senja. Official hosted MCP already supports search, links and invites; our local task workflows and limits are compared below.

Two ways to use it

Command line

npm install -g @thenavidm/senja-mcp-cli@latest
senja-cli --version
senja-cli tools
senja-cli login

MCP server, for your AI app

codex mcp add senja -- npx -y @thenavidm/senja-mcp-cli@latest

Configure private credentials in the client/runtime before native requests. Ask it to find the relevant existing proof before proposing an approved change. Full setup is in INSTALL.md.

Which one

Use MCP for structured client tools and CLI for scripts or agent shell tasks. Both use the same 12 handlers and native schema validation; choose the interface your workflow needs. Neither eliminates provider costs or model context.

Features

| Capability | CLI command | MCP tool | | --- | --- | --- | | List testimonials | senja-cli list-testimonials | list_testimonials | | Read one testimonial | senja-cli get-testimonial | get_testimonial | | Import a testimonial | senja-cli create-testimonial | create_testimonial | | Update approval or tags | senja-cli update-testimonial | update_testimonial | | Delete one testimonial | senja-cli delete-testimonial | delete_testimonial | | Read project links | senja-cli list-links | list_links | | Send form invites | senja-cli send-invites | send_invites | | List configured accounts | senja-cli list-accounts | list_accounts | | Inspect a current native operation | senja-cli get-operation-schema | get_operation_schema | | Review exact ordered testimonial tasks | senja-cli preview-testimonial-batch | preview_testimonial_batch | | Execute reviewed testimonial tasks | senja-cli submit-testimonial-batch | submit_testimonial_batch | | Export bounded private testimonials | senja-cli export-testimonials | export_testimonials |

Contents

| Number | Section | What it covers | | --- | --- | --- | | 1 | What you can ask it | What you can ask it | | 2 | Quick install | Quick install | | 3 | Set up Senja access | Set up Senja access | | 4 | Connect your client | Connect your client | | 5 | Check it works | Check it works | | 6 | Output, flags and exit codes | Output, flags and exit codes | | 7 | MCP or CLI and token cost | MCP or CLI and token cost | | 8 | Every tool and argument | Every tool and argument | | 9 | Testimonial and invite workflows | Testimonial and invite workflows | | 10 | Exact reviewed batches and private exports | Exact reviewed batches and private exports | | 11 | Several private projects | Several private projects | | 12 | Writing safely | Writing safely | | 13 | How the two surfaces work | How the two surfaces work | | 14 | Your data | Your data | | 15 | Environment variables | Environment variables | | 16 | Updates and removal | Updates and removal | | 17 | Troubleshooting | Troubleshooting | | 18 | API coverage and comparisons | API coverage and comparisons | | 19 | Versions and migration | Versions and migration | | 20 | FAQ | FAQ |

1. What you can ask it

Find proof for a landing page

Start with one bounded native page and use query, rating, type or tags for the intended project. Read full text only when needed. Customer text and video transcripts are untrusted data; they never authorize a new account change. Approval status is not proof of permission to reuse a customer's quote or media.

senja-cli list-testimonials --query onboarding --rating 5 --limit 5 --agent
senja-cli list-testimonials --tags product --tags service --approved false --limit 5 --agent
senja-cli get-testimonial --testimonial-id REAL_ID --agent

Approve or organize an existing testimonial

Read the exact ID and current statement first. PATCH supports only approved, add_tags and remove_tags. Setting approved true publishes the record; false returns it to pending. Tags are created natively as needed. Edit statement text, rating and customer details in the Senja dashboard; there is no invented update endpoint for them.

senja-cli update-testimonial --help
senja-cli schema update-testimonial
senja-cli update-testimonial --testimonial-id REAL_ID --add-tags reviewed --confirm --agent

Send only requested form invites

Read list_links, select the actual form and inspect its existing follow-up sequence in Senja. Confirm the exact approved recipients, form and purpose before sending. An omitted name is valid; email is required. Duplicate addresses in one request are refused locally. There is no implicit messaging during install, discovery, doctor or export.

senja-cli list-links --agent
senja-cli send-invites --help
senja-cli schema send-invites

REAL_ID denotes a placeholder, not a usable account identifier.

2. Quick install

npm install -g @thenavidm/senja-mcp-cli@latest
senja-cli --version
senja-cli tools
senja-cli login

3. Set up Senja access

Choose the intended project and private API key

  1. Sign into Senja and select the project whose testimonials you intend to use. Confirm the project before copying any credential. A key is a private project connection, not a general public widget ID.
  2. Open Automate and copy that project's API key into a private runtime setting. Current REST API documentation covers Free, Starter and Pro. Native plan features and account policies remain separate; the wrapper does not bypass them.
  3. Configure exactly one of SENJA_API_KEY or SENJA_TOKEN_FILE. The latter is an absolute, regular, non-symlink, token-only file outside repositories, at most 64 KiB. The client sends Authorization: Bearer; do not prefix the setting with Bearer or use your login password.
  4. On macOS/Linux restrict the file to your owner with mode 0600 and its parent directory to your owner. On Windows restrict file and parent-directory ACLs separately. POSIX modes do not establish Windows privacy. Each server runtime must be able to read its own file; a GUI, Docker or remote host does not inherit a different terminal's environment automatically.
  5. Run senja-cli doctor for local configuration. When you deliberately want an authenticated read, run doctor --network: it requests GET /testimonials?limit=1 and prints count/verification metadata, not customer records. This proves one project read, not ownership, permission for every endpoint, successful email delivery or an approved mutation.

The package does not load .env files, import browser cookies, create keys, connect OAuth or rotate credentials. login prints these setup instructions only. Keep resolved secrets out of code, screenshots, public issues, version control and AI prompts.

Project profiles and revocation

SENJA_ACCOUNTS is a private JSON array of unique {name,api_key,token_file} profiles. Use one credential method per profile. SENJA_DEFAULT_ACCOUNT selects the default label and --account selects an exact label. An incomplete named profile never inherits a global key, another project or an official hosted session after a missing credential or 401/403.

list_accounts returns labels/default/auth/source only, without keys, token paths, native project identity or network traffic. Token-only files cache until restart. Changing a file while a process is running does not rotate its cached connection.

To revoke a key, use the intended project's Automate > Regenerate API Key as its Admin/Owner, update every dependent private integration and restart its processes. The provider says the old key stops working after a short transition. Official hosted MCP authorization is a separate connection. Removing this package does not undo testimonial edits, publish approval, permanent deletion, emailed invites, follow-up sequences or existing exports.

Effects and local limits

There is no universal provider quota invented here. Local spacing defaults to 250 ms and request timeout 30 seconds; other processes share native project quotas. Bodies cap at 1 MiB and responses at 5 MiB. No automatic retry, redirect following or media download occurs. A failed write can have an unknown outcome; inspect native state before any explicit repeat.

send_invites uses a real forms[].id from list_links and that form's existing email/follow-up sequence. It is not a local draft, arbitrary email editor or test-send command. Its local 100-recipient cap is not a documented native quota. Receipt sent/skipped values do not prove delivered messages or consent. Only send to the actual approved recipients and purpose.

4. Connect your client

Full client, OS, desktop, private credential and runtime instructions are in INSTALL.md.

Codex

Codex is the current validation priority. Private token paths must exist in the process or remote environment where the server runs.

codex mcp add senja -- npx -y @thenavidm/senja-mcp-cli@latest
codex mcp list

Account credentials must reach the server through private environment settings. codex mcp add --env NAME=value stores values in your local config, so never commit that config or put secrets in a shared command. In TOML, the equivalent server is:

[mcp_servers.senja]
command = "npx"
args = ["-y", "@thenavidm/senja-mcp-cli@latest"]
env_vars = ["SENJA_API_KEY", "SENJA_TOKEN_FILE", "SENJA_ACCOUNTS", "SENJA_DEFAULT_ACCOUNT", "SENJA_READ_ONLY", "SENJA_ALLOW_DESTRUCTIVE"]

env_vars forwards those names from the environment available to Codex. If that environment does not contain them, configure private env settings locally. Codex can also call the CLI directly with SKILL.md and --agent output.

Claude Code

For a user-scoped connection, after privately configuring credentials:

claude mcp add --scope user senja -- npx -y @thenavidm/senja-mcp-cli@latest
claude mcp list

Use the client's private local environment settings for the account variable if they are not inherited. Claude's -e NAME=value registration option writes values into its config; only use it locally through your secret manager, with no shared command transcript. Never place credentials in a project .mcp.json. Reconnect and ask Claude to verify credentials.

Alternatively install the CLI, make SKILL.md available to Claude, and use shell commands. Registering both surfaces is optional.

Claude Desktop

Install the .mcpb extension

  1. Download senja-3.0.0.mcpb from GitHub Releases.
  2. In a supported Claude Desktop build, open Settings > Extensions > Advanced settings > Install Extension… and select it.
  3. Enter a private project API key in the sensitive setting, OR an absolute private token-only file path. Leave the unused method empty. Requests use Authorization: Bearer. Named profiles require private manual runtime settings.
  4. Enable read-only if you want only the 6 read operations. Reconnect and verify the intended project with one deliberate read.

The bundle includes production dependencies and no credentials. Use a regular private token-only file if you prefer file-based credentials. The manifest requires Node 22 or newer from a compatible host. Organization policy may restrict custom extensions. Manual bundle updates require installing the new version; no automatic directory updates are promised. GUI installation remains unverified separately from archive/protocol checks.

Manual config

Open Settings > Developer > Edit Config, or use your platform's config file:

| OS | Typical config path | | --- | --- | | macOS | ~/Library/Application Support/Claude/claude_desktop_config.json | | Windows | %APPDATA%\Claude\claude_desktop_config.json | | Linux | ~/.config/Claude/claude_desktop_config.json; confirm the location through Edit Config in your installed build |

{
  "mcpServers": {
    "senja": {
      "command": "npx",
      "args": ["-y", "@thenavidm/senja-mcp-cli@latest"],
      "env": {
        "SENJA_API_KEY": "YOUR_PRIVATE_API_KEY",
        "SENJA_TOKEN_FILE": ""
      }
    }
  }
}

Replace the placeholders only in your private file. Merge the server entry into an existing mcpServers object instead of replacing other integrations. Fully quit and reopen Claude Desktop. Do not enable an extension and a manual entry with the same name; choose one route.

If a Windows launcher cannot execute npx directly, use "command": "cmd" with "args": ["/c", "npx", "-y", "@thenavidm/senja-mcp-cli@latest"]. An absolute node executable and installed dist/index.js path also avoids launcher/PATH problems.

Cursor

Use private user settings at ~/.cursor/mcp.json, or Settings > Tools & MCP. Cursor documents environment interpolation and envFile support.

{
  "mcpServers": {
    "senja": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@thenavidm/senja-mcp-cli@latest"],
      "env": {
        "SENJA_API_KEY": "${env:SENJA_API_KEY}",
        "SENJA_TOKEN_FILE": "${env:SENJA_TOKEN_FILE}"
      }
    }
  }
}

The environment values must exist for the Cursor process. If you use envFile, keep that file private and outside version control. A project's .cursor/mcp.json must not contain actual credentials. Reconnect the server after saving.

VS Code and Copilot

Use MCP: Open User Configuration. VS Code uses servers and secure inputs, rather than a mcpServers root:

{
  "inputs": [
    {"type": "promptString", "id": "senja-api-token", "description": "Senja API key (leave empty for a private token file)", "password": true},
    {"type": "promptString", "id": "senja-token-file", "description": "Optional private token-file path (leave empty for API key)"}
  ],
  "servers": {
    "senja": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@thenavidm/senja-mcp-cli@latest"],
      "env": {
        "SENJA_API_KEY": "${input:senja-api-token}",
        "SENJA_TOKEN_FILE": "${input:senja-token-file}"
      }
    }
  }
}

Start Senja through the MCP controls, approve trust if prompted, and enter credentials in the private input prompts. Workspace .vscode/mcp.json may contain this placeholder-only structure, but never resolved secret values. Remote development runs the server in the selected remote environment, so local file paths refer to that environment.

Windsurf

Open Cascade's MCP settings or edit the private user file ~/.codeium/windsurf/mcp_config.json. Use the Claude Desktop manual mcpServers block above with your locally configured env values. See Windsurf's current MCP documentation. Restart or reconnect Senja in Cascade; project files must not contain secrets.

Zed

Open Settings > AI > MCP Servers > Add Server > Add Local Server, or your user settings file. Zed uses context_servers:

{
  "context_servers": {
    "senja": {
      "command": "npx",
      "args": ["-y", "@thenavidm/senja-mcp-cli@latest"],
      "env": {
        "SENJA_API_KEY": "YOUR_PRIVATE_API_KEY",
        "SENJA_TOKEN_FILE": ""
      }
    }
  }
}

Enter actual values only in private user settings. Check the active-server indicator before prompting. Do not wrap command and args inside a nested command object from older Zed examples.

Gemini CLI

Merge the Claude Desktop manual mcpServers block into your private ~/.gemini/settings.json. Configure the private credential values locally, then restart Gemini CLI and inspect /mcp. See Gemini CLI's MCP configuration. Its project settings must not contain real credentials. You can instead use the CLI from an agent shell.

Other local stdio clients use the same command and arguments, adapted to their config format. A client that only accepts a remote MCP URL cannot connect directly: this package does not ship a public HTTP listener. ChatGPT's remote connector setup is not a substitute for local stdio installation.

Docker

Build locally from the reviewed source; no prebuilt registry image is claimed:

git clone https://github.com/thenavidm/senja-mcp-cli.git
cd senja-mcp-cli
docker build -t senja-mcp-cli .
docker run --rm -i -e SENJA_API_KEY senja-mcp-cli

Cline and other local MCP clients

Use the client's Add MCP server flow with command npx, arguments -y and @thenavidm/senja-mcp-cli@latest, stdio transport, and private local SENJA_API_KEY or SENJA_TOKEN_FILE settings. UI names depend on the installed client. Reconnect and discover tools before an account call. Browser-only clients need a remote HTTPS connector; use Senja's official server rather than this local stdio command.

5. Check it works

senja-cli --version
senja-cli tools
senja-cli list-accounts --agent
senja-cli doctor
senja-cli doctor --network
senja-cli list-testimonials --limit 1 --agent --select total,testimonials.id

Only the final two commands intentionally contact Senja. The one-item example may return a private ID; use doctor --network if you only need verification metadata. Never create, approve, delete or email a testimonial merely to test installation. Fixtures/protocol discovery, actual provider outcomes, desktop GUI installation and completed Codex usage measurements are distinct checks.

6. Output, flags and exit codes

senja-cli tools --agent
senja-cli list-testimonials --limit 5 --agent --select total,testimonials.id
senja-cli schema send-invites

--agent requests compact JSON with no prompts and never confirms. senja-cli which <words> finds the command for a task. Repeated array flags collect tags; one --recipients or --tasks flag contains one JSON object. Whole native bodies use payload or an absolute regular non-symlink payload_file capped1MiB. Do not mix body methods.

| Exit | Meaning | | --- | --- | | 0 | Success | | 1 | Unexpected error | | 2 | Usage, invalid native input, a refused effect, an unknown command or a hidden write | | 3 | Not found | | 4 | Authentication/permission | | 5 | Native API error | | 7 | Rate limited | | 10 | Missing/invalid private configuration |

7. MCP or CLI and token cost

MCP clients can load all schemas, defer discovery, or load selected schemas; the mode changes input overhead. CLI use still needs command/schema discovery and model-readable results. --agent and --select can reduce formatting/output for an appropriate task, but do not prove smaller total cost.

Measured on 2026-10-05 against 2.0.1, with Claude Code 2.1.286 on Claude Opus 5.5 (one short prompt with and without the server connected, the difference read from the API's own usage figures) and Codex 0.159.3 on gpt-6.1-sol:

| Cost | 2.0.1 | 3.0.0 | | --- | --- | --- | | Claude Code, every tool loaded, every message | 7,900 | 7,551 | | Claude Code's default, tool search, every message | 742 | 742 | | SKILL.md, read once | 2,358 | 2,440 | | Codex over the CLI, one task, median of five | 125,564 | 126,370 | | Codex over MCP, the same task, median of five | 44,983 | 45,393 |

The task was "find the command that sends testimonial invites, and the flags it requires". Every tool loaded costs less because the testimonial integrations and media are written once. Over the CLI, two 3.0.0 runs asked which sends testimonial invites, got the command's help in the answer and took three commands; the other three asked which testimonial invites, which fits three commands alike, and took five, as every 2.0.1 run did. The medians are both five-command runs, 806 tokens apart for 3.0.0's longer general help, and over all five runs 3.0.0 averaged 109,209 against 134,461. Over MCP, Codex now prints create_testimonial with its argument comments, 1,692 characters more. SKILL.md costs 82 more because it says how approval works over MCP and how which finds a command, and what exit codes 1 and 2 cover.

Tool-list bytes or characters divided by four are not API usage, and no other offering was measured.

8. Every tool and argument

list_testimonials

Read one native page with exact current search, tag, approval, language and date/rating filters.

| Argument | Type | Required | Meaning and constraints | | --- | --- | --- | --- | | sort | string | Optional | Native sort field; direction uses order. {"enum": ["date", "rating"]} | | order | string | Optional | {"enum": ["asc", "desc"]} | | approved | boolean | Optional | Exact native/schema value | | rating | integer | Optional | {"minimum": 1, "maximum": 5} | | type | string | Optional | {"enum": ["text", "video"]} | | integration | string | Optional | {"enum": ["twitter", "product_hunt", "google", "facebook", "reddit", "capterra", "g2", "linkedin", "app_store", "trustpilot", "shopify", "play_store", "yelp", "slack", "discord", "apple_podcasts", "telegram", "whatsapp", "instagram", "youtube", "tiktok", "appsumo", "amazon", "zillow", "udemy", "chrome_web_store", "airbnb", "skillshare", "realtor", "sourceforge", "whop", "wordpress", "fiverr", "homestars", "web_page"]} | | tags | array | Optional | {"maxItems": 100} | | query | string | Optional | Native full-text search, including customer name/email; output may contain personal data. | | lang | string | Optional | Native ISO 639 language selector. | | limit | integer | Optional | Native page size. total counts only the current page. {"minimum": 1, "maximum": 1000} | | page | integer | Optional | {"minimum": 1} | | account | string | Optional | Exact configured private account profile label; not a tenant or provider account ID. |

senja-cli list-testimonials --help
senja-cli schema list-testimonials
{
  "type": "object",
  "properties": {
    "sort": {
      "type": "string",
      "enum": [
        "date",
        "rating"
      ],
      "description": "Native sort field; direction uses order."
    },
    "order": {
      "type": "string",
      "enum": [
        "asc",
        "desc"
      ]
    },
    "approved": {
      "type": "boolean"
    },
    "rating": {
      "type": "integer",
      "minimum": 1,
      "maximum": 5
    },
    "type": {
      "type": "string",
      "enum": [
        "text",
        "video"
      ]
    },
    "integration": {
      "type": "string",
      "enum": [
        "twitter",
        "product_hunt",
        "google",
        "facebook",
        "reddit",
        "capterra",
        "g2",
        "linkedin",
        "app_store",
        "trustpilot",
        "shopify",
        "play_store",
        "yelp",
        "slack",
        "discord",
        "apple_podcasts",
        "telegram",
        "whatsapp",
        "instagram",
        "youtube",
        "tiktok",
        "appsumo",
        "amazon",
        "zillow",
        "udemy",
        "chrome_web_store",
        "airbnb",
        "skillshare",
        "realtor",
        "sourceforge",
        "whop",
        "wordpress",
        "fiverr",
        "homestars",
        "web_page"
      ]
    },
    "tags": {
      "type": "array",
      "maxItems": 100,
      "items": {
        "type": "string",
        "minLength": 1,
        "description": "Nonempty tag name."
      }
    },
    "query": {
      "type": "string",
      "minLength": 1,
      "description": "Native full-text search, including customer name/email; output may contain personal data.",
      "maxLength": 10000
    },
    "lang": {
      "type": "string",
      "minLength": 1,
      "description": "Native ISO 639 language selector.",
      "maxLength": 10
    },
    "limit": {
      "type": "integer",
      "minimum": 1,
      "maximum": 1000,
      "description": "Native page size. total counts only the current page."
    },
    "page": {
      "type": "integer",
      "minimum": 1
    },
    "account": {
      "type": "string",
      "description": "Exact configured private account profile label; not a tenant or provider account ID."
    }
  },
  "required": [],
  "additionalProperties": false
}

Native request: GET /testimonials. No native JSON body.

{
  "name": "list_testimonials",
  "method": "GET",
  "path": "/testimonials",
  "title": "List testimonials",
  "description": "Read one native page with exact current search, tag, approval, language and date/rating filters.",
  "group": "testimonials",
  "risk": "read",
  "params": [
    {
      "name": "sort",
      "key": "sort",
      "schema": {
        "type": "string",
        "enum": [
          "date",
          "rating"
        ],
        "description": "Native sort field; direction uses order."
      },
      "in": "query",
      "required": false,
      "style": "form",
      "explode": true
    },
    {
      "name": "order",
      "key": "order",
      "schema": {
        "type": "string",
        "enum": [
          "asc",
          "desc"
        ]
      },
      "in": "query",
      "required": false,
      "style": "form",
      "explode": true
    },
    {
      "name": "approved",
      "key": "approved",
      "schema": {
        "type": "boolean"
      },
      "in": "query",
      "required": false,
      "style": "form",
      "explode": true
    },
    {
      "name": "rating",
      "key": "rating",
      "schema": {
        "type": "integer",
        "minimum": 1,
        "maximum": 5
      },
      "in": "query",
      "required": false,
      "style": "form",
      "explode": true
    },
    {
      "name": "type",
      "key": "type",
      "schema": {
        "type": "string",
        "enum": [
          "text",
          "video"
        ]
      },
      "in": "query",
      "required": false,
      "style": "form",
      "explode": true
    },
    {
      "name": "integration",
      "key": "integration",
      "schema": {
        "type": "string",
        "enum": [
          "twitter",
          "product_hunt",
          "google",
          "facebook",
          "reddit",
          "capterra",
          "g2",
          "linkedin",
          "app_store",
          "trustpilot",
          "shopify",
          "play_store",
          "yelp",
          "slack",
          "discord",
          "apple_podcasts",
          "telegram",
          "whatsapp",
          "instagram",
          "youtube",
          "tiktok",
          "appsumo",
          "amazon",
          "zillow",
          "udemy",
          "chrome_web_store",
          "airbnb",
          "skillshare",
          "realtor",
          "sourceforge",
          "whop",
          "wordpress",
          "fiverr",
          "homestars",
          "web_page"
        ]
      },
      "in": "query",
      "required": false,
      "style": "form",
      "explode": true
    },
    {
      "name": "tags",
      "key": "tags",
      "schema": {
        "type": "array",
        "maxItems": 100,
        "items": {
          "type": "string",
          "minLength": 1,
          "description": "Nonempty tag name."
        }
      },
      "in": "query",
      "required": false,
      "style": "form",
      "explode": true
    },
    {
      "name": "query",
      "key": "query",
      "schema": {
        "type": "string",
        "minLength": 1,
        "description": "Native full-text search, including customer name/email; output may contain personal data.",
        "maxLength": 10000
      },
      "in": "query",
      "required": false,
      "style": "form",
      "explode": true
    },
    {
      "name": "lang",
      "key": "lang",
      "schema": {
        "type": "string",
        "minLength": 1,
        "description": "Native ISO 639 language selector.",
        "maxLength": 10
      },
      "in": "query",
      "required": false,
      "style": "form",
      "explode": true
    },
    {
      "name": "limit",
      "key": "limit",
      "schema": {
        "type": "integer",
        "minimum": 1,
        "maximum": 1000,
        "description": "Native page size. total counts only the current page."
      },
      "in": "query",
      "required": false,
      "style": "form",
      "explode": true
    },
    {
      "name": "page",
      "key": "page",
      "schema": {
        "type": "integer",
        "minimum": 1
      },
      "in": "query",
      "required": false,
      "style": "form",
      "explode": true
    }
  ],
  "bodySchema": null,
  "bodyRequired": false,
  "privateOutput": false
}

get_testimonial

Read one exact testimonial, including native video metadata and public/dashboard links.

| Argument | Type | Required | Meaning and constraints | | --- | --- | --- | --- | | testimonial_id | string | Required | Exact testimonial ID. No slash, traversal or arbitrary URL. | | account | string | Optional | Exact configured private account profile label; not a tenant or provider account ID. |

senja-cli get-testimonial --help
senja-cli schema get-testimonial
{
  "type": "object",
  "properties": {
    "testimonial_id": {
      "type": "string",
      "minLength": 1,
      "description": "Exact testimonial ID. No slash, traversal or arbitrary URL."
    },
    "account": {
      "type": "string",
      "description": "Exact configured private account profile label; not a tenant or provider account ID."
    }
  },
  "required": [
    "testimonial_id"
  ],
  "additionalProperties": false
}

Native request: GET /testimonials/{testimonial_id}. No native JSON body.

{
  "name": "get_testimonial",
  "method": "GET",
  "path": "/testimonials/{testimonial_id}",
  "title": "Read one testimonial",
  "description": "Read one exact testimonial, including native video metadata and public/dashboard links.",
  "group": "testimonials",
  "risk": "read",
  "params": [
    {
      "name": "testimonial_id",
      "key": "testimonial_id",
      "schema": {
        "type": "string",
        "minLength": 1,
        "description": "Exact testimonial ID. No slash, traversal or arbitrary URL."
      },
      "in": "path",
      "required": true,
      "style": "form",
      "explode": true
    }
  ],
  "bodySchema": null,
  "bodyRequired": false,
  "privateOutput": false
}

create_testimonial

Create one text/video testimonial from an authorized existing customer statement. Explicit approval is required.

| Argument | Type | Required | Meaning and constraints | | --- | --- | --- | --- | | title | string | Optional | Exact native/schema value | | text | string | Optional | Exact native/schema value | | customer_name | string | Optional | Exact native/schema value | | customer_company | string | Optional | Exact native/schema value | | customer_tagline | string | Optional | Exact native/schema value | | customer_username | string | Optional | Exact native/schema value | | form_id | string | Optional | Exact native/schema value | | url | string | Optional | HTTPS URL without embedded credentials; provider retrieves media where supported. {"format": "uri"} | | thumbnail_url | string | Optional | HTTPS URL without embedded credentials; provider retrieves media where supported. {"format": "uri"} | | customer_avatar | string | Optional | HTTPS URL without embedded credentials; provider retrieves media where supported. {"format": "uri"} | | customer_company_logo | string | Optional | HTTPS URL without embedded credentials; provider retrieves media where supported. {"format": "uri"} | | customer_url | string | Optional | HTTPS URL without embedded credentials; provider retrieves media where supported. {"format": "uri"} | | video_url | string | Optional | HTTPS URL without embedded credentials; provider retrieves media where supported. {"format": "uri"} | | type | string | Optional | {"enum": ["text", "video"]} | | customer_email | string | Optional | {"format": "email"} | | rating | integer | Optional | {"minimum": 1, "maximum": 5} | | date | string | Optional | {"format": "date-time"} | | approved | boolean | Optional | Explicitly true publishes the testimonial; false keeps it pending. | | integration | string | Optional | {"enum": ["twitter", "product_hunt", "google", "facebook", "reddit", "capterra", "g2", "linkedin", "app_store", "trustpilot", "shopify", "play_store", "yelp", "slack", "discord", "apple_podcasts", "telegram", "whatsapp", "instagram", "youtube", "tiktok", "appsumo", "amazon", "zillow", "udemy", "chrome_web_store", "airbnb", "skillshare", "realtor", "sourceforge", "whop", "wordpress", "fiverr", "homestars", "web_page"]} | | tags | array | Optional | {"maxItems": 100} | | media | array | Optional | {"maxItems": 100} | | media[].alt | string | Optional | Exact native/schema value | | media[].url | string | Required | {"format": "uri"} | | media[].type | string | Required | {"enum": ["image", "video"]} | | account | string | Optional | Exact configured private account profile label; not a tenant or provider account ID. | | confirm | boolean | Optional | Set true only when the user asked for exactly this action. | | payload | object | Optional | Complete native JSON body; do not mix with body flags or payload_file. Arrays use repeated JSON object flags or a whole native array in a private file. | | payload.title | string | Optional | Exact native/schema value | | payload.text | string | Optional | Exact native/schema value | | payload.customer_name | string | Required | Exact native/schema value | | payload.customer_company | string | Optional | Exact native/schema value | | payload.customer_tagline | string | Optional | Exact native/schema value | | payload.customer_username | string | Optional | Exact native/schema value | | payload.form_id | string | Optional | Exact native/schema value | | payload.url | string | Optional | HTTPS URL without embedded credentials; provider retrieves media where supported. {"format": "uri"} | | payload.thumbnail_url | string | Optional | HTTPS URL without embedded credentials; provider retrieves media where supported. {"format": "uri"} | | payload.customer_avatar | string | Optional | HTTPS URL without embedded credentials; provider retrieves media where supported. {"format": "uri"} | | payload.customer_company_logo | string | Optional | HTTPS URL without embedded credentials; provider retrieves media where supported. {"format": "uri"} | | payload.customer_url | string | Optional | HTTPS URL without embedded credentials; provider retrieves media where supported. {"format": "uri"} | | payload.video_url | string | Optional | HTTPS URL without embedded credentials; provider retrieves media where supported. {"format": "uri"} | | payload.type | string | Required | {"enum": ["text", "video"]} | | payload.customer_email | string | Optional | {"format": "email"} | | payload.rating | integer | Optional | {"minimum": 1, "maximum": 5} | | payload.date | string | Optional | {"format": "date-time"} | | payload.approved | boolean | Optional | Explicitly true publishes the testimonial; false keeps it pending. | | payload.integration | string | Optional | {"enum": ["twitter", "product_hunt", "google", "facebook", "reddit", "capterra", "g2", "linkedin", "app_store", "trustpilot", "shopify", "play_store", "yelp", "slack", "discord", "apple_podcasts", "telegram", "whatsapp", "instagram", "youtube", "tiktok", "appsumo", "amazon", "zillow", "udemy", "chrome_web_store", "airbnb", "skillshare", "realtor", "sourceforge", "whop", "wordpress", "fiverr", "homestars", "web_page"]} | | payload.tags | array | Optional | {"maxItems": 100} | | payload.media | array | Optional | {"maxItems": 100} | | payload.media[].alt | string | Optional | Exact native/schema value | | payload.media[].url | string | Required | {"format": "uri"} | | payload.media[].type | string | Required | {"enum": ["image", "video"]} | | payload_file | string | Optional | Absolute regular non-symlink JSON body file, at most 1 MiB. Cannot mix with payload/body flags. |

senja-cli create-testimonial --help
senja-cli schema create-testimonial
{
  "type": "object",
  "properties": {
    "title": {
      "type": "string",
      "minLength": 1,
      "description": ""
    },
    "text": {
      "type": "string",
      "minLength": 1,
      "description": ""
    },
    "customer_name": {
      "type": "string",
      "minLength": 1,
      "description": ""
    },
    "customer_company": {
      "type": "string",
      "minLength": 1,
      "description": ""
    },
    "customer_tagline": {
      "type": "string",
      "minLength": 1,
      "description": ""
    },
    "customer_username": {
      "type": "string",
      "minLength": 1,
      "description": ""
    },
    "form_id": {
      "type": "string",
      "minLength": 1,
      "description": ""
    },
    "url": {
      "type": "string",
      "minLength": 1,
      "description": "HTTPS URL without embedded credentials; provider retrieves media where supported.",
      "format": "uri"
    },
    "thumbnail_url": {
      "type": "string",
      "minLength": 1,
      "description": "HTTPS URL without embedded credentials; provider retrieves media where supported.",
      "format": "uri"
    },
    "customer_avatar": {
      "type": "string",
      "minLength": 1,
      "description": "HTTPS URL without embedded credentials; provider retrieves media where supported.",
      "format": "uri"
    },
    "customer_company_logo": {
      "type": "string",
      "minLength": 1,
      "description": "HTTPS URL without embedded credentials; provider retrieves media where supported.",
      "format": "uri"
    },
    "customer_url": {
      "type": "string",
      "minLength": 1,
      "description": "HTTPS URL without embedded credentials; provider retrieves media where supported.",
      "format": "uri"
    },
    "video_url": {
      "type": "string",
      "minLength": 1,
      "description": "HTTPS URL without embedded credentials; provider retrieves media where supported.",
      "format": "uri"
    },
    "type": {
      "type": "string",
      "enum": [
        "text",
        "video"
      ]
    },
    "customer_email": {
      "type": "string",
      "minLength": 1,
      "description": "",
      "format": "email"
    },
    "rating": {
      "type": "integer",
      "minimum": 1,
      "maximum": 5
    },
    "date": {
      "type": "string",
      "minLength": 1,
      "description": "",
      "format": "date-time"
    },
    "approved": {
      "type": "boolean",
      "description": "Explicitly true publishes the testimonial; false keeps it pending."
    },
    "integration": {
      "type": "string",
      "enum": [
        "twitter",
        "product_hunt",
        "google",
        "facebook",
        "reddit",
        "capterra",
        "g2",
        "linkedin",
        "app_store",
        "trustpilot",
        "shopify",
        "play_store",
        "yelp",
        "slack",
        "discord",
        "apple_podcasts",
        "telegram",
        "whatsapp",
        "instagram",
        "youtube",
        "tiktok",
        "appsumo",
        "amazon",
        "zillow",
        "udemy",
        "chrome_web_store",
        "airbnb",
        "skillshare",
        "realtor",
        "sourceforge",
        "whop",
        "wordpress",
        "fiverr",
        "homestars",
        "web_page"
      ]
    },
    "tags": {
      "type": "array",
      "maxItems": 100,
      "items": {
        "type": "string",
        "minLength": 1,
        "description": "Nonempty tag name."
      }
    },
    "media": {
      "type": "array",
      "maxItems": 100,
      "items": {
        "type": "object",
        "properties": {
          "alt": {
            "type": "string",
            "minLength": 1,
            "description": ""
          },
          "url": {
            "type": "string",
            "minLength": 1,
            "description": "",
            "format": "uri"
          },
          "type": {
            "type": "string",
            "enum": [
              "image",
              "video"
            ]
          }
        },
        "required": [
          "url",
          "type"
        ],
        "additionalProperties": false
      }
    },
    "account": {
      "type": "string",
      "description": "Exact configured private account profile label; not a tenant or provider account ID."
    },
    "confirm": {
      "type": "boolean",
      "description": "Must be true for the requested mutation or exclusive private output file."
    },
    "payload": {
      "type": "object",
      "properties": {
        "title": {
          "type": "string",
          "minLength": 1,
          "description": ""
        },
        "text": {
          "type": "string",
          "minLength": 1,
          "description": ""
        },
        "customer_name": {
          "type": "string",
          "minLength": 1,
          "description": ""
        },
        "customer_company": {
          "type": "string",
          "minLength": 1,
          "description": ""
        },
        "customer_tagline": {
          "type": "string",
          "minLength": 1,
          "description": ""
        },
        "customer_username": {
          "type": "string",
          "minLength": 1,
          "description": ""
        },
        "form_id": {
          "type": "string",
          "minLength": 1,
          "description": ""
        },
        "url": {
          "type": "string",
          "minLength": 1,
          "description": "HTTPS URL without embedded credentials; provider retrieves media where supported.",
          "format": "uri"
        },
        "thumbnail_url": {
          "type": "string",
          "minLength": 1,
          "description": "HTTPS URL without embedded credentials; provider retrieves media where supported.",
          "format": "uri"
        },
        "customer_avatar": {
          "type": "string",
          "minLength": 1,
          "description": "HTTPS URL without embedded credentials; provider retrieves media where supported.",
          "format": "uri"
        },
        "customer_company_logo": {
          "type": "string",
          "minLength": 1,
          "description": "HTTPS URL without embedded credentials; provider retrieves media where supported.",
          "format": "uri"
        },
        "customer_url": {
          "type": "string",
          "minLength": 1,
          "description": "HTTPS URL without embedded credentials; provider retrieves media where supported.",
          "format": "uri"
        },
        "video_url": {
          "type": "string",
          "minLength": 1,
          "description": "HTTPS URL without embedded credentials; provider retrieves media where supported.",
          "format": "uri"
        },
        "type": {
          "type": "string",
          "enum": [
            "text",
            "video"
          ]
        },
        "customer_email": {
          "type": "string",
          "minLength": 1,
          "description": "",
          "format": "email"
        },
        "rating": {
          "type": "integer",
          "minimum": 1,
          "maximum": 5
        },
        "date": {
          "type": "string",
          "minLength": 1,
          "description": "",
          "format": "date-time"
        },
        "approved": {
          "type": "boolean",
          "description": "Explicitly true publishes the testimonial; false keeps it pending."
        },
        "integration": {
          "type": "string",
          "enum": [
            "twitter",
            "product_hunt",
            "google",
            "facebook",
            "reddit",
            "capterra",
            "g2",
            "linkedin",
            "app_store",
            "trustpilot",
            "shopify",
            "play_store",
            "yelp",
            "slack",
            "discord",
            "apple_podcasts",
            "telegram",
            "whatsapp",
            "instagram",
            "youtube",
            "tiktok",
            "appsumo",
            "amazon",
            "zillow",
            "udemy",
            "chrome_web_store",
            "airbnb",
            "skillshare",
            "realtor",
            "sourceforge",
            "whop",
            "wordpress",
            "fiverr",
            "homestars",
            "web_page"
          ]
        },
        "tags": {
          "type": "array",
          "maxItems": 100,
          "items": {
            "type": "string",
            "minLength": 1,
            "description": "Nonempty tag name."
          }
        },
        "media": {
          "type": "array",
          "maxItems": 100,
          "items": {
            "type": "object",
            "properties": {
              "alt": {
                "type": "string",
                "minLength": 1,
                "description": ""
              },
              "url": {
                "type": "string",
                "minLength": 1,
                "description": "",
                "format": "uri"
              },
              "type": {
                "type": "string",
                "enum": [
                  "image",
                  "video"
                ]
              }
            },
            "required": [
              "url",
              "type"
            ],
            "additionalProperties": false
          }
        }
      },
      "required": [
        "type",
        "customer_name"
      ],
      "additionalProperties": false,
      "description": "Complete native JSON body; do not mix with body flags or payload_file. Arrays use repeated JSON object flags or a whole native array in a private file."
    },
    "payload_file": {
      "type": "string",
      "minLength": 1,
      "description": "Absolute regular non-symlink JSON body file, at most 1 MiB. Cannot mix with payload/body flags."
    }
  },
  "required": [],
  "additionalProperties": false
}

Native request: POST /testimonials. Provide native body fields OR payload OR payload_file, never mixed. Native body required: type, customer_name

{
  "name": "create_testimonial",
  "method": "POST",
  "path": "/testimonials",
  "title": "Import a testimonial",
  "description": "Create one text/video testimonial from an authorized existing customer statement. Explicit approval is required.",
  "group": "testimonials",
  "risk": "destructive",
  "params": [],
  "bodySchema": {
    "type": "object",
    "properties": {
      "title": {
        "type": "string",
        "minLength": 1,
        "description": ""
      },
      "text": {
        "type": "string",
        "minLength": 1,
        "description": ""
      },
      "customer_name": {
        "type": "string",
        "minLength": 1,
        "description": ""
      },
      "customer_company": {
        "type": "string",
        "minLength": 1,
        "description": ""
      },
      "customer_tagline": {
        "type": "string",
        "minLength": 1,
        "description": ""
      },
      "customer_username": {
        "type": "string",
        "minLength": 1,
        "description": ""
      },
      "form_id": {
        "type": "string",
        "minLength": 1,
        "description": ""
      },
      "url": {
        "type": "string",
        "minLength": 1,
        "description": "HTTPS URL without embedded credentials; provider retrieves media where supported.",
        "format": "uri"
      },
      "thumbnail_url": {
        "type": "string",
        "minLength": 1,
        "description": "HTTPS URL without embedded credentials; provider retrieves media where supported.",
        "format": "uri"
      },
      "customer_avatar": {
        "type": "string",
        "minLength": 1,
        "description": "HTTPS URL without embedded credentials; provider retrieves media where supported.",
        "format": "uri"
      },
      "customer_company_logo": {
        "type": "string",
        "minLength": 1,
        "description": "HTTPS URL without embedded credentials; provider retrieves media where supported.",
        "format": "uri"
      },
      "customer_url": {
        "type": "string",
        "minLength": 1,
        "description": "HTTPS URL without embedded credentials; provider retrieves media where supported.",
        "format": "uri"
      },
      "video_url": {
        "type": "string",
        "minLength": 1,
        "description": "HTTPS URL without embedded credentials; provider retrieves media where supported.",
        "format": "uri"
      },
      "type": {
        "type": "string",
        "enum": [
          "text",
          "video"
        ]
      },
      "customer_email": {
        "type": "string",
        "minLength": 1,
        "description": "",
        "format": "email"
      },
      "rating": {
        "type": "integer",
        "minimum": 1,
        "maximum": 5
      },
      "date": {
        "type": "string",
        "minLength": 1,
        "description": "",
        "format": "date-time"
      },
      "approved": {
        "type": "boolean",
        "description": "Explicitly true publishes the testimonial; false keeps it pending."
      },
      "integration": {
        "type": "string",
        "enum": [
          "twitter",
          "product_hunt",
          "google",
          "facebook",
          "reddit",
          "capterra",
          "g2",
          "linkedin",
          "app_store",
          "trustpilot",
          "shopify",
          "play_store",
          "yelp",
          "slack",
          "discord",
          "apple_podcasts",
          "telegram",
          "whatsapp",
          "instagram",
          "youtube",
          "tiktok",
          "appsumo",
          "amazon",
          "zillow",
          "udemy",
          "chrome_web_store",
          "airbnb",
          "skillshare",
          "realtor",
          "sourceforge",
          "whop",
          "wordpress",
          "fiverr",
          "homestars",
          "web_page"
        ]
      },
      "tags": {
        "type": "array",
        "maxItems": 100,
        "items": {
          "type": "string",
          "minLength": 1,
          "description": "Nonempty tag name."
        }
      },
      "media": {
        "type": "array",
        "maxItems": 100,
        "items": {
          "type": "object",
          "properties": {
            "alt": {
              "type": "string",
              "minLength": 1,
              "description": ""
            },
            "url": {
              "type": "string",
              "minLength": 1,
              "description": "",
              "format": "uri"
            },
            "type": {
              "type": "string",
              "enum": [
                "image",
                "video"
              ]
            }
          },
          "required": [
            "url",
            "type"
          ],
          "additionalProperties": false
        }
      }
    },
    "required": [
      "type",
      "customer_name"
    ],
    "additionalProperties": false
  },
  "bodyRequired": true,
  "privateOutput": false
}

update_testimonial

Change only native approval status and tag additions/removals. Text, rating and customer edits remain dashboard-only.

| Argument | Type | Required | Meaning and constraints | | --- | --- | --- | --- | | testimonial_id | string | Required | Exact testimonial ID. No slash, traversal or arbitrary URL. | | approved | boolean | Optional | Exact native/schema value | | add_tags | array | Optional | {"maxItems": 100} | | remove_tags | array | Optional | {"maxItems": 100} | | account | string | Optional | Exact configured private account profile label; not a tenant or provider account ID. | | confirm | boolean | Optional | Set true only when the user asked for exactly this action. | | payload | object | Optional | Complete native JSON body; do not mix with body flags or payload_file. Arrays use repeated JSON object flags or a whole native array in a private file. | | payload.approved | boolean | Optional | Exact native/schema value | | payload.add_tags | array | Optional | {"maxItems": 100} | | payload.remove_tags | array | Optional | {"maxItems": 100} | | payload_file | string | Optional | Absolute regular non-symlink JSON body file, at most 1 MiB. Cannot mix with payload/body flags. |

senja-cli update-testimonial --help
senja-cli schema update-testimonial
{
  "type": "object",
  "properties": {
    "testimonial_id": {
      "type": "string",
      "minLength": 1,
      "description": "Exact testimonial ID. No slash, traversal or arbitrary URL."
    },
    "approved": {
      "type": "boolean"
    },
    "add_tags": {
      "type": "array",
      "maxItems": 100,
      "items": {
        "type": "string",
        "minLength": 1,
        "description": "Nonempty tag name."
      }
    },
    "remove_tags": {
      "type": "array",
      "maxItems": 100,
      "items": {
        "type": "string",
        "minLength": 1,
        "description": "Nonempty tag name."
      }
    },
    "account": {
      "type": "string",
      "description": "Exact configured private account profile label; not a tenant or provider account ID."
    },
    "confirm": {
      "type": "boolean",
      "description": "Must be true for the requested mutation or exclusive private output file."
    },
    "payload": {
      "type": "object",
      "properties": {
        "approved": {
          "type": "boolean"
        },
        "add_tags": {
          "type": "array",
          "maxItems": 100,
          "items": {
            "type": "string",
            "minLength": 1,
            "description": "Nonempty tag name."
          }
        },
        "remove_tags": {
          "type": "array",
          "maxItems": 100,
          "items": {
            "type": "string",
            "minLength": 1,
            "description": "Nonempty tag name."
          }
        }
      },
      "required": [],
      "additionalProperties": false,
      "description": "Complete native JSON body; do not mix with body flags or payload_file. Arrays use repeated JSON object flags or a whole native array in a private file."
    },
    "payload_file": {
      "type": "string",
      "minLength": 1,
      "description": "Absolute regular non-symlink JSON body file, at most 1 MiB. Cannot mix with payload/body flags."
    }
  },
  "required": [
    "testimonial_id"
  ],
  "additionalProperties": false
}

Native request: PATCH /testimonials/{testimonial_id}. Provide native body fields OR payload OR payload_file, never mixed. Native body requires at least one approval or nonempty tag change.

{
  "name": "update_testimonial",
  "method": "PATCH",
  "path": "/testimonials/{testimonial_id}",
  "title": "Update approval or tags",
  "description": "Change only native approval status and tag additions/removals. Text, rating and customer edits remain dashboard-only.",
  "group": "testimonials",
  "risk": "destructive",
  "params": [
    {
      "name": "testimonial_id",
      "key": "testimonial_id",
      "schema": {
        "type": "string",
        "minLength": 1,
        "description": "Exact testimonial ID. No slash, traversal or arbitrary URL."
      },
      "in": "path",
      "required": true,
      "style": "form",
      "explode": true
    }
  ],
  "bodySchema": {
    "type": "object",
    "properties": {
      "approved": {
        "type": "boolean"
      },
      "add_tags": {
        "type": "array",
        "maxItems": 100,
        "items": {
          "type": "string",
          "minLength": 1,
          "description": "Nonempty tag name."
        }
      },
      "remove_tags": {
        "type": "array",
        "maxItems": 100,
        "items": {
          "type": "string",
          "minLength": 1,
          "description": "Nonempty tag name."
        }
      }
    },
    "required": [],
    "additionalProperties": false
  },
  "bodyRequired": true,
  "privateOutput": false
}

delete_testimonial

Permanently delete exactly the requested testimonial. Irreversible; confirmation required.

| Argument | Type | Required | Meaning and constraints | | --- | --- | --- | --- | | testimonial_id | string | Required | Exact testimonial ID. No slash, traversal or arbitrary URL. | | account | string | Optional | Exact configured private account profile label; not a tenant or provider account ID. | | confirm | boolean | Optional | Set true only when the user asked for exactly this action. |

senja-cli delete-testimonial --help
senja-cli schema delete-testimonial
{
  "type": "object",
  "properties": {
    "testimonial_id": {
      "type": "string",
      "minLength": 1,
      "description": "Exact testimonial ID. No slash, traversal or arbitrary URL."
    },
    "account": {
      "type": "string",
      "description": "Exact configured private account profile label; not a tenant or provider account ID."
    },
    "confirm": {
      "type": "boolean",
      "description": "Must be true for the requested mutation or exclusive private output file."
    }
  },
  "required": [
    "testimonial_id"
  ],
  "additionalProperties": false
}

Native request: DELETE /testimonials/{testimonial_id}. No native JSON body.

{
  "name": "delete_testimonial",
  "method": "DELETE",
  "path": "/testimonials/{testimonial_id}",
  "title": "Delete one testimonial",
  "description": "Permanently delete exactly the requested testimonial. Irreversible; confirmation required.",
  "group": "testimonials",
  "risk": "destructive",
  "params": [
    {
      "name": "testimonial_id",
      "key": "testimonial_id",
      "schema": {
        "type": "string",
        "minLength": 1,
        "description": "Exact testimonial ID. No slash, traversal or arbitrary URL."
      },
      "in": "path",
      "required": true,
      "style": "form",
      "explode": true
    }
  ],
  "bodySchema": null,
  "bodyRequired": false,
  "privateOutput": false
}

list_links

Read native form, widget, Wall of Love, quick-link, case-study and sizzle-reel groups with their IDs and URLs.

| Argument | Type | Required | Meaning and constraints | | --- | --- | --- | --- | | account | string | Optional | Exact configured private account profile label; not a tenant or provider account ID. |

senja-cli list-links --help
senja-cli schema list-links
{
  "type": "object",
  "properties": {
    "account": {
      "type": "string",
      "description": "Exact configured private account profile label; not a tenant or provider account ID."
    }
  },
  "required": [],
  "additionalProperties": false
}

Native request: GET /links. No native JSON body.

{
  "name": "list_links",
  "method": "GET",
  "path": "/links",
  "title": "Read project links",
  "description": "Read native form, widget, Wall of Love, quick-link, case-study and sizzle-reel groups with their IDs and URLs.",
  "group": "project_links",
  "risk": "read",
  "params": [],
  "bodySchema": null,
  "bodyRequired": false,
  "privateOutput": false
}

send_invites

Send email invites using a selected form and its existing follow-up sequence. Local cap100 recipients, not a documented provider quota.

| Argument | Type | Required | Meaning and constraints | | --- | --- | --- | --- | | form_id | string | Optional | Exact forms[].id from list_links. | | recipients | array | Optional | {"minItems": 1, "maxItems": 100} | | recipients[].email | string | Required | {"format": "email"} | | recipients[].name | string | Optional | Exact native/schema value | | account | string | Optional | Exact configured private account profile label; not a tenant or provider account ID. | | confirm | boolean | Optional | Set true only when the user asked for exactly this action. | | payload | object | Optional | Complete native JSON body; do not mix with body flags or payload_file. Arrays use repeated JSON object flags or a whole native array in a private file. | | payload.form_id | string | Required | Exact forms[].id from list_links. | | payload.recipients | array | Required | {"minItems": 1, "maxItems": 100} | | payload.recipients[].email | string | Required | {"format": "email"} | | payload.recipients[].name | string | Optional | Exact native/schema value | | payload_file | string | Optional | Absolute regular non-symlink JSON body file, at most 1 MiB. Cannot mix with payload/body flags. |

senja-cli send-invites --help
senja-cli schema send-invites
{
  "type": "object",
  "properties": {
    "form_id": {
      "type": "string",
      "minLength": 1,
      "description": "Exact forms[].id from list_links."
    },
    "recipients": {
      "type": "array",
      "minItems": 1,
      "maxItems": 100,
      "items": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "minLength": 1,
            "description": "",
            "format": "email"
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "description": ""
          }
        },
        "required": [
          "email"
        ],
        "additionalProperties": false
      }
    },
    "account": {
      "type": "string",
      "description": "Exact configured private account profile label; not a tenant or provider account ID."
    },
    "confirm": {
      "type": "boolean",
      "description": "Must be true for the requested mutation or exclusive private output file."
    },
    "payload": {
      "type": "object",
      "properties": {
        "form_id": {
          "type": "string",
          "minLength": 1,
          "description": "Exact forms[].id from list_links."
        },
        "recipients": {
          "type": "array",
          "minItems": 1,
          "maxItems": 100,
          "items": {
            "type": "object",
            "properties": {
              "email": {
                "type": "string",
                "minLength": 1,
                "description": "",
                "format": "email"
              },
              "name": {
                "type": "string",
                "minLength": 1,
                "description": ""
              }
            },
            "required": [
              "email"
            ],
            "additionalProperties": false
          }
        }
      },
      "required": [
        "form_id",
        "recipients"
      ],
      "additionalProperties": false,
      "description": "Complete native JSON body; do not mix with body flags or payload_file. Arrays use repeated JSON object flags or a whole native array in a private file."
    },
    "payload_file": {
      "type": "string",
      "minLength": 1,
      "description": "Absolute regular non-symlink JSON body file, at most 1 MiB. Cannot mix with payload/body flags."
    }
  },
  "required": [],
  "additionalProperties": false
}

Native request: POST /invites. Provide native body fields OR payload OR payload_file, never mixed. Native body required: form_id, recipients

{
  "name": "send_invites",
  "method": "POST",
  "path": "/i