The **Android Developer Console API** is a RESTful service that lets verified
developers automate **Android developer verification** workflows in the
**Android Developer Console**, including retrieving developer accounts, checking
key eligibility requirements, registering Android package names, registering app
signing keys, and verifying key ownership.

> [!NOTE]
> **Note:** For step-by-step setup instructions, including enabling the API in Google Cloud Console, configuring OAuth 2.0 Web Server credentials, and integrating with your build pipeline, see [Register package names with the Android Developer
> Console API](https://developer.android.com/developer-verification/guides/developer-console-api).

## Overview, use cases, and implementation context

### Key use cases and features

- **Automated CI/CD package name registration:** Register dozens or hundreds of Android package names programmatically (`CreateAndroidPackage`).
- **Pre-flight historical key policy inspection:** Programmatically inspect whether Google has previously observed a package name in the ecosystem and whether registering a specific signing certificate requires key ownership verification (`GetAndroidPackageRegistrationPolicy`).
- **Automated app signing key registration and ownership verification:** Register public signing certificate SHA-256 fingerprints (`CreateAndroidPackageKey`), retrieve unique verification challenge tokens (`verificationToken`), and automate proof of private key possession using single-request or resumable signed APK uploads (`VerifyAndroidPackageKeyOwnership`).
- **Programmatic justification submission:** Submit ownership justifications (`JustifyAndroidPackageKeyRegistration`).
- **Status monitoring:** Monitor registration status across developer accounts, package names, and app signing keys (`GetDeveloperAccount`, `ListDeveloperAccounts`, `GetAndroidPackage`, `ListAndroidPackages`, `GetAndroidPackageKey`, `ListAndroidPackageKeys`).

### End-to-end implementation workflow

1. **Verify developer identity once in the UI:** Complete developer identity verification (`INDIVIDUAL` or `ORGANIZATION`) in the [Android Developer
   Console](https://developer.android.com/developer-verification/guides/android-developer-console) so `verificationState` is `VERIFIED`.
2. **Enable the API and authenticate:** Enable `androiddeveloperconsole.googleapis.com` in your Google Cloud project and obtain a user-delegated OAuth 2.0 Bearer access token with scope `https://www.googleapis.com/auth/androiddeveloperconsole`.
3. **Discover your developer account resource name:** Call `GET
   /v1/developerAccounts` (`ListDeveloperAccounts`) to retrieve `developerAccounts/{developer_account}` and verify `verificationState` is `VERIFIED`.
4. **Check registration policy for the package name:** Call `GET
   /v1/developerAccounts/{id}/androidPackages/{pkg}/registrationPolicy` (`GetAndroidPackageRegistrationPolicy`) to inspect `keySelectionStrategy` (`SELECT_KEY_FROM_LIST` or `USE_ANY_KEY`) and any known historical signing keys (`knownKeys`).
5. **Create the Android package resource:** Call `POST
   /v1/developerAccounts/{id}/androidPackages?androidPackageId={pkg}` (`CreateAndroidPackage`) with body `{"name": ""}` (creates resource in `DRAFT` state).
6. **Register your app signing key fingerprint:** Call `POST
   /v1/developerAccounts/{id}/androidPackages/{pkg}/keys` (`CreateAndroidPackageKey`) with JSON body `{"certificateFingerprintSha256":
   "..."}`. Inspect the returned state:
   - `DRAFT`: Proof of private key ownership is required, and the response includes a unique `verificationToken` for Step 7.
   - `IN_REVIEW`: Proof of ownership and justification are skipped automatically (for example, when registering a new package name that has never been seen on Android, or when you have already verified ownership of this signing key for another package name in the same `DeveloperAccount`). Skip Step 7 and the justification call in Step 8, and proceed directly to polling `GetAndroidPackage` and `GetAndroidPackageKey`.
7. **Build and upload the verification APK (if state is `DRAFT`):** Embed the returned `verificationToken` string into `assets/adi-registration.properties` inside a minimal APK matching `packageName`, sign it with your private app signing key, and upload it using `POST
   /upload/v1/developerAccounts/{id}/androidPackages/{pkg}/keys/{sha256}:verify` (`VerifyAndroidPackageKeyOwnership`).
8. **Submit justification (if required) and poll registration status:** If the key is in `OWNERSHIP_VERIFIED` state and `registrationJustificationRequired` is `true`, call `POST
   /v1/developerAccounts/{id}/androidPackages/{pkg}/keys/{sha256}:justifyAndroidPackageKeyRegistration` (`JustifyAndroidPackageKeyRegistration`). Poll `GetAndroidPackage` and `GetAndroidPackageKey` until `state` reaches `REGISTERED`.

### Local CLI commands for preparing key fingerprints and verification APKs

- **Extract SHA-256 certificate fingerprint from a keystore (`keytool`):**

      keytool -list -v -keystore release-key.jks -alias my-key-alias

- **Verify SHA-256 signing certificate digest on a built APK (`apksigner`):**

      apksigner verify --print-certs app-release.apk

- **Inspect APK package name and embedded token file before upload (`aapt2`
  and `unzip`):**

      aapt2 dump badging app-release.apk | head -n 1
      unzip -p app-release.apk assets/adi-registration.properties

### Android Developer Console UI and API capabilities

| Task | Android Developer Console Web UI (`android.google.com/developerconsole`) | Android Developer Console API |
|---|---|---|
| Developer identity verification (KYC/KYB) and fee payment | Supported (required one-time prerequisite) | Not supported using the API (read-only status check using `GetDeveloperAccount` and `ListDeveloperAccounts`) |
| View linked developer accounts | Account switcher in console header | `GET /v1/developerAccounts` (`ListDeveloperAccounts`) |
| Inspect historical signing keys and policy for a package name | Displayed during "Register package name" wizard | `GET /v1/.../registrationPolicy` (`GetAndroidPackageRegistrationPolicy`) |
| Register a new Android package name | **Package names** \> **Register package name** | `POST /v1/{parent}/androidPackages?androidPackageId=...` (`CreateAndroidPackage`) |
| View or list registered and draft package names | **Package names** dashboard table | `GET /v1/{name}` (`GetAndroidPackage`), `GET /v1/{parent}/androidPackages` (`ListAndroidPackages`) |
| Add an app signing key and generate challenge token | Package detail \> **Add signing key** | `POST /v1/{parent}/keys` (`CreateAndroidPackageKey`) |
| Prove private key ownership (`adi-registration.properties`) | Upload signed snippet APK in console UI | `POST /upload/v1/{name}:verify` (`VerifyAndroidPackageKeyOwnership`) |
| Submit justification when key requires manual review | Text prompt during key registration workflow | `POST /v1/{name}:justifyAndroidPackageKeyRegistration` (`JustifyAndroidPackageKeyRegistration`) |

## Service configuration and authentication

All API requests must use HTTPS and include an `Authorization: Bearer
ACCESS_TOKEN` header obtained using the OAuth 2.0 Web Server flow for a Google
Account that has completed developer identity verification in the [Android
Developer Console](https://developer.android.com/developer-verification/guides/android-developer-console).

| Property | Value |
|---|---|
| **Base REST endpoint** | `https://androiddeveloperconsole.googleapis.com` |
| **Media upload endpoint** | `https://androiddeveloperconsole.googleapis.com/upload` |
| **API version** | `v1` |
| **Required OAuth 2.0 scope** | `https://www.googleapis.com/auth/androiddeveloperconsole` |
| **Default quota limit** | `2,000` requests per day per Google Cloud project per method |

> [!NOTE]
> **Note:** Authentication requires user-delegated OAuth 2.0 credentials (`Authorization: Bearer ACCESS_TOKEN`). Service accounts, Workload Identity Federation, and API keys aren't supported because **Android Developer Console** accounts are linked directly to verified user Google Accounts.

## API resources and endpoints

The **Android Developer Console API** organizes resources in the following
hierarchy:

- `DeveloperAccount` (`developerAccounts/{developer_account}`)
  - `AndroidPackage` (`developerAccounts/{developer_account}/androidPackages/{android_package}`)
    - `AndroidPackageRegistrationPolicy` (`developerAccounts/{developer_account}/androidPackages/{android_package}/registrationPolicy`)
    - `AndroidPackageKey` (`developerAccounts/{developer_account}/androidPackages/{android_package}/keys/{key}`)

### Resource: DeveloperAccount

Represents an account in the **Android Developer Console** associated with a
developer identity.

| Field | Type | Description |
|---|---|---|
| `name` | `string` | Identifier. Resource name in the format `developerAccounts/{developer_account}`. |
| `displayName` | `string` | Output only. Human-readable name associated with the developer account (individual name or organization name). |
| `verificationState` | `enum (VerificationState)` | Output only. Current developer identity verification status of the account. |

#### Enum: DeveloperAccount.VerificationState

| Value | Description |
|---|---|
| `VERIFIED` | Developer identity verification is complete. The account can register package names and app signing keys. |
| `NOT_VERIFIED` | Developer identity verification hasn't been completed in the **Android Developer Console**. |

#### Methods: DeveloperAccount

| Method | HTTP request | Description |
|---|---|---|
| [`GetDeveloperAccount`](https://developer.android.com/developer-verification/reference/developer-console-api#getdeveloperaccount) | `GET /v1/{name=developerAccounts/*}` | Retrieves metadata and verification state for a single `DeveloperAccount`. |
| [`ListDeveloperAccounts`](https://developer.android.com/developer-verification/reference/developer-console-api#listdeveloperaccounts) | `GET /v1/developerAccounts` | Lists all `DeveloperAccount` objects accessible to the authenticated Google Account (unpaginated). |

### Resource: AndroidPackage

Represents an Android package name registered or being registered under a
`DeveloperAccount`.

| Field | Type | Description |
|---|---|---|
| `name` | `string` | Identifier. Resource name in the format `developerAccounts/{developer_account}/androidPackages/{android_package}`, where `{android_package}` is the Android package name (for example, `com.example.myapp`). |
| `packageName` | `string` | Output only. The Android package name (for example, `com.example.myapp`). |
| `state` | `enum (AndroidPackage.State)` | Output only. Current registration lifecycle state of the package name. |
| `registeredAppStore` | `boolean` | Output only. Indicates whether this package name is currently active as a registered app store. |

#### Enum: AndroidPackage.State

| Value | Description |
|---|---|
| `DRAFT` | The package name resource has been created, and app signing key registration or ownership verification is still in progress. |
| `IN_REVIEW` | The package name registration and any required key justification have been submitted and are under review by Google. A package transitions from `DRAFT` to `IN_REVIEW` either immediately upon `CreateAndroidPackageKey` (when key ownership verification is skipped, including when the key was already verified for another package name in the same `DeveloperAccount`) or after completing `VerifyAndroidPackageKeyOwnership` and, if required, `JustifyAndroidPackageKeyRegistration`. |
| `REGISTERED` | The package name is actively registered to this developer account for **Android developer verification**. |
| `PENDING_TRANSFER` | The package name is awaiting completion of an ownership transfer to another developer account. |

#### Resource: AndroidPackageRegistrationPolicy

Singleton resource returned by
[`GetAndroidPackageRegistrationPolicy`](https://developer.android.com/developer-verification/reference/developer-console-api#getandroidpackageregistrationpolicy)
that describes historical public signing keys detected for a package name and
whether registering the package name with a given signing key requires a written
justification.

| Field | Type | Description |
|---|---|---|
| `name` | `string` | Identifier. Resource name in the format `developerAccounts/{developer_account}/androidPackages/{android_package}/registrationPolicy`. |
| `knownKeys[]` | `object (KnownKey)` | List of historical app signing keys previously observed distributing apps with this package name, sorted lexicographically by `certificateFingerprintSha256`. |
| `knownKeys[].certificateFingerprintSha256` | `string` | Output only. Normalized 64-character lowercase hexadecimal SHA-256 fingerprint of the historical signing certificate (without colons). |
| `knownKeys[].justificationRequirement` | `enum (JustificationRequirement)` | Output only. Indicates whether registering this key requires calling `JustifyAndroidPackageKeyRegistration` (`REQUIRED` or `NOT_REQUIRED`). If the signing key was previously verified on another package name under the same `DeveloperAccount`, both `VerifyAndroidPackageKeyOwnership` and `JustifyAndroidPackageKeyRegistration` are skipped even when `justificationRequirement` is `REQUIRED`. |
| `keySelectionStrategy` | `enum (KeySelectionStrategy)` | Output only. Key selection policy for registering this package name: `SELECT_KEY_FROM_LIST` (must register a key from `knownKeys`) or `USE_ANY_KEY` (any valid app signing key owned by the developer can be registered). |

#### Enum: KnownKey.JustificationRequirement

| Value | Description |
|---|---|
| `REQUIRED` | Registering this known key requires submitting a written justification using `JustifyAndroidPackageKeyRegistration` after completing `VerifyAndroidPackageKeyOwnership` (unless the key was previously verified on another package name under the same `DeveloperAccount`, in which case both `VerifyAndroidPackageKeyOwnership` and `JustifyAndroidPackageKeyRegistration` are skipped). |
| `NOT_REQUIRED` | Registering this known key does not require a justification. The key transitions directly to `IN_REVIEW` after `VerifyAndroidPackageKeyOwnership` (or immediately upon `CreateAndroidPackageKey` if the key was previously verified on another package name under the same `DeveloperAccount`). |

#### Enum: AndroidPackageRegistrationPolicy.KeySelectionStrategy

| Value | Description |
|---|---|
| `SELECT_KEY_FROM_LIST` | The caller must register one of the historical keys listed in `knownKeys`. |
| `USE_ANY_KEY` | In addition to any keys in `knownKeys`, the caller can register any valid app signing key not previously observed in the Android ecosystem. |

#### Methods: AndroidPackage

| Method | HTTP request | Description |
|---|---|---|
| [`GetAndroidPackageRegistrationPolicy`](https://developer.android.com/developer-verification/reference/developer-console-api#getandroidpackageregistrationpolicy) | `GET /v1/{name=developerAccounts/*/androidPackages/*/registrationPolicy}` | Retrieves the key selection strategy and known historical signing keys for a package name. |
| [`CreateAndroidPackage`](https://developer.android.com/developer-verification/reference/developer-console-api#createandroidpackage) | `POST /v1/{parent=developerAccounts/*}/androidPackages?androidPackageId={package_name}` | Creates a new `AndroidPackage` resource in `DRAFT` state to start registering a package name. |
| [`GetAndroidPackage`](https://developer.android.com/developer-verification/reference/developer-console-api#getandroidpackage) | `GET /v1/{name=developerAccounts/*/androidPackages/*}` | Retrieves details and current registration state for an existing `AndroidPackage`. |
| [`ListAndroidPackages`](https://developer.android.com/developer-verification/reference/developer-console-api#listandroidpackages) | `GET /v1/{parent=developerAccounts/*}/androidPackages` | Lists `AndroidPackage` objects under a `DeveloperAccount` (`pageSize` max `1000`, `pageToken`). |

### Resource: AndroidPackageKey

Represents a public app signing certificate fingerprint associated with an
`AndroidPackage` and tracks ownership verification and registration review
state.

| Field | Type | Description |
|---|---|---|
| `name` | `string` | Identifier. Server-assigned resource name in the format `developerAccounts/{developer_account}/androidPackages/{android_package}/keys/{key}`, where `{key}` is a normalized 64-character lowercase hexadecimal SHA-256 fingerprint without colons. Must be omitted or empty when calling `CreateAndroidPackageKey`. |
| `certificateFingerprintSha256` | `string` | Required. Immutable. SHA-256 hash of the app signing certificate. On input in `CreateAndroidPackageKey`, accepts either plain 64-character hex (`60e860e8...`) or colon-separated hex (`60:E8:60:E8:...`). On output, always normalized to 64-character lowercase hexadecimal without colons. |
| `state` | `enum (AndroidPackageKey.State)` | Output only. Current verification and registration lifecycle state of the key. |
| `verificationToken` | `string` | Output only. Unique challenge token generated by Google. Used only when state is `DRAFT` (can be ignored when `CreateAndroidPackageKey` transitions the key directly to `IN_REVIEW`). When the state is `DRAFT`, embed this string inside `assets/adi-registration.properties` in a signed APK to complete `VerifyAndroidPackageKeyOwnership`. |
| `registrationJustificationRequired` | `boolean` | Output only. If `true` and the key is in `OWNERSHIP_VERIFIED` state, you must submit a written justification using `JustifyAndroidPackageKeyRegistration` before registration proceeds to `IN_REVIEW`. If `CreateAndroidPackageKey` transitions the key directly to `IN_REVIEW` (because the key was previously verified on another package name in the same `DeveloperAccount`), justification is skipped. |

#### Enum: AndroidPackageKey.State

| Value | Description |
|---|---|
| `DRAFT` | The key resource has been created, and proof of private key possession using signed APK upload (`VerifyAndroidPackageKeyOwnership`) is still required because ownership of this key has not yet been verified on any package name under this `DeveloperAccount`. |
| `OWNERSHIP_VERIFIED` | Private key ownership has been verified using a signed APK upload. If `registrationJustificationRequired` is `true`, a justification is still required before review begins. |
| `IN_REVIEW` | The key registration is under review by Google. A key transitions here either immediately upon `CreateAndroidPackageKey` when proof of ownership is not required (for example, on a new package name that has never been seen on Android, or when the key was previously verified on another package name under the same `DeveloperAccount`, which also skips `JustifyAndroidPackageKeyRegistration`), directly after `VerifyAndroidPackageKeyOwnership` (if `registrationJustificationRequired` is `false`), or after `JustifyAndroidPackageKeyRegistration` (if `registrationJustificationRequired` is `true`). |
| `REGISTERED` | The app signing key is actively registered to this package name for **Android developer verification**. |
| `PENDING_TRANSFER` | The app signing key registration is awaiting completion of a transfer. |

#### Methods: AndroidPackageKey

| Method | HTTP request | Description |
|---|---|---|
| [`CreateAndroidPackageKey`](https://developer.android.com/developer-verification/reference/developer-console-api#createandroidpackagekey) | `POST /v1/{parent=developerAccounts/*/androidPackages/*}/keys` | Registers a new app signing certificate SHA-256 fingerprint under an `AndroidPackage`. Returns the key in `DRAFT` state (when proof of ownership using `VerifyAndroidPackageKeyOwnership` is required) or directly in `IN_REVIEW` state (when ownership verification is skipped, such as for a new package name that has never been seen on Android or a key already verified on another package name in the same `DeveloperAccount`). |
| [`GetAndroidPackageKey`](https://developer.android.com/developer-verification/reference/developer-console-api#getandroidpackagekey) | `GET /v1/{name=developerAccounts/*/androidPackages/*/keys/*}` | Retrieves status, fingerprint, and verification metadata of a specific `AndroidPackageKey`. |
| [`ListAndroidPackageKeys`](https://developer.android.com/developer-verification/reference/developer-console-api#listandroidpackagekeys) | `GET /v1/{parent=developerAccounts/*/androidPackages/*}/keys` | Lists all `AndroidPackageKey` objects registered under an `AndroidPackage` (`pageSize` max `1000`, `pageToken`). |
| [`VerifyAndroidPackageKeyOwnership`](https://developer.android.com/developer-verification/reference/developer-console-api#verifyandroidpackagekeyownership) | `POST /upload/v1/{name=developerAccounts/*/androidPackages/*/keys/*}:verify` | Uploads a signed minimal APK containing `verificationToken` in `assets/adi-registration.properties` to verify private key ownership and submit ready keys for review. |
| [`JustifyAndroidPackageKeyRegistration`](https://developer.android.com/developer-verification/reference/developer-console-api#justifyandroidpackagekeyregistration) | `POST /v1/{name=developerAccounts/*/androidPackages/*/keys/*}:justifyAndroidPackageKeyRegistration` | Submits additional justification context when `registrationJustificationRequired` is `true` and submits verified keys for review. |

## Error handling

When an API request fails, the **Android Developer Console API** returns an HTTP
`4xx` or `5xx` status code and a standard
[`google.rpc.Status`](https://cloud.google.com/apis/design/errors#error_model) JSON error body:

    {
      "error": {
        "code": 400,
        "message": "Invalid certificate fingerprint SHA256 format.",
        "status": "INVALID_ARGUMENT",
        "details": []
      }
    }

### HTTP status codes and common resolutions

| HTTP code | gRPC status | Common causes | Resolution |
|---|---|---|---|
| `400 Bad Request` | `INVALID_ARGUMENT` | Missing or invalid Java-style `androidPackageId`; invalid `certificateFingerprintSha256` format; non-empty `name` field on `CreateAndroidPackage` or `CreateAndroidPackageKey`; uploaded APK is unsigned, corrupted, missing `assets/adi-registration.properties`, missing matching `verificationToken`, or signed with a mismatched certificate. | Validate request formats against the resource schemas, omit or empty `name` on create calls, and verify your APK signature and embedded token using `apksigner verify --print-certs` and `unzip -p app-release.apk assets/adi-registration.properties` before uploading. |
| `400 Bad Request` | `FAILED_PRECONDITION` | `DeveloperAccount` has `verificationState: NOT_VERIFIED`; key selection violates `AndroidPackageRegistrationPolicy` (`SELECT_KEY_FROM_LIST`); calling `VerifyAndroidPackageKeyOwnership` or `JustifyAndroidPackageKeyRegistration` in an ineligible state. | Complete developer identity verification in the [Android Developer Console](https://developer.android.com/developer-verification/guides/android-developer-console), check `GetAndroidPackageRegistrationPolicy` first, and inspect the resource's current `state`. |
| `401 Unauthorized` | `UNAUTHENTICATED` | Missing, expired, or invalid OAuth 2.0 Bearer access token, or attempt to authenticate using an API key or service account. | Obtain a fresh user-delegated OAuth 2.0 Bearer access token with scope `https://www.googleapis.com/auth/androiddeveloperconsole`. |
| `403 Forbidden` | `PERMISSION_DENIED` | Authenticated user lacks permission on the target `DeveloperAccount` or `AndroidPackage`, or the **Android Developer Console API** isn't enabled on the Google Cloud project. | Verify account membership using `ListDeveloperAccounts` and ensure `androiddeveloperconsole.googleapis.com` is enabled in Google Cloud Console. |
| `404 Not Found` | `NOT_FOUND` | Specified `DeveloperAccount`, `AndroidPackage`, or `AndroidPackageKey` resource path doesn't exist. | Confirm resource paths using `ListDeveloperAccounts`, `ListAndroidPackages`, or `ListAndroidPackageKeys`. Ensure `{key}` IDs use lowercase hex without colons. |
| `409 Conflict` | `ALREADY_EXISTS` | Package name or SHA-256 certificate fingerprint is already registered under this or another developer account. | Inspect existing registrations using `GetAndroidPackage` or `GetAndroidPackageKey`, or check historical ownership using `GetAndroidPackageRegistrationPolicy`. |
| `429 Too Many Requests` | `RESOURCE_EXHAUSTED` | Exceeded per-method quota of `2,000` requests per day per Google Cloud project. | Implement exponential backoff with jitter and avoid high-frequency polling loops. |
| `500` / `503` | `INTERNAL` / `UNAVAILABLE` | Transient backend error or temporary service unavailability. | Retry idempotent requests with truncated exponential backoff. |

## HTTP request and response examples

Replace placeholder values such as `ACCESS_TOKEN`, `1234567890`,
`com.example.myapp`, and `60e860e8...` with your own values.

### 1. GetDeveloperAccount

    curl -X GET \
      -H "Authorization: Bearer ACCESS_TOKEN" \
      "https://androiddeveloperconsole.googleapis.com/v1/developerAccounts/1234567890"

**Response:**

    {
      "name": "developerAccounts/1234567890",
      "displayName": "Example Developer",
      "verificationState": "VERIFIED"
    }

### 2. ListDeveloperAccounts

    curl -X GET \
      -H "Authorization: Bearer ACCESS_TOKEN" \
      "https://androiddeveloperconsole.googleapis.com/v1/developerAccounts"

**Response:**

    {
      "developerAccounts": [
        {
          "name": "developerAccounts/1234567890",
          "displayName": "Example Developer",
          "verificationState": "VERIFIED"
        }
      ]
    }

### 3. GetAndroidPackageRegistrationPolicy

    curl -X GET \
      -H "Authorization: Bearer ACCESS_TOKEN" \
      "https://androiddeveloperconsole.googleapis.com/v1/developerAccounts/1234567890/androidPackages/com.example.myapp/registrationPolicy"

**Response:**

    {
      "name": "developerAccounts/1234567890/androidPackages/com.example.myapp/registrationPolicy",
      "knownKeys": [
        {
          "certificateFingerprintSha256": "60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123",
          "justificationRequirement": "NOT_REQUIRED"
        }
      ],
      "keySelectionStrategy": "SELECT_KEY_FROM_LIST"
    }

### 4. CreateAndroidPackage

    curl -X POST \
      -H "Authorization: Bearer ACCESS_TOKEN" \
      -H "Content-Type: application/json; charset=utf-8" \
      -d '{"name": ""}' \
      "https://androiddeveloperconsole.googleapis.com/v1/developerAccounts/1234567890/androidPackages?androidPackageId=com.example.myapp"

**Response:**

    {
      "name": "developerAccounts/1234567890/androidPackages/com.example.myapp",
      "packageName": "com.example.myapp",
      "state": "DRAFT",
      "registeredAppStore": false
    }

### 5. GetAndroidPackage

    curl -X GET \
      -H "Authorization: Bearer ACCESS_TOKEN" \
      "https://androiddeveloperconsole.googleapis.com/v1/developerAccounts/1234567890/androidPackages/com.example.myapp"

**Response:**

    {
      "name": "developerAccounts/1234567890/androidPackages/com.example.myapp",
      "packageName": "com.example.myapp",
      "state": "REGISTERED",
      "registeredAppStore": false
    }

### 6. ListAndroidPackages

    curl -X GET \
      -H "Authorization: Bearer ACCESS_TOKEN" \
      "https://androiddeveloperconsole.googleapis.com/v1/developerAccounts/1234567890/androidPackages?pageSize=100"

**Response:**

    {
      "androidPackages": [
        {
          "name": "developerAccounts/1234567890/androidPackages/com.example.myapp",
          "packageName": "com.example.myapp",
          "state": "REGISTERED",
          "registeredAppStore": false
        }
      ],
      "nextPageToken": ""
    }

### 7. CreateAndroidPackageKey

    curl -X POST \
      -H "Authorization: Bearer ACCESS_TOKEN" \
      -H "Content-Type: application/json; charset=utf-8" \
      -d '{
        "certificateFingerprintSha256": "60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123"
      }' \
      "https://androiddeveloperconsole.googleapis.com/v1/developerAccounts/1234567890/androidPackages/com.example.myapp/keys"

**Response:**

    {
      "name": "developerAccounts/1234567890/androidPackages/com.example.myapp/keys/60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123",
      "certificateFingerprintSha256": "60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123",
      "state": "DRAFT",
      "verificationToken": "token_xyz987654321"
    }

> [!NOTE]
> **Note:** `state` is `DRAFT` when proof of private key ownership is required. If ownership verification is not required (for example, when registering a new package name that has never been seen on Android or when this key was already verified on another package name under the same `DeveloperAccount`), `CreateAndroidPackageKey` returns an `IN_REVIEW` state and automatically queues the key for review. In that case, don't call `VerifyAndroidPackageKeyOwnership` (Example 10) or `JustifyAndroidPackageKeyRegistration` (Example 11).

### 8. GetAndroidPackageKey

    curl -X GET \
      -H "Authorization: Bearer ACCESS_TOKEN" \
      "https://androiddeveloperconsole.googleapis.com/v1/developerAccounts/1234567890/androidPackages/com.example.myapp/keys/60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123"

**Response:**

    {
      "name": "developerAccounts/1234567890/androidPackages/com.example.myapp/keys/60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123",
      "certificateFingerprintSha256": "60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123",
      "state": "REGISTERED"
    }

### 9. ListAndroidPackageKeys

    curl -X GET \
      -H "Authorization: Bearer ACCESS_TOKEN" \
      "https://androiddeveloperconsole.googleapis.com/v1/developerAccounts/1234567890/androidPackages/com.example.myapp/keys?pageSize=100"

**Response:**

    {
      "androidPackageKeys": [
        {
          "name": "developerAccounts/1234567890/androidPackages/com.example.myapp/keys/60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123",
          "certificateFingerprintSha256": "60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123",
          "state": "REGISTERED"
        }
      ],
      "nextPageToken": ""
    }

### 10. VerifyAndroidPackageKeyOwnership

#### Option A: Single-request media upload

    curl -X POST \
      -H "Authorization: Bearer ACCESS_TOKEN" \
      -H "Content-Type: application/octet-stream" \
      --data-binary @app-release.apk \
      "https://androiddeveloperconsole.googleapis.com/upload/v1/developerAccounts/1234567890/androidPackages/com.example.myapp/keys/60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123:verify?uploadType=media"

#### Option B: Resumable upload protocol (recommended for large APKs or CI/CD)

Step 1: Start the resumable upload session and extract the returned
`X-Goog-Upload-URL` header:

    curl -i -X POST \
      "https://androiddeveloperconsole.googleapis.com/upload/v1/developerAccounts/1234567890/androidPackages/com.example.myapp/keys/60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123:verify" \
      -H "Authorization: Bearer ACCESS_TOKEN" \
      -H "X-Goog-Upload-Protocol: resumable" \
      -H "X-Goog-Upload-Command: start" \
      -H "X-Goog-Upload-Header-Content-Length: FILE_SIZE_IN_BYTES" \
      -H "X-Goog-Upload-Header-Content-Type: application/vnd.android.package-archive" \
      -H "Content-Type: application/json" \
      -d '{
        "name": "developerAccounts/1234567890/androidPackages/com.example.myapp/keys/60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123"
      }'

Step 2: Upload the signed APK binary to `UPLOAD_SESSION_URI` and finalize the
session:

    curl -X PUT \
      "UPLOAD_SESSION_URI" \
      -H "Content-Length: FILE_SIZE_IN_BYTES" \
      -H "X-Goog-Upload-Offset: 0" \
      -H "X-Goog-Upload-Command: upload, finalize" \
      --data-binary "@app-release.apk"

**Response:**

    {
      "name": "developerAccounts/1234567890/androidPackages/com.example.myapp/keys/60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123",
      "certificateFingerprintSha256": "60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123",
      "state": "IN_REVIEW"
    }

### 11. JustifyAndroidPackageKeyRegistration

    curl -X POST \
      -H "Authorization: Bearer ACCESS_TOKEN" \
      -H "Content-Type: application/json; charset=utf-8" \
      -d '{
        "justification": "We previously distributed com.example.myapp directly from https://downloads.example.com and are migrating to our rotated production key."
      }' \
      "https://androiddeveloperconsole.googleapis.com/v1/developerAccounts/1234567890/androidPackages/com.example.myapp/keys/60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123:justifyAndroidPackageKeyRegistration"

**Response:**

    {
      "name": "developerAccounts/1234567890/androidPackages/com.example.myapp/keys/60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123",
      "certificateFingerprintSha256": "60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123",
      "state": "IN_REVIEW",
      "registrationJustificationRequired": true
    }

## Additional resources

- [Register package names with the Android Developer Console API](https://developer.android.com/developer-verification/guides/developer-console-api)
- [Check app registration status with the Android Developer ID Status API](https://developer.android.com/developer-verification/guides/check-registration-status)
- [Register on Android Developer Console](https://developer.android.com/developer-verification/guides/android-developer-console)
- [Register on Google Play Console](https://developer.android.com/developer-verification/guides/google-play-console)