Billing

https://d1y2lf8k3vrkfu.cloudfront.net/openapi/en-us/dest/AdvertisingBilling_prod_3p.json

Invoices, payments, the methods an account pays with, and the profiles that decide who gets charged.

class ad_api.api.Billing(account: str = 'default', marketplace: Marketplaces = Marketplaces.EU, credentials: Dict[str, str] | None = None, proxies: Dict[str, str] | None = None, verify: bool = True, timeout: int | None = None, debug: bool = False, access_token: str | None = None, verify_additional_credentials: bool = True)

Note

The contract is Advertising Billing version 3.0 and carries no beta marker. Two invoice routes the contract lists, GET /invoices and GET /invoices/{invoiceId}, live in ad_api.api.Invoices rather than here, where their subject belongs.

### Endpoint map

:header-rows: 1

Path

Method

Kind

Answer

POST /billing/statuses

list_billing_status

read

200

POST /billing/notifications

list_billing_notifications

read

200

POST /invoiceSummaries/list

invoice_summaries

read

200

POST /billing/paymentMethods/list

get_customer_payment_methods

read

200

POST /billing/paymentAgreements/list

get_payment_agreements

read

200

GET /billing/documents/{documentId}

get_billing_document

read

200

GET /billingProfileAgreementContents/{id}

get_billing_profile_agreement_content

read

200

POST /billingProfiles/list

list_billing_profiles

read

200

POST /billingProfileUsages/list

list_billing_profile_usages

read

200

GET /billingStatements/{requestId}

get_billing_statement

read

200

POST /billing/invoices/pay

pay_invoices

write

200

POST /billing/paymentAgreements

create_payment_agreements

write

200

POST /billing/paymentProfiles

create_payment_profiles

write

207

POST /billingProfiles

create_billing_profiles

write

207

PUT /billingProfiles

update_billing_profiles

write

207

POST /billingProfileUsages

apply_billing_profile

write

207

POST /billingStatements

create_billing_statement

write

207

Five of the writes answer 207, a multi-status: the answer reports per item rather than as a whole.

### Two invoice routes, two date formats

Both read invoices, and they do not agree on much.

:header-rows: 1

Invoices.list_invoices

Billing.invoice_summaries

Dates as

"20260902"

"2026-09-02"

Fields as

plain strings

{"code": ..., "value": ...} pairs

Payload shape

{"status": "success", "payload": {...}}

{"invoiceSummaries": [...]}

Filtering

by the caller

on the service

Page control

count and cursor

maxResults and nextToken

Reading Invoices needs the extra layer: the invoices sit at payload["payload"]["invoiceSummaries"], and payload["invoiceSummaries"] is None without complaint.

### Marketplace accounts are turned away

The billing profile routes refuse regional seller accounts:

POST /billingProfiles/list
400 The API doesnot support marketplace accounts

POST /billingProfileUsages/list
400 Bad request received: only Global, Manager and Sponsored Ads
    marketplace accounts are supported

That comes from the service, not the package. A Global, Manager or Sponsored Ads account reaches them.

### The required parameters the contract calls optional

Three routes name a query parameter without marking it required, and then refuse the call when it is missing.

:header-rows: 1

Route

Parameter

Accepted values

get_customer_payment_methods

criteriaType

PAY_NOW, AUTO_PAY

get_payment_agreements

agreementType

PAY_NOW, AUTO_PAY

get_billing_document

docType

the kind of document

Each answers 400 naming the member it wanted.

### Sorting invoice summaries

invoice_summaries accepts sort with an attribute and a direction. The contract types attribute as a plain string with no list of values, and only two are accepted:

  • invoiceIssuedDate

  • invoiceDueDate

Anything else answers 400 Invalid input because of error(s): [sort:attribute field is invalid]. Those two are the names the answer uses, not the ones the filters use: invoiceDate, issuedDate, dueDate, amountDue and status are all refused.

