import React from "react"; import CodeSnippet from "$app/components/ui/CodeSnippet"; import { ApiEndpoint } from "../ApiEndpoint"; import { ApiParameter, ApiParameters } from "../ApiParameters"; import { ApiResponseFields, renderFields } from "../ApiResponseFields"; import { CATEGORY_FIELDS, PRODUCT_FIELDS, PRODUCT_LIST_FIELDS } from "../responseFieldDefinitions"; const ProductResponseFields = () => ( {renderFields([ { name: "success", type: "boolean", description: "Whether the request succeeded" }, { name: "products", type: "array", description: "Array of product objects", children: PRODUCT_LIST_FIELDS }, { name: "next_page_key", type: "string", description: "Opaque cursor to pass as page_key to fetch the next page", condition: "present when more results follow", }, { name: "next_page_url", type: "string", description: "Path-relative URL (with query string) for the next page of results", condition: "present when more results follow", }, ])} ); const SingleProductResponseFields = () => ( {renderFields([ { name: "success", type: "boolean", description: "Whether the request succeeded" }, { name: "product", type: "object", description: "The product object", children: PRODUCT_FIELDS }, ])} ); const CreateProductResponseFields = () => ( {renderFields([ { name: "success", type: "boolean", description: "Whether the request succeeded" }, { name: "product", type: "object", description: "The product object", children: PRODUCT_FIELDS }, { name: "warning", type: "string", description: "Explains why the product was saved as a draft instead of being published (for example, an unconfirmed email address; publish it later with POST /v2/products/:id/enable), or that a post-publish step failed. Check the product's published field for its actual state.", condition: "present when publishing did not fully succeed", }, ])} ); const CategoriesResponseFields = () => ( {renderFields([ { name: "success", type: "boolean", description: "Whether the request succeeded" }, { name: "categories", type: "array", description: "Flat list of product categories", children: CATEGORY_FIELDS }, ])} ); const UpdateProductResponseFields = () => ( {renderFields([ { name: "success", type: "boolean", description: "Whether the request succeeded" }, { name: "product", type: "object", description: "The product object", children: PRODUCT_FIELDS }, { name: "warning", type: "string", description: "Warning about offer codes that became invalid for the product, or custom HTML that has no buy element.", condition: "present when there is an advisory warning after the update", }, { name: "file_id_mappings", type: "object", description: "Map of client file ids (files[][id] or files[][external_id]) to the canonical ProductFile id. Use this after attaching a newly uploaded file so a follow-up variant or rich_content write can reference it without GET-diffing the file list.", condition: "present when at least one files entry remapped a client id", }, ])} ); const CustomHtmlDocumentation = () => (

Custom HTML landing pages

A product can have one custom HTML landing page, stored in its custom_html field. While it's set and the product is published, buyers see it instead of the default product page. Authenticate with a Bearer token that has the edit_products scope.

{`curl https://api.gumroad.com/v2/products/ \\ -X PUT \\ -H "Authorization: Bearer " \\ -H "Content-Type: application/json" \\ -d '{"custom_html":"

My landing page

"}'`}
{`gumroad products page preview ./landing.html gumroad products page publish ./landing.html`}

Your HTML is sanitized — disallowed tags and attributes are stripped — then served inside a sandboxed iframe ( sandbox="allow-scripts allow-forms allow-popups allow-popups-to-escape-sandbox" ).

It can:

It can't:

Every external load is restricted to Gumroad's CDN (images and media) or the named font and script CDNs above, so the page has no arbitrary-host network channel — it can't beacon data off to a server you control.

Live values and buy buttons

Mark elements with data attributes that Gumroad fills in server-side so the page always shows current values and a working checkout button:

For products with selection state, set the choice directly on the buy element. Invalid values silently fall back to the product defaults — they won't break the page.

{`Buy now Buy Pro – $99/year `}
); export const GetCategories = () => ( {`curl https://api.gumroad.com/v2/categories \\ -d "access_token=ACCESS_TOKEN" \\ -X GET`} {`{ "success": true, "categories": [ { "id": 123, "name": "figma", "label": "Figma", "path": "design/ui-and-web/figma", "parent_id": 122 } ] }`} ); export const GetProducts = () => ( {`curl https://api.gumroad.com/v2/products \\ -d "access_token=ACCESS_TOKEN" \\ -X GET`} gumroad products list {`{ "success": true, "products": [{ "custom_permalink": null, "custom_receipt": null, "custom_summary": "You'll get one PSD file.", "custom_fields": [], "customizable_price": null, "description": "I made this for fun.", "deleted": false, "max_purchase_count": null, "name": "Pencil Icon PSD", "preview_url": null, "require_shipping": false, "subscription_duration": null, "published": true, "url": null, # Deprecated, always null "id": "A-m3CDDC5dlrSdKZp0RFhA==", "price": 100, "taxonomy_id": 123, "category": "design/ui-and-web/figma", "category_label": "Figma", "purchasing_power_parity_prices": { "US": 100, "IN": 50, "EC": 25 }, "currency": "usd", "short_url": "https://sahil.gumroad.com/l/pencil", "thumbnail_url": "https://public-files.gumroad.com/variants/72iaezqqthnj1350mdc618namqki/f2f9c6fc18a80b8bafa38f3562360c0e42507f1c0052dcb708593f7efa3bdab8", "tags": ["pencil", "icon"], "formatted_price": "$1", "file_info": {}, "sales_count": 0, # available with the 'view_sales' or 'account' scope "sales_usd_cents": 0, # available with the 'view_sales' or 'account' scope "is_tiered_membership": true, "recurrences": ["monthly"], # if is_tiered_membership is true, renders list of available subscription durations; otherwise null "variants": [ { "title": "Tier", "options": [ { "name": "First Tier", "price_difference": 0, # 0 for tiered membership options; non-zero for non-membership options with a price bump "purchasing_power_parity_prices": { # present when PPP is enabled for the seller and the product has not opted out; null when price_difference is null "US": 200, "IN": 100, "EC": 50 }, "is_pay_what_you_want": false, "recurrence_prices": { # present for membership products; otherwise null "monthly": { "price_cents": 300, "suggested_price_cents": null, # may return number if is_pay_what_you_want is true "purchasing_power_parity_prices": { "US": 400, "IN": 200, "EC": 100 } } } } ] } ] }, {...}, {...}] }`} ); export const GetProduct = () => ( {`curl https://api.gumroad.com/v2/products/A-m3CDDC5dlrSdKZp0RFhA== \\ -d "access_token=ACCESS_TOKEN" \\ -X GET`} gumroad products show A-m3CDDC5dlrSdKZp0RFhA== {`{ "success": true, "product": { "custom_permalink": null, "custom_receipt": null, "custom_summary": "You'll get one PSD file.", "custom_html": null, "custom_fields": [], "customizable_price": null, "description": "I made this for fun.", "deleted": false, "max_purchase_count": null, "name": "Pencil Icon PSD", "preview_url": null, "require_shipping": false, "subscription_duration": null, "published": true, "url": null, # Deprecated, always null "id": "A-m3CDDC5dlrSdKZp0RFhA==", "price": 100, "taxonomy_id": 123, "category": "design/ui-and-web/figma", "category_label": "Figma", "purchasing_power_parity_prices": { "US": 100, "IN": 50, "EC": 25 }, "currency": "usd", "short_url": "https://sahil.gumroad.com/l/pencil", "thumbnail_url": "https://public-files.gumroad.com/variants/72iaezqqthnj1350mdc618namqki/f2f9c6fc18a80b8bafa38f3562360c0e42507f1c0052dcb708593f7efa3bdab8", "tags": ["pencil", "icon"], "formatted_price": "$1", "file_info": {}, "sales_count": 0, # available with the 'view_sales' or 'account' scope "sales_usd_cents": 0, # available with the 'view_sales' or 'account' scope "is_tiered_membership": true, "recurrences": ["monthly"], # if is_tiered_membership is true, renders list of available subscription durations; otherwise null "variants": [ { "title": "Tier", "options": [ { "name": "First Tier", "price_difference": 0, # 0 for tiered membership options; non-zero for non-membership options with a price bump "purchasing_power_parity_prices": { # present when PPP is enabled for the seller and the product has not opted out; null when price_difference is null "US": 200, "IN": 100, "EC": 50 }, "is_pay_what_you_want": false, "recurrence_prices": { # present for membership products; otherwise null "monthly": { "price_cents": 300, "suggested_price_cents": null, # may return number if is_pay_what_you_want is true "purchasing_power_parity_prices": { "US": 400, "IN": 200, "EC": 100 } } } } ] } ] } }`} ); export const CreateProduct = () => ( Create a new product. The product is published immediately unless you pass draft=true or{" "} published=false. If publishing is blocked (for example, your email address is not confirmed or no payout method is set up), the product is saved as a draft and the response includes a warning{" "} explaining why; publish it later with POST /v2/products/:id/enable. Requires the{" "} edit_products or account scope. } > (optional) array of files to attach — see Attaching to a product } />

