thoughtleaders-cli 0.6.10__tar.gz → 0.6.11__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/.claude-plugin/plugin.json +1 -1
  2. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/AGENTS.md +1 -0
  3. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/PKG-INFO +1 -1
  4. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/pyproject.toml +1 -1
  5. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/skills/tl/SKILL.md +3 -11
  6. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/src/tl_cli/__init__.py +1 -1
  7. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/src/tl_cli/commands/channels.py +3 -9
  8. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/src/tl_cli/commands/sponsorships.py +3 -9
  9. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/.claude-plugin/marketplace.json +0 -0
  10. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/.github/workflows/python-publish.yml +0 -0
  11. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/.gitignore +0 -0
  12. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/CLAUDE.md +0 -0
  13. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/LICENSE +0 -0
  14. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/README.md +0 -0
  15. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/agents/tl-analyst.md +0 -0
  16. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/commands/tl-balance.md +0 -0
  17. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/commands/tl-reports.md +0 -0
  18. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/commands/tl-sponsorships.md +0 -0
  19. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/commands/tl.md +0 -0
  20. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/docs/architecture.md +0 -0
  21. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/hooks/hooks.json +0 -0
  22. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/hooks/scripts/post-usage.sh +0 -0
  23. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/hooks/scripts/pre-check.sh +0 -0
  24. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/skills/tl/references/business-glossary.md +0 -0
  25. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/skills/tl/references/elasticsearch-schema.md +0 -0
  26. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/skills/tl/references/firebolt-schema.md +0 -0
  27. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/skills/tl/references/postgres-schema.md +0 -0
  28. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/skills/tl-report-builder/SKILL.md +0 -0
  29. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/skills/tl-report-builder/examples/e2e_findings.md +0 -0
  30. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/skills/tl-report-builder/examples/golden_queries.md +0 -0
  31. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/skills/tl-report-builder/references/columns_brands.md +0 -0
  32. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/skills/tl-report-builder/references/columns_channels.md +0 -0
  33. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/skills/tl-report-builder/references/columns_content.md +0 -0
  34. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/skills/tl-report-builder/references/columns_sponsorships.md +0 -0
  35. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/skills/tl-report-builder/references/intelligence_filterset_schema.json +0 -0
  36. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/skills/tl-report-builder/references/intelligence_widget_schema.json +0 -0
  37. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/skills/tl-report-builder/references/report_glossary.md +0 -0
  38. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/skills/tl-report-builder/references/sortable_columns.json +0 -0
  39. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/skills/tl-report-builder/references/sponsorship_filterset_schema.json +0 -0
  40. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/skills/tl-report-builder/references/sponsorship_widget_schema.json +0 -0
  41. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/skills/tl-report-builder/references/widgets.md +0 -0
  42. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/skills/tl-report-builder/tools/column_builder.md +0 -0
  43. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/skills/tl-report-builder/tools/database_query.md +0 -0
  44. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/skills/tl-report-builder/tools/keyword_research.md +0 -0
  45. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/skills/tl-report-builder/tools/name_resolver.md +0 -0
  46. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/skills/tl-report-builder/tools/sample_judge.md +0 -0
  47. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/skills/tl-report-builder/tools/similar_channels.md +0 -0
  48. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/skills/tl-report-builder/tools/topic_matcher.md +0 -0
  49. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/skills/tl-report-builder/tools/widget_builder.md +0 -0
  50. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/src/tl_cli/_completions.py +0 -0
  51. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/src/tl_cli/auth/__init__.py +0 -0
  52. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/src/tl_cli/auth/commands.py +0 -0
  53. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/src/tl_cli/auth/login.py +0 -0
  54. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/src/tl_cli/auth/pkce.py +0 -0
  55. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/src/tl_cli/auth/token_store.py +0 -0
  56. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/src/tl_cli/client/__init__.py +0 -0
  57. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/src/tl_cli/client/errors.py +0 -0
  58. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/src/tl_cli/client/http.py +0 -0
  59. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/src/tl_cli/commands/__init__.py +0 -0
  60. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/src/tl_cli/commands/_comments_common.py +0 -0
  61. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/src/tl_cli/commands/ask.py +0 -0
  62. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/src/tl_cli/commands/balance.py +0 -0
  63. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/src/tl_cli/commands/brands.py +0 -0
  64. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/src/tl_cli/commands/changelog.py +0 -0
  65. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/src/tl_cli/commands/db.py +0 -0
  66. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/src/tl_cli/commands/deals.py +0 -0
  67. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/src/tl_cli/commands/describe.py +0 -0
  68. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/src/tl_cli/commands/doctor.py +0 -0
  69. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/src/tl_cli/commands/matches.py +0 -0
  70. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/src/tl_cli/commands/proposals.py +0 -0
  71. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/src/tl_cli/commands/recommender.py +0 -0
  72. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/src/tl_cli/commands/reports.py +0 -0
  73. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/src/tl_cli/commands/schema.py +0 -0
  74. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/src/tl_cli/commands/setup.py +0 -0
  75. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/src/tl_cli/commands/snapshots.py +0 -0
  76. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/src/tl_cli/commands/uploads.py +0 -0
  77. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/src/tl_cli/commands/whoami.py +0 -0
  78. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/src/tl_cli/config.py +0 -0
  79. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/src/tl_cli/filters.py +0 -0
  80. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/src/tl_cli/hints.py +0 -0
  81. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/src/tl_cli/main.py +0 -0
  82. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/src/tl_cli/output/__init__.py +0 -0
  83. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/src/tl_cli/output/formatter.py +0 -0
  84. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/src/tl_cli/self_update.py +0 -0
  85. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/tests/__init__.py +0 -0
  86. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/tests/test_auth.py +0 -0
  87. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/tests/test_filters.py +0 -0
  88. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/tests/test_output.py +0 -0
  89. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/tests/test_sponsorships.py +0 -0
  90. {thoughtleaders_cli-0.6.10 → thoughtleaders_cli-0.6.11}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tl-cli",