### pay_invoices does not name invoices

Its body carries no invoice ids. It names targetCountryCodes and settles the open balance there through a payment agreement:

:header-rows: 1

Field

Type

Meaning

idempotenceId

string

Required, and the only required member. The same id twice counts as one request, so a retry after a timeout does not charge twice.

mode

string

EXECUTE charges. PREVIEW simulates and moves nothing.

paymentAgreementId

string

The agreement to charge. Omit it and the latest agreement is used.

reasonLocale

string

Locale of the reason text, such as es_ES.

targetCountryCodes

array

The countries whose balance is collected.

The answer carries success and failure, both always present, so a 200 alone does not mean the money moved.

### The writes that were not exercised

Five routes change how an account is charged, and none was called:

  • pay_invoices — no ISSUED invoice existed to settle, and EXECUTE moves money

  • create_payment_agreements — creates a real agreement

  • create_payment_profiles — a profile decides where money is taken from

  • create_billing_profiles and update_billing_profiles — change who gets invoiced

  • apply_billing_profile — relinks countries to a profile

  • create_billing_statement — starts a job

Four of them also have entries the contract never describes: billingProfiles, billingProfileUsages and paymentProfiles are named as lists, and what an entry holds is not written down. Read one back from the matching list route before building a body.

### Example: the invoices of a period

from ad_api.api import Billing

client = Billing(account='my_account', debug=False)

res = client.invoice_summaries(body={
    "invoiceIssuedDateRangeFilter": {
        "startDate": "2026-09-01",
        "endDate": "2026-10-31",
    },
    "statusValueFilter": {"include": ["PAID_IN_FULL"]},
    "sort": {"attribute": "invoiceIssuedDate", "direction": "DESC"},
    "maxResults": 50,
})

for row in res.payload["invoiceSummaries"]:
    print(row["id"],
          row["invoiceIssuedDate"],
          row["status"]["code"],
          row["amountDue"]["value"],
          row["amountDue"]["currencyCode"])

### Example: what the account pays with

from ad_api.api import Billing

client = Billing(account='my_account', debug=False)

# criteriaType is required even though the contract lists it as optional
methods = client.get_customer_payment_methods(criteriaType="AUTO_PAY")
for card in methods.payload["creditCardPaymentMethods"]:
    print(card["brand"], card["tail"], card["expiryDetails"])

agreements = client.get_payment_agreements(agreementType="AUTO_PAY")
for agreement in agreements.payload["paymentAgreements"]:
    for method in agreement["paymentProfile"]["paymentMethods"]:
        print(method.get("priority"), method.get("type"), method.get("brand"))

### Example: a statement request

from ad_api.api import Billing

client = Billing(account='my_account', debug=False)

res = client.create_billing_statement(body={
    "startDate": "2026-09-01",
    "endDate": "2026-09-30",
    "locale": "es_ES",
    "countryCodes": ["ES"],
    "format": "CSV",
})

# answers 207 and a request id
request_id = res.payload.get("requestId")
print(client.get_billing_statement(request_id).payload)
list_billing_status(**kwargs) → ApiResponse

Get the billing status for a list of advertising accounts.

Request Body
Bulk Get Billing Statuses Request Body {
The properties needed to get the billing statuses for a set of advertisers.
advertiserMarketplaces* (array) minItems: 0 maxItems: 100 [
advertiserMarketplace {
marketplaceId* (string)
advertiserId* (string)
}
]
locale (string) Locale. Enum: [‘ar_AE’, ‘cs_CZ’, ‘de_DE’, ‘en_AU’, ‘en_CA’, ‘en_GB’, ‘en_IN’, ‘en_SG’, ‘es_ES’, ‘es_MX’, ‘fr_CA’, ‘fr_FR’, ‘he_IL’, ‘hi_IN’, ‘it_IT’, ‘ja_JP’, ‘ko_KR’, ‘nl_NL’, ‘pl_PL’, ‘pt_BR’, ‘sv_SE’, ‘ta_IN’, ‘tr_TR’, ‘zh_CN’, ‘zh_TW’]
}
Returns

