Publish a product from the test environment to production. This is a one-way, first-publish-only operation that copies the current test version to production.
POST /v1/actions/onetime-product/publish-product
Authentication: API Key
Do not include the X-Environment header for this endpoint. Publishing is always one-way from test to production.
Request Body
Field Type Required Description idstring Yes Product ID (Short ID format PROD_xxx)
Example Request
SDK
TypeScript (fetch)
Java
Python
Go
Rust
C
C++
cURL
wget
const { product } = await client . onetimeProducts . publish ({
id: "PROD_3kF9mNpQrStUvWxYz1A2bC" ,
});
// Uses callApi() helper from authentication.mdx
const result = await callApi ( "POST" , "/v1/actions/onetime-product/publish-product" , {
id: "PROD_3kF9mNpQrStUvWxYz1A2bC" ,
});
console . log ( result . data . product . status ); // => "active"
// Uses callApi() helper from authentication.mdx
String body = """
{"id":"PROD_3kF9mNpQrStUvWxYz1A2bC"}""" ;
String response = callApi ( "POST" , "/v1/actions/onetime-product/publish-product" , body);
System . out . println (response);
# Uses call_api() helper from authentication.mdx
result = call_api( "POST" , "/v1/actions/onetime-product/publish-product" , {
"id" : "PROD_3kF9mNpQrStUvWxYz1A2bC" ,
})
print (result[ "data" ][ "product" ][ "status" ]) # => "active"
// Uses callAPI() helper from authentication.mdx
body := map [ string ] interface {}{
"id" : "PROD_3kF9mNpQrStUvWxYz1A2bC" ,
}
result , err := callAPI ( "POST" , "/v1/actions/onetime-product/publish-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_3kF9mNpQrStUvWxYz1A2bC"
});
let result = call_api ( "POST" , "/v1/actions/onetime-product/publish-product" , & body ) . await ? ;
println! ( "{}" , result );
/* Uses call_api() helper from authentication.mdx */
const char * body = "{ \" id \" : \" PROD_3kF9mNpQrStUvWxYz1A2bC \" }" ;
char * response = call_api ( "POST" , "/v1/actions/onetime-product/publish-product" , body);
printf ( " %s \n " , response);
free (response);
// Uses callApi() helper from authentication.mdx
std ::string body = R"({"id":"PROD_3kF9mNpQrStUvWxYz1A2bC"})" ;
std ::string response = callApi ( "POST" , "/v1/actions/onetime-product/publish-product" , body);
std ::cout << response << std ::endl;
MERCHANT_ID = "MER_2aUyqjCzEIiEcYMKj7TZtw"
TIMESTAMP = $( date +%s )
BODY = '{"id":"PROD_3kF9mNpQrStUvWxYz1A2bC"}'
BODY_HASH = $( echo -n " $BODY " | openssl dgst -sha256 -binary | base64 -w 0 )
CANONICAL_REQUEST = "POST
/v1/actions/onetime-product/publish-product
$TIMESTAMP
$BODY_HASH "
SIGNATURE = $( echo -n " $CANONICAL_REQUEST " | openssl dgst -sha256 -sign private_key.pem | base64 -w 0 )
curl -X POST "https://api.waffo.ai/v1/actions/onetime-product/publish-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_3kF9mNpQrStUvWxYz1A2bC"}'
BODY_HASH = $( echo -n " $BODY " | openssl dgst -sha256 -binary | base64 -w 0 )
CANONICAL_REQUEST = "POST
/v1/actions/onetime-product/publish-product
$TIMESTAMP
$BODY_HASH "
SIGNATURE = $( echo -n " $CANONICAL_REQUEST " | openssl dgst -sha256 -sign private_key.pem | base64 -w 0 )
wget -qO- "https://api.waffo.ai/v1/actions/onetime-product/publish-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_3kF9mNpQrStUvWxYz1A2bC" ,
"storeId" : "STO_2aUyqjCzEIiEcYMKj7TZtw" ,
"name" : "Premium Template Pack" ,
"description" : "50 premium design templates for your next project." ,
"prices" : {
"USD" : { "amount" : "49.00" , "taxCategory" : "digital_goods" },
"EUR" : { "amount" : "45.00" , "taxCategory" : "digital_goods" }
},
"media" : [
{ "type" : "image" , "url" : "https://example.com/templates-preview.png" , "alt" : "Template preview" }
],
"successUrl" : "https://example.com/thank-you" ,
"metadata" : { "category" : "design" , "fileCount" : "50" },
"status" : "active" ,
"createdAt" : "2026-01-15T10:30:00.000Z" ,
"updatedAt" : "2026-01-15T12:00:00.000Z"
}
}
}
Response Fields
Same as Create Product response .
Only the first publish is supported. Once a product has a production version, this endpoint cannot be used again for the same product. To update the production version after initial publish, use the Update Product endpoint with the X-Environment: prod header.
Errors
Retry policy: Never retry 4xx — fix the request and resubmit. Retry 5xx with exponential backoff (start 5s, max 3 attempts).
Status errors[0].messageWhat it means Recommended handling 400 Missing required field: idid not providedFix the body, resubmit 400 Invalid ID formatThe provided Short ID could not be decoded Fix the id format, resubmit 400 No test version foundThe product has no version in the test environment yet Create the product first via Create Product 400 Test version is not activeThe current test version’s status is inactive Activate the test version via Update Status first 400 Already published to productionThe product already has a production version Use Update Product with X-Environment: prod to make further changes 404 Product not foundProduct does not exist or is not accessible Verify the id belongs to your merchant account 500 Internal server errorUnexpected server-side failure Retry with exponential backoff (start 5s, max 3 attempts)