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

# Create Endpoint | Webhooks API

> Create endpoint via the Atoa Webhooks API, request parameters, response schema and code samples in cURL, Python, JavaScript, PHP, Go and Java.

Register a webhook endpoint and subscribe to one or more event types in a single call. Use [List event types](https://docs.paywithatoa.com/api-reference/webhook/v2/list-event-types.md) to get the full list of available event type names.

> [!NOTE]
>
> **Initial registration only.** Use this endpoint to register a new URL with its initial event subscriptions. To change events or authentication on an existing endpoint, use [Update endpoint](https://docs.paywithatoa.com/api-reference/webhook/v2/update-endpoint.md). To change the URL, delete the endpoint and create a new one.

### Authorization

Bearer `<token>`

**Request Body Schema**

**url** `string` *required*

The HTTPS endpoint URL that will receive webhook deliveries. Must return HTTP `200` on success — failures are retried with exponential back-off for up to 24 hours. **This URL cannot be changed after creation** — to use a different URL, delete the endpoint and create a new one.

**events** `string[]` *required*

One or more event types to subscribe to. Valid values: `PAYMENTS_STATUS`, `EXPIRED_STATUS`, `REFUND_STATUS`, `POS_PAYMENT_STATUS`, `PAYMENT_METHOD_STATUS`. Subscribing to `POS_PAYMENT_STATUS` requires a webhook signing key to be generated first.

Each event type supports a maximum of **3 registered endpoints**. If an event type already has 3 endpoints, adding another endpoint subscribed to that event returns a `400` error. Use [List endpoints](https://docs.paywithatoa.com/api-reference/webhook/v2/list-endpoints.md) to check current registrations before creating.

**description** `string`

Optional label for this endpoint (max 100 characters). Shown in the Atoa Dashboard to help identify the endpoint.

**authentication** `object`

Optional. Credentials Atoa will include in every webhook delivery to authenticate against your server. Two methods are supported — choose one. Fields from different methods cannot be mixed.

> **None — no authentication**
>
> Omit the `authentication` field entirely. No credentials will be sent with deliveries. Use [signature verification](https://docs.paywithatoa.com/api-reference/webhook/introduction.md#signature-verification) to validate requests on your side.

> **Basic Auth — username + password**
>
> Atoa includes an `Authorization: Basic <base64(username:password)>` header in every delivery request. Pass both fields together.
>
> **username** `string` *required*
>
> Username for HTTP Basic Authentication.
>
> **password** `string` *required*
>
> Password for HTTP Basic Authentication.

> **OAuth 2.0 — client credentials flow**
>
> Before each delivery, Atoa calls your token endpoint using the `client_credentials` grant to obtain a short-lived access token, then includes it as `Authorization: Bearer <token>` in the delivery request. Pass all three fields together.
>
> **clientId** `string` *required*
>
> Client ID registered with your authorisation server.
>
> **clientSecret** `string` *required*
>
> Client secret for the above client ID.
>
> **authUrl** `string` *required*
>
> Your token endpoint URL (e.g. `https://auth.your-server.com/oauth/token`). Atoa will POST to this URL to fetch an access token before each delivery.

**Response**

**id** `string`

Unique identifier for the endpoint.

**url** `string`

The registered endpoint URL.

**description** `string`

The endpoint description, or `null` if not set.

**environment** `string`

`SANDBOX` or `PRODUCTION`, derived from the API key used.

**events** `array`

Subscribed event types.

**event** `string`

Event type name (e.g. `PAYMENTS_STATUS`).

**label** `string`

Human-readable label (e.g. `Payment Status`).

**hasAuthentication** `boolean`

Whether endpoint authentication is configured.

**authenticationType** `string`

`BASIC`, `OAUTH2`, or `null` if no authentication is configured.

**failureCount** `number`

Consecutive failed deliveries since the last successful delivery. Resets to `0` on success.

**lastDeliveredAt** `string`

ISO 8601 timestamp of the last successful delivery, or `null` if never delivered.

```bash No Auth theme={null}
curl --request POST \
  --url https://api.atoa.me/api/webhook/v2/endpoints \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '{
    "url": "https://your-server.com/webhooks",
    "events": ["PAYMENTS_STATUS", "REFUND_STATUS"],
    "description": "Production orders endpoint"
  }'
```

```bash Basic Auth theme={null}
curl --request POST \
  --url https://api.atoa.me/api/webhook/v2/endpoints \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '{
    "url": "https://your-server.com/webhooks",
    "events": ["PAYMENTS_STATUS", "REFUND_STATUS"],
    "description": "Production orders endpoint",
    "authentication": {
      "username": "your-username",
      "password": "your-password"
    }
  }'
```

```bash OAuth 2.0 theme={null}
curl --request POST \
  --url https://api.atoa.me/api/webhook/v2/endpoints \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '{
    "url": "https://your-server.com/webhooks",
    "events": ["PAYMENTS_STATUS", "REFUND_STATUS"],
    "description": "Production orders endpoint",
    "authentication": {
      "clientId": "your-client-id",
      "clientSecret": "your-client-secret",
      "authUrl": "https://auth.your-server.com/oauth/token"
    }
  }'
```

```python Python theme={null}
import requests

url = "https://api.atoa.me/api/webhook/v2/endpoints"

payload = {
    "url": "https://your-server.com/webhooks",
    "events": ["PAYMENTS_STATUS", "REFUND_STATUS"],
    "description": "Production orders endpoint"
}
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.request("POST", url, json=payload, headers=headers)
print(response.text)
```

```javascript JavaScript theme={null}
const options = {
  method: 'POST',
  headers: { Authorization: 'Bearer <token>', 'Content-Type': 'application/json' },
  body: JSON.stringify({
    url: 'https://your-server.com/webhooks',
    events: ['PAYMENTS_STATUS', 'REFUND_STATUS'],
    description: 'Production orders endpoint'
  })
};

fetch('https://api.atoa.me/api/webhook/v2/endpoints', options)
  .then(response => response.json())
  .then(response => console.log(response))
  .catch(err => console.error(err));
```

```php PHP theme={null}
<?php

$curl = curl_init();

curl_setopt_array($curl, [
  CURLOPT_URL => "https://api.atoa.me/api/webhook/v2/endpoints",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => "",
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "POST",
  CURLOPT_POSTFIELDS => json_encode([
    "url" => "https://your-server.com/webhooks",
    "events" => ["PAYMENTS_STATUS", "REFUND_STATUS"],
    "description" => "Production orders endpoint"
  ]),
  CURLOPT_HTTPHEADER => [
    "Authorization: Bearer <token>",
    "Content-Type: application/json"
  ],
]);

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
  echo "cURL Error #:" . $err;
} else {
  echo $response;
}
```

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

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

func main() {

	url := "https://api.atoa.me/api/webhook/v2/endpoints"

	payload := strings.NewReader(`{
    "url": "https://your-server.com/webhooks",
    "events": ["PAYMENTS_STATUS", "REFUND_STATUS"],
    "description": "Production orders endpoint"
  }`)

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

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

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

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

	fmt.Println(string(body))

}
```

```java Java theme={null}
HttpResponse<String> response = Unirest.post("https://api.atoa.me/api/webhook/v2/endpoints")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"url\": \"https://your-server.com/webhooks\",\n  \"events\": [\"PAYMENTS_STATUS\", \"REFUND_STATUS\"],\n  \"description\": \"Production orders endpoint\"\n}")
  .asString();
```

```json 200 theme={null}
{
  "id": "4a124f25-fe8d-47a0-92c8-16d94cbfe24c",
  "url": "https://your-server.com/webhooks",
  "description": "Production orders endpoint",
  "environment": "PRODUCTION",
  "events": [
    { "event": "PAYMENTS_STATUS", "label": "Payment Status" },
    { "event": "REFUND_STATUS", "label": "Refund Status" }
  ],
  "hasAuthentication": false,
  "authenticationType": null,
  "failureCount": 0,
  "lastDeliveredAt": null
}
```

```json 400 (events required) theme={null}
{
  "name": "BAD_REQUEST",
  "message": "At least one event type is required.",
  "status": 400
}
```

```json 400 (duplicate events) theme={null}
{
  "name": "BAD_REQUEST",
  "message": "Duplicate event types are not allowed.",
  "status": 400
}
```

```json 400 (URL not HTTPS) theme={null}
{
  "name": "BAD_REQUEST",
  "message": "Endpoint URL must use HTTPS.",
  "status": 400
}
```

```json 400 (URL is localhost) theme={null}
{
  "name": "BAD_REQUEST",
  "message": "Endpoint URL cannot point to localhost.",
  "status": 400
}
```

```json 400 (URL is IP address) theme={null}
{
  "name": "BAD_REQUEST",
  "message": "Endpoint URL cannot use an IP address.",
  "status": 400
}
```

```json 400 (URL already registered) theme={null}
{
  "name": "BAD_REQUEST",
  "message": "This webhook URL is already registered. Use the update API to modify the events or authentication details for this endpoint.",
  "status": 400
}
```

```json 400 (capacity exceeded) theme={null}
{
  "name": "BAD_REQUEST",
  "message": "Payment Status has reached the maximum limit of 3 endpoints per event type.",
  "status": 400
}
```

```json 400 (POS without signing secret) theme={null}
{
  "name": "BAD_REQUEST",
  "message": "POS Payment Status requires V2 signing. Please generate a signing secret from the dashboard to proceed.",
  "status": 400
}
```

```json 401 theme={null}
{
  "name": "UNAUTHORIZED",
  "message": "Unauthorized",
  "status": 401,
  "errors": "[]"
}
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.