导入目录

通过JSON导入来创建和更新商品目录

您可以通过从JSON文件导入来创建、更新或禁用商品。

注:
您可以通过API调用手动在发布商帐户中创建、更新或禁用商品。但是,您需要对每个商品进行单独请求或操作。通过导入功能,您可以在一个JSON文件指定多个商品,从而同时对它们执行这些操作。

通过此工具,您可以:

功能:

  • 支持以下类型的商品:
    • 虚拟物品
    • 虚拟货币
    • 虚拟货币套餐
    • 捆绑包
  • 数据验证。如文件结构或数据格式不符合要求,导入时将看到以下错误列表。

限制:

注:
对于预先创建好的商品,可从CSV文件中导入区域价格

导入商品目录

要从文件导入商品目录:

  1. 发布商帐户中打开项目。
  2. 在侧边栏中,单击商店,然后前往虚拟货币虚拟物品捆绑包部分。
  3. 单击导入商品

  1. 选择操作:
    • 添加新商品 — 仅添加具有新SKU的商品。
    • 添加新商品并更新现有商品 — 将添加具有新SKU的商品,且将更新现有商品的数据。
    • 添加新商品,更新现有商品并禁用缺失的商品 — 将添加/更新文件中具有SKU的商品。如目录中有某个商品,但文件中没有SKU,则该商品在发布商帐户中的状态将变为部分可用 — 商品将无法单独购买,但可以作为捆绑包或奖励的一部分提供。

  1. 填充文件以便导入:
    • 在下载窗口中下载文件模板,根据下方示例进行填写。
    • 导出商品并用导出的文件作为模板。
    • 创建您自己的JSON文件并按照下方示例进行填写。

完整JSON文件示例:

Copy
Full screen
Small screen

{
    "virtual_currency": [
        {
            "sku": "Gem_test_import",
            "name": {
                "en": "Gem_test_import"
            },
            "type": "virtual_currency",
            "description": {
                "en": "my test imported currency"
            },
            "image_url": "https://cdn3.xsolla.com/img/misc/merchant/default-dc-image.png",
            "description": {
                "en": "my test imported currency",
                "de": "meine importierte Testwährung"
            },
            "attributes": [],
            "is_free": false,
            "order": 1,
            "groups": [],
            "regional_prices": [],
            "prices": [
                {
                    "amount": 2,
                    "currency": "USD",
                    "is_default": true,
                    "is_enabled": true
                }
            ],
            "media_list": [],
            "vc_prices": [],
            "is_enabled": true,
            "is_show_in_store": true,
            "regions": [],
            "limits": {
                "per_user": null,
                "per_item": null,
                "recurrent_schedule": null
            },
            "periods": [],
            "inventory_options": {
                "consumable": true,
                "expiration_period": null
            },
            "is_hard": false
        }
    ],
    "virtual_items": [
        {
            "sku": "event_access_test_import",
            "name": {
                "en": "Special Event Access_test_import"
            },
            "type": "virtual_good",
            "description": {
                "en": "Get special event access as a bonus only on your first purchase. Find the right doggy at the Robo-Dog Exhibition!"
            },
            "image_url": "https://cdn3.xsolla.com/img/misc/images/1e3ef1a96cc9dd8d98bc124d5d6fad79.png",
            "long_description": null,
            "attributes": [],
            "is_free": false,
            "order": 1,
            "groups": [
                "my_test_group"
            ],
            "regional_prices": [],
            "prices": [
                {
                    "amount": 35,
                    "currency": "USD",
                    "is_default": true,
                    "is_enabled": true
                }
            ],
            "media_list": [],
            "vc_prices": [],
            "is_enabled": true,
            "is_show_in_store": true,
            "regions": [],
            "limits": {
                "per_user": null,
                "per_item": null,
                "recurrent_schedule": null
            },
            "periods": [],
            "inventory_options": {
                "consumable": true,
                "expiration_period": null
            }
        }
    ],
    "virtual_currency_packages": [
        {
            "item_id": 441982,
            "sku": "small_gold_pack_test_import",
            "type": "bundle",
            "name": {
                "en": "Small gold pack"
            },
            "bundle_type": "virtual_currency_package",
            "description": {
                "en": "Gold x100"
            },
            "image_url": "https://cdn3.xsolla.com/img/misc/images/ba43c46ea75fd5713c210f5736993a92.png",
            "vc_prices": [],
            "regional_prices": [],
            "prices": [
                {
                    "amount": 5,
                    "currency": "USD",
                    "is_default": true,
                    "is_enabled": true
                }
            ],
            "is_enabled": true,
            "is_show_in_store": true,
            "regions": [],
            "limits": {
                "per_user": null,
                "per_item": null,
                "recurrent_schedule": null
            },
            "periods": [],
            "attributes": [],
            "long_description": null,
            "media_list": [],
            "order": 100000000,
            "is_free": false,
            "groups": [],
            "content": [
                {
                    "sku": "Gem_test_import",
                    "quantity": 100
                }
            ]
        }
    ],
    "bundles": [
        {
            "item_id": 684024,
            "sku": "start_pack_test_import_test_import",
            "type": "bundle",
            "name": {
                "en": "Legendary Start Pack"
            },
            "bundle_type": "standard",
            "description": {
                "en": "Crystal x 1\nGem x 1"
            },
            "image_url": "https://cdn3.xsolla.com/img/misc/merchant/default-dc-image.png",
            "regional_prices": [],
            "prices": [
                {
                    "amount": 20,
                    "currency": "USD",
                    "is_default": true,
                    "is_enabled": true
                }
            ],
            "virtual_prices": [],
            "is_enabled": true,
            "is_show_in_store": true,
            "regions": [],
            "limits": {
                "per_user": null,
                "per_item": null,
                "recurrent_schedule": null
            },
            "periods": [],
            "attributes": [],
            "long_description": null,
            "media_list": [],
            "order": 5,
            "is_free": false,
            "groups": [
                "my_test_group"
            ],
            "content": [
                {
                    "sku": "Gem_test_import",
                    "quantity": 1
                },
                {
                    "sku": "event_access_test_import",
                    "quantity": 1
                }
            ]
        }
    ]
}

  1. 在导入窗口的相应字段中上传完整文件。
  2. 如导入过程中发生错误,导入窗口中将显示错误列表和改正建议。请对文件作出必要更改,然后重新上传。

