# Create a tool

> POST /v1/tools

A request an agent can make mid-conversation, in a project. Attach it to agents by name in their definitions. Its address may not be on this deployment's network, and a credential it names must be a tool credential assigned to the project — sent only where it already goes, or pinned there if this is its first use. Needs `tools:write` and a live key.

## Body

Sent as JSON. A field this operation does not take is refused, so a typo fails loudly.

| Field | Type | Required | Description |
|---|---|---|---|
| `description` | string | Yes |  |
| `http` | object | Yes | `method`, `url`, `headers`, `auth` — `{"type": "bearer", "vault_key_id": …}` names a credential from `POST /v1/vault/secrets` — and `timeout_ms`. |
| `name` | string | Yes | What the model calls it: letters, digits and underscores. |
| `parameters` | object | Yes | The JSON Schema of what the model sends it. |
| `project_id` | string (uuid) | Yes | The project it belongs to. |
| `speaking_hint` | string | No |  |

## Answer

`201` with [ToolObject](/reference/objects/ToolObject).

## Errors

Every error is a [problem document](/errors) with a stable `code`.

| Status | When |
|---|---|
| `401` | The key is missing, mistyped, unknown, revoked or expired. |
| `403` | A credential sent somewhere it does not go yet, or a test key. |
| `409` | The project already has a tool by that name, or it is frozen. |
| `422` | The tool's shape, its address or its credential will not do. |
| `429` | Too many requests for this key or its organization; see `Retry-After`. |
| `500` | Something went wrong on our side. Quote the `request_id` to support. |

## Examples

**curl**

```sh
#!/bin/sh
# Create a tool. Give it to agents by name in their definitions. With a live key.
curl -sS --fail-with-body -X POST "https://api.aigently.ai/v1/tools" \
  -H "Authorization: Bearer $AIGENTLY_API_KEY" \
  --json '{
  "project_id": "0b1c2d3e-4f5a-6b7c-8d9e-0f1a2b3c4d5e",
  "name": "lookup_order",
  "description": "Look up the status of an order by its number.",
  "parameters": {
    "type": "object",
    "properties": {
      "order_id": {
        "type": "string",
        "description": "The order number."
      }
    },
    "required": [
      "order_id"
    ]
  },
  "http": {
    "method": "GET",
    "url": "https://orders.aigently.ai/v1/orders/{order_id}",
    "auth": {
      "type": "bearer",
      "vault_key_id": "2e4a6c8e-0a2c-4e4a-d6c8-e0a2c4e6a8ca"
    }
  },
  "speaking_hint": "One moment while I look that up."
}'
```

**JavaScript**

```js
// Create a tool. Give it to agents by name in their definitions. With a live key.
const response = await fetch("https://api.aigently.ai/v1/tools", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.AIGENTLY_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "project_id": "0b1c2d3e-4f5a-6b7c-8d9e-0f1a2b3c4d5e",
    "name": "lookup_order",
    "description": "Look up the status of an order by its number.",
    "parameters": {
      "type": "object",
      "properties": {
        "order_id": {
          "type": "string",
          "description": "The order number."
        }
      },
      "required": [
        "order_id"
      ]
    },
    "http": {
      "method": "GET",
      "url": "https://orders.aigently.ai/v1/orders/{order_id}",
      "auth": {
        "type": "bearer",
        "vault_key_id": "2e4a6c8e-0a2c-4e4a-d6c8-e0a2c4e6a8ca"
      }
    },
    "speaking_hint": "One moment while I look that up."
  }),
});
const answer = await response.json();
if (!response.ok) throw new Error(`${answer.code}: ${answer.detail}`);
console.log(answer);
```

**Python**

```python
# Create a tool. Give it to agents by name in their definitions. With a live key.
# pip install httpx
import os

import httpx

response = httpx.post(
    "https://api.aigently.ai/v1/tools",
    headers={
        "Authorization": f"Bearer {os.environ['AIGENTLY_API_KEY']}",
    },
    json={
        "project_id": "0b1c2d3e-4f5a-6b7c-8d9e-0f1a2b3c4d5e",
        "name": "lookup_order",
        "description": "Look up the status of an order by its number.",
        "parameters": {
            "type": "object",
            "properties": {
                "order_id": {
                    "type": "string",
                    "description": "The order number.",
                },
            },
            "required": ["order_id"],
        },
        "http": {
            "method": "GET",
            "url": "https://orders.aigently.ai/v1/orders/{order_id}",
            "auth": {
                "type": "bearer",
                "vault_key_id": "2e4a6c8e-0a2c-4e4a-d6c8-e0a2c4e6a8ca",
            },
        },
        "speaking_hint": "One moment while I look that up.",
    },
)
if response.is_error:
    raise SystemExit(response.text)
print(response.json())
```

**Go**

