Invoice

Monthly invoices for a Google Ads account can be retrieved using the InvoiceService.

Prerequisites

  • Have monthly invoicing enabled for the Google Ads account. See the guides on account billing setups and budgets to learn how to manage billing using the Google Ads API.
  • If set, login-customer-id must specify the customer ID of a manager account that is managing the Google Ads account for which you're retrieving invoices. This is labeled as the paying manager in the Google Ads UI.

Retrieving invoices

To retrieve invoices, you need to request the InvoiceService.ListInvoices method setting all the required fields in the ListInvoicesRequest: customer_id, billing_setup, issue_year, and issue_month.

Here is an example:

// Issues the request.
ListInvoicesResponse response =
    invoiceServiceClient.listInvoices(
        String.valueOf(customerId),
        ResourceNames.billingSetup(customerId, billingSetupId),
        String.valueOf(oneMonthAgo.getYear()),
        MonthOfYear.valueOf(oneMonthAgo.getMonth().toString()));
      
ListInvoicesResponse response = invoiceServiceClient.ListInvoices(customerId.ToString(),
    ResourceNames.BillingSetup(customerId, billingSetupId),
    // Year must be 2019 or later.
    lastMonthDateTime.Year.ToString("yyyy"),
    lastMonth);
      
// Issues the request.
$response = $googleAdsClient->getInvoiceServiceClient()->listInvoices(
    ListInvoicesRequest::build(
        $customerId,
        ResourceNames::forBillingSetup($customerId, $billingSetupId),
        // The year needs to be 2019 or later.
        date('Y', $lastMonth),
        MonthOfYear::value(strtoupper(date('F', $lastMonth)))
    )
);
      
# Issues a request to list invoices.
response = client.get_service("InvoiceService").list_invoices(
    customer_id=customer_id,
    billing_setup=client.get_service("GoogleAdsService").billing_setup_path(
        customer_id, billing_setup_id
    ),
    # The year needs to be 2019 or later, per the docs:
    # https://developers.google.com/google-ads/api/docs/billing/invoice?hl=en#retrieving_invoices
    issue_year=str(last_month.year),
    issue_month=last_month.strftime("%B").upper(),
)
      
# Issues a request to list invoices.
response = client.service.invoice.list_invoices(
  customer_id: customer_id,
  billing_setup: client.path.billing_setup(customer_id, billing_setup_id),
  # The year needs to be 2019 or later.
  issue_year: last_month.year.to_s,
  # '%^B' option returns the uppercased full month name (e.g. 'JANUARY').
  issue_month: last_month.strftime("%^B").to_sym,
)
      
# Issue the request.
my $response = $api_client->InvoiceService()->list({
    customerId   => $customer_id,
    billingSetup =>
      Google::Ads::GoogleAds::V19::Utils::ResourceNames::billing_setup(
      ($customer_id, $billing_setup_id)
      ),
    # The year needs to be 2019 or later.
    issueYear  => strftime("%Y", @last_month),
    issueMonth => uc(strftime("%B", @last_month))});
      

The response is a ListInvoicesResponse object that contains the list of matching Invoices, each of which contains a large set of fields such as:

  • IDs: payments_account_id, payments_profile_id.
  • Time: issue_date, due_date, service_date_range.
  • Amounts: subtotal_amount_micros, tax_amount_micros, total_amount_micros.
  • PDF: pdf_url. See downloading an invoice PDF for instructions.
  • History: corrected_invoice, replaced_invoices.

It also contains other specific fields when relevant:

  • Adjustments: adjustments_subtotal_amount_micros, adjustments_tax_amount_micros, adjustments_total_amount_micros.
  • Regulatory costs: regulatory_costs_subtotal_amount_micros, regulatory_costs_tax_amount_micros, regulatory_costs_total_amount_micros.
  • Export charges: export_charge_subtotal_amount_micros, export_charge_tax_amount_micros, export_charge_total_amount_micros.

Getting budget details

An Invoice provides detailed information about related account budgets as a list of AccountBudgetSummary objects in the account_budget_summaries field:

  • IDs: customer, account_budget, purchase_order_number.
  • Time: billable_activity_date_range.
  • Amounts: subtotal_amount_micros, tax_amount_micros, total_amount_micros, invalid_activity_amount_micros, billed_amount_micros, served_amount_micros, overdelivery_amount_micros.

Getting account details

