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

# Custom Functions

> Define custom function tools the Agent API can call, then feed results back to continue the run - the type: function tool, the function_call item, and function_call_output keyed by call_id.

A custom tool (`type: function`) lets the agent call code you control - your database, an internal API, or any business logic.
You declare the function with a `name`, a `description`, and a JSON Schema for its `parameters`.
The model decides when to call it and fills in the arguments; you run the function and return the result so the run can continue.

Unlike built-in tools, the Agent API never executes your code.
When the model calls a custom function, the run pauses and hands the call back to you.

## Define a custom tool

Declare the tool in the `tools` array. Set `strict: true` to enforce the parameter schema.

<CodeGroup>
  ```python Python theme={null}
  from perplexity import Perplexity

  client = Perplexity()

  tools = [
      {
          "type": "function",
          "name": "get_order_status",
          "description": "Look up the current status of an internal order by its order ID.",
          "parameters": {
              "type": "object",
              "properties": {"order_id": {"type": "string"}},
              "required": ["order_id"],
          },
          "strict": True,
      }
  ]

  response = client.responses.create(
      model="openai/gpt-5.6-sol",
      input="What's the status of order ORD-10042?",
      tools=tools,
  )
  ```

  ```typescript Typescript theme={null}
  import Perplexity from '@perplexity-ai/perplexity_ai';

  const client = new Perplexity();

  const tools = [
    {
      type: 'function' as const,
      name: 'get_order_status',
      description: 'Look up the current status of an internal order by its order ID.',
      parameters: {
        type: 'object',
        properties: { order_id: { type: 'string' } },
        required: ['order_id'],
      },
      strict: true,
    },
  ];

  const response = await client.responses.create({
    model: 'openai/gpt-5.6-sol',
    input: "What's the status of order ORD-10042?",
    tools,
  });
  ```

  ```bash cURL theme={null}
  curl https://api.perplexity.ai/v1/agent \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "openai/gpt-5.6-sol",
      "input": "What is the status of order ORD-10042?",
      "tools": [
        {
          "type": "function",
          "name": "get_order_status",
          "description": "Look up the current status of an internal order by its order ID.",
          "parameters": {
            "type": "object",
            "properties": { "order_id": { "type": "string" } },
            "required": ["order_id"]
          },
          "strict": true
        }
      ]
    }' | jq
  ```
</CodeGroup>

## Read the function call

The run pauses and returns the call in the response `output` array as a `function_call` item with the name and the arguments the model filled in:

```json theme={null}
{
  "type": "function_call",
  "id": "fc_abc123",
  "call_id": "call_xyz789",
  "name": "get_order_status",
  "arguments": "{\"order_id\":\"ORD-10042\"}"
}
```

## Return the result

Pull that item off the response, run the function on your side, then continue the run by sending the result back.
The follow-up request replays the conversation so far - the original question, the `function_call` the model emitted, and a `function_call_output` carrying your result under the same `call_id`:

<CodeGroup>
  ```python Python theme={null}
  import json

  function_call = next(item for item in response.output if item.type == "function_call")

  def get_order_status(order_id: str) -> dict:
      orders = {"ORD-10042": {"status": "in_transit", "carrier": "DHL", "eta": "2026-06-23"}}
      return orders.get(order_id, {"error": "order not found"})

  result = get_order_status(**json.loads(function_call.arguments))

  followup = client.responses.create(
      model="openai/gpt-5.6-sol",
      input=[
          {"role": "user", "content": "What's the status of order ORD-10042?"},
          {
              "type": "function_call",
              "call_id": function_call.call_id,
              "name": function_call.name,
              "arguments": function_call.arguments,
          },
          {
              "type": "function_call_output",
              "call_id": function_call.call_id,
              "output": json.dumps(result),
          },
      ],
      tools=tools,
  )

  print(followup.output_text)
  ```

  ```typescript Typescript theme={null}
  const functionCall = response.output.find((item) => item.type === 'function_call');
  if (functionCall?.type !== 'function_call') throw new Error('No function call returned.');

  function getOrderStatus(orderId: string) {
    const orders: Record<string, unknown> = {
      'ORD-10042': { status: 'in_transit', carrier: 'DHL', eta: '2026-06-23' },
    };
    return orders[orderId] ?? { error: 'order not found' };
  }

  const args = JSON.parse(functionCall.arguments) as { order_id: string };
  const result = getOrderStatus(args.order_id);

  const followup = await client.responses.create({
    model: 'openai/gpt-5.6-sol',
    input: [
      { type: 'message', role: 'user', content: "What's the status of order ORD-10042?" },
      {
        type: 'function_call',
        call_id: functionCall.call_id,
        name: functionCall.name,
        arguments: functionCall.arguments,
      },
      {
        type: 'function_call_output',
        call_id: functionCall.call_id,
        output: JSON.stringify(result),
      },
    ],
    tools,
  });

  console.log(followup.output_text);
  ```

  ```bash cURL theme={null}
  curl https://api.perplexity.ai/v1/agent \
    -H "Authorization: Bearer $PERPLEXITY_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "openai/gpt-5.6-sol",
      "input": [
        { "role": "user", "content": "What is the status of order ORD-10042?" },
        {
          "type": "function_call",
          "call_id": "call_xyz789",
          "name": "get_order_status",
          "arguments": "{\"order_id\":\"ORD-10042\"}"
        },
        {
          "type": "function_call_output",
          "call_id": "call_xyz789",
          "output": "{\"status\": \"in_transit\", \"carrier\": \"DHL\", \"eta\": \"2026-06-23\"}"
        }
      ]
    }' | jq
  ```
</CodeGroup>

<Note>
  `call_id` is the correlation key: the `function_call` the model emits and the `function_call_output` you return must carry the same value.
  Set `strict: true` on the tool to enforce the parameter schema.
  You continue the run by replaying the prior items in the `input` array - pass the `function_call` and its `function_call_output` together so the model sees its own request and your result.
</Note>

## Next steps

<CardGroup cols={2}>
  <Card title="Give it tools" icon="wrench" href="/docs/agent-api/building-agents/give-it-tools">
    The end-to-end how-to for wiring built-in, MCP, and custom tools into a run.
  </Card>

  <Card title="Tools overview" icon="list" href="/docs/agent-api/tools/overview">
    Every built-in tool, plus MCP servers and custom functions.
  </Card>
</CardGroup>
