curl --request POST \
--url https://api.saasybill.com/v1/usage_events \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"events": [
{
"event_id": "evt_20261012_0001",
"subscription": "9d4e2b7a-13c5-4f8e-b6a0-2e1d7c9f5b33",
"meter_code": "api_calls",
"quantity": "1250",
"timestamp": "2026-10-12T03:15:00Z"
},
{
"event_id": "evt_20261012_0002",
"subscription": "9d4e2b7a-13c5-4f8e-b6a0-2e1d7c9f5b33",
"meter_code": "storage_gb",
"quantity": "12.5",
"timestamp": "2026-10-12T03:15:00Z"
}
]
}
'{
"object": "usage_event_batch",
"created": 2,
"duplicates": 0,
"rejected": 0,
"results": [
{
"event_id": "evt_20261012_0001",
"status": "created"
},
{
"event_id": "evt_20261012_0002",
"status": "created"
}
]
}{
"object": "usage_event_batch",
"created": 1,
"duplicates": 1,
"rejected": 1,
"results": [
{
"event_id": "evt_20261012_0001",
"status": "created"
},
{
"event_id": "evt_20261012_0002",
"status": "duplicate"
},
{
"event_id": "evt_20261012_0004",
"status": "rejected",
"error": {
"code": "meter_not_on_plan",
"message": "This subscription's plan does not bill for this meter."
}
}
]
}{
"error": {
"type": "authentication_error",
"code": "invalid_api_key",
"message": "Provide a valid API key as `Authorization: Bearer <key>`.",
"request_id": "req_4f1a9c2e7b8d3a605e1c9f02"
}
}{
"error": {
"type": "permission_error",
"code": "insufficient_scope",
"message": "This API key does not have the `usage:write` scope.",
"request_id": "req_4f1a9c2e7b8d3a605e1c9f02"
}
}{
"error": {
"type": "not_found",
"code": "unknown_endpoint",
"message": "There is no such endpoint.",
"request_id": "req_4f1a9c2e7b8d3a605e1c9f02"
}
}{
"error": {
"type": "conflict",
"code": "idempotency_conflict",
"message": "This `Idempotency-Key` was used with a different request. Use a new key for a different request.",
"request_id": "req_4f1a9c2e7b8d3a605e1c9f02"
}
}{
"error": {
"type": "invalid_request_error",
"code": "invalid_parameter",
"message": "`events.3.quantity`: A quantity is a plain number greater than zero, with at most 4 decimal places and no sign or exponent.",
"param": "events.3.quantity",
"request_id": "req_4f1a9c2e7b8d3a605e1c9f02"
}
}{
"error": {
"type": "rate_limit_error",
"code": "rate_limited",
"message": "Too many requests. Try again in 12 seconds.",
"request_id": "req_4f1a9c2e7b8d3a605e1c9f02"
}
}{
"error": {
"type": "api_error",
"code": "internal_error",
"message": "Something went wrong on our side. Retry the request; if it keeps failing, quote the request id.",
"request_id": "req_4f1a9c2e7b8d3a605e1c9f02"
}
}Report usage
Sends up to 100 usage events, each naming the subscription it is billed to and the meter it counts against. Every event carries an event_id of your own, unique across your organisation, and that is what makes a resend safe: an event that was already stored with the same details is counted once and reported as a duplicate, so retrying a batch that timed out cannot double count. The same event_id with different details is rejected as event_id_conflict. An event that is malformed fails the whole request, with nothing stored. An event that is well formed but cannot be accepted — a subscription that no longer exists, a meter the subscription’s plan does not bill for — is rejected on its own and the rest are stored. The response is then 207, and results says why for each: a 2xx does not mean every event was stored, so read rejected. Usage is billed in arrears, when the subscription’s period ends.
curl --request POST \
--url https://api.saasybill.com/v1/usage_events \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"events": [
{
"event_id": "evt_20261012_0001",
"subscription": "9d4e2b7a-13c5-4f8e-b6a0-2e1d7c9f5b33",
"meter_code": "api_calls",
"quantity": "1250",
"timestamp": "2026-10-12T03:15:00Z"
},
{
"event_id": "evt_20261012_0002",
"subscription": "9d4e2b7a-13c5-4f8e-b6a0-2e1d7c9f5b33",
"meter_code": "storage_gb",
"quantity": "12.5",
"timestamp": "2026-10-12T03:15:00Z"
}
]
}
'{
"object": "usage_event_batch",
"created": 2,
"duplicates": 0,
"rejected": 0,
"results": [
{
"event_id": "evt_20261012_0001",
"status": "created"
},
{
"event_id": "evt_20261012_0002",
"status": "created"
}
]
}{
"object": "usage_event_batch",
"created": 1,
"duplicates": 1,
"rejected": 1,
"results": [
{
"event_id": "evt_20261012_0001",
"status": "created"
},
{
"event_id": "evt_20261012_0002",
"status": "duplicate"
},
{
"event_id": "evt_20261012_0004",
"status": "rejected",
"error": {
"code": "meter_not_on_plan",
"message": "This subscription's plan does not bill for this meter."
}
}
]
}{
"error": {
"type": "authentication_error",
"code": "invalid_api_key",
"message": "Provide a valid API key as `Authorization: Bearer <key>`.",
"request_id": "req_4f1a9c2e7b8d3a605e1c9f02"
}
}{
"error": {
"type": "permission_error",
"code": "insufficient_scope",
"message": "This API key does not have the `usage:write` scope.",
"request_id": "req_4f1a9c2e7b8d3a605e1c9f02"
}
}{
"error": {
"type": "not_found",
"code": "unknown_endpoint",
"message": "There is no such endpoint.",
"request_id": "req_4f1a9c2e7b8d3a605e1c9f02"
}
}{
"error": {
"type": "conflict",
"code": "idempotency_conflict",
"message": "This `Idempotency-Key` was used with a different request. Use a new key for a different request.",
"request_id": "req_4f1a9c2e7b8d3a605e1c9f02"
}
}{
"error": {
"type": "invalid_request_error",
"code": "invalid_parameter",
"message": "`events.3.quantity`: A quantity is a plain number greater than zero, with at most 4 decimal places and no sign or exponent.",
"param": "events.3.quantity",
"request_id": "req_4f1a9c2e7b8d3a605e1c9f02"
}
}{
"error": {
"type": "rate_limit_error",
"code": "rate_limited",
"message": "Too many requests. Try again in 12 seconds.",
"request_id": "req_4f1a9c2e7b8d3a605e1c9f02"
}
}{
"error": {
"type": "api_error",
"code": "internal_error",
"message": "Something went wrong on our side. Retry the request; if it keeps failing, quote the request id.",
"request_id": "req_4f1a9c2e7b8d3a605e1c9f02"
}
}usage:write scope. See Authentication. For how usage is priced and invoiced, see Usage-based billing.Authorizations
An API key. Its scopes decide what it may call: customers:read (List and look up customers.) customers:write (Create customers, and Xero contacts where the organisation allows it.) catalogue:read (List plans and charges.) subscriptions:read (List and look up subscriptions.) subscriptions:write (Create subscriptions, change units, end and restore them.) invoices:read (List and look up invoices.) credit_notes:read (List and look up credit notes, and where their credit was applied.)
Headers
1 to 255 printable characters. A retry with the same key and body returns the first response.
1 - 255"usage_batch_2026-10-12T10"
Body
1 - 100 elementsShow child attributes
Show child attributes
Response
Success.
"usage_event_batch"Events stored by this request.
Events already stored with the same details, counted once.
Events not stored. results says why for each. Resend them once fixed.
One entry per event, in the order they were sent.
Show child attributes
Show child attributes
Was this page helpful?