Submit an event

Submits a signal to an existing outcome. The request body and token are validated immediately, then the event is enqueued for asynchronous processing. Identity checks, condition evaluation and state transitions happen in a background consumer with automatic retries.

The event names its outcome by outcome_key. Create the outcome first with POST /v1/outcomes: an event whose outcome_key has no outcome is discarded. Events for CONFIRMED or FAILED outcomes are rejected as OUTCOME_NOT_OPEN.

Returns 202 Accepted on success.

The request body is capped at 256 KiB. Larger bodies are rejected with 413 PAYLOAD_TOO_LARGE. Keep properties small and store large metadata (documents, transcripts, images) in your own storage, sending only a reference.

Example

curl -X POST https://api.thewitn.com/v1/events \
  -H "Authorization: Bearer $WITN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "outcome_key": "support:ticket:1001",
    "action": "csat_received",
    "properties": {
      "value": 4,
      "settles_at": "2024-01-18T10:00:00Z"
    }
  }'

properties is an open object. Send whatever fields your workflow produces. The whole object is stored on the event log and any field is available to a condition.

A comparison or match reads one property. By default that is properties.value:

{ "fact": "csat_received", "operator": "gte", "value": 3 }

To read a different field, name it on the fact after a colon, action:property. So you can keep several values on one event and compare any of them:

{ "outcome_key": "...", "action": "review", "properties": { "score": 0.92, "tier": "gold" } }

Reference them as review:score or review:tier. Reach nested fields with dots, review:meta.overall.

properties.settles_at is reserved: it optionally overrides the next settlement timestamp. Use it when an event carries its own business deadline, such as an appointment time plus a grace period. It must be an ISO datetime string.

Idempotency

idempotency_key is optional. Send one to make retries safe. The same key on the same outcome always maps to the same event, so if a request times out after the server already accepted it, you can retry with the same key and it will not create a second billable event.

Keys are scoped to your account and outcome key, so two accounts or two outcomes can use the same idempotency key without clashing. Reusing an idempotency key on the same outcome with a different body keeps the first event and drops the later one. Leave the key out and every request is treated as a new event.

curl -X POST https://api.thewitn.com/v1/events \
  -H "Authorization: Bearer $WITN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "outcome_key": "support:ticket:1001",
    "action": "csat_received",
    "idempotency_key": "csat-1001-attempt-1"
  }'

Multiple events with the same action

When you submit more than one event with the same action, there are two separate rules:

FieldRule
The property a condition reads (value by default, or the action:property you named)A comparison uses the latest event for that action. A count tallies every occurrence.
properties.settles_atOverrides the next settles_at for the outcome. If omitted, witn uses the event timestamp plus the task's settlement_period.

Concurrent submissions

Concurrent submissions return 202 Accepted once they are enqueued. If the first event advances the outcome before the second is processed, the background consumer discards the second event because the outcome is already terminal:

const res = await fetch('https://api.thewitn.com/v1/events', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.WITN_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    outcome_key: 'support:ticket:1001',
    action: 'csat_received',
  }),
})

if (res.status === 202) {
  // The event was accepted for async processing.
  // Inspect the outcome later if you need the final state.
}

Errors

CodeStatusWhen
VALIDATION_ERROR400outcome_key or action is missing or invalid.
TOKEN_INVALID401The token is missing or not recognised.
PAYLOAD_TOO_LARGE413The event body exceeded the 256 KiB ingest limit.

On this page