An Invoice provides information about related accounts as a list of AccountSummary objects in the account_summaries field. It includes details about billing corrections, adjustments, export charges, and regulatory costs.

Understanding amounts

All the amounts provided in AccountBudgetSummary, AccountSummary and Invoice objects are attributable during their service periods and are evaluated according to these rules:

AccountBudgetSummary Evaluation rule
served_amount_micros account_budget_served
billed_amount_micros account_budget_billed
overdelivery_amount_micros account_budget_overdelivery
invalid_activity_amount_micros account_budget_invalid_activity
subtotal_amount_micros account_budget_pretax
tax_amount_micros account_budget_tax
total_amount_micros account_budget_pretax+
account_budget_tax
AccountSummary Evaluation rule
billing_correction_subtotal_amount_micros account_billing_correction_pretax
coupon_adjustment_subtotal_amount_micros account_coupon_adjustment_pretax
excess_credit_adjustment_subtotal_amount_micros account_excess_credit_adjustment_pretax
regulatory_costs_subtotal_amount_micros account_regulatory_costs_pretax
export_charge_subtotal_amount_micros account_export_charge_pretax
billing_correction_tax_amount_micros account_billing_correction_tax
coupon_adjustment_tax_amount_micros account_coupon_adjustment_tax
excess_credit_adjustment_tax_amount_micros account_excess_credit_adjustment_tax
regulatory_costs_tax_amount_micros account_regulatory_costs_tax
export_charge_tax_amount_micros account_export_charge_tax
billing_correction_total_amount_micros account_billing_correction_pretax+
account_billing_correction_tax
coupon_adjustment_total_amount_micros account_coupon_adjustment_pretax+
account_coupon_adjustment_tax
excess_credit_adjustment_total_amount_micros account_excess_credit_adjustment_pretax+
account_excess_credit_adjustment_tax
regulatory_costs_total_amount_micros account_regulatory_costs_pretax+
account_regulatory_costs_tax
export_charge_total_amount_micros account_export_charge_pretax+
account_export_charge_tax
subtotal_amount_micros account_pretax
tax_amount_micros account_tax
total_amount_micros account_pretax+
account_tax
Invoice Evaluation rule
adjustments_subtotal_amount_micros i=1naccount_billing_correction_pretaxi+
i=1naccount_coupon_adjustment_pretaxi+
i=1naccount_excess_credit_adjustment_pretaxi
regulatory_costs_subtotal_amount_micros i=1naccount_regulatory_costs_pretaxi
export_charge_subtotal_amount_micros i=1naccount_export_charge_pretaxi
adjustments_tax_amount_micros i=1naccount_billing_correction_taxi+
i=1naccount_coupon_adjustment_taxi+
i=1naccount_excess_credit_adjustment_taxi
regulatory_costs_tax_amount_micros i=1naccount_regulatory_costs_taxi
export_charge_tax_amount_micros i=1naccount_export_charge_taxi
adjustments_total_amount_micros adjustments_pretax+
adjustments_tax
regulatory_costs_total_amount_micros regulatory_costs_pretax+
regulatory_costs_tax
export_charge_total_amount_micros export_charge_pretax+
export_charge_tax
subtotal_amount_micros adjustments_pretax+
i=1naccount_budget_pretaxi
tax_amount_micros adjustments_tax+
regulatory_costs_tax+
export_charge_tax+
i=1naccount_budget_taxi
total_amount_micros pretax+
regulatory_costs_pretax+
export_charge_pretax+
tax

Here is an example of how the retrieved invoices can be iterated on:

// Iterates over all invoices retrieved and prints their information.
for (Invoice invoice : response.getInvoicesList()) {
  System.out.printf(
      "- Found the invoice '%s':\n"
          + "  ID (also known as Invoice Number): '%s'\n"
          + "  Type: %s\n"
          + "  Billing setup ID: '%s'\n"
          + "  Payments account ID (also known as Billing Account Number): '%s'\n"
          + "  Payments profile ID (also known as Billing ID): '%s'\n"
          + "  Issue date (also known as Invoice Date): %s\n"
          + "  Due date: %s\n"
          + "  Currency code: %s\n"
          + "  Service date range (inclusive): from %s to %s\n"
          + "  Adjustments: subtotal '%.2f', tax '%.2f', total '%.2f'\n"
          + "  Regulatory costs: subtotal '%.2f', tax '%.2f', total '%.2f'\n"
          + "  Replaced invoices: '%s'\n"
          + "  Amounts: subtotal '%.2f', tax '%.2f', total '%.2f'\n"
          + "  Corrected invoice: '%s'\n"
          + "  PDF URL: '%s'\n"
          + "  Account budgets: ",
      invoice.getResourceName(),
      invoice.getId(),
      invoice.getType(),
      invoice.getBillingSetup(),
      invoice.getPaymentsAccountId(),
      invoice.getPaymentsProfileId(),
      invoice.getIssueDate(),
      invoice.getDueDate(),
      invoice.getCurrencyCode(),
      invoice.getServiceDateRange().getStartDate(),
      invoice.getServiceDateRange().getEndDate(),
      convertMicrosToCurrency(invoice.getAdjustmentsSubtotalAmountMicros()),
      convertMicrosToCurrency(invoice.getAdjustmentsTaxAmountMicros()),
      convertMicrosToCurrency(invoice.getAdjustmentsTotalAmountMicros()),
      convertMicrosToCurrency(invoice.getRegulatoryCostsSubtotalAmountMicros()),
      convertMicrosToCurrency(invoice.getRegulatoryCostsTaxAmountMicros()),
      convertMicrosToCurrency(invoice.getRegulatoryCostsTotalAmountMicros()),
      invoice.getReplacedInvoicesList(),
      convertMicrosToCurrency(invoice.getSubtotalAmountMicros()),
      convertMicrosToCurrency(invoice.getTaxAmountMicros()),
      convertMicrosToCurrency(invoice.getTotalAmountMicros()),
      invoice.getCorrectedInvoice(),
      invoice.getPdfUrl());
  for (AccountBudgetSummary accountBudgetSummary : invoice.getAccountBudgetSummariesList()) {
    System.out.printf(
        "  - Account budget '%s':\n"
            + "      Name (also known as Account Budget): '%s'\n"
            + "      Customer (also known as Account ID): '%s'\n"
            + "      Customer descriptive name (also known as Account): '%s'\n"
            + "      Purchase order number (also known as Purchase Order): '%s'\n"
            + "      Billing activity date range (inclusive): from %s to %s\n"
            + "      Amounts: subtotal '%.2f', tax '%.2f', total '%.2f'\n",
        accountBudgetSummary.getAccountBudget(),
        accountBudgetSummary.getAccountBudgetName(),
        accountBudgetSummary.getCustomer(),
        accountBudgetSummary.getCustomerDescriptiveName(),
        accountBudgetSummary.getPurchaseOrderNumber(),
        accountBudgetSummary.getBillableActivityDateRange().getStartDate(),
        accountBudgetSummary.getBillableActivityDateRange().getEndDate(),
        convertMicrosToCurrency(accountBudgetSummary.getSubtotalAmountMicros()),
        convertMicrosToCurrency(accountBudgetSummary.getTaxAmountMicros()),
        convertMicrosToCurrency(accountBudgetSummary.getTotalAmountMicros()));
  }
}
      
