Skip to main content
A Reconify sender does three things: it posts batches of events, it reads every item result, and it retries without creating duplicate evidence. This guide covers all three with a write or admin key, which you create in Authentication.

Anatomy of an event

An event answers four questions at once: which journey it belongs to, what happened, which operation it is part of, and which entity the money moves toward. Everything else is context that makes the evaluation sharper.

The fields you send

Two of those fields fill themselves in when you leave them out, and the result says so through a warnings entry. An absent id receives a generated one, marked id_generated, and an absent occurred_at defaults to the receipt time, marked occurred_at_generated. Both defaults cost you something: a generated ID makes the event unsafe to retry, and a defaulted timestamp measures deadlines from when the request arrived rather than from when the money moved. The contract rejects any field it does not define, which is why source-only context goes into metadata or data rather than onto the event itself.

Metadata and personal data

Reconify retains event metadata as evidence. Use it for opaque internal identifiers and operational context that does not identify a person. Do not send names, email addresses, phone numbers, postal addresses, or other personal data in metadata.
An identifier is not automatically anonymous because it is hashed. Use a stable internal identifier that does not reveal a person and cannot be derived from their contact details.
For example, an internal customer ID is suitable metadata:
Compliant metadata
An email address is personal data and must not be sent:
Non-compliant metadata
The same rule applies whether you call POST /v2/events directly or use client.ingestion.ingestMonitoringEvents in the TypeScript SDK. Keep the lookup from your opaque ID to the person in your own authorized system.

The data object

data carries what a provider or a failure knows about the event. Enrich events with provider data covers the integration side of those provider fields.

The event a read returns

A read returns the normalized event, which is not identical to what you sent. Some values come from you, some Reconify derives, and some Reconify observes.

Send one event

The smallest useful request carries a single event in the events array:

Send a batch

One request carries 1 to 500 events, and the response keeps the order you sent them. Two events that share a reference belong to the same operation, so a batch often carries a whole flow:
cURL
Limits and pagination covers the body and event size bounds.

Read every result

Reconify validates each item independently, so every event comes back with one of three outcomes:
  • accepted means Reconify stored the event.
  • duplicate means the same event ID and content were already stored.
  • rejected means Reconify stored nothing, and code, field, and message explain why.
An HTTP 202 covers a mixed batch. A batch where every item fails returns 422. Because of that, the status alone never tells you what landed, and your handler reads the results array:
The index locates the item in the array you submitted, which keeps the customer reference out of your logs. Each code points at one fix:

Retry safely

A retry that reuses the same event IDs and the same payloads is safe. Reconify answers duplicate for anything it stored before the retry, and duplicate counts as delivered. Reusing an ID with different content returns idempotency_conflict, which signals a producer bug rather than a delivery problem. Events without an id receive a generated one, so Reconify cannot recognize their replay. Those events are unsafe to retry. Both SDKs retry reads automatically and leave ingestion alone by default, because a batch without stable IDs cannot be replayed safely. Ingestion retries become an option once every event carries an id:
The full policy lives in TypeScript errors and retries and Python errors and retries.

Verify what arrived

A read or admin key lists events or fetches one by ID, which is how you confirm that your sender works end to end:
The response carries the normalized event from the anatomy above. Four of its fields confirm the flow landed as intended: reference matches what you sent, event_type matches your type, entity_type reads as the flow implies, and status reaches processed once evaluation finishes. received and published are normal in the seconds after ingestion. A status that stays there for minutes belongs in Troubleshooting. Sending the identical batch a second time closes the loop on retry safety, because every item comes back as duplicate. An idempotency_conflict there means the payload changed between the two attempts.

What comes next

Four pages continue from a working sender.

TypeScript

Send event batches with the TypeScript SDK.

Python

Send event batches with the Python SDK.

Trace across services

Link one transaction that spans several services.

Go live

Check the integration before and after launch.