Google Cloud Which project's quota are my API calls charged against?

Any call we make against a Google API is charged against a project quota. Depending on the API that we’re using, that project quota might limit the frequency of calls, the total number of calls, or even the number of calls per user.

But which project’s quota is it that’s being charged? To find out, we need to distinguish between two classes of APIs:

  1. Resource-oriented APIs are APIs that operate on resources that belong to a Google Cloud project. Examples for such APIs include the Compute Engine API, BigQuery API, or IAM API.

    Although there’s no definite way to find out whether an API is resource-oriented or not, we can get a pretty good clue by looking at the API’s URLs: If the URLs contain a project ID or project number, then odds are that we’re dealing with a resource-oriented API; otherwise, it’s probably a non-resource-oriented API.

  2. Non-resource-oriented APIs are APIs that don’t have any clear association with a Google project.

    Most non-Cloud APIs like Maps fall into this bucket. But there are also a few Cloud APIs like the OS Login API or Resource Manager API that don’t have a clear association with a resource project and are therefore considered non-resource-oriented APIs.

Note that this distinction applies to an entire API, not to individual resources/methods.

Resource project, client project, or user project

Whether an API is resource-oriented or not determines how it charges quotas:

  • The default behavior of resource-oriented APIs is that they charge quota against the resource project. That’s the project that contains the resource which the API call operates on.

    To allow that to happen, we have to enable the respective API in the resource project.

  • For non-resource-oriented APIs, charging a resource project isn’t an option. For those APIs, the default is therefore to charge the client project. That’s the project that contains:

    • the OAuth client ID (if we’re authenticating as a user),
    • the service account (if we’re authenticating a service account), or
    • the API key (if we’re not using an OAuth).

    For that to work, we have to enable the respective API in the client project.

We can override these defaults and instruct the API to charge a user project instead. To do that, we have to add a X-Goog-User-Project header to our HTTP request that contains:

a caller-specified project for quota and billing purposes. The caller must have serviceusage.services.use permission on the project.

Charging gcloud usage

Applied to gcloud, the default quota-charging behavior means that:

  • Running gcloud compute instances list –project my-project is charged against my-project, because the Compute Engine API is a resource-oriented API.
  • Running gcloud projects list is charged against some Google-owned project that contains gcloud’s OAuth Client ID because the Resource Manager API is a non-resource oriented API.

gcloud also provides a –billing-project parameter, which lets us specify a:

… Google Cloud project that will be charged quota for operations performed in gcloud. If you need to operate on one project, but need quota against a different project, you can use this flag to specify the billing project.

That sounds a lot like the definition of the X-Goog-User-Project header. And indeed, that’s exactly what gcloud uses under the hood:

> gcloud projects list --billing-project my-billing-project --log-http
…
==== request start ====
uri: https://cloudresourcemanager.googleapis.com/v1/projects?alt=json&filter=lifecycleState%3AACTIVE&pageSize=500
method: GET
== headers start ==
b'X-Goog-User-Project': b'my-billing-project'      <--- !!
b'accept': b'application/json'
b'accept-encoding': b'gzip, deflate'
b'authorization': --- Token Redacted ---
b'content-length': b'0'
b'user-agent': b'google-cloud-sdk gcloud/…'
== headers end ==
…
Any opinions expressed on this blog are Johannes' own. Refer to the respective vendor’s product documentation for authoritative information.
« Back to home