Event Sourcing API


The API for Event Sourcing supports the operations of saving events to aggregates and retrieving those events for rebuilding the current state of a particular aggregate. In a CQRS architecture it typically means operations performed by the command-side of the application.

Event batches

When you update an aggregate you do so by saving batches of events. The reason for this is to ensure atomicity in the case when a command results in multiple events being emitted simultaneously.

Aggregate versioning

All aggregates have a current version. Each batch of events that is saved to the aggregate increments the aggregate version by one, regardless of whether the batch contains a single or multiple events.

Loading an aggregate

Before appending events to your aggregate you typically load (hydrate) it by loading all previous events for that particular aggregateId and fast-forward it into its current state. To limit the size of the reponse the optional query parameters since and limit can be used. Note that the parameters represents changes to the aggregate which does not necessarily correspond to the number of events that has been appended to it. The default limit is set to 1000.


There are two ways to handle concurrency in the Event Sourcing API. You can either use our built in optimistic concurrency control support or make sure you’re always writing data to one aggregate using a single writer thread. Both methods have their pros and cons and are perfectly viable solutions.

Optimistic concurrency control

To guarantee consistent writes to an aggregate in a multi-threaded scenario you can use the field expectedVersion when posting event batches. When creating a new aggregate the field should be set to 0 to guarantee that no previous events have been stored for that id.

When loading events for an aggregate the response will contain the field aggregateVersion. That number is what you are supposed to use as the expectedVersion in your next aggregate update. If the aggregate was updated by some other process concurrently, ie. the server-side version check fails, you will get a HTTP 409 (Conflict) response back. You will then have to load the aggregate once again, re-apply your change and try to save it again.

Single writer

If you are reading and writing aggregates from a single thread or process (eg. like in the Actor model) you don’t have to care about the version fields at all.

Deleting aggregates

Deleting data might be considered unorthodox in the world of event sourcing. However, we chose the pragmatic way allowing API users to delete aggregates, including all events, either by a single aggregateId or by aggregate type. The HTTP DELETE request will return a deleteToken valid for ten minutes. To permanently delete the aggregate(s), re-issue the DELETE request with the deleteToken appended as a query parameter.

curl -i \
  --header "Serialized-Access-Key: <YOUR_ACCESS_KEY>" \
  --header "Serialized-Secret-Access-Key: <YOUR_SECRET_ACCESS_KEY>" \
  -X DELETE https://api.serialized.io/aggregates/order

HTTP/1.1 200 OK
Content-Type: application/json
Date: Tue, 12 Jun 2018 15:27:25 GMT

  "deleteToken": "3c159b36-2840-480b-b436-fa69ac21d5e4"

curl -i \
  --header "Serialized-Access-Key: <YOUR_ACCESS_KEY>" \
  --header "Serialized-Secret-Access-Key: <YOUR_SECRET_ACCESS_KEY>" \
  -X DELETE https://api.serialized.io/aggregates/order?deleteToken=3c159b36-2840-480b-b436-fa69ac21d5e4

HTTP/1.1 204 No Content
Date: Tue, 12 Jun 2018 15:29:45 GMT