Skip to main content
Create a new one-time purchase product with multi-currency pricing.
POST /v1/actions/onetime-product/create-product
Authentication: API Key

Request Body

FieldTypeRequiredDescription
storeIdstringYesStore ID (Short ID format STO_xxx)
namestringYesProduct name (max 64 chars)
descriptionstring | nullNoProduct description (supports Markdown; pass null or "" to clear)
pricesobjectYesMulti-currency pricing map (see below)
mediaarrayNoProduct images/videos (see below)
successUrlstring | nullNoRedirect URL after successful purchase (max 512 chars, must be a valid http(s) URL; pass null or "" to clear)
metadataobjectNoCustom key-value data (max 50 keys)

Price Object Format

Prices are a map of ISO 4217 currency codes to price configuration objects. At least one currency is required.
{
  "USD": {
    "amount": "29.00",
    "taxIncluded": false,
    "taxCategory": "saas"
  },
  "EUR": {
    "amount": "27.00",
    "taxIncluded": true,
    "taxCategory": "saas"
  }
}
FieldTypeDescription
amountstringPrice as a display format string (e.g., “29.00” = $29.00)
taxIncludedbooleanWhether the amount already includes tax
taxCategorystringTax category for tax calculation
Supported taxCategory values:
ValueDescription
digital_goodsGeneral digital goods
saasSoftware as a Service
softwareDownloadable software
ebookElectronic books
online_courseOnline courses and education
consultingConsulting services
professional_serviceProfessional services

Media Item Format

{
  "type": "image",
  "url": "https://example.com/product.png",
  "alt": "Product screenshot",
  "thumbnail": "https://example.com/product-thumb.png"
}
FieldTypeDescription
typestringimage or video
urlstringMedia URL
altstringAlt text for accessibility
thumbnailstringThumbnail URL (optional for images, recommended for videos)

Example Request

import { WaffoPancake, TaxCategory } from "@waffo/pancake-ts";

const client = new WaffoPancake({
  merchantId: process.env.WAFFO_MERCHANT_ID!,
  privateKey: process.env.WAFFO_PRIVATE_KEY!,
});

const { product } = await client.onetimeProducts.create({
  storeId: "STO_2aUyqjCzEIiEcYMKj7TZtw",
  name: "Premium Template Pack",
  description: "50 premium design templates for your next project.",
  prices: {
    USD: { amount: "49.00", taxIncluded: false, taxCategory: TaxCategory.DigitalGoods },
    EUR: { amount: "45.00", taxIncluded: true, taxCategory: TaxCategory.DigitalGoods },
  },
  media: [
    { type: "image", url: "https://example.com/templates-preview.png", alt: "Template preview" },
  ],
  successUrl: "https://example.com/thank-you",
  metadata: { category: "design", fileCount: "50" },
});

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-15T10:30:00.000Z"
    }
  }
}

Response Fields

The response is wrapped in data.product. The product object is a flattened detail view combining product and version fields.
FieldTypeDescription
idstringProduct ID (PROD_xxx)
storeIdstringStore ID (STO_xxx)
namestringProduct name (from current version)
descriptionstring | nullProduct description (from current version)
pricesobjectMulti-currency pricing map (see below)
mediaarrayMedia items (from current version)
successUrlstring | nullSuccess redirect URL (from current version)
metadataobjectCustom metadata (from current version)
statusstringStatus in the current environment: active or inactive
createdAtstringProduct creation timestamp (ISO 8601)
updatedAtstringProduct last update timestamp (ISO 8601)
Response price object (per currency):
FieldTypeDescription
amountstringPrice as a display format string (e.g., “49.00”)
taxCategorystringTax category for tax calculation
The status field reflects the environment you are operating in. When created in the test environment (default), status is active. When created in the production environment, the production status is returned.

Errors

Retry policy: Never retry 4xx — fix the request and resubmit. Retry 5xx with exponential backoff (start 5s, max 3 attempts).
Statuserrors[0].messageWhat it meansRecommended handling
400Missing required field: storeIdstoreId not providedFix the body, resubmit
400Invalid ID formatThe provided Short ID could not be decodedFix the storeId format, resubmit
400Missing required field: namename not providedFix the body, resubmit
400Prices must have at least one currencyprices is missing or an empty objectProvide at least one currency entry, resubmit
400Invalid currency codeCurrency code must be exactly 3 uppercase letters (ISO 4217, e.g. USD, EUR, JPY)Use a valid ISO 4217 code, resubmit
400Invalid amountAmount must be a positive number string (e.g. "9.99", "100")Use a positive number string, resubmit
404Store not foundStore does not exist or is not accessibleVerify the storeId belongs to your merchant account
500Internal server errorUnexpected server-side failureRetry with exponential backoff (start 5s, max 3 attempts)