成功上传后,具有指定SKU的商品将完成创建、更新或禁用。

导出商品目录

要将一个商品或商品目录导出到JSON文件:

  1. 发布商帐户中打开项目。
  2. 在侧边栏中,单击商店,然后前往虚拟货币虚拟物品捆绑包部分。
  3. 单击导出商品

  1. 选择操作:
    • 导出全部商品 — 将导出包含该项目所有类型商品的完整目录。例如您前往虚拟货币部分并导出所有商品,JSON文件将导出项目的虚拟货币、虚拟货币套餐、虚拟物品和游戏密钥套餐。
    • 仅导出所选商品 — 在打开的窗口中选择要导出的商品。

  1. 单击导出

JSON文件将自动开始下载。

从外部平台导入目录

您可以从外部平台导入商品和订阅及同步用户物品库。

注意
导入后,可通过以下方式同步导入源和艾克索拉中对商品目录和订阅所作的更改:如果无法导入目录,请在发布商帐户中或通过API方法来配置商品和订阅目录。

从Google Play导入目录

注意

开始导入前,请检查您的Google Play项目已启用Google Play Android Developer API。请访问https://console.developers.google.com/apis/api/androidpublisher.googleapis.com/overview?project={project_id}project_id是您在Google Play中的项目ID。如该API为禁用状态,请启用它。该设置的应用需要一些时间,如启用该设置后立即尝试导入,可能会失败。请等待几分钟后再试。

  1. 发布商帐户中打开您的项目。
  2. 在侧边栏中单击商店
  3. 目录管理窗格中,单击配置
  4. 与外部平台集成窗格中,单击配置
  5. Google Play窗格中,单击配置
  6. 指定应用程序ID — 您在Google Play中的应用ID。
注:
您可以在Google Play Console中找到应用程序ID。在侧边栏中,单击 All apps。在表格中找到所需的应用。其ID在名称和Logo旁边的App列中。
  1. 上传包含私钥的JSON。
注:
私钥在创建您的服务帐户时生成。

  1. 前往Google Play Console,在侧边栏中单击Users and permissions,然后将服务帐户添加为新用户。

  1. 单击保存
  2. 单击开始导入。目录导入将立即开始。
注:
SKU对应于导入源中的产品ID。
  1. 要在通过建站器创建的网页商城中销售虚拟物品,请在发布商帐户中配置物品组,然后为每个物品分配一个或多个组
  2. 要显示物品图片,请在您的发布商帐户中上传图片
注:
对于孟加拉国的用户,目录价格以默认货币显示(美元),而不是孟加拉塔卡(BDT)。

从PlayFab导入目录

