Skip to content

Commit 268104c

Browse files
tothandrasgergely-kurucz-konghqcoderabbitai[bot]
authored
feat(api): customer v3 API (#3690)
Signed-off-by: Gergely Tamás Kurucz <[email protected]> Co-authored-by: Gergely Tamas Kurucz <[email protected]> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
1 parent d7f9379 commit 268104c

File tree

31 files changed

+2271
-112
lines changed

31 files changed

+2271
-112
lines changed

api/spec/src/v3/common/pagination.tsp

Lines changed: 20 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ namespace Common;
1010
/**
1111
* Cursor page query.
1212
*/
13-
@friendlyName("CursorPageQuery")
14-
model CursorPageQuery {
13+
@friendlyName("CursorPaginationQuery")
14+
model CursorPaginationQuery {
1515
/**
1616
* Determines which page of the collection to retrieve.
1717
*/
@@ -25,6 +25,21 @@ model CursorPageQuery {
2525
};
2626
}
2727

28+
/**
29+
* Page pagination query.
30+
*/
31+
@friendlyName("PagePaginationQuery")
32+
model PagePaginationQuery {
33+
/**
34+
* Determines which page of the collection to retrieve.
35+
*/
36+
@query(#{ explode: true, style: "deepObject" })
37+
page?: {
38+
size?: integer;
39+
number?: integer;
40+
};
41+
}
42+
2843
/**
2944
* Cursor pagination metadata.
3045
*/
@@ -73,34 +88,6 @@ model CursorMeta {
7388
page: CursorMetaPage;
7489
}
7590

76-
/**
77-
* Cursor pagination metadata with total.
78-
*/
79-
@friendlyName("CursorMetaWithTotal")
80-
@useRef("../../../../common/definitions/metadatas.yaml#/components/schemas/CursorMetaWithTotal")
81-
model CursorMetaWithTotal {
82-
...CursorMeta;
83-
84-
/**
85-
* Total number of items in the collection.
86-
*/
87-
total: integer;
88-
}
89-
90-
/**
91-
* Cursor pagination metadata with estimated total.
92-
*/
93-
@friendlyName("CursorMetaWithEstimatedTotal")
94-
@useRef("../../../../common/definitions/metadatas.yaml#/components/schemas/CursorMetaWithEstimatedTotal")
95-
model CursorMetaWithEstimatedTotal {
96-
...CursorMeta;
97-
98-
/**
99-
* Estimated total number of items in the collection.
100-
*/
101-
estimated_total: integer;
102-
}
103-
10491
/**
10592
* Page before.
10693
*/
@@ -166,19 +153,19 @@ model PageNumber {
166153
*/
167154
@friendlyName("PaginatedMeta")
168155
@useRef("../../../../common/definitions/metadatas.yaml#/components/schemas/PaginatedMeta")
169-
model PaginatedMeta {
156+
model PageMeta {
170157
/**
171158
* Page metadata.
172159
*/
173-
page: PageMeta;
160+
page: PagePaginatedMeta;
174161
}
175162

176163
/**
177164
* Pagination information.
178165
*/
179166
@friendlyName("PageMeta")
180167
@useRef("../../../../common/definitions/metadatas.yaml#/components/schemas/PageMeta")
181-
model PageMeta {
168+
model PagePaginatedMeta {
182169
/**
183170
* Page number.
184171
*/
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import "../shared/index.tsp";
2+
3+
namespace Customers;
4+
5+
/**
6+
* Customers can be individuals or organizations that can subscribe to plans and have access to features.
7+
*/
8+
@friendlyName("BillingCustomer")
9+
model Customer {
10+
...Shared.Resource;
11+
12+
#suppress "@openmeter/api-spec/doc-decorator" "shared model"
13+
@visibility(Lifecycle.Create, Lifecycle.Read)
14+
key: Shared.ExternalResourceKey;
15+
16+
/**
17+
* Mapping to attribute metered usage to the customer by the event subject.
18+
*/
19+
@visibility(Lifecycle.Create, Lifecycle.Read, Lifecycle.Update)
20+
@summary("Usage Attribution")
21+
usage_attribution?: CustomerUsageAttribution;
22+
23+
/**
24+
* The primary email address of the customer.
25+
*/
26+
@visibility(Lifecycle.Create, Lifecycle.Read, Lifecycle.Update)
27+
@summary("Primary Email")
28+
primary_email?: string;
29+
30+
/**
31+
* Currency of the customer.
32+
* Used for billing, tax and invoicing.
33+
*/
34+
@visibility(Lifecycle.Create, Lifecycle.Read, Lifecycle.Update)
35+
@summary("Currency")
36+
currency?: Shared.CurrencyCode;
37+
38+
/**
39+
* The billing address of the customer.
40+
* Used for tax and invoicing.
41+
*/
42+
@visibility(Lifecycle.Create, Lifecycle.Read, Lifecycle.Update)
43+
@summary("Billing Address")
44+
billing_address?: Address;
45+
}
46+
47+
/**
48+
* Address
49+
*/
50+
@friendlyName("BillingAddress")
51+
model Address {
52+
/**
53+
* Country code in [ISO 3166-1](https://www.iso.org/iso-3166-country-codes.html) alpha-2 format.
54+
*/
55+
@visibility(Lifecycle.Create, Lifecycle.Read, Lifecycle.Update)
56+
@summary("Country")
57+
country?: Shared.CountryCode;
58+
59+
/**
60+
* Postal code.
61+
*/
62+
@visibility(Lifecycle.Create, Lifecycle.Read, Lifecycle.Update)
63+
@summary("Postal Code")
64+
postal_code?: string;
65+
66+
/**
67+
* State or province.
68+
*/
69+
@visibility(Lifecycle.Create, Lifecycle.Read, Lifecycle.Update)
70+
@summary("State")
71+
state?: string;
72+
73+
/**
74+
* City.
75+
*/
76+
@visibility(Lifecycle.Create, Lifecycle.Read, Lifecycle.Update)
77+
@summary("City")
78+
city?: string;
79+
80+
/**
81+
* First line of the address.
82+
*/
83+
@visibility(Lifecycle.Create, Lifecycle.Read, Lifecycle.Update)
84+
@summary("Line 1")
85+
line1?: string;
86+
87+
/**
88+
* Second line of the address.
89+
*/
90+
@visibility(Lifecycle.Create, Lifecycle.Read, Lifecycle.Update)
91+
@summary("Line 2")
92+
line2?: string;
93+
94+
/**
95+
* Phone number.
96+
*/
97+
@visibility(Lifecycle.Create, Lifecycle.Read, Lifecycle.Update)
98+
@summary("Phone Number")
99+
phone_number?: string;
100+
}
101+
102+
/**
103+
* Mapping to attribute metered usage to the customer.
104+
* One customer can have zero or more subjects,
105+
* but one subject can only belong to one customer.
106+
*/
107+
@friendlyName("BillingCustomerUsageAttribution")
108+
model CustomerUsageAttribution {
109+
/**
110+
* The subjects that are attributed to the customer.
111+
* Can be empty when no usage event subjects are associated with the customer.
112+
*/
113+
@visibility(Lifecycle.Create, Lifecycle.Read, Lifecycle.Update)
114+
@summary("Subject Keys")
115+
@minItems(0)
116+
subject_keys: UsageAttributionSubjectKey[];
117+
}
118+
119+
/**
120+
* Subject key.
121+
*/
122+
@minLength(1)
123+
@friendlyName("UsageAttributionSubjectKey")
124+
scalar UsageAttributionSubjectKey extends string;
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import "./customer.tsp";
2+
import "./operations.tsp";
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import "@typespec/http";
2+
import "@typespec/rest";
3+
import "@typespec/openapi";
4+
import "@typespec/openapi3";
5+
import "../common/error.tsp";
6+
import "../common/pagination.tsp";
7+
import "../common/parameters.tsp";
8+
import "../shared/index.tsp";
9+
import "./customer.tsp";
10+
11+
using TypeSpec.Http;
12+
using TypeSpec.OpenAPI;
13+
14+
namespace Customers;
15+
16+
/**
17+
* Query params for listing customers.
18+
*/
19+
@friendlyName("ListCustomersParams")
20+
model ListCustomersParams {
21+
...Common.PagePaginationQuery;
22+
23+
/**
24+
* Sort customers returned in the response.
25+
* Supported sort attributes are:
26+
* - `id`
27+
* - `name` (default)
28+
* - `created_at`
29+
*
30+
* The `asc` suffix is optional as the default sort order is ascending.
31+
* The `desc` suffix is used to specify a descending order.
32+
*/
33+
@query(#{ name: "sort" })
34+
sort?: Common.SortQuery;
35+
}
36+
37+
interface CustomersOperations {
38+
@post
39+
@operationId("create-customer")
40+
@summary("Create customer")
41+
@extension(Shared.UnstableExtension, true)
42+
@extension(Shared.InternalExtension, true)
43+
create(
44+
@body
45+
customer: Shared.CreateRequest<Customer>,
46+
): Shared.CreateResponse<Customer> | Common.ErrorResponses;
47+
48+
@get
49+
@operationId("get-customer")
50+
@summary("Get customer")
51+
@extension(Shared.UnstableExtension, true)
52+
@extension(Shared.InternalExtension, true)
53+
get(
54+
@path customerId: Shared.ULID,
55+
): Shared.GetResponse<Customer> | Common.NotFound | Common.ErrorResponses;
56+
57+
@get
58+
@operationId("list-customers")
59+
@summary("List customers")
60+
@extension(Shared.UnstableExtension, true)
61+
@extension(Shared.InternalExtension, true)
62+
list(
63+
...ListCustomersParams,
64+
): Shared.PagePaginatedResponse<Customer> | Common.ErrorResponses;
65+
66+
@put
67+
@operationId("upsert-customer")
68+
@summary("Upsert customer")
69+
@extension(Shared.UnstableExtension, true)
70+
@extension(Shared.InternalExtension, true)
71+
upsert(
72+
@path customerId: Shared.ULID,
73+
74+
@body
75+
customer: Shared.UpsertRequest<Customer>,
76+
):
77+
| Shared.UpsertResponse<Customer>
78+
| Common.Gone
79+
| Common.NotFound
80+
| Common.ErrorResponses;
81+
82+
@delete
83+
@operationId("delete-customer")
84+
@summary("Delete customer")
85+
@extension(Shared.UnstableExtension, true)
86+
@extension(Shared.InternalExtension, true)
87+
delete(
88+
@path customerId: Shared.ULID,
89+
): Shared.DeleteResponse | Common.NotFound | Common.ErrorResponses;
90+
}

api/spec/src/v3/konnect.tsp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import "@typespec/openapi";
44
import "@typespec/openapi3";
55
import "./shared/index.tsp";
66
import "./events/index.tsp";
7+
import "./customers/index.tsp";
78

89
using TypeSpec.Http;
910
using TypeSpec.OpenAPI;
@@ -26,7 +27,6 @@ using TypeSpec.OpenAPI;
2627
@server("https://global.api.konghq.com/v3", "Global Production region")
2728
@tagMetadata(Shared.EventsTag, #{ description: Shared.EventsDescription })
2829
@tagMetadata(Shared.CustomersTag, #{ description: Shared.CustomersDescription })
29-
@tagMetadata(Shared.MetersTag, #{ description: Shared.MetersDescription })
3030
@useAuth(systemAccountAccessToken | personalAccessToken | konnectAccessToken)
3131
namespace MeteringAndBilling;
3232

@@ -35,6 +35,11 @@ namespace MeteringAndBilling;
3535
@friendlyName("${Shared.MeteringAndBillingTitle}: ${Shared.EventsTag}")
3636
interface EventsEndpoints extends Events.EventsOperations {}
3737

38+
@route("/openmeter/customers")
39+
@tag(Shared.CustomersTag)
40+
@friendlyName("${Shared.MeteringAndBillingTitle}: ${Shared.CustomersTag}")
41+
interface CustomersEndpoints extends Customers.CustomersOperations {}
42+
3843
/**
3944
* The system account access token is meant for automations and integrations that are not directly associated with a human identity.
4045
*/

api/spec/src/v3/openmeter.tsp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import "@typespec/openapi";
44
import "@typespec/openapi3";
55
import "./events/index.tsp";
66
import "./shared/index.tsp";
7+
import "./customers/index.tsp";
78

89
using TypeSpec.Http;
910
using TypeSpec.OpenAPI;
@@ -21,14 +22,17 @@ using TypeSpec.OpenAPI;
2122
},
2223
termsOfService: "https://openmeter.cloud/terms-of-service",
2324
})
24-
@server("https://127.0.0.1/api/v3", "Local")
2525
@server("https://openmeter.cloud/api/v3", "Cloud")
2626
@tagMetadata(Shared.EventsTag, #{ description: Shared.EventsDescription })
2727
@tagMetadata(Shared.CustomersTag, #{ description: Shared.CustomersDescription })
28-
@tagMetadata(Shared.MetersTag, #{ description: Shared.MetersDescription })
2928
namespace OpenMeter;
3029

3130
@route("/openmeter/events")
3231
@tag(Shared.EventsTag)
3332
@friendlyName("${Shared.OpenMeterTitle}: ${Shared.EventsTag}")
3433
interface EventsEndpoints extends Events.EventsOperations {}
34+
35+
@route("/openmeter/customers")
36+
@tag(Shared.CustomersTag)
37+
@friendlyName("${Shared.OpenMeterTitle}: ${Shared.CustomersTag}")
38+
interface CustomersEndpoints extends Customers.CustomersOperations {}

api/spec/src/v3/shared/consts.tsp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@ const MetersDescription = "Meters specify how to aggregate events for billing an
88
const EventsTag = "Metering Events";
99
const EventsDescription = "Metering events are used to track usage of your product or service. Events are processed asynchronously by the meters, so they may not be immediately available for querying.";
1010

11-
const CustomersTag = "Billing Customers";
11+
const CustomersTag = "OpenMeter Customers";
1212
const CustomersDescription = "Customers are used to track usage of your product or service. Customers can be individuals or organizations that can subscribe to plans and have access to features.";
1313

14-
const EntitlementsTag = "Billing Entitlements";
14+
const EntitlementsTag = "OpenMeter Entitlements";
1515
const EntitlementsDescription = "Entitlements are used to control access to features for customers.";
1616

17-
const SubscriptionsTag = "Billing Subscriptions";
17+
const SubscriptionsTag = "OpenMeter Subscriptions";
1818
const SubscriptionsDescription = "Subscriptions are used to track usage of your product or service. Subscriptions can be individuals or organizations that can subscribe to plans and have access to features.";
1919

2020
const UnstableExtension = "x-unstable";

api/spec/src/v3/shared/properties.tsp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,16 @@ union ULIDOrResourceKey {
4646
@example("019ae40f-4258-7f15-9491-842f42a7d6ac")
4747
scalar ExternalResourceKey extends string;
4848

49+
/**
50+
* ULID ID or External Resource Key.
51+
*/
52+
@friendlyName("ULIDOrExternalResourceKey")
53+
@summary("ULID ID or External Resource Key")
54+
union ULIDOrExternalResourceKey {
55+
id: ULID,
56+
key: ExternalResourceKey,
57+
}
58+
4959
/**
5060
* [RFC3339](https://tools.ietf.org/html/rfc3339) formatted date-time string in UTC.
5161
*/

0 commit comments

Comments
 (0)