Install
openclaw skills install google-merchantGoogle Merchant Center API integration with managed OAuth. This is a write-capable integration — it can read, create, update, and delete products, inventories, data sources, promotions, account settings, and conversions in Google Shopping. Use this skill when users want to interact with their Merchant Center data. All write operations (creating/updating/deleting products, inventories, promotions, data sources, or account settings) require explicit user approval with specific resource identifiers before execution. 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 google-merchantAccess the Google Merchant Center API with managed OAuth authentication. Manage products, inventories, promotions, data sources, and reports for Google Shopping.
# List products in your Merchant Center account
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/google-merchant/products/v1/accounts/{accountId}/products')
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/google-merchant/{sub-api}/{version}/accounts/{accountId}/{resource}
The Merchant API uses a modular sub-API structure:
{sub-api} — the service module: products, accounts, datasources, reports, promotions, inventories, notifications, conversions{version} — currently v1{accountId} — your Merchant Center account IDMaton proxies requests to merchantapi.googleapis.com and automatically injects your OAuth token.
Important: The v1 API requires one-time developer registration. See Developer Registration section.
All requests require the Maton API key in the Authorization header:
Authorization: Bearer $MATON_API_KEY
IMPORTANT: Treat MATON_API_KEY as a secret — do not log it, include it in chats or prompts visible to others, or expose it in shared files or outputs. The key authenticates with Maton, and the Google Merchant connection is independently scoped via OAuth. Use least-privilege Google Merchant access, revoke the connection when no longer needed, and if the key is compromised, rotate it immediately at maton.ai/settings.
Environment Variable: Set your API key as MATON_API_KEY:
export MATON_API_KEY="YOUR_API_KEY"
Your Merchant Center account ID is a numeric identifier. To find it:
https://merchants.google.com/mc/overview?a=ACCOUNT_IDImportant: Before using the v1 API, you must complete a one-time developer registration to associate your account with the API.
Option A: Try fetching via API first
Try listing accounts using the v1beta endpoint. If this works, you can get your account ID automatically:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/google-merchant/accounts/v1beta/accounts')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
try:
result = json.load(urllib.request.urlopen(req))
for account in result.get('accounts', []):
print(f"Account ID: {account['accountId']}, Name: {account['accountName']}")
except Exception as e:
print(f"v1beta not available - use Option B to get your account ID manually")
EOF
Option B: From Merchant Center UI (if Option A fails)
If the v1beta endpoint is unavailable or returns an error:
https://merchants.google.com/mc/overview?a=YOUR_ACCOUNT_IDFor example, if your URL is https://merchants.google.com/mc/overview?a=123456789, your account ID is 123456789.
Call the registerGcp endpoint with your account ID and email:
python <<'EOF'
import urllib.request, os, json
account_id = 'YOUR_ACCOUNT_ID' # From Step 1
developer_email = 'your-email@example.com' # Your Google account email
data = json.dumps({'developerEmail': developer_email}).encode()
req = urllib.request.Request(
f'https://api.maton.ai/google-merchant/accounts/v1/accounts/{account_id}/developerRegistration:registerGcp',
data=data,
method='POST'
)
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Content-Type', 'application/json')
result = json.load(urllib.request.urlopen(req))
print(json.dumps(result, indent=2))
EOF
Response:
{
"name": "accounts/123456789/developerRegistration",
"gcpIds": ["216141799266"]
}
After registration, v1 endpoints will work:
python <<'EOF'
import urllib.request, os, json
account_id = 'YOUR_ACCOUNT_ID'
req = urllib.request.Request(f'https://api.maton.ai/google-merchant/accounts/v1/accounts/{account_id}')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Note: Registration only needs to be done once per Merchant Center account. After registration, all v1 endpoints will work for that account.
Manage your Google Merchant OAuth connections at https://api.maton.ai.
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections?app=google-merchant&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': 'google-merchant'}).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-07T06:41:22.751289Z",
"last_updated_time": "2026-02-07T06:42:29.411979Z",
"url": "https://connect.maton.ai/?session_token=...",
"app": "google-merchant",
"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 Google Merchant 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/google-merchant/products/v1/accounts/123456/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
Always include the Maton-Connection header to ensure requests go to the intended account, especially before any write operation. If you have multiple connections and omit this header, the gateway uses the default connection, which may not be the intended account.
The Merchant API is organized into sub-APIs:
| Sub-API | Purpose | Version |
|---|---|---|
products | Product catalog management | v1 |
accounts | Account settings and users | v1 |
datasources | Data source configuration | v1 |
reports | Analytics and reporting | v1 |
promotions | Promotional offers (requires enrollment) | v1 |
inventories | Local and regional inventory | v1 |
notifications | Webhook subscriptions | v1 |
conversions | Conversion tracking | v1 |
GET /google-merchant/accounts/v1/accounts
Returns all Merchant Center accounts accessible with your OAuth credentials. Use this to find your account ID.
GET /google-merchant/accounts/v1/accounts/{accountId}
GET /google-merchant/accounts/v1/accounts/{accountId}:listSubaccounts
Note: This endpoint only works for multi-client accounts (MCAs). Standard merchant accounts will receive a 403 error.
GET /google-merchant/accounts/v1/accounts/{accountId}/businessInfo
PATCH /google-merchant/accounts/v1/accounts/{accountId}/businessInfo?updateMask=customerService
Content-Type: application/json
{
"customerService": {
"email": "support@example.com"
}
}
GET /google-merchant/accounts/v1/accounts/{accountId}/homepage
GET /google-merchant/accounts/v1/accounts/{accountId}/shippingSettings
POST /google-merchant/accounts/v1/accounts/{accountId}/shippingSettings:insert
Content-Type: application/json
{
"services": [
{
"serviceName": "Standard Shipping",
"deliveryCountries": ["US"],
"currencyCode": "USD",
"deliveryTime": {
"minTransitDays": 3,
"maxTransitDays": 7,
"minHandlingDays": 0,
"maxHandlingDays": 1
},
"rateGroups": [
{
"singleValue": {
"flatRate": {
"amountMicros": "0",
"currencyCode": "USD"
}
}
}
],
"active": true
}
]
}
GET /google-merchant/accounts/v1/accounts/{accountId}/users
GET /google-merchant/accounts/v1/accounts/{accountId}/users/{email}
GET /google-merchant/accounts/v1/accounts/{accountId}/programs
GET /google-merchant/accounts/v1/accounts/{accountId}/regions
GET /google-merchant/accounts/v1/accounts/{accountId}/issues
GET /google-merchant/accounts/v1/accounts/{accountId}/onlineReturnPolicies
GET /google-merchant/products/v1/accounts/{accountId}/products
Query parameters:
pageSize (integer): Maximum results per pagepageToken (string): Pagination tokenGET /google-merchant/products/v1/accounts/{accountId}/products/{productId}
Product ID format: contentLanguage~feedLabel~offerId (e.g., en~US~sku123)
POST /google-merchant/products/v1/accounts/{accountId}/productInputs:insert?dataSource=accounts/{accountId}/dataSources/{dataSourceId}
Content-Type: application/json
{
"offerId": "sku123",
"contentLanguage": "en",
"feedLabel": "US",
"productAttributes": {
"title": "Product Title",
"description": "Product description",
"link": "https://example.com/product",
"imageLink": "https://example.com/image.jpg",
"availability": "in_stock",
"price": {
"amountMicros": "19990000",
"currencyCode": "USD"
},
"condition": "new"
}
}
Note: Products can only be inserted into data sources with input: "API" type. Create an API data source first if needed.
DELETE /google-merchant/products/v1/accounts/{accountId}/productInputs/{productId}?dataSource=accounts/{accountId}/dataSources/{dataSourceId}
GET /google-merchant/inventories/v1/accounts/{accountId}/products/{productId}/localInventories
Note: Local inventories are only available for products with LOCAL channel. Use a product ID like local~en~US~sku123.
POST /google-merchant/inventories/v1/accounts/{accountId}/products/{productId}/localInventories:insert
Content-Type: application/json
{
"storeCode": "store123"
}
Note: The storeCode must be a valid store code configured in your Merchant Center account. Additional inventory attributes may be available - refer to the Google Merchant API Reference for the complete field list.
GET /google-merchant/inventories/v1/accounts/{accountId}/products/{productId}/regionalInventories
GET /google-merchant/datasources/v1/accounts/{accountId}/dataSources
GET /google-merchant/datasources/v1/accounts/{accountId}/dataSources/{dataSourceId}
POST /google-merchant/datasources/v1/accounts/{accountId}/dataSources
Content-Type: application/json
{
"displayName": "API Data Source",
"primaryProductDataSource": {
"feedLabel": "US",
"contentLanguage": "en"
}
}
Response:
{
"name": "accounts/123456/dataSources/789",
"dataSourceId": "789",
"displayName": "API Data Source",
"primaryProductDataSource": {
"feedLabel": "US",
"contentLanguage": "en"
},
"input": "API"
}
PATCH /google-merchant/datasources/v1/accounts/{accountId}/dataSources/{dataSourceId}?updateMask=displayName
Content-Type: application/json
{
"displayName": "Updated Name"
}
DELETE /google-merchant/datasources/v1/accounts/{accountId}/dataSources/{dataSourceId}
POST /google-merchant/datasources/v1/accounts/{accountId}/dataSources/{dataSourceId}:fetch
Note: Fetch only works for data sources with FILE input type. API and UI data sources cannot be fetched.
POST /google-merchant/reports/v1/accounts/{accountId}/reports:search
Content-Type: application/json
{
"query": "SELECT offer_id, title, clicks, impressions FROM product_performance_view WHERE date BETWEEN '2026-01-01' AND '2026-01-31'"
}
Example: Query product_view (requires id field):
{
"query": "SELECT id, offer_id, title, item_issues FROM product_view LIMIT 10"
}
Note: The product_view table requires the id field in the SELECT clause.
Available report tables:
product_performance_view - Clicks, impressions, CTR by productproduct_view - Current inventory with attributes and issues (requires id in SELECT)price_competitiveness_product_view - Pricing vs competitors (requires Market Insights)price_insights_product_view - Suggested pricingbest_sellers_product_cluster_view - Best sellers by category (requires Market Insights)competitive_visibility_competitor_view - Competitor visibilityNote: Promotions require your Merchant Center account to be enrolled in the Promotions program. You'll receive a 403 error if not enrolled.
GET /google-merchant/promotions/v1/accounts/{accountId}/promotions
GET /google-merchant/promotions/v1/accounts/{accountId}/promotions/{promotionId}
POST /google-merchant/promotions/v1/accounts/{accountId}/promotions:insert
Content-Type: application/json
{
"promotionId": "promo123",
"contentLanguage": "en",
"targetCountry": "US",
"redemptionChannel": ["ONLINE"],
"attributes": {
"longTitle": "20% off all products",
"promotionEffectiveDates": "2026-02-01T00:00:00Z/2026-02-28T23:59:59Z"
}
}
GET /google-merchant/notifications/v1/accounts/{accountId}/notificationsubscriptions
POST /google-merchant/notifications/v1/accounts/{accountId}/notificationsubscriptions
Content-Type: application/json
{
"registeredEvent": "PRODUCT_STATUS_CHANGE",
"callBackUri": "https://example.com/webhook",
"allManagedAccounts": true
}
Note: You must specify either allManagedAccounts: true OR targetAccount: "accounts/{accountId}" to indicate which accounts the subscription applies to.
Alternative with targetAccount:
{
"registeredEvent": "PRODUCT_STATUS_CHANGE",
"callBackUri": "https://example.com/webhook",
"targetAccount": "accounts/123456789"
}
DELETE /google-merchant/notifications/v1/accounts/{accountId}/notificationsubscriptions/{subscriptionId}
GET /google-merchant/conversions/v1/accounts/{accountId}/conversionSources
POST /google-merchant/conversions/v1/accounts/{accountId}/conversionSources
Content-Type: application/json
{
"merchantCenterDestination": {
"displayName": "My Conversion Source",
"destination": "SHOPPING_ADS",
"currencyCode": "USD",
"attributionSettings": {
"attributionLookbackWindowDays": 30,
"attributionModel": "CROSS_CHANNEL_LAST_CLICK"
}
}
}
DELETE /google-merchant/conversions/v1/accounts/{accountId}/conversionSources/{conversionSourceId}
The API uses token-based pagination:
GET /google-merchant/products/v1/accounts/{accountId}/products?pageSize=50
Response includes nextPageToken when more results exist:
{
"products": [...],
"nextPageToken": "CAE..."
}
Use the token for the next page:
GET /google-merchant/products/v1/accounts/{accountId}/products?pageSize=50&pageToken=CAE...
const accountId = '123456789';
const response = await fetch(
`https://api.maton.ai/google-merchant/products/v1/accounts/${accountId}/products`,
{
headers: {
'Authorization': `Bearer ${process.env.MATON_API_KEY}`
}
}
);
const data = await response.json();
import os
import requests
account_id = '123456789'
response = requests.get(
f'https://api.maton.ai/google-merchant/products/v1/accounts/{account_id}/products',
headers={'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'}
)
data = response.json()
contentLanguage~feedLabel~offerId (e.g., en~US~sku123)input: "API" typeLOCAL channel (not ONLINE)curl -g when URLs contain brackets to disable glob parsingjq or other commands, environment variables like $MATON_API_KEY may not expand correctly in some shell environments| Status | Meaning |
|---|---|
| 400 | Invalid request or missing Google Merchant connection |
| 401 | Invalid/missing Maton API key, or GCP project not registered (see Developer Registration) |
| 403 | Permission denied - account not enrolled in required program or feature not available |
| 404 | Resource not found |
| 429 | Rate limited |
| 4xx/5xx | Passthrough error from Google Merchant API |
"GCP project is not registered": You need to complete developer registration. See Developer Registration section.
"The caller does not have access to the accounts": The specified account ID is not accessible with your OAuth credentials. Verify you have access to the Merchant Center account.
"Promotion program not enabled": Your Merchant Center account is not enrolled in the Promotions program. Enable it in Merchant Center settings.
"This method can only be accessed by multi-client accounts": You're calling an endpoint (like listSubaccounts) that only works for multi-client accounts (MCAs).
"Mismatched channel": You're trying to access local inventories for an ONLINE product. Local inventories only work with LOCAL channel products.
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
Ensure your URL path starts with google-merchant. For example:
https://api.maton.ai/google-merchant/products/v1/accounts/{accountId}/productshttps://api.maton.ai/products/v1/accounts/{accountId}/productsIf you see an error like "GCP project is not registered with the merchant account":
?a=)registerGcp endpoint with your account ID and email