Docs
Dashboard
On this page

    Products

    48 endpoints. Each needs an API key or OAuth token with the scope shown; the key already names its store, so paths start at /v1/store. Generated from the live contract; also in openapi.json.

    Products with tab counts

    GET/v1/store/products

    Or name the store: GET /v1/stores/{storeId}/products

    catalog:readlistProducts

    Parameters

    • tab"all" | "active" | "draft" | "archived" | "low_stock" | "files" | "keys_and_serials" | "memberships" | "services" | "bundles"query
    • qstring | nullquery
    • cursorstring | nullquery
    • limitinteger | stringquery
    • type"file" | "license_key" | "serial" | "subscription" | "discord_role" | "service" | "bundle" | nullquery
    • idsstring | nullquery
    • categorypcat_… | nullquery
    • collectioncol_… | nullquery
    • sort"created" | "name" | "type" | "price" | "stock" | "sold" | "revenue" | "status" | "updated" | "manual"query
    • dir"asc" | "desc"query

    Response ListProductsResponse

    • itemsProduct[]required
    • nextCursorCursor | nullrequired
    • countsProductCountsrequired

    Example

    curl "https://api.shopfa.st/v1/store/products" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY"
    const res = await fetch('https://api.shopfa.st/v1/store/products', {
      method: 'GET',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
      },
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "GET",
        "https://api.shopfa.st/v1/store/products",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("GET", "https://api.shopfa.st/v1/store/products", nil)
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    Create a product

    POST/v1/store/products

    Or name the store: POST /v1/stores/{storeId}/products

    catalog:writecreateProduct

    Body

    • namestringrequired
    • type"file" | "license_key" | "serial" | "subscription" | "discord_role" | "service" | "bundle"required
    • priceMinorintegerrequired
    • compareAtMinorinteger | nullrequired
    • descriptionstringrequired
    • deliversstringrequired
    • status"active" | "draft" | "archived"required
    • lowStockThresholdintegerrequired

    Response Product

    • idProductIdrequired
    • storeIdStoreIdrequired
    • namestringrequired
    • slugstringrequired
    • typeProductTyperequired
    • statusProductStatusrequired
    • priceMinorMinorUnitsrequired
    • compareAtMinorMinorUnits | nullrequired
    • currencyCurrencyCoderequired
    • descriptionstringrequired
    15 more fields
    • deliversstringrequired
    • coverUrlstringrequired
    • stockinteger | nullrequired
    • lowStockThresholdintegerrequired
    • unitsSoldintegerrequired
    • revenueMinorMinorUnitsrequired
    • createdAtTimestamprequired
    • updatedAtTimestamprequired
    • visibilityProductVisibilityrequired
    • pricingModePricingModerequired
    • variantCountintegerrequired
    • priceMaxMinorMinorUnits | nullrequired
    • tagsstring[]required
    • publishAtTimestamp | nullrequired
    • planLockedAtTimestamp | nullrequired

    Example

    curl -X POST "https://api.shopfa.st/v1/store/products" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
      "name": "string",
      "type": "file",
      "priceMinor": 0,
      "compareAtMinor": 0,
      "description": "string",
      "delivers": "string",
      "status": "active",
      "lowStockThreshold": 0
    }'
    const res = await fetch('https://api.shopfa.st/v1/store/products', {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        "name": "string",
        "type": "file",
        "priceMinor": 0,
        "compareAtMinor": 0,
        "description": "string",
        "delivers": "string",
        "status": "active",
        "lowStockThreshold": 0
      }),
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "POST",
        "https://api.shopfa.st/v1/store/products",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
        json={
          "name": "string",
          "type": "file",
          "priceMinor": 0,
          "compareAtMinor": 0,
          "description": "string",
          "delivers": "string",
          "status": "active",
          "lowStockThreshold": 0
        },
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("POST", "https://api.shopfa.st/v1/store/products", strings.NewReader(`{
      "name": "string",
      "type": "file",
      "priceMinor": 0,
      "compareAtMinor": 0,
      "description": "string",
      "delivers": "string",
      "status": "active",
      "lowStockThreshold": 0
    }`))
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    req.Header.Set("Content-Type", "application/json")
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    One product

    GET/v1/store/products/{productId}

    Or name the store: GET /v1/stores/{storeId}/products/{productId}

    catalog:readgetProduct

    Parameters

    • productIdprd_…pathrequired

    Response Product

    • idProductIdrequired
    • storeIdStoreIdrequired
    • namestringrequired
    • slugstringrequired
    • typeProductTyperequired
    • statusProductStatusrequired
    • priceMinorMinorUnitsrequired
    • compareAtMinorMinorUnits | nullrequired
    • currencyCurrencyCoderequired
    • descriptionstringrequired
    15 more fields
    • deliversstringrequired
    • coverUrlstringrequired
    • stockinteger | nullrequired
    • lowStockThresholdintegerrequired
    • unitsSoldintegerrequired
    • revenueMinorMinorUnitsrequired
    • createdAtTimestamprequired
    • updatedAtTimestamprequired
    • visibilityProductVisibilityrequired
    • pricingModePricingModerequired
    • variantCountintegerrequired
    • priceMaxMinorMinorUnits | nullrequired
    • tagsstring[]required
    • publishAtTimestamp | nullrequired
    • planLockedAtTimestamp | nullrequired

    Example

    curl "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY"
    const res = await fetch('https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk', {
      method: 'GET',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
      },
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "GET",
        "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("GET", "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk", nil)
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    Update a product

    PATCH/v1/store/products/{productId}

    Or name the store: PATCH /v1/stores/{storeId}/products/{productId}

    catalog:writeupdateProduct

    Parameters

    • productIdprd_…pathrequired

    Body

    • namestring
    • type"file" | "license_key" | "serial" | "subscription" | "discord_role" | "service" | "bundle"
    • priceMinorinteger
    • compareAtMinorinteger | null
    • descriptionstring
    • deliversstring
    • status"active" | "draft" | "archived"
    • lowStockThresholdinteger

    Response Product

    • idProductIdrequired
    • storeIdStoreIdrequired
    • namestringrequired
    • slugstringrequired
    • typeProductTyperequired
    • statusProductStatusrequired
    • priceMinorMinorUnitsrequired
    • compareAtMinorMinorUnits | nullrequired
    • currencyCurrencyCoderequired
    • descriptionstringrequired
    15 more fields
    • deliversstringrequired
    • coverUrlstringrequired
    • stockinteger | nullrequired
    • lowStockThresholdintegerrequired
    • unitsSoldintegerrequired
    • revenueMinorMinorUnitsrequired
    • createdAtTimestamprequired
    • updatedAtTimestamprequired
    • visibilityProductVisibilityrequired
    • pricingModePricingModerequired
    • variantCountintegerrequired
    • priceMaxMinorMinorUnits | nullrequired
    • tagsstring[]required
    • publishAtTimestamp | nullrequired
    • planLockedAtTimestamp | nullrequired

    Example

    curl -X PATCH "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
      "name": "string",
      "type": "file",
      "priceMinor": 0,
      "compareAtMinor": 0,
      "description": "string",
      "delivers": "string",
      "status": "active",
      "lowStockThreshold": 0
    }'
    const res = await fetch('https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk', {
      method: 'PATCH',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        "name": "string",
        "type": "file",
        "priceMinor": 0,
        "compareAtMinor": 0,
        "description": "string",
        "delivers": "string",
        "status": "active",
        "lowStockThreshold": 0
      }),
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "PATCH",
        "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
        json={
          "name": "string",
          "type": "file",
          "priceMinor": 0,
          "compareAtMinor": 0,
          "description": "string",
          "delivers": "string",
          "status": "active",
          "lowStockThreshold": 0
        },
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("PATCH", "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk", strings.NewReader(`{
      "name": "string",
      "type": "file",
      "priceMinor": 0,
      "compareAtMinor": 0,
      "description": "string",
      "delivers": "string",
      "status": "active",
      "lowStockThreshold": 0
    }`))
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    req.Header.Set("Content-Type", "application/json")
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    Delete a product (soft: orders keep it, it can be restored, its slug is freed)

    DELETE/v1/store/products/{productId}

    Or name the store: DELETE /v1/stores/{storeId}/products/{productId}

    catalog:writedeleteProduct

    Parameters

    • productIdprd_…pathrequired

    Response Ok

    • okbooleanrequired

    Example

    curl -X DELETE "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY"
    const res = await fetch('https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk', {
      method: 'DELETE',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
      },
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "DELETE",
        "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("DELETE", "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk", nil)
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    Keys in the pool, with who each assigned key went to

    GET/v1/store/products/{productId}/keys

    Or name the store: GET /v1/stores/{storeId}/products/{productId}/keys

    catalog:readlistKeys

    Parameters

    • productIdprd_…pathrequired
    • status"available" | "assigned" | "all"query
    • variantIdvar_… | nullquery
    • qstring | nullquery
    • cursorstring | nullquery
    • limitinteger | stringquery
    • sort"added" | "option" | "status" | "order"query
    • dir"asc" | "desc"query

    Response ListKeysResponse

    • itemsLicenseKeyRow[]required
    • nextCursorCursor | nullrequired
    • statsKeyPoolStatsrequired

    Example

    curl "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/keys" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY"
    const res = await fetch('https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/keys', {
      method: 'GET',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
      },
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "GET",
        "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/keys",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("GET", "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/keys", nil)
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    Add license keys or serials to a product pool (duplicates are skipped)

    POST/v1/store/products/{productId}/keys

    Or name the store: POST /v1/stores/{storeId}/products/{productId}/keys

    catalog:writeaddLicenseKeys

    Parameters

    • productIdprd_…pathrequired

    Body

    • keysstring[]required

    Response AddLicenseKeysResponse

    • addedintegerrequired
    • skippedDuplicatesintegerrequired
    • stockintegerrequired

    Example

    curl -X POST "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/keys" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
      "keys": [
        "string"
      ]
    }'
    const res = await fetch('https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/keys', {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        "keys": [
          "string"
        ]
      }),
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "POST",
        "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/keys",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
        json={
          "keys": [
            "string"
          ]
        },
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("POST", "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/keys", strings.NewReader(`{
      "keys": [
        "string"
      ]
    }`))
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    req.Header.Set("Content-Type", "application/json")
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    Pick the theme template a product page uses (null: the default product template)

    PUT/v1/store/products/{productId}/template

    Or name the store: PUT /v1/stores/{storeId}/products/{productId}/template

    catalog:writerole: catalog:writesetProductTemplate

    Parameters

    • productIdprd_…pathrequired

    Body

    • templateSuffixstring | nullrequired

    Response SetProductTemplateResponse

    • productIdProductIdrequired
    • templateSuffixTemplateSuffix | nullrequired

    Example

    curl -X PUT "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/template" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
      "templateSuffix": "string"
    }'
    const res = await fetch('https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/template', {
      method: 'PUT',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        "templateSuffix": "string"
      }),
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "PUT",
        "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/template",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
        json={
          "templateSuffix": "string"
        },
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("PUT", "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/template", strings.NewReader(`{
      "templateSuffix": "string"
    }`))
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    req.Header.Set("Content-Type", "application/json")
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    Everything the product editor shows: variants, media, files, delivery, checkout fields, SEO and relations

    GET/v1/store/products/{productId}/full

    Or name the store: GET /v1/stores/{storeId}/products/{productId}/full

    catalog:readgetProductFull

    Parameters

    • productIdprd_…pathrequired

    Response ProductFull

    • idProductIdrequired
    • storeIdStoreIdrequired
    • namestringrequired
    • slugstringrequired
    • typeProductTyperequired
    • statusProductStatusrequired
    • priceMinorMinorUnitsrequired
    • compareAtMinorMinorUnits | nullrequired
    • currencyCurrencyCoderequired
    • descriptionstringrequired
    50 more fields
    • deliversstringrequired
    • coverUrlstringrequired
    • stockinteger | nullrequired
    • lowStockThresholdintegerrequired
    • unitsSoldintegerrequired
    • revenueMinorMinorUnitsrequired
    • createdAtTimestamprequired
    • updatedAtTimestamprequired
    • visibilityProductVisibilityrequired
    • pricingModePricingModerequired
    • variantCountintegerrequired
    • priceMaxMinorMinorUnits | nullrequired
    • tagsstring[]required
    • publishAtTimestamp | nullrequired
    • planLockedAtTimestamp | nullrequired
    • descriptionHtmlstringrequired
    • shortDescriptionstringrequired
    • featuredbooleanrequired
    • pwywMinMinorMinorUnits | nullrequired
    • pwywSuggestedMinorMinorUnits | nullrequired
    • taxCategoryTaxCategoryrequired
    • taxCategoryReviewTaxCategoryReview
    • minPerOrderintegerrequired
    • maxPerOrderinteger | nullrequired
    • maxPerCustomerinteger | nullrequired
    • stockModeStockModerequired
    • outOfStockBehaviorOutOfStockBehaviorrequired
    • variantsProductVariant[]required
    • mediaProductMedia[]required
    • filesProductFile[]required
    • keyStatsKeyPoolStats | nullrequired
    • deliveryProductDeliveryrequired
    • checkoutFieldsCheckoutField[]required
    • seoProductSeorequired
    • previousSlugsstring[]required
    • collectionIdsCollectionId[]required
    • categoryIdsCategoryId[]required
    • upsellIdsProductId[]required
    • crossSellIdsProductId[]required
    • bundleProductIdsProductId[]required
    • bundlePartsBundlePart[]required
    • bundlePricingBundlePricingrequired
    • quantityTiersQuantityTier[]required
    • tiersWithCouponsbooleanrequired
    • paymentRulesPaymentRulesrequired
    • affiliateCommissionBpsBps | nullrequired
    • fraudProductFraudrequired
    • templateSuffixstringrequired
    • deletedAtTimestamp | nullrequired
    • attributesProductAttributesrequired

    Example

    curl "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/full" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY"
    const res = await fetch('https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/full', {
      method: 'GET',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
      },
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "GET",
        "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/full",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("GET", "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/full", nil)
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    Save the whole editor document. 409 when someone else saved since baseUpdatedAt

    PUT/v1/store/products/{productId}/full

    Or name the store: PUT /v1/stores/{storeId}/products/{productId}/full

    catalog:writesaveProductFull

    Parameters

    • productIdprd_…pathrequired

    Body

    • productobjectrequired
      • namestringrequired
      • slugstring | nullrequired
      • type"file" | "license_key" | "serial" | "subscription" | "discord_role" | "service" | "bundle"required
      • status"active" | "draft" | "archived"required
      • descriptionstringrequired
      • shortDescriptionstringrequired
      • deliversstringrequired
      • tagsstring[]required
      • visibility"public" | "unlisted" | "private"required
      • publishAtstring | nullrequired
      • featuredbooleanrequired
      • pricingMode"fixed" | "pay_what_you_want" | "free"required
      • priceMinorintegerrequired
      • compareAtMinorinteger | nullrequired
      • pwywMinMinorinteger | nullrequired
      • pwywSuggestedMinorinteger | nullrequired
      • taxCategory"digital_goods" | "ebook" | "software" | "saas" | "online_course" | "membership" | "service" | "exempt"required
      • minPerOrderintegerrequired
      • maxPerOrderinteger | nullrequired
      • maxPerCustomerinteger | nullrequired
      • stockMode"unlimited" | "limited" | "key_pool" | "serial_pool"required
      • stockinteger | nullrequired
      • lowStockThresholdintegerrequired
      • outOfStockBehavior"hide" | "show_sold_out" | "allow_preorder"required
      • variantsobject[]required
        • idvar_… | nullrequired
        • namestringrequired
        • descriptionstringrequired
        • priceMinorintegerrequired
        • compareAtMinorinteger | nullrequired
        • enabledbooleanrequired
        • stockinteger | nullrequired
        • deliveryNotestringrequired
        • fileRefsstring[]required
        • discordRoleIdstring | nullrequired
        • paymentRulesobject | null
        • lowStockThresholdinteger | null
        • newKeysstring[]
      • mediaobject[]required
        • sourceobjectrequired
        • altstringrequired
        • kind"image" | "video" | "youtube" | "vimeo"
        • posterUrlstring | null
        • externalIdstring | null
      • filesobject[]required
        • idfil_… | nullrequired
        • refstringrequired
        • namestringrequired
        • newVersionobject | nullrequired
      • deliveryobjectrequired
        • fileobjectrequired
        • keysobjectrequired
        • discordobjectrequired
        • subscriptionobjectrequired
        • serviceobjectrequired
        • postPurchaseMessagestringrequired
        • redirectUrlstring | nullrequired
        • dynamicobject
        • warrantyobject
      • checkoutFieldsobject[]required
        • idstringrequired
        • labelstringrequired
        • type"text" | "textarea" | "email" | "number" | "select" | "checkbox" | "url" | "password" | "hidden" | "discord_id"required
        • requiredbooleanrequired
        • placeholderstringrequired
        • helpTextstringrequired
        • optionsstring[]required
        • defaultValuestring
      • seoobjectrequired
        • titlestring | nullrequired
        • descriptionstring | nullrequired
        • ogImage"cover" | "custom"required
        • ogImageUrlstring | nullrequired
      • collectionIdscol_…[]required
      • categoryIdspcat_…[]
      • upsellIdsprd_…[]required
      • crossSellIdsprd_…[]required
      • bundleProductIdsprd_…[]required
      • bundlePartsobject[]
        • productIdprd_…required
        • variantIdvar_… | nullrequired
      • bundlePricingobject
      • quantityTiersobject[]
        • minQuantityintegerrequired
        • discountBpsintegerrequired
      • tiersWithCouponsboolean
      • paymentRulesobject
        • disabledMethods"card" | "apple_pay" | "google_pay" | "paypal" | "crypto" | "bank_transfer" | "store_credit" | "manual" | "cash_app" | "skins" | "gift_code"[]required
        • multipliersobject[]required
      • affiliateCommissionBpsinteger | nullrequired
      • fraudobjectrequired
        • blockVpnbooleanrequired
        • requireVerifiedEmailbooleanrequired
      • newKeysstring[]
      • attributesobject
        • gamestring | null
        • platforms"windows" | "mac" | "linux" | "steam" | "epic" | "battlenet" | "riot" | "ea" | "ubisoft" | "xbox" | "playstation" | "switch" | "android" | "ios" | "web" | "other"[]
        • regionstring | null
        • status"undetected" | "updated" | "testing" | "updating" | "detected" | "down" | null
        • statusNotestring
        • statusUpdatedAtstring | null
        • instantDeliveryboolean
        • presetKeystring | null
        • featuresstring[]
        • featureGroupsobject[]
        • requirementsstring[]
    • baseUpdatedAtstring | nullrequired

    Response ProductSaved

    • idProductIdrequired
    • storeIdStoreIdrequired
    • namestringrequired
    • slugstringrequired
    • typeProductTyperequired
    • statusProductStatusrequired
    • priceMinorMinorUnitsrequired
    • compareAtMinorMinorUnits | nullrequired
    • currencyCurrencyCoderequired
    • descriptionstringrequired
    51 more fields
    • deliversstringrequired
    • coverUrlstringrequired
    • stockinteger | nullrequired
    • lowStockThresholdintegerrequired
    • unitsSoldintegerrequired
    • revenueMinorMinorUnitsrequired
    • createdAtTimestamprequired
    • updatedAtTimestamprequired
    • visibilityProductVisibilityrequired
    • pricingModePricingModerequired
    • variantCountintegerrequired
    • priceMaxMinorMinorUnits | nullrequired
    • tagsstring[]required
    • publishAtTimestamp | nullrequired
    • planLockedAtTimestamp | nullrequired
    • descriptionHtmlstringrequired
    • shortDescriptionstringrequired
    • featuredbooleanrequired
    • pwywMinMinorMinorUnits | nullrequired
    • pwywSuggestedMinorMinorUnits | nullrequired
    • taxCategoryTaxCategoryrequired
    • taxCategoryReviewTaxCategoryReview
    • minPerOrderintegerrequired
    • maxPerOrderinteger | nullrequired
    • maxPerCustomerinteger | nullrequired
    • stockModeStockModerequired
    • outOfStockBehaviorOutOfStockBehaviorrequired
    • variantsProductVariant[]required
    • mediaProductMedia[]required
    • filesProductFile[]required
    • keyStatsKeyPoolStats | nullrequired
    • deliveryProductDeliveryrequired
    • checkoutFieldsCheckoutField[]required
    • seoProductSeorequired
    • previousSlugsstring[]required
    • collectionIdsCollectionId[]required
    • categoryIdsCategoryId[]required
    • upsellIdsProductId[]required
    • crossSellIdsProductId[]required
    • bundleProductIdsProductId[]required
    • bundlePartsBundlePart[]required
    • bundlePricingBundlePricingrequired
    • quantityTiersQuantityTier[]required
    • tiersWithCouponsbooleanrequired
    • paymentRulesPaymentRulesrequired
    • affiliateCommissionBpsBps | nullrequired
    • fraudProductFraudrequired
    • templateSuffixstringrequired
    • deletedAtTimestamp | nullrequired
    • attributesProductAttributesrequired
    • keyImportobjectrequired
      • addedintegerrequired
      • alreadyInPoolintegerrequired

    Example

    curl -X PUT "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/full" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
      "product": {
        "name": "string",
        "slug": "string",
        "type": "file",
        "status": "active",
        "description": "string",
        "shortDescription": "string",
        "delivers": "string",
        "tags": [
          "string"
        ],
        "visibility": "public",
        "publishAt": "2026-10-21T12:00:00.000Z",
        "featured": false,
        "pricingMode": "fixed",
        "priceMinor": 0,
        "compareAtMinor": 0,
        "pwywMinMinor": 0,
        "pwywSuggestedMinor": 0,
        "taxCategory": "digital_goods",
        "minPerOrder": 1,
        "maxPerOrder": 1,
        "maxPerCustomer": 1,
        "stockMode": "unlimited",
        "stock": 0,
        "lowStockThreshold": 0,
        "outOfStockBehavior": "hide",
        "variants": [
          {
            "id": "var_0123456789abcdefghjk",
            "name": "string",
            "description": "string",
            "priceMinor": 0,
            "compareAtMinor": 0,
            "enabled": false,
            "stock": 0,
            "deliveryNote": "string",
            "fileRefs": [
              "string"
            ],
            "discordRoleId": "string"
          }
        ],
        "media": [
          {
            "source": {
              "mediaId": "med_0123456789abcdefghjk"
            },
            "alt": "string"
          }
        ],
        "files": [
          {
            "id": "fil_0123456789abcdefghjk",
            "ref": "string",
            "name": "string",
            "newVersion": {
              "uploadId": "upl_0123456789abcdefghjk",
              "version": "string",
              "changelog": "string"
            }
          }
        ],
        "delivery": {
          "file": {
            "downloadLimit": 1,
            "linkExpiryHours": 1,
            "notifyOnUpdate": false
          },
          "keys": {
            "pattern": "string",
            "instructions": "string"
          },
          "discord": {
            "guildId": "string",
            "roleId": "string",
            "roleName": "string",
            "removeOnRefund": false,
            "removeOnExpiry": false
          },
          "subscription": {
            "interval": "week",
            "intervalCount": 1,
            "trialDays": 0,
            "renewalReminderDays": 0,
            "cancelBehavior": "end_of_period",
            "gracePeriodDays": 0
          },
          "service": {
            "instructions": "string",
            "bookingUrl": "https://example.com",
            "turnaroundDays": 1
          },
          "postPurchaseMessage": "string",
          "redirectUrl": "https://example.com"
        },
        "checkoutFields": [
          {
            "id": "string",
            "label": "string",
            "type": "text",
            "required": false,
            "placeholder": "string",
            "helpText": "string",
            "options": [
              "string"
            ]
          }
        ],
        "seo": {
          "title": "string",
          "description": "string",
          "ogImage": "cover",
          "ogImageUrl": "string"
        },
        "collectionIds": [
          "col_0123456789abcdefghjk"
        ],
        "upsellIds": [
          "prd_0123456789abcdefghjk"
        ],
        "crossSellIds": [
          "prd_0123456789abcdefghjk"
        ],
        "bundleProductIds": [
          "prd_0123456789abcdefghjk"
        ],
        "affiliateCommissionBps": 0,
        "fraud": {
          "blockVpn": false,
          "requireVerifiedEmail": false
        }
      },
      "baseUpdatedAt": "2026-10-21T12:00:00.000Z"
    }'
    const res = await fetch('https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/full', {
      method: 'PUT',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        "product": {
          "name": "string",
          "slug": "string",
          "type": "file",
          "status": "active",
          "description": "string",
          "shortDescription": "string",
          "delivers": "string",
          "tags": [
            "string"
          ],
          "visibility": "public",
          "publishAt": "2026-10-21T12:00:00.000Z",
          "featured": false,
          "pricingMode": "fixed",
          "priceMinor": 0,
          "compareAtMinor": 0,
          "pwywMinMinor": 0,
          "pwywSuggestedMinor": 0,
          "taxCategory": "digital_goods",
          "minPerOrder": 1,
          "maxPerOrder": 1,
          "maxPerCustomer": 1,
          "stockMode": "unlimited",
          "stock": 0,
          "lowStockThreshold": 0,
          "outOfStockBehavior": "hide",
          "variants": [
            {
              "id": "var_0123456789abcdefghjk",
              "name": "string",
              "description": "string",
              "priceMinor": 0,
              "compareAtMinor": 0,
              "enabled": false,
              "stock": 0,
              "deliveryNote": "string",
              "fileRefs": [
                "string"
              ],
              "discordRoleId": "string"
            }
          ],
          "media": [
            {
              "source": {
                "mediaId": "med_0123456789abcdefghjk"
              },
              "alt": "string"
            }
          ],
          "files": [
            {
              "id": "fil_0123456789abcdefghjk",
              "ref": "string",
              "name": "string",
              "newVersion": {
                "uploadId": "upl_0123456789abcdefghjk",
                "version": "string",
                "changelog": "string"
              }
            }
          ],
          "delivery": {
            "file": {
              "downloadLimit": 1,
              "linkExpiryHours": 1,
              "notifyOnUpdate": false
            },
            "keys": {
              "pattern": "string",
              "instructions": "string"
            },
            "discord": {
              "guildId": "string",
              "roleId": "string",
              "roleName": "string",
              "removeOnRefund": false,
              "removeOnExpiry": false
            },
            "subscription": {
              "interval": "week",
              "intervalCount": 1,
              "trialDays": 0,
              "renewalReminderDays": 0,
              "cancelBehavior": "end_of_period",
              "gracePeriodDays": 0
            },
            "service": {
              "instructions": "string",
              "bookingUrl": "https://example.com",
              "turnaroundDays": 1
            },
            "postPurchaseMessage": "string",
            "redirectUrl": "https://example.com"
          },
          "checkoutFields": [
            {
              "id": "string",
              "label": "string",
              "type": "text",
              "required": false,
              "placeholder": "string",
              "helpText": "string",
              "options": [
                "string"
              ]
            }
          ],
          "seo": {
            "title": "string",
            "description": "string",
            "ogImage": "cover",
            "ogImageUrl": "string"
          },
          "collectionIds": [
            "col_0123456789abcdefghjk"
          ],
          "upsellIds": [
            "prd_0123456789abcdefghjk"
          ],
          "crossSellIds": [
            "prd_0123456789abcdefghjk"
          ],
          "bundleProductIds": [
            "prd_0123456789abcdefghjk"
          ],
          "affiliateCommissionBps": 0,
          "fraud": {
            "blockVpn": false,
            "requireVerifiedEmail": false
          }
        },
        "baseUpdatedAt": "2026-10-21T12:00:00.000Z"
      }),
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "PUT",
        "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/full",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
        json={
          "product": {
            "name": "string",
            "slug": "string",
            "type": "file",
            "status": "active",
            "description": "string",
            "shortDescription": "string",
            "delivers": "string",
            "tags": [
              "string"
            ],
            "visibility": "public",
            "publishAt": "2026-10-21T12:00:00.000Z",
            "featured": False,
            "pricingMode": "fixed",
            "priceMinor": 0,
            "compareAtMinor": 0,
            "pwywMinMinor": 0,
            "pwywSuggestedMinor": 0,
            "taxCategory": "digital_goods",
            "minPerOrder": 1,
            "maxPerOrder": 1,
            "maxPerCustomer": 1,
            "stockMode": "unlimited",
            "stock": 0,
            "lowStockThreshold": 0,
            "outOfStockBehavior": "hide",
            "variants": [
              {
                "id": "var_0123456789abcdefghjk",
                "name": "string",
                "description": "string",
                "priceMinor": 0,
                "compareAtMinor": 0,
                "enabled": False,
                "stock": 0,
                "deliveryNote": "string",
                "fileRefs": [
                  "string"
                ],
                "discordRoleId": "string"
              }
            ],
            "media": [
              {
                "source": {
                  "mediaId": "med_0123456789abcdefghjk"
                },
                "alt": "string"
              }
            ],
            "files": [
              {
                "id": "fil_0123456789abcdefghjk",
                "ref": "string",
                "name": "string",
                "newVersion": {
                  "uploadId": "upl_0123456789abcdefghjk",
                  "version": "string",
                  "changelog": "string"
                }
              }
            ],
            "delivery": {
              "file": {
                "downloadLimit": 1,
                "linkExpiryHours": 1,
                "notifyOnUpdate": False
              },
              "keys": {
                "pattern": "string",
                "instructions": "string"
              },
              "discord": {
                "guildId": "string",
                "roleId": "string",
                "roleName": "string",
                "removeOnRefund": False,
                "removeOnExpiry": False
              },
              "subscription": {
                "interval": "week",
                "intervalCount": 1,
                "trialDays": 0,
                "renewalReminderDays": 0,
                "cancelBehavior": "end_of_period",
                "gracePeriodDays": 0
              },
              "service": {
                "instructions": "string",
                "bookingUrl": "https://example.com",
                "turnaroundDays": 1
              },
              "postPurchaseMessage": "string",
              "redirectUrl": "https://example.com"
            },
            "checkoutFields": [
              {
                "id": "string",
                "label": "string",
                "type": "text",
                "required": False,
                "placeholder": "string",
                "helpText": "string",
                "options": [
                  "string"
                ]
              }
            ],
            "seo": {
              "title": "string",
              "description": "string",
              "ogImage": "cover",
              "ogImageUrl": "string"
            },
            "collectionIds": [
              "col_0123456789abcdefghjk"
            ],
            "upsellIds": [
              "prd_0123456789abcdefghjk"
            ],
            "crossSellIds": [
              "prd_0123456789abcdefghjk"
            ],
            "bundleProductIds": [
              "prd_0123456789abcdefghjk"
            ],
            "affiliateCommissionBps": 0,
            "fraud": {
              "blockVpn": False,
              "requireVerifiedEmail": False
            }
          },
          "baseUpdatedAt": "2026-10-21T12:00:00.000Z"
        },
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("PUT", "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/full", strings.NewReader(`{
      "product": {
        "name": "string",
        "slug": "string",
        "type": "file",
        "status": "active",
        "description": "string",
        "shortDescription": "string",
        "delivers": "string",
        "tags": [
          "string"
        ],
        "visibility": "public",
        "publishAt": "2026-10-21T12:00:00.000Z",
        "featured": false,
        "pricingMode": "fixed",
        "priceMinor": 0,
        "compareAtMinor": 0,
        "pwywMinMinor": 0,
        "pwywSuggestedMinor": 0,
        "taxCategory": "digital_goods",
        "minPerOrder": 1,
        "maxPerOrder": 1,
        "maxPerCustomer": 1,
        "stockMode": "unlimited",
        "stock": 0,
        "lowStockThreshold": 0,
        "outOfStockBehavior": "hide",
        "variants": [
          {
            "id": "var_0123456789abcdefghjk",
            "name": "string",
            "description": "string",
            "priceMinor": 0,
            "compareAtMinor": 0,
            "enabled": false,
            "stock": 0,
            "deliveryNote": "string",
            "fileRefs": [
              "string"
            ],
            "discordRoleId": "string"
          }
        ],
        "media": [
          {
            "source": {
              "mediaId": "med_0123456789abcdefghjk"
            },
            "alt": "string"
          }
        ],
        "files": [
          {
            "id": "fil_0123456789abcdefghjk",
            "ref": "string",
            "name": "string",
            "newVersion": {
              "uploadId": "upl_0123456789abcdefghjk",
              "version": "string",
              "changelog": "string"
            }
          }
        ],
        "delivery": {
          "file": {
            "downloadLimit": 1,
            "linkExpiryHours": 1,
            "notifyOnUpdate": false
          },
          "keys": {
            "pattern": "string",
            "instructions": "string"
          },
          "discord": {
            "guildId": "string",
            "roleId": "string",
            "roleName": "string",
            "removeOnRefund": false,
            "removeOnExpiry": false
          },
          "subscription": {
            "interval": "week",
            "intervalCount": 1,
            "trialDays": 0,
            "renewalReminderDays": 0,
            "cancelBehavior": "end_of_period",
            "gracePeriodDays": 0
          },
          "service": {
            "instructions": "string",
            "bookingUrl": "https://example.com",
            "turnaroundDays": 1
          },
          "postPurchaseMessage": "string",
          "redirectUrl": "https://example.com"
        },
        "checkoutFields": [
          {
            "id": "string",
            "label": "string",
            "type": "text",
            "required": false,
            "placeholder": "string",
            "helpText": "string",
            "options": [
              "string"
            ]
          }
        ],
        "seo": {
          "title": "string",
          "description": "string",
          "ogImage": "cover",
          "ogImageUrl": "string"
        },
        "collectionIds": [
          "col_0123456789abcdefghjk"
        ],
        "upsellIds": [
          "prd_0123456789abcdefghjk"
        ],
        "crossSellIds": [
          "prd_0123456789abcdefghjk"
        ],
        "bundleProductIds": [
          "prd_0123456789abcdefghjk"
        ],
        "affiliateCommissionBps": 0,
        "fraud": {
          "blockVpn": false,
          "requireVerifiedEmail": false
        }
      },
      "baseUpdatedAt": "2026-10-21T12:00:00.000Z"
    }`))
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    req.Header.Set("Content-Type", "application/json")
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    Create a product from the editor (description sanitized, slug unique per store)

    POST/v1/store/products/full

    Or name the store: POST /v1/stores/{storeId}/products/full

    catalog:writecreateProductFull

    Body

    • namestringrequired
    • slugstring | nullrequired
    • type"file" | "license_key" | "serial" | "subscription" | "discord_role" | "service" | "bundle"required
    • status"active" | "draft" | "archived"required
    • descriptionstringrequired
    • shortDescriptionstringrequired
    • deliversstringrequired
    • tagsstring[]required
    • visibility"public" | "unlisted" | "private"required
    • publishAtstring | nullrequired
    • featuredbooleanrequired
    • pricingMode"fixed" | "pay_what_you_want" | "free"required
    • priceMinorintegerrequired
    • compareAtMinorinteger | nullrequired
    • pwywMinMinorinteger | nullrequired
    • pwywSuggestedMinorinteger | nullrequired
    • taxCategory"digital_goods" | "ebook" | "software" | "saas" | "online_course" | "membership" | "service" | "exempt"required
    • minPerOrderintegerrequired
    • maxPerOrderinteger | nullrequired
    • maxPerCustomerinteger | nullrequired
    • stockMode"unlimited" | "limited" | "key_pool" | "serial_pool"required
    • stockinteger | nullrequired
    • lowStockThresholdintegerrequired
    • outOfStockBehavior"hide" | "show_sold_out" | "allow_preorder"required
    • variantsobject[]required
      • idvar_… | nullrequired
      • namestringrequired
      • descriptionstringrequired
      • priceMinorintegerrequired
      • compareAtMinorinteger | nullrequired
      • enabledbooleanrequired
      • stockinteger | nullrequired
      • deliveryNotestringrequired
      • fileRefsstring[]required
      • discordRoleIdstring | nullrequired
      • paymentRulesobject | null
      • lowStockThresholdinteger | null
      • newKeysstring[]
    • mediaobject[]required
      • sourceobjectrequired
      • altstringrequired
      • kind"image" | "video" | "youtube" | "vimeo"
      • posterUrlstring | null
      • externalIdstring | null
    • filesobject[]required
      • idfil_… | nullrequired
      • refstringrequired
      • namestringrequired
      • newVersionobject | nullrequired
    • deliveryobjectrequired
      • fileobjectrequired
        • downloadLimitinteger | nullrequired
        • linkExpiryHoursinteger | nullrequired
        • notifyOnUpdatebooleanrequired
      • keysobjectrequired
        • patternstring | nullrequired
        • instructionsstringrequired
      • discordobjectrequired
        • guildIdstring | nullrequired
        • roleIdstring | nullrequired
        • roleNamestringrequired
        • removeOnRefundbooleanrequired
        • removeOnExpirybooleanrequired
        • mode"disabled" | "optional" | "mandatory"
        • extraGrantsobject[]
      • subscriptionobjectrequired
        • interval"week" | "month" | "year"required
        • intervalCountintegerrequired
        • trialDaysintegerrequired
        • renewalReminderDaysintegerrequired
        • cancelBehavior"end_of_period" | "immediately"required
        • gracePeriodDaysintegerrequired
      • serviceobjectrequired
        • instructionsstringrequired
        • bookingUrlstring | nullrequired
        • turnaroundDaysinteger | nullrequired
      • postPurchaseMessagestringrequired
      • redirectUrlstring | nullrequired
      • dynamicobject
        • enabledbooleanrequired
        • urlstring | nullrequired
        • secretVersionintegerrequired
      • warrantyobject
        • daysinteger | nullrequired
        • termsstringrequired
    • checkoutFieldsobject[]required
      • idstringrequired
      • labelstringrequired
      • type"text" | "textarea" | "email" | "number" | "select" | "checkbox" | "url" | "password" | "hidden" | "discord_id"required
      • requiredbooleanrequired
      • placeholderstringrequired
      • helpTextstringrequired
      • optionsstring[]required
      • defaultValuestring
    • seoobjectrequired
      • titlestring | nullrequired
      • descriptionstring | nullrequired
      • ogImage"cover" | "custom"required
      • ogImageUrlstring | nullrequired
    • collectionIdscol_…[]required
    • categoryIdspcat_…[]
    • upsellIdsprd_…[]required
    • crossSellIdsprd_…[]required
    • bundleProductIdsprd_…[]required
    • bundlePartsobject[]
      • productIdprd_…required
      • variantIdvar_… | nullrequired
    • bundlePricingobject
    • quantityTiersobject[]
      • minQuantityintegerrequired
      • discountBpsintegerrequired
    • tiersWithCouponsboolean
    • paymentRulesobject
      • disabledMethods"card" | "apple_pay" | "google_pay" | "paypal" | "crypto" | "bank_transfer" | "store_credit" | "manual" | "cash_app" | "skins" | "gift_code"[]required
      • multipliersobject[]required
        • method"card" | "apple_pay" | "google_pay" | "paypal" | "crypto" | "bank_transfer" | "store_credit" | "manual" | "cash_app" | "skins" | "gift_code"required
        • bpsintegerrequired
    • affiliateCommissionBpsinteger | nullrequired
    • fraudobjectrequired
      • blockVpnbooleanrequired
      • requireVerifiedEmailbooleanrequired
    • newKeysstring[]
    • attributesobject
      • gamestring | null
      • platforms"windows" | "mac" | "linux" | "steam" | "epic" | "battlenet" | "riot" | "ea" | "ubisoft" | "xbox" | "playstation" | "switch" | "android" | "ios" | "web" | "other"[]
      • regionstring | null
      • status"undetected" | "updated" | "testing" | "updating" | "detected" | "down" | null
      • statusNotestring
      • statusUpdatedAtstring | null
      • instantDeliveryboolean
      • presetKeystring | null
      • featuresstring[]
      • featureGroupsobject[]
        • titlestringrequired
        • itemsstring[]required
      • requirementsstring[]

    Response ProductSaved

    • idProductIdrequired
    • storeIdStoreIdrequired
    • namestringrequired
    • slugstringrequired
    • typeProductTyperequired
    • statusProductStatusrequired
    • priceMinorMinorUnitsrequired
    • compareAtMinorMinorUnits | nullrequired
    • currencyCurrencyCoderequired
    • descriptionstringrequired
    51 more fields
    • deliversstringrequired
    • coverUrlstringrequired
    • stockinteger | nullrequired
    • lowStockThresholdintegerrequired
    • unitsSoldintegerrequired
    • revenueMinorMinorUnitsrequired
    • createdAtTimestamprequired
    • updatedAtTimestamprequired
    • visibilityProductVisibilityrequired
    • pricingModePricingModerequired
    • variantCountintegerrequired
    • priceMaxMinorMinorUnits | nullrequired
    • tagsstring[]required
    • publishAtTimestamp | nullrequired
    • planLockedAtTimestamp | nullrequired
    • descriptionHtmlstringrequired
    • shortDescriptionstringrequired
    • featuredbooleanrequired
    • pwywMinMinorMinorUnits | nullrequired
    • pwywSuggestedMinorMinorUnits | nullrequired
    • taxCategoryTaxCategoryrequired
    • taxCategoryReviewTaxCategoryReview
    • minPerOrderintegerrequired
    • maxPerOrderinteger | nullrequired
    • maxPerCustomerinteger | nullrequired
    • stockModeStockModerequired
    • outOfStockBehaviorOutOfStockBehaviorrequired
    • variantsProductVariant[]required
    • mediaProductMedia[]required
    • filesProductFile[]required
    • keyStatsKeyPoolStats | nullrequired
    • deliveryProductDeliveryrequired
    • checkoutFieldsCheckoutField[]required
    • seoProductSeorequired
    • previousSlugsstring[]required
    • collectionIdsCollectionId[]required
    • categoryIdsCategoryId[]required
    • upsellIdsProductId[]required
    • crossSellIdsProductId[]required
    • bundleProductIdsProductId[]required
    • bundlePartsBundlePart[]required
    • bundlePricingBundlePricingrequired
    • quantityTiersQuantityTier[]required
    • tiersWithCouponsbooleanrequired
    • paymentRulesPaymentRulesrequired
    • affiliateCommissionBpsBps | nullrequired
    • fraudProductFraudrequired
    • templateSuffixstringrequired
    • deletedAtTimestamp | nullrequired
    • attributesProductAttributesrequired
    • keyImportobjectrequired
      • addedintegerrequired
      • alreadyInPoolintegerrequired

    Example

    curl -X POST "https://api.shopfa.st/v1/store/products/full" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
      "name": "string",
      "slug": "string",
      "type": "file",
      "status": "active",
      "description": "string",
      "shortDescription": "string",
      "delivers": "string",
      "tags": [
        "string"
      ],
      "visibility": "public",
      "publishAt": "2026-10-21T12:00:00.000Z",
      "featured": false,
      "pricingMode": "fixed",
      "priceMinor": 0,
      "compareAtMinor": 0,
      "pwywMinMinor": 0,
      "pwywSuggestedMinor": 0,
      "taxCategory": "digital_goods",
      "minPerOrder": 1,
      "maxPerOrder": 1,
      "maxPerCustomer": 1,
      "stockMode": "unlimited",
      "stock": 0,
      "lowStockThreshold": 0,
      "outOfStockBehavior": "hide",
      "variants": [
        {
          "id": "var_0123456789abcdefghjk",
          "name": "string",
          "description": "string",
          "priceMinor": 0,
          "compareAtMinor": 0,
          "enabled": false,
          "stock": 0,
          "deliveryNote": "string",
          "fileRefs": [
            "string"
          ],
          "discordRoleId": "string"
        }
      ],
      "media": [
        {
          "source": {
            "mediaId": "med_0123456789abcdefghjk"
          },
          "alt": "string"
        }
      ],
      "files": [
        {
          "id": "fil_0123456789abcdefghjk",
          "ref": "string",
          "name": "string",
          "newVersion": {
            "uploadId": "upl_0123456789abcdefghjk",
            "version": "string",
            "changelog": "string"
          }
        }
      ],
      "delivery": {
        "file": {
          "downloadLimit": 1,
          "linkExpiryHours": 1,
          "notifyOnUpdate": false
        },
        "keys": {
          "pattern": "string",
          "instructions": "string"
        },
        "discord": {
          "guildId": "string",
          "roleId": "string",
          "roleName": "string",
          "removeOnRefund": false,
          "removeOnExpiry": false
        },
        "subscription": {
          "interval": "week",
          "intervalCount": 1,
          "trialDays": 0,
          "renewalReminderDays": 0,
          "cancelBehavior": "end_of_period",
          "gracePeriodDays": 0
        },
        "service": {
          "instructions": "string",
          "bookingUrl": "https://example.com",
          "turnaroundDays": 1
        },
        "postPurchaseMessage": "string",
        "redirectUrl": "https://example.com"
      },
      "checkoutFields": [
        {
          "id": "string",
          "label": "string",
          "type": "text",
          "required": false,
          "placeholder": "string",
          "helpText": "string",
          "options": [
            "string"
          ]
        }
      ],
      "seo": {
        "title": "string",
        "description": "string",
        "ogImage": "cover",
        "ogImageUrl": "string"
      },
      "collectionIds": [
        "col_0123456789abcdefghjk"
      ],
      "categoryIds": [
        "pcat_0123456789abcdefghjk"
      ],
      "upsellIds": [
        "prd_0123456789abcdefghjk"
      ],
      "crossSellIds": [
        "prd_0123456789abcdefghjk"
      ],
      "bundleProductIds": [
        "prd_0123456789abcdefghjk"
      ],
      "bundleParts": [],
      "bundlePricing": {
        "kind": "fixed"
      },
      "quantityTiers": [],
      "tiersWithCoupons": true,
      "paymentRules": {
        "disabledMethods": [],
        "multipliers": []
      },
      "affiliateCommissionBps": 0,
      "fraud": {
        "blockVpn": false,
        "requireVerifiedEmail": false
      },
      "newKeys": [],
      "attributes": {}
    }'
    const res = await fetch('https://api.shopfa.st/v1/store/products/full', {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        "name": "string",
        "slug": "string",
        "type": "file",
        "status": "active",
        "description": "string",
        "shortDescription": "string",
        "delivers": "string",
        "tags": [
          "string"
        ],
        "visibility": "public",
        "publishAt": "2026-10-21T12:00:00.000Z",
        "featured": false,
        "pricingMode": "fixed",
        "priceMinor": 0,
        "compareAtMinor": 0,
        "pwywMinMinor": 0,
        "pwywSuggestedMinor": 0,
        "taxCategory": "digital_goods",
        "minPerOrder": 1,
        "maxPerOrder": 1,
        "maxPerCustomer": 1,
        "stockMode": "unlimited",
        "stock": 0,
        "lowStockThreshold": 0,
        "outOfStockBehavior": "hide",
        "variants": [
          {
            "id": "var_0123456789abcdefghjk",
            "name": "string",
            "description": "string",
            "priceMinor": 0,
            "compareAtMinor": 0,
            "enabled": false,
            "stock": 0,
            "deliveryNote": "string",
            "fileRefs": [
              "string"
            ],
            "discordRoleId": "string"
          }
        ],
        "media": [
          {
            "source": {
              "mediaId": "med_0123456789abcdefghjk"
            },
            "alt": "string"
          }
        ],
        "files": [
          {
            "id": "fil_0123456789abcdefghjk",
            "ref": "string",
            "name": "string",
            "newVersion": {
              "uploadId": "upl_0123456789abcdefghjk",
              "version": "string",
              "changelog": "string"
            }
          }
        ],
        "delivery": {
          "file": {
            "downloadLimit": 1,
            "linkExpiryHours": 1,
            "notifyOnUpdate": false
          },
          "keys": {
            "pattern": "string",
            "instructions": "string"
          },
          "discord": {
            "guildId": "string",
            "roleId": "string",
            "roleName": "string",
            "removeOnRefund": false,
            "removeOnExpiry": false
          },
          "subscription": {
            "interval": "week",
            "intervalCount": 1,
            "trialDays": 0,
            "renewalReminderDays": 0,
            "cancelBehavior": "end_of_period",
            "gracePeriodDays": 0
          },
          "service": {
            "instructions": "string",
            "bookingUrl": "https://example.com",
            "turnaroundDays": 1
          },
          "postPurchaseMessage": "string",
          "redirectUrl": "https://example.com"
        },
        "checkoutFields": [
          {
            "id": "string",
            "label": "string",
            "type": "text",
            "required": false,
            "placeholder": "string",
            "helpText": "string",
            "options": [
              "string"
            ]
          }
        ],
        "seo": {
          "title": "string",
          "description": "string",
          "ogImage": "cover",
          "ogImageUrl": "string"
        },
        "collectionIds": [
          "col_0123456789abcdefghjk"
        ],
        "categoryIds": [
          "pcat_0123456789abcdefghjk"
        ],
        "upsellIds": [
          "prd_0123456789abcdefghjk"
        ],
        "crossSellIds": [
          "prd_0123456789abcdefghjk"
        ],
        "bundleProductIds": [
          "prd_0123456789abcdefghjk"
        ],
        "bundleParts": [],
        "bundlePricing": {
          "kind": "fixed"
        },
        "quantityTiers": [],
        "tiersWithCoupons": true,
        "paymentRules": {
          "disabledMethods": [],
          "multipliers": []
        },
        "affiliateCommissionBps": 0,
        "fraud": {
          "blockVpn": false,
          "requireVerifiedEmail": false
        },
        "newKeys": [],
        "attributes": {}
      }),
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "POST",
        "https://api.shopfa.st/v1/store/products/full",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
        json={
          "name": "string",
          "slug": "string",
          "type": "file",
          "status": "active",
          "description": "string",
          "shortDescription": "string",
          "delivers": "string",
          "tags": [
            "string"
          ],
          "visibility": "public",
          "publishAt": "2026-10-21T12:00:00.000Z",
          "featured": False,
          "pricingMode": "fixed",
          "priceMinor": 0,
          "compareAtMinor": 0,
          "pwywMinMinor": 0,
          "pwywSuggestedMinor": 0,
          "taxCategory": "digital_goods",
          "minPerOrder": 1,
          "maxPerOrder": 1,
          "maxPerCustomer": 1,
          "stockMode": "unlimited",
          "stock": 0,
          "lowStockThreshold": 0,
          "outOfStockBehavior": "hide",
          "variants": [
            {
              "id": "var_0123456789abcdefghjk",
              "name": "string",
              "description": "string",
              "priceMinor": 0,
              "compareAtMinor": 0,
              "enabled": False,
              "stock": 0,
              "deliveryNote": "string",
              "fileRefs": [
                "string"
              ],
              "discordRoleId": "string"
            }
          ],
          "media": [
            {
              "source": {
                "mediaId": "med_0123456789abcdefghjk"
              },
              "alt": "string"
            }
          ],
          "files": [
            {
              "id": "fil_0123456789abcdefghjk",
              "ref": "string",
              "name": "string",
              "newVersion": {
                "uploadId": "upl_0123456789abcdefghjk",
                "version": "string",
                "changelog": "string"
              }
            }
          ],
          "delivery": {
            "file": {
              "downloadLimit": 1,
              "linkExpiryHours": 1,
              "notifyOnUpdate": False
            },
            "keys": {
              "pattern": "string",
              "instructions": "string"
            },
            "discord": {
              "guildId": "string",
              "roleId": "string",
              "roleName": "string",
              "removeOnRefund": False,
              "removeOnExpiry": False
            },
            "subscription": {
              "interval": "week",
              "intervalCount": 1,
              "trialDays": 0,
              "renewalReminderDays": 0,
              "cancelBehavior": "end_of_period",
              "gracePeriodDays": 0
            },
            "service": {
              "instructions": "string",
              "bookingUrl": "https://example.com",
              "turnaroundDays": 1
            },
            "postPurchaseMessage": "string",
            "redirectUrl": "https://example.com"
          },
          "checkoutFields": [
            {
              "id": "string",
              "label": "string",
              "type": "text",
              "required": False,
              "placeholder": "string",
              "helpText": "string",
              "options": [
                "string"
              ]
            }
          ],
          "seo": {
            "title": "string",
            "description": "string",
            "ogImage": "cover",
            "ogImageUrl": "string"
          },
          "collectionIds": [
            "col_0123456789abcdefghjk"
          ],
          "categoryIds": [
            "pcat_0123456789abcdefghjk"
          ],
          "upsellIds": [
            "prd_0123456789abcdefghjk"
          ],
          "crossSellIds": [
            "prd_0123456789abcdefghjk"
          ],
          "bundleProductIds": [
            "prd_0123456789abcdefghjk"
          ],
          "bundleParts": [],
          "bundlePricing": {
            "kind": "fixed"
          },
          "quantityTiers": [],
          "tiersWithCoupons": True,
          "paymentRules": {
            "disabledMethods": [],
            "multipliers": []
          },
          "affiliateCommissionBps": 0,
          "fraud": {
            "blockVpn": False,
            "requireVerifiedEmail": False
          },
          "newKeys": [],
          "attributes": {}
        },
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("POST", "https://api.shopfa.st/v1/store/products/full", strings.NewReader(`{
      "name": "string",
      "slug": "string",
      "type": "file",
      "status": "active",
      "description": "string",
      "shortDescription": "string",
      "delivers": "string",
      "tags": [
        "string"
      ],
      "visibility": "public",
      "publishAt": "2026-10-21T12:00:00.000Z",
      "featured": false,
      "pricingMode": "fixed",
      "priceMinor": 0,
      "compareAtMinor": 0,
      "pwywMinMinor": 0,
      "pwywSuggestedMinor": 0,
      "taxCategory": "digital_goods",
      "minPerOrder": 1,
      "maxPerOrder": 1,
      "maxPerCustomer": 1,
      "stockMode": "unlimited",
      "stock": 0,
      "lowStockThreshold": 0,
      "outOfStockBehavior": "hide",
      "variants": [
        {
          "id": "var_0123456789abcdefghjk",
          "name": "string",
          "description": "string",
          "priceMinor": 0,
          "compareAtMinor": 0,
          "enabled": false,
          "stock": 0,
          "deliveryNote": "string",
          "fileRefs": [
            "string"
          ],
          "discordRoleId": "string"
        }
      ],
      "media": [
        {
          "source": {
            "mediaId": "med_0123456789abcdefghjk"
          },
          "alt": "string"
        }
      ],
      "files": [
        {
          "id": "fil_0123456789abcdefghjk",
          "ref": "string",
          "name": "string",
          "newVersion": {
            "uploadId": "upl_0123456789abcdefghjk",
            "version": "string",
            "changelog": "string"
          }
        }
      ],
      "delivery": {
        "file": {
          "downloadLimit": 1,
          "linkExpiryHours": 1,
          "notifyOnUpdate": false
        },
        "keys": {
          "pattern": "string",
          "instructions": "string"
        },
        "discord": {
          "guildId": "string",
          "roleId": "string",
          "roleName": "string",
          "removeOnRefund": false,
          "removeOnExpiry": false
        },
        "subscription": {
          "interval": "week",
          "intervalCount": 1,
          "trialDays": 0,
          "renewalReminderDays": 0,
          "cancelBehavior": "end_of_period",
          "gracePeriodDays": 0
        },
        "service": {
          "instructions": "string",
          "bookingUrl": "https://example.com",
          "turnaroundDays": 1
        },
        "postPurchaseMessage": "string",
        "redirectUrl": "https://example.com"
      },
      "checkoutFields": [
        {
          "id": "string",
          "label": "string",
          "type": "text",
          "required": false,
          "placeholder": "string",
          "helpText": "string",
          "options": [
            "string"
          ]
        }
      ],
      "seo": {
        "title": "string",
        "description": "string",
        "ogImage": "cover",
        "ogImageUrl": "string"
      },
      "collectionIds": [
        "col_0123456789abcdefghjk"
      ],
      "categoryIds": [
        "pcat_0123456789abcdefghjk"
      ],
      "upsellIds": [
        "prd_0123456789abcdefghjk"
      ],
      "crossSellIds": [
        "prd_0123456789abcdefghjk"
      ],
      "bundleProductIds": [
        "prd_0123456789abcdefghjk"
      ],
      "bundleParts": [],
      "bundlePricing": {
        "kind": "fixed"
      },
      "quantityTiers": [],
      "tiersWithCoupons": true,
      "paymentRules": {
        "disabledMethods": [],
        "multipliers": []
      },
      "affiliateCommissionBps": 0,
      "fraud": {
        "blockVpn": false,
        "requireVerifiedEmail": false
      },
      "newKeys": [],
      "attributes": {}
    }`))
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    req.Header.Set("Content-Type", "application/json")
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    Who last changed a product and when, and how many sales changed its stock since a time (the editor explains a save conflict with it)

    GET/v1/store/products/{productId}/last-edit

    Or name the store: GET /v1/stores/{storeId}/products/{productId}/last-edit

    catalog:readgetProductLastEdit

    Parameters

    • productIdprd_…pathrequired
    • sincestring | nullquery

    Response ProductLastEdit

    • updatedAtTimestamprequired
    • editedByobject | nullrequired
    • editedAtTimestamp | nullrequired
    • salesSinceintegerrequired

    Example

    curl "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/last-edit" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY"
    const res = await fetch('https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/last-edit', {
      method: 'GET',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
      },
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "GET",
        "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/last-edit",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("GET", "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/last-edit", nil)
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    Copy a product as a draft (variants, media, files, settings; not keys or sales)

    POST/v1/store/products/{productId}/duplicate

    Or name the store: POST /v1/stores/{storeId}/products/{productId}/duplicate

    catalog:writeduplicateProduct

    Parameters

    • productIdprd_…pathrequired

    Response ProductFull

    • idProductIdrequired
    • storeIdStoreIdrequired
    • namestringrequired
    • slugstringrequired
    • typeProductTyperequired
    • statusProductStatusrequired
    • priceMinorMinorUnitsrequired
    • compareAtMinorMinorUnits | nullrequired
    • currencyCurrencyCoderequired
    • descriptionstringrequired
    50 more fields
    • deliversstringrequired
    • coverUrlstringrequired
    • stockinteger | nullrequired
    • lowStockThresholdintegerrequired
    • unitsSoldintegerrequired
    • revenueMinorMinorUnitsrequired
    • createdAtTimestamprequired
    • updatedAtTimestamprequired
    • visibilityProductVisibilityrequired
    • pricingModePricingModerequired
    • variantCountintegerrequired
    • priceMaxMinorMinorUnits | nullrequired
    • tagsstring[]required
    • publishAtTimestamp | nullrequired
    • planLockedAtTimestamp | nullrequired
    • descriptionHtmlstringrequired
    • shortDescriptionstringrequired
    • featuredbooleanrequired
    • pwywMinMinorMinorUnits | nullrequired
    • pwywSuggestedMinorMinorUnits | nullrequired
    • taxCategoryTaxCategoryrequired
    • taxCategoryReviewTaxCategoryReview
    • minPerOrderintegerrequired
    • maxPerOrderinteger | nullrequired
    • maxPerCustomerinteger | nullrequired
    • stockModeStockModerequired
    • outOfStockBehaviorOutOfStockBehaviorrequired
    • variantsProductVariant[]required
    • mediaProductMedia[]required
    • filesProductFile[]required
    • keyStatsKeyPoolStats | nullrequired
    • deliveryProductDeliveryrequired
    • checkoutFieldsCheckoutField[]required
    • seoProductSeorequired
    • previousSlugsstring[]required
    • collectionIdsCollectionId[]required
    • categoryIdsCategoryId[]required
    • upsellIdsProductId[]required
    • crossSellIdsProductId[]required
    • bundleProductIdsProductId[]required
    • bundlePartsBundlePart[]required
    • bundlePricingBundlePricingrequired
    • quantityTiersQuantityTier[]required
    • tiersWithCouponsbooleanrequired
    • paymentRulesPaymentRulesrequired
    • affiliateCommissionBpsBps | nullrequired
    • fraudProductFraudrequired
    • templateSuffixstringrequired
    • deletedAtTimestamp | nullrequired
    • attributesProductAttributesrequired

    Example

    curl -X POST "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/duplicate" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY"
    const res = await fetch('https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/duplicate', {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
      },
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "POST",
        "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/duplicate",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("POST", "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/duplicate", nil)
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    Restore a deleted product as a draft

    POST/v1/store/products/{productId}/restore

    Or name the store: POST /v1/stores/{storeId}/products/{productId}/restore

    catalog:writerestoreProduct

    Parameters

    • productIdprd_…pathrequired

    Response ProductFull

    • idProductIdrequired
    • storeIdStoreIdrequired
    • namestringrequired
    • slugstringrequired
    • typeProductTyperequired
    • statusProductStatusrequired
    • priceMinorMinorUnitsrequired
    • compareAtMinorMinorUnits | nullrequired
    • currencyCurrencyCoderequired
    • descriptionstringrequired
    50 more fields
    • deliversstringrequired
    • coverUrlstringrequired
    • stockinteger | nullrequired
    • lowStockThresholdintegerrequired
    • unitsSoldintegerrequired
    • revenueMinorMinorUnitsrequired
    • createdAtTimestamprequired
    • updatedAtTimestamprequired
    • visibilityProductVisibilityrequired
    • pricingModePricingModerequired
    • variantCountintegerrequired
    • priceMaxMinorMinorUnits | nullrequired
    • tagsstring[]required
    • publishAtTimestamp | nullrequired
    • planLockedAtTimestamp | nullrequired
    • descriptionHtmlstringrequired
    • shortDescriptionstringrequired
    • featuredbooleanrequired
    • pwywMinMinorMinorUnits | nullrequired
    • pwywSuggestedMinorMinorUnits | nullrequired
    • taxCategoryTaxCategoryrequired
    • taxCategoryReviewTaxCategoryReview
    • minPerOrderintegerrequired
    • maxPerOrderinteger | nullrequired
    • maxPerCustomerinteger | nullrequired
    • stockModeStockModerequired
    • outOfStockBehaviorOutOfStockBehaviorrequired
    • variantsProductVariant[]required
    • mediaProductMedia[]required
    • filesProductFile[]required
    • keyStatsKeyPoolStats | nullrequired
    • deliveryProductDeliveryrequired
    • checkoutFieldsCheckoutField[]required
    • seoProductSeorequired
    • previousSlugsstring[]required
    • collectionIdsCollectionId[]required
    • categoryIdsCategoryId[]required
    • upsellIdsProductId[]required
    • crossSellIdsProductId[]required
    • bundleProductIdsProductId[]required
    • bundlePartsBundlePart[]required
    • bundlePricingBundlePricingrequired
    • quantityTiersQuantityTier[]required
    • tiersWithCouponsbooleanrequired
    • paymentRulesPaymentRulesrequired
    • affiliateCommissionBpsBps | nullrequired
    • fraudProductFraudrequired
    • templateSuffixstringrequired
    • deletedAtTimestamp | nullrequired
    • attributesProductAttributesrequired

    Example

    curl -X POST "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/restore" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY"
    const res = await fetch('https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/restore', {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
      },
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "POST",
        "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/restore",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("POST", "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/restore", nil)
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    Apply one action to many products

    POST/v1/store/products/bulk

    Or name the store: POST /v1/stores/{storeId}/products/bulk

    catalog:writebulkProducts

    Body

    • productIdsprd_…[]required
    • opobjectrequired

    Response BulkProductsResponse

    • updatedintegerrequired
    • createdProductId[]required
    • skippedobject[]required
      • productIdProductIdrequired
      • reasonstringrequired

    Example

    curl -X POST "https://api.shopfa.st/v1/store/products/bulk" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
      "productIds": [
        "prd_0123456789abcdefghjk"
      ],
      "op": {
        "action": "set_status",
        "status": "active"
      }
    }'
    const res = await fetch('https://api.shopfa.st/v1/store/products/bulk', {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        "productIds": [
          "prd_0123456789abcdefghjk"
        ],
        "op": {
          "action": "set_status",
          "status": "active"
        }
      }),
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "POST",
        "https://api.shopfa.st/v1/store/products/bulk",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
        json={
          "productIds": [
            "prd_0123456789abcdefghjk"
          ],
          "op": {
            "action": "set_status",
            "status": "active"
          }
        },
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("POST", "https://api.shopfa.st/v1/store/products/bulk", strings.NewReader(`{
      "productIds": [
        "prd_0123456789abcdefghjk"
      ],
      "op": {
        "action": "set_status",
        "status": "active"
      }
    }`))
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    req.Header.Set("Content-Type", "application/json")
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    Every product as CSV (PRODUCT_CSV_COLUMNS)

    GET/v1/store/products/export

    Or name the store: GET /v1/stores/{storeId}/products/export

    catalog:readexportProducts

    Response ExportProductsResponse

    • filenamestringrequired
    • csvstringrequired

    Example

    curl "https://api.shopfa.st/v1/store/products/export" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY"
    const res = await fetch('https://api.shopfa.st/v1/store/products/export', {
      method: 'GET',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
      },
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "GET",
        "https://api.shopfa.st/v1/store/products/export",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("GET", "https://api.shopfa.st/v1/store/products/export", nil)
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    Create or update products from CSV (matched by slug). dryRun validates without writing; any error writes nothing

    POST/v1/store/products/import

    Or name the store: POST /v1/stores/{storeId}/products/import

    catalog:writeimportProducts

    Body

    • csvstringrequired
    • dryRunbooleanrequired

    Response ProductImportResult

    • createdintegerrequired
    • updatedintegerrequired
    • skippedintegerrequired
    • categoriesCreatedintegerrequired
    • rowsProductImportRow[]required
    • errorsobject[]required
      • lineintegerrequired
      • columnstringrequired
      • messagestringrequired
    • dryRunbooleanrequired

    Example

    curl -X POST "https://api.shopfa.st/v1/store/products/import" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
      "csv": "string",
      "dryRun": false
    }'
    const res = await fetch('https://api.shopfa.st/v1/store/products/import', {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        "csv": "string",
        "dryRun": false
      }),
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "POST",
        "https://api.shopfa.st/v1/store/products/import",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
        json={
          "csv": "string",
          "dryRun": False
        },
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("POST", "https://api.shopfa.st/v1/store/products/import", strings.NewReader(`{
      "csv": "string",
      "dryRun": false
    }`))
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    req.Header.Set("Content-Type", "application/json")
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    Recently deleted products that can be restored

    GET/v1/store/products/deleted

    Or name the store: GET /v1/stores/{storeId}/products/deleted

    catalog:readlistDeletedProducts

    Response ListDeletedProductsResponse

    • itemsobject[]required
      • idProductIdrequired
      • namestringrequired
      • typestringrequired
      • deletedAtTimestamprequired

    Example

    curl "https://api.shopfa.st/v1/store/products/deleted" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY"
    const res = await fetch('https://api.shopfa.st/v1/store/products/deleted', {
      method: 'GET',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
      },
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "GET",
        "https://api.shopfa.st/v1/store/products/deleted",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("GET", "https://api.shopfa.st/v1/store/products/deleted", nil)
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    The signing secret for this product's delivery URL (Standard Webhooks)

    GET/v1/store/products/{productId}/delivery-webhook/secret

    Or name the store: GET /v1/stores/{storeId}/products/{productId}/delivery-webhook/secret

    catalog:readrole: catalog:writegetDeliveryWebhookSecret

    Parameters

    • productIdprd_…pathrequired

    Response DeliveryWebhookSecret

    • secretstringrequired
    • versionintegerrequired

    Example

    curl "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/delivery-webhook/secret" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY"
    const res = await fetch('https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/delivery-webhook/secret', {
      method: 'GET',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
      },
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "GET",
        "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/delivery-webhook/secret",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("GET", "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/delivery-webhook/secret", nil)
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    Replace the signing secret; the old one stops verifying at once

    POST/v1/store/products/{productId}/delivery-webhook/rotate

    Or name the store: POST /v1/stores/{storeId}/products/{productId}/delivery-webhook/rotate

    catalog:writerole: catalog:writerotateDeliveryWebhookSecret

    Parameters

    • productIdprd_…pathrequired

    Response DeliveryWebhookSecret

    • secretstringrequired
    • versionintegerrequired

    Example

    curl -X POST "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/delivery-webhook/rotate" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY"
    const res = await fetch('https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/delivery-webhook/rotate', {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
      },
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "POST",
        "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/delivery-webhook/rotate",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("POST", "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/delivery-webhook/rotate", nil)
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    Call a delivery URL with a signed sample order and show what buyers would get

    POST/v1/store/products/{productId}/delivery-webhook/test

    Or name the store: POST /v1/stores/{storeId}/products/{productId}/delivery-webhook/test

    catalog:writerole: catalog:writetestDeliveryWebhook

    Parameters

    • productIdprd_…pathrequired

    Body

    • urlstringrequired

    Response DeliveryWebhookTest

    • okbooleanrequired
    • statusinteger | nullrequired
    • durationMsintegerrequired
    • errorstringrequired
    • keysstring[]required
    • messagestringrequired
    • bodyPreviewstringrequired

    Example

    curl -X POST "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/delivery-webhook/test" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
      "url": "https://example.com"
    }'
    const res = await fetch('https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/delivery-webhook/test', {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        "url": "https://example.com"
      }),
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "POST",
        "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/delivery-webhook/test",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
        json={
          "url": "https://example.com"
        },
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("POST", "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/delivery-webhook/test", strings.NewReader(`{
      "url": "https://example.com"
    }`))
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    req.Header.Set("Content-Type", "application/json")
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    Subscriptions to this product: state, period end and renewals

    GET/v1/store/products/{productId}/subscribers

    Or name the store: GET /v1/stores/{storeId}/products/{productId}/subscribers

    catalog:readrole: catalog:readlistProductSubscribers

    Parameters

    • productIdprd_…pathrequired
    • state"all" | "active" | "past_due" | "ended"query

    Response ListProductSubscribersResponse

    • itemsProductSubscriber[]required
    • countsobjectrequired
      • activeintegerrequired
      • pastDueintegerrequired
      • endedintegerrequired

    Example

    curl "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/subscribers" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY"
    const res = await fetch('https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/subscribers', {
      method: 'GET',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
      },
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "GET",
        "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/subscribers",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("GET", "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/subscribers", nil)
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    Cancel a subscription now (access ends and Discord roles come off) or at the period end

    POST/v1/store/products/{productId}/subscribers/{subscriptionId}/cancel

    Or name the store: POST /v1/stores/{storeId}/products/{productId}/subscribers/{subscriptionId}/cancel

    catalog:writerole: catalog:writecancelProductSubscriber

    Parameters

    • productIdprd_…pathrequired
    • subscriptionIdsub_…pathrequired

    Body

    • when"now" | "period_end"required

    Response ProductSubscriber

    • idSubscriptionIdrequired
    • emailstringrequired
    • stateSubscriberStaterequired
    • orderIdOrderIdrequired
    • orderNumberstringrequired
    • currentPeriodEndTimestamprequired
    • renewalsintegerrequired
    • createdAtTimestamprequired
    • endedAtTimestamp | nullrequired

    Example

    curl -X POST "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/subscribers/sub_0123456789abcdefghjk/cancel" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
      "when": "now"
    }'
    const res = await fetch('https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/subscribers/sub_0123456789abcdefghjk/cancel', {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        "when": "now"
      }),
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "POST",
        "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/subscribers/sub_0123456789abcdefghjk/cancel",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
        json={
          "when": "now"
        },
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("POST", "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/subscribers/sub_0123456789abcdefghjk/cancel", strings.NewReader(`{
      "when": "now"
    }`))
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    req.Header.Set("Content-Type", "application/json")
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    A short-lived link for the seller to download the current version of a deliverable

    GET/v1/store/products/{productId}/files/{fileId}/download

    Or name the store: GET /v1/stores/{storeId}/products/{productId}/files/{fileId}/download

    catalog:readgetFileDownloadUrl

    Parameters

    • productIdprd_…pathrequired
    • fileIdfil_…pathrequired

    Response GetFileDownloadUrlResponse

    • urlstringrequired
    • expiresAtTimestamprequired

    Example

    curl "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/files/fil_0123456789abcdefghjk/download" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY"
    const res = await fetch('https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/files/fil_0123456789abcdefghjk/download', {
      method: 'GET',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
      },
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "GET",
        "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/files/fil_0123456789abcdefghjk/download",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("GET", "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/files/fil_0123456789abcdefghjk/download", nil)
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    Import keys or serials from pasted text or CSV: format check, duplicates skipped, optionally reserved for one option

    POST/v1/store/products/{productId}/keys/import

    Or name the store: POST /v1/stores/{storeId}/products/{productId}/keys/import

    catalog:writeimportKeys

    Parameters

    • productIdprd_…pathrequired

    Body

    • textstringrequired
    • delimiter"newline" | "comma" | "semicolon" | "tab" | "csv"required
    • variantIdvar_… | nullrequired
    • strictbooleanrequired

    Response KeyImportResult

    • addedintegerrequired
    • duplicatesInInputintegerrequired
    • duplicatesInPoolintegerrequired
    • invalidobject[]required
      • lineintegerrequired
      • valuestringrequired
    • invalidCountintegerrequired
    • stockintegerrequired

    Example

    curl -X POST "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/keys/import" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
      "text": "string",
      "delimiter": "newline",
      "variantId": "var_0123456789abcdefghjk",
      "strict": false
    }'
    const res = await fetch('https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/keys/import', {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        "text": "string",
        "delimiter": "newline",
        "variantId": "var_0123456789abcdefghjk",
        "strict": false
      }),
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "POST",
        "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/keys/import",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
        json={
          "text": "string",
          "delimiter": "newline",
          "variantId": "var_0123456789abcdefghjk",
          "strict": False
        },
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("POST", "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/keys/import", strings.NewReader(`{
      "text": "string",
      "delimiter": "newline",
      "variantId": "var_0123456789abcdefghjk",
      "strict": false
    }`))
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    req.Header.Set("Content-Type", "application/json")
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    Keys as CSV (value, status, option, order, assigned at)

    GET/v1/store/products/{productId}/keys/export

    Or name the store: GET /v1/stores/{storeId}/products/{productId}/keys/export

    catalog:readrole: catalog:writeexportKeys

    Parameters

    • productIdprd_…pathrequired
    • status"available" | "assigned" | "all"query
    • variantIdvar_… | nullquery

    Response ExportProductsResponse

    • filenamestringrequired
    • csvstringrequired

    Example

    curl "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/keys/export" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY"
    const res = await fetch('https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/keys/export', {
      method: 'GET',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
      },
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "GET",
        "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/keys/export",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("GET", "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/keys/export", nil)
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    Remove unused keys from the pool (assigned keys are never removed)

    POST/v1/store/products/{productId}/keys/remove

    Or name the store: POST /v1/stores/{storeId}/products/{productId}/keys/remove

    catalog:writeremoveKeys

    Parameters

    • productIdprd_…pathrequired

    Body

    • keyIdskey_…[]required

    Response RemoveKeysResponse

    • removedintegerrequired
    • stockintegerrequired

    Example

    curl -X POST "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/keys/remove" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
      "keyIds": [
        "key_0123456789abcdefghjk"
      ]
    }'
    const res = await fetch('https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/keys/remove', {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        "keyIds": [
          "key_0123456789abcdefghjk"
        ]
      }),
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "POST",
        "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/keys/remove",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
        json={
          "keyIds": [
            "key_0123456789abcdefghjk"
          ]
        },
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("POST", "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/keys/remove", strings.NewReader(`{
      "keyIds": [
        "key_0123456789abcdefghjk"
      ]
    }`))
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    req.Header.Set("Content-Type", "application/json")
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    Move a product in the order the storefront lists products (or in a hand-picked collection): first, last, or next to another product

    POST/v1/store/products/{productId}/move

    Or name the store: POST /v1/stores/{storeId}/products/{productId}/move

    catalog:writemoveProduct

    Parameters

    • productIdprd_…pathrequired

    Body

    • to"top" | "bottom" | "before" | "after" | "position"required
    • anchorprd_… | null
    • positioninteger | null
    • collectionIdcol_… | null

    Response ProductMoved

    • productIdProductIdrequired
    • indexintegerrequired
    • totalintegerrequired

    Example

    curl -X POST "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/move" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
      "to": "top",
      "anchor": null,
      "position": null,
      "collectionId": null
    }'
    const res = await fetch('https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/move', {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        "to": "top",
        "anchor": null,
        "position": null,
        "collectionId": null
      }),
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "POST",
        "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/move",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
        json={
          "to": "top",
          "anchor": None,
          "position": None,
          "collectionId": None
        },
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("POST", "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/move", strings.NewReader(`{
      "to": "top",
      "anchor": null,
      "position": null,
      "collectionId": null
    }`))
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    req.Header.Set("Content-Type", "application/json")
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    Show one license key in full

    POST/v1/store/products/{productId}/keys/{keyId}/reveal

    Or name the store: POST /v1/stores/{storeId}/products/{productId}/keys/{keyId}/reveal

    catalog:writerole: catalog:writerevealLicenseKey

    Parameters

    • productIdprd_…pathrequired
    • keyIdkey_…pathrequired

    Response RevealLicenseKeyResponse

    • valuestringrequired

    Example

    curl -X POST "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/keys/key_0123456789abcdefghjk/reveal" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY"
    const res = await fetch('https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/keys/key_0123456789abcdefghjk/reveal', {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
      },
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "POST",
        "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/keys/key_0123456789abcdefghjk/reveal",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("POST", "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/keys/key_0123456789abcdefghjk/reveal", nil)
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    A product’s licensing: API keys, device binding, expiry clock, auto-pause and linked status

    GET/v1/store/products/{productId}/licensing

    Or name the store: GET /v1/stores/{storeId}/products/{productId}/licensing

    catalog:readrole: catalog:readgetProductLicensing

    Parameters

    • productIdprd_…pathrequired

    Response ProductLicensing

    • productIdProductIdrequired
    • settingsLicenseSettingsrequired
    • publishableKeyPublishableLicenseKey | nullrequired
    • publicKeystringrequired
    • publicKeyIdstringrequired
    • keysRotatedAtTimestamp | nullrequired
    • plansLicensePlanOut[]required
    • linkedComponentsLinkedComponent[]required
    • pausedNowSalesPause | nullrequired
    • recentPausesSalesPause[]required
    • statsobjectrequired
      • activeintegerrequired
      • expiredintegerrequired
      • notStartedintegerrequired
      • revokedintegerrequired
      • devicesintegerrequired
      • validations24hintegerrequired

    Example

    curl "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/licensing" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY"
    const res = await fetch('https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/licensing', {
      method: 'GET',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
      },
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "GET",
        "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/licensing",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("GET", "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/licensing", nil)
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    Save a product’s licensing settings (turning the API on mints its keys)

    PUT/v1/store/products/{productId}/licensing

    Or name the store: PUT /v1/stores/{storeId}/products/{productId}/licensing

    catalog:writerole: catalog:writesaveProductLicensing

    Parameters

    • productIdprd_…pathrequired

    Body

    • apiEnabledboolean
    • clock"purchase" | "activation"
    • hwidobject
      • enabledboolean
      • maxDevicesinteger
      • buyerResetsPer30dinteger
      • resetCooldownHoursinteger
    • autoPauseobject
      • enabledboolean
      • when"outage" | "degraded" | "not_live"
      • storefront"show_disabled" | "hide"
      • blockValidationboolean
      • compensateboolean
      • notifyBuyersboolean
    • extendEnabledboolean
    • metadataobject
    • rateLimitPerMinuteinteger

    Response ProductLicensing

    • productIdProductIdrequired
    • settingsLicenseSettingsrequired
    • publishableKeyPublishableLicenseKey | nullrequired
    • publicKeystringrequired
    • publicKeyIdstringrequired
    • keysRotatedAtTimestamp | nullrequired
    • plansLicensePlanOut[]required
    • linkedComponentsLinkedComponent[]required
    • pausedNowSalesPause | nullrequired
    • recentPausesSalesPause[]required
    • statsobjectrequired
      • activeintegerrequired
      • expiredintegerrequired
      • notStartedintegerrequired
      • revokedintegerrequired
      • devicesintegerrequired
      • validations24hintegerrequired

    Example

    curl -X PUT "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/licensing" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
      "apiEnabled": false,
      "clock": "purchase",
      "hwid": {},
      "autoPause": {},
      "extendEnabled": true,
      "metadata": {},
      "rateLimitPerMinute": 60
    }'
    const res = await fetch('https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/licensing', {
      method: 'PUT',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        "apiEnabled": false,
        "clock": "purchase",
        "hwid": {},
        "autoPause": {},
        "extendEnabled": true,
        "metadata": {},
        "rateLimitPerMinute": 60
      }),
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "PUT",
        "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/licensing",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
        json={
          "apiEnabled": False,
          "clock": "purchase",
          "hwid": {},
          "autoPause": {},
          "extendEnabled": True,
          "metadata": {},
          "rateLimitPerMinute": 60
        },
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("PUT", "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/licensing", strings.NewReader(`{
      "apiEnabled": false,
      "clock": "purchase",
      "hwid": {},
      "autoPause": {},
      "extendEnabled": true,
      "metadata": {},
      "rateLimitPerMinute": 60
    }`))
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    req.Header.Set("Content-Type", "application/json")
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    Replace the product’s publishable key or its signing key (old ones stop working at once)

    POST/v1/store/products/{productId}/licensing/rotate

    Or name the store: POST /v1/stores/{storeId}/products/{productId}/licensing/rotate

    catalog:writerole: catalog:writerotateLicenseKeys

    Parameters

    • productIdprd_…pathrequired

    Body

    • which"publishable" | "signing"required

    Response ProductLicensing

    • productIdProductIdrequired
    • settingsLicenseSettingsrequired
    • publishableKeyPublishableLicenseKey | nullrequired
    • publicKeystringrequired
    • publicKeyIdstringrequired
    • keysRotatedAtTimestamp | nullrequired
    • plansLicensePlanOut[]required
    • linkedComponentsLinkedComponent[]required
    • pausedNowSalesPause | nullrequired
    • recentPausesSalesPause[]required
    • statsobjectrequired
      • activeintegerrequired
      • expiredintegerrequired
      • notStartedintegerrequired
      • revokedintegerrequired
      • devicesintegerrequired
      • validations24hintegerrequired

    Example

    curl -X POST "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/licensing/rotate" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
      "which": "publishable"
    }'
    const res = await fetch('https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/licensing/rotate', {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        "which": "publishable"
      }),
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "POST",
        "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/licensing/rotate",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
        json={
          "which": "publishable"
        },
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("POST", "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/licensing/rotate", strings.NewReader(`{
      "which": "publishable"
    }`))
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    req.Header.Set("Content-Type", "application/json")
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    A product’s self-serve replacement policy (window, limit, reason and proof, automatic or reviewed) and its queue numbers

    GET/v1/store/products/{productId}/replacement-policy

    Or name the store: GET /v1/stores/{storeId}/products/{productId}/replacement-policy

    catalog:readrole: catalog:readgetReplacementPolicy

    Parameters

    • productIdprd_…pathrequired

    Response ProductReplacementPolicy

    • productIdProductIdrequired
    • policyReplacementPolicyrequired
    • warrantyDaysinteger | nullrequired
    • statsobjectrequired
      • pendingintegerrequired
      • approved30dintegerrequired
      • rejected30dintegerrequired
      • poolAvailableintegerrequired

    Example

    curl "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/replacement-policy" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY"
    const res = await fetch('https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/replacement-policy', {
      method: 'GET',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
      },
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "GET",
        "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/replacement-policy",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("GET", "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/replacement-policy", nil)
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    Save a product’s self-serve replacement policy

    PUT/v1/store/products/{productId}/replacement-policy

    Or name the store: PUT /v1/stores/{storeId}/products/{productId}/replacement-policy

    catalog:writerole: catalog:writesaveReplacementPolicy

    Parameters

    • productIdprd_…pathrequired

    Body

    • enabledboolean
    • windowDaysinteger | null
    • maxReplacementsinteger
    • requireReasonboolean
    • requireProofTextboolean
    • requireProofUploadboolean
    • approval"auto" | "review"

    Response ProductReplacementPolicy

    • productIdProductIdrequired
    • policyReplacementPolicyrequired
    • warrantyDaysinteger | nullrequired
    • statsobjectrequired
      • pendingintegerrequired
      • approved30dintegerrequired
      • rejected30dintegerrequired
      • poolAvailableintegerrequired

    Example

    curl -X PUT "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/replacement-policy" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
      "enabled": false,
      "windowDays": null,
      "maxReplacements": 1,
      "requireReason": true,
      "requireProofText": false,
      "requireProofUpload": false,
      "approval": "review"
    }'
    const res = await fetch('https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/replacement-policy', {
      method: 'PUT',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        "enabled": false,
        "windowDays": null,
        "maxReplacements": 1,
        "requireReason": true,
        "requireProofText": false,
        "requireProofUpload": false,
        "approval": "review"
      }),
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "PUT",
        "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/replacement-policy",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
        json={
          "enabled": False,
          "windowDays": None,
          "maxReplacements": 1,
          "requireReason": True,
          "requireProofText": False,
          "requireProofUpload": False,
          "approval": "review"
        },
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("PUT", "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/replacement-policy", strings.NewReader(`{
      "enabled": false,
      "windowDays": null,
      "maxReplacements": 1,
      "requireReason": true,
      "requireProofText": false,
      "requireProofUpload": false,
      "approval": "review"
    }`))
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    req.Header.Set("Content-Type", "application/json")
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    Who owns the product and who each channel would reach with these filters (consent applied)

    POST/v1/store/products/{productId}/broadcasts/audience

    Or name the store: POST /v1/stores/{storeId}/products/{productId}/broadcasts/audience

    catalog:writerole: marketing:readbroadcastAudience

    Parameters

    • productIdprd_…pathrequired

    Body

    • activeOnlyboolean
    • variantIdsvar_…[]
    • purchasedAfterstring | null
    • purchasedBeforestring | null
    • marketingOnlyboolean

    Response BroadcastAudience

    • ownersintegerrequired
    • emailobjectrequired
      • eligibleintegerrequired
      • skippedobject[]required
        • reasonBroadcastSkipReasonrequired
        • countintegerrequired
    • discordintegerrequired
    • telegramintegerrequired
    • sampleobject[]required
      • emailstringrequired
      • optionstringrequired
      • purchasedAtTimestamprequired
      • activebooleanrequired

    Example

    curl -X POST "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/broadcasts/audience" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
      "activeOnly": true,
      "variantIds": [],
      "purchasedAfter": null,
      "purchasedBefore": null,
      "marketingOnly": false
    }'
    const res = await fetch('https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/broadcasts/audience', {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        "activeOnly": true,
        "variantIds": [],
        "purchasedAfter": null,
        "purchasedBefore": null,
        "marketingOnly": false
      }),
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "POST",
        "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/broadcasts/audience",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
        json={
          "activeOnly": True,
          "variantIds": [],
          "purchasedAfter": None,
          "purchasedBefore": None,
          "marketingOnly": False
        },
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("POST", "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/broadcasts/audience", strings.NewReader(`{
      "activeOnly": true,
      "variantIds": [],
      "purchasedAfter": null,
      "purchasedBefore": null,
      "marketingOnly": false
    }`))
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    req.Header.Set("Content-Type", "application/json")
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    Post an update to owners: adds the version to the history, attaches the new file version and sends in the background

    POST/v1/store/products/{productId}/broadcasts

    Or name the store: POST /v1/stores/{storeId}/products/{productId}/broadcasts

    catalog:writerole: marketing:writesendBroadcast

    Parameters

    • productIdprd_…pathrequired

    Body

    • titlestringrequired
    • versionstring
    • changelogstring
    • channelsobjectrequired
      • emailbooleanrequired
      • discordbooleanrequired
      • telegrambooleanrequired
    • docobjectrequired
      • versionnumber
      • subjectstringrequired
      • preheaderstring
      • styleobject
        • accentstring | null
        • backgroundstring
        • surfacestring
        • textstring
        • mutedstring
        • borderstring
        • buttonTextstring
        • radiusinteger
        • buttonRadiusinteger
        • font"system" | "humanist" | "geometric" | "serif" | "mono"
        • widthinteger
        • showLogoboolean
        • accentBarboolean
      • blocksobject[]required
    • dmTextstring
    • filtersobjectrequired
      • activeOnlyboolean
      • variantIdsvar_…[]
      • purchasedAfterstring | null
      • purchasedBeforestring | null
      • marketingOnlyboolean
    • fileobject | null
    • showInLibraryboolean

    Response ProductBroadcast

    • idProductBroadcastIdrequired
    • productIdProductIdrequired
    • productNamestringrequired
    • titlestringrequired
    • versionstringrequired
    • changelogstringrequired
    • channelsBroadcastChannelsrequired
    • filtersBroadcastFiltersrequired
    • statusBroadcastStatusrequired
    • countsBroadcastCountsrequired
    5 more fields
    • fileobject | nullrequired
    • showInLibrarybooleanrequired
    • createdBystringrequired
    • createdAtTimestamprequired
    • finishedAtTimestamp | nullrequired

    Example

    curl -X POST "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/broadcasts" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
      "title": "string",
      "version": "",
      "changelog": "",
      "channels": {
        "email": false,
        "discord": false,
        "telegram": false
      },
      "doc": {
        "subject": "string",
        "blocks": [
          {
            "id": "string",
            "type": "heading",
            "text": "string"
          }
        ]
      },
      "dmText": "",
      "filters": {},
      "file": null,
      "showInLibrary": true
    }'
    const res = await fetch('https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/broadcasts', {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        "title": "string",
        "version": "",
        "changelog": "",
        "channels": {
          "email": false,
          "discord": false,
          "telegram": false
        },
        "doc": {
          "subject": "string",
          "blocks": [
            {
              "id": "string",
              "type": "heading",
              "text": "string"
            }
          ]
        },
        "dmText": "",
        "filters": {},
        "file": null,
        "showInLibrary": true
      }),
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "POST",
        "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/broadcasts",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
        json={
          "title": "string",
          "version": "",
          "changelog": "",
          "channels": {
            "email": False,
            "discord": False,
            "telegram": False
          },
          "doc": {
            "subject": "string",
            "blocks": [
              {
                "id": "string",
                "type": "heading",
                "text": "string"
              }
            ]
          },
          "dmText": "",
          "filters": {},
          "file": None,
          "showInLibrary": True
        },
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("POST", "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/broadcasts", strings.NewReader(`{
      "title": "string",
      "version": "",
      "changelog": "",
      "channels": {
        "email": false,
        "discord": false,
        "telegram": false
      },
      "doc": {
        "subject": "string",
        "blocks": [
          {
            "id": "string",
            "type": "heading",
            "text": "string"
          }
        ]
      },
      "dmText": "",
      "filters": {},
      "file": null,
      "showInLibrary": true
    }`))
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    req.Header.Set("Content-Type", "application/json")
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    Send the update email to yourself with sample values

    POST/v1/store/products/{productId}/broadcasts/test

    Or name the store: POST /v1/stores/{storeId}/products/{productId}/broadcasts/test

    catalog:writerole: marketing:writetestBroadcast

    Parameters

    • productIdprd_…pathrequired

    Body

    • titlestringrequired
    • versionstring
    • changelogstring
    • channelsobjectrequired
      • emailbooleanrequired
      • discordbooleanrequired
      • telegrambooleanrequired
    • docobjectrequired
      • versionnumber
      • subjectstringrequired
      • preheaderstring
      • styleobject
        • accentstring | null
        • backgroundstring
        • surfacestring
        • textstring
        • mutedstring
        • borderstring
        • buttonTextstring
        • radiusinteger
        • buttonRadiusinteger
        • font"system" | "humanist" | "geometric" | "serif" | "mono"
        • widthinteger
        • showLogoboolean
        • accentBarboolean
      • blocksobject[]required
    • dmTextstring
    • filtersobjectrequired
      • activeOnlyboolean
      • variantIdsvar_…[]
      • purchasedAfterstring | null
      • purchasedBeforestring | null
      • marketingOnlyboolean
    • fileobject | null
    • showInLibraryboolean

    Response TestBroadcastResponse

    • sentTostringrequired

    Example

    curl -X POST "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/broadcasts/test" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
      "title": "string",
      "version": "",
      "changelog": "",
      "channels": {
        "email": false,
        "discord": false,
        "telegram": false
      },
      "doc": {
        "subject": "string",
        "blocks": [
          {
            "id": "string",
            "type": "heading",
            "text": "string"
          }
        ]
      },
      "dmText": "",
      "filters": {},
      "file": null,
      "showInLibrary": true
    }'
    const res = await fetch('https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/broadcasts/test', {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        "title": "string",
        "version": "",
        "changelog": "",
        "channels": {
          "email": false,
          "discord": false,
          "telegram": false
        },
        "doc": {
          "subject": "string",
          "blocks": [
            {
              "id": "string",
              "type": "heading",
              "text": "string"
            }
          ]
        },
        "dmText": "",
        "filters": {},
        "file": null,
        "showInLibrary": true
      }),
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "POST",
        "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/broadcasts/test",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
        json={
          "title": "string",
          "version": "",
          "changelog": "",
          "channels": {
            "email": False,
            "discord": False,
            "telegram": False
          },
          "doc": {
            "subject": "string",
            "blocks": [
              {
                "id": "string",
                "type": "heading",
                "text": "string"
              }
            ]
          },
          "dmText": "",
          "filters": {},
          "file": None,
          "showInLibrary": True
        },
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("POST", "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/broadcasts/test", strings.NewReader(`{
      "title": "string",
      "version": "",
      "changelog": "",
      "channels": {
        "email": false,
        "discord": false,
        "telegram": false
      },
      "doc": {
        "subject": "string",
        "blocks": [
          {
            "id": "string",
            "type": "heading",
            "text": "string"
          }
        ]
      },
      "dmText": "",
      "filters": {},
      "file": null,
      "showInLibrary": true
    }`))
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    req.Header.Set("Content-Type", "application/json")
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    Whether the product’s downloads are marked per buyer, and how

    GET/v1/store/products/{productId}/watermark

    Or name the store: GET /v1/stores/{storeId}/products/{productId}/watermark

    catalog:readrole: catalog:readgetProductWatermark

    Parameters

    • productIdprd_…pathrequired

    Response ProductWatermark

    • productIdProductIdrequired
    • settingsWatermarkSettingsrequired
    • markedintegerrequired
    • lastMarkedAtTimestamp | nullrequired
    • filesobject[]required
      • namestringrequired
      • filenamestringrequired
      • kindWatermarkKind | nullrequired

    Example

    curl "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/watermark" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY"
    const res = await fetch('https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/watermark', {
      method: 'GET',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
      },
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "GET",
        "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/watermark",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("GET", "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/watermark", nil)
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    Turn per-buyer watermarks on or off for PDFs, images, ZIP archives and text files

    PUT/v1/store/products/{productId}/watermark

    Or name the store: PUT /v1/stores/{storeId}/products/{productId}/watermark

    catalog:writerole: catalog:writesaveProductWatermark

    Parameters

    • productIdprd_…pathrequired

    Body

    • enabledboolean
    • pdfboolean
    • imageboolean
    • archiveboolean
    • textboolean
    • label"email" | "order" | "code"

    Response ProductWatermark

    • productIdProductIdrequired
    • settingsWatermarkSettingsrequired
    • markedintegerrequired
    • lastMarkedAtTimestamp | nullrequired
    • filesobject[]required
      • namestringrequired
      • filenamestringrequired
      • kindWatermarkKind | nullrequired

    Example

    curl -X PUT "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/watermark" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
      "enabled": false,
      "pdf": true,
      "image": true,
      "archive": true,
      "text": true,
      "label": "email"
    }'
    const res = await fetch('https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/watermark', {
      method: 'PUT',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        "enabled": false,
        "pdf": true,
        "image": true,
        "archive": true,
        "text": true,
        "label": "email"
      }),
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "PUT",
        "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/watermark",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
        json={
          "enabled": False,
          "pdf": True,
          "image": True,
          "archive": True,
          "text": True,
          "label": "email"
        },
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("PUT", "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/watermark", strings.NewReader(`{
      "enabled": false,
      "pdf": true,
      "image": true,
      "archive": true,
      "text": true,
      "label": "email"
    }`))
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    req.Header.Set("Content-Type", "application/json")
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    Pay what you want for updates (owners chip in) and for renewals (Extend at a price the buyer picks)

    GET/v1/store/products/{productId}/update-support

    Or name the store: GET /v1/stores/{storeId}/products/{productId}/update-support

    catalog:readrole: catalog:readgetUpdateSupport

    Parameters

    • productIdprd_…pathrequired

    Response UpdateSupportSettings

    • enabledbooleanrequired
    • minimumMinorMinorUnitsrequired
    • suggestedMinorMinorUnitsrequired
    • headingstringrequired
    • messagestringrequired
    • renewalPwywbooleanrequired
    • renewalMinimumPctintegerrequired

    Example

    curl "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/update-support" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY"
    const res = await fetch('https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/update-support', {
      method: 'GET',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
      },
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "GET",
        "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/update-support",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("GET", "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/update-support", nil)
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    Save pay what you want for updates and renewals

    PUT/v1/store/products/{productId}/update-support

    Or name the store: PUT /v1/stores/{storeId}/products/{productId}/update-support

    catalog:writerole: catalog:writesaveUpdateSupport

    Parameters

    • productIdprd_…pathrequired

    Body

    • enabledboolean
    • minimumMinorinteger
    • suggestedMinorinteger
    • headingstring
    • messagestring
    • renewalPwywboolean
    • renewalMinimumPctinteger

    Response UpdateSupportSettings

    • enabledbooleanrequired
    • minimumMinorMinorUnitsrequired
    • suggestedMinorMinorUnitsrequired
    • headingstringrequired
    • messagestringrequired
    • renewalPwywbooleanrequired
    • renewalMinimumPctintegerrequired

    Example

    curl -X PUT "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/update-support" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
      "enabled": false,
      "minimumMinor": 0,
      "suggestedMinor": 500,
      "heading": "Support the next update",
      "message": "Like the updates? Chip in what you want. You keep everything you own either way.",
      "renewalPwyw": false,
      "renewalMinimumPct": 50
    }'
    const res = await fetch('https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/update-support', {
      method: 'PUT',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        "enabled": false,
        "minimumMinor": 0,
        "suggestedMinor": 500,
        "heading": "Support the next update",
        "message": "Like the updates? Chip in what you want. You keep everything you own either way.",
        "renewalPwyw": false,
        "renewalMinimumPct": 50
      }),
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "PUT",
        "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/update-support",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
        json={
          "enabled": False,
          "minimumMinor": 0,
          "suggestedMinor": 500,
          "heading": "Support the next update",
          "message": "Like the updates? Chip in what you want. You keep everything you own either way.",
          "renewalPwyw": False,
          "renewalMinimumPct": 50
        },
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("PUT", "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/update-support", strings.NewReader(`{
      "enabled": false,
      "minimumMinor": 0,
      "suggestedMinor": 500,
      "heading": "Support the next update",
      "message": "Like the updates? Chip in what you want. You keep everything you own either way.",
      "renewalPwyw": false,
      "renewalMinimumPct": 50
    }`))
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    req.Header.Set("Content-Type", "application/json")
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    The Telegram group or channel this product invites buyers to, and how long access lasts

    GET/v1/store/products/{productId}/telegram-access

    Or name the store: GET /v1/stores/{storeId}/products/{productId}/telegram-access

    catalog:readrole: catalog:readgetCommunityAccess

    Parameters

    • productIdprd_…pathrequired

    Response CommunityProductView

    • settingsCommunityAccessSettingsrequired
    • botobjectrequired
      • connectedbooleanrequired
      • usernamestringrequired
    • mode"live" | "simulated"required
    • grantsobjectrequired
      • activeintegerrequired
      • waitingintegerrequired
      • removedintegerrequired

    Example

    curl "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/telegram-access" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY"
    const res = await fetch('https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/telegram-access', {
      method: 'GET',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
      },
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "GET",
        "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/telegram-access",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("GET", "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/telegram-access", nil)
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    Save Telegram access for a product (the bot must be an admin of the chat who can invite and remove members)

    PUT/v1/store/products/{productId}/telegram-access

    Or name the store: PUT /v1/stores/{storeId}/products/{productId}/telegram-access

    catalog:writerole: catalog:writesaveCommunityAccess

    Parameters

    • productIdprd_…pathrequired

    Body

    • enabledboolean
    • chatIdstring | null
    • chatTitlestring
    • chatType"group" | "supergroup" | "channel" | null
    • duration"auto" | "fixed" | "lifetime"
    • fixedDaysinteger | null
    • removeOnRefundboolean
    • removeOnChargebackboolean
    • removeOnExpiryboolean
    • inviteHoursinteger

    Response CommunityProductView

    • settingsCommunityAccessSettingsrequired
    • botobjectrequired
      • connectedbooleanrequired
      • usernamestringrequired
    • mode"live" | "simulated"required
    • grantsobjectrequired
      • activeintegerrequired
      • waitingintegerrequired
      • removedintegerrequired

    Example

    curl -X PUT "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/telegram-access" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
      "enabled": false,
      "chatId": null,
      "chatTitle": "",
      "chatType": null,
      "duration": "auto",
      "fixedDays": null,
      "removeOnRefund": true,
      "removeOnChargeback": true,
      "removeOnExpiry": true,
      "inviteHours": 24
    }'
    const res = await fetch('https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/telegram-access', {
      method: 'PUT',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        "enabled": false,
        "chatId": null,
        "chatTitle": "",
        "chatType": null,
        "duration": "auto",
        "fixedDays": null,
        "removeOnRefund": true,
        "removeOnChargeback": true,
        "removeOnExpiry": true,
        "inviteHours": 24
      }),
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "PUT",
        "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/telegram-access",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
        json={
          "enabled": False,
          "chatId": None,
          "chatTitle": "",
          "chatType": None,
          "duration": "auto",
          "fixedDays": None,
          "removeOnRefund": True,
          "removeOnChargeback": True,
          "removeOnExpiry": True,
          "inviteHours": 24
        },
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("PUT", "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/telegram-access", strings.NewReader(`{
      "enabled": false,
      "chatId": null,
      "chatTitle": "",
      "chatType": null,
      "duration": "auto",
      "fixedDays": null,
      "removeOnRefund": true,
      "removeOnChargeback": true,
      "removeOnExpiry": true,
      "inviteHours": 24
    }`))
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    req.Header.Set("Content-Type", "application/json")
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    Queue a product update for 10 seconds (undo window), then post it like sendBroadcast

    POST/v1/store/products/{productId}/broadcasts/queue

    Or name the store: POST /v1/stores/{storeId}/products/{productId}/broadcasts/queue

    catalog:writerole: marketing:writequeueBroadcast

    Parameters

    • productIdprd_…pathrequired

    Body

    • titlestringrequired
    • versionstring
    • changelogstring
    • channelsobjectrequired
      • emailbooleanrequired
      • discordbooleanrequired
      • telegrambooleanrequired
    • docobjectrequired
      • versionnumber
      • subjectstringrequired
      • preheaderstring
      • styleobject
        • accentstring | null
        • backgroundstring
        • surfacestring
        • textstring
        • mutedstring
        • borderstring
        • buttonTextstring
        • radiusinteger
        • buttonRadiusinteger
        • font"system" | "humanist" | "geometric" | "serif" | "mono"
        • widthinteger
        • showLogoboolean
        • accentBarboolean
      • blocksobject[]required
    • dmTextstring
    • filtersobjectrequired
      • activeOnlyboolean
      • variantIdsvar_…[]
      • purchasedAfterstring | null
      • purchasedBeforestring | null
      • marketingOnlyboolean
    • fileobject | null
    • showInLibraryboolean

    Response PendingAction

    • idPendingActionIdrequired
    • kindPendingActionKindrequired
    • labelstringrequired
    • statePendingActionStaterequired
    • commitAtTimestamprequired
    • createdAtTimestamprequired
    • settledAtTimestamp | nullrequired
    • errorstringrequired
    • targetobjectrequired
      • kind"order" | "campaign" | "product" | "products" | "discounts"required
      • idstringrequired
    • actorNamestringrequired
    • minebooleanrequired

    Example

    curl -X POST "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/broadcasts/queue" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
      "title": "string",
      "version": "",
      "changelog": "",
      "channels": {
        "email": false,
        "discord": false,
        "telegram": false
      },
      "doc": {
        "subject": "string",
        "blocks": [
          {
            "id": "string",
            "type": "heading",
            "text": "string"
          }
        ]
      },
      "dmText": "",
      "filters": {},
      "file": null,
      "showInLibrary": true
    }'
    const res = await fetch('https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/broadcasts/queue', {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        "title": "string",
        "version": "",
        "changelog": "",
        "channels": {
          "email": false,
          "discord": false,
          "telegram": false
        },
        "doc": {
          "subject": "string",
          "blocks": [
            {
              "id": "string",
              "type": "heading",
              "text": "string"
            }
          ]
        },
        "dmText": "",
        "filters": {},
        "file": null,
        "showInLibrary": true
      }),
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "POST",
        "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/broadcasts/queue",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
        json={
          "title": "string",
          "version": "",
          "changelog": "",
          "channels": {
            "email": False,
            "discord": False,
            "telegram": False
          },
          "doc": {
            "subject": "string",
            "blocks": [
              {
                "id": "string",
                "type": "heading",
                "text": "string"
              }
            ]
          },
          "dmText": "",
          "filters": {},
          "file": None,
          "showInLibrary": True
        },
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("POST", "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/broadcasts/queue", strings.NewReader(`{
      "title": "string",
      "version": "",
      "changelog": "",
      "channels": {
        "email": false,
        "discord": false,
        "telegram": false
      },
      "doc": {
        "subject": "string",
        "blocks": [
          {
            "id": "string",
            "type": "heading",
            "text": "string"
          }
        ]
      },
      "dmText": "",
      "filters": {},
      "file": null,
      "showInLibrary": true
    }`))
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    req.Header.Set("Content-Type", "application/json")
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    Queue deleting products for 10 seconds (undo window)

    POST/v1/store/products/bulk-delete-queue

    Or name the store: POST /v1/stores/{storeId}/products/bulk-delete-queue

    catalog:writerole: catalog:writequeueProductsDelete

    Body

    • productIdsprd_…[]required

    Response PendingAction

    • idPendingActionIdrequired
    • kindPendingActionKindrequired
    • labelstringrequired
    • statePendingActionStaterequired
    • commitAtTimestamprequired
    • createdAtTimestamprequired
    • settledAtTimestamp | nullrequired
    • errorstringrequired
    • targetobjectrequired
      • kind"order" | "campaign" | "product" | "products" | "discounts"required
      • idstringrequired
    • actorNamestringrequired
    • minebooleanrequired

    Example

    curl -X POST "https://api.shopfa.st/v1/store/products/bulk-delete-queue" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
      "productIds": [
        "prd_0123456789abcdefghjk"
      ]
    }'
    const res = await fetch('https://api.shopfa.st/v1/store/products/bulk-delete-queue', {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        "productIds": [
          "prd_0123456789abcdefghjk"
        ]
      }),
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "POST",
        "https://api.shopfa.st/v1/store/products/bulk-delete-queue",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
        json={
          "productIds": [
            "prd_0123456789abcdefghjk"
          ]
        },
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("POST", "https://api.shopfa.st/v1/store/products/bulk-delete-queue", strings.NewReader(`{
      "productIds": [
        "prd_0123456789abcdefghjk"
      ]
    }`))
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    req.Header.Set("Content-Type", "application/json")
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    The product's one status: badge, label, note (the open incident's title while one is open) and auto-pause

    GET/v1/store/products/{productId}/status

    Or name the store: GET /v1/stores/{storeId}/products/{productId}/status

    catalog:readrole: catalog:readgetProductStatus

    Parameters

    • productIdprd_…pathrequired

    Example

    curl "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/status" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY"
    const res = await fetch('https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/status', {
      method: 'GET',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
      },
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "GET",
        "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/status",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("GET", "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/status", nil)
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    Auto-renew for one product: whether buyers can opt in, the dunning schedule and who renews

    GET/v1/store/products/{productId}/auto-renew

    Or name the store: GET /v1/stores/{storeId}/products/{productId}/auto-renew

    catalog:readrole: catalog:readgetProductAutoRenew

    Parameters

    • productIdprd_…pathrequired

    Response ProductAutoRenewView

    • settingsAutoRenewProductSettingsrequired
    • eligiblebooleanrequired
    • reasonstringrequired
    • optionsobject[]required
      • namestringrequired
      • everystringrequired
    • renewingMethodsstring[]required
    • activeintegerrequired
    • retryingintegerrequired

    Example

    curl "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/auto-renew" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY"
    const res = await fetch('https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/auto-renew', {
      method: 'GET',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
      },
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "GET",
        "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/auto-renew",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("GET", "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/auto-renew", nil)
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    Allow auto-renew on a subscription or duration product and set its retry days

    PUT/v1/store/products/{productId}/auto-renew

    Or name the store: PUT /v1/stores/{storeId}/products/{productId}/auto-renew

    catalog:writerole: catalog:writesaveProductAutoRenew

    Parameters

    • productIdprd_…pathrequired

    Body

    • allowedbooleanrequired
    • retryDaysinteger[]required
    • graceDaysintegerrequired

    Response ProductAutoRenewView

    • settingsAutoRenewProductSettingsrequired
    • eligiblebooleanrequired
    • reasonstringrequired
    • optionsobject[]required
      • namestringrequired
      • everystringrequired
    • renewingMethodsstring[]required
    • activeintegerrequired
    • retryingintegerrequired

    Example

    curl -X PUT "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/auto-renew" \
      -H "Authorization: Bearer $SHOPFAST_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
      "allowed": false,
      "retryDays": [
        1
      ],
      "graceDays": 0
    }'
    const res = await fetch('https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/auto-renew', {
      method: 'PUT',
      headers: {
        Authorization: `Bearer ${process.env.SHOPFAST_API_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        "allowed": false,
        "retryDays": [
          1
        ],
        "graceDays": 0
      }),
    });
    if (!res.ok) throw new Error((await res.json()).detail);
    const data = await res.json();
    import os, requests
    
    res = requests.request(
        "PUT",
        "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/auto-renew",
        headers={"Authorization": f"Bearer {os.environ['SHOPFAST_API_KEY']}"},
        json={
          "allowed": False,
          "retryDays": [
            1
          ],
          "graceDays": 0
        },
    )
    res.raise_for_status()
    data = res.json()
    req, _ := http.NewRequest("PUT", "https://api.shopfa.st/v1/store/products/prd_0123456789abcdefghjk/auto-renew", strings.NewReader(`{
      "allowed": false,
      "retryDays": [
        1
      ],
      "graceDays": 0
    }`))
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SHOPFAST_API_KEY"))
    req.Header.Set("Content-Type", "application/json")
    res, err := http.DefaultClient.Do(req)
    Try it with your key

    Use a test key on a development store. The key stays in this tab (sessionStorage) and is sent only to the base URL above.

    Was this page helpful?