ApiResponse

list_billing_notifications(**kwargs) → ApiResponse

Get the billing notifications for a list advertising accounts.

Request Body
Bulk Get Billing Notifications Request Body {
The properties needed to get the billing notifications for a set of advertisers.
advertiserMarketplaces* (array) minItems: 0 maxItems: 100 [
advertiserMarketplace {
marketplaceId* (string)
advertiserId* (string)
}
]
locale (string) Locale. Enum: [‘ar_AE’, ‘cs_CZ’, ‘de_DE’, ‘en_AU’, ‘en_CA’, ‘en_GB’, ‘en_IN’, ‘en_SG’, ‘es_ES’, ‘es_MX’, ‘fr_CA’, ‘fr_FR’, ‘he_IL’, ‘hi_IN’, ‘it_IT’, ‘ja_JP’, ‘ko_KR’, ‘nl_NL’, ‘pl_PL’, ‘pt_BR’, ‘sv_SE’, ‘ta_IN’, ‘tr_TR’, ‘zh_CN’, ‘zh_TW’]
}
Returns

ApiResponse

get_customer_payment_methods(**kwargs) → ApiResponse

Lists the ways this account can pay.

Query

  • criteriaType (string): required. PAY_NOW or AUTO_PAY. The service answers 400 Value null at 'criteriaType' failed to satisfy constraint when it is missing. It does not go in the body; this route takes no body.

Returns

ApiResponse carrying five lists, always the same five, some empty:

  • creditCardPaymentMethods

  • externalDeductFromPaymentPaymentMethods

  • externalPayByInvoicePaymentMethods

  • payByInvoicePaymentMethods

  • sellerPayablePaymentMethods

A card entry carries brand, tail (the last four digits), expiryDetails with month and year, eligibleCountries and an instrumentId that identifies the instrument for later calls. Treat the instrumentId as a credential.

pay_invoices(**kwargs) → ApiResponse

Collects the outstanding balance for one or more countries.

This does not name invoices. The body carries no invoice ids: it names the countries whose debt is collected, and the service settles whatever is open there through a payment agreement. To read which invoices exist, use Invoices.list_invoices.

Warning

Written from the contract. No live call was possible: the account held no ISSUED invoice, and EXECUTE moves money.

Request Body (required)

  • idempotenceId (string): required, and the only required member. Two requests carrying the same id are treated as one, so a retry after a timeout does not charge twice.

  • mode (string): EXECUTE charges, PREVIEW simulates and moves nothing. Use PREVIEW to check a body before committing to it.

  • paymentAgreementId (string): the agreement to charge, whose payment profile decides the method. Omit it and the advertiser’s latest agreement is used.

  • reasonLocale (string): the locale of the reason text, such as es_ES.

  • targetCountryCodes (array): the countries whose balance is collected. This is what selects the debt.

Returns

ApiResponse carrying success and failure, both always present. An empty failure means every collection went through. A 200 does not by itself mean the money moved: read failure.

get_payment_agreements(**kwargs) → ApiResponse

Lists the payment agreements this account holds.

Query

  • agreementType (string): required. AUTO_PAY or PAY_NOW. The service answers 400 Value null at 'agreementType' failed to satisfy constraint when it is missing. It does not go in the body; this route takes no body.

Returns

ApiResponse with paymentAgreements, a list. An account that pays automatically holds AUTO_PAY agreements and answers an empty list for PAY_NOW, and the reverse, so an empty answer here means the account holds none of that type rather than that the call failed.

Each agreement carries a paymentAgreementId and a paymentProfile whose paymentMethods are ordered by priority, starting at 0. The lowest priority is tried first and the next covers if it cannot be charged.

create_payment_agreements(**kwargs) → ApiResponse

