> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.phonic.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.phonic.ai/_mcp/server.

# Create

POST https://api.phonic.ai/v1/webhooks
Content-Type: application/json

Creates a webhook that sends the chosen events for the chosen projects
to `endpoint_url`. The response includes the webhook's signing secret.

Requires an API key with workspace access, or an access token. An API
key restricted to selected projects can only use projects within its
scope.


Reference: https://docs.phonic.ai/api-reference/webhooks/create

## Authentication

- `Authorization` header (bearer token, required) — Bearer authentication header of the form `Bearer <PHONIC_API_KEY>`. Manage your API keys [here](https://phonic.co/api-keys).

## Request

### Body (application/json)

This endpoint expects a CreateWebhookRequest.

- `endpoint_url` (string, required) — The URL that receives the webhook's requests. Must be a publicly routable HTTPS URL without embedded credentials, and unique within the workspace. It cannot be changed later.
- `events` (list of enum, required) — The events to send to the endpoint.
  - Allowed values: `conversation.ended`, `conversation.analysis`, `conversation.transferred`
- `project_ids` (list of string, required) — The projects whose events are sent to the endpoint.

## Response

### 201

Webhook created

- `id` (string, required) — The webhook ID.
- `signing_secret` (string, required) — The secret used to sign the webhook's requests. It can be fetched again from `GET /webhooks/{id}/secret`.

## Errors

### 400 Bad Request Error

Invalid parameters, including a project ID that is not in the workspace

- `error` (ValidationErrorError, required)
- `param_errors` (map from string to string, required) — Parameter-specific validation errors

### 401 Unauthorized Error

Unauthorized (authentication missing or invalid, or not an API key or access token)

- `error` (BasicErrorError, optional)

### 403 Forbidden Error

The API key does not have workspace access, or `project_ids` includes a project outside the API key's scope.

- `error` (BasicErrorError, optional)

### 409 Conflict Error

A webhook with this endpoint URL already exists in the workspace.

- `error` (ValidationErrorError, required)
- `param_errors` (map from string to string, required) — Parameter-specific validation errors

### 500 Internal Server Error

Internal server error

- `error` (BasicErrorError, optional)

## Types

### ValidationErrorError

- `message` (string, required) — Error message

### BasicErrorError

- `message` (string, required) — Error message
- `code` (string, optional) — Error code

## Examples

**Request**

```json
{
  "endpoint_url": "https://example.com/phonic/webhooks",
  "events": [
    "conversation.ended",
    "conversation.analysis"
  ],
  "project_ids": [
    "proj_ad0334f1-2487-4155-9df3-abd8129b29ad"
  ]
}
```

**Response**

```json
{
  "id": "wh_0b6a3d7e-5c1f-4a8e-9d2b-7f3e1c4a5b6d",
  "signing_secret": "whsec_c2VjcmV0LWV4YW1wbGUtdmFsdWUtMTIz"
}
```

**SDK Code**

```python webhooks_create_example
import requests

url = "https://api.phonic.ai/v1/webhooks"

payload = {
    "endpoint_url": "https://example.com/phonic/webhooks",
    "events": ["conversation.ended", "conversation.analysis"],
    "project_ids": ["proj_ad0334f1-2487-4155-9df3-abd8129b29ad"]
}
headers = {
    "Authorization": "Bearer <apiKey>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript webhooks_create_example
const url = 'https://api.phonic.ai/v1/webhooks';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <apiKey>', 'Content-Type': 'application/json'},
  body: '{"endpoint_url":"https://example.com/phonic/webhooks","events":["conversation.ended","conversation.analysis"],"project_ids":["proj_ad0334f1-2487-4155-9df3-abd8129b29ad"]}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go webhooks_create_example
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api.phonic.ai/v1/webhooks"

	payload := strings.NewReader("{\n  \"endpoint_url\": \"https://example.com/phonic/webhooks\",\n  \"events\": [\n    \"conversation.ended\",\n    \"conversation.analysis\"\n  ],\n  \"project_ids\": [\n    \"proj_ad0334f1-2487-4155-9df3-abd8129b29ad\"\n  ]\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <apiKey>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby webhooks_create_example
require 'uri'
require 'net/http'

url = URI("https://api.phonic.ai/v1/webhooks")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <apiKey>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"endpoint_url\": \"https://example.com/phonic/webhooks\",\n  \"events\": [\n    \"conversation.ended\",\n    \"conversation.analysis\"\n  ],\n  \"project_ids\": [\n    \"proj_ad0334f1-2487-4155-9df3-abd8129b29ad\"\n  ]\n}"

response = http.request(request)
puts response.read_body
```

```java webhooks_create_example
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.phonic.ai/v1/webhooks")
  .header("Authorization", "Bearer <apiKey>")
  .header("Content-Type", "application/json")
  .body("{\n  \"endpoint_url\": \"https://example.com/phonic/webhooks\",\n  \"events\": [\n    \"conversation.ended\",\n    \"conversation.analysis\"\n  ],\n  \"project_ids\": [\n    \"proj_ad0334f1-2487-4155-9df3-abd8129b29ad\"\n  ]\n}")
  .asString();
```

```php webhooks_create_example
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.phonic.ai/v1/webhooks', [
  'body' => '{
  "endpoint_url": "https://example.com/phonic/webhooks",
  "events": [
    "conversation.ended",
    "conversation.analysis"
  ],
  "project_ids": [
    "proj_ad0334f1-2487-4155-9df3-abd8129b29ad"
  ]
}',
  'headers' => [
    'Authorization' => 'Bearer <apiKey>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp webhooks_create_example
using RestSharp;

var client = new RestClient("https://api.phonic.ai/v1/webhooks");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <apiKey>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"endpoint_url\": \"https://example.com/phonic/webhooks\",\n  \"events\": [\n    \"conversation.ended\",\n    \"conversation.analysis\"\n  ],\n  \"project_ids\": [\n    \"proj_ad0334f1-2487-4155-9df3-abd8129b29ad\"\n  ]\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift webhooks_create_example
import Foundation

let headers = [
  "Authorization": "Bearer <apiKey>",
  "Content-Type": "application/json"
]
let parameters = [
  "endpoint_url": "https://example.com/phonic/webhooks",
  "events": ["conversation.ended", "conversation.analysis"],
  "project_ids": ["proj_ad0334f1-2487-4155-9df3-abd8129b29ad"]
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api.phonic.ai/v1/webhooks")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```