# SkillPatch skill: google-ads-api-quickstart

This skill guides developers through the Google Ads API quickstart process, covering credential setup, choosing among 6 client libraries (Python, Java, .NET, PHP, Ruby, Perl) or REST, and running a "retrieve campaigns" script. It enforces dynamic API and runtime version resolution to avoid hardcoded values. It also provides troubleshooting guidance for common errors such as USER_PERMISSION_DENIED, login_customer_id issues, and DEVELOPER_TOKEN_NOT_APPROVED.

You (the agent) were given this URL and asked to use this skill. This is a **public** skill — no SkillPatch account, API key, or prior setup is required. Two ways to use it:

**1. Use it right now** — the skill's complete file tree (SKILL.md + all reference files) is inlined below; read `SKILL.md` first, then follow it, consulting the other files as it directs.

**2. Install the exact package onto disk** (recommended if you can run a shell — this reproduces the skill byte-for-byte, including any binary assets that can't be inlined):

```bash
mkdir -p .claude/skills/google-ads-api-quickstart
curl -sSL https://skillpatch.dev/install_skill/google-ads-api-quickstart | tar -xz -C .claude/skills/
```

(`.claude/skills/` is Claude Code's convention; use whatever directory your agent loads skills from.)


---

## Skill files (8)

- `SKILL.md`
- `references/dotnet.md`
- `references/java.md`
- `references/perl.md`
- `references/php.md`
- `references/python.md`
- `references/rest.md`
- `references/ruby.md`


### `SKILL.md`

````markdown
---
name: google-ads-api-quickstart
description: |
  Guides developers through Google Ads API quickstart: credential setup, choosing from 6 client libraries/REST, configuring environments, and running a "retrieve campaigns" script. Troubleshoots common setup errors: USER_PERMISSION_DENIED, login_customer_id issues, and DEVELOPER_TOKEN_NOT_APPROVED.

  Use this skill when:
  - The user asks how to get started with the Google Ads API.
  - The user needs to set up Google Ads credentials or developer tokens.
  - The user wants to write a quickstart/example script for Google Ads.
  - The user encounters errors like USER_PERMISSION_DENIED or DEVELOPER_TOKEN_NOT_APPROVED.
compatibility: "Outbound HTTPS connectivity required to access the Google Ads API and documentation. Note: If network access is restricted, the agent will fall back to using the last-known stable versions cached within the skill resources."
metadata:
  author: google-ads-api-team
  version: "1.0"
  category: GoogleAds
---
# Google Ads API Quickstart
This skill guides you from absolute zero to running your first successful request to retrieve campaigns.

## Supported Tracks
You can choose to use this skill with:

1. **Official Client Libraries:** Python, Java, .NET, PHP, Ruby, or Perl.
2. **Direct REST:** Raw HTTP REST requests.

---

## Crucial Requirement: Dynamic Version Resolution & Runtime Resolution

> [!IMPORTANT]
> To ensure the integration is secure, stable, and up-to-date, you must resolve all API and runtime versions dynamically. Do not rely on hardcoded defaults.

### Strict Constraints:

*   **DO NOT Hardcode:** Never use hardcoded Google Ads API versions (e.g., `v24`) or language runtime versions (e.g., `Python 3.8+`, `Java 11+`) in generated code or environment setup instructions, unless the user explicitly requests a specific version.
*   **MANDATORY Dynamic Resolution:** You must dynamically resolve the latest stable versions *at the start of execution* before generating any code or configuration, using the procedures detailed below.

### A. Dynamic API Version Resolution
To ensure the integration is secure, stable, and up-to-date, you **MUST** resolve the absolute newest stable major version of the Google Ads API dynamically.

#### Execution Steps:

1.  **Pre-Flight Version Resolution:** Use your web search or URL-reading tools to inspect the latest entry in the [Google Ads API Release Notes](https://developers.google.com/google-ads/api/docs/release-notes.md.txt) or the highest versioned directory in the [Googleapis Github Repository](https://github.com/googleapis/googleapis/tree/master/google/ads/googleads) to resolve `RESOLVED_API_VERSION` (e.g., `v24`). If using Java, you **MUST** also resolve the latest stable release version of the Google Ads Java Client Library (referred to as `RESOLVED_LIBRARY_VERSION`, e.g., `34.0.0`).

2.  **Mandatory Response Anchor:** You **MUST** output the following confirmation block as the **very first line** of your response to the user. Do not output any greeting, pleasantries, or introductory text before this block.
    
    ```text
    [SYSTEM: Using Google Ads API version: RESOLVED_API_VERSION (Resolved from release notes)]
    ```

3.  **Strict Placeholder Mapping Table:** You **MUST** perform on-the-fly search-and-replace on all code templates and reference files using the mapping table below. Do not leave raw placeholders in the final output.

    | Target Language / Tech | Placeholder in Template | Replacement Pattern | Example (Assuming API `v24`) |
    | :--- | :--- | :--- | :--- |
    | **Java** (Maven/Gradle) | `LATEST_LIBRARY_VERSION` | Search & substitute the latest Maven release version of the library. | `34.0.0` |
    | **Java** (Imports) | `vXX` | Replace with **lower-case** API version. | `com.google.ads.googleads.v24` |
    | **.NET / C#** (Namespaces) | `VXX` | Replace with **title-case** API version. | `Google.Ads.GoogleAds.V24` |
    | **PHP** (Namespaces) | `VXX` | Replace with **title-case** API version. | `Google\Ads\GoogleAds\V24` |
    | **REST** (Endpoint URL) | `vXX` | Replace with **lower-case** API version. | `https://googleads.googleapis.com/v24/...` |

> [!TIP]
> **Offline Fallback:** If the URLs are unreachable or the scrape fails, do not halt execution. Fall back to these last-known stable versions:
> *   **Google Ads API Major Version (`RESOLVED_API_VERSION`):** `v24`
> *   **Java Client Library Version (`RESOLVED_LIBRARY_VERSION`):** `34.0.0`

### B. Dynamic Language Runtime Version Resolution
To prevent the generated setup guides from becoming obsolete due to language deprecation cycles, you **MUST** resolve language requirements dynamically.

#### Execution Steps:

1.  **Fetch Live Requirements:** Use your URL-reading tools to inspect the official [Google Ads Client Libraries - Supported Versions](https://developers.google.com/google-ads/api/docs/client-libs.md.txt#supported_api_versions) page.

2.  **Extract Minimums:** Identify the minimum supported runtime version for the user's chosen language by scanning the Overview page or compatibility tables (e.g., looking for explicit requirements like Python 3.8+, Java 11+, .NET 6.0+, PHP 8.1+, Ruby 3.0+).

3.  **Apply On-The-Fly:** Substitute all runtime placeholders (e.g., `<PYTHON_MIN_VERSION>`) in your generated setup guides with these resolved versions.

> [!TIP]
> **Offline Fallback:** If the URL is unreachable or the scrape fails, do not halt execution. Fall back to these last-known safe minimum versions:
> *   **Python:** `3.9+`
> *   **Java:** `11+`
> *   **.NET:** `6.0+`
> *   **PHP:** `8.1+`
> *   **Ruby:** `3.0+`
> *   **Perl:** `5.28.1+`

---

## Step 1: Obtain Google Ads API Credentials

Before installing libraries or making API calls, you must obtain the five required authentication parameters.

### 1. Developer Token

*   **Purpose:** Identifies your developer access and API quota.
*   **How to Obtain:**
    1. Navigate directly to the **API Center** in your Google Ads Manager Account: https://ads.google.com/aw/apicenter *(Note: You must sign in with a Manager account, not a standard serving account)*.
    2. Copy your Developer Token.

> [!WARNING]
> **Pending Token Restriction:** If your Developer Token status is "Pending" (unapproved), you **MUST ONLY** target **Google Ads Test Accounts**. Attempting to call a production account with a pending token will fail with the error: `DEVELOPER_TOKEN_NOT_APPROVED`.

### 2. OAuth2 Client ID & Client Secret

*   **Purpose:** Identifies your application to Google's OAuth 2.0 server and allows you to request user authorization.
*   **How to Obtain:**
    1. Open the [Google Cloud Console](https://console.cloud.google.com/).
    2. Create a new project (or select an existing one).
    3. Search for the **Google Ads API** in the API Library and click **Enable**.
    4. Configure the **OAuth Consent Screen**:
       *   Select **External** user type.
       *   Set the Publishing Status to **Testing**.
       *   > [!IMPORTANT]
       *   > **Add Test Users:** You **MUST** add the email address of the Google account you use to log into Google Ads as a **Test User** in this step. Otherwise, you will be blocked during authorization.
    5. Create the OAuth Client:
       *   Go to **APIs & Services 🡒 Credentials**.
       *   Click **Create Credentials 🡒 OAuth client ID**.
       *   Select **Desktop App** as the Application Type.
       *   Name the client and click **Create**.
    6. **Download Secrets:** Click the download icon (JSON) next to your newly created Client ID. Save this file locally as `client_secrets.json`.

### 3. OAuth2 Refresh Token

*   **Purpose:** Allows your application to obtain new access tokens automatically without requiring manual user login every hour.
*   **How to Obtain:**
    You must run the Google Cloud (`gcloud`) CLI to generate your refresh token.

    #### 1. Install and Verify gcloud CLI:
    Ensure the [gcloud CLI](https://cloud.google.com/sdk/docs/install) is installed and available in your terminal.

    #### 2. Execute the Login Flow:
    Run the following command in your terminal, passing the path to the `client_secrets.json` file downloaded in the previous step:
    
    ```bash
    gcloud auth application-default login \
      --scopes=https://www.googleapis.com/auth/adwords,https://www.googleapis.com/auth/cloud-platform \
      --client-id-file=client_secrets.json
    ```

    #### 3. Authorize in Browser:
    1. The command will open a Google Account login window in your browser.
    2. Sign in using the **Test User** email registered in your OAuth Consent Screen setup.
    3. If your app is unverified, click **Advanced** and continue to the project. Click **Continue** to grant permissions.

    #### 4. Retrieve Your Refresh Token:
    Once successful, `gcloud` will output a message indicating where the credentials were saved (typically `~/.config/gcloud/application_default_credentials.json`). Open that file to copy your `refresh_token`.

### 4. Client Customer ID

*   **Purpose:** The 10-digit ID of the specific Google Ads account you want to query or make changes to.
*   **Format:** Must be 10 digits with **no hyphens** (e.g., `1234567890`, NOT `123-456-7890`).
*   **How to Find It:** Log in to the Google Ads UI; the ID is displayed in the top-right corner next to your user icon.

> [!IMPORTANT]
> **Test Account Requirement:** If your Developer Token is pending (unapproved), this **MUST** be the Customer ID of a **Test Account**. Test accounts have a red "Test account" banner in the top right of the UI.

---

### 5. Login Customer ID

*   **What it is:** The 10-digit Customer ID of the Google Ads Manager Account that owns or manages the target client account.
*   **Format:** Must be 10 digits with **no hyphens** (e.g., `9876543210`).
*   **When to Use:** This is **mandatory** if your OAuth credentials (and developer token) belong to a Manager Account, but you are querying a child/client account (Client Customer ID).

> [!CAUTION]
> **Preventing `USER_PERMISSION_DENIED`:**
> If you are accessing a client account through a Manager Account hierarchy, you **MUST** set this parameter.
> *   `login_customer_id` = The **Manager** Account ID.
> *   `client_customer_id` = The **Child/Client** Account ID.
> Leaving `login_customer_id` blank in a manager-client hierarchy is the #1 cause of permission errors.

---

## Step 2: Choose Your Integration Strategy

Developers can connect to the Google Ads API using either the official high-level client libraries or direct HTTPS REST requests.

### Path A: Official Client Libraries (Recommended)

> [!IMPORTANT]
> **Mandatory Agent Directive:** Once the user selects their language, you **MUST**:
> 1. Use the `view_file` tool to lazy-load the corresponding reference file listed below.
> 2. Apply the **Dynamic Version Resolution** (Section B) to dynamically replace all `vXX`/`VXX` placeholders and library versions *before* generating code.

#### Python
If you need to set up the Google Ads API environment for Python, do not guess the configuration.
Instead, read the detailed setup guide:

*   [Google Ads API Python Setup Reference](references/python.md)
*(Package: `google-ads`)*

#### Java
If you need to set up the Google Ads API environment for Java, do not guess the configuration.
Instead, read the detailed setup guide:

*   [Google Ads API Java Setup Reference](references/java.md)
*(Artifact: `com.google.api-ads:google-ads`)*

#### .NET / C#
If you need to set up the Google Ads API environment for .NET/C#, do not guess the configuration.
Instead, read the detailed setup guide:

*   [Google Ads API .NET Setup Reference](references/dotnet.md)
*(Package: `Google.Ads.GoogleAds`)*

#### PHP
If you need to set up the Google Ads API environment for PHP, do not guess the configuration.
Instead, read the detailed setup guide:

*   [Google Ads API PHP Setup Reference](references/php.md)
*(Package: `googleads/google-ads-php`)*

#### Ruby
If you need to set up the Google Ads API environment for Ruby, do not guess the configuration.
Instead, read the detailed setup guide:

*   [Google Ads API Ruby Setup Reference](references/ruby.md)
*(Gem: `google-ads-ruby`)*

#### Perl
If you need to set up the Google Ads API environment for Perl, do not guess the configuration.
Instead, read the detailed setup guide:

*   [Google Ads API Perl Setup Reference](references/perl.md)
*(Package: `Google::Ads::GoogleAds::Client`)*

### Path B: Direct HTTP REST (No Library Overhead)

Use this path if the user's environment does not support the official client libraries (e.g., lightweight serverless functions, custom language stacks, or restricted runtimes).

> [!IMPORTANT]
> **Mandatory Agent Directive:** If the user chooses the REST path, you **MUST**:
> 1. Use the `view_file` tool to lazy-load the REST reference file below.
> 2. Apply **Dynamic Version Resolution** (Section B) to replace all `vXX` placeholders in the endpoint URLs (e.g., resolving `vXX` to `v24` in `https://googleads.googleapis.com/v24/...`).

#### REST (HTTP)
If you need to set up the Google Ads API environment for REST (HTTP), do not guess the configuration.
Instead, read the detailed setup guide:

*   [Google Ads API REST Setup Reference](references/rest.md)
*(Protocol: Raw HTTP POST JSON)*

---

## Cross-Referencing: AI-Assistant & MCP Connection

> [!TIP]
> **AI Assistant / MCP Integration Handoff:**
> If the goal is to connect an **AI Assistant** (such as Gemini, Cursor, or Claude Code) to query Google Ads via natural language:
> 1. **DO NOT** write custom scripts or client library code.
> 2. **STOP** executing this skill.
> 3. **Transition Immediately** to the **`google-ads-api-mcp-setup`** skill to install and configure the official Google Ads Model Context Protocol (MCP) Server.

---

## Step 4: Troubleshooting Common Errors

> [!IMPORTANT]
> **Static Diagnostics Constraint:** When troubleshooting, you **MUST NOT** execute bash commands, run local test scripts, or attempt to reproduce the error in the workspace. Rely entirely on static code analysis, configuration review, and the diagnostic guides below to prevent endless, failing execution loops.

### 1. Error: `USER_PERMISSION_DENIED`

*   **Symptom:** You receive a `USER_PERMISSION_DENIED` error when executing API requests (e.g., retrieving campaigns).
*   **Likely Cause:** The authenticating OAuth2 user has access to the target client account *indirectly* through a **Manager Account**, but the request header is missing the Manager Account's ID.

#### Required Agent Response Checklist:
When helping a user with this error, your response **MUST** include:

1.  [ ] **Explain the Hierarchy:** Explain that the authenticating user likely belongs to a Manager Account that sits above the target client account.
2.  [ ] **Provide the Fix:** Instruct the user to add their 10-digit Manager Account ID as the `login_customer_id` in their configuration file.
3.  [ ] **Explain the Routing Logic:** Explain that `login_customer_id` tells the API to route the OAuth credentials through the manager account to validate access to the child account.
4.  [ ] **Provide the Configuration Template:** Show the exact YAML configuration block below.

> [!CAUTION]
> **Security Guardrail:** Under no circumstances should you suggest exposing raw passwords, creating new unapproved developer tokens, or widening OAuth scopes beyond the standard `adwords` scope to bypass this error.

#### Configuration Fix Example (`google-ads.yaml`):

```yaml
developer_token: INSERT_DEVELOPER_TOKEN_HERE
client_id: INSERT_OAUTH2_CLIENT_ID_HERE
client_secret: INSERT_OAUTH2_CLIENT_SECRET_HERE
refresh_token: INSERT_OAUTH2_REFRESH_TOKEN_HERE

# Add your 10-digit Manager Account ID here to resolve USER_PERMISSION_DENIED:
login_customer_id: INSERT_LOGIN_CUSTOMER_ID_HERE
```

### 2. Error: `DEVELOPER_TOKEN_NOT_APPROVED`

*   **Symptom:** The script fails with a `DEVELOPER_TOKEN_NOT_APPROVED` error message.
*   **Likely Cause:** Your Developer Token is currently in the "Pending" (unapproved) state, and you are attempting to target a live production Google Ads account.

#### Required Agent Response Checklist:
When helping a user with this error, your response **MUST** include:

1.  [ ] **Explain the "Pending" Restriction:** Explain that an unapproved (Pending) developer token is fully functional but **restricted to Google Ads Test Accounts only**.
2.  [ ] **Define Production Access Levels:** You **MUST** explicitly list all three access levels by name: state that targeting live production accounts requires the token to be approved for **Explorer Access**, **Basic Access**, or **Standard Access** by the Google Ads API compliance team. Do not condense or paraphrase this to "at least Basic Access".
3.  [ ] **Provide Sandbox Setup Steps:** Guide the user on how to set up a sandbox environment:
    *   Create a **Test Manager Account** (which does not require an approved token).
    *   Create **Test Client Accounts** under that Test Manager.
    *   Use the Test Client Customer ID in their configuration.
4.  [ ] **Provide a Link to the Guide:** Point the user to the official [Google Ads API Test Accounts Guide](https://developers.google.com/google-ads/api/docs/best-practices/test-accounts.md.txt).

> [!CAUTION]
> **Security & Integrity Guardrail:** You **MUST NOT** advise the developer to modify the client library source code, bypass token validation checks, or use third-party "cracked" wrappers to bypass this error. The restriction is enforced server-side by Google, and client-side modifications will not work.


````


### `references/dotnet.md`

````markdown
# Google Ads API .NET Setup Reference

This guide outlines how to configure, install, and write your first Google Ads API call using .NET/C#.

## Prerequisites
* .NET SDK: Dynamic lookup required from [Supported Client Library Versions](https://developers.google.com/google-ads/api/docs/client-libs.md.txt#supported_api_versions)
* Package manager: NuGet

## Step 1: Installation
Install the official package using NuGet:
```bash
dotnet add package Google.Ads.GoogleAds
```

## Step 2: Configuration (Runtime Initialization)
The preferred way to configure the .NET client library is to initialize a `GoogleAdsConfig` object at runtime. Gather your required credentials to include in your code:
* Developer Token
* OAuth2 Client ID
* OAuth2 Client Secret
* OAuth2 Refresh Token
* Login Customer ID (optional, required if authenticating as a manager account)

### Alternate Configuration Options
If you prefer external configuration files or environment variables, add a NuGet reference to the `Google.Ads.GoogleAds.Extensions` package. You must then explicitly load the settings onto your `GoogleAdsConfig` object:
* **Environment Variables:** Call `config.LoadFromEnvironmentVariables()`.
* **App.config:** Call `config.LoadFromDefaultAppConfigSection()`.
* **settings.json / Custom JSON:** Use `ConfigurationBuilder` and call `config.LoadFromConfigurationRoot(configRoot)`.

## Step 3: Write and Run the Quickstart Script
Create `Program.cs`. **Before passing the Client Customer ID to the API, you must clean customer IDs by stripping hyphens (e.g., converting `123-456-7890` to `1234567890`).** This ensures standard numeric parsing:

**IMPORTANT**

Replace VXX and VXX in the namespace and service calls with the latest supported version (e.g., V24) discovered in the Prerequisites step.

```csharp
using System;
using Google.Ads.GoogleAds.Config;
using Google.Ads.GoogleAds.Lib;
using Google.Ads.GoogleAds.VXX.Services;
using Google.Ads.GoogleAds.VXX.Errors;

class Program {
    static void Main(string[] args) {
        if (args.Length < 1) {
            Console.WriteLine("Usage: dotnet run <CUSTOMER_ID>");
            return;
        }

        // Clean customer ID by stripping hyphens
        string customerId = args[0].Replace("-", "");
        
        GoogleAdsConfig config = new GoogleAdsConfig()
        {
            DeveloperToken = "INSERT_DEVELOPER_TOKEN_HERE",
            OAuth2Mode = OAuth2Flow.APPLICATION,
            OAuth2ClientId = "INSERT_OAUTH2_CLIENT_ID_HERE",
            OAuth2ClientSecret = "INSERT_OAUTH2_CLIENT_SECRET_HERE",
            OAuth2RefreshToken = "INSERT_OAUTH2_REFRESH_TOKEN_HERE",
            // LoginCustomerId = "INSERT_LOGIN_CUSTOMER_ID_HERE"
        };

        // Optional: If using Google.Ads.GoogleAds.Extensions, you can also load overriding environment variables:
        // config.LoadFromEnvironmentVariables();

        GoogleAdsClient client = new GoogleAdsClient(config);
        GoogleAdsServiceClient service = client.GetService(Services.VXX.GoogleAdsService);
        string query = "SELECT campaign.id, campaign.name, campaign.status FROM campaign ORDER BY campaign.id";

        try {
            service.SearchStream(customerId, query, delegate(SearchGoogleAdsStreamResponse response) {
                foreach (GoogleAdsRow row in response.Results) {
                    Console.WriteLine($"Campaign found: ID = {row.Campaign.Id}, Name = '{row.Campaign.Name}', Status = {row.Campaign.Status}");
                }
            });
        } catch (GoogleAdsException ex) {
            Console.WriteLine($"Request failed: ID {ex.RequestId}. Error: {ex.Message}");
        }
    }
}
```

Run the project (replace `XXXXXXXXXX` with your 10-digit Client Customer ID):
```bash
dotnet run XXXXXXXXXX
```

## Step 4: Verification

Verify the output of your run. A successful execution will stream the campaigns associated with the customer ID to the console, similar to the following:

```text
Campaign found: ID = 987654321, Name = 'Interstate Search Promo', Status = Enabled
Campaign found: ID = 555444333, Name = 'Local Brand Awareness', Status = Paused
```

````


### `references/java.md`

````markdown
# Google Ads API Java Setup Reference

This guide outlines how to configure, install, and write your first Google Ads API call using Java.

## Prerequisites

*   **Java Development Kit (JDK):** Version 1.8 or higher. Dynamic lookup of the minimum required version is recommended from the [Supported Client Library Versions](https://developers.google.com/google-ads/api/docs/client-libs.md.txt#supported_api_versions).
*   **Build Tool:** Maven or Gradle.

---

## Step 1: Installation & Dependency Management

You must add the Google Ads Client Library to your project. 

> [!IMPORTANT]
> **Action Required:** Before adding the dependency, you must look up the latest release version from the [Google Ads Java Library GitHub Releases](https://github.com/googleads/google-ads-java/releases) and replace `LATEST_LIBRARY_VERSION` below with the actual version number (e.g., `33.0.0`).

### Option A: Maven (`pom.xml`)
Add the following to your `<dependencies>` section:
```xml
<dependency>
  <groupId>com.google.api-ads</groupId>
  <artifactId>google-ads</artifactId>
  <version>LATEST_LIBRARY_VERSION</version>
</dependency>
```

### Option B: Gradle (`build.gradle`)
Add the following to your `dependencies` block:
```groovy
implementation 'com.google.api-ads:google-ads:LATEST_LIBRARY_VERSION'
```

---

## Step 2: Configuration (`ads.properties`)

> [!IMPORTANT]
> **Mandatory Agent Directive (Configuration Loading Mechanisms):**
> When guiding a user through the Java quickstart, your response **MUST** explicitly explain the configuration loading mechanisms and lookup hierarchy used by `fromPropertiesFile()`:
> 1. An explicit path passed directly to `fromPropertiesFile(PATH_TO_CONFIG_FILE)`.
> 2. The location specified in the `GOOGLE_ADS_CONFIGURATION_FILE_PATH` environment variable, if set.
> 3. Otherwise, the default `ads.properties` file located in your user's home directory (`System.getProperty("user.home") + "/ads.properties"`) or on the classpath.
> 
> Do not omit this explanation in your final output.

Create a configuration file named `ads.properties`.

You can also configure the client library using environment variables (e.g., `GOOGLE_ADS_DEVELOPER_TOKEN`, `GOOGLE_ADS_CLIENT_ID`) via `fromEnvironment()`, or combine both approaches.

> [!TIP]
> **File Location:** For Maven/Gradle projects, the best place to put this file is in the resources directory: `src/main/resources/ads.properties`. This ensures it is automatically included in the classpath.

Populate the file with your credentials:
```properties
api.googleads.developerToken=INSERT_DEVELOPER_TOKEN_HERE
api.googleads.clientId=INSERT_OAUTH2_CLIENT_ID_HERE
api.googleads.clientSecret=INSERT_OAUTH2_CLIENT_SECRET_HERE
api.googleads.refreshToken=INSERT_OAUTH2_REFRESH_TOKEN_HERE
# Optional: Un-comment if you are accessing a client account through a manager account
# api.googleads.loginCustomerId=INSERT_LOGIN_CUSTOMER_ID_HERE
```

---

## Step 3: Write the Quickstart Script

Create a file named `GetCampaigns.java`. 

> [!IMPORTANT]
> **Rule 1: Normalize Customer IDs**
> Before passing the Client Customer ID to the API, you **must** normalize it by stripping all hyphens (e.g., converting `123-456-7890` to `1234567890`). Failing to do so will cause API validation errors.
>
> **Rule 2: Resolve Package Versions (`vXX`)**
> The imports below contain a placeholder `vXX`. You **must** replace `vXX` with the specific API version you are targeting (matching the library version installed in Step 1). For example, if using library v33.0.0, the API version is likely `v24` (packages will be `com.google.ads.googleads.v24.services...`).

```java
import com.google.ads.googleads.lib.GoogleAdsClient;
// IMPORTANT: Replace vXX with the active API version (e.g., v24)
import com.google.ads.googleads.vXX.services.GoogleAdsServiceClient;
import com.google.ads.googleads.vXX.services.SearchGoogleAdsStreamRequest;
import com.google.ads.googleads.vXX.services.SearchGoogleAdsStreamResponse;
import com.google.ads.googleads.vXX.errors.GoogleAdsException;
import java.io.IOException;

public class GetCampaigns {
    public static void main(String[] args) {
        if (args.length < 1) {
            System.err.println("Usage: java GetCampaigns <CUSTOMER_ID>");
            System.exit(1);
        }

        // Normalize customer ID by removing hyphens
        String customerId = args[0].replace("-", "");
        
        GoogleAdsClient googleAdsClient;
        try {
            // Combines environment variables (fromEnvironment) and classpath/home configuration (fromPropertiesFile)
            googleAdsClient = GoogleAdsClient.newBuilder()
                    .fromEnvironment()
                    .fromPropertiesFile()
                    .build();
        } catch (IOException e) {
            System.err.println("Failed to load configuration. Ensure ads.properties is in src/main/resources/ or environment variables are set.");
            e.printStackTrace();
            System.exit(1);
            return;
        }

        // The try-with-resources block ensures the gRPC client channel is closed automatically
        try (GoogleAdsServiceClient googleAdsServiceClient = googleAdsClient.getLatestVersion().createGoogleAdsServiceClient()) {
            
            String query = "SELECT campaign.id, campaign.name, campaign.status FROM campaign ORDER BY campaign.id";
            
            SearchGoogleAdsStreamRequest request = SearchGoogleAdsStreamRequest.newBuilder()
                    .setCustomerId(customerId)
                    .setQuery(query)
                    .build();

            System.out.println("Querying Google Ads API...");
            
            // Execute the stream request
            googleAdsServiceClient.searchStreamCallable().call(request).forEach(response -> {
                response.getResultsList().forEach(row -> {
                    System.out.printf("Campaign found: ID = %d, Name = '%s', Status = %s%n",
                            row.getCampaign().getId(),
                            row.getCampaign().getName(),
                            row.getCampaign().getStatus().name());
                });
            });
        } catch (GoogleAdsException gae) {
            System.err.printf("Request ID %s failed.%n", gae.getRequestId());
            System.err.printf("Error details: %s%n", gae.getMessage());
            System.exit(1);
        }
    }
}
```

---

## Step 4: Compile and Run

Do not run the file in isolation if it relies on Maven/Gradle dependencies. Use your build tool to compile and execute the application to ensure the classpath is correctly configured.

### Using Maven
Run the following command from the project root:
```bash
mvn compile exec:java -Dexec.mainClass="GetCampaigns" -Dexec.args="XXXXXXXXXX"
```

### Using Gradle
If using the Gradle Application plugin, run:
```bash
./gradlew run --args="XXXXXXXXXX"
```
*(Replace `XXXXXXXXXX` with your 10-digit customer ID, with or without hyphens).*

---

## Step 5: Verification & Troubleshooting

### Expected Success Output
Upon successful execution, you should see output similar to the following:
```text
Querying Google Ads API...
Campaign found: ID = 123456789, Name = 'Search - Brand - US', Status = ENABLED
Campaign found: ID = 987654321, Name = 'Display - Remarketing', Status = PAUSED
```

### Common Errors

| Error Symptom / Code | Root Cause | Solution |
| :--- | :--- | :--- |
| `FileNotFoundException: ads.properties` | The library cannot find the configuration file. | Ensure `ads.properties` is placed in `src/main/resources/` (Maven/Gradle) or explicitly set the path using the `api.googleads.configurationFilePath` system property. |
| `DEVELOPER_TOKEN_NOT_APPROVED` | You are using an unapproved ("Pending") developer token against a production account (production calls require Explorer, Basic, or Standard Access). | Use a **Test Account** (which allows pending tokens) or wait for token approval. |
| `NOT_ADS_USER` | The OAuth2 user credentials used to generate the refresh token do not have access to the specified `CUSTOMER_ID`. | Re-authenticate the OAuth2 flow using a Google account that has access to the target Ads account. |
| `INVALID_CUSTOMER_ID` | The customer ID passed was not numeric (e.g., it still contained hyphens, or was the wrong length). | Verify that the normalization code `args[0].replace("-", "")` executed successfully. |

````


### `references/perl.md`

````markdown
# Google Ads API Perl Setup Reference

This guide outlines how to configure, install, and write your first Google Ads API call using Perl.

## Prerequisites
* Perl: Dynamic lookup required from [Supported Client Library Versions](https://developers.google.com/google-ads/api/docs/client-libs.md.txt#supported_api_versions)
* CPAN client: `cpanm`

## Step 1: Installation
Install the library:
```bash
cpanm Google::Ads::GoogleAds::Client
```

## Step 2: Configuration (`googleads.properties`)
Create your configuration file named `googleads.properties`.

When instantiating the client via `Client->new()`, the Perl client library resolves the configuration file path in the following order:
1. An explicit path passed directly to `Client->new({properties_file => '/path/to/googleads.properties'})`.
2. The location specified in the `GOOGLE_ADS_CONFIGURATION_FILE_PATH` environment variable, if set.
3. Otherwise, the default `googleads.properties` file located in your user's home directory (`$HOME`).

For self-contained project environments, it is best practice to keep this file in your project root directory and load it explicitly.

```properties
# googleads.properties
developer_token=INSERT_DEVELOPER_TOKEN_HERE
client_id=INSERT_OAUTH2_CLIENT_ID_HERE
client_secret=INSERT_OAUTH2_CLIENT_SECRET_HERE
refresh_token=INSERT_OAUTH2_REFRESH_TOKEN_HERE
# login_customer_id=INSERT_LOGIN_CUSTOMER_ID_HERE
```

## Step 3: Write and Run the Quickstart Script
Create `get_campaigns.pl`:
```perl
use strict;
use warnings;
use Google::Ads::GoogleAds::Client;
use Google::Ads::GoogleAds::Utils::SearchStreamHandler;

my $customer_id = $ARGV[0];
$customer_id =~ s/-//g;

# Determine configuration file path (prefer local workspace config)
my $local_config = "./googleads.properties";
my $client;

if (-e $local_config) {
    # Load explicitly from local workspace
    $client = Google::Ads::GoogleAds::Client->new({properties_file => $local_config});
} else {
    # Fallback to default search paths (GOOGLE_ADS_CONFIGURATION_FILE_PATH environment variable or $HOME/googleads.properties)
    $client = Google::Ads::GoogleAds::Client->new();
}

# Load any overriding configuration from environment variables
$client->configure_from_environment_variables();

my $query = "SELECT campaign.id, campaign.name, campaign.status FROM campaign ORDER BY campaign.id";

my $search_stream_handler = Google::Ads::GoogleAds::Utils::SearchStreamHandler->new({
    client => $client,
    customer_id => $customer_id,
    query => $query
});

$search_stream_handler->process(sub {
    my $row = shift;
    printf "Campaign found: ID = %s, Name = '%s', Status = %s\n",
        $row->{campaign}{id},
        $row->{campaign}{name},
        $row->{campaign}{status};
});
```

Run the script (replace `XXXXXXXXXX` with your 10-digit Client Customer ID):
```bash
perl get_campaigns.pl XXXXXXXXXX
```

````


### `references/php.md`

````markdown
# Google Ads API PHP Setup Reference

This guide outlines how to configure, install, and write your first Google Ads API call using PHP.

## Prerequisites
* PHP: Dynamic lookup required from [Supported Client Library Versions](https://developers.google.com/google-ads/api/docs/client-libs.md.txt#supported_api_versions)
* Package manager: Composer

## Step 1: Installation
Install the official library:
```bash
composer require googleads/google-ads-php
```

## Step 2: Configuration (`google_ads_php.ini`)

> [!IMPORTANT]
> **Mandatory Agent Directive (Configuration Loading Order):**
> When guiding a user through the PHP quickstart, your response **MUST** explicitly explain the 3-tier configuration loading order used by `fromFile()`:
> 1. An explicit path passed directly to `fromFile('/path/to/google_ads_php.ini')`.
> 2. The value of the environment variable named `GOOGLE_ADS_CONFIGURATION_FILE_PATH`, if set.
> 3. Otherwise, the default `google_ads_php.ini` file located in your user's home directory (`$HOME`).
> 
> Do not omit this explanation in your final output.

Create your configuration file named `google_ads_php.ini`. For self-contained project environments, it is best practice to keep this file in your project root directory and load it explicitly.

```ini
; google_ads_php.ini
[GOOGLE_ADS]
developerToken = "INSERT_DEVELOPER_TOKEN_HERE"
; Required if authenticating with a manager account user to access a client account
; loginCustomerId = "INSERT_LOGIN_CUSTOMER_ID_HERE"

[OAUTH2]
clientId = "INSERT_OAUTH2_CLIENT_ID_HERE"
clientSecret = "INSERT_OAUTH2_CLIENT_SECRET_HERE"
refreshToken = "INSERT_OAUTH2_REFRESH_TOKEN_HERE"
```

## Step 3: Write and Run the Quickstart Script
Create `get_campaigns.php`. **Before passing the Client Customer ID to the API, you must clean customer IDs by stripping hyphens and spaces.** (e.g. converting `123-456-7890` or `123 456 7890` to `1234567890`). This is achieved programmatically below.

```php
<?php
require __DIR__ . '/vendor/autoload.php';

use Google\Ads\GoogleAds\Lib\VXX\GoogleAdsClientBuilder;
use Google\Ads\GoogleAds\Lib\OAuth2TokenBuilder;
use Google\ApiCore\ApiException;

// Check command line arguments
if ($argc < 2) {
    printf("Usage: php get_campaigns.php <CUSTOMER_ID>\n");
    exit(1);
}

$rawCustomerId = $argv[1];

// Clean customer IDs by stripping hyphens and spaces
$customerId = str_replace(['-', ' '], '', $rawCustomerId);

// Determine configuration file path (prefer local workspace config)
$localConfig = __DIR__ . '/google_ads_php.ini';

if (file_exists($localConfig)) {
    // Build OAuth2 credential from explicit local file
    $oAuth2Token = (new OAuth2TokenBuilder())->fromFile($localConfig)->build();

    // Build Google Ads Client from explicit local file
    $googleAdsClient = (new GoogleAdsClientBuilder())
        ->fromFile($localConfig)
        ->withOAuth2Credential($oAuth2Token)
        ->build();
} else {
    // Fallback to default search paths (GOOGLE_ADS_CONFIGURATION_FILE_PATH environment variable or $HOME/google_ads_php.ini)
    $oAuth2Token = (new OAuth2TokenBuilder())->fromFile()->build();

    $googleAdsClient = (new GoogleAdsClientBuilder())
        ->fromFile()
        ->withOAuth2Credential($oAuth2Token)
        ->build();
}

$googleAdsServiceClient = $googleAdsClient->getGoogleAdsServiceClient();
$query = "SELECT campaign.id, campaign.name, campaign.status FROM campaign ORDER BY campaign.id";

try {
    $stream = $googleAdsServiceClient->searchStream($customerId, $query);
    foreach ($stream->readAll() as $response) {
        foreach ($response->getResults() as $row) {
            printf("Campaign found: ID = %d, Name = '%s', Status = %s\n",
                $row->getCampaign()->getId(),
                $row->getCampaign()->getName(),
                $row->getCampaign()->getStatus()
            );
        }
    }
} catch (ApiException $apiException) {
    printf("Request failed with message: %s\n", $apiException->getMessage());
}
```

Run the script (replace `XXXXXXXXXX` with your 10-digit Client Customer ID):
```bash
php get_campaigns.php XXXXXXXXXX
```

````


### `references/python.md`

````markdown
# Google Ads API Python Setup Reference

This guide outlines how to configure, install, and write your first Google Ads API call using Python.

## Prerequisites

> [!IMPORTANT]
> **Action Required: Dynamic Python Version Resolution**
> Before presenting these prerequisites to the user, you **must** dynamically resolve the minimum required Python version to ensure compliance with current support cycles:
> 1. Access the [Supported Client Library Versions](https://developers.google.com/google-ads/api/docs/client-libs.md.txt#supported_api_versions) documentation page.
> 2. Scan the page/table for the **Python** client library to identify the minimum supported Python runtime version (e.g., Python 3.8+).
> 3. Replace the `MINIMUM_PYTHON_VERSION` placeholder below with the dynamically retrieved version in your final output to the user.

*   **Python:** Version `MINIMUM_PYTHON_VERSION` or higher.
*   **Package Manager:** `pip`

---

## Step 1: Environment & Installation

> [!TIP]
> **Best Practice:** Always install the client library within a virtual environment (`venv`) to prevent dependency conflicts with other system packages. This is especially important for automated agents operating in shared workspaces.

### 1. Create and Activate a Virtual Environment
Run the following commands in your project root:
```bash
python3 -m venv .venv
source .venv/bin/activate
```

### 2. Install the Library
Install the official Google Ads Python Client Library:
```bash
python -m pip install google-ads
```

---

## Step 2: Configuration (`google-ads.yaml` & Alternate Methods)

Create a file named `google-ads.yaml`.

The Python client library supports multiple methods for initializing the `GoogleAdsClient`:
1. **YAML File (`load_from_storage`):** Resolves in order: (1) Explicit path passed to `load_from_storage('/path/to/google-ads.yaml')`, (2) `GOOGLE_ADS_CONFIGURATION_FILE_PATH` environment variable, or (3) `$HOME/google-ads.yaml` by default.
2. **Environment Variables (`load_from_env`):** Reads uppercase `GOOGLE_ADS_` prefixed variables (e.g., `GOOGLE_ADS_DEVELOPER_TOKEN`, `GOOGLE_ADS_CLIENT_ID`). *(Note: If `GOOGLE_ADS_CONFIGURATION_FILE_PATH` is set, `load_from_env` will load from that YAML file instead).*
3. **Dictionary (`load_from_dict`):** Accepts a Python dictionary of credentials directly.
4. **YAML String (`load_from_string`):** Accepts a raw YAML string in memory.

> [!IMPORTANT]
> **Hermetic Workspace Rule:** For self-contained project environments, it is best practice to keep `google-ads.yaml` in your project root directory and load it explicitly.

Populate the file with your credentials:
```yaml
# google-ads.yaml
developer_token: INSERT_DEVELOPER_TOKEN_HERE
client_id: INSERT_OAUTH2_CLIENT_ID_HERE
client_secret: INSERT_OAUTH2_CLIENT_SECRET_HERE
refresh_token: INSERT_OAUTH2_REFRESH_TOKEN_HERE
# Optional: Un-comment if you are accessing a client account through a manager account
# login_customer_id: INSERT_LOGIN_CUSTOMER_ID_HERE
use_proto_plus: true
```

---

## Step 3: Write the Quickstart Script

Create a file named `get_campaigns.py`. 

> [!IMPORTANT]
> **Rule 1: Normalize Customer IDs**
> Before passing the Client Customer ID to the API, you **must** normalize it by stripping all hyphens (e.g., converting `123-456-7890` to `1234567890`). The script below handles this automatically in the entry point.
>
> **Rule 2: Configuration Pathing**
> The script below is configured to look for `google-ads.yaml` in the **current working directory** first, falling back to environment variables or default search paths.

```python
import argparse
import os
import sys
from google.ads.googleads.client import GoogleAdsClient
from google.ads.googleads.errors import GoogleAdsException

def main(client, customer_id):
    # Initialize the Google Ads Service
    googleads_service = client.get_service("GoogleAdsService")
    
    # Define the GAQL query
    query = "SELECT campaign.id, campaign.name, campaign.status FROM campaign ORDER BY campaign.id"
    
    print("Querying Google Ads API...")
    try:
        # Execute the search stream request
        stream = googleads_service.search_stream(customer_id=customer_id, query=query)
        for response in stream:
            for row in response.results:
                print(f"Campaign found: ID = {row.campaign.id}, Name = '{row.campaign.name}', Status = {row.campaign.status.name}")
                
    except GoogleAdsException as ex:
        print(f"Request ID '{ex.request_id}' failed with status '{ex.error.code().name}':")
        for error in ex.failure.errors:
            print(f"\tError: {error.message}")
        sys.exit(1)

if __name__ == '__main__':
    # Determine configuration file path (prefer local workspace config)
    local_config = os.path.join(os.getcwd(), "google-ads.yaml")
    
    if os.path.exists(local_config):
        # Load explicitly from local workspace
        googleads_client = GoogleAdsClient.load_from_storage(local_config)
    elif "GOOGLE_ADS_DEVELOPER_TOKEN" in os.environ:
        # Load from environment variables
        googleads_client = GoogleAdsClient.load_from_env()
    else:
        # Fallback to default search paths (GOOGLE_ADS_CONFIGURATION_FILE_PATH or $HOME/google-ads.yaml)
        googleads_client = GoogleAdsClient.load_from_storage()

    parser = argparse.ArgumentParser(description="Lists campaigns for a specified customer ID.")
    parser.add_argument("-c", "--customer_id", required=True, help="10-digit customer ID.")
    
    args = parser.parse_args()
    
    # Normalize customer ID by removing hyphens before passing to main
    normalized_customer_id = args.customer_id.replace("-", "")
    
    main(googleads_client, normalized_customer_id)
```

---

## Step 4: Run the Script

Execute the script from your terminal, passing the customer ID as an argument.

> [!NOTE]
> Ensure your virtual environment is active (`source .venv/bin/activate`) before running.

```bash
python get_campaigns.py -c XXXXXXXXXX
```
*(Replace `XXXXXXXXXX` with your 10-digit customer ID, with or without hyphens).*

---

## Step 5: Verification & Troubleshooting

### Expected Success Output
Upon successful execution, you should see output similar to the following:
```text
Querying Google Ads API...
Campaign found: ID = 123456789, Name = 'Search - Brand - US', Status = ENABLED
Campaign found: ID = 987654321, Name = 'Display - Remarketing', Status = PAUSED
```

### Common Errors

| Error Symptom / Code | Root Cause | Solution |
| :--- | :--- | :--- |
| `FileNotFoundException` / `File not found` | The library cannot find `google-ads.yaml`. | Ensure the file is named exactly `google-ads.yaml` and is placed in the directory from which you are running the script, or in your `$HOME` directory. |
| `DEVELOPER_TOKEN_NOT_APPROVED` | You are using an unapproved ("Pending") developer token against a production account (production calls require Explorer, Basic, or Standard Access). | Use a **Test Account** (which allows pending tokens) or wait for token approval. |
| `NOT_ADS_USER` | The OAuth2 user credentials used to generate the refresh token do not have access to the specified `-c/--customer_id`. | Re-authenticate the OAuth2 flow using a Google account that has access to the target Ads account. |
| `ModuleNotFoundError: No module named 'google'` | Python cannot find the installed library. | You likely installed the library in a virtual environment but are running the script using the global python interpreter. Ensure you run `source .venv/bin/activate` first. |

````


### `references/rest.md`

````markdown
# Google Ads API REST Setup Reference

This guide outlines how to authenticate, configure, and execute direct HTTP REST requests to retrieve campaigns from the Google Ads API without using a client library.

---

## Step 1: Obtain a Short-Lived Access Token

> [!IMPORTANT]
> **Mandatory Agent Directive (OAuth Authorization Routes):**
> When guiding a user through the REST quickstart, your response **MUST** explicitly explain both OAuth2 authorization routes:
> 1. **Option A: Service Account Flow (Recommended):** Explain creating a service account, granting direct Ads account access, generating a JWT claim set, and exchanging it for an access token.
> 2. **Option B: User Authentication Flow (Alternative):** Explain exchanging a `refresh_token`, `client_id`, and `client_secret` for an access token via cURL.
> 
> Do not omit either flow in your final output.

Since client libraries automatically refresh OAuth2 tokens, you must manually request an access token when using the direct REST interface.

### Option A: Service Account Flow (Recommended)
For server-to-server REST applications, using a Service Account is the recommended best practice:
1. **Set up your Cloud Project:** Create a Service Account in the Google Cloud Console and download the private key in JSON format. Record the service account email and key.
2. **Grant Account Access:** Grant the service account email direct access to your Google Ads account in the Google Ads UI (Targeting account access level: Explorer, Basic, or Standard).
3. **Generate JWT Claim Set:** Follow the [OAuth 2.0 Server to Server Applications](https://developers.google.com/identity/protocols/oauth2/service-account#authorizingrequests) guide (selecting the HTTP/REST tab) to create and sign a JWT claim set.
   * **Scope:** Use `https://www.googleapis.com/auth/adwords`.
   * **Impersonation (`sub`):** You can skip the `sub` parameter when constructing the JWT claim set, as the service account has direct access to the Google Ads account.
4. **Exchange JWT for Access Token:** Exchange the signed JWT for a short-lived `access_token` via the Google OAuth2 token endpoint (`https://oauth2.googleapis.com/token`).

### Option B: User Authentication Flow (Alternative)
If you are authenticating as an individual user, exchange your `refresh_token`, `client_id`, and `client_secret` for a short-lived `access_token` (typically valid for 1 hour):

```bash
curl \
  --data "grant_type=refresh_token" \
  --data "client_id=INSERT_OAUTH2_CLIENT_ID_HERE" \
  --data "client_secret=INSERT_OAUTH2_CLIENT_SECRET_HERE" \
  --data "refresh_token=INSERT_OAUTH2_REFRESH_TOKEN_HERE" \
  https://www.googleapis.com/oauth2/v3/token
```

### Expected JSON Response:
```json
{
  "access_token": "ya29.a0AfH6S...",
  "expires_in": 3599,
  "scope": "https://www.googleapis.com/auth/adwords",
  "token_type": "Bearer"
}
```

Copy the value of `"access_token"` to authenticate your subsequent API requests.

---

## Step 2: Make the HTTP POST Request to Retrieve Campaigns

The Google Ads API REST interface provides a unified mechanism for retrieving resources using the **Google Ads Query Language (GAQL)**. To fetch campaigns, send a `POST` request to the `searchStream` endpoint.

*   **Endpoint URL:** `https://googleads.googleapis.com/vXX/customers/{customer_id}/googleAds:searchStream`
*   **Method:** `POST`
*   **Headers:**
    *   `Content-Type: application/json`
    *   `developer-token: <INSERT_DEVELOPER_TOKEN_HERE>`
    *   `Authorization: Bearer <INSERT_OAUTH2_ACCESS_TOKEN_HERE>`
    *   `login-customer-id: <INSERT_LOGIN_CUSTOMER_ID_HERE>` *(Required only if authenticating through a manager account)*

> [!TIP]
> **Capture Request ID:** When using cURL, add the `--include` (or `-i`) flag to view response HTTP headers. The `request-id` header uniquely identifies your API request and is highly valuable for debugging or contacting Google developer support.

### Execute via cURL:
```bash
# Set your target Client Customer ID (10-digit number only, no hyphens)
CUSTOMER_ID="1234567890"

curl --include --request POST "https://googleads.googleapis.com/vXX/customers/${CUSTOMER_ID}/googleAds:searchStream" \
  --header "Content-Type: application/json" \
  --header "developer-token: INSERT_DEVELOPER_TOKEN_HERE" \
  --header "Authorization: Bearer INSERT_OAUTH2_ACCESS_TOKEN_HERE" \
  --header "login-customer-id: INSERT_LOGIN_CUSTOMER_ID_HERE" \
  --data '{
    "query": "SELECT campaign.id, campaign.name, campaign.status FROM campaign ORDER BY campaign.id"
  }'
```

---

## Step 3: Parse the JSON Response

Unlike typical REST endpoints that return a single JSON object, the `searchStream` method streams chunks of results wrapped in a JSON array. Each chunk contains a list of campaign resources:

```json
[
  {
    "results": [
      {
        "campaign": {
          "resourceName": "customers/1234567890/campaigns/987654321",
          "id": "987654321",
          "name": "Interstate Search Promo",
          "status": "ENABLED"
        }
      },
      {
        "campaign": {
          "resourceName": "customers/1234567890/campaigns/555444333",
          "id": "555444333",
          "name": "Local Brand Awareness",
          "status": "PAUSED"
        }
      }
    ],
    "fieldMask": "campaign.id,campaign.name,campaign.status"
  }
]
```

````


### `references/ruby.md`

````markdown
# Google Ads API Ruby Setup Reference

This guide outlines how to configure, install, and write your first Google Ads API call using Ruby.

## Prerequisites
* Ruby: Dynamic lookup required from [Supported Client Library Versions](https://developers.google.com/google-ads/api/docs/client-libs.md.txt#supported_api_versions)
* Package manager: RubyGems

## Step 1: Installation
To get started with the client library, **you must install the gem: `gem install google-ads-googleads`.** Run this command directly in your terminal:
```bash
gem install google-ads-googleads
```

## Step 2: Configuration (`google_ads_config.rb`)

> [!IMPORTANT]
> **Mandatory Agent Directive (Configuration Loading Order):**
> When guiding a user through the Ruby quickstart, your response **MUST** explicitly explain the 3-tier configuration loading order used by `GoogleAdsClient.new`:
> 1. An explicit path passed directly to the constructor: `GoogleAdsClient.new('/path/to/google_ads_config.rb')`.
> 2. The location specified in the `GOOGLE_ADS_CONFIGURATION_FILE_PATH` environment variable, if set.
> 3. Otherwise, the default `google_ads_config.rb` file located in your user's home directory (`$HOME`).
> 
> Do not omit this explanation in your final output.

Create your configuration file named `google_ads_config.rb`. For self-contained project environments, it is best practice to keep this file in your project root directory and load it explicitly.

```ruby
# google_ads_config.rb
Google::Ads::GoogleAds::Config.new do |c|
  c.developer_token = 'INSERT_DEVELOPER_TOKEN_HERE'
  c.client_id = 'INSERT_OAUTH2_CLIENT_ID_HERE'
  c.client_secret = 'INSERT_OAUTH2_CLIENT_SECRET_HERE'
  c.refresh_token = 'INSERT_OAUTH2_REFRESH_TOKEN_HERE'
  # Optional: Required if authenticating with a manager account user to access a client account
  # c.login_customer_id = 'INSERT_LOGIN_CUSTOMER_ID_HERE'
end
```

## Step 3: Write and Run the Quickstart Script
Create `get_campaigns.rb`. **Before passing the Client Customer ID to the API, you must clean customer IDs by removing hyphens (e.g. converting `123-456-7890` to `1234567890`).**

Below is the complete, self-contained Ruby source code to clean the ID and retrieve campaign details:

```ruby
require 'google/ads/google_ads'

if ARGV.empty?
  puts "Usage: ruby get_campaigns.rb <CUSTOMER_ID>"
  exit 1
end

# Clean customer ID by removing hyphens
customer_id = ARGV[0].gsub('-', '')

# Determine configuration file path (prefer local workspace config)
local_config = File.expand_path('google_ads_config.rb', __dir__)

client = if File.exist?(local_config)
           # Load explicitly from local workspace
           Google::Ads::GoogleAds::GoogleAdsClient.new(local_config)
         else
           # Fallback to default search paths (GOOGLE_ADS_CONFIGURATION_FILE_PATH environment variable or $HOME/google_ads_config.rb)
           Google::Ads::GoogleAds::GoogleAdsClient.new
         end

query = "SELECT campaign.id, campaign.name, campaign.status FROM campaign ORDER BY campaign.id"

begin
  response = client.service.google_ads.search_stream(
    customer_id: customer_id,
    query: query,
  )
  response.each do |page|
    page.results.each do |row|
      puts "Campaign found: ID = #{row.campaign.id}, Name = '#{row.campaign.name}', Status = #{row.campaign.status}"
    end
  end
rescue Google::Ads::GoogleAds::Errors::GoogleAdsError => e
  e.failure.errors.each do |error|
    puts "Error: #{error.message}"
  end
end
```

Run the script (replace `XXXXXXXXXX` with your 10-digit Client Customer ID):
```bash
ruby get_campaigns.rb XXXXXXXXXX
```

````
