Source: https://datafa.st/docs/api/website/goals/create
Markdown source: https://datafa.st/docs/api/website/goals/create.md
Description: Record a server-side custom goal event for a visitor. This is the recommended way to track signups, feature usage, and other backend-confirmed actions — more reliable than client-side tracking alone. See [custom goals](/docs/custom-goals) for naming conventions and dashboard setup.

# Create a custom goal

`POST https://datafa.st/api/v1/goals`

Record a server-side custom goal event for a visitor. This is the recommended way to track signups, feature usage, and other backend-confirmed actions — more reliable than client-side tracking alone. See [custom goals](/docs/custom-goals) for naming conventions and dashboard setup.

Goal names are lowercased and spaces become underscores. The name `identify` is reserved.

> **Related:** [Custom goals](/docs/custom-goals) · [Journey tracking](/changelog/goal-tracking)

## Request

#### Query parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `websiteId` | string | Required with dft_ | Required with a `dft_` account token on Website API routes. Omit with a `df_` website key. Example: `?websiteId=665f0b3c4d2e1a0012345678`. |

#### Body parameters

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `datafast_visitor_id` | string | Yes | Visitor UUID from the `datafast_visitor_id` cookie or tracking script. Example: `"a3ab2331-989f-4cfa-91c6-2461c9e3c6bd"`. Alias: `visitorId` on some endpoints. |
| `visitorId` | string | No | Alias for `datafast_visitor_id` on endpoints that accept both names. |
| `name` | string | Yes | Goal name stored lowercase; spaces → `_`. Allowed: `a-z`, `0-9`, `_`, `-`, `:`. Max 64 chars. Reserved: `identify`. Example: `"newsletter_signup"`. See [custom goals](/docs/custom-goals). |
| `description` | string | No | Optional description stored with the event. Example: `"Newsletter form submit"`. |
| `metadata` | object | No | Optional key/value pairs on the event. Max 10 keys; keys `^[a-z0-9_-]+$` (max 64); values max 255 chars. Example: `{"plan": "pro", "source": "api"}`. |

#### Example request body

```json
{
  "datafast_visitor_id": "a3ab2331-989f-4cfa-91c6-2461c9e3c6bd",
  "name": "newsletter_signup",
  "metadata": { "plan": "pro" }
}
```

## Response

Returns a JSON object with `status: "success"` and endpoint-specific fields in `data` (and `pagination` when the endpoint is paginated).

#### Response fields

| Field | Type | Description |
| --- | --- | --- |
| `status` | string | `success`. |
| `data[].message` | string | Human-readable confirmation or status message for the operation. |
| `data[].eventId` | string | ObjectId of the event created by DataFast. |

## Authentication

- **`df_` website API key:** The website is inferred from the key. You do not need a `websiteId` query parameter.
- **`dft_` account token:** Requires `goals:write` permission and `?websiteId=` on every request. The token must be allowed to access that website.

Read [authentication and scopes](/docs/api/authentication) for token creation, permission lists, and scoped tokens.

### Errors

**400** — Missing fields, invalid goal name format, reserved name, invalid metadata, or invalid JSON body.

**403** — Tracking suspended for this website.

**404** — Visitor has no pageviews on this website.

See [API errors](/docs/api#errors) for the standard error envelope, auth failures, validation errors, permission errors, and rate limits.

## Code examples

### Example request

```bash
curl -X POST "https://datafa.st/api/v1/goals" \
  -H "Authorization: Bearer df_xxx" \
  -H "Content-Type: application/json" \
  -d '{"datafast_visitor_id":"a3ab2331-989f-4cfa-91c6-2461c9e3c6bd","name":"newsletter_signup","metadata":{"plan":"pro"}}'
```

### Success response

```json
{
  "status": "success",
  "data": [{
    "message": "Custom event created successfully",
    "eventId": "67f8b9b5c320277df9a9d681"
  }]
}
```
