gumroad

Review·Scanned 2/17/2026

This skill provides a Gumroad API integration via Maton-managed gateways for products, sales, licenses, and webhooks. It requires the MATON_API_KEY and includes code that calls https://gateway.maton.ai, https://ctrl.maton.ai, and runs shell/python snippets (e.g., python <<'EOF').

from clawhub.ai·v1.0·15.5 KB·0 installs
Scanned from 1.0.0 at 0603444 · Transparency log ↗
$ vett add clawhub.ai/byungkyu/gumroadReview findings below

Gumroad

Access the Gumroad API with managed OAuth authentication. Manage products, view sales, verify licenses, and set up webhooks for your digital storefront.

Quick Start

# Get current user info
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://gateway.maton.ai/gumroad/v2/user')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

Base URL

https://gateway.maton.ai/gumroad/v2/{resource}

The gateway proxies requests to api.gumroad.com/v2 and automatically injects your OAuth token.

Authentication

All requests require the Maton API key in the Authorization header:

Authorization: Bearer $MATON_API_KEY

Environment Variable: Set your API key as MATON_API_KEY:

export MATON_API_KEY="YOUR_API_KEY"

Getting Your API Key

  1. Sign in or create an account at maton.ai
  2. Go to maton.ai/settings
  3. Copy your API key

Connection Management

Manage your Gumroad OAuth connections at https://ctrl.maton.ai.

List Connections

python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.maton.ai/connections?app=gumroad&status=ACTIVE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

Create Connection

python <<'EOF'
import urllib.request, os, json
data = json.dumps({'app': 'gumroad'}).encode()
req = urllib.request.Request('https://ctrl.maton.ai/connections', data=data, method='POST')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Content-Type', 'application/json')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

Get Connection

python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.maton.ai/connections/{connection_id}')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

Response:

{
  "connection": {
    "connection_id": "e1a4444f-2bb8-4e09-9265-3afe71b74b1f",
    "status": "ACTIVE",
    "creation_time": "2026-02-08T06:22:48.654579Z",
    "last_updated_time": "2026-02-08T06:23:07.420381Z",
    "url": "https://connect.maton.ai/?session_token=...",
    "app": "gumroad",
    "metadata": {}
  }
}

Open the returned url in a browser to complete OAuth authorization.

Delete Connection

python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.maton.ai/connections/{connection_id}', method='DELETE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

Specifying Connection

If you have multiple Gumroad connections, specify which one to use with the Maton-Connection header:

python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://gateway.maton.ai/gumroad/v2/products')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Maton-Connection', 'e1a4444f-2bb8-4e09-9265-3afe71b74b1f')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

If omitted, the gateway uses the default (oldest) active connection.

API Reference

User Info

Get Current User

GET /gumroad/v2/user

Response:

{
  "success": true,
  "user": {
    "name": "Chris",
    "currency_type": "usd",
    "bio": null,
    "twitter_handle": null,
    "id": "1690942847664",
    "user_id": "QmTtTnViFSoocHAexgLuJw==",
    "url": "https://chriswave1246.gumroad.com",
    "profile_url": "https://public-files.gumroad.com/...",
    "email": "chris@example.com",
    "display_name": "Chris"
  }
}

Product Operations

List Products

GET /gumroad/v2/products

Response:

{
  "success": true,
  "products": [
    {
      "id": "ABC123",
      "name": "My Product",
      "price": 500,
      "currency": "usd",
      "short_url": "https://gumroad.com/l/abc",
      "sales_count": 10,
      "sales_usd_cents": 5000
    }
  ]
}

Get Product

GET /gumroad/v2/products/{product_id}

Update Product

PUT /gumroad/v2/products/{product_id}
Content-Type: application/x-www-form-urlencoded

name=Updated%20Name&price=1000

Enable/Disable Product

PUT /gumroad/v2/products/{product_id}/disable
Content-Type: application/x-www-form-urlencoded

disabled=true

Delete Product

DELETE /gumroad/v2/products/{product_id}

Note: Creating new products via API is not supported. Products must be created through the Gumroad website.

Offer Code Operations

List Offer Codes

GET /gumroad/v2/products/{product_id}/offer_codes

