# Send Event

> POST /events/send — send a custom event to trigger automations for a contact.

`POST /events/send`

Records a custom event for a contact and immediately enrolls that contact into every **enabled** [automation](https://www.sendping.co/docs/automations/overview) **belonging to the given `domain`** whose trigger matches the event name. `domain` is required — every automation belongs to one of your sending domains, so the same event name (e.g. `user.created`) used across several products can never trigger another product's automations. The contact is identified by `contact_id` or `email` — supply one of the two. If you send both, `contact_id` wins and `email` is ignored. If an email is supplied and no matching contact exists in that domain's contacts, one is created automatically when the run starts; each domain keeps its own contact records, so unsubscribe state stays separate per domain.

**Body parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `event` | string | Yes | The custom event name. Must not start with the reserved `sendping:` prefix. |
| `domain` | string | Yes | The sending domain this event belongs to (one of your domains, e.g. `yourdomain.com`). Only automations belonging to this domain are triggered. |
| `contact_id` | string | No | Identify the contact by id. Provide `contact_id` OR `email`; when both are present `contact_id` takes precedence and `email` is ignored. An id that matches no contact in this domain returns `not_found` (404). |
| `email` | string | No | Identify the contact by email address. Provide `contact_id` OR `email`. If no contact with this address exists in the domain's contacts, one is created when the run starts. |
| `payload` | object | No | Optional. Arbitrary key-value data associated with the event. Must be an object (not an array). Fields become available as `event.*` variables in automation steps. |

> **Warning:** If an [event definition](https://www.sendping.co/docs/api/events-create) with a schema exists for this event name, the payload is validated against it — fields that don't match the expected type are rejected with a `422` error and the event is not delivered.

**Node.js**

```js
import { SendPing } from 'sendping';

const mb = new SendPing('mb_xxxxxxxxx');

const { data, error } = await mb.events.send({
  "event": "purchase.completed",
  "domain": "yourdomain.com",
  "email": "user@example.com",
  "payload": {
    "plan": "pro",
    "amount": 49
  }
});
console.log({ data, error });
```

**Ruby**

```ruby
require "sendping"

SendPing.api_key = "mb_xxxxxxxxx"

SendPing::Events.send({
  "event": "purchase.completed",
  "domain": "yourdomain.com",
  "email": "user@example.com",
  "payload": {
    "plan": "pro",
    "amount": 49
  }
})
```

**PHP**

```php
<?php
require 'vendor/autoload.php';

use SendPing\SendPing;

$sendping = SendPing::client('mb_xxxxxxxxx');

$sendping->events->send([
  'event' => "purchase.completed",
  'domain' => "yourdomain.com",
  'email' => "user@example.com",
  'payload' => [
    'plan' => "pro",
    'amount' => 49
  ]
]);
```

**Python**

```python
import sendping

sendping.api_key = "mb_xxxxxxxxx"

sendping.Events.send({
  "event": "purchase.completed",
  "domain": "yourdomain.com",
  "email": "user@example.com",
  "payload": {
    "plan": "pro",
    "amount": 49
  }
})
```

**Go**

```go
import "github.com/shekhu10/sendping-sdks/sendping-go"

client := sendping.NewClient("mb_xxxxxxxxx")

event, err := client.Events.Send(&sendping.SendEventRequest{
    Event:   "purchase.completed",
    Domain:  "yourdomain.com",
    Email:   "user@example.com",
    Payload: map[string]any{"plan": "pro", "amount": 49},
})
```

**Rust**

```rust
use sendping::{SendEventOptions, SendPing};

let mb = SendPing::new("mb_xxxxxxxxx");

let params = SendEventOptions::new("purchase.completed", "yourdomain.com")
    .with_email("user@example.com")
    .with_payload_entry("plan", serde_json::json!("pro"))
    .with_payload_entry("amount", serde_json::json!(49));
let _event = mb.events.send(params).await?;
```

**Java**

```java
import co.sendping.SendPing;
import co.sendping.SendPingResponse;
import co.sendping.requests.SendEventRequest;

SendPing sendping = new SendPing("mb_xxxxxxxxx");

SendEventRequest request = SendEventRequest.builder()
        .event("purchase.completed")
        .domain("yourdomain.com")
        .email("user@example.com")
        .payload("plan", "pro")
        .payload("amount", 49)
        .build();

SendPingResponse response = sendping.events().send(request);
```

**.NET**

```csharp
using SendPing;

ISendPing sendping = SendPingClient.Create("mb_xxxxxxxxx");

var resp = await sendping.EventSendAsync(new EventSendOptions
{
    Event = "purchase.completed",
    Domain = "yourdomain.com",
    Email = "user@example.com",
    Payload = new Dictionary<string, object?>
    {
        ["plan"] = "pro",
        ["amount"] = 49,
    },
});
```

**cURL**

```bash
curl -X POST 'https://www.sendping.co/api/events/send' \
  -H 'Authorization: Bearer mb_xxxxxxxxx' \
  -H 'Content-Type: application/json' \
  -d '{
  "event": "purchase.completed",
  "domain": "yourdomain.com",
  "email": "user@example.com",
  "payload": {
    "plan": "pro",
    "amount": 49
  }
}'
```

**CLI**

```bash
sendping events send \
  --name 'purchase.completed' \
  --domain 'yourdomain.com' \
  --email 'user@example.com' \
  --data '{"plan":"pro","amount":49}'
```

### Response

```json
{
  "object": "event",
  "id": "b6d24b8e-af0b-4c3c-be0c-359bbd97381e",
  "event": "purchase.completed",
  "contact_id": "e169aa45-1ecf-4183-9955-b1499d5701d3",
  "enrolled": 1
}
```

`enrolled` is the number of automations the contact was enrolled into as a result of this event. Errors: `validation_error` (422) if `event`, the contact identifier, or `domain` is missing, the domain is not one of yours, the event name uses the reserved prefix, or the payload does not match the event definition's schema; `not_found` (404) when the supplied `contact_id` matches no contact in that domain; `restricted_api_key` (401) when a domain-scoped key targets a `domain` outside its scope; `automation_quota_exceeded` (429) when the rolling 30-day automation-run quota is exhausted — the body carries `kind: "automation_runs"` with `used`, `limit`, `period` and `next_plan`. See [Errors](https://www.sendping.co/docs/api/errors).