Cover images and thumbnails are attached separately via POST /v2/products/:id/covers and{" "} POST /v2/products/:id/thumbnail.

{`curl https://api.gumroad.com/v2/products \\ -d "access_token=ACCESS_TOKEN" \\ -d "native_type=digital" \\ -d "name=Pencil Icon PSD" \\ -d "price=100" \\ -d "price_currency_type=usd" \\ -d "category=design/ui-and-web/figma" \\ -X POST`} {`gumroad products create --type digital \\ --name "Pencil Icon PSD" \\ --price 1.00 \\ --currency usd`} {`{ "success": true, "product": { "id": "A-m3CDDC5dlrSdKZp0RFhA==", "name": "Pencil Icon PSD", "price": 100, "currency": "usd", "taxonomy_id": 123, "category": "design/ui-and-web/figma", "category_label": "Figma", "published": true, "files": [], "covers": [], "main_cover_id": null, "rich_content": [], "has_same_rich_content_for_all_variants": true # ...remaining product fields } }`}
); export const UpdateProduct = () => ( Update an existing product. Send only the fields you want to change. Sending files,{" "} tags, or rich_content replaces the entire collection. Requires the{" "} edit_products or account scope. } > (optional) array of files; full replacement — see Attaching to a product for how to keep existing files } /> {`curl https://api.gumroad.com/v2/products/A-m3CDDC5dlrSdKZp0RFhA== \\ -d "access_token=ACCESS_TOKEN" \\ -d "name=Pencil Icon PSD v2" \\ -d "max_purchase_count=100" \\ -d "category=design/ui-and-web/figma" \\ -X PUT`} {`gumroad products update A-m3CDDC5dlrSdKZp0RFhA== \\ --name "Pencil Icon PSD v2" \\ --max-purchase-count 100`} {`{ "success": true, "product": { "id": "A-m3CDDC5dlrSdKZp0RFhA==", "name": "Pencil Icon PSD v2", "max_purchase_count": 100, "files": [ { "id": "K7QmZw==", "name": "Pencil Icon", "size": 102400, "url": "https://api.gumroad.com/r/...signed...", "filetype": "psd", "filegroup": "image" } ] # ...remaining product fields } }`} ); export const DeleteProduct = () => ( {`curl https://api.gumroad.com/v2/products/A-m3CDDC5dlrSdKZp0RFhA== \\ -d "access_token=ACCESS_TOKEN" \\ -X DELETE`} gumroad products delete A-m3CDDC5dlrSdKZp0RFhA== {`{ "success": true, "message": "The product has been deleted successfully." }`} ); export const EnableProduct = () => ( {`curl https://api.gumroad.com/v2/products/A-m3CDDC5dlrSdKZp0RFhA==/enable \\ -d "access_token=ACCESS_TOKEN" \\ -X PUT`} gumroad products publish A-m3CDDC5dlrSdKZp0RFhA== {`{ "success": true, "product": { "custom_permalink": null, "custom_receipt": null, "custom_summary": "You'll get one PSD file.", "custom_fields": [], "customizable_price": null, "description": "I made this for fun.", "deleted": false, "max_purchase_count": null, "name": "Pencil Icon PSD", "preview_url": null, "require_shipping": false, "subscription_duration": null, "published": true, "url": null, # Deprecated, always null "id": "A-m3CDDC5dlrSdKZp0RFhA==", "price": 100, "purchasing_power_parity_prices": { "US": 100, "IN": 50, "EC": 25 }, "currency": "usd", "short_url": "https://sahil.gumroad.com/l/pencil", "thumbnail_url": "https://public-files.gumroad.com/variants/72iaezqqthnj1350mdc618namqki/f2f9c6fc18a80b8bafa38f3562360c0e42507f1c0052dcb708593f7efa3bdab8", "tags": ["pencil", "icon"], "formatted_price": "$1", "file_info": {}, "sales_count": 0, # available with the 'view_sales' or 'account' scope "sales_usd_cents": 0, # available with the 'view_sales' or 'account' scope "is_tiered_membership": true, "recurrences": ["monthly"], # if is_tiered_membership is true, renders list of available subscription durations; otherwise null "variants": [ { "title": "Tier", "options": [ { "name": "First Tier", "price_difference": 0, # 0 for tiered membership options; non-zero for non-membership options with a price bump "purchasing_power_parity_prices": { # present when PPP is enabled for the seller and the product has not opted out; null when price_difference is null "US": 200, "IN": 100, "EC": 50 }, "is_pay_what_you_want": false, "recurrence_prices": { # present for membership products; otherwise null "monthly": { "price_cents": 300, "suggested_price_cents": null, # may return number if is_pay_what_you_want is true "purchasing_power_parity_prices": { "US": 400, "IN": 200, "EC": 100 } } } } ] } ] } }`} ); export const DisableProduct = () => ( {`curl https://api.gumroad.com/v2/products/A-m3CDDC5dlrSdKZp0RFhA==/disable \\ -d "access_token=ACCESS_TOKEN" \\ -X PUT`} gumroad products unpublish A-m3CDDC5dlrSdKZp0RFhA== {`{ "success": true, "product": { "custom_permalink": null, "custom_receipt": null, "custom_summary": "You'll get one PSD file.", "custom_fields": [], "customizable_price": null, "description": "I made this for fun.", "deleted": false, "max_purchase_count": null, "name": "Pencil Icon PSD", "preview_url": null, "require_shipping": false, "subscription_duration": null, "published": false, "url": null, # Deprecated, always null "id": "A-m3CDDC5dlrSdKZp0RFhA==", "price": 100, "currency": "usd", "short_url": "https://sahil.gumroad.com/l/pencil", "thumbnail_url": "https://public-files.gumroad.com/variants/72iaezqqthnj1350mdc618namqki/f2f9c6fc18a80b8bafa38f3562360c0e42507f1c0052dcb708593f7efa3bdab8", "tags": ["pencil", "icon"], "formatted_price": "$1", "file_info": {}, "sales_count": 0, # available with the 'view_sales' or 'account' scope "sales_usd_cents": 0, # available with the 'view_sales' or 'account' scope "is_tiered_membership": true, "recurrences": ["monthly"], # if is_tiered_membership is true, renders list of available subscription durations; otherwise null "variants": [ { "title": "Tier", "options": [ { "name": "First Tier", "price_difference": 0, # 0 for tiered membership options; non-zero for non-membership options with a price bump "is_pay_what_you_want": false, "recurrence_prices": { # present for membership products; otherwise null "monthly": { "price_cents": 300, "suggested_price_cents": null # may return number if is_pay_what_you_want is true } } } ] } ] } }`} );