Creates a payment agreement, which decides how an account gets charged.

Warning

Written from the contract, and the contract describes this route thinly: it names the media type and nothing else. No body is documented here because none is documented there, and the call was not made because a payment agreement is not something to create by way of a test.

What the route takes can be inferred from get_payment_agreements, which returns the shape it produces: an agreement carries a paymentProfile whose paymentMethods are ordered by priority. Building one means naming those methods.

Read the live schema before using this. Until then, treat the body as unknown rather than copying a guess from here.

Returns

ApiResponse with the created agreement, in the shape get_payment_agreements lists.

invoice_summaries(**kwargs) → ApiResponse

Lists invoice summaries with filters, sorting and paging.

This is the route to reach for when the question is “which invoices fall in this period”. Invoices.list_invoices returns a flat page and leaves the filtering to the caller; this one filters on the service, by issued date, due date, status, country, invoice number and payment method.

Note the date format. Here it is ISO-8601 with the date alone, "2026-09-01". Invoices.list_invoices answers dates as "20260902". The two shapes are not interchangeable.

Request Body (optional)

Every member is optional. An empty object returns the first page.

  • invoiceIssuedDateRangeFilter (object): startDate and endDate, both inclusive, both "YYYY-MM-DD".

  • invoiceDueDateRangeFilter (object): same shape, for the due date.

  • statusValueFilter (object): include, a list of statuses such as PAID_IN_FULL or ACCUMULATING.

  • countryValueFilter (object): include, up to 30 country codes.

  • invoiceNumberFilter (object): include, up to 30 invoice numbers.

  • paymentMethodTypeValueFilter (object): include, up to 10 method types.

  • reserveOrderNumberFilter (object): include, up to 30 reserve order numbers.

  • sort (object): attribute and direction. The only attributes the service accepts are invoiceIssuedDate and invoiceDueDate; anything else answers 400 Invalid input because of error(s): [sort:attribute field is invalid]. Those are the names the answer uses, not the filter names: invoiceDate, issuedDate, dueDate, amountDue and status are all refused.

  • maxResults (integer): page size.

  • nextToken (string): token from a previous answer.

  • aggregation (object): attribute and groupBy, to total rather than list.

The include filters also accept queryTermMatchType, which decides how the term is matched.

Returns

ApiResponse with invoiceSummaries. Each entry is richer than what Invoices.list_invoices returns and shaped differently: dates come as "2026-10-26" rather than "20261026", and most fields are {"code": ..., "value": ...} pairs rather than plain strings. A summary carries id, invoiceIssuedDate, invoiceDueDate, amountDue and remainingAmountDue (each with a currencyCode and a value), status, paymentStatus, country, product, paymentMethodType, invoicingLevel and fxInformation.

list_billing_profiles(**kwargs) → ApiResponse

Lists the billing profiles of the account.

A billing profile decides who gets invoiced and with which payment method, so this is the starting point before reading usages or creating a statement.

Request Body (optional)

  • filters (object): narrow the list.

  • maxResults (integer): page size.

  • nextToken (string): token from a previous answer.

Warning

The service refuses marketplace accounts. Called from a regional seller account it answers 400 The API doesnot support marketplace accounts. It wants a Global, Manager or Sponsored Ads account.

Returns

ApiResponse with the profiles and the token for the next page.

list_billing_profile_usages(**kwargs) → ApiResponse

Lists which billing profile each country uses.

The answer links a country to a billingProfileId. With expandBillingProfile it carries the whole profile rather than the identifier.

Request Body (optional)

  • expandBillingProfile (boolean): return the full profile, not only its id.

  • expandFallbackBillingProfile (boolean): also return the profile that would apply if the main one could not be used.

  • filters (object): narrow by country or profile.

  • maxResults (integer): page size.

  • nextToken (string): token from a previous answer.

Warning

