POST /v1/actions/subscription-product/update-product
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Product ID (PROD_xxx format) |
name | string | No | Updated product name (max 64 chars) |
billingPeriod | string | No | weekly, monthly, quarterly, or yearly |
prices | object | No | Updated multi-currency pricing |
description | string | null | No | Updated description (pass null or "" to clear) |
media | array | No | Updated media |
successUrl | string | null | No | Updated redirect URL (max 512 chars, must be a valid http(s) URL; pass null or "" to clear) |
metadata | object | No | Updated metadata (may include trialDays) |
Example Request
const { product } = await client.subscriptionProducts.update({
id: "PROD_3F7H2J5L8N1Q4S6U",
name: "Pro Plan v2",
billingPeriod: BillingPeriod.Monthly,
prices: {
USD: { amount: "39.00", taxIncluded: false, taxCategory: TaxCategory.SaaS },
EUR: { amount: "36.00", taxIncluded: false, taxCategory: TaxCategory.SaaS },
},
metadata: { trialDays: 7 },
});
// Uses callApi() helper from authentication.mdx
const result = await callApi("POST", "/v1/actions/subscription-product/update-product", {
id: "PROD_3F7H2J5L8N1Q4S6U",
name: "Pro Plan v2",
billingPeriod: "monthly",
prices: {
USD: { amount: "39.00", taxIncluded: false, taxCategory: "saas" },
EUR: { amount: "36.00", taxIncluded: false, taxCategory: "saas" },
},
metadata: { trialDays: 7 },
});
console.log(result.data);
// Uses callApi() helper from authentication.mdx
String body = """
{"id":"PROD_3F7H2J5L8N1Q4S6U","name":"Pro Plan v2","billingPeriod":"monthly","prices":{"USD":{"amount":"39.00","taxIncluded":false,"taxCategory":"saas"},"EUR":{"amount":"36.00","taxIncluded":false,"taxCategory":"saas"}},"metadata":{"trialDays":7}}""";
String response = callApi("POST", "/v1/actions/subscription-product/update-product", body);
System.out.println(response);
# Uses call_api() helper from authentication.mdx
result = call_api("POST", "/v1/actions/subscription-product/update-product", {
"id": "PROD_3F7H2J5L8N1Q4S6U",
"name": "Pro Plan v2",
"billingPeriod": "monthly",
"prices": {
"USD": {"amount": "39.00", "taxIncluded": False, "taxCategory": "saas"},
"EUR": {"amount": "36.00", "taxIncluded": False, "taxCategory": "saas"},
},
"metadata": {"trialDays": 7},
})
print(result["data"])
// Uses callAPI() helper from authentication.mdx
body := map[string]interface{}{
"id": "PROD_3F7H2J5L8N1Q4S6U",
"name": "Pro Plan v2",
"billingPeriod": "monthly",
"prices": map[string]interface{}{
"USD": map[string]interface{}{"amount": "39.00", "taxIncluded": false, "taxCategory": "saas"},
"EUR": map[string]interface{}{"amount": "36.00", "taxIncluded": false, "taxCategory": "saas"},
},
"metadata": map[string]interface{}{"trialDays": 7},
}
result, err := callAPI("POST", "/v1/actions/subscription-product/update-product", body)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(result))
// Uses call_api() helper from authentication.mdx
let body = serde_json::json!({
"id": "PROD_3F7H2J5L8N1Q4S6U",
"name": "Pro Plan v2",
"billingPeriod": "monthly",
"prices": {
"USD": {"amount": "39.00", "taxIncluded": false, "taxCategory": "saas"},
"EUR": {"amount": "36.00", "taxIncluded": false, "taxCategory": "saas"}
},
"metadata": {"trialDays": 7}
});
let result = call_api("POST", "/v1/actions/subscription-product/update-product", &body).await?;
println!("{}", result);
/* Uses call_api() helper from authentication.mdx */
const char *body = "{\"id\":\"PROD_3F7H2J5L8N1Q4S6U\",\"name\":\"Pro Plan v2\",\"billingPeriod\":\"monthly\",\"prices\":{\"USD\":{\"amount\":\"39.00\",\"taxIncluded\":false,\"taxCategory\":\"saas\"},\"EUR\":{\"amount\":\"36.00\",\"taxIncluded\":false,\"taxCategory\":\"saas\"}},\"metadata\":{\"trialDays\":7}}";
char *response = call_api("POST", "/v1/actions/subscription-product/update-product", body);
printf("%s\n", response);
free(response);
// Uses callApi() helper from authentication.mdx
std::string body = R"({"id":"PROD_3F7H2J5L8N1Q4S6U","name":"Pro Plan v2","billingPeriod":"monthly","prices":{"USD":{"amount":"39.00","taxIncluded":false,"taxCategory":"saas"},"EUR":{"amount":"36.00","taxIncluded":false,"taxCategory":"saas"}},"metadata":{"trialDays":7}})";
std::string response = callApi("POST", "/v1/actions/subscription-product/update-product", body);
std::cout << response << std::endl;
MERCHANT_ID="MER_2aUyqjCzEIiEcYMKj7TZtw"
TIMESTAMP=$(date +%s)
BODY='{
"id": "PROD_3F7H2J5L8N1Q4S6U",
"name": "Pro Plan v2",
"billingPeriod": "monthly",
"prices": {
"USD": { "amount": "39.00", "taxIncluded": false, "taxCategory": "saas" },
"EUR": { "amount": "36.00", "taxIncluded": false, "taxCategory": "saas" }
},
"metadata": { "trialDays": 7 }
}'
BODY_HASH=$(echo -n "$BODY" | openssl dgst -sha256 -binary | base64 | tr -d '\n')
CANONICAL_REQUEST="POST
/v1/actions/subscription-product/update-product
$TIMESTAMP
$BODY_HASH"
SIGNATURE=$(echo -n "$CANONICAL_REQUEST" | openssl dgst -sha256 -sign private_key.pem | base64 | tr -d '\n')
curl -X POST "https://api.waffo.ai/v1/actions/subscription-product/update-product" \
-H "Content-Type: application/json" \
-H "X-Merchant-Id: $MERCHANT_ID" \
-H "X-Timestamp: $TIMESTAMP" \
-H "X-Signature: $SIGNATURE" \
-d "$BODY"
MERCHANT_ID="MER_2aUyqjCzEIiEcYMKj7TZtw"
TIMESTAMP=$(date +%s)
BODY='{
"id": "PROD_3F7H2J5L8N1Q4S6U",
"name": "Pro Plan v2",
"billingPeriod": "monthly",
"prices": {
"USD": { "amount": "39.00", "taxIncluded": false, "taxCategory": "saas" },
"EUR": { "amount": "36.00", "taxIncluded": false, "taxCategory": "saas" }
},
"metadata": { "trialDays": 7 }
}'
BODY_HASH=$(echo -n "$BODY" | openssl dgst -sha256 -binary | base64 | tr -d '\n')
CANONICAL_REQUEST="POST
/v1/actions/subscription-product/update-product
$TIMESTAMP
$BODY_HASH"
SIGNATURE=$(echo -n "$CANONICAL_REQUEST" | openssl dgst -sha256 -sign private_key.pem | base64 | tr -d '\n')
wget -qO- "https://api.waffo.ai/v1/actions/subscription-product/update-product" \
--header="Content-Type: application/json" \
--header="X-Merchant-Id: $MERCHANT_ID" \
--header="X-Timestamp: $TIMESTAMP" \
--header="X-Signature: $SIGNATURE" \
--post-data="$BODY"
Success Response (200)
{
"data": {
"product": {
"id": "PROD_3F7H2J5L8N1Q4S6U",
"storeId": "STO_2D5F8G3H1K4M6N9P",
"name": "Pro Plan v2",
"description": null,
"billingPeriod": "monthly",
"prices": {
"USD": { "amount": "39.00", "taxCategory": "saas" },
"EUR": { "amount": "36.00", "taxCategory": "saas" }
},
"media": [],
"successUrl": null,
"metadata": { "trialDays": 7 },
"status": "active",
"createdAt": "2026-03-30T10:30:00.000Z",
"updatedAt": "2026-03-30T11:00:00.000Z"
}
}
}
Response Fields
Same as Create Subscription Product response.Product updates create new immutable versions. Existing subscriptions retain their original version. New signups use the latest version. If the submitted content is identical to the current version, no new version is created.
Errors
Retry policy: Never retry 4xx — fix the request and resubmit. Retry 5xx with exponential backoff (start 5s, max 3 attempts).
| Status | errors[0].message | What it means | Recommended handling |
|---|---|---|---|
| 400 | Missing header: x-context-merchant-id | The merchant context header was not forwarded | Fix your SDK configuration |
| 400 | Missing or invalid header: x-context-environment | Environment header is missing or not test / prod | Set X-Environment to test or prod |
| 400 | Missing required field: id | Request body did not include id | Add id, resubmit |
| 400 | Expected format: PROD_xxx, got "X" | id is not a valid Short ID | Use a PROD_ prefixed Short ID |
| 400 | Field name must be a non-empty string | name was provided as an empty string | Omit name to keep current value, or provide a non-empty string |
| 400 | Invalid billingPeriod | billingPeriod is not one of weekly / monthly / quarterly / yearly | Use one of the four allowed values |
| 400 | Field prices must be a non-empty object | prices was provided but empty | Omit prices to keep current value, or include at least one currency |
| 400 | Invalid currency code: "X". Must be 3 uppercase letters (e.g., "USD", "EUR", "JPY") | A key in prices is not a valid ISO 4217 code | Use 3 uppercase letters |
| 400 | Invalid amount for X: "Y". Must be a positive number string (e.g., "9.99", "1000") | Amount string couldn’t be parsed | Use a positive decimal string |
| 400 | Message contains has no version | The target environment (test or prod) has no version yet | Create a version in this environment first (publish from test, or create in test) |
| 401 | Unauthorized | Authentication failed | Verify API key, timestamp, and signature |
| 404 | Product not found / Current version not found | Product ID does not exist (or current version missing) | Verify the product ID |
| 500 | Internal server error | Transient downstream failure | Retry with exponential backoff (start 5s, max 3 attempts) |