Usage Data
Field reference, deduplication rules, and examples for sending activity data to Harmony
A usage push tells Harmony what people actually did in an application. Where a users push reports who has access, a usage push reports who used that access — which is what turns an inventory into a license optimization tool.
This page covers the usage endpoint in full. For setup, see Bring Your Own App.
How usage differs from users
Usage pushes are additive, not snapshots. Each push adds activity records to what Harmony already has. Nothing is removed by omitting it — there is no equivalent of the users snapshot rule here.
Instead of replacement, usage relies on deduplication: every record carries an event_id that you choose, and Harmony counts each event_id exactly once no matter how many times you send it. That is what makes usage pushes safe to retry.
Endpoint
POST https://external.harmony.io/custom-push/v1/usage
Authorization: Bearer <access key>
Content-Type: application/jsonRequest body
external_app_id
string
Yes
The App ID you registered in Harmony. Must match the value used in your users pushes for this application.
events
array
Yes
Between 1 and 100 activity records. See below.
schema_version
string
No
Defaults to "1.0". Reserved for future versions of this API.
Usage fields
Each object in the events array describes one activity observation.
event_id
string
Yes
1–255 chars
Your stable identifier for this record. This is the deduplication key — see The event ID contract below. Getting this right is the single most important part of a usage push.
event_date
string
Yes
YYYY-MM-DD
The calendar day the activity happened, in UTC. Usage is tracked per day; there is no need for a timestamp.
actor_email
string
Yes
Valid email, max 254 chars
The email address of the person who performed the activity. This is how the record is attributed to a user and, through them, to an employee.
actor_id
string
No
255 chars
The application's own identifier for that person — the same value you send as external_id in your users push. Recommended: it makes attribution reliable even if a user's email address changes.
action
string
Yes
1–255 chars
What the user did, as a short label. Becomes a named activity metric in Harmony. Keep the set of values small and stable — login, message_sent, report_generated.
metric_value
number
Yes
≥ 0, finite
How much of that action occurred. For a per-interaction record this is usually 1; for a daily total it is the count for that day.
outcome_reason
string
No
See values below
What metric_value measures. Defaults to request_count.
metadata
object
No
1 KB serialized
Any additional key/value data you want to carry along. Free-form JSON.
outcome_reason values
Value
metric_value represents
request_count
A number of actions or interactions. This is the default.
token_used
A quantity of consumed units, such as AI tokens or API credits.
cost_usd
An amount of money in US dollars.
Use this to report cost or consumption alongside plain activity counts. A single application can send several actions with different outcome_reason values — for example action: "chat_message" with request_count, and action: "chat_message" with cost_usd for the same day's spend.
The event ID contract
event_id is how Harmony knows whether two records describe the same activity or two different activities.
Sending the same
event_idtwice is always safe. The second one is ignored. Retry freely.Sending the same real-world activity under a new
event_idcounts it twice. This is the failure mode to avoid.
Because of that, an event_id must be derived from the data, never generated fresh at send time.
Never use a random value, a UUID generated per request, a timestamp of when your script ran, or a row counter. Any of these produce a new ID every run, so re-running your script double-counts everything it already sent.
There are two correct approaches. Pick the one that matches your data.
If your application has native event IDs
Some applications record every interaction individually with its own identifier — an audit log ID, an event ID, a message ID. Use it directly.
With native IDs, many records per user per day are expected and correct — one per interaction.
If you report daily totals
Most applications only expose aggregates: "Alice sent 47 messages on July 20th". Build a natural key from the values that make the record unique.
Re-running your script for July 20th produces the same key, so the record is recognized and updated rather than added again. This is what makes daily backfills and overlapping date ranges safe.
The 90-day activity window
Harmony's activity statistics are calculated over a rolling 90-day window.
Usage records older than 90 days are accepted and stored, but they do not appear in activity charts or influence active/inactive user determination. If you are backfilling history, anything beyond 90 days will not surface in the interface.
For an initial load, pushing the last 90 days of activity gives you a complete picture immediately. Older history is optional.
Response
202 Accepted:
batch_id
A unique identifier for this request. Useful when contacting support about a specific push.
accepted_rows
How many activity records were accepted.
Unlike a users push, there is no snapshot_id — usage records are independent, so there is nothing to join across requests.
For error responses, see the API reference.
Examples
A minimal push
A fully populated push
Reporting both an activity count and its cost for the same day:
Note the two distinct event_id values. They describe two different measurements of the same day's work, so they must not collide.
A daily usage script
Because the event IDs are deterministic, this script is safe to re-run, safe to run twice by mistake, and safe to point at an overlapping range of dates when catching up.
Recommended push frequency
Daily is the usual pattern: each morning, push yesterday's activity. Applications that expose real-time events can push more frequently.
If your script misses a day, simply include the missed dates in the next run. Deterministic event IDs make overlapping ranges harmless.
See also
Users data — reporting who has access
API reference — errors, retries, and limits
Last updated
Was this helpful?
