Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Billing Meters and Billing Meter Events #275

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,8 @@ extension StripeSignatureError: AbortError {
* [x] Subscription Schedule
* [x] Test Clocks
* [x] Usage Records
* [x] Meters
* [x] Meter Events
---
### Connect
* [x] Account
Expand Down
44 changes: 44 additions & 0 deletions Sources/StripeKit/Billing/Meter Events/MeterEvent.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//
// MeterEvent.swift
// stripe-kit
//
// Created by TelemetryDeck on 08.01.25.
//

import Foundation

/// The [Meter Even Object](https://docs.stripe.com/api/billing/meter-event/object).
public struct MeterEvent: Codable {
/// String representing the object’s type. Objects of the same type share the same value.
public var object: String
/// Time at which the object was created. Measured in seconds since the Unix epoch.
public var created: Date?
/// The name of the meter event. Corresponds with the `event_name` field on a meter.
public var eventName: String
/// A unique identifier for the event.
public var identifier: String
/// Has the value `true` if the object exists in live mode or the value `false` if the object exists in test mode.
public var livemode: Bool
/// The payload of the event. This contains the fields corresponding to a meter’s `customer_mapping.event_payload_key` (default is `stripe_customer_id`) and `value_settings.event_payload_key` (default is `value`). Read more about the [payload](https://docs.stripe.com/billing/subscriptions/usage-based/recording-usage#payload-key-overrides).
public var payload: [String: String]
/// The timestamp passed in when creating the event. Measured in seconds since the Unix epoch.
public var timestamp: Date

public init(
object: String,
created: Date? = nil,
eventName: String,
identifier: String,
livemode: Bool,
payload: [String: String],
timestamp: Date
) {
self.object = object
self.created = created
self.eventName = eventName
self.identifier = identifier
self.livemode = livemode
self.payload = payload
self.timestamp = timestamp
}
}
62 changes: 62 additions & 0 deletions Sources/StripeKit/Billing/Meter Events/MeterEventRoutes.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
//
// MeterEventRoutes.swift
// stripe-kit
//
// Created by TelemetryDeck on 08.01.25.
//

import Foundation
import NIO
import NIOHTTP1

public protocol MeterEventRoutes: StripeAPIRoute {
/// Creates a billing meter event.
///
/// - Parameters:
/// - event_name: The name of the meter event. Corresponds with the `event_name` field on a meter.
/// - payload: The payload of the event. This contains the fields corresponding to a meter’s `customer_mapping.event_payload_key` (default is `stripe_customer_id`) and `value_settings.event_payload_key` (default is `value`). Read more about the [payload](https://docs.stripe.com/billing/subscriptions/usage-based/recording-usage#payload-key-overrides).
/// - identifier: A unique identifier for the event.
/// - timestamp: The timestamp passed in when creating the event. Measured in seconds since the Unix epoch. Must be within the past 35 calendar days or up to 5 minutes in the future. Defaults to current timestamp if not specified.
func create(
event_name: String,
payload: [String: String],
identifier: String?,
timestamp: Date?) async throws -> MeterEvent
}

public struct StripeMeterEventRoutes: MeterEventRoutes {
public var headers: HTTPHeaders = [:]

private let apiHandler: StripeAPIHandler
private let meterevents = APIBase + APIVersion + "billing/meter_events"

init(apiHandler: StripeAPIHandler) {
self.apiHandler = apiHandler
}

public func create(
event_name: String,
payload: [String: String],
identifier: String?,
timestamp: Date?) async throws -> MeterEvent
{
var body: [String: Any] = [
"event_name": event_name,
"payload": payload
]

if let identifier {
body["identifier"] = identifier
}

if let timestamp {
body["timestamp"] = Int(timestamp.timeIntervalSince1970)
}

return try await apiHandler.send(
method: .POST,
path: meterevents,
body: .string(body.queryParameters),
headers: headers)
}
}
100 changes: 100 additions & 0 deletions Sources/StripeKit/Billing/Meters/Meter.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
//
// Meter.swift
// stripe-kit
//
// Created by TelemetryDeck on 08.01.25.
//

import Foundation

/// The Meter Object
public struct Meter: Codable {
/// Unique identifier for the object.
public var id: String
/// String representing the object’s type. Objects of the same type share the same value.
public var object: String
/// Time at which the object was created. Measured in seconds since the Unix epoch.
public var created: Date?
/// Fields that specify how to map a meter event to a customer.
public var customerMapping: MeterCustomerMapping
/// The meter’s name.
public var displayName: String
/// The name of the meter event to record usage for. Corresponds with the `event_name` field on meter events.
public var eventName: String
/// The time window to pre-aggregate meter events for, if any.
public var eventTimeWindow: MeterEventTimeWindow?
/// Has the value `true` if the object exists in live mode or the value `false` if the object exists in test mode.
public var liveMode: Bool?
/// The meter’s status.
public var status: MeterStatus
/// The timestamps at which the meter status changed.
public var meterStatusTransitions: MeterStatusTransitions?
/// Time at which the object was last updated. Measured in seconds since the Unix epoch.
public var updated: Date
/// Fields that specify how to calculate a meter event’s value.
public var valueSettings: MeterValueSettings
}

public struct MeterCustomerMapping: Codable {
/// The key in the meter event payload to use for mapping the event to a customer.
public var eventPayloadKey: String
/// The method for mapping a meter event to a customer.
public var type: MeterCustomerMappingType
}

public enum MeterCustomerMappingType: String, Codable {
/// Map a meter event to a customer by passing a customer ID in the event’s payload.
case byID = "by_id"
}

public enum MeterEventTimeWindow: String, Codable {
/// Events are pre-aggregated in daily buckets.
case day
/// Events are pre-aggregated in hourly buckets.
case hour
}

public enum MeterStatus: String, Codable {
/// The meter is active.
case active
/// The meter is inactive. No more events for this meter will be accepted. The meter cannot be attached to a price.
case inactive
}

public struct MeterStatusTransitions: Codable {
/// The time the meter was deactivated, if any. Measured in seconds since Unix epoch.
public var deactivatedAt: Date?
}

public struct MeterValueSettings: Codable {
/// The key in the meter event payload to use as the value for this meter.
public var eventPayloadKey: String
}

public struct MeterDefaultAggregation: Codable {
public var formula: MeterDefaultAggregationFormula
}

public enum MeterDefaultAggregationFormula: String, Codable {
/// Count the number of events.
case count
/// Sum each event’s value.
case sum
}

public struct MeterList: Codable {
public var object: String
public var hasMore: Bool?
public var url: String?
public var data: [Meter]?

public init(object: String,
hasMore: Bool? = nil,
url: String? = nil,
data: [Meter]? = nil) {
self.object = object
self.hasMore = hasMore
self.url = url
self.data = data
}
}
66 changes: 66 additions & 0 deletions Sources/StripeKit/Billing/Meters/MeterEventSummary.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
//
// MeterEventSummary.swift
// stripe-kit
//
// Created by TelemetryDeck on 17.01.25.
//

import Foundation

/// The [Meter Event Summary Object](https://docs.stripe.com/api/billing/meter-event-summary)
public struct MeterEventSummary: Codable {
/// Unique identifier for the object.
public var id: String
/// String representing the object’s type. Objects of the same type share the same value.
public var object: String
/// Aggregated value of all the events within `start_time` (inclusive) and `end_time` (inclusive). The aggregation strategy is defined on meter via `default_aggregation`.
public var aggregatedValue: Float
/// End timestamp for this event summary (exclusive). Must be aligned with minute boundaries.
public var endTime: Date
/// Has the value `true` if the object exists in live mode or the value `false` if the object exists in test mode.
public var livemode: Bool
/// The meter associated with this event summary.
public var meter: String
/// Start timestamp for this event summary (inclusive). Must be aligned with minute boundaries.
public var startTime: Date

public init(
id: String,
object: String,
aggregatedValue: Float,
endTime: Date,
livemode: Bool,
meter: String,
startTime: Date
) {
self.id = id
self.object = object
self.aggregatedValue = aggregatedValue
self.endTime = endTime
self.livemode = livemode
self.meter = meter
self.startTime = startTime
}
}

public enum MeterEventSummaryValueGroupingWindow: String, Codable {
case day
case hour
}

public struct MeterEventSummaryList: Codable {
public var object: String
public var hasMore: Bool?
public var url: String?
public var data: [MeterEventSummary]?

public init(object: String,
hasMore: Bool? = nil,
url: String? = nil,
data: [MeterEventSummary]? = nil) {
self.object = object
self.hasMore = hasMore
self.url = url
self.data = data
}
}
Loading
Loading