Skip to content

billgerrard/bing-content-api

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

NAME

Bing::ContentAPI - Perl interface to the Bing Ads / Microsoft Advertising Content API

DESCRIPTION

Add, modify and delete products from the Microsoft Advertising Merchant Center platform
via the Bing Ads / Microsoft Advertising Content API.

https://learn.microsoft.com/en-us/advertising/shopping-content/

Authentication is done via OAuth using Authorization Code Grant Flow

See https://learn.microsoft.com/en-us/advertising/guides/authentication-oauth and
https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow

Follow the steps to register an application with the Microsoft identity platform:
https://learn.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app

Set up a Redirect URI. Set up a Mobile/Desktop app redirect URI (not a Web application redirect).
https://learn.microsoft.com/en-us/azure/active-directory/develop/reply-url

A redirect URI of 'http://localhost/native-app' is used as an example in this documentation.

Steps to authorize a native application and generate an initial refresh token:

Note: Substitute CLIENT_ID, REDIRECT_URI and AUTHORIZATION_CODE with the
actual values in the appropriate locations in the examples.

1) Request user consent through web browser:
(using an existing Bing Ads / Microsoft Advertising account when prompted)

https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&response_type=code&response_mode=query&scope=offline_access%20https%3A%2F%2Fads.microsoft.com%2Fmsads.manage

Response received:
http://localhost/native-app?code=AUTHORIZATION_CODE

2) Use the authorization 'code' received to request the access token and refresh token.
Note: scope must include 'offline_access', as included in the example, to receive a refresh token.

$ curl \
  -d client_id=CLIENT_ID \
  -d code=AUTHORIZATION_CODE \
  -d grant_type=authorization_code \
  -d redirect_uri=REDIRECT_URI \
  -d scope=offline_access%20https%3A%2F%2Fads.microsoft.com%2Fmsads.manage \
  -H "Content-Type: application/x-www-form-urlencoded" \
  https://login.microsoftonline.com/common/oauth2/v2.0/token

Response:
{
  "token_type": "Bearer",
  "scope": "https://ads.microsoft.com/msads.manage",
  "expires_in": 3600,
  "ext_expires_in": 3600,
  "access_token": "...",
  "refresh_token": "..."
}

3) Use the received refresh_token as the initial refresh_token in Bing::ContentAPI->new()

SYNOPSIS

use Bing::ContentAPI;
use Data::Dumper;

my $bing = Bing::ContentAPI->new({
  debug => 0,
  redirect_uri    => 'http://localhost/native-app',
  merchant_id     => '12345',          # merchant_id is the Merchant Center store ID
  developer_token => '123ABC456DEF789',
  client_id       => '1234abcd-5679-efgh-123456789',
  refresh_token   => load_token(),     # previously saved refresh token
});
save_token($bing->{refresh_token}); # save new refresh token

sub load_token {
  my $token;
  # load token from storage
  return $token;
}

sub save_token {
  my $token = shift;
  # save token to storage
}

my ($request, $result, $products, $batch_id, $product_id);

# list products

my $nextPageToken = '';
do {
  $request = {
    resource => 'products',
    method   => 'list',
    params   => ['max-results' => 250],
  };
  push @{$request->{params}}, ('start-token', "$nextPageToken") if $nextPageToken ne '';

  $result = $bing->get(%$request);
  $nextPageToken = $result->{response}->{nextPageToken} || '';

  print "$result->{code} ". ($result->{code} eq '200' ? 'success' : 'failure') ."\n";
  print "Products list: \n". Dumper $result;
} while ($nextPageToken ne '');

# list catalogs

$result = $bing->get(
  resource => 'catalogs',
  method   => 'list',
);
print "$result->{code} ". ($result->{code} eq '200' ? 'success' : 'failure') ."\n";
print "Catalogs list: \n". Dumper $result;

# get status of product offers in a catalog

my $catalogID = 123456;
$result = $bing->get(
  resource => 'catalogs',
  method   => 'status',
  id       => $catalogID,
);
print "$result->{code} ". ($result->{code} eq '200' ? 'success' : 'failure') ."\n";
print "Catalog status: \n". Dumper $result;

# insert a product

$result = $bing->post(
  resource => 'products',
  method   => 'insert',
  dryrun   => 1,
  body => {
    contentLanguage => 'en',
    targetCountry => 'US',
    channel => 'online',
    offerId => '333333',
    title => 'Item title',
    description => 'The item description',
    link => 'http://www.bing.com',
    imageLink => 'https://img-prod-cms-rt-microsoft-com.akamaized.net/cms/api/am/imageFileData/RE1Mu3b',
    availability => 'in stock',
    condition => 'new',
    price => {
        value => '99.95',
        currency => 'USD',
    },
    shipping => [
      {
        country => 'US',
        service => 'Standard Shipping',
        price => {
          value => '7.95',
          currency => 'USD',
        },
      },
    ],
    brand => 'Apple',
    gtin => '33333367890',
    mpn => '333333',
    googleProductCategory => 'Home & Garden > Household Supplies > Household Paper Products > Paper Towels',
    productType => 'Home & Garden > Household Supplies > Household Paper Products > Paper Towels',
    customLabel1 => 'Paper Towels'
  }
);
print "$result->{code} ". ($result->{code} eq '200' ? 'success' : 'failure') ."\n";

# get single product info

$product_id = '333333';
$result = $bing->get(
  resource => 'products',
  method   => 'get',
  id       => 'online:en:US:'. $product_id
);
print "$result->{code} ". ($result->{code} eq '200' ? 'success' : 'failure') ."\n";
print "Products info: \n". Dumper $result;

# delete a product

print "product delete: ";

my $del_product_id = '333333';
$result = $bing->delete(
  resource => 'products',
  method   => 'delete',
  id       => 'online:en:US:'. $del_product_id,
  dryrun   => 1,
);
print "$result->{code} ". ($result->{code} eq '204' ? 'success' : 'failure') ."\n"; # 204 = delete success
print Dumper $result;

# batch insert

$products = [];
$batch_id = 0;

foreach my $i ('211203'..'211205') {
  push @$products, {
    batchId => ++$batch_id,
    merchantId => $bing->{merchant_id},
    method => 'insert', # insert / get / delete
    #productId => '', # for get / delete
    product => { # for insert
      contentLanguage => 'en',
      targetCountry => 'US',
      channel => 'online',
      offerId => "$i",
      title => "item title $i",
      description => "The item description for $i",
      link => 'http://www.bing.com',
      imageLink => 'https://img-prod-cms-rt-microsoft-com.akamaized.net/cms/api/am/imageFileData/RE1Mu3b',
      availability => 'in stock',
      condition => 'new',
      price => {
        value => '10.95',
        currency => 'USD',
      },
      shipping => [
        {
          country => 'US',
          service => 'Standard Shipping',
          price => {
            value => '7.95',
            currency => 'USD',
          },
        },
      ],
      brand => 'Apple',
      gtin => "${i}67890",
      mpn => "$i",
      googleProductCategory => 'Home & Garden > Household Supplies > Household Paper Products > Paper Towels',
      productType => 'Home & Garden > Household Supplies > Household Paper Products > Paper Towels',
      customLabel1 => 'Paper Towels'
    }
  };
}

$result = $bing->post(
  resource => 'products',
  method   => 'batch',
  dryrun   => 1,
  body => { entries => $products }
);
print "$result->{code} ". ($result->{code} eq '200' ? 'success' : 'failure') ."\n";

# batch get

$products = [];
$batch_id = 0;
foreach my $product_id ('211203'..'211209') {
  push @$products, {
    batchId    => ++$batch_id,
    merchantId => $bing->{merchant_id},
    method     => 'get', # insert / get / delete
    productId  => 'online:en:US:'. $product_id, # for get / delete
  };
}

$result = $bing->post(
  resource => 'products',
  method   => 'batch',
  dryrun   => 1,
  body => { entries => $products }
);
print "$result->{code} ". ($result->{code} eq '200' ? 'success' : 'failure') ."\n";
print Dumper $result;

# batch delete

$products = [];
$batch_id = 0;
foreach my $product_id ('211203'..'211205') {
  push @$products, {
    batchId    => ++$batch_id,
    merchantId => $bing->{merchant_id},
    method     => 'delete', # insert / get / delete
    productId  => 'online:en:US:'. $product_id, # for get / delete
  };
}

$result = $bing->post(
  resource => 'products',
  method   => 'batch',
  dryrun   => 1,
  body => { entries => $products }
);
print "$result->{code} ". ($result->{code} eq '200' ? 'success' : 'failure') ."\n";

METHODS AND FUNCTIONS

new()

Create a new Bing::ContentAPI object

debug

Displays API debug information

merchant_id

Merchant ID is the Microsoft Advertising Merchant Center Store ID at https://ads.microsoft.com/

developer_token

Developer token from https://developers.ads.microsoft.com/Account

client_id

Client ID is the Application ID value in "Registering Your Application":
https://learn.microsoft.com/en-us/advertising/guides/authentication-oauth-register

redirect_uri

Redirect URI is the Mobile/Desktop app redirect URI value in "Registering Your Application":
https://learn.microsoft.com/en-us/advertising/guides/authentication-oauth-register

refresh_token

The current refresh token

refresh_access_token()

Using the current refresh_token, obtain a new access and refresh token

access_token

returns access_token obtained via refresh_access_token()

refresh_token

returns refresh_token obtained via refresh_access_token()

PRODUCTS

batch

Retrieves, inserts, and deletes multiple products in a single request.

insert

Uploads a product to your Merchant Center account. If an item with the
same channel, contentLanguage, offerId, and targetCountry already exists,
this method updates that entry.

list

Lists the products in your Merchant Center account.

get

Retrieves a product from your Merchant Center account.

delete

Deletes a product from your Merchant Center account.

CATALOGS

list

Lists the catalogs in your Merchant Center Account.

status

Lists the status and issues of products offers in your Merchant Center Account.

UNIMPLEMENTED FEATURES

Certain API methods are not yet implemented (no current personal business need).

A "custom" resource is available to perform methods that are not implemented by
this module.

$result = $bing->get(
  resource => 'custom',
  method   => 'merchantId/orders/orderId'
);

PREREQUISITES

JSON
REST::Client
HTML::Entities

AUTHOR

Original Author
Bill Gerrard <bill@gerrard.org>

COPYRIGHT AND LICENSE

Copyright (C) 2018-2022 Bill Gerrard

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.20.2 or,
at your option, any later version of Perl 5 you may have available.
Disclaimer of warranty: This program is provided by the copyright holder
and contributors "As is" and without any express or implied warranties.
The implied warranties of merchantability, fitness for a particular purpose,
or non-infringement are disclaimed to the extent permitted by your local
law. Unless required by law, no copyright holder or contributor will be
liable for any direct, indirect, incidental, or consequential damages
arising in any way out of the use of the package, even if advised of the
possibility of such damage.

Releases

No releases published

Packages

No packages published

Languages