Skip to main content

Meta Catalog Batch API integration through ROI Hunter

Updated over a month ago

If you have a catalog with a big amount of products and quickly-changing inventory, using product feeds might not be a viable option for you. Instead of using a product feed to update a catalog, it's possible to use Meta's Catalog Batch API to send real-time information about the products that have changed via HTTP requests.

In order for you to use our features such (Image Templates, Dynamic Slideshows, Product Insights, etc.) with Catalog Batch API, we provide an endpoint where you send HTTP requests, we enhance products and forward them to Meta.

NOTE: We don't support API integration combined with product feed source file (XML or CSV feed). Once the catalog is whitelisted for our API, it should not contain any other data source.

Catalog Batch API

ROI Hunter API is similar to Meta API, but there are a few differences and specifics. All implementation details are described in this article. We highly recommend studying it carefully.

The endpoint for ROI Hunter is:

POST 
https://products-api.roihunter.com/api/v2/catalogs/{catalogMetaId}/batch

You need an access token to send HTTP requests. Contact us, and we will provide you with the token.

HTTP request body

Field

Description

access_token

type: string

Required.

allow_upsert

type: boolean

Optional. Default value: true.

If true, then update requests for non existing products are allowed to create the products.

requests

type: array<object>

Required.

An array of batch request objects.

Batch request object should contain the following fields:

  • method

    • (type: string)

    • Use CREATE, UPDATE or DELETE.

  • retailer_id

    • (type: string)

    • The advertiser-supplied product ID (not the Meta ID).

  • data

    • (type: object)

    • JSON object containing fields and values for the product. Required for CREATE and UPDATE requests. Irrelevant for DELETE requests

Every HTTP request must contain non-empty requests field, containing requests of CREATE, UPDATE or DELETE method. Every request method has some specifics, documented below.

CREATE method

Use this method to add new products to the catalog. CREATE requests on products which already exist are accepted and converted to updates.

Required fields in data

Field

Description

name

type: string

Product's name. Max size: 100.

price

type: integer

The price multiplied by 100.

currency

type: string

Currency for the value specified. Use ISO 4217 for currency standards.

url

type: string

Link to merchant's site where someone can buy the product.

image_url

type: string

Link to product image used in the ad.

description

type: string

Product's description. Max size: 5000.

At least one of the following fields must be set in order to create valid product.

brand

type: string

Product's brand.

gtin

type: string

Global Trade Item Number can include UPC, EAN, JAN, and ISBN. Max size: 70

manufacturer_part_number

type: string

Unique manufacturer ID for product. This field is usually called mpn in CSV/XML product feeds.

Optional fields in data

additional_image_urls

type: array<string>

URLs for up to 20 different images.

address

type: object

An object containing latitude and longitude.

age_group

type: string

Group of people who are the same age or a similar age. Accepted values are newborn, infant, toddler, kids, adult.

applinks

type: object

Links to mobile apps. An object containing mobile platforms (ios, android, ...), where every platform contains a list of platform-specific app properties, such as name or ID.

availability

type: string

  • in stock - Product ships immediately.

  • out of stock - No plan to restock

  • available for order - Ships in 1–2 weeks.

  • discontinued

availability_radius

type: float

Radius specified in kilometers from the given address.

category

type: string

Google product category (GPC) for the product. Use the category's taxonomy path or its ID number, listed here.

color

type: string

Product color.

Max size: 100.

condition

type: string

Product's condition: new, refurbished, used.

custom_label_0

type: string

Additional information about product.

Max size: 100.

custom_label_1

type: string

Additional information about product.

Max size: 100.

custom_label_2

type: string

Additional information about product.

Max size: 100.

custom_label_3

type: string

Additional information about product.

Max size: 100.

custom_label_4

type: string

Additional information about product.

Max size: 100.

custom_number_0

type: integer

Additional numeric information about product. A whole positive number is required.

custom_number_1

type: integer

Additional numeric information about product. A whole positive number is required.

