Install
openclaw skills install gumroadGumroad API integration with managed OAuth. Access products, sales, subscribers, licenses, and webhooks for your digital storefront. Use this skill when users want to manage their Gumroad products, verify licenses, view sales data, or set up webhook notifications. For other third party apps, use the api-gateway skill (https://clawhub.ai/byungkyu/api-gateway). Requires network access and valid Maton API key.
openclaw skills install gumroadAccess the Gumroad API with managed OAuth authentication. Manage products, view sales, verify licenses, and set up webhooks for your digital storefront.
# Get current user info
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.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
https://api.maton.ai/gumroad/v2/{resource}
Maton proxies requests to api.gumroad.com/v2 and automatically injects your OAuth token.
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"
Manage your Gumroad OAuth connections at https://api.maton.ai.
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.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
python <<'EOF'
import urllib.request, os, json
data = json.dumps({'app': 'gumroad'}).encode()
req = urllib.request.Request('https://api.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
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.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": "{connection_id}",
"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.
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.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
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://api.maton.ai/gumroad/v2/products')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Maton-Connection', '{connection_id}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
If you have multiple connections, always include this header to ensure requests go to the intended account.
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"
}
}
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 /gumroad/v2/products/{product_id}
PUT /gumroad/v2/products/{product_id}
Content-Type: application/x-www-form-urlencoded
name=Updated%20Name&price=1000
PUT /gumroad/v2/products/{product_id}/disable
Content-Type: application/x-www-form-urlencoded
disabled=true
DELETE /gumroad/v2/products/{product_id}
Note: Creating new products via API is not supported. Products must be created through the Gumroad website.
GET /gumroad/v2/products/{product_id}/offer_codes
GET /gumroad/v2/products/{product_id}/offer_codes/{offer_code_id}
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)PUT /gumroad/v2/products/{product_id}/offer_codes/{offer_code_id}
Content-Type: application/x-www-form-urlencoded
max_purchase_count=100
DELETE /gumroad/v2/products/{product_id}/offer_codes/{offer_code_id}
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 paginationExample 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 /gumroad/v2/sales/{sale_id}
GET /gumroad/v2/products/{product_id}/subscribers
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"
}
}
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."
}
PUT /gumroad/v2/licenses/enable
Content-Type: application/x-www-form-urlencoded
product_id={product_id}&license_key={license_key}
PUT /gumroad/v2/licenses/disable
Content-Type: application/x-www-form-urlencoded
product_id={product_id}&license_key={license_key}
PUT /gumroad/v2/licenses/decrement_uses_count
Content-Type: application/x-www-form-urlencoded
product_id={product_id}&license_key={license_key}
Subscribe to notifications for sales and other events.
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_restartedResponse:
{
"success": true,
"resource_subscriptions": [
{
"id": "wX43hzi-s7W4JfYFkxyeiQ==",
"resource_name": "sale",
"post_url": "https://example.com/webhook"
}
]
}
DELETE /gumroad/v2/resource_subscriptions/{resource_subscription_id}
Response:
{
"success": true,
"message": "The resource_subscription was deleted successfully."
}
GET /gumroad/v2/products/{product_id}/variant_categories
GET /gumroad/v2/products/{product_id}/variant_categories/{variant_category_id}
POST /gumroad/v2/products/{product_id}/variant_categories
Content-Type: application/x-www-form-urlencoded
title=Size
DELETE /gumroad/v2/products/{product_id}/variant_categories/{variant_category_id}
GET /gumroad/v2/products/{product_id}/variant_categories/{variant_category_id}/variants
POST /gumroad/v2/products/{product_id}/variant_categories/{variant_category_id}/variants
Content-Type: application/x-www-form-urlencoded
name=Large&price_difference=200
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 /gumroad/v2/products/{product_id}/variant_categories/{variant_category_id}/variants/{variant_id}
GET /gumroad/v2/products/{product_id}/custom_fields
POST /gumroad/v2/products/{product_id}/custom_fields
Content-Type: application/x-www-form-urlencoded
name=Company%20Name&required=true
PUT /gumroad/v2/products/{product_id}/custom_fields/{name}
Content-Type: application/x-www-form-urlencoded
required=false
DELETE /gumroad/v2/products/{product_id}/custom_fields/{name}
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.
const response = await fetch(
'https://api.maton.ai/gumroad/v2/products',
{
headers: {
'Authorization': `Bearer ${process.env.MATON_API_KEY}`
}
}
);
const data = await response.json();
import os
import requests
response = requests.get(
'https://api.maton.ai/gumroad/v2/products',
headers={'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'}
)
data = response.json()
import os
import requests
response = requests.post(
'https://api.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']}")
success boolean fieldapplication/x-www-form-urlencoded content type (not JSON)jq or other commands, environment variables like $MATON_API_KEY may not expand correctly in some shell environments| Status | Meaning |
|---|---|
| 400 | Missing Gumroad connection or bad request |
| 401 | Invalid or missing Maton API key |
| 404 | Resource not found (returned with success: false) |
| 429 | Rate limited |
| 4xx/5xx | Passthrough error from Gumroad API |
Gumroad errors typically return HTTP 404 with a JSON body:
{
"success": false,
"message": "Error description"
}
MATON_API_KEY environment variable is set:echo $MATON_API_KEY
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.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
gumroad. For example:https://api.maton.ai/gumroad/v2/userhttps://api.maton.ai/v2/user