Same account restriction as list_billing_profiles, and the message names what it wants: only Global, Manager and Sponsored Ads marketplace accounts are supported.

Returns

ApiResponse with one entry per country and profile pairing.

get_billing_document(documentId, **kwargs) → ApiResponse

Reads one billing document.

Path

  • documentId (string): required.

Query

  • docType (string): required in practice, though the contract lists it as a plain parameter. Without it the service answers 400 Value null at 'docType' failed to satisfy constraint.

Returns

ApiResponse with the document.

get_billing_profile_agreement_content(billingProfileAgreementContentId, **kwargs) → ApiResponse

Reads the agreement text attached to a billing profile.

Path

  • billingProfileAgreementContentId (string): required.

Query

  • languageOfPreference (string): the language the text comes back in.

Returns

ApiResponse with the agreement content.

get_billing_statement(billingStatementRequestId, **kwargs) → ApiResponse

Reports on a billing statement request.

The identifier comes from the route that creates the statement request, and this reads its progress or its result.

Note

The contract answers this read with vnd.createbillingstatementsrequest.v1, the same media type the creation route uses. That is what it declares, odd as the name is.

Path

  • billingStatementRequestId (string): required. Three names are in play for this one value: the contract calls it billingStatementRequestId, the method takes billingStatementRequestId, and a rejected call comes back naming billingStatementId.

The error for a malformed value also mentions a request parameter the contract does not list.

Returns

ApiResponse with the state of that request.

create_billing_statement(**kwargs) → ApiResponse

Asks the service to generate a billing statement for a period.

The work is asynchronous. This answers a requestId, and get_billing_statement reads the state of that request.

Request Body (required)

  • startDate (string): required. The first day of the period.

  • endDate (string): required. The last day of the period.

  • locale (string): required. The language the statement comes back in.

  • countryCodes (array): the countries to cover.

  • format (string): CSV is the only value the contract lists.

Returns

ApiResponse with the request identifier. The contract answers 207, a multi-status, not 200.

apply_billing_profile(**kwargs) → ApiResponse

Links one or more countries to a billing profile.

The service calls this applying a profile: after it, the countries named charge through that profile.

Request Body (required)

  • billingProfileUsages (array): required. One entry per country and profile pairing, which reads back in the same shape list_billing_profile_usages returns.

The contract does not describe the fields inside each entry, so read one back from list_billing_profile_usages before building a body here.

Warning

Not exercised. Applying a profile changes how an account gets charged.

Returns

ApiResponse. The contract answers 207, a multi-status, not 200.

create_billing_profiles(**kwargs) → ApiResponse

Creates one or more billing profiles.

Request Body (required)

  • billingProfiles (array): required, between 0 and 100 entries. Each one describes a profile to create.

The contract names the list and stops there: the fields of an entry are not described. Read one back from list_billing_profiles for the shape, rather than guessing at it.

Warning

Not exercised. Creating a billing profile changes how an account gets invoiced.

Returns

ApiResponse. The contract answers 207, a multi-status, not 200.

update_billing_profiles(**kwargs) → ApiResponse

Updates one or more billing profiles.

Request Body

  • billingProfiles (array): between 0 and 100 entries. Each one names a profile and the fields to change.

The same gap as create_billing_profiles: the contract does not describe the fields inside an entry.

Warning

Not exercised, for the same reason as the create route.

Returns

ApiResponse. The contract answers 207, a multi-status, not 200.

create_payment_profiles(**kwargs) → ApiResponse

Creates one or more payment profiles.

Request Body (required)

  • paymentProfiles (array): required. Each entry describes a profile: which payment methods to use and in what order.

The contract names the list and does not describe its entries. The shape of a payment method reads back from get_payment_agreements, whose agreements carry a paymentProfile holding paymentMethods ordered by priority.

Warning

Not exercised. A payment profile decides where money is taken from.

Returns

ApiResponse. The contract answers 207, a multi-status, not 200.