Get Offer Code

GET /gumroad/v2/products/{product_id}/offer_codes/{offer_code_id}

Create Offer Code

POST /gumroad/v2/products/{product_id}/offer_codes
Content-Type: application/x-www-form-urlencoded

name=SUMMER20&amount_off=20

Parameters:

  • name - The code customers enter (required)
  • amount_off - Cents or percentage off (required)
  • offer_type - "cents" or "percent" (default: "cents")
  • max_purchase_count - Maximum uses (optional)

Update Offer Code

PUT /gumroad/v2/products/{product_id}/offer_codes/{offer_code_id}
Content-Type: application/x-www-form-urlencoded

max_purchase_count=100

Delete Offer Code

DELETE /gumroad/v2/products/{product_id}/offer_codes/{offer_code_id}

Sales Operations

List Sales

GET /gumroad/v2/sales

Query parameters:

  • after - Only sales after this date (YYYY-MM-DD)
  • before - Only sales before this date (YYYY-MM-DD)
  • page - Page number for pagination

Example with filters:

GET /gumroad/v2/sales?after=2026-01-01&before=2026-12-31

Response:

{
  "success": true,
  "sales": [
    {
      "id": "sale_abc123",
      "email": "customer@example.com",
      "seller_id": "seller123",
      "product_id": "prod123",
      "product_name": "My Product",
      "price": 500,
      "currency_symbol": "$",
      "created_at": "2026-01-15T10:30:00Z"
    }
  ]
}

Get Sale

GET /gumroad/v2/sales/{sale_id}

Subscriber Operations

List Subscribers

GET /gumroad/v2/products/{product_id}/subscribers

Get Subscriber

GET /gumroad/v2/subscribers/{subscriber_id}

Response:

{
  "success": true,
  "subscriber": {
    "id": "sub123",
    "product_id": "prod123",
    "product_name": "Monthly Subscription",
    "user_id": "user123",
    "user_email": "subscriber@example.com",
    "status": "alive",
    "created_at": "2026-01-01T00:00:00Z"
  }
}

License Operations

Verify License

POST /gumroad/v2/licenses/verify
Content-Type: application/x-www-form-urlencoded

product_id={product_id}&license_key={license_key}

Parameters:

  • product_id - The product ID (required)
  • license_key - The license key to verify (required)
  • increment_uses_count - Increment the use count (default: true)

Response (success):

{
  "success": true,
  "uses": 1,
  "purchase": {
    "seller_id": "seller123",
    "product_id": "prod123",
    "product_name": "My Product",
    "permalink": "abc",
    "email": "customer@example.com",
    "license_key": "ABC-123-DEF",
    "quantity": 1,
    "created_at": "2026-01-15T00:00:00Z"
  }
}

Response (failure):

{
  "success": false,
  "message": "That license does not exist for the provided product."
}

Enable License

PUT /gumroad/v2/licenses/enable
Content-Type: application/x-www-form-urlencoded

product_id={product_id}&license_key={license_key}

Disable License

PUT /gumroad/v2/licenses/disable
Content-Type: application/x-www-form-urlencoded

product_id={product_id}&license_key={license_key}

Decrement License Uses

PUT /gumroad/v2/licenses/decrement_uses_count
Content-Type: application/x-www-form-urlencoded

product_id={product_id}&license_key={license_key}

Resource Subscriptions (Webhooks)

Subscribe to notifications for sales and other events.

List Resource Subscriptions

GET /gumroad/v2/resource_subscriptions?resource_name=sale

Parameters:

  • resource_name - Required. One of: sale, refund, dispute, dispute_won, cancellation, subscription_updated, subscription_ended, subscription_restarted

Response:

{
  "success": true,
  "resource_subscriptions": [
    {
      "id": "wX43hzi-s7W4JfYFkxyeiQ==",
      "resource_name": "sale",
      "post_url": "https://example.com/webhook"
    }
  ]
}

Create Resource Subscription

PUT /gumroad/v2/resource_subscriptions
Content-Type: application/x-www-form-urlencoded

resource_name=sale&post_url=https://example.com/webhook

Response:

{
  "success": true,
  "resource_subscription": {
    "id": "wX43hzi-s7W4JfYFkxyeiQ==",
    "resource_name": "sale",
    "post_url": "https://example.com/webhook"
  }
}

Delete Resource Subscription

DELETE /gumroad/v2/resource_subscriptions/{resource_subscription_id}

Response:

{
  "success": true,
  "message": "The resource_subscription was deleted successfully."
}

Variant Categories

List Variant Categories

GET /gumroad/v2/products/{product_id}/variant_categories

Get Variant Category

GET /gumroad/v2/products/{product_id}/variant_categories/{variant_category_id}

Create Variant Category

POST /gumroad/v2/products/{product_id}/variant_categories
Content-Type: application/x-www-form-urlencoded

title=Size

Delete Variant Category

DELETE /gumroad/v2/products/{product_id}/variant_categories/{variant_category_id}

Variants

List Variants

GET /gumroad/v2/products/{product_id}/variant_categories/{variant_category_id}/variants

Create Variant

POST /gumroad/v2/products/{product_id}/variant_categories/{variant_category_id}/variants
Content-Type: application/x-www-form-urlencoded

name=Large&price_difference=200

Update Variant

PUT /gumroad/v2/products/{product_id}/variant_categories/{variant_category_id}/variants/{variant_id}
Content-Type: application/x-www-form-urlencoded

name=Extra%20Large

Delete Variant

DELETE /gumroad/v2/products/{product_id}/variant_categories/{variant_category_id}/variants/{variant_id}

Custom Fields

List Custom Fields

GET /gumroad/v2/products/{product_id}/custom_fields

Create Custom Field

POST /gumroad/v2/products/{product_id}/custom_fields
Content-Type: application/x-www-form-urlencoded

name=Company%20Name&required=true

Update Custom Field

PUT /gumroad/v2/products/{product_id}/custom_fields/{name}
Content-Type: application/x-www-form-urlencoded

required=false

Delete Custom Field

DELETE /gumroad/v2/products/{product_id}/custom_fields/{name}

Pagination

Gumroad uses page-based pagination for endpoints that return lists:

GET /gumroad/v2/sales?page=1
GET /gumroad/v2/sales?page=2

Continue incrementing the page number until you receive an empty list.

Code Examples

JavaScript

const response = await fetch(
  'https://gateway.maton.ai/gumroad/v2/products',
  {
    headers: {
      'Authorization': `Bearer ${process.env.MATON_API_KEY}`
    }
  }
);
const data = await response.json();

Python

import os
import requests

response = requests.get(
    'https://gateway.maton.ai/gumroad/v2/products',
    headers={'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'}
)
data = response.json()

Python (Verify License)

import os
import requests

response = requests.post(
    'https://gateway.maton.ai/gumroad/v2/licenses/verify',
    headers={'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'},
    data={
        'product_id': 'your_product_id',
        'license_key': 'CUSTOMER-LICENSE-KEY'
    }
)
result = response.json()
if result['success']:
    print(f"License valid! Uses: {result['uses']}")
else:
    print(f"Invalid: {result['message']}")

Notes

  • All responses include a success boolean field
  • Product creation is not available via API - products must be created through the Gumroad website
  • POST/PUT requests use application/x-www-form-urlencoded content type (not JSON)
  • Prices are in cents (e.g., 500 = $5.00)
  • License keys are case-insensitive
  • Resource subscription webhooks send POST requests to your specified URL
  • IMPORTANT: When piping curl output to jq or other commands, environment variables like $MATON_API_KEY may not expand correctly in some shell environments

Error Handling

StatusMeaning
400Missing Gumroad connection or bad request
401Invalid or missing Maton API key
404Resource not found (returned with success: false)
429Rate limited
4xx/5xxPassthrough error from Gumroad API

Gumroad errors typically return HTTP 404 with a JSON body:

{
  "success": false,
  "message": "Error description"
}

Troubleshooting: Invalid API Key

When you receive a "Invalid API key" error, ALWAYS follow these steps before concluding there is an issue:

  1. Check that the MATON_API_KEY environment variable is set:
echo $MATON_API_KEY
  1. Verify the API key is valid by listing connections:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.maton.ai/connections')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

Resources