> For clean Markdown content of this page, append .md to this URL. For the complete documentation index, see https://docs.agentmail.to/llms.txt.

# Create Polling Webhook

POST https://api.agentmail.to/v0/webhooks/polling
Content-Type: application/json

Creates a subscription the agent polls for events, and returns the `token` that reads it. Each
organization, pod, and inbox holds at most 10 polling webhooks; a repeat create with the same
`client_id` re-issues the token of the existing one instead of counting against that limit.

**CLI:**
```bash
agentmail webhooks polling create --client-id my-agent --event-types message.received
```

Reference: https://docs.agentmail.to/api-reference/webhooks/polling/create

## Authentication

- `Authorization` header (bearer token, required) — Bearer authentication of the form `Bearer <token>`, where token is your auth token.

## Servers

- `https://api.agentmail.to` (prod, default)
- `https://x402.api.agentmail.to` (prod-x402)
- `https://mpp.api.agentmail.to` (prod-mpp)
- `https://api.agentmail.eu` (eu-prod)

## Request

### Body (application/json)

This endpoint expects a CreatePollingWebhookRequest.

- `client_id` (string, required) — Required. Idempotency key of the subscription: creating again with the same `client_id` through the same route returns the existing subscription with a fresh token instead of a second subscription, so a restarted agent resumes where it left off. Also accepted in place of `webhook_id` on get and delete.
- `event_types` (list of enum, required) — Full list of event types this webhook should receive. At least one type is required. Send every type you want in this array (not incremental). See [Webhooks overview](https://docs.agentmail.to/webhooks-overview) for spam, blocked, and unauthenticated events and required permissions.
  - Allowed values: `message.received`, `message.received.spam`, `message.received.blocked`, `message.received.unauthenticated`, `message.sent`, `message.delivered`, `message.bounced`, `message.complained`, `message.rejected`, `message.opened`, `domain.verified`, `calendar.event.created`, `calendar.event.updated`, `calendar.event.deleted`, `calendar.event.responded`, `calendar.event.starting`, `calendar.event.ending`
- `inbox_ids` (list of string, optional) — Inboxes for which to send events. Maximum 10 per webhook.
- `pod_ids` (list of string, optional) — Pods for which to receive events. Maximum 10 channels (pods plus inboxes) per subscription. The subscription receives an event that matches any listed pod or inbox, so a listed pod already covers every inbox in it.

## Response

### 200

- `client_id` (string, required) — Required. Idempotency key of the subscription: creating again with the same `client_id` through the same route returns the existing subscription with a fresh token instead of a second subscription, so a restarted agent resumes where it left off. Also accepted in place of `webhook_id` on get and delete.
- `created_at` (datetime, required) — Time at which the subscription was created.
- `event_types` (list of enum, required) — Event types for which to send events.
  - Allowed values: `message.received`, `message.received.spam`, `message.received.blocked`, `message.received.unauthenticated`, `message.sent`, `message.delivered`, `message.bounced`, `message.complained`, `message.rejected`, `message.opened`, `domain.verified`, `calendar.event.created`, `calendar.event.updated`, `calendar.event.deleted`, `calendar.event.responded`, `calendar.event.starting`, `calendar.event.ending`
- `token` (string, required) — Credential for reading this subscription's events. Hand it to the Svix AutoConfig consumer (`AutoConfigConsumer` in the `svix` package for TypeScript and Python): `receive` returns the events queued since your last commit, `commit` marks them as processed. Returned by create only and never readable afterward. Create again with the same `client_id` to get a new token; the previous one stops working immediately.
- `updated_at` (datetime, required) — Time at which the subscription was last updated.
- `webhook_id` (string, required) — ID of webhook.
- `inbox_id` (string, optional) — ID of the inbox the subscription belongs to, if it was created for an inbox. This is not the list of inboxes it receives events for; see `inbox_ids`.
- `inbox_ids` (list of string, optional) — Inboxes for which to send events. Maximum 10 per webhook.
- `pod_id` (string, optional) — ID of the pod the subscription belongs to: the pod it was created in, or the pod of the inbox it belongs to. Absent for an organization subscription. This is not the list of pods it receives events for; see `pod_ids`.
- `pod_ids` (list of string, optional) — Pods for which to send events. Maximum 10 per webhook.

## Errors

### 400 Validation Error

- `name` (string, required) — Name of error.
- `errors` (any, required) — Validation errors. Each entry has a path and a message identifying the invalid field.
- `code` (string, optional) — Stable, machine-readable error code in snake_case (for example, not_found or missing_permission). Branch on this rather than the message text.
- `message` (string, optional) — Error message.
- `fix` (string, optional) — The concrete next action that resolves the error.
- `docs` (string, optional) — Link to the error reference entry for this code.

### 409 Conflict Error

- `name` (string, required) — Name of error.
- `message` (string, required) — Error message.
- `code` (string, optional) — Stable, machine-readable error code in snake_case (for example, not_found or missing_permission). Branch on this rather than the message text.
- `fix` (string, optional) — The concrete next action that resolves the error.
- `docs` (string, optional) — Link to the error reference entry for this code.

## Examples

**Request**

```json
{
  "client_id": "client_id",
  "event_types": [
    "message.received",
    "message.received"
  ]
}
```

**Response**

```json
{
  "client_id": "client_id",
  "created_at": "2024-01-15T09:30:00Z",
  "event_types": [
    "message.received",
    "message.received"
  ],
  "token": "token",
  "updated_at": "2024-01-15T09:30:00Z",
  "webhook_id": "webhook_id",
  "inbox_id": "inbox_id",
  "inbox_ids": [
    "inbox_ids",
    "inbox_ids"
  ],
  "pod_id": "pod_id",
  "pod_ids": [
    "pod_ids",
    "pod_ids"
  ]
}
```

**SDK Code**

```python
import requests

url = "https://api.agentmail.to/v0/webhooks/polling"

payload = {
    "client_id": "client_id",
    "event_types": ["message.received", "message.received"]
}
headers = {
    "Authorization": "Bearer <api_key>",
    "Content-Type": "application/json"
}

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

print(response.json())
```

```javascript
const url = 'https://api.agentmail.to/v0/webhooks/polling';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <api_key>', 'Content-Type': 'application/json'},
  body: '{"client_id":"client_id","event_types":["message.received","message.received"]}'
};

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

```go
package main

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

func main() {

	url := "https://api.agentmail.to/v0/webhooks/polling"

	payload := strings.NewReader("{\n  \"client_id\": \"client_id\",\n  \"event_types\": [\n    \"message.received\",\n    \"message.received\"\n  ]\n}")

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

	req.Header.Add("Authorization", "Bearer <api_key>")
	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
require 'uri'
require 'net/http'

url = URI("https://api.agentmail.to/v0/webhooks/polling")

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

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <api_key>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"client_id\": \"client_id\",\n  \"event_types\": [\n    \"message.received\",\n    \"message.received\"\n  ]\n}"

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

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

HttpResponse<String> response = Unirest.post("https://api.agentmail.to/v0/webhooks/polling")
  .header("Authorization", "Bearer <api_key>")
  .header("Content-Type", "application/json")
  .body("{\n  \"client_id\": \"client_id\",\n  \"event_types\": [\n    \"message.received\",\n    \"message.received\"\n  ]\n}")
  .asString();
```

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

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.agentmail.to/v0/webhooks/polling', [
  'body' => '{
  "client_id": "client_id",
  "event_types": [
    "message.received",
    "message.received"
  ]
}',
  'headers' => [
    'Authorization' => 'Bearer <api_key>',
    'Content-Type' => 'application/json',
  ],
]);

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

```csharp
using RestSharp;

var client = new RestClient("https://api.agentmail.to/v0/webhooks/polling");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <api_key>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"client_id\": \"client_id\",\n  \"event_types\": [\n    \"message.received\",\n    \"message.received\"\n  ]\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = [
  "Authorization": "Bearer <api_key>",
  "Content-Type": "application/json"
]
let parameters = [
  "client_id": "client_id",
  "event_types": ["message.received", "message.received"]
] as [String : Any]

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

let request = NSMutableURLRequest(url: NSURL(string: "https://api.agentmail.to/v0/webhooks/polling")! 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()
```