# Oppy Events API and Automation Rules: The Complete Guide

Published: 2026-03-27
Updated: 2026-07-10
Source: https://docs.oppy.pro/n/oppy-welcome-kit-events-api-timeline-guide
Account: Oppy Inc

---

# Oppy Events API and Automation Rules

The Events Timeline is how external tools talk to Oppy. Every time something happens in a business (a payment, a form submission, a deal closing), an event can be sent to Oppy, and Automation Rules respond to it automatically: no polling, no manual checking, no copy-pasting between systems.

**Who this is for:** anyone who wants to understand how Oppy connects to the rest of a tech stack: a current customer wiring up a tool, a prospect evaluating whether Oppy fits their stack, or a developer implementing the integration.

&gt; [!TIP]
&gt; New to Oppy? Here&#39;s what this unlocks: any tool that can make an HTTP request (Stripe, Salesforce, HubSpot, a CRM, a form builder, Zapier, or custom code) can notify Oppy the moment something happens, and Oppy can act on it instantly: send a message, update a contact, alert a team, or kick off a workflow. No custom integration code required on Oppy&#39;s side.

---

## 3 Steps to Post Your First Event

### Step 1: Get your API key

Go to [Settings → API Keys](https://app.oppy.pro/profile) and copy your key.

### Step 2: Send an event

Most senders can set a custom header. Use your account API key:

```bash
curl -X POST https://io.oppy.pro/api/events \
  -H &quot;Content-Type: application/json&quot; \
  -H &quot;X-API-Key: YOUR_API_KEY&quot; \
  -d &#39;{
    &quot;event_type&quot;: &quot;payment_received&quot;,
    &quot;message&quot;: &quot;New payment from Jane Smith&quot;,
    &quot;source&quot;: &quot;stripe&quot;
  }&#39;
```

If your sender can&#39;t set custom headers (common with CRMs, form tools, and Zapier-style webhooks), pass a scoped ingress token in the URL instead. No headers needed at all:

```bash
curl -X POST &quot;https://io.oppy.pro/api/events?token=YOUR_INGRESS_TOKEN&quot; \
  -H &quot;Content-Type: application/json&quot; \
  -d &#39;{
    &quot;event_type&quot;: &quot;payment_received&quot;,
    &quot;message&quot;: &quot;New payment from Jane Smith&quot;,
    &quot;source&quot;: &quot;stripe&quot;
  }&#39;
```

An ingress token is tied to one source name, so events sent with it are automatically namespaced to that source (see below) even if the payload never mentions it.

### Step 3: Check your Timeline

Go to [Events](https://app.oppy.pro/events). Your event will appear instantly.

That&#39;s it. Only `event_type` is required. Add `message`, `source`, and `payload` to make events more useful.

---

## Request Fields

**Endpoint:** `POST https://io.oppy.pro/api/events`

**Two ways to authenticate:**

| Mode | How | Best for |
|------|-----|----------|
| Header | `X-API-Key: YOUR_API_KEY` | Your full account-admin API key. Use when the sender lets you set custom headers. |
| Query token | `?token=YOUR_INGRESS_TOKEN` on the URL | A scoped &quot;events ingress&quot; token tied to one source name. Use when the sender can&#39;t set custom headers (most CRMs, Zapier, Make.com, form tools). |

Get an ingress token from **Settings → API Keys**, or ask your Oppy concierge to create one scoped to a source (e.g. &quot;stripe&quot;, &quot;hubspot&quot;, &quot;sierra&quot;).

| Field | Required | Description |
|-------|----------|-------------|
| `event_type` | **Yes** | What happened: `payment_received`, `form_submitted`, `deal_closed_won` |
| `source` | No | Where it came from: `stripe`, `salesforce`, `activecampaign` |
| `message` | No | Human-readable summary shown in the timeline |
| `payload` | No | Any JSON (the full webhook body, custom fields, anything) |
| `description` | No | Longer description for context |
| `metadata` | No | Internal metadata (not shown in timeline UI) |
| `status` | No | `active` (default), `completed`, `pending`, `inactive` |

---

## How Oppy Names Your Event

You don&#39;t have to send a perfectly-formatted `event_type`. Oppy looks for the event name in common fields (`event_type`, `event`, `type`, `eventType`, or a header some vendors send) and auto-detects it from whatever your sender provides.

Whatever name it finds gets **namespaced to your source**, so different vendors never collide. A `payment.succeeded` event sent with `source: &quot;stripe&quot;` (or a Stripe-scoped token) lands as `stripe.payment.succeeded`. The same event name from a different source stays completely separate in your Timeline and in Automation Rules.

## Verification Handshakes

Some platforms (Slack, Monday.com, and similar) send a one-time &quot;challenge&quot; request to confirm the endpoint is real before they&#39;ll start delivering events. `POST /api/events` recognizes these automatically and echoes the challenge back, so you can point Slack/Monday&#39;s webhook setup straight at the endpoint with no extra configuration.

## Sending Many Events at Once

Some integrations batch multiple events into one request. Send a JSON array instead of a single object and Oppy will fan each item out as its own event:

```json
[
  { &quot;event_type&quot;: &quot;contact_updated&quot;, &quot;source&quot;: &quot;hubspot&quot;, &quot;payload&quot;: { &quot;id&quot;: &quot;1&quot; } },
  { &quot;event_type&quot;: &quot;deal_stage_changed&quot;, &quot;source&quot;: &quot;hubspot&quot;, &quot;payload&quot;: { &quot;id&quot;: &quot;2&quot; } }
]
```

## Limits

To keep things fast and fair for everyone: up to **120 events per minute** per source, and **128KB** per request. If you&#39;re sending a high-volume integration and expect to need more, talk to your Oppy contact.

---

## Real-World Examples

### Stripe: Payment received

```json
{
  &quot;event_type&quot;: &quot;payment_received&quot;,
  &quot;message&quot;: &quot;Payment of $49 received&quot;,
  &quot;source&quot;: &quot;stripe&quot;,
  &quot;payload&quot;: {
    &quot;customer_email&quot;: &quot;jane@example.com&quot;,
    &quot;amount&quot;: 4900,
    &quot;plan&quot;: &quot;pro&quot;
  }
}
```

### Salesforce: Deal closed

```json
{
  &quot;event_type&quot;: &quot;deal_closed_won&quot;,
  &quot;message&quot;: &quot;Deal closed: Acme Corp Enterprise&quot;,
  &quot;source&quot;: &quot;salesforce&quot;,
  &quot;payload&quot;: {
    &quot;opportunity_id&quot;: &quot;006xx000001abc&quot;,
    &quot;account_name&quot;: &quot;Acme Corp&quot;,
    &quot;amount&quot;: 25000,
    &quot;owner_email&quot;: &quot;rep@yourco.com&quot;,
    &quot;stage&quot;: &quot;Closed Won&quot;
  }
}
```

### ActiveCampaign: Contact tagged

```json
{
  &quot;event_type&quot;: &quot;contact_tag_added&quot;,
  &quot;message&quot;: &quot;Contact tagged as hot-lead&quot;,
  &quot;source&quot;: &quot;activecampaign&quot;,
  &quot;payload&quot;: {
    &quot;contact_email&quot;: &quot;buyer@example.com&quot;,
    &quot;tag&quot;: &quot;hot-lead&quot;,
    &quot;list&quot;: &quot;Sales Pipeline&quot;,
    &quot;automation&quot;: &quot;Lead Scoring v2&quot;
  }
}
```

### Typeform: Form submitted

```json
{
  &quot;event_type&quot;: &quot;form_submitted&quot;,
  &quot;message&quot;: &quot;New lead form submitted&quot;,
  &quot;source&quot;: &quot;typeform&quot;,
  &quot;payload&quot;: {
    &quot;name&quot;: &quot;Alex Johnson&quot;,
    &quot;email&quot;: &quot;alex@example.com&quot;,
    &quot;interest&quot;: &quot;Enterprise plan&quot;
  }
}
```

### Calendly: Appointment booked

```json
{
  &quot;event_type&quot;: &quot;appointment_booked&quot;,
  &quot;message&quot;: &quot;Demo call booked for Friday 2pm&quot;,
  &quot;source&quot;: &quot;calendly&quot;,
  &quot;payload&quot;: {
    &quot;guest_email&quot;: &quot;prospect@company.com&quot;,
    &quot;meeting_at&quot;: &quot;2026-04-01T14:00:00Z&quot;
  }
}
```

---

## Code Snippets

### JavaScript / Node.js

```javascript
await fetch(&#39;https://io.oppy.pro/api/events&#39;, {
  method: &#39;POST&#39;,
  headers: {
    &#39;Content-Type&#39;: &#39;application/json&#39;,
    &#39;X-API-Key&#39;: process.env.OPPY_API_KEY,
  },
  body: JSON.stringify({
    event_type: &#39;payment_received&#39;,
    source: &#39;stripe&#39;,
    message: &#39;New payment received&#39;,
    payload: { customer_email: &#39;jane@example.com&#39;, amount: 4900 },
  }),
});
```

### Python

```python
import requests

requests.post(
    &#39;https://io.oppy.pro/api/events&#39;,
    headers={
        &#39;Content-Type&#39;: &#39;application/json&#39;,
        &#39;X-API-Key&#39;: OPPY_API_KEY,
    },
    json={
        &#39;event_type&#39;: &#39;deal_closed_won&#39;,
        &#39;source&#39;: &#39;salesforce&#39;,
        &#39;message&#39;: &#39;Deal closed: Acme Corp&#39;,
        &#39;payload&#39;: {&#39;account_name&#39;: &#39;Acme Corp&#39;, &#39;amount&#39;: 25000},
    },
)
```

### Zapier / Make.com (no code)

Use **Webhooks by Zapier → POST** or **Make.com HTTP module** to POST to `https://io.oppy.pro/api/events` with your API key in the `X-API-Key` header.

---

## Automation Rules

Once events appear in the Timeline, create rules to respond automatically:

1. Go to **Automations** in the sidebar
2. Create a new rule matching your `event_type`
3. Set an action: send a message, update a contact, notify your team

**Example:** When `payment_received` arrives → Oppy looks up the contact and sends a personalized thank-you email.

For the plain-English, business-use-case version of this (no code, just outcomes), see [Public Events &amp; Automation Rules: A Guide to What&#39;s Possible](https://app.oppy.pro/n/public-events-automation-rules-customer-guide).

---

## Need Help?

- **Ask your Oppy concierge** (blue icon, bottom right): it can build automations for you
- **Chat with AI about this guide:**
  - [Open in Claude](https://claude.ai/new?q=Read%20and%20help%20me%20implement%20the%20Oppy%20Events%20API%20from%20this%20guide%3A%20https%3A%2F%2Fapp.oppy.pro%2Fn%2Foppy-welcome-kit-events-api-timeline-guide)
  - [Open in ChatGPT](https://chatgpt.com/?hints=discuss&amp;q=Read%20and%20help%20me%20implement%20the%20Oppy%20Events%20API%20from%20this%20guide%3A%20https%3A%2F%2Fapp.oppy.pro%2Fn%2Foppy-welcome-kit-events-api-timeline-guide)