```go
// Create a tool. Give it to agents by name in their definitions. With a live key.
package main

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	payload := []byte(`{
  "project_id": "0b1c2d3e-4f5a-6b7c-8d9e-0f1a2b3c4d5e",
  "name": "lookup_order",
  "description": "Look up the status of an order by its number.",
  "parameters": {
    "type": "object",
    "properties": {
      "order_id": {
        "type": "string",
        "description": "The order number."
      }
    },
    "required": [
      "order_id"
    ]
  },
  "http": {
    "method": "GET",
    "url": "https://orders.aigently.ai/v1/orders/{order_id}",
    "auth": {
      "type": "bearer",
      "vault_key_id": "2e4a6c8e-0a2c-4e4a-d6c8-e0a2c4e6a8ca"
    }
  },
  "speaking_hint": "One moment while I look that up."
}`)
	request, err := http.NewRequest("POST", "https://api.aigently.ai/v1/tools", bytes.NewReader(payload))
	if err != nil {
		panic(err)
	}
	request.Header.Set("Authorization", "Bearer "+os.Getenv("AIGENTLY_API_KEY"))
	request.Header.Set("Content-Type", "application/json")
	response, err := http.DefaultClient.Do(request)
	if err != nil {
		panic(err)
	}
	defer response.Body.Close()
	body, _ := io.ReadAll(response.Body)
	if response.StatusCode >= 400 {
		fmt.Fprintln(os.Stderr, string(body))
		os.Exit(1)
	}
	fmt.Println(string(body))
}
```

**Java**

```java
// Create a tool. Give it to agents by name in their definitions. With a live key.
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class Main {
    public static void main(String[] args) throws Exception {
        String body = """
            {
              "project_id": "0b1c2d3e-4f5a-6b7c-8d9e-0f1a2b3c4d5e",
              "name": "lookup_order",
              "description": "Look up the status of an order by its number.",
              "parameters": {
                "type": "object",
                "properties": {
                  "order_id": {
                    "type": "string",
                    "description": "The order number."
                  }
                },
                "required": [
                  "order_id"
                ]
              },
              "http": {
                "method": "GET",
                "url": "https://orders.aigently.ai/v1/orders/{order_id}",
                "auth": {
                  "type": "bearer",
                  "vault_key_id": "2e4a6c8e-0a2c-4e4a-d6c8-e0a2c4e6a8ca"
                }
              },
              "speaking_hint": "One moment while I look that up."
            }
            """;
        HttpRequest request = HttpRequest.newBuilder(URI.create("https://api.aigently.ai/v1/tools"))
            .header("Authorization", "Bearer " + System.getenv("AIGENTLY_API_KEY"))
            .header("Content-Type", "application/json")
            .method("POST", HttpRequest.BodyPublishers.ofString(body))
            .build();
        // HTTP/1.1: on a plain-http address Java's default asks to upgrade, which not every
        // server allows.
        HttpClient client = HttpClient.newBuilder().version(HttpClient.Version.HTTP_1_1).build();
        HttpResponse<String> response =
            client.send(request, HttpResponse.BodyHandlers.ofString());
        if (response.statusCode() >= 400) {
            System.err.println(response.body());
            System.exit(1);
        }
        System.out.println(response.body());
    }
}
```

**C#**

```csharp
// Create a tool. Give it to agents by name in their definitions. With a live key.
using System.Net.Http.Headers;
using System.Text;

using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("AIGENTLY_API_KEY"));
var request = new HttpRequestMessage(HttpMethod.Post, "https://api.aigently.ai/v1/tools")
{
    Content = new StringContent(
        """
        {
          "project_id": "0b1c2d3e-4f5a-6b7c-8d9e-0f1a2b3c4d5e",
          "name": "lookup_order",
          "description": "Look up the status of an order by its number.",
          "parameters": {
            "type": "object",
            "properties": {
              "order_id": {
                "type": "string",
                "description": "The order number."
              }
            },
            "required": [
              "order_id"
            ]
          },
          "http": {
            "method": "GET",
            "url": "https://orders.aigently.ai/v1/orders/{order_id}",
            "auth": {
              "type": "bearer",
              "vault_key_id": "2e4a6c8e-0a2c-4e4a-d6c8-e0a2c4e6a8ca"
            }
          },
          "speaking_hint": "One moment while I look that up."
        }
        """,
        Encoding.UTF8,
        "application/json"),
};
var response = await client.SendAsync(request);
var body = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode)
{
    Console.Error.WriteLine(body);
    return 1;
}
Console.WriteLine(body);
return 0;
```

**PHP**

```php
<?php
// Create a tool. Give it to agents by name in their definitions. With a live key.
$curl = curl_init("https://api.aigently.ai/v1/tools");
curl_setopt_array($curl, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer " . getenv("AIGENTLY_API_KEY"),
        "Content-Type: application/json",
    ],
    CURLOPT_POSTFIELDS => json_encode([
        "project_id" => "0b1c2d3e-4f5a-6b7c-8d9e-0f1a2b3c4d5e",
        "name" => "lookup_order",
        "description" => "Look up the status of an order by its number.",
        "parameters" => [
            "type" => "object",
            "properties" => [
                "order_id" => [
                    "type" => "string",
                    "description" => "The order number.",
                ],
            ],
            "required" => ["order_id"],
        ],
        "http" => [
            "method" => "GET",
            "url" => "https://orders.aigently.ai/v1/orders/{order_id}",
            "auth" => [
                "type" => "bearer",
                "vault_key_id" => "2e4a6c8e-0a2c-4e4a-d6c8-e0a2c4e6a8ca",
            ],
        ],
        "speaking_hint" => "One moment while I look that up.",
    ]),
]);
$body = curl_exec($curl);
if (curl_getinfo($curl, CURLINFO_RESPONSE_CODE) >= 400) {
    fwrite(STDERR, $body . "\n");
    exit(1);
}
echo $body, "\n";
```
