| name | gumroad |
| description | Use the `gumroad` CLI to look up and manage Gumroad data from the terminal. Trigger when the user asks about Gumroad products, files, file uploads, attachments, sales, subscribers, licenses, payouts, audience emails, broadcasts, offer codes, webhooks, refund policies, or any Gumroad data lookup. Also trigger on "check my Gumroad", "look up a sale", "verify a license", "list my products", "how much have I made", "who bought", "recent sales", "refund a sale", "create a product", "upload a file", "attach a file to a product", "add a cover image", "set a product thumbnail", "get product content", "set product content", "upload product media", "publish a product landing page", "publish custom HTML", "clear custom HTML", "customize my profile page", "publish a profile landing page", "set profile custom HTML", "attach a file to a variant", "finish a failed upload", "abort an upload", "manage webhooks", "draft an email", "preview a broadcast", "send an audience email", "list drafts", "set refund policy", "check my refund policy", "check my earnings", "see my revenue", "who subscribed", "manage my store", "discount code", "coupon", "shipping status", "payout schedule", or any request to query or act on Gumroad data — even if the user doesn't say "Gumroad" explicitly but is clearly referring to their creator store or digital product sales. Do NOT trigger for Gumroad web UI, Rails, or codebase questions.
|
gumroad CLI
Use gumroad (Gumroad CLI) to query and manage Gumroad data.
Agent invariants
Always follow these rules:
- Always pass
--no-input to prevent interactive prompts from blocking.
- Always pass
--json for programmatic access.
- Use
--json --jq <expr> together to extract exactly what you need.
- For operations that can prompt for confirmation (delete, refund, mutating admin actions,
files abort, files complete replay, product updates that remove files, or products content set when omitted page IDs will be deleted), add --yes to skip confirmation.
- Pass
--quiet to suppress spinners and status messages.
- Pass
--dry-run to preview mutating requests without executing them.
- Use
--page-delay 200ms with --all to avoid rate limits on large datasets.
- Prices are in whole currency units (e.g.
--price 10.00 for $10), not cents. The CLI converts internally. Use --currency eur to change currency.
- Products are created as drafts — use
gumroad products publish <id> to make them live.
- Product cover and thumbnail uploads support JPEG, PNG, and GIF. WebP is not supported by the API and the CLI rejects it before upload.
- Product custom HTML landing pages use
gumroad products page preview <id> ./landing.html to run the backend sanitizer without writing, gumroad products page publish <id> ./landing.html to store the page, gumroad products page clear <id> --yes to remove it, and gumroad products page url <id> to print the live URL. --dry-run only previews the CLI request body; it does not call the backend sanitizer. Inspect .sanitization_report in preview and publish JSON output for server-side changes.
- Profile custom HTML landing pages mirror the product commands without a product id and without checkout:
gumroad user page preview ./landing.html, gumroad user page publish ./landing.html (read from stdin with -), gumroad user page clear --yes, and gumroad user page url (prints the public profile URL and its /landing/embed URL). A profile has no buy button, so omit data-gumroad-action="buy" and the checkout data attributes; link to products instead.
- Storefront pages (slugged pages serving at
<username>.gumroad.com/<slug>) use gumroad pages list, gumroad pages create --title <title> [--slug <slug>] [path] (with an HTML path or - the page is created as custom HTML; without one it starts empty for the in-app editor), gumroad pages pull <slug> to download a page's existing custom HTML so pull → edit → push is a real round trip (writes <slug>.html; -o <path> to choose, -o - for stdout; refuses to overwrite without --force; errors with a hint when the page has no custom HTML), gumroad pages scaffold <slug> to generate starter HTML for a rich-text page or a default profile from a static snapshot of its current render (same flags as pull; pushing the scaffold converts the page to custom HTML and replaces the dynamic storefront/editor experience), gumroad pages push <slug> ./page.html to replace a page with custom HTML, and gumroad pages preview ./page.html to run the backend sanitizer without publishing. The loop for going custom: pull (or scaffold when there's no custom HTML yet) → edit → preview → push. --json/--jq on pull/scaffold still write the file and additionally print the raw API response; combining them with -o - is rejected since both would own stdout. The special slug profile targets the profile landing page (pull profile downloads your published custom HTML, scaffold profile snapshots the default storefront render when none is published; push uses the same endpoints as user page publish). Custom HTML pages require the seller's custom_html_pages feature to be enabled; without it writes fail with an access message. Writes to slugged pages (pages create/pages push <slug>) also require the token to carry the edit_profile scope — tokens minted before the CLI requested that scope get a 403 telling them to re-run gumroad auth login.
- Product rich content uses
gumroad products content list <id> --json --no-input to inspect page IDs, gumroad products content get <id> --json --no-input to dump the shared rich_content page array, and gumroad products content set <id> content.json --dry-run --json --no-input to preview a whole-document replacement. Without an explicit path, whole-document set reads ./content.json; set --page reads ./page.json. Use --page <page_id> with get/set to edit one matching page object; set --page still sends a merged whole-document PUT. For per-variant content, pass both --variant <variant_id> and --category <cat_id>. Whole-document set deletes existing pages omitted from the JSON.
- Custom HTML pages can use
data-gumroad-field="name", data-gumroad-field="price", data-gumroad-field="description", and data-gumroad-action="buy". To preselect checkout state, add data-gumroad-option="<variant name>", data-gumroad-quantity="<integer>", data-gumroad-price="<decimal>", or data-gumroad-recurrence="monthly|quarterly|biannually|yearly|every_two_years". Production validates these values and falls back to product defaults when invalid. Prefer anchors for buy CTAs so production can add a checkout href; non-anchor buy elements also post to checkout.
- Audience emails are created as drafts by default. Use
gumroad emails send-preview <id> --json --no-input and inspect .preview_url before gumroad emails send <id> --yes --json --no-input. Creating with --send publishes and blasts immediately, so use --dry-run first and require explicit human approval.
- If a command fails with a seller auth error, run
gumroad auth status --json --no-input first. Agents can start seller auth with gumroad auth login --no-input and hand the printed approval URL to a human, or use an existing seller token via GUMROAD_ACCESS_TOKEN or gumroad auth login --with-token.
- For admin commands in agents/CI, pass
--non-interactive and set GUMROAD_ADMIN_TOKEN; interactive shells can store an admin token with gumroad auth login --web.
Response shapes
Most responses are wrapped in {"success": true, ...} with resource-specific keys:
user → .user, user update → .user
user page preview → .custom_html, .sanitization_report
user page publish / user page clear → .custom_html, .previous_custom_html, .profile_url, .sanitization_report
user page url → .profile_url, .has_landing_page
pages list → .pages[] (.slug, .title, .content, .custom_html, .url); pages create / pages push <slug> → .page; pages pull <slug> / pages scaffold <slug> → .page + .rendered_html (pull writes the page's .page.custom_html; scaffold writes .rendered_html, the static render snapshot); pages pull profile / pages scaffold profile → .custom_html, .rendered_html, .has_landing_page, .profile_url; pages push profile → profile shape (.custom_html, .previous_custom_html, .profile_url, .sanitization_report); pages preview → .custom_html, .sanitization_report
refund-policy view/set → .refund_policy
products list → .products[]
products view → .product
products content get → rich content page array directly, or one page object with --page
products content list → rich content page summary array directly
products content set → mutation envelope with
Admin pagination models differ by command:
- Cursor-paginated:
admin users affiliates, admin users comments list, admin users credits list, admin users radar, admin users purchases, and admin purchases lookup return .pagination.next as a cursor string. Pass it back with --cursor.
- Page-paginated:
admin products list returns .pagination.next as an integer page number. Pass it back with --page; use --per-page for page size.
- Capped, not continuable:
admin users related returns at most 50 related users per signal. Always inspect .truncated; when any signal is true, the result hit the cap and there is no cursor/page to fetch the rest.
- Capped, not continuable:
admin purchases search returns .has_more when the server capped results. --limit is server-capped at 25 and there is no continuation token.
Bulk operations
When creating or updating many products:
- Check existing products and permalinks first, then skip duplicates on re-runs.
- Derive custom permalinks deterministically from source data so retries are idempotent.
- Use
--dry-run --json to preview generated requests, and ask the user to confirm before mutating more than 5 products.
- Continue past per-product errors, collect each failure with its product/permalink, and summarize successes and failures at the end.
- For product media failures after creation, retry with the command printed in the error, such as
gumroad products covers add <id> --image ./cover.jpg.
Commands
auth — Manage authentication
gumroad auth status --json --no-input
gumroad auth login --no-input
gumroad auth login --with-token --json --no-input < token.txt
printf '%s\n' "$GUMROAD_ACCESS_TOKEN" | gumroad auth login --with-token --json --no-input
gumroad auth token --no-input
gumroad auth login --web
gumroad auth logout --yes --no-input
user — Account info
gumroad user --json --no-input
gumroad user --json --jq '.user.email' --no-input
gumroad user update --name "Jane Doe" --bio "I make great things." --json --no-input
gumroad user update --bio "" --json --no-input
gumroad user page preview ./landing.html --json --no-input
gumroad user page publish ./landing.html --json --no-input
gumroad user page publish - --json --no-input < landing.html
gumroad user page clear --yes --json --no-input
gumroad user page url --no-input
gumroad user page url --json --jq '.profile_url' --no-input
refund-policy — Store-wide refund policy
gumroad refund-policy view --json --no-input
gumroad refund-policy view --json --jq '.refund_policy.in_effect' --no-input
gumroad refund-policy set --period 30 --fine-print "Refund requests are reviewed within 2 business days." --json --no-input
gumroad refund-policy set --period none --fine-print "" --json --no-input
admin — Internal admin API
gumroad admin users info --email seller@example.com --json --non-interactive --no-input
gumroad admin users info --username sellerone --json --non-interactive --no-input
gumroad admin users affiliates --user-id 2245593582708 --direction granted --limit 50 --json --non-interactive --no-input
gumroad admin users affiliates --username sellerone --direction granted --limit 50 --json --non-interactive --no-input
gumroad admin users affiliates --email seller@example.com --direction received --cursor cur-next --json --non-interactive --no-input
gumroad admin users comments list --user-id 2245593582708 --type note --limit 50 --json --non-interactive --no-input
gumroad admin users comments list --username sellerone --type note --limit 50 --json --non-interactive --no-input
gumroad admin users comments add --user-id 2245593582708 --content "VAT exempt confirmed" --yes --json --non-interactive --no-input
gumroad admin users credits list --user-id 2245593582708 --limit 50 --json --non-interactive --no-input
gumroad admin users credits list --username sellerone --limit 50 --json --non-interactive --no-input
gumroad admin users credits add --user-id 2245593582708 --expected-email seller@example.com --amount-cents 1000 --reason --dry-run --json --non-interactive --no-input
gumroad admin credits add --user-id 2245593582708 --expected-email seller@example.com --amount-cents 1000 --reason -- --json --non-interactive --no-input
gumroad admin compliance --user-id 2245593582708 --json --non-interactive --no-input
gumroad admin compliance --username sellerone --json --non-interactive --no-input
gumroad admin radar --user-id 2245593582708 -- 50 --json --non-interactive --no-input
gumroad admin radar --username sellerone -- 50 --json --non-interactive --no-input
gumroad admin purchases --user-id 2245593582708 --status successful --has-early-fraud-warning= -- 50 --json --non-interactive --no-input
gumroad admin purchases --username sellerone --status successful -- 50 --json --non-interactive --no-input
gumroad admin suspension --username sellerone --json --non-interactive --no-input
gumroad admin related --email seller@example.com --signal ip --signal payment_address --json --non-interactive --no-input
gumroad admin related --username sellerone --signal ip --json --non-interactive --no-input
gumroad admin related --email seller@example.com --json --jq --non-interactive --no-input
gumroad admin mark-compliant --user-id 2245593582708 --expected-email seller@example.com --note -- --json --non-interactive --no-input
gumroad admin mark-compliant --user-id 2245593582708 --expected-email seller@example.com --note --clear-suspension -- --json --non-interactive --no-input
gumroad admin --user-id 2245593582708 --expected-email seller@example.com --note -- --json --non-interactive --no-input
gumroad admin suspend-for-tos-violation --user-id 2245593582708 --expected-email seller@example.com --note -- --json --non-interactive --no-input
gumroad admin products flag-for-tos-violation <product-id> --user-id 2245593582708 --expected-email seller@example.com -- --json --non-interactive --no-input
gumroad admin payouts scheduled create --user-id 2245593582708 --expected-email seller@example.com --processor stripe --payout-date 2026-06-15 --note -- --json --non-interactive --no-input
gumroad admin payouts scheduled list --status pending --user-id 2245593582708 --json --non-interactive --no-input
gumroad admin payouts list --user-id 2245593582708 -- 25 --json --jq --non-interactive --no-input
gumroad admin refund-balance --user-id 2245593582708 --expected-email seller@example.com --dry-run --json --non-interactive --no-input
gumroad admin refund-balance --user-id 2245593582708 --expected-email seller@example.com -- --json --non-interactive --no-input
gumroad admin refund-all-for-fraud --user-id 2245593582708 --expected-email seller@example.com --expected-count 18 -- --json --non-interactive --no-input
gumroad admin refund-all-for-fraud --user-id 2245593582708 --expected-email seller@example.com --expected-count 18 --block-buyers -- --json --non-interactive --no-input
gumroad admin purchases view <purchase-id> --with-clusters --json --non-interactive --no-input
gumroad admin purchases search --email buyer@example.com --json --jq --non-interactive --no-input
gumroad admin purchases lookup --stripe-fingerprint fp_abc -- 25 --json --non-interactive --no-input
gumroad admin purchases refund <purchase-id> --email buyer@example.com --reason -- --json --non-interactive --no-input
gumroad admin purchases refund <purchase-id> --email buyer@example.com --amount 5.00 --reason -- --json --non-interactive --no-input
gumroad admin products list --email seller@example.com --page 2 --per-page 25 --json --non-interactive --no-input
gumroad admin products view <product-id> --with-fraud-context --json --non-interactive --no-input
gumroad admin watch --user-id 2245593582708 --expected-email seller@example.com --revenue-threshold 200 --note -- --json --non-interactive --no-input
gumroad admin update-watch --user-id 2245593582708 --expected-email seller@example.com --revenue-threshold 500 -- --json --non-interactive --no-input
gumroad admin update-watch --user-id 2245593582708 --expected-email seller@example.com --revenue-threshold 500 --clear-note -- --json --non-interactive --no-input
gumroad admin unwatch --user-id 2245593582708 --expected-email seller@example.com -- --json --non-interactive --no-input
products — Manage products
gumroad products list --json --no-input
gumroad products list --all --json --no-input
gumroad products list --page-key <cursor> --json --no-input
gumroad products view <id> --json --no-input
gumroad products categories --search figma --json --no-input
gumroad products comps --category design/ui-and-web/figma --json --no-input
gumroad products comps --category music-and-sound-design --query "whoosh sfx" --json --no-input
gumroad products create --name "Art Pack" --price 10.00 --json --no-input
gumroad products create --name "Figma Kit" --category design/ui-and-web/figma --json --no-input
gumroad products create --name "Art Pack" --price 10.00 --file ./pack.zip --file-name "Art Pack.zip" --json --no-input
gumroad products create --name "Art Pack" --price 10.00 --cover-image ./cover.jpg --thumbnail ./thumb.jpg --json --no-input
gumroad products create --name "Newsletter" --type membership --subscription-duration monthly --json --no-input
gumroad products create --name "E-Book" --type ebook --price 5 --tag art --tag digital --json --no-input
gumroad products update <id> --name "New Name" --json --no-input
gumroad products update <id> --price 15.00 --currency eur --json --no-input
gumroad products update <id> --category design/ui-and-web/figma --json --no-input
gumroad products update <id> --file ./pack.zip --json --no-input
gumroad products update <id> --cover-image ./cover.jpg --json --no-input
gumroad products update <id> --preview-image ./gallery-1.jpg --preview-image ./gallery-2.jpg --json --no-input
gumroad products update <id> --preview-video ./demo.mp4 --json --no-input
gumroad products update <id> --thumbnail ./thumb.jpg --json --no-input
gumroad products update <> --refund-period none --refund-fine-print --json --no-input
gumroad products update <> --refund-period inherit --json --no-input
gumroad products create --name --price 10 --refund-period none --json --no-input
gumroad products page preview <> ./landing.html --json --no-input
gumroad products page publish <> ./landing.html --json --no-input
gumroad products page publish <> - --json --no-input < landing.html
gumroad products page clear <> -- --json --no-input
gumroad products page url <> --no-input
gumroad products page url <> --json --jq --no-input
gumroad products covers add <> --image ./cover.jpg --json --no-input
gumroad products covers add <> --url https://www.youtube.com/watch?v=qKebcV1jv3A --json --no-input
gumroad products covers reorder <> <cover_id> <cover_id> --json --no-input
gumroad products covers remove <> <cover_id> -- --json --no-input
gumroad products thumbnail <> --image ./thumb.jpg --json --no-input
gumroad products thumbnail <> --url https://example.com/thumb.png --json --no-input
gumroad products thumbnail remove <> -- --json --no-input
gumroad products content list <> --json --no-input
gumroad products content get <> --json --no-input > content.json
gumroad products content <> content.json --dry-run --json --no-input
gumroad products content <> content.json -- --json --no-input
gumroad products content get <> --page <page_id> --json --no-input > page.json
gumroad products content <> --page <page_id> --dry-run --json --no-input
gumroad products content <> page.json --page <page_id> --dry-run --json --no-input
gumroad products content list <> --variant <variant_id> --category <cat_id> --json --no-input
gumroad products content get <> --variant <variant_id> --category <cat_id> --json --no-input > content.json
gumroad products content <> content.json --variant <variant_id> --category <cat_id> --dry-run --json --no-input
gumroad products content <> content.json --variant <variant_id> --category <cat_id> -- --json --no-input
gumroad products publish <> --json --no-input
gumroad products unpublish <> --json --no-input
gumroad products delete <> -- --json --no-input
gumroad products skus <> --json --no-input
In custom HTML, use Gumroad data attributes for live product values and checkout:
<h1 data-gumroad-field="name">Product name</h1>
<span data-gumroad-field="price">$0</span>
<p data-gumroad-field="description">Product description</p>
<a data-gumroad-action="buy">Buy now</a>
<a data-gumroad-action="buy" data-gumroad-option="Pro" data-gumroad-recurrence="yearly">Buy Pro - $99/year</a>
<button data-gumroad-action="buy" data-gumroad-quantity="2">Buy 2 seats</button>
<button data-gumroad-action="buy" data-gumroad-price="19.99">Pay $19.99</button>
List flags: --all, --page-key.
Categories: products categories [--search <term>] returns label, path, and numeric ID. Prefer --category <path> for product create/update. --taxonomy-id remains supported when you already have the numeric ID, but it cannot be combined with --category.
Comps: products comps [--category <path>] [--query <text>] [--currency <iso>] (category or query required) reports the price distribution of comparable priced public products: count of discoverable priced listings (free products excluded), p25/p50/p75 of price_cents in one currency (default usd), and the top five products by sales volume with name, formatted price, and public URL. --category includes descendant categories. Use it to anchor pricing advice in real marketplace numbers instead of static defaults.
Create flags: --name (required), --price, --type (digital|course|ebook|membership|bundle|coffee|call|commission), --currency, --pay-what-you-want, --suggested-price, --description, --custom-summary, --custom-permalink, --custom-receipt, --max-purchase-count, --category, --taxonomy-id, --tag (repeatable), --file (repeatable), --file-name (repeatable, aligned to --file), --file-description (repeatable, aligned to --file), --cover-image, --preview-image (repeatable), --preview-video (repeatable), --thumbnail.
Update flags: --name, --price, --currency, --description, --custom-summary, --custom-permalink, --custom-receipt, --max-purchase-count, --category, --taxonomy-id, --tag (repeatable), --custom-html, --file (repeatable), --file-name, --file-description, --cover-image, --preview-image (repeatable), --preview-video (repeatable), --thumbnail. Prefer products page preview/publish/clear/url for custom HTML page workflows; products update --custom-html remains supported as a low-level product update flag.
Use products update --file for shared product Content. It replaces existing rich content file embeds in place when they exist, or creates file embeds when the document has none; pass one --file per existing file embed and use products content get/set for structural content edits. For products with per-variant Content, use variants update ... --file for the specific variant you want to change.
Use --cover-image for the primary cover, repeat --preview-image for additional gallery/preview images, repeat --preview-video for video previews (MP4, MOV, M4V, MPEG, WMV, or WebM), and --thumbnail for the card/library thumbnail. When multiple media flags are combined, covers attach in a fixed order: cover image first, then preview images (in flag order), then preview videos (in flag order) — images and videos cannot be interleaved in a single command. These media flags run the required two-step API flow: direct upload first, then attach by signed blob ID. For an existing product, products thumbnail set --url asks Gumroad to download and attach a public HTTP(S) image directly.
files — Upload and recover file attachments
gumroad files upload ./pack.zip --json --no-input
gumroad files upload ./pack.zip --name "Art Pack.zip" --json --no-input
gumroad files complete --recovery recovery.json --yes --json --no-input
jq '.error.recovery' err.json | gumroad files complete --recovery - --yes --json --no-input
gumroad files abort --upload-id up-123 --key attachments/u/k/original/pack.zip --yes --json --no-input
files upload and files complete both return .file_url. When a JSON upload fails with recovery details, reuse .error.recovery with files complete to finish it or files abort to reclaim the orphaned multipart upload.
media — Public media library (page images)
Files from files upload are stored privately and can never be displayed on custom product landing pages or profile pages — the pages' Content-Security-Policy only allows Gumroad's public CDN, and page moderation cannot fetch private URLs, so a page embedding one fails review every time. To put an image on a page, upload it to the public media library instead and embed the returned .media.url in the page HTML before pages push / products page publish.
gumroad media upload ./logo.png --json --no-input
gumroad media upload ./logo.png --name "Store logo" --json --jq '.media.url' --no-input
gumroad media list --json --no-input
gumroad media delete k3n8xq1p9wr2sd4a --yes --json --no-input
The CLI detects JPEG, PNG, GIF, WebP, BMP, and ICO images up to 10 MB. It rejects SVG and other formats it cannot identify locally. Gumroad checks each image again and moderates it before hosting. A flagged image fails with the moderation message. Deleting a file breaks each page that still embeds its URL. The upload command requires the edit_profile scope. The list command requires the view_profile scope. Tokens created before the CLI requested these scopes fail with Access denied: This endpoint requires the view_profile scope. Run gumroad auth login again to create a token with the new scopes.
If an upload returns media_commit_state_unknown, do not retry it automatically. Read .error.recovery.key. List the media and find the item whose URL contains that key. If the item exists, the upload completed. If it does not exist, keep .error.recovery.signed_blob_id and .error.recovery.key for support. If an upload returns media_direct_upload_state_unknown, do not start a new upload. Keep the same recovery values for support. If it returns media_output_failed, the upload completed. Use .error.recovery.media_id and .error.recovery.media_url. Do not retry the upload. If a delete returns media_delete_output_failed, the deletion completed. Do not retry it. If a delete returns media_delete_state_unknown, list the media and search for .error.recovery.media_id. Do not retry the deletion automatically.
emails — Manage audience emails
gumroad emails create --subject "New release" --body ./email.html --json --no-input
gumroad emails create --subject "Product update" --body ./email.html --audience product --product <id> --json --no-input
gumroad emails send-preview <id> --json --jq '.preview_url' --no-input
gumroad emails view <id> --json --no-input
gumroad emails list --state draft --json --no-input
gumroad emails list --state published --all --json --no-input
gumroad emails send <id> --yes --json --no-input
gumroad emails delete <id> --yes --json --no-input
Create flags: --subject (required), --body (required HTML file path, or - for stdin), --audience (all|customers|followers|product, default all), --product (required for product audience), --send (publish and send immediately).
List flags: --state (published|scheduled|draft), --all, --page-key.
Use --dry-run --json --no-input to inspect create params without calling the API. Passing --send blasts the audience immediately; prefer the draft → send-preview URL → send workflow. send-preview emails a copy to the seller. Scheduled emails can only be created in the web UI; the CLI can list and view them (--state scheduled) but not create them.
workflows — Inspect email workflows
gumroad workflows list --json --no-input
gumroad workflows view <id> --json --no-input
gumroad workflows view <id> --json --jq '.workflow.emails[] | {subject, click_rate}' --no-input
Workflows are read-only in the CLI; create and edit them in the Gumroad dashboard. view returns steps ordered by delay, each with delay (amount + unit), sent_count, open_count, open_rate, click_count, click_rate. Rates are null for unsent steps. Plain output for view prints one row per email step.
sales — Manage sales
gumroad sales list --json --no-input
gumroad sales list --product <id> --after 2024-01-01 --json --no-input
gumroad sales list --email user@example.com --json --no-input
gumroad sales list --all --json --no-input
gumroad sales list --after 2024-01-01 --before 2024-01-31 --csv --no-input
gumroad sales list --json --jq '.sales[] | select(.email == "user@example.com")' --no-input
gumroad sales buyers --product <id> --json --no-input
gumroad sales buyers --product <old-id> --product <new-id> --json --no-input
gumroad sales buyers --product <id> --after 2024-01-01 --csv --no-input
gumroad sales buyers --product <id> --json --jq '.buyers[].email' --no-input
gumroad sales summary --json --no-input
gumroad sales summary --from 2026-01-01 --to 2026-05-21 --json --no-input
gumroad sales summary --group-by product --json --no-input
gumroad sales summary --group-by month --from 2026-01-01 --to 2026-05-21 --json --no-input
gumroad sales export --from 2026-01-01 --to 2026-05-21 --no-input
gumroad sales export --after 2026-01-01 --before 2026-05-21 --no-input
gumroad sales export --product <id> --json --no-input
gumroad sales view <id> --json --no-input
gumroad sales refund <> -- --json --no-input
gumroad sales refund <> --amount 5.00 -- --json --no-input
gumroad sales refund <> --amount 25 --currency jpy -- --json --no-input
gumroad sales resend-receipt <> --json --no-input
List filters/output: --product, --order, --email, --after (YYYY-MM-DD), --before (YYYY-MM-DD), --all, --page-key, --csv.
Buyer-currency amounts: sales charged in the buyer's local currency carry a buyer_presentment object in JSON output (currency, price_cents, tip_cents, tax fields, shipping_cents, total_cents, fx_rate, refunded_cents); it is omitted for canonical (USD-charged) sales. The list table appends (buyer: 21.01 CAD) to TOTAL, sales list --csv has four trailing columns (buyer_currency, buyer_total_cents, buyer_refunded_cents, buyer_fx_rate — empty for canonical sales), sales view prints Buyer charged: and FX rate: lines, and sales view --plain appends one extra column ONLY for presentment sales (canonical sales keep the seven-column schema).
Summary filters: --from (YYYY-MM-DD), --to (YYYY-MM-DD), --group-by (product|day|week|month).
Export filters: --from/--after (YYYY-MM-DD), --to/--before (YYYY-MM-DD), --product.
payouts — View payouts
gumroad payouts list --json --no-input
gumroad payouts list --after 2024-01-01 --before 2024-12-31 --json --no-input
gumroad payouts list --all --json --no-input
gumroad payouts view <id> --json --no-input
gumroad payouts view <id> --include-transactions --json --no-input
gumroad payouts upcoming --json --no-input
List filters: --after, --before, --all, --page-key, --no-upcoming.
View flags: --include-transactions, --no-sales.
subscribers — View subscribers
gumroad subscribers list --product <id> --json --no-input
gumroad subscribers list --product <id> --email user@example.com --json --no-input
gumroad subscribers list --product <id> --all --json --no-input
gumroad subscribers view <id> --json --no-input
List flags: --product (required), --email, --all, --page-key.
licenses — Manage license keys
License keys are passed via stdin. Never pass keys as command-line arguments.
echo "$LICENSE_KEY" | gumroad licenses verify --product <id> --no-increment --json --no-input
echo "$LICENSE_KEY" | gumroad licenses verify --product <id> --json --no-input
echo "$LICENSE_KEY" | gumroad licenses enable --product <id> --json --no-input
echo "$LICENSE_KEY" | gumroad licenses disable --product <id> --json --no-input
echo "$LICENSE_KEY" | gumroad licenses decrement --product <id> --json --no-input
echo "$LICENSE_KEY" | gumroad licenses rotate --product <id> --json --no-input
All subcommands require --product <id>. Key comes from stdin.
offer-codes — Manage discount codes
gumroad offer-codes list --product <id> --json --no-input
gumroad offer-codes create --product <id> --name SAVE10 --percent-off 10 --json --no-input
gumroad offer-codes create --product <id> --name FLAT5 --amount 5.00 --json --no-input
gumroad offer-codes create --product <id> --name SUMMER --percent-off 10 --minimum-amount 100.00 --json --no-input
gumroad offer-codes view <code_id> --product <id> --json --no-input
gumroad offer-codes update <code_id> --product <id> --max-purchase-count 100 --json --no-input
gumroad offer-codes delete <code_id> --product <id> --yes --json --no-input
Create flags: --product (required), --name (required), --percent-off OR --amount, --minimum-amount (minimum order total before the discount applies, e.g. 100.00), --max-purchase-count, --universal.
upsells — Manage upsells and cross-sells
An upsell offers a different version of the product being bought. A cross-sell offers a different product (optionally discounted) to buyers of selected products, or to buyers of every product when universal.
gumroad upsells list --json --no-input
gumroad upsells create --name "Pro upgrade" --product <id> --offer-variant <selected_variant_id>:<offered_variant_id> --json --no-input
gumroad upsells create --name "Audiobook" --product <offered_id> --cross-sell --selected-product <id> --percent-off 50 --json --no-input
gumroad upsells create --name "Add-on" --product <offered_id> --cross-sell --universal --amount 5 --json --no-input
gumroad upsells view <upsell_id> --json --no-input
gumroad upsells update <upsell_id> --paused=false --json --no-input
gumroad upsells delete <upsell_id> --yes --json --no-input
Create flags: --name (required), --product (required, the offered product), --cross-sell, --text, --description, --variant (offered version), --universal, --replace-selected-products, --paused, --amount OR --percent-off, --selected-product (repeatable), --offer-variant <selected>:<offered> (repeatable).
Update fetches the upsell and changes only the flags you pass; pass --remove-offer to drop the discount. --selected-product / --offer-variant replace the current set.
variant-categories — Manage variant categories
gumroad variant-categories list --product <id> --json --no-input
gumroad variant-categories create --product <id> --title "Size" --json --no-input
gumroad variant-categories view <cat_id> --product <id> --json --no-input
gumroad variant-categories update <cat_id> --product <id> --title "Color" --json --no-input
gumroad variant-categories delete <cat_id> --product <id> --yes --json --no-input
variants — Manage variants within a category
gumroad variants list --product <id> --category <cat_id> --json --no-input
gumroad variants create --product <id> --category <cat_id> --name "Large" --json --no-input
gumroad variants create --product <id> --category <cat_id> --name "XL" --price-difference 5.00 --json --no-input
gumroad variants view <var_id> --product <id> --category <cat_id> --json --no-input
gumroad variants update <var_id> --product <id> --category <cat_id> --name "Medium" --json --no-input
gumroad variants update <var_id> --product <id> --category <cat_id> --file ./license.pdf --json --no-input
gumroad variants delete <var_id> --product <id> --category <cat_id> --yes --json --no-input
All subcommands require --product and --category.
Update flags: --name, --description, --price-difference, --max-purchase-count, --file (repeatable), --file-name, --file-description. Use variants update --file only for products with per-variant Content; for shared Content, roll files at the product level with products update --file.
custom-fields — Manage custom fields
Custom fields are keyed by name, not ID.
gumroad custom-fields list --product <id> --json --no-input
gumroad custom-fields create --product <id> --name "Company" --required --json --no-input
gumroad custom-fields update --product <id> --name "Company" --required --json --no-input
gumroad custom-fields delete --product <id> --name "Company" --yes --json --no-input
webhooks — Manage webhooks
gumroad webhooks list --resource sale --json --no-input
gumroad webhooks create --resource sale --url https://example.com/hook --json --no-input
gumroad webhooks delete <id> --yes --json --no-input
Tips
- Use
--all with products list, sales list, subscribers list, payouts list to fetch every page automatically.
- Use
--plain for tab-separated output suitable for cut, awk, and other Unix tools.
- Run
gumroad <command> --help for full flag details on any command.