// information.
foreach (Invoice invoice in response.Invoices)
{
    Console.WriteLine(
        "- Found the invoice '{0}':\n" +
        "  ID (also known as Invoice Number): '{1}'\n" +
        "  Type: {2}\n" +
        "  Billing setup ID: '{3}'\n" +
        "  Payments account ID (also known as Billing Account Number): '{4}'\n" +
        "  Payments profile ID (also known as Billing ID): '{5}'\n" +
        "  Issue date (also known as Invoice Date): {6}\n" +
        "  Due date: {7}\n" +
        "  Currency code: {8}\n" +
        "  Service date range (inclusive): from {9} to {10}\n" +
        "  Adjustments: subtotal '{11}', tax '{12}', total '{13}'\n" +
        "  Regulatory costs: subtotal '{14}', tax '{15}', total '{16}'\n" +
        "  Replaced invoices: '{17}'\n" +
        "  Amounts: subtotal '{18}', tax '{19}', total '{20}'\n" +
        "  Corrected invoice: '{21}'\n" +
        "  PDF URL: '{22}'\n" +
        "  Account budgets:\n",
        invoice.ResourceName,
        invoice.Id,
        invoice.Type.ToString(),
        invoice.BillingSetup,
        invoice.PaymentsAccountId,
        invoice.PaymentsProfileId,
        invoice.IssueDate,
        invoice.DueDate,
        invoice.CurrencyCode,
        invoice.ServiceDateRange.StartDate,
        invoice.ServiceDateRange.EndDate,
        FormatMicros(invoice.AdjustmentsSubtotalAmountMicros),
        FormatMicros(invoice.AdjustmentsTaxAmountMicros),
        FormatMicros(invoice.AdjustmentsTotalAmountMicros),
        FormatMicros(invoice.RegulatoryCostsSubtotalAmountMicros),
        FormatMicros(invoice.RegulatoryCostsTaxAmountMicros),
        FormatMicros(invoice.RegulatoryCostsTotalAmountMicros),
        invoice.ReplacedInvoices.Count > 0
            ? string.Join("', '", invoice.ReplacedInvoices)
            : "none",
        FormatMicros(invoice.SubtotalAmountMicros),
        FormatMicros(invoice.TaxAmountMicros),
        FormatMicros(invoice.TotalAmountMicros),
        string.IsNullOrEmpty(invoice.CorrectedInvoice)
            ? invoice.CorrectedInvoice
            : "none",
        invoice.PdfUrl);
    foreach (AccountBudgetSummary accountBudgetSummary in
        invoice.AccountBudgetSummaries)
    {
        Console.WriteLine(
            "\t- Account budget '{0}':\n" +
            "\t  Name (also known as Account Budget): '{1}'\n" +
            "\t  Customer (also known as Account ID): '{2}'\n" +
            "\t  Customer descriptive name (also known as Account): '{3}'\n" +
            "\t  Purchase order number (also known as Purchase Order): '{4}'\n" +
            "\t  Billing activity date range (inclusive): from {5} to {6}\n" +
            "\t  Amounts: subtotal '{7}', tax '{8}', total '{9}'\n",
            accountBudgetSummary.AccountBudget,
            accountBudgetSummary.AccountBudgetName ?? "none",
            accountBudgetSummary.Customer,
            accountBudgetSummary.CustomerDescriptiveName ?? "none",
            accountBudgetSummary.PurchaseOrderNumber ?? "none",
            accountBudgetSummary.BillableActivityDateRange.StartDate,
            accountBudgetSummary.BillableActivityDateRange.EndDate,
            FormatMicros(accountBudgetSummary.SubtotalAmountMicros),
            FormatMicros(accountBudgetSummary.TaxAmountMicros),
            FormatMicros(accountBudgetSummary.TotalAmountMicros));
    }
}
      