custom_number_2

type: integer

Additional numeric information about product. A whole positive number is required.

custom_number_3

type: integer

Additional numeric information about product. A whole positive number is required.

custom_number_4

type: integer

Additional numeric information about product. A whole positive number is required.

gender

type: string

Gender for sizing. Values include male, female, unisex.

importer_address

type: object

Address of the product importer.

importer_name

type: string

Name of the product importer.

internal_label

type: array<string>

Use up to 5000 labels per product and 110 characters per label.

manufacturer_info

type: string

The manufacturer information.

material

type: string

Material of the product.

origin_country

type: string

2-letter code of a country.

pattern

type: string

Pattern or graphic print on the product.

Max size: 100.

product_priority_0

type: float

Product priority.

Decimal number between 0.7 and 1.3.

product_priority_1

type: float

Product priority.

Decimal number between 0.7 and 1.3.

product_priority_2

type: float

Product priority.

Decimal number between 0.7 and 1.3.

product_priority_3

type: float

Product priority.

Decimal number between 0.7 and 1.3.

product_priority_4

type: float

Product priority.

Decimal number between 0.7 and 1.3.

product_type

type: string

Retailer-defined category for the product.

Max size: 750.

retailer_product_group_id

type: string

Advertisers can use it to group products together. This field is usually called item_group_id in CSV/XML product feeds.

sale_price

type: integer

The sale price multiplied by 100.

sale_price_effective_date

type: string

Start and end date and time for the sale, separated by a slash. Write the start and end dates as YYYY-MM-DD. Add a "T" after each date and then include the time. Write the time in a 24-hour format (0:00 to 23:59). Example: 2014-11-01T12:00-0300/2014-12-01T00:00-0300.

shipping

type: array<object>

Shipping information. Array of objects containing shipping_country, shipping_region, shipping_service, shipping_price_value and shipping_price_currency.

size

type: string

Size of the product. Example: Small or XL.

video

type: array<object>

URLs and tags for videos to be used in your ads. Tags are optional and, if used, should describe what is in the video.

Each product can have up to 20 videos, where every video can have up to 1 tag.

Video object should contain:

  • url

    • (type: string)

  • tag

    • (type: array<string>)

    • optional; max 1 per video URL

visibility

type: string

  • published

  • staging

  • hidden

  • whitelist_only

vendor_id

type: string

The ID of the vendor/seller that sells the product.

Example HTTP request

{
"access_token": "<ACCESS_TOKEN>",
"requests": [{
"method": "CREATE",
"retailer_id": "retailer_id_1",
"data": {
"applinks": {
"ios": [{
"url": "example-ios://example",
"app_store_id": 123,
"app_name": "app name"
}],
"android": [{
"app_name": "app name",
"package": "com.package.name",
"url": "example-android://example"
}]
},
"availability": "in stock",
"brand": "Some brand",
"category": "t-shirts",
"condition": "new",
"currency": "USD",
"description": "Product description",
"image_url": "http://www.images.example.com/t-shirts/1.png",
"name": "Product name",
"price": 1000,
"retailer_product_group_id": "product-group-1",
"shipping": [{
"shipping_country": "US",
"shipping_region": "CA",
"shipping_service": "service",
"shipping_price_value": "10",
"shipping_price_currency": "USD"
}],
"url": "http://www.images.example.com/t-shirts/1.png",
"video": [{
"url":"http://example.com/video_1.mp4",
"tag": ["Summer"]
}]
}
}]
}

Example response (OK)

Response contains a handle, which can be used to check the status of asynchronous processing of the batch of products. One handle is returned for the whole request.

Status code: 200

Response body:

{
"handles": [
"Aczq4HLYFA8flS0gWr5YzLuShNtJnxFh5K4kLJQeY..."
]
}

Example response (product errors/warnings)

If product in the HTTP request has an invalid product URL, then it cannot be stored. This problem is returned as error. If product data contain an unsupported extra field, then this extra field is ignored. This is returned as a warning.

Status code: 200

Response body:

{
"handles":[
"Aczq4HLYFA8flS0gWr5YzLuShNtJnxFh5K4kLJQeY..."
],
"validation_status": [
{
"retailer_id": "1",
"errors": [
{
"message": "Product has the attribute 'URL' in unsupported format. Please make sure every product has a valid attribute 'URL' starting with one of: 'http://', 'https://', 'ftp://', 'sftp://'."
}
],
"warnings": [
{
"message": "The request contains unsupported product fields, which will be ignored. Ignored fields: {'some_field'}"
}
]
}
]
}

Example response (no changes)

HTTP request, which was not forwarded to Meta at all, because there were no changes compared to the previous state

Status code: 200

Response body:

{
"message": "There are no applicable requests in provided payload. No API calls to Meta will be made."
}

Example response (invalid request body)

HTTP request, which is missing method (CREATE/UPDATE/DELETE) in the data.

Status code: 400

Response body:

{
"error": {
"code": "request_invalid_data",
"message": "Errors: required key not provided @ data['requests'][0]['method']",
"severity": "critical"
}
}

Example response (exceeding rate limit)

HTTP request, which exceeded API rate limit (you can ask Meta to increase the API limits for you).

Status code: 400

Response body:

{
"error": {
"message": "Calls to this api have exceeded the rate limit. (613)"
}
}

Example response (server error)

HTTP request has failed unexpectedly

Status code: 500

Response body:

{
"error": {
"message": "An unexpected error has occurred. Please retry your request later."
}
}

UPDATE method

Use this method to update the values of existing products in catalog. This method doesn’t have any required fields, the only limitation is that at least one field to update must be sent.

Example HTTP request

{
"access_token": "<ACCESS_TOKEN>",
"requests": [
{
"method": "UPDATE",
"retailer_id": "retailer_id_1",
"data": {
"price": 800
}
}
]
}

Example response (OK)

Response contains a handle, which can be used to check the status of asynchronous processing of the batch of products. One handle is returned for the whole request.

Status code: 200

Response body:

{
"handles": [
"Aczq4HLYFA8flS0gWr5YzLuShNtJnxFh5K4kLJQeY..."
]
}

Example response (some products not changed)

When HTTP requests contains more products, but some of them did not change comparing to previous state, then they are not forwarded to Meta and retailer IDs of such products are returned in unchanged_products.

Status code: 200

Response body:

{
"handles": [
"Aczq4HLYFA8flS0gWr5YzLuShNtJnxFh5K4kLJQeY..."
],
"unchanged_products": {
"message": "Some of the products already contain given changes. Updates of those products will not be sent to FB again.",
"retailer_ids": [
"2"
]
}
}

DELETE method

Use this method to delete products in catalog.

Example HTTP request

{
"access_token": "<ACCESS_TOKEN>",
"requests": [
{
"method": "DELETE",
"retailer_id": "retailer_id_1"
}
]
}

Limitations

  • Meta limits the HTTP request to contain up to 5000 products.

  • ROI Hunter does not apply any rate limit on the API requests. But there is a limit applied by Meta. In case you are hitting the rate limit for your catalog, please contact our Support team. We can request Meta Support to increase your limit. The rate limit on catalog is driven by the number of Facebook and Instagram users that saw products from yout catalog. See more about the calculation here.

  • Meta also has a limitation on how big payload can be in terms of Bytes. In case of too big payload, Meta will return an error with status code 500 and a response {"error":{"code":1,"message":"Please reduce the amount of data you're asking for, then retry your request"}} In such a case you need to make your payload smaller and try again. We suggest sending up 5MB of the payload for safety and stability.

  • More information about limitations can be seen also here.

Check Batch Request Status API

A successful batch update return handle, which can be used to check the status of the update. To check the status use the endpoint:

GET 
https://products-api.roihunter.com/api/v2/catalogs/{catalogMetaId}
/check_batch_request_status

HTTP parameters

Parameter

Description

access_token

type: string

Required.

handle

type: string

Unique handle of a batch request.

load_ids_of_invalid_requests

type: boolean

When true the returned status will contain a list of product ids (retailer ids) for which the requests failed

Example HTTP request

GET https://products-api.roihunter.com/api/v2/catalogs/123456/check_batch_request_status?access_token=AAA&handle=BBB&load_ids_of_invalid_requests=true

Example response (OK)

Status is finished what means that batch request with the corresponding handle was already processed. There are no errors, so all products were processed successfully.

Status code: 200

Response body:

{
"data": [
{
"handle": "Aczq4HLYFA8flS0gWr5YzLuShNtJnxFh5K4kLJQeY...",
"status": "finished",
"errors_total_count": 0,
"errors": [],
"warnings": []
}
]
}

Maintaining catalog quality

There will always be the risk that some requests fail. As you're only communicating changes with Catalog Batch API (instead of always providing the whole state of your catalog as with feed files), there's the possibility that the Catalog on Meta will start drifting apart from your actual inventory status. Thus, we recommend running full updates for all your products periodically, for example, once per day.

Features

ROI Hunter allows all its feed-related features also for API catalogs. You can

  • apply image templates, dynamic slideshows

  • connect product insights from Google Analytics, Google shopping and even connect the custom source with product data

  • promote products dynamically filtered according

We recommend you to not change this kind of settings too frequently. Bear in mind that if you e.g. apply an image template, we have to re-upload the whole product inventory which can take even several hours based on the number of products and Meta limits.

FAQ

How long does it take to process the request?

It takes about a second to forward the request to Meta. But if you have also image templates applied on the catalog, it may take about a minute based on the count of created/updated products.

Even though we are constantly working on improvements, to ensure correct processing of HTTP requests, you should set the request timeout to 300 seconds, what corresponds to global server time-out of the API.

Is there any limitation in number of requests?

ROI Hunter does not apply any limitation. We accept the limitation defined by Meta for your Product catalog. See more information here.

What I need to check to make sure that my request passed properly and the product is in required state?

  1. Check batch request response and its message.

  2. Check batch request status using handle.

How should I react to request issues?

If the HTTP request ends with status code 500, or the error message says Calls to this api have exceeded the rate limit. (613), you can re-try the same request later.

For any other error, you should edit your request accordingly to make it valid. The issues are described in the response message and in batch request status.

How to fix invalid product state (incorrect availability, price, image) for API integrated catalog?

  1. Make sure that you follow this documentation and your requests are passing. Check the latest request containing the product. If you cannot find it, you can just send the same product again.

  2. Check the latest product data that you have sent to us - are they correct? Send the product again with the correct data.

  3. If re-sending did not help, please get in touch with us for detailed investigation. Please provide: Product Catalog ID, problematic product(s) ID(s), expected and actual value.

How can I check that the product is in requested state on Meta?

You can check the products in Commerce Manager (former Catalog Manager) in Meta Business Manager, but please keep in mind that the images displayed on this page might not be always up to date.

If you have access to Meta Graph API, you can check the products also there. Details about Product Items can be seen in Meta Developer documentation.

In this example, you can see a call to check product availability, price and images. The product can be filtered by retailer_id field.

https://graph.facebook.com/v21.0/{catalogMetaId}/products?fields=id,name,retailer_id,url,availability,price,sale_price,image_url,image_cdn_urls,additional_image_urls,additional_image_cdn_urls&filter={"retailer_id":{"eq":"4"}}

Here is an example response in Graph API explorer tool:

The fields image_url and additional_image_urls represent the images provided by you (or by ROI Hunter when the image template is applied).

image_cdn_urls and additional_image_cdn_urls represent images fetched to Meta cache. If these fields are empty, Meta has not fetched the current images yet (no Pixel or App event has not been fired for the product since the last update).

In case of any additional questions, feel free to reach out to our Support team for more info. 😉

Did this answer your question?