3
- "version": "0.6.10",
3
+ "version": "0.6.11",
4
4
  "description": "ThoughtLeaders CLI — query sponsorship deals, channels, brands, uploads, and intelligence from the terminal",
5
5
  "author": {
6
6
  "name": "ThoughtLeaders",
@@ -95,6 +95,7 @@ The version string is defined in three files and all three must be updated toget
95
95
  ## Coding
96
96
 
97
97
  * Do not reference internal architecture of the ThoughtLeaders app in comments or skills. Specifially: do not reference internal table names, field names, API endpoints, Python modules or functions (including the sanitizer).
98
+ * Do not let server implementation details into skill files (anything under `skills/`). Skills describe *what the CLI does* from the user's seat — observable command surface, inputs, outputs, examples. Do not say "the server enforces X", "the API validates Y on its side", "the backend rejects Z" — those are mechanism notes that drift the moment the server changes. State the user-visible behaviour ("unknown keys come back as 400") without naming where it's enforced.
98
99
  * Place all imports at the start of the Python module file
99
100
 
100
101
  # Git commit rules
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: thoughtleaders-cli
3
- Version: 0.6.10
3
+ Version: 0.6.11
4
4
  Summary: ThoughtLeaders CLI — query sponsorship data, channels, brands, and intelligence
5
5
  Project-URL: Homepage, https://thoughtleaders.io
6
6
  Project-URL: Repository, https://github.com/ThoughtLeaders-io/thoughtleaders-cli
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "thoughtleaders-cli"
7
- version = "0.6.10"
7
+ version = "0.6.11"
8
8
  description = "ThoughtLeaders CLI — query sponsorship data, channels, brands, and intelligence"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -141,7 +141,7 @@ Prefer writing Python code, shell code, or `jq` commands that fetche or analysis
141
141
  tl sponsorships list [filters...] # Sponsorships — list curve, mult 1.0
142
142
  tl sponsorships show <id> # Sponsorship detail (2 credits)
143
143
  tl sponsorships create --channel <id> --brand <id> # Create proposal (free)
144
- tl sponsorships update <id> '<json>' # Update whitelisted fields (2 credits) — only `publish_status` editable; non-full-access users can only edit sponsorships in their own org
144
+ tl sponsorships update <id> '<json>' # Update a sponsorship (2 credits)
145
145
  tl deals list [filters...] # Shortcut: agreed-upon sponsorships (status:deal); same curve as sponsorships list
146
146
  tl deals show <id> # Deal detail (2 credits)
147
147
  tl matches list [filters...] # Shortcut: possible brand-channel pairings (status:match); same curve
@@ -153,7 +153,7 @@ tl proposals create --channel <id> --brand <id> # Create proposal (free)
153
153
  tl uploads list [filters...] # Video uploads from ES — list curve, mult 1.0
154
154
  tl uploads show <id> # Upload detail (2 credits)
155
155
  tl channels show <id-or-name> # Channel detail (2 credits; accepts numeric ID or name) — for channel search use raw SQL on thoughtleaders_channel
156
- tl channels update <id> '<json>' # Update whitelisted demographic fields (2 credits; full-access only)
156
+ tl channels update <id> '<json>' # Update a channel (2 credits)
157
157
  tl channels history <id-or-name> # Sponsorship history (5 credits/result, linear)
158
158
  tl channels similar <id-or-name> # Similarity recommender (25 credits flat; Intelligence plan)
159
159
  tl brands show <id-or-name> # Brand detail (1 credit)
@@ -182,17 +182,11 @@ tl <entity> comment-edit <comment-id> "msg" # Edit own comment (author or super
182
182
 
183
183
  ### Updating records
184
184
 
185
- A narrow write surface is exposed for two resources. Each command takes the record id and a single JSON object with the fields to change; the server enforces a hard-coded field whitelist and rejects anything else with a 400. Each call costs 2 credits.
186
-
187
185
  ```bash
188
186
  tl sponsorships update <id> '<json>' # Edit a sponsorship (adlink)
189
187
  tl channels update <id> '<json>' # Edit a channel
190
188
  ```
191
189
 
192
- **Sponsorships** — only `publish_status` is editable. Accepts either an int code or a status label (`proposed`, `pending`, `sold`, `matched`, `outreach`, `proposal_approved`, `advertiser_reject`, `publisher_reject`, `agency_reject`, `unavailable`). Non-full-access users may only update sponsorships tied to their own organization (either through `creator_profile` or through the channel's `publication`). Trying to edit a sponsorship outside the user's org returns 403.
193
-
194
- **Channels** — only the demographic fields are editable: `demographic_usa_share` and `demographic_male_share` (integers 0–100), `demographic_age` / `demographic_device` / `demographic_geo` (JSON objects with numeric values). Requires full-access permission; non-full-access users get a 403. The `demographics_updated_at` timestamp is refreshed automatically when any whitelisted demographic field changes.
195
-
196
190
  Examples:
197
191
  ```bash
198
192
  tl sponsorships update 98765 '{"publish_status": "sold"}'
@@ -202,7 +196,7 @@ tl channels update 12345 '{"demographic_geo": {"US": 60, "UK": 12, "CA": 8}}'
202
196
  tl channels update 12345 '{"demographic_male_share": 55, "demographic_usa_share": 70}'
203
197
  ```
204
198
 
205
- Anything outside these whitelists price, cost, owner, channel name, etc.is not editable through the CLI and must be done in the app or by a human with DB access.
199
+ Each call costs 2 credits. If a request is rejected with a 400, the response body names the offending key read it and retry with a smaller body. If the user wants to edit something the API rejects, the change has to be made in the app or by a human with DB access.
206
200
 
207
201
  ### Raw queries (`tl db`)
208
202
 
@@ -326,8 +320,6 @@ See [references/business-glossary.md](references/business-glossary.md) for reven
326
320
  | Arbitrary read-only `SELECT` on Postgres | **Available** via `tl db pg`. | SELECT-only, mandatory `LIMIT ≤ 500` + `OFFSET`, only certain SQL forms are allowed. See `references/postgres-schema.md`. |
327
321
  | Cross-reference helpers ("channels proposed to brand X", "channels sponsored by MBN brands in last N days") | **Available** via `tl db pg`. | Write the join: `thoughtleaders_adlink` ↔ `adspot` ↔ `channel` ↔ `profile` ↔ `profile_brands` ↔ `brand`. Filter by `publish_status` for proposed/sold and by date range as needed. See `references/postgres-schema.md` for the exact column names. |
328
322
  | **AdLink INSERT** with custom price/cost/owner/`weighted_price`/`created_where` | **Unavailable** — `tl sponsorships create` exists but only creates a free *proposal* between a channel and a brand. The `tl db pg` sanitizer accepts SELECT only — no INSERT/UPDATE. | Done in the app or by a human with DB access. |
329
- | **AdLink UPDATE** of any field other than `publish_status` (price, cost, owner, send_date, …) | **Unavailable** — `tl sponsorships update` only accepts `publish_status` and only for sponsorships in the user's org (full-access bypasses the org check). | Done in the app or by a human with DB access. |
330
- | **Channel UPDATE** of any field other than the demographic fields (`demographic_usa_share`, `demographic_male_share`, `demographic_age`, `demographic_device`, `demographic_geo`) | **Unavailable** — `tl channels update` only accepts those fields, and only for full-access users. | Done in the app or by a human with DB access. |
331
323
  | Pre-insert validation queries (joining `adspot ↔ channel ↔ profile ↔ org` to confirm MSN, integration=1, persona, plan) | **Available** via `tl db pg`. | One SELECT joining the four tables. Use `thoughtleaders_channel.media_selling_network_join_date IS NOT NULL` for MSN, `thoughtleaders_adspot.integration = 1` for mention adspots, `thoughtleaders_profile.persona` for the persona code (see persona constants in `references/postgres-schema.md`). |
332
324
  | Firebolt cross-table or join queries; filtering on non-indexed columns in WHERE | **Unavailable** — not accepted. | Fetch a wider slice keyed on `channel_id` (and optionally `id`), filter the rest in `jq`/Python. |
333
325
  | ES `query_string`, `regexp`, `wildcard`, `fuzzy`, `more_like_this`, parent/child joins; any `script_*`; multiple aggregations in one body | **Unavailable** — not accepted. | Rewrite using `term`/`terms`/`match`/`bool`/`nested`. For multi-agg dashboards, run multiple `tl db es` calls and combine client-side. For "similar"-style queries, try `tl channels similar` / `tl brands similar` (server-implemented similarity search). |
@@ -1,3 +1,3 @@
1
1
  """ThoughtLeaders CLI — query sponsorship data, channels, brands, and intelligence."""
2
2
 
3
- __version__ = "0.6.10"
3
+ __version__ = "0.6.11"
@@ -238,19 +238,13 @@ def history_cmd(
238
238
  @app.command("update")
239
239
  def update_cmd(
240
240
  channel_id: int = typer.Argument(..., help="Channel ID (numeric)"),
241
- fields: str = typer.Argument(..., help='JSON object of fields to update, e.g. \'{"demographic_male_share": 62}\''),
241
+ fields: str = typer.Argument(..., help='JSON object of fields to update'),
242
242
  json_output: bool = typer.Option(False, "--json", help="JSON output"),
243
243
  toon_output: bool = typer.Option(False, "--toon", help="TOON output (token-efficient for LLMs)"),
244
244
  ) -> None:
245
- """Update whitelisted channel fields (demographics; full-access only).
245
+ """Update a channel.
246
246
 
247
- Editable fields: demographic_usa_share, demographic_male_share,
248
- demographic_age, demographic_device, demographic_geo. The
249
- demographics_updated_at timestamp is refreshed automatically.
250
-
251
- Examples:
252
- tl channels update 12345 '{"demographic_male_share": 62}'
253
- tl channels update 12345 '{"demographic_geo": {"US": 60, "UK": 12}}'
247
+ Unknown fields are rejected with a 400 listing the offending key.
254
248
  """
255
249
  fmt = detect_format(json_output, False, False, toon_output)
256
250
  try:
@@ -198,19 +198,13 @@ def create_cmd(
198
198
  @app.command("update")
199
199
  def update_cmd(
200
200
  sponsorship_id: int = typer.Argument(..., help="Sponsorship (adlink) ID"),
201
- fields: str = typer.Argument(..., help='JSON object of fields to update, e.g. \'{"publish_status": "sold"}\''),
201
+ fields: str = typer.Argument(..., help='JSON object of fields to update'),
202
202
  json_output: bool = typer.Option(False, "--json", help="JSON output"),
203
203
  toon_output: bool = typer.Option(False, "--toon", help="TOON output (token-efficient for LLMs)"),
204
204
  ) -> None:
205
- """Update whitelisted sponsorship fields.
205
+ """Update a sponsorship.
206
206
 
207
- Editable fields: publish_status (int code or status label, e.g. 'sold',
208
- 'pending', 'matched'). Non-full-access users may only update sponsorships
209
- tied to their own organization.
210
-
211
- Examples:
212
- tl sponsorships update 98765 '{"publish_status": "sold"}'
213
- tl sponsorships update 98765 '{"publish_status": 3}'
207
+ Unknown fields are rejected with a 400 listing the offending key.
214
208
  """
215
209
  fmt = detect_format(json_output, False, False, toon_output)
216
210
  try: