microsoft/bingads
Microsoft Bing Ads PHP SDK with PSR-4 autoloading and SOAP proxies for all Bing Ads API services. Simplifies OAuth authentication and integrates easily via Composer (microsoft/bingads) so you can build and manage advertising apps in PHP.
Installation
composer require microsoft/bingads
Ensure extension=soap is enabled in php.ini.
First Authentication
Use the OAuthDesktopMobileAuthCodeGrant for local development:
use Microsoft\BingAds\V13\Authentication\OAuthDesktopMobileAuthCodeGrant;
use Microsoft\BingAds\V13\Authentication\AuthenticationHelper;
$authenticationHelper = new AuthenticationHelper();
$authCodeGrant = new OAuthDesktopMobileAuthCodeGrant(
$authenticationHelper->GetDeveloperToken(),
$authenticationHelper->GetRefreshToken(),
$authenticationHelper->GetAccessToken(),
$authenticationHelper->GetAuthCode()
);
$authCodeGrant->Authenticate();
First API Call Fetch account information:
use Microsoft\BingAds\V13\CampaignManagement\CampaignManagementServiceClient;
$serviceClient = new CampaignManagementServiceClient(
$authCodeGrant->GetAccessToken(),
$authCodeGrant->GetRefreshToken(),
$authCodeGrant->GetCustomerId()
);
$accounts = $serviceClient->GetCustomerAccounts();
vendor/microsoft/bingads/src/V13/ (auto-generated proxies)Pattern: Initialize once, reuse across requests.
// app/Services/BingAdsService.php
class BingAdsService {
private $serviceClient;
public function __construct(OAuthDesktopMobileAuthCodeGrant $auth) {
$this->serviceClient = new CampaignManagementServiceClient(
$auth->GetAccessToken(),
$auth->GetRefreshToken(),
$auth->GetCustomerId()
);
}
public function getCampaigns() {
return $this->serviceClient->GetCampaigns();
}
}
Use BulkService for large-scale updates:
$bulkService = new BulkServiceClient($auth);
$bulkOperation = new BulkOperationHeader();
$bulkOperation->Operation = BulkOperationType::Add;
$bulkOperation->Objects = [$campaign1, $campaign2];
$bulkResponse = $bulkService->ExecuteBulkOperation($bulkOperation);
Generate and download reports:
$reportingService = new ReportingServiceClient($auth);
$reportRequest = new ReportRequest();
$reportRequest->ReportName = "CampaignPerformanceReport";
$reportRequest->Aggregation = ReportAggregation::Daily;
$reportRequest->Columns = ["CampaignName", "Impressions", "Clicks"];
$downloadRequest = new DownloadReportRequest($reportRequest);
$reportDownload = $reportingService->DownloadReport($downloadRequest);
Wrap API calls in try-catch:
try {
$response = $serviceClient->GetCampaigns();
} catch (Exception $e) {
if ($e->getCode() === 401) {
$auth->RefreshToken(); // Refresh and retry
}
throw $e;
}
Store credentials in .env:
BINGADS_DEVELOPER_TOKEN=your_dev_token
BINGADS_REFRESH_TOKEN=your_refresh_token
BINGADS_CUSTOMER_ID=1234567
Load via Laravel’s config() helper or a custom config file.
Token Expiry
401 Unauthorized by refreshing the token:
if ($e->getCode() === 401) {
$auth->RefreshToken();
retry(); // Implement retry logic
}
retry() helper or a custom decorator.Sandbox vs. Production
login.windows-ppe.net (not live-int.com as of v13.0.10).Scopes
msads.manage (required for MFA).oAuthScope in ServiceClient constructor:
$serviceClient = new CampaignManagementServiceClient(
$auth->GetAccessToken(),
$auth->GetRefreshToken(),
$auth->GetCustomerId(),
['oAuthScope' => 'https://bingads.microsoft.com/Api/Advertiser/Manage']
);
Bulk Operations
ValidateBulkOperation to pre-check:
$validation = $bulkService->ValidateBulkOperation($bulkOperation);
if ($validation->HasErrors) {
throw new \RuntimeException("Bulk operation validation failed");
}
Reporting Delays
OfflineConversionReport) take 24+ hours to populate.reportReady() check with exponential backoff.SOAP Headers
CustomerId or CustomerAccountId in headers causes 400 Bad Request.$serviceClient->GetServiceClient()->GetSoapClient()->__getLastRequestHeaders();
Rate Limiting
throttle middleware or a queue:
Queue::later(now()->addSeconds(0.2), fn() => $serviceClient->GetCampaigns());
Enable SOAP Debugging
$serviceClient->GetServiceClient()->GetSoapClient()->setDebug(true);
$lastRequest = $serviceClient->GetServiceClient()->GetSoapClient()->__getLastRequest();
$lastResponse = $serviceClient->GetServiceClient()->GetSoapClient()->__getLastResponse();
Log Authentication Tokens
access_token or refresh_token in production.customer_id and timestamp for debugging:
Log::debug("BingAds request for customer {$auth->GetCustomerId()}");
Version Mismatches
InvalidOperationException.composer.json:
"microsoft/bingads": "13.0.28"
Custom Proxies
CampaignManagementServiceClient) to add business logic:
class CustomCampaignServiceClient extends CampaignManagementServiceClient {
public function getActiveCampaigns() {
$campaigns = parent::GetCampaigns();
return array_filter($campaigns, fn($c) => $c->Status == 'Active');
}
}
Event Listeners
illuminate.queue events to retry failed Bing Ads jobs:
Queue::failing(function (FailedJob $job, $exception) {
if (str_contains($exception->getMessage(), '401')) {
$job->release(60); // Retry after 60 seconds
}
});
Model Bindings
class BingAdCampaign extends Model {
protected $fillable = ['name', 'status', 'budget'];
public static function syncFromApi() {
$campaigns = app(BingAdsService::class)->getCampaigns();
return self::upsert($campaigns->toArray(), ['id']);
}
}
Testing
ServiceClient in PHPUnit:
$mockClient = $this->createMock(CampaignManagementServiceClient::class);
$mockClient->method('GetCampaigns')->willReturn(new Campaign[]);
$this->app->instance(CampaignManagementServiceClient::class, $mockClient);
How can I help you explore Laravel packages today?