注意
支持的PlayFab API版本:Economy v1

PlayFab为游戏开发者提供现成可用的服务器解决方案,用于目录管理与游戏营收。集成PlayFab后,您可以从PlayFab导入目录到商店以使用艾克索拉解决方案。

注:
您将需要PlayFab中的项目ID和项目密钥。此外,您要导入艾克索拉的目录在PlayFab中应被设置为基本目录(Base)。

  1. 发布商帐户中打开您的项目。
  2. 在侧边栏中单击商店
  3. 目录管理窗格中,单击配置
  4. 与外部平台集成窗格中,单击配置
  5. PlayFab窗格中,单击配置
  6. 商品导入选项卡中指定:
  7. 单击保存
  8. 让用户物品库与PlayFab同步(可选):
    1. 前往物品库同步并指定:
    2. 用户物品库与PlayFab同步开关设置为
    3. 单击保存
  9. 前往商品导入选项卡,然后单击开始导入。目录导入将立即开始。
  10. 要在通过建站器创建的网页商城中销售虚拟物品,请在发布商帐户中配置物品组,然后为每个物品分配一个或多个组
  11. 要显示物品图片,请在您的发布商帐户中上传图片

要检查导入是否成功完成,请前往侧边栏中的商店部分,确保虚拟货币虚拟物品捆绑包选项卡中启用了虚拟物品、货币和捆绑包。

注意
检查导入结果时,请注意一个虚拟货币套餐是一个只包含一种货币的捆绑包。PlayFab使用的是与真实货币1美分等价的虚拟货币RM(100 RM = 1 USD)。例如,如果从PlayFab导入400 RM,在发布商帐户中看到的是4 USD。

重新导入目录

重新导入目录时,需考虑以下情况:

  • 已在商店中的商品将被更新。
  • 不在商店中的商品将被添加。
  • 已从导入源中删除的商品将保留在商店中。您可以在发布商帐户中删除或通过API删除。

通过API自动创建商品

如需根据自己系统的数据创建大量商品,可使用API自动化该过程。

您需要:

如要使用商品组,请预先通过发布商帐户界面创建组。

如要使用多种商品类型,应按照下列顺序进行创建:

  1. 在发布商帐户中创建商品组。
  2. 虚拟货币。
  3. 虚拟物品。
  4. 虚拟货币套餐。
  5. 捆绑包。

下面是一个脚本示例,它重复调用创建虚拟物品方法来创建虚拟物品。

该脚本使用JavaScript和JavaScript运行时引擎 — Node.js开发。

  1. 导入“node-fetch”模块的fetch函数以向艾克索拉服务器发送HTTP请求。
Copy
Full screen
Small screen
import fetch from "node-fetch";
  1. 设置请求授权所需的常量。不要插入<your project_id from PA><your api key from PA>,而应插入项目ID和API密钥的值,它们将使用Base64编码以便后续在API请求中使用。
Copy
Full screen
Small screen
const projectId = <your project_id from PA>;

const apiKey = <your api key from PA>;

const buff = new Buffer(`${projectId}:${apiKey}`);

const basicAuth = buff.toString('base64')
  1. 实现辅助函数sleep,用于在发送请求时创建延迟。这是为了不超出API请求的流量限制所必需的。
Copy
Full screen
Small screen
function sleep(ms) {

   return new Promise(resolve => setTimeout(resolve, ms));

}
  1. 实现您系统专用的getItems函数从您的系统获取商品数据。
Copy
Full screen
Small screen
async function getItems() {

   // receive items from the original system or read from a pre-prepared file

   return items;

}
  1. 实现您系统专用的prepareData函数以根据创建虚拟物品API调用中的数据格式来格式化商品数据。
Copy
Full screen
Small screen
function prepareData(items) {

   // format items in accordance with API requirements

   return formattedItems;

}
  1. 添加createItem函数,它向艾克索拉API发送POST请求来创建虚拟物品
Copy
Full screen
Small screen
async function createItem(item) {

   const url = `https://store.xsolla.com/api/v2/project/${projectId}/admin/items/virtual_items`;



   return await fetch(url, {

       method: "POST",

       headers: {

           Authorization: "Basic " + basicAuth,

           "Content-Type": "application/json"

       },

       body: JSON.stringify(item),

   });

}
  1. 添加checkItemExist函数,它检查指定SKU的虚拟物品是否存在。该函数向艾克索拉API发送一个GET请求:
    • 如收到包含404 HTTP代码的响应,说明指定SKU的商品不存在,需要创建。
    • 如收到包含200 HTTP代码的响应,说明找到了指定SKU的商品,无需创建。
