Metadata-Version: 2.4
Name: arcane-bing
Version: 1.0.2
Summary: Helpers to request bing API
Author: Arcane
Author-email: product@wearcane.com
Requires-Python: >=3.11,<3.14
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Requires-Dist: arcane-core (>=1.41.0,<2.0.0)
Requires-Dist: backoff (>=1.10.0)
Requires-Dist: msads (==13.0.29)
Requires-Dist: python-dateutil (>=2.8.2)
Requires-Dist: urllib3 (>=2.0)
Description-Content-Type: text/markdown

# Arcane bing

This package is based on [msads](https://learn.microsoft.com/en-us/advertising/guides/python-sdk-migration-soap-to-rest?view=bingads-13), the Microsoft Advertising REST SDK.

## Get Started

```sh
pip install arcane-bing
```

## Example Usage

### Reporting

```python
bing_client = Client(
    credentials=Config.BING_ADS_CREDENTIALS,
    secrets_bucket=Config.SECRETS_BUCKET,
    refresh_token_location=Config.BING_ADS_REFRESH_TOKEN,
    storage_client=storage_client
)

reporting_service_manager, reporting_service = bing_client.get_bing_ads_api_client()

report_request = build_campaigns_report(bing_account_id)

result_file_path = bing_client.submit_and_download(report_request, reporting_service_manager)
```

### Campaign Service

:warning: For some API methods, you must provide the client's account id and the manager's customer id

```python
from arcane.bing import Client, to_microsoft_advertising_exception
from openapi_client.exceptions import ApiException
from openapi_client.models.campaign import CampaignType, GetCampaignsByAccountIdRequest


bing_client = Client(
    credentials=Config.BING_ADS_CREDENTIALS,
    secrets_bucket=Config.SECRETS_BUCKET,
    refresh_token_location=Config.BING_ADS_REFRESH_TOKEN,
    storage_client=storage_client,
    customer_id=CUSTOMER_ID,
    account_id=ACCOUNT_ID
)

campaign_service = bing_client.get_service_client(service_name='CampaignManagement')

try:
    # Ids are strings. Without campaign_type, only Search campaigns are returned.
    request = GetCampaignsByAccountIdRequest(
        AccountId=str(ACCOUNT_ID),
        CampaignType=CampaignType.SEARCH | CampaignType.SHOPPING
    )
    response = campaign_service.get_campaigns_by_account_id(get_campaigns_by_account_id_request=request)
    all_campaigns = response.campaigns or []
    # do stuff with all_campaigns
except ApiException as e:
    # Raises MicrosoftAdvertisingAccountLostAccessException, MicrosoftAdvertisingAuthenticationException,
    # MicrosoftAdvertisingRateLimitException, MicrosoftAdvertisingServerException or MicrosoftAdvertisingApiException
    raise to_microsoft_advertising_exception(e, ACCOUNT_ID) from e
```

### Errors

Client methods calling Microsoft Advertising (`get_bing_campaigns`, `get_account_name`, `submit_and_download`)
convert API errors according to the [Microsoft Advertising error code](https://learn.microsoft.com/en-us/advertising/guides/operation-error-codes?view=bingads-13):

| Exception | Cause | Retried by the client |
|---|---|---|
| `MicrosoftAdvertisingAccountLostAccessException` | No access to the account, invalid account | No |
| `MicrosoftAdvertisingAuthenticationException` | Invalid or expired credentials | No |
| `MicrosoftAdvertisingRateLimitException` | Too many calls or report requests | Yes, after 60 seconds |
| `MicrosoftAdvertisingServerException` | Microsoft Advertising unavailable | Yes |
| `MicrosoftAdvertisingApiException` | Any other rejected request | No |

Network errors (timeouts, closed connections) keep their type and are retried.