// Iterates over all invoices retrieved and prints their information.
foreach ($response->getInvoices() as $invoice) {
    /** @var Invoice $invoice */
    printf(
        "- Found the invoice '%s':" . PHP_EOL .
        "  ID (also known as Invoice Number): '%s'" . PHP_EOL .
        "  Type: %s" . PHP_EOL .
        "  Billing setup ID: '%s'" . PHP_EOL .
        "  Payments account ID (also known as Billing Account Number): '%s'" . PHP_EOL .
        "  Payments profile ID (also known as Billing ID): '%s'" . PHP_EOL .
        "  Issue date (also known as Invoice Date): %s" . PHP_EOL .
        "  Due date: %s" . PHP_EOL .
        "  Currency code: %s" . PHP_EOL .
        "  Service date range (inclusive): from %s to %s" . PHP_EOL .
        "  Adjustments: subtotal '%.2f', tax '%.2f', total '%.2f'" . PHP_EOL .
        "  Regulatory costs: subtotal '%.2f', tax '%.2f', total '%.2f'" . PHP_EOL .
        "  Replaced invoices: '%s'" . PHP_EOL .
        "  Amounts: subtotal '%.2f', tax '%.2f', total '%.2f'" . PHP_EOL .
        "  Corrected invoice: '%s'" . PHP_EOL .
        "  PDF URL: '%s'" . PHP_EOL .
        "  Account budgets:" . PHP_EOL,
        $invoice->getResourceName(),
        $invoice->getId(),
        InvoiceType::name($invoice->getType()),
        $invoice->getBillingSetup(),
        $invoice->getPaymentsAccountId(),
        $invoice->getPaymentsProfileId(),
        $invoice->getIssueDate(),
        $invoice->getDueDate(),
        $invoice->getCurrencyCode(),
        $invoice->getServiceDateRange()->getStartDate(),
        $invoice->getServiceDateRange()->getEndDate(),
        Helper::microToBase($invoice->getAdjustmentsSubtotalAmountMicros()),
        Helper::microToBase($invoice->getAdjustmentsTaxAmountMicros()),
        Helper::microToBase($invoice->getAdjustmentsTotalAmountMicros()),
        Helper::microToBase($invoice->getRegulatoryCostsSubtotalAmountMicros()),
        Helper::microToBase($invoice->getRegulatoryCostsTaxAmountMicros()),
        Helper::microToBase($invoice->getRegulatoryCostsTotalAmountMicros()),
        $invoice->getReplacedInvoices()
            ? implode(
                "', '",
                iterator_to_array($invoice->getReplacedInvoices()->getIterator())
            ) : 'none',
        Helper::microToBase($invoice->getSubtotalAmountMicros()),
        Helper::microToBase($invoice->getTaxAmountMicros()),
        Helper::microToBase($invoice->getTotalAmountMicros()),
        $invoice->getCorrectedInvoice() ?: 'none',
        $invoice->getPdfUrl()
    );
    foreach ($invoice->getAccountBudgetSummaries() as $accountBudgetSummary) {
        /** @var AccountBudgetSummary $accountBudgetSummary */
        printf(
            "  - Account budget '%s':" . PHP_EOL .
            "      Name (also known as Account Budget): '%s'" . PHP_EOL .
            "      Customer (also known as Account ID): '%s'" . PHP_EOL .
            "      Customer descriptive name (also known as Account): '%s'" . PHP_EOL .
            "      Purchase order number (also known as Purchase Order): '%s'" . PHP_EOL .
            "      Billing activity date range (inclusive): from %s to %s" . PHP_EOL .
            "      Amounts: subtotal '%.2f', tax '%.2f', total '%.2f'" . PHP_EOL,
            $accountBudgetSummary->getAccountBudget(),
            $accountBudgetSummary->getAccountBudgetName() ?: 'none',
            $accountBudgetSummary->getCustomer(),
            $accountBudgetSummary->getCustomerDescriptiveName() ?: 'none',
            $accountBudgetSummary->getPurchaseOrderNumber() ?: 'none',
            $accountBudgetSummary->getBillableActivityDateRange()->getStartDate(),
            $accountBudgetSummary->getBillableActivityDateRange()->getEndDate(),
            Helper::microToBase($accountBudgetSummary->getSubtotalAmountMicros()),
            Helper::microToBase($accountBudgetSummary->getTaxAmountMicros()),
            Helper::microToBase($accountBudgetSummary->getTotalAmountMicros())
        );
    }
}
      
    for invoice in response.invoices:
        print(
            f"""
- Found the invoice {invoice.resource_name}
    ID (also known as Invoice Number): '{invoice.id}'
    Type: {invoice.type_}
    Billing setup ID: '{invoice.billing_setup}'
    Payments account ID (also known as Billing Account Number): '{invoice.payments_account_id}'
    Payments profile ID (also known as Billing ID): '{invoice.payments_profile_id}'
    Issue date (also known as Invoice Date): {invoice.issue_date}
    Due date: {invoice.due_date}
    Currency code: {invoice.currency_code}
    Service date range (inclusive): from {invoice.service_date_range.start_date} to {invoice.service_date_range.end_date}
    Adjustments:
        subtotal {_micros_to_currency(invoice.adjustments_subtotal_amount_micros)}
        tax {_micros_to_currency(invoice.adjustments_tax_amount_micros)}
        total {_micros_to_currency(invoice.adjustments_total_amount_micros)}
    Regulatory costs:
        subtotal {_micros_to_currency(invoice.regulatory_costs_subtotal_amount_micros)}
        tax {_micros_to_currency(invoice.regulatory_costs_tax_amount_micros)}
        total {_micros_to_currency(invoice.regulatory_costs_total_amount_micros)}
    Replaced invoices: {invoice.replaced_invoices.join(", ") if invoice.replaced_invoices else "none"}
    Amounts:
        subtotal {_micros_to_currency(invoice.subtotal_amount_micros)}
        tax {_micros_to_currency(invoice.tax_amount_micros)}
        total {_micros_to_currency(invoice.total_amount_micros)}
    Corrected invoice: {invoice.corrected_invoice or "none"}
    PDF URL: {invoice.pdf_url}
    Account budgets:
    """
        )
        for account_budget_summary in invoice.account_budget_summaries:
            print(
                f"""
                  - Account budget '{account_budget_summary.account_budget}':
                      Name (also known as Account Budget): '{account_budget_summary.account_budget_name}'
                      Customer (also known as Account ID): '{account_budget_summary.customer}'
                      Customer descriptive name (also known as Account): '{account_budget_summary.customer_descriptive_name}'
                      Purchase order number (also known as Purchase Order): '{account_budget_summary.purchase_order_number}'
                      Billing activity date range (inclusive):
                        from #{account_budget_summary.billable_activity_date_range.start_date}
                        to #{account_budget_summary.billable_activity_date_range.end_date}
                      Amounts:
                        subtotal '{_micros_to_currency(account_budget_summary.subtotal_amount_micros)}'
                        tax '{_micros_to_currency(account_budget_summary.tax_amount_micros)}'
                        total '{_micros_to_currency(account_budget_summary.total_amount_micros)}'
                """
            )
      