Copy
Full screen
Small screen
async function checkItemExist(sku) {

   const url = `https://store.xsolla.com/api/v2/project/${projectId}/admin/items/virtual_items/sku/${sku}`;

   const response = await fetch(url, {

       method: "GET",

       headers: {

           Authorization: "Basic " + basicAuth

       }

   });

   return response.status !== 404;

}
  1. 添加createItems函数,它检查商品列表以查找艾克索拉侧是否存在您系统中SKU指定的商品。如没有该SKU的商品,则该函数创建该商品。进度信息在控制台中显示。
Copy
Full screen
Small screen
async function createItems(items) {

   let success = 0;

   let alreadyCreated = 0;

   for (let i = 0; i < items.length; i++) {

       const item = items[i];

       if (item['sku'] === undefined) {

           console.log(`${i} Field "sku" not specified`);

           continue;

       }

       const sku = item['sku'];

       if (await checkItemExist(sku)) {

           console.log(`${i} Item with sku "${sku}" already created`);

           alreadyCreated++;

           continue;

       }

       const response = await createItem(item);

       if (response.status === 201) {

           console.log(`${i} Item with sku "${sku}" successfully created`)

           success++;

       } else {

           const jsonData = await response.json();

           console.log(`${i} An error occurred while creating the items with sku "${sku}"`);

           console.log(jsonData);

       }

       // add a delay so as not to run into rate limits

       await sleep(500);

   }

   console.log(`${success} items out of ${items.length} created. ${alreadyCreated} items already existed`);

}
  1. 添加run函数,以正确的顺序调用上述所有函数。
Copy
Full screen
Small screen
async function run() {

 const items = await getItems();

 const formattedItems = prepareData(items);

 await createItems(formattedItems);

}

完整代码:

Copy
Full screen
Small screen
import fetch from "node-fetch";

const projectId = <your project_id from PA>;
const apiKey = <your api key from PA>;
const buff = new Buffer(`${projectId}:${apiKey}`);
const basicAuth = buff.toString('base64')

function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

async function getItems() {
    // receive items from the original system or read from a pre-prepared file
    return items;
}

function prepareData(items) {
    // format items in accordance with API requirements
    return formatedItems;
}

async function createItem(item) {
    const url = `https://store.xsolla.com/api/v2/project/${projectId}/admin/items/virtual_items`;

    return await fetch(url, {
        method: "POST",
        headers: {
            Authorization: "Basic " + basicAuth,
            "Content-Type": "application/json"
        },
        body: JSON.stringify(item),
    });
}

async function isItemExisted(sku) {
    const url = `https://store.xsolla.com/api/v2/project/${projectId}/admin/items/virtual_items/sku/${sku}`;
    const response = await fetch(url, {
        method: "GET",
        headers: {
            Authorization: "Basic " + basicAuth
        }
    });
    return response.status !== 404;
}

async function createItems(items) {
    let success = 0;
    let alreadyCreated = 0;
    for (let i = 0; i < items.length; i++) {
        const item = items[i];
        if (item['sku'] === undefined) {
            console.log(`${i} Field "sku" not specified`);
            continue;
        }
        const sku = item['sku'];
        if (await isItemExisted(sku)) {
            console.log(`${i} Item with sku "${sku}" already created`);
            alreadyCreated++;
            continue;
        }
        const response = await createItem(item);
        if (response.status === 201) {
            console.log(`${i} Item with sku "${sku}" successfully created`)
            success++;
        } else {
            const jsonData = await response.json();
            console.log(`${i} An error occurred while creating the items with sku "${sku}"`);
            console.log(jsonData);
        }
        // add a delay so as not to run into rate limits
        await sleep(500);
    }
    console.log(`${success} items out of ${items.length} created. ${alreadyCreated} items already existed`);
}

async function run() {
  const items = await getItems();
  const formattedItems = prepareData(items);
  await createItems(formattedItems);
}

run(); 
本文对您的有帮助吗?
谢谢!
我们还有其他可改进之处吗? 留言
非常抱歉
请说明为何本文没有帮助到您。 留言
感谢您的反馈!
我们会查看您的留言并运用它改进用户体验。
上次更新时间: 2024年11月8日

发现了错别字或其他内容错误? 请选择文本,然后按Ctrl+Enter。

报告问题
我们非常重视内容质量。您的反馈将帮助我们做得更好。
请留下邮箱以便我们后续跟进
感谢您的反馈!