You learned how to design usage events. Now learn how to get usage events into Metronome, the data to send, and other best practices. If you have questions along the way, your Metronome representative is available to provide support and share best practices.
Send usage events to Metronome
"transaction_id": string, // (required) unique identifier for this event
"customer_id": string, // (required) which customer the event applies to
"timestamp": string, // (required) when the event happened
"event_type": string, // (required) the kind of event, such as page_view or sent_email
"properties": object, // (optional) key/value pairs with details of the event
Metronome uses the
transaction_id to ignore duplicate events. Once a usage event is accepted with a given transaction ID, subsequent events within the next 34 days with the same ID are treated as duplicates and ignored.
customer_id specifies which of your customers is responsible for any billing associated with the event. There are two ways to identify a Metronome customer in usage events: a customer ID or an ingest alias. Ingest aliases are useful when sending events using an identifier from your system, such as an email address or account number.
Each customer in Metronome may have multiple ingest aliases, and usage events with a
customer_id matching any of those aliases will count towards that customer's usage.
timestamp must be an RFC 3339 string with a 4-digit year, such as
2021-01-23T01:23:45Z. When querying usage data or producing an invoice, this field is used to select only events that happened in a certain time range. Timestamps more than 24 hours in the future are rejected by the API.
event_type works along with the
properties map to describe the details of the event. For example, a content delivery network (CDN) might generate events of the type
http_request with properties like
bytes_sent to support billing based on data transfer. They might also generate a different type of event,
cache_invalidation, with a property
All keys and values in the
properties map should be represented as strings, even though the values will often be numeric. This prevents the loss of precision that often occurs in systems that use floating point numbers. Internally, Metronome uses arbitrary precision decimals to provide exact results of computation.
Queue and retry
If usage events are lost on their way to Metronome, this directly translates into lost revenue. If you're sending events through the API, you need to be resilient to failures such as network issues or process crashes. A good way to gain this resilience is to put your usage events on a reliable queue such as Amazon SQS or RabbitMQ, and have a process pull from that queue and push events to Metronome.
If your call to the Metronome
/ingest endpoint fails with a network error or a
5xx HTTP status code, some of your events may have been ingested, but others may not. You should always retry a failed call to
/ingest until you receive a
200 status code. The unique
transaction_id in each event prevents duplicate processing, so retries are always safe.
If a call to
/ingest fails with a
4xx HTTP status code, this indicates an issue with the payload. Do not automatically retry such a call. Instead, put it aside in a dead letter queue and trigger an alarm so you can investigate the failure and resolve the issue.
Message queue logging
When first integrating with Metronome, it's helpful to enable logging in your message queue. This lets you audit exactly what usage events are being sent to Metronome. We recommend also enabling logging any time you make a change to your usage events.
Trial ingestion resilience
To test your system’s response to elevated error rates from Metronome’s API, Metronome can set up an automatic failure rate of your choice (we recommend 20%). Contact your Metronome representative to specify the % failure rate, when to enable and disable the test, and if you'd like to apply it to your sandbox or production instance.
Aggregate over a single property
A billable metric can only aggregate over a single property. For example, if you're an email sending service, you might have a usage event that looks like:
This event supports charging customers based on how many emails they sent or the maximum size of an email, but it would not support charging based on the total amount of data transfer—defined as the size of the email multiplied by the number of recipients. To do this, you must introduce a new property with the result of that multiplication:
Heartbeat event idempotence
Usage events typically fall into one of two categories: an event that occurs when a user takes some action, or a periodic "heartbeat" that measures the current state—a common approach in infrastructure services. For example, a service selling computation might send a per-node heartbeat to Metronome each minute describing the CPU and disk utilization on that node. These events could be aggregated into the metrics "CPU minutes" and "gigabyte minutes."
It's important for heartbeat events to ensure that usage is only counted once. This is accomplished by choosing a deterministic
transaction_id for duplicate events to have the same ID. Metronome guarantees that only one event with a given
transaction_id is processed.
In the example of a per-node per-minute heartbeat, you might structure a transaction ID as follows:
unix_now() is a function that returns the number of seconds since the Unix epoch. By including both the node ID and a minute-granularity timestamp in the transaction ID, it's guaranteed that duplicate events from the same node in the same minute is ignored.
Using this type of
transaction_id means you also don't have to worry about sending events too often. In fact, we recommend sending two or more heartbeats per measurement period. Duplicates will be safely ignored, and this way you decrease the risk of missing a measurement period due to timer imprecision or a temporary delay.
Usage events are designed to target very specific billable metrics, so if the data structure changes, it could prevent downstream metrics from being properly recorded. It's best to work with your Metronome representative any time you are adjusting the structure of your usage events. We can help validate and test the change with you to avoid any disruption.
Ensure Metronome does not block critical paths
Metronome has been expressly designed to use safely in the most critical parts of your application. In accordance with availability best practices, we suggest verifying that Metronome is not a blocker in your customer creation path. Since Metronome can match events sent at any time before or after customer creation using ingest aliases, we recommend creating the customer in your system first—then creating the matching customer record in Metronome asynchronously.