# Iterates over all invoices retrieved and prints their information.
response.invoices.each do |invoice|
  puts <<~OUTPUT
  - Found the invoice '#{invoice.resource_name}'
    ID (also known as Invoice Number): '#{invoice.id}'
    Type: #{invoice.type}
    Billing Setup ID: '#{invoice.billing_setup}'
    Payments account ID (also known as Billing Account Number): '#{invoice.payments_account_id}'
    Payments profile ID (also known as Billing ID): '#{invoice.payments_profile_id}'
    Issue date (also known as Invoice Date): #{invoice.issue_date}
    Due date: #{invoice.due_date}
    Currency code: #{invoice.currency_code}
    Service date range (inclusive):
      from #{invoice.service_date_range.start_date}
      to #{invoice.service_date_range.end_date}
    Adjustments:
      subtotal '#{micro_to_base(invoice.adjustments_subtotal_amount_micros)}'
      tax '#{micro_to_base(invoice.adjustments_tax_amount_micros)}'
      total '#{micro_to_base(invoice.adjustments_total_amount_micros)}'
    Regulatory costs:
      subtotal '#{micro_to_base(invoice.regulatory_costs_subtotal_amount_micros)}'
      tax '#{micro_to_base(invoice.regulatory_costs_tax_amount_micros)}'
      total '#{micro_to_base(invoice.regulatory_costs_total_amount_micros)}'
    Replaced invoices: '#{invoice.replaced_invoices ? invoice.replaced_invoices.join(", ") : 'none'}'
    Amounts:
      subtotal '#{micro_to_base(invoice.subtotal_amount_micros)}'
      tax '#{micro_to_base(invoice.tax_amount_micros)}'
      total '#{micro_to_base(invoice.total_amount_micros)}'
    Corrected invoice: '#{invoice.corrected_invoices ? invoice.corrected_invoices : 'none'}'
    PDF URL: '#{invoice.pdf_url}'
    Account budgets:
  OUTPUT
  invoice.account_budget_summaries.each do |account_budget_summary|
    puts <<~OUTPUT
    \tAccount budget '#{account_budget_summary.account_budget}':
    \t  Name (also known as Account Budget): '#{account_budget_summary.account_budget_name}'
    \t  Customer (also known as Account ID): '#{account_budget_summary.customer}'
    \t  Customer descriptive name (also known as Account): '#{account_budget_summary.customer_descriptive_name}'
    \t  Purchase order number (also known as Purchase Order): '#{account_budget_summary.purchase_order_number}'
    \t  Billing activity date range (inclusive):
    \t    from #{account_budget_summary.billable_activity_date_range.start_date}
    \t    to #{account_budget_summary.billable_activity_date_range.end_date}
    \t  Amounts:
    \t    subtotal '#{micro_to_base(account_budget_summary.subtotal_amount_micros)}'
    \t    tax '#{micro_to_base(account_budget_summary.tax_amount_micros)}'
    \t    total '#{micro_to_base(account_budget_summary.total_amount_micros)}'
    OUTPUT
  end
end
      
# Iterate over all invoices retrieved and print their information.
foreach my $invoice (@$response) {
  printf "- Found the invoice '%s':\n" .
    "  ID (also known as Invoice Number): '%s'\n" .
    "  Type: %s\n" .
    "  Billing setup ID: '%s'\n" .
    "  Payments account ID (also known as Billing Account Number): '%s'\n" .
    "  Payments profile ID (also known as Billing ID): '%s'\n" .
    "  Issue date (also known as Invoice Date): %s\n" .
    "  Due date: %s\n" .
    "  Currency code: %s\n" .
    "  Service date range (inclusive): from %s to %s\n" .
    "  Adjustments: subtotal '%.2f', tax '%.2f', total '%.2f'\n" .
    "  Regulatory costs: subtotal '%.2f', tax '%.2f', total '%.2f'\n" .
    "  Replaced invoices: '%s'\n" .
    "  Amounts: subtotal '%.2f', tax '%.2f', total '%.2f'\n" .
    "  Corrected invoice: '%s'\n" .
    "  PDF URL: '%s'\n" .
    "  Account budgets:\n",
    $invoice->{resourceName},
    $invoice->{id},
    $invoice->{type},
    $invoice->{billingSetup},
    $invoice->{paymentsAccountId},
    $invoice->{paymentsProfileId},
    $invoice->{issueDate},
    $invoice->{dueDate},
    $invoice->{currencyCode},
    $invoice->{serviceDateRange}{startDate},
    $invoice->{serviceDateRange}{endDate},
    micro_to_base($invoice->{adjustmentsSubtotalAmountMicros}),
    micro_to_base($invoice->{adjustmentsTaxAmountMicros}),
    micro_to_base($invoice->{adjustmentsTotalAmountMicros}),
    micro_to_base($invoice->{regulatoryCostsSubtotalAmountMicros}),
    micro_to_base($invoice->{regulatoryCostsTaxAmountMicros}),
    micro_to_base($invoice->{regulatoryCostsTotalAmountMicros}),
    $invoice->{replacedInvoices}
    ? join(',', @{$invoice->{replacedInvoices}})
    : "none",
    micro_to_base($invoice->{subtotalAmountMicros}),
    micro_to_base($invoice->{taxAmountMicros}),
    micro_to_base($invoice->{totalAmountMicros}),
    $invoice->{correctedInvoice} ? $invoice->{correctedInvoice} : "none",
    $invoice->{pdfUrl};

  foreach my $account_budget_summary (@{$invoice->{accountBudgetSummaries}}) {
    printf "  - Account budget '%s':\n" .
      "      Name (also known as Account Budget): '%s'\n" .
      "      Customer (also known as Account ID): '%s'\n" .
      "      Customer descriptive name (also known as Account): '%s'\n" .
      "      Purchase order number (also known as Purchase Order): '%s'\n" .
      "      Billing activity date range (inclusive): from %s to %s\n" .
      "      Amounts: subtotal '%.2f', tax '%.2f', total '%.2f'\n",
      $account_budget_summary->{accountBudget},
      $account_budget_summary->{accountBudgetName}
      ? $account_budget_summary->{accountBudgetName}
      : "none",
      $account_budget_summary->{customer},
      $account_budget_summary->{customerDescriptiveName}
      ? $account_budget_summary->{customerDescriptiveName}
      : "none",
      $account_budget_summary->{purchaseOrderNumber}
      ? $account_budget_summary->{purchaseOrderNumber}
      : "none",
      $account_budget_summary->{billableActivityDateRange}{startDate},
      $account_budget_summary->{billableActivityDateRange}{endDate},
      $account_budget_summary->{subtotalAmountMicros},
      $account_budget_summary->{taxAmountMicros},
      $account_budget_summary->{totalAmountMicros};
  }
}
      

Downloading an invoice PDF

Any invoice can be downloaded as a PDF file. Once you have retrieved the Invoice, you need to send an HTTP request for the URL that is stored in its pdf_url field. This request must be authenticated using the same Google account used to retrieve the invoice; that is, you need to specify an OAuth access token generated using the Google account in the Authorization: Bearer request header:

curl --request GET \
     --header "Authorization: Bearer access token" \
     Invoice.pdf_url > filename.pdf

The result is an invoice PDF content stored in the file filename.pdf.

Common error codes

Scenario Error Code
Missing or empty billing setup, issue year, or issue month. RequestError.REQUIRED_FIELD_MISSING
Can't parse given billing setup, issue year, or issue month. FieldError.INVALID_VALUE
Request is for invoices issued before January 1, 2019. InvoiceError.YEAR_MONTH_TOO_OLD
Request is for a customer who doesn't receive invoices. InvoiceError.NOT_INVOICED_CUSTOMER
User doesn't have permission to view invoices of the billing setup. AuthorizationError.ACTION_NOT_PERMITTED