> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gloo.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Completions with Tool Use

> Learn how to extend model capabilities via the Completions API with tool use.

This recipe provides an example of Completions API tool use for structured output. Instead of receiving unstructured text responses, you can force the AI to return predictable, machine-readable data that your application can easily parse and use.

We'll build a goal-setting assistant that takes a user's goal in plain English and returns a structured growth plan with actionable steps and timelines.

<Warning>
  **Completions V1 is Deprecated**: This tutorial now uses the V2 API. If you're using V1 (`/ai/v1/chat/completions`), please migrate to V2 for better performance and intelligent routing.

  [View V2 Guide](/api-guides/completions-v2) | [Migration Steps](/api-guides/completions-v2#migrating-from-completions-v1)
</Warning>

## Prerequisites

Before starting, ensure you have:

* A Gloo AI Studio account
* Your Client ID and Client Secret from the [API Credentials page](/studio/manage-api-credentials)
* **Authentication setup** - Complete the [Authentication Tutorial](/tutorials/authentication) first

<Info>
  The Completions API with tool use requires Bearer token authentication. If you haven't set up authentication yet, follow the [Authentication Tutorial](/tutorials/authentication) to learn how to exchange your credentials for access tokens and manage token expiration.
</Info>

***

## Step 1: Define Your Tool Schema

The first step is to define a function schema that describes the structured output you want. This tells the AI exactly what format to return:

```json theme={null}
{
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "create_growth_plan",
        "description": "Creates a structured personal growth plan with a title and a series of actionable steps.",
        "parameters": {
          "type": "object",
          "properties": {
            "goal_title": {
              "type": "string",
              "description": "A concise, encouraging title for the user's goal."
            },
            "steps": {
              "type": "array",
              "description": "A list of concrete steps the user should take.",
              "items": {
                "type": "object",
                "properties": {
                  "step_number": { "type": "integer" },
                  "action": {
                    "type": "string",
                    "description": "The specific, actionable task for this step."
                  },
                  "timeline": {
                    "type": "string",
                    "description": "A suggested timeframe for this step (e.g., 'Week 1-2')."
                  }
                },
                "required": ["step_number", "action", "timeline"]
              }
            }
          },
          "required": ["goal_title", "steps"]
        }
      }
    }
  ]
}
```

***

## Step 2: Make the API Call

Now make the API request with the tool definition and set `tool_choice: "required"` to force the AI to use your tool:

```json theme={null}
{
  "auto_routing": true,
  "messages": [
    {
      "role": "user",
      "content": "I want to grow in my faith."
    }
  ],
  "tools": [
    // ... The tool definition from Step 1 goes here ...
  ],
  "tool_choice": "required"
}
```

<Info>
  **Auto-Routing**: Setting `auto_routing: true` lets Gloo AI automatically select the optimal model for your tool use request. This is the recommended V2 approach. You can also specify a direct model like `"model": "gloo-anthropic-claude-sonnet-4.5"` if you need explicit control.
</Info>

### Example Response

The API will return structured data in the `tool_calls` array:

```json theme={null}
{
  "id": "chatcmpl-ecc49558",
  "choices": [
    {
      "finish_reason": "tool_calls",
      "index": 0,
      "message": {
        "content": null,
        "role": "assistant",
        "tool_calls": [
          {
            "id": "tooluse_c0lmjtOJSlOYQZPBsp4biQ",
            "function": {
              "arguments": "{\"goal_title\": \"Growing Deeper in Faith\", \"steps\": [{\"step_number\": 1, \"action\": \"Establish a consistent daily quiet time with God through prayer and Bible reading, starting with 10-15 minutes each morning\", \"timeline\": \"Week 1-2\"}, {\"step_number\": 2, \"action\": \"Choose a Bible reading plan or devotional to provide structure for your study time\", \"timeline\": \"Week 2-3\"}, {\"step_number\": 3, \"action\": \"Find a local church community or small group where you can worship, learn, and build relationships with other believers\", \"timeline\": \"Week 3-4\"}, {\"step_number\": 4, \"action\": \"Begin journaling your prayers, thoughts, and insights from Scripture to track your spiritual growth\", \"timeline\": \"Week 4-5\"}, {\"step_number\": 5, \"action\": \"Look for opportunities to serve others in your community or church as a way to live out your faith\", \"timeline\": \"Month 2\"}, {\"step_number\": 6, \"action\": \"Seek out a mentor or accountability partner who can encourage you and help you grow in your walk with God\", \"timeline\": \"Month 2-3\"}]}",
              "name": "create_growth_plan"
            },
            "type": "function"
          }
        ]
      }
    }
  ],
  "created": 1755118870,
  "model": "gloo-anthropic-claude-sonnet-4.5",
  "object": "chat.completion",
  "usage": {
    "completion_tokens": 391,
    "prompt_tokens": 1631,
    "total_tokens": 2022
  }
}
```

Notice how the `arguments` field contains a JSON string that matches your tool schema perfectly!

***

## Complete Examples

The following examples combine token retrieval, expiration checking, making the API call with tool use, and parsing the structured response into a complete, runnable script for each language.

You'll want to first set up your environment variables in either an `.env` file:

```
GLOO_CLIENT_ID=YOUR_CLIENT_ID
GLOO_CLIENT_SECRET=YOUR_CLIENT_SECRET
```

Or export them in your shell for Go and Java:

```bash theme={null}
export GLOO_CLIENT_ID="your_actual_client_id_here"
export GLOO_CLIENT_SECRET="your_actual_client_secret_here"
```

<CodeGroup>
  ```python Python theme={null}
  import requests
  import time
  import json
  import os
  from dotenv import load_dotenv

  # Load environment variables from .env file
  load_dotenv()

  # --- Configuration ---
  # It's recommended to load credentials from environment variables
  CLIENT_ID = os.getenv("GLOO_CLIENT_ID", "YOUR_CLIENT_ID")
  CLIENT_SECRET = os.getenv("GLOO_CLIENT_SECRET", "YOUR_CLIENT_SECRET")
  TOKEN_URL = "https://platform.ai.gloo.com/oauth2/token"
  API_URL = "https://platform.ai.gloo.com/ai/v2/chat/completions"

  # --- State Management ---
  # In a real application, you would persist this token information
  access_token_info = {}

  def get_access_token():
      """Retrieves a new access token."""
      headers = {"Content-Type": "application/x-www-form-urlencoded"}
      data = {"grant_type": "client_credentials", "scope": "api/access"}
      response = requests.post(TOKEN_URL, headers=headers, data=data, auth=(CLIENT_ID, CLIENT_SECRET))
      response.raise_for_status()
      token_data = response.json()
      token_data['expires_at'] = int(time.time()) + token_data['expires_in']
      return token_data

  def is_token_expired(token_info):
      """Checks if the token is expired or close to expiring."""
      if not token_info or 'expires_at' not in token_info:
          return True
      return time.time() > (token_info['expires_at'] - 60)

  def create_goal_setting_request(user_goal):
      """Creates a goal-setting request with tool use."""
      global access_token_info
      if is_token_expired(access_token_info):
          print("Token is expired or missing. Fetching a new one...")
          access_token_info = get_access_token()

      headers = {
          "Authorization": f"Bearer {access_token_info['access_token']}",
          "Content-Type": "application/json"
      }

      payload = {
          "auto_routing": True,
          "messages": [{"role": "user", "content": user_goal}],
          "tools": [
              {
                  "type": "function",
                  "function": {
                      "name": "create_growth_plan",
                      "description": "Creates a structured personal growth plan with a title and a series of actionable steps.",
                      "parameters": {
                          "type": "object",
                          "properties": {
                              "goal_title": {
                                  "type": "string",
                                  "description": "A concise, encouraging title for the user's goal."
                              },
                              "steps": {
                                  "type": "array",
                                  "description": "A list of concrete steps the user should take.",
                                  "items": {
                                      "type": "object",
                                      "properties": {
                                          "step_number": {"type": "integer"},
                                          "action": {
                                              "type": "string",
                                              "description": "The specific, actionable task for this step."
                                          },
                                          "timeline": {
                                              "type": "string",
                                              "description": "A suggested timeframe for this step (e.g., 'Week 1-2')."
                                          }
                                      },
                                      "required": ["step_number", "action", "timeline"]
                                  }
                              }
                          },
                          "required": ["goal_title", "steps"]
                      }
                  }
              }
          ],
          "tool_choice": "required"
      }

      response = requests.post(API_URL, headers=headers, json=payload)
      response.raise_for_status()
      return response.json()

  def parse_growth_plan(api_response):
      """Parses the API response and extracts the structured growth plan."""
      try:
          tool_call = api_response['choices'][0]['message']['tool_calls'][0]
          function_args = json.loads(tool_call['function']['arguments'])
          return function_args
      except (KeyError, IndexError, json.JSONDecodeError) as e:
          raise ValueError(f"Failed to parse growth plan: {e}")

  def display_growth_plan(growth_plan):
      """Displays the growth plan in a user-friendly format."""
      print(f"\n🎯 {growth_plan['goal_title']}")
      print("=" * (len(growth_plan['goal_title']) + 4))

      for step in growth_plan['steps']:
          print(f"\n{step['step_number']}. {step['action']}")
          print(f"   ⏰ Timeline: {step['timeline']}")

  # --- Main Execution ---
  if __name__ == "__main__":
      try:
          user_goal = "I want to grow in my faith."
          print(f"Creating growth plan for: '{user_goal}'")

          # Make API call with tool use
          response = create_goal_setting_request(user_goal)

          # Parse the structured response
          growth_plan = parse_growth_plan(response)

          # Display the results
          display_growth_plan(growth_plan)

          # Also show raw JSON for developers
          print(f"\n📊 Raw JSON output:")
          print(json.dumps(growth_plan, indent=2))

      except requests.exceptions.HTTPError as err:
          print(f"An HTTP error occurred: {err}")
      except Exception as err:
          print(f"An error occurred: {err}")
  ```

  ```javascript JavaScript theme={null}
  // Load environment variables from .env file
  require('dotenv').config();

  const axios = require('axios');

  // --- Configuration ---
  const CLIENT_ID = process.env.GLOO_CLIENT_ID || "YOUR_CLIENT_ID";
  const CLIENT_SECRET = process.env.GLOO_CLIENT_SECRET || "YOUR_CLIENT_SECRET";
  const TOKEN_URL = "https://platform.ai.gloo.com/oauth2/token";
  const API_URL = "https://platform.ai.gloo.com/ai/v2/chat/completions";

  // --- State Management ---
  let tokenInfo = {};

  async function getAccessToken() {
      const body = 'grant_type=client_credentials&scope=api/access';
      const response = await axios.post(TOKEN_URL, body, {
          headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
          auth: { username: CLIENT_ID, password: CLIENT_SECRET }
      });
      const tokenData = response.data;
      tokenData.expires_at = Math.floor(Date.now() / 1000) + tokenData.expires_in;
      return tokenData;
  }

  function isTokenExpired(token) {
      if (!token || !token.expires_at) return true;
      return (Date.now() / 1000) > (token.expires_at - 60);
  }

  async function createGoalSettingRequest(userGoal) {
      if (isTokenExpired(tokenInfo)) {
          console.log("Token is expired or missing. Fetching a new one...");
          tokenInfo = await getAccessToken();
      }

      const payload = {
          auto_routing: true,
          messages: [{ role: "user", content: userGoal }],
          tools: [
              {
                  type: "function",
                  function: {
                      name: "create_growth_plan",
                      description: "Creates a structured personal growth plan with a title and a series of actionable steps.",
                      parameters: {
                          type: "object",
                          properties: {
                              goal_title: {
                                  type: "string",
                                  description: "A concise, encouraging title for the user's goal."
                              },
                              steps: {
                                  type: "array",
                                  description: "A list of concrete steps the user should take.",
                                  items: {
                                      type: "object",
                                      properties: {
                                          step_number: { type: "integer" },
                                          action: {
                                              type: "string",
                                              description: "The specific, actionable task for this step."
                                          },
                                          timeline: {
                                              type: "string",
                                              description: "A suggested timeframe for this step (e.g., 'Week 1-2')."
                                          }
                                      },
                                      required: ["step_number", "action", "timeline"]
                                  }
                              }
                          },
                          required: ["goal_title", "steps"]
                      }
                  }
              }
          ],
          tool_choice: "required"
      };

      const response = await axios.post(API_URL, payload, {
          headers: {
              'Authorization': `Bearer ${tokenInfo.access_token}`,
              'Content-Type': 'application/json',
          },
      });
      return response.data;
  }

  function parseGrowthPlan(apiResponse) {
      try {
          const toolCall = apiResponse.choices[0].message.tool_calls[0];
          return JSON.parse(toolCall.function.arguments);
      } catch (error) {
          throw new Error(`Failed to parse growth plan: ${error.message}`);
      }
  }

  function displayGrowthPlan(growthPlan) {
      console.log(`\n🎯 ${growthPlan.goal_title}`);
      console.log("=".repeat(growthPlan.goal_title.length + 4));

      growthPlan.steps.forEach(step => {
          console.log(`\n${step.step_number}. ${step.action}`);
          console.log(`   ⏰ Timeline: ${step.timeline}`);
      });
  }

  // --- Main Execution ---
  async function main() {
      try {
          const userGoal = "I want to grow in my faith.";
          console.log(`Creating growth plan for: '${userGoal}'`);

          // Make API call with tool use
          const response = await createGoalSettingRequest(userGoal);

          // Parse the structured response
          const growthPlan = parseGrowthPlan(response);

          // Display the results
          displayGrowthPlan(growthPlan);

          // Also show raw JSON for developers
          console.log(`\n📊 Raw JSON output:`);
          console.log(JSON.stringify(growthPlan, null, 2));

      } catch (error) {
          console.error("An error occurred:", error.response ? error.response.data : error.message);
      }
  }

  main();
  ```

  ```typescript TypeScript theme={null}
  import axios from 'axios';
  import * as dotenv from 'dotenv';

  // Load environment variables from .env file
  dotenv.config();

  // Type definitions
  interface TokenInfo {
      access_token: string;
      expires_in: number;
      expires_at: number;
      token_type: string;
  }

  interface GrowthStep {
      step_number: number;
      action: string;
      timeline: string;
  }

  interface GrowthPlan {
      goal_title: string;
      steps: GrowthStep[];
  }

  interface ToolCall {
      id: string;
      type: string;
      function: {
          name: string;
          arguments: string;
      };
  }

  interface ApiResponse {
      choices: Array<{
          message: {
              tool_calls: ToolCall[];
          };
      }>;
  }

  // --- Configuration ---
  const CLIENT_ID = process.env.GLOO_CLIENT_ID || "YOUR_CLIENT_ID";
  const CLIENT_SECRET = process.env.GLOO_CLIENT_SECRET || "YOUR_CLIENT_SECRET";
  const TOKEN_URL = "https://platform.ai.gloo.com/oauth2/token";
  const API_URL = "https://platform.ai.gloo.com/ai/v2/chat/completions";

  // --- State Management ---
  let tokenInfo: TokenInfo | null = null;

  async function getAccessToken(): Promise<TokenInfo> {
      const body = 'grant_type=client_credentials&scope=api/access';
      const response = await axios.post<TokenInfo>(TOKEN_URL, body, {
          headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
          auth: { username: CLIENT_ID, password: CLIENT_SECRET }
      });
      const tokenData = response.data;
      (tokenData as any).expires_at = Math.floor(Date.now() / 1000) + tokenData.expires_in;
      return tokenData;
  }

  function isTokenExpired(token: TokenInfo | null): boolean {
      if (!token || !(token as any).expires_at) return true;
      return (Date.now() / 1000) > ((token as any).expires_at - 60);
  }

  async function createGoalSettingRequest(userGoal: string): Promise<ApiResponse> {
      if (isTokenExpired(tokenInfo)) {
          console.log("Token is expired or missing. Fetching a new one...");
          tokenInfo = await getAccessToken();
      }

      const payload = {
          auto_routing: true,
          messages: [{ role: "user", content: userGoal }],
          tools: [
              {
                  type: "function",
                  function: {
                      name: "create_growth_plan",
                      description: "Creates a structured personal growth plan with a title and a series of actionable steps.",
                      parameters: {
                          type: "object",
                          properties: {
                              goal_title: {
                                  type: "string",
                                  description: "A concise, encouraging title for the user's goal."
                              },
                              steps: {
                                  type: "array",
                                  description: "A list of concrete steps the user should take.",
                                  items: {
                                      type: "object",
                                      properties: {
                                          step_number: { type: "integer" },
                                          action: {
                                              type: "string",
                                              description: "The specific, actionable task for this step."
                                          },
                                          timeline: {
                                              type: "string",
                                              description: "A suggested timeframe for this step (e.g., 'Week 1-2')."
                                          }
                                      },
                                      required: ["step_number", "action", "timeline"]
                                  }
                              }
                          },
                          required: ["goal_title", "steps"]
                      }
                  }
              }
          ],
          tool_choice: "required"
      };

      const response = await axios.post<ApiResponse>(API_URL, payload, {
          headers: {
              'Authorization': `Bearer ${tokenInfo!.access_token}`,
              'Content-Type': 'application/json',
          },
      });
      return response.data;
  }

  function parseGrowthPlan(apiResponse: ApiResponse): GrowthPlan {
      try {
          const toolCall = apiResponse.choices[0].message.tool_calls[0];
          return JSON.parse(toolCall.function.arguments) as GrowthPlan;
      } catch (error: any) {
          throw new Error(`Failed to parse growth plan: ${error.message}`);
      }
  }

  function displayGrowthPlan(growthPlan: GrowthPlan): void {
      console.log(`\n🎯 ${growthPlan.goal_title}`);
      console.log("=".repeat(growthPlan.goal_title.length + 4));

      growthPlan.steps.forEach(step => {
          console.log(`\n${step.step_number}. ${step.action}`);
          console.log(`   ⏰ Timeline: ${step.timeline}`);
      });
  }

  // --- Main Execution ---
  async function main(): Promise<void> {
      try {
          const userGoal = "I want to grow in my faith.";
          console.log(`Creating growth plan for: '${userGoal}'`);

          // Make API call with tool use
          const response = await createGoalSettingRequest(userGoal);

          // Parse the structured response
          const growthPlan = parseGrowthPlan(response);

          // Display the results
          displayGrowthPlan(growthPlan);

          // Also show raw JSON for developers
          console.log(`\n📊 Raw JSON output:`);
          console.log(JSON.stringify(growthPlan, null, 2));

      } catch (error: any) {
          console.error("An error occurred:", error.response ? error.response.data : error.message);
      }
  }

  main();
  ```

  ```php PHP theme={null}
  <?php
  require_once 'vendor/autoload.php';

  // Load environment variables from .env file
  $dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
  $dotenv->load();

  // --- Configuration ---
  $CLIENT_ID = $_ENV['GLOO_CLIENT_ID'] ?? 'YOUR_CLIENT_ID';
  $CLIENT_SECRET = $_ENV['GLOO_CLIENT_SECRET'] ?? 'YOUR_CLIENT_SECRET';
  $TOKEN_URL = 'https://platform.ai.gloo.com/oauth2/token';
  $API_URL = 'https://platform.ai.gloo.com/ai/v2/chat/completions';

  // Validate credentials
  if ($CLIENT_ID === 'YOUR_CLIENT_ID' || $CLIENT_SECRET === 'YOUR_CLIENT_SECRET' ||
      empty($CLIENT_ID) || empty($CLIENT_SECRET)) {
      echo "Error: GLOO_CLIENT_ID and GLOO_CLIENT_SECRET must be set\n";
      echo "Either:\n";
      echo "1. Create a .env file with your credentials:\n";
      echo "   GLOO_CLIENT_ID=your_client_id_here\n";
      echo "   GLOO_CLIENT_SECRET=your_client_secret_here\n";
      echo "2. Export them as environment variables:\n";
      echo "   export GLOO_CLIENT_ID=\"your_client_id_here\"\n";
      echo "   export GLOO_CLIENT_SECRET=\"your_client_secret_here\"\n";
      exit(1);
  }

  // --- State Management ---
  $tokenInfo = [];

  function getAccessToken($clientId, $clientSecret, $tokenUrl) {
      $postData = 'grant_type=client_credentials&scope=api/access';
      $ch = curl_init();
      curl_setopt($ch, CURLOPT_URL, $tokenUrl);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
      curl_setopt($ch, CURLOPT_POST, 1);
      curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
      curl_setopt($ch, CURLOPT_USERPWD, $clientId . ':' . $clientSecret);
      curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/x-www-form-urlencoded']);
      $result = curl_exec($ch);
      if (curl_errno($ch)) throw new Exception(curl_error($ch));
      curl_close($ch);
      $tokenData = json_decode($result, true);
      $tokenData['expires_at'] = time() + $tokenData['expires_in'];
      return $tokenData;
  }

  function isTokenExpired($token) {
      if (empty($token) || !isset($token['expires_at'])) return true;
      return time() > ($token['expires_at'] - 60);
  }

  function createGoalSettingRequest($userGoal, $apiUrl, &$tokenInfo, $clientId, $clientSecret, $tokenUrl) {
      if (isTokenExpired($tokenInfo)) {
          echo "Token is expired or missing. Fetching a new one...\n";
          $tokenInfo = getAccessToken($clientId, $clientSecret, $tokenUrl);
      }

      $tools = [
          [
              'type' => 'function',
              'function' => [
                  'name' => 'create_growth_plan',
                  'description' => 'Creates a structured personal growth plan with a title and a series of actionable steps.',
                  'parameters' => [
                      'type' => 'object',
                      'properties' => [
                          'goal_title' => [
                              'type' => 'string',
                              'description' => 'A concise, encouraging title for the user\'s goal.'
                          ],
                          'steps' => [
                              'type' => 'array',
                              'description' => 'A list of concrete steps the user should take.',
                              'items' => [
                                  'type' => 'object',
                                  'properties' => [
                                      'step_number' => ['type' => 'integer'],
                                      'action' => [
                                          'type' => 'string',
                                          'description' => 'The specific, actionable task for this step.'
                                      ],
                                      'timeline' => [
                                          'type' => 'string',
                                          'description' => 'A suggested timeframe for this step (e.g., \'Week 1-2\').'
                                      ]
                                  ],
                                  'required' => ['step_number', 'action', 'timeline']
                              ]
                          ]
                      ],
                      'required' => ['goal_title', 'steps']
                  ]
              ]
          ]
      ];

      $payload = json_encode([
          'auto_routing' => true,
          'messages' => [['role' => 'user', 'content' => $userGoal]],
          'tools' => $tools,
          'tool_choice' => 'required'
      ]);

      $ch = curl_init();
      curl_setopt($ch, CURLOPT_URL, $apiUrl);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
      curl_setopt($ch, CURLOPT_POST, 1);
      curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
      curl_setopt($ch, CURLOPT_HTTPHEADER, [
          'Content-Type: application/json',
          'Authorization: Bearer ' . $tokenInfo['access_token'],
      ]);
      $result = curl_exec($ch);
      if (curl_errno($ch)) throw new Exception(curl_error($ch));
      curl_close($ch);
      return json_decode($result, true);
  }

  function parseGrowthPlan($apiResponse) {
      try {
          $toolCall = $apiResponse['choices'][0]['message']['tool_calls'][0];
          return json_decode($toolCall['function']['arguments'], true);
      } catch (Exception $e) {
          throw new Exception("Failed to parse growth plan: " . $e->getMessage());
      }
  }

  function displayGrowthPlan($growthPlan) {
      echo "\n🎯 " . $growthPlan['goal_title'] . "\n";
      echo str_repeat("=", strlen($growthPlan['goal_title']) + 4) . "\n";

      foreach ($growthPlan['steps'] as $step) {
          echo "\n" . $step['step_number'] . ". " . $step['action'] . "\n";
          echo "   ⏰ Timeline: " . $step['timeline'] . "\n";
      }
  }

  // --- Main Execution ---
  try {
      $userGoal = "I want to grow in my faith.";
      echo "Creating growth plan for: '$userGoal'\n";

      // Make API call with tool use
      $response = createGoalSettingRequest($userGoal, $API_URL, $tokenInfo, $CLIENT_ID, $CLIENT_SECRET, $TOKEN_URL);

      // Parse the structured response
      $growthPlan = parseGrowthPlan($response);

      // Display the results
      displayGrowthPlan($growthPlan);

      // Also show raw JSON for developers
      echo "\n📊 Raw JSON output:\n";
      echo json_encode($growthPlan, JSON_PRETTY_PRINT) . "\n";

  } catch (Exception $e) {
      echo 'Error: ' . $e->getMessage() . "\n";
  }
  ?>
  ```

  ```go Go theme={null}
  package main

  import (
  	"bytes"
  	"encoding/json"
  	"fmt"
  	"io/ioutil"
  	"net/http"
  	"os"
  	"strings"
  	"time"

  	"github.com/joho/godotenv"
  )

  // --- Configuration ---
  var (
  	clientID     string
  	clientSecret string
  	tokenURL     = "https://platform.ai.gloo.com/oauth2/token"
  	apiURL       = "https://platform.ai.gloo.com/ai/v2/chat/completions"
  )

  // --- State Management ---
  var tokenInfo *TokenInfo

  // --- Data Structures ---
  type TokenInfo struct {
  	AccessToken string `json:"access_token"`
  	ExpiresIn   int    `json:"expires_in"`
  	ExpiresAt   int64  `json:"expires_at"`
  	TokenType   string `json:"token_type"`
  }

  type GrowthStep struct {
  	StepNumber int    `json:"step_number"`
  	Action     string `json:"action"`
  	Timeline   string `json:"timeline"`
  }

  type GrowthPlan struct {
  	GoalTitle string       `json:"goal_title"`
  	Steps     []GrowthStep `json:"steps"`
  }

  type ToolCall struct {
  	ID       string `json:"id"`
  	Type     string `json:"type"`
  	Function struct {
  		Name      string `json:"name"`
  		Arguments string `json:"arguments"`
  	} `json:"function"`
  }

  type ApiResponse struct {
  	Choices []struct {
  		Message struct {
  			ToolCalls []ToolCall `json:"tool_calls"`
  		} `json:"message"`
  	} `json:"choices"`
  }

  // --- Function Definitions ---
  func getAccessToken() (*TokenInfo, error) {
  	data := strings.NewReader("grant_type=client_credentials&scope=api/access")
  	req, err := http.NewRequest("POST", tokenURL, data)
  	if err != nil {
  		return nil, err
  	}

  	req.SetBasicAuth(clientID, clientSecret)
  	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")

  	client := &http.Client{}
  	resp, err := client.Do(req)
  	if err != nil {
  		return nil, err
  	}
  	defer resp.Body.Close()

  	if resp.StatusCode != http.StatusOK {
  		bodyBytes, _ := ioutil.ReadAll(resp.Body)
  		return nil, fmt.Errorf("failed to get token: %s - %s", resp.Status, string(bodyBytes))
  	}

  	body, err := ioutil.ReadAll(resp.Body)
  	if err != nil {
  		return nil, err
  	}

  	var localTokenInfo TokenInfo
  	if err := json.Unmarshal(body, &localTokenInfo); err != nil {
  		return nil, err
  	}

  	localTokenInfo.ExpiresAt = time.Now().Unix() + int64(localTokenInfo.ExpiresIn)
  	return &localTokenInfo, nil
  }

  func isTokenExpired(token *TokenInfo) bool {
  	if token == nil || token.ExpiresAt == 0 {
  		return true
  	}
  	return time.Now().Unix() > (token.ExpiresAt - 60)
  }

  func createGoalSettingRequest(userGoal string) (*ApiResponse, error) {
  	var err error
  	if isTokenExpired(tokenInfo) {
  		fmt.Println("Token is expired or missing. Fetching a new one...")
  		tokenInfo, err = getAccessToken()
  		if err != nil {
  			return nil, err
  		}
  	}

  	tools := []map[string]interface{}{
  		{
  			"type": "function",
  			"function": map[string]interface{}{
  				"name":        "create_growth_plan",
  				"description": "Creates a structured personal growth plan with a title and a series of actionable steps.",
  				"parameters": map[string]interface{}{
  					"type": "object",
  					"properties": map[string]interface{}{
  						"goal_title": map[string]interface{}{
  							"type":        "string",
  							"description": "A concise, encouraging title for the user's goal.",
  						},
  						"steps": map[string]interface{}{
  							"type":        "array",
  							"description": "A list of concrete steps the user should take.",
  							"items": map[string]interface{}{
  								"type": "object",
  								"properties": map[string]interface{}{
  									"step_number": map[string]string{"type": "integer"},
  									"action": map[string]string{
  										"type":        "string",
  										"description": "The specific, actionable task for this step.",
  									},
  									"timeline": map[string]string{
  										"type":        "string",
  										"description": "A suggested timeframe for this step (e.g., 'Week 1-2').",
  									},
  								},
  								"required": []string{"step_number", "action", "timeline"},
  							},
  						},
  					},
  					"required": []string{"goal_title", "steps"},
  				},
  			},
  		},
  	}

  	payload := map[string]interface{}{
  		"auto_routing": true,
  		"messages":     []map[string]string{{"role": "user", "content": userGoal}},
  		"tools":        tools,
  		"tool_choice":  "required",
  	}
  	jsonPayload, _ := json.Marshal(payload)

  	req, err := http.NewRequest("POST", apiURL, bytes.NewBuffer(jsonPayload))
  	if err != nil {
  		return nil, err
  	}

  	req.Header.Add("Authorization", "Bearer "+tokenInfo.AccessToken)
  	req.Header.Add("Content-Type", "application/json")

  	client := &http.Client{}
  	resp, err := client.Do(req)
  	if err != nil {
  		return nil, err
  	}
  	defer resp.Body.Close()

  	body, _ := ioutil.ReadAll(resp.Body)

  	if resp.StatusCode != http.StatusOK {
  		return nil, fmt.Errorf("API call failed: %s - %s", resp.Status, string(body))
  	}

  	var result ApiResponse
  	json.Unmarshal(body, &result)

  	return &result, nil
  }

  func parseGrowthPlan(apiResponse *ApiResponse) (*GrowthPlan, error) {
  	if len(apiResponse.Choices) == 0 || len(apiResponse.Choices[0].Message.ToolCalls) == 0 {
  		return nil, fmt.Errorf("no tool calls found in response")
  	}

  	toolCall := apiResponse.Choices[0].Message.ToolCalls[0]
  	var growthPlan GrowthPlan
  	if err := json.Unmarshal([]byte(toolCall.Function.Arguments), &growthPlan); err != nil {
  		return nil, fmt.Errorf("failed to parse growth plan: %v", err)
  	}

  	return &growthPlan, nil
  }

  func displayGrowthPlan(growthPlan *GrowthPlan) {
  	fmt.Printf("\n🎯 %s\n", growthPlan.GoalTitle)
  	fmt.Printf("%s\n", strings.Repeat("=", len(growthPlan.GoalTitle)+4))

  	for _, step := range growthPlan.Steps {
  		fmt.Printf("\n%d. %s\n", step.StepNumber, step.Action)
  		fmt.Printf("   ⏰ Timeline: %s\n", step.Timeline)
  	}
  }

  // Helper to get environment variables
  func getEnv(key, fallback string) string {
  	if value, ok := os.LookupEnv(key); ok {
  		return value
  	}
  	return fallback
  }

  // Initialize loads environment variables and validates configuration
  func init() {
  	// Load environment variables from .env file if it exists
  	_ = godotenv.Load()

  	// Get credentials from environment
  	clientID = getEnv("GLOO_CLIENT_ID", "")
  	clientSecret = getEnv("GLOO_CLIENT_SECRET", "")

  	// Validate that credentials are provided
  	if clientID == "" || clientSecret == "" {
  		fmt.Println("Error: GLOO_CLIENT_ID and GLOO_CLIENT_SECRET must be set")
  		fmt.Println("Either:")
  		fmt.Println("1. Create a .env file with your credentials:")
  		fmt.Println("   GLOO_CLIENT_ID=your_client_id_here")
  		fmt.Println("   GLOO_CLIENT_SECRET=your_client_secret_here")
  		fmt.Println("2. Export them as environment variables:")
  		fmt.Println("   export GLOO_CLIENT_ID=\"your_client_id_here\"")
  		fmt.Println("   export GLOO_CLIENT_SECRET=\"your_client_secret_here\"")
  		os.Exit(1)
  	}
  }

  // --- Main Execution ---
  func main() {
  	userGoal := "I want to grow in my faith."
  	fmt.Printf("Creating growth plan for: '%s'\n", userGoal)

  	// Make API call with tool use
  	response, err := createGoalSettingRequest(userGoal)
  	if err != nil {
  		fmt.Printf("Error creating growth plan: %v\n", err)
  		return
  	}

  	// Parse the structured response
  	growthPlan, err := parseGrowthPlan(response)
  	if err != nil {
  		fmt.Printf("Error parsing growth plan: %v\n", err)
  		return
  	}

  	// Display the results
  	displayGrowthPlan(growthPlan)

  	// Also show raw JSON for developers
  	fmt.Printf("\n📊 Raw JSON output:\n")
  	jsonBytes, _ := json.MarshalIndent(growthPlan, "", "  ")
  	fmt.Printf("%s\n", string(jsonBytes))
  }
  ```

  ```java Java theme={null}
  import com.google.gson.Gson;
  import com.google.gson.JsonObject;
  import com.google.gson.JsonArray;
  import io.github.cdimascio.dotenv.Dotenv;
  import java.io.IOException;
  import java.net.URI;
  import java.net.http.HttpClient;
  import java.net.http.HttpRequest;
  import java.net.http.HttpResponse;
  import java.time.Instant;
  import java.util.Base64;
  import java.util.List;

  // --- Main Application Class ---
  public class Main {
      public static void main(String[] args) {
          // Validate credentials before proceeding
          if (!CompletionsToolUse.validateCredentials()) {
              System.exit(1);
          }

          CompletionsToolUse toolUse = new CompletionsToolUse();
          try {
              String userGoal = "I want to grow in my faith.";
              System.out.println("Creating growth plan for: '" + userGoal + "'");

              // Make API call with tool use
              ApiResponse response = toolUse.createGoalSettingRequest(userGoal);

              // Parse the structured response
              GrowthPlan growthPlan = toolUse.parseGrowthPlan(response);

              // Display the results
              toolUse.displayGrowthPlan(growthPlan);

              // Also show raw JSON for developers
              System.out.println("\n📊 Raw JSON output:");
              System.out.println(toolUse.gson.toJson(growthPlan));

          } catch (Exception e) {
              e.printStackTrace();
          }
      }
  }

  // --- Completions Tool Use Class ---
  class CompletionsToolUse {
      // Load environment variables from .env file if it exists
      private static final Dotenv dotenv = Dotenv.configure()
              .ignoreIfMissing()
              .load();

      private static final String CLIENT_ID = dotenv.get("GLOO_CLIENT_ID", "YOUR_CLIENT_ID");
      private static final String CLIENT_SECRET = dotenv.get("GLOO_CLIENT_SECRET", "YOUR_CLIENT_SECRET");
      private static final String TOKEN_URL = "https://platform.ai.gloo.com/oauth2/token";
      private static final String API_URL = "https://platform.ai.gloo.com/ai/v2/chat/completions";

      private TokenInfo tokenInfo;
      private final HttpClient httpClient = HttpClient.newHttpClient();
      public final Gson gson = new Gson();

      // Validate that credentials are provided
      public static boolean validateCredentials() {
          if ("YOUR_CLIENT_ID".equals(CLIENT_ID) || CLIENT_ID == null || CLIENT_ID.trim().isEmpty() ||
              "YOUR_CLIENT_SECRET".equals(CLIENT_SECRET) || CLIENT_SECRET == null || CLIENT_SECRET.trim().isEmpty()) {
              System.err.println("Error: GLOO_CLIENT_ID and GLOO_CLIENT_SECRET must be set");
              System.err.println("Either:");
              System.err.println("1. Create a .env file with your credentials:");
              System.err.println("   GLOO_CLIENT_ID=your_client_id_here");
              System.err.println("   GLOO_CLIENT_SECRET=your_client_secret_here");
              System.err.println("2. Export them as environment variables:");
              System.err.println("   export GLOO_CLIENT_ID=\"your_client_id_here\"");
              System.err.println("   export GLOO_CLIENT_SECRET=\"your_client_secret_here\"");
              return false;
          }
          return true;
      }

      // --- Data Classes ---
      static class TokenInfo {
          String access_token;
          int expires_in;
          long expires_at;
      }

      static class GrowthStep {
          int step_number;
          String action;
          String timeline;
      }

      static class GrowthPlan {
          String goal_title;
          List<GrowthStep> steps;
      }

      static class ToolCall {
          String id;
          String type;
          Function function;

          static class Function {
              String name;
              String arguments;
          }
      }

      static class ApiResponse {
          List<Choice> choices;

          static class Choice {
              Message message;

              static class Message {
                  List<ToolCall> tool_calls;
              }
          }
      }

      // --- Token Management ---
      private void fetchAccessToken() throws IOException, InterruptedException {
          String auth = CLIENT_ID + ":" + CLIENT_SECRET;
          String encodedAuth = Base64.getEncoder().encodeToString(auth.getBytes());
          String requestBody = "grant_type=client_credentials&scope=api/access";

          HttpRequest request = HttpRequest.newBuilder()
                  .uri(URI.create(TOKEN_URL))
                  .header("Content-Type", "application/x-www-form-urlencoded")
                  .header("Authorization", "Basic " + encodedAuth)
                  .POST(HttpRequest.BodyPublishers.ofString(requestBody))
                  .build();

          HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
          if (response.statusCode() != 200) {
              throw new IOException("Failed to get token: " + response.body());
          }

          this.tokenInfo = gson.fromJson(response.body(), TokenInfo.class);
          this.tokenInfo.expires_at = Instant.now().getEpochSecond() + this.tokenInfo.expires_in;
      }

      private boolean isTokenExpired() {
          if (this.tokenInfo == null || this.tokenInfo.expires_at == 0) return true;
          return Instant.now().getEpochSecond() > (this.tokenInfo.expires_at - 60);
      }

      // --- API Methods ---
      public ApiResponse createGoalSettingRequest(String userGoal) throws IOException, InterruptedException {
          if (isTokenExpired()) {
              System.out.println("Token is expired or missing. Fetching a new one...");
              fetchAccessToken();
          }

          // Create the tool definition using JsonObject for proper structure
          JsonObject toolSchema = new JsonObject();
          toolSchema.addProperty("type", "function");

          JsonObject function = new JsonObject();
          function.addProperty("name", "create_growth_plan");
          function.addProperty("description", "Creates a structured personal growth plan with a title and a series of actionable steps.");

          JsonObject parameters = new JsonObject();
          parameters.addProperty("type", "object");

          JsonObject properties = new JsonObject();

          JsonObject goalTitle = new JsonObject();
          goalTitle.addProperty("type", "string");
          goalTitle.addProperty("description", "A concise, encouraging title for the user's goal.");
          properties.add("goal_title", goalTitle);

          JsonObject steps = new JsonObject();
          steps.addProperty("type", "array");
          steps.addProperty("description", "A list of concrete steps the user should take.");

          JsonObject items = new JsonObject();
          items.addProperty("type", "object");

          JsonObject itemProperties = new JsonObject();
          JsonObject stepNumber = new JsonObject();
          stepNumber.addProperty("type", "integer");
          itemProperties.add("step_number", stepNumber);

          JsonObject action = new JsonObject();
          action.addProperty("type", "string");
          action.addProperty("description", "The specific, actionable task for this step.");
          itemProperties.add("action", action);

          JsonObject timeline = new JsonObject();
          timeline.addProperty("type", "string");
          timeline.addProperty("description", "A suggested timeframe for this step (e.g., 'Week 1-2').");
          itemProperties.add("timeline", timeline);

          items.add("properties", itemProperties);

          JsonArray required = new JsonArray();
          required.add("step_number");
          required.add("action");
          required.add("timeline");
          items.add("required", required);

          steps.add("items", items);
          properties.add("steps", steps);

          parameters.add("properties", properties);

          JsonArray requiredParams = new JsonArray();
          requiredParams.add("goal_title");
          requiredParams.add("steps");
          parameters.add("required", requiredParams);

          function.add("parameters", parameters);
          toolSchema.add("function", function);

          JsonArray tools = new JsonArray();
          tools.add(toolSchema);

          JsonObject message = new JsonObject();
          message.addProperty("role", "user");
          message.addProperty("content", userGoal);

          JsonArray messages = new JsonArray();
          messages.add(message);

          JsonObject payload = new JsonObject();
          payload.addProperty("auto_routing", true);
          payload.add("messages", messages);
          payload.add("tools", tools);
          payload.addProperty("tool_choice", "required");

          HttpRequest request = HttpRequest.newBuilder()
                  .uri(URI.create(API_URL))
                  .header("Content-Type", "application/json")
                  .header("Authorization", "Bearer " + this.tokenInfo.access_token)
                  .POST(HttpRequest.BodyPublishers.ofString(gson.toJson(payload)))
                  .build();

          HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
          if (response.statusCode() != 200) {
              throw new IOException("API call failed: " + response.body());
          }

          return gson.fromJson(response.body(), ApiResponse.class);
      }

      public GrowthPlan parseGrowthPlan(ApiResponse apiResponse) {
          try {
              ToolCall toolCall = apiResponse.choices.get(0).message.tool_calls.get(0);
              return gson.fromJson(toolCall.function.arguments, GrowthPlan.class);
          } catch (Exception e) {
              throw new RuntimeException("Failed to parse growth plan: " + e.getMessage(), e);
          }
      }

      public void displayGrowthPlan(GrowthPlan growthPlan) {
          System.out.println("\n🎯 " + growthPlan.goal_title);
          System.out.println("=".repeat(growthPlan.goal_title.length() + 4));

          for (GrowthStep step : growthPlan.steps) {
              System.out.println("\n" + step.step_number + ". " + step.action);
              System.out.println("   ⏰ Timeline: " + step.timeline);
          }
      }
  }
  ```
</CodeGroup>

***

## Testing Your Implementation

To test any of the complete examples:

1. **Set up your environment variables** with your actual Gloo AI credentials
2. **Install dependencies** according to each language's requirements
3. **Run the script** and observe the structured output

The script will:

* Automatically handle token retrieval and expiration
* Make a tool-use API call with the goal "I want to grow in my faith"
* Parse the JSON response into a structured format
* Display the growth plan in a user-friendly format
* Show the raw JSON for developers

***

## Key Benefits

This approach provides several advantages over simple chat completions:

1. **Predictable Structure**: The response always follows your defined schema
2. **Machine-Readable**: Easy to parse and use in applications
3. **Type Safety**: Clear data types for each field
4. **Validation**: The API enforces your schema requirements
5. **Flexibility**: Can adapt to any structured output needs

***

## Working Code Sample

<Card title="View Complete Code" icon="github" href="https://github.com/GlooDeveloper/gloo-ai-docs-cookbook/tree/main/completions-tool-use">
  Clone or browse the complete working examples for all 6 languages (JavaScript, TypeScript, Python, PHP, Go, Java) with setup instructions.
</Card>

## Next Steps

Now that you understand how to use tool use for structured output with V2, consider exploring:

1. **[Completions V2 Guide](/api-guides/completions-v2)** - Learn about auto-routing and model selection options
2. **[Tool Use Guide](/api-guides/tool-use)** - For more advanced tool use patterns and multi-step workflows
3. **[Completions API Reference](/api-reference/studio/post-completions)** - Full API documentation
4. **Custom Schemas** - Adapt this pattern for your specific use cases
