Skip to content

Commit 6be8127

Browse files
authored
Merge branch 'main' into ntotten-patch-2
2 parents ba1d6e8 + 6d9b87f commit 6be8127

29 files changed

+3217
-1541
lines changed

.gitignore

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ public/robots.txt
6464
public/sitemap.xml
6565
public/sitemap-*.xml
6666
api.json
67+
api-preview.json
6768
build/
6869
.next/
6970
docs/dev-portal/zudoku/
@@ -85,7 +86,7 @@ docs/dev-portal/zudoku/
8586
!.styles/config/vocabularies/Base
8687

8788

88-
# Screenshots
89+
# Screenshots
8990
auth.json
9091

9192
# docs generation
@@ -95,4 +96,4 @@ auth.json
9596
/index.d.ts
9697

9798

98-
/.lycheecache
99+
/.lycheecache

.vscode/extensions.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
"recommendations": ["prettier.prettier-vscode"]
2+
"recommendations": ["esbenp.prettier-vscode"]
33
}

.vscode/settings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"editor.defaultFormatter": "prettier.prettier-vscode",
2+
"editor.defaultFormatter": "esbenp.prettier-vscode",
33
"npm.packageManager": "npm",
44
"editor.formatOnSave": true,
55
"search.exclude": {

docs/articles/advanced-path-matching.mdx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,27 @@ However, you can opt to use a more advanced path matching approach based on the
1616
web standard
1717
[URLPattern](https://developer.mozilla.org/en-US/docs/Web/API/URLPattern).
1818

19+
In order to use URLPattern matching you must set your route's
20+
`x-zuplo-path.pathMode` to `url-pattern`.
21+
22+
The URLPattern matching mode can be set in the UI as shown below:
23+
24+
![Route ](../../public/media/advanced-path-matching/image.png)
25+
26+
Alternatively, you can set it in your OpenAPI file as follows:
27+
28+
```json {4-6} title="config/routes.oas.json"
29+
{
30+
"paths": {
31+
"/files/:path*": {
32+
"x-zuplo-path": {
33+
"pathMode": "url-pattern"
34+
}
35+
}
36+
}
37+
}
38+
```
39+
1940
The most basic path is `/` which will simple match the root path. You can add
2041
other static paths like `/foo` and `/foo/bar`
2142

docs/articles/logging.mdx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,3 +88,28 @@ details.
8888
events in the environment where your API runs. It's provided in your logs for
8989
potential troubleshooting. Normally, it's recommended to rely on the
9090
`requestId` for tracing.
91+
92+
## Custom Log Properties
93+
94+
In addition to the default fields, you can also add custom fields to your logs.
95+
This can be done using the `context.log.setLogProperties!` method.
96+
97+
```ts
98+
import { ZuploContext, ZuploRequest } from "@zuplo/runtime";
99+
100+
export default async function policy(
101+
request: ZuploRequest,
102+
context: ZuploContext,
103+
) {
104+
context.log.setLogProperties!({ customProperty: "value" });
105+
context.log.info("Hello World");
106+
return request;
107+
}
108+
```
109+
110+
These properties will be included in all subsequent log messages for that
111+
request. If the property already exists, it will be overwritten.
112+
113+
The log properties will be exported in a format native to the plugin you are
114+
using. For example, in the case of the OpenTelemetry plugin, the properties will
115+
be included in the `attributes` field of the log record.

docs/articles/metrics-plugins.mdx

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Zuplo supports logging to the following sources:
1111
- Datadog (Beta)
1212
- Dynatrace (Beta)
1313
- New Relic (Beta)
14+
- OpenTelemetry (Beta)
1415

1516
If you would like to log to a different source, reach out to support@zuplo.com
1617
and we'd be happy to work with you to add a new logging plugin.
@@ -281,3 +282,90 @@ can use a tool like the
281282
aggregation.
282283

283284
:::
285+
286+
### OpenTelemetry (Beta)
287+
288+
The OpenTelemetry metrics plugin sends metrics to any OpenTelemetry-compatible
289+
collector using the
290+
[OTLP HTTP JSON format](https://opentelemetry.io/docs/specs/otlp/#json-protobuf-encoding).
291+
This allows you to integrate with a wide variety of observability backends that
292+
support OpenTelemetry, including Grafana, Jaeger, Honeycomb, and many others.
293+
294+
By default, we send all metrics to your OpenTelemetry collector. However, you
295+
have the option below to configure which metrics you want to send.
296+
297+
```ts
298+
import {
299+
RuntimeExtensions,
300+
OTelMetricsPlugin,
301+
environment,
302+
} from "@zuplo/runtime";
303+
304+
export function runtimeInit(runtime: RuntimeExtensions) {
305+
runtime.addPlugin(
306+
new OTelMetricsPlugin({
307+
// The OTLP HTTP endpoint URL for your collector
308+
url: "https://otel-collector.example.com:4318/v1/metrics",
309+
// Optional headers for authentication
310+
headers: {
311+
Authorization: `Bearer ${environment.OTEL_API_KEY}`,
312+
},
313+
// Resource attributes to include with all metrics
314+
attributes: {
315+
"service.name": "my-api",
316+
"deployment.environment": environment.ENVIRONMENT ?? "development",
317+
},
318+
metrics: {
319+
latency: true,
320+
requestContentLength: true,
321+
responseContentLength: true,
322+
},
323+
// You can also choose to add additional attributes to include in the metrics
324+
include: {
325+
country: false,
326+
httpMethod: false,
327+
statusCode: false,
328+
path: false,
329+
},
330+
}),
331+
);
332+
}
333+
```
334+
335+
The plugin uses
336+
[OpenTelemetry semantic conventions](https://opentelemetry.io/docs/specs/semconv/)
337+
for metric names and attributes:
338+
339+
| Metric | Name | Unit |
340+
| ----------------------- | -------------------------------- | ---- |
341+
| Request latency | `http.server.request.duration` | ms |
342+
| Request content length | `http.server.request.body.size` | By |
343+
| Response content length | `http.server.response.body.size` | By |
344+
345+
When `include` options are enabled, the following attributes are added:
346+
347+
| Option | Attribute |
348+
| ------------ | ----------------------------- |
349+
| `country` | `client.geo.country_iso_code` |
350+
| `httpMethod` | `http.request.method` |
351+
| `statusCode` | `http.response.status_code` |
352+
| `path` | `http.route` |
353+
354+
The above configuration applies globally for all metrics sent to your
355+
OpenTelemetry collector. If you wish to dynamically configure information for a
356+
particular ZuploContext, you can use the `OTelMetricsPlugin` in your code.
357+
Currently, the only configuration you can set is the attributes. The values you
358+
set here will be appended to those set globally in the `zuplo.runtime.ts` file.
359+
360+
```ts
361+
import { ZuploContext, ZuploRequest, OTelMetricsPlugin } from "@zuplo/runtime";
362+
363+
export default async function (request: ZuploRequest, context: ZuploContext) {
364+
const someValue = "hello";
365+
OTelMetricsPlugin.setContext(context, {
366+
attributes: { "my.custom.attribute": someValue },
367+
});
368+
369+
return "What zup?";
370+
}
371+
```

docs/articles/monetization.mdx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,20 @@ combined with Zuplo's API management capabilities. You can:
6565
Learn how improving API quality can increase revenue in this blog post:
6666
[Increase Revenue by Improving API Quality](https://zuplo.com/blog/2024/02/02/increase-revenue-by-improving-api-quality)
6767

68+
## Zuplo Monetization API (Preview)
69+
70+
For teams who want a fully integrated, first-party metering solution, Zuplo now
71+
offers the Monetization API. Built from years of enterprise customer
72+
collaboration, this API provides:
73+
74+
- **Native metering** - Track usage directly within Zuplo without external
75+
services
76+
- **Product catalog** - Define meters, features, and plans via API
77+
- **Real-time queries** - Check usage instantly for billing or quota enforcement
78+
- **Simplified architecture** - One platform for gateway and monetization
79+
80+
[Explore the Monetization API →](./monetization/index.mdx)
81+
6882
## Enterprise Solutions
6983

7084
For organizations with complex monetization requirements that go beyond standard
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
---
2+
title: API Access
3+
sidebar_label: API Access
4+
---
5+
6+
:::warning
7+
8+
The Monetization APIs are in preview and subject to change. Features and
9+
endpoints documented here may be modified as we refine the service based on
10+
customer feedback.
11+
12+
:::
13+
14+
## Buckets
15+
16+
Each Zuplo project includes three isolated buckets that mirror your
17+
[environment structure](../environments.mdx):
18+
19+
| Bucket | Purpose |
20+
| ---------------- | ------------------------------------------------------------- |
21+
| **Working Copy** | Your development sandbox for building and testing |
22+
| **Preview** | Staging environments for validating changes before production |
23+
| **Production** | Your live environment serving real customers |
24+
25+
Meters, features, plans, and subscriptions are all scoped to a specific bucket.
26+
This isolation enables independent development workflows where you can:
27+
28+
- **Experiment freely** - Test new pricing models or usage tracking in
29+
development without affecting production data
30+
- **Validate changes** - Promote your product catalog configuration through
31+
preview environments before going live
32+
- **Maintain separation** - Keep development test data completely isolated from
33+
production customer usage
34+
35+
When you're satisfied with your configuration in one bucket, you can recreate
36+
that same configuration in another bucket to promote changes through your
37+
deployment pipeline.
38+
39+
## Authentication
40+
41+
All Monetization API requests require authentication using a Zuplo API key.
42+
43+
All examples in this documentation assume the following environment variables
44+
are set in your terminal:
45+
46+
```bash
47+
# Your Bucket ID (could be working-copy, preview, or production)
48+
# (Found in Project Services > Bucket Details)
49+
export BUCKET_ID=your-bucket-id
50+
# Your Zuplo API Key (Found in Account Settings > Zuplo API Keys)
51+
export ZAPI_KEY=zpka_YOUR_API_KEY
52+
```
53+
54+
Include your API key in the `Authorization` header:
55+
56+
```shell
57+
curl \
58+
https://dev.zuplo.com/v3/metering/$BUCKET_ID/meters \
59+
--header "Authorization: Bearer $ZAPI_KEY"
60+
```
61+
62+
## API Reference
63+
64+
For complete API operations, see the API Reference documentation:
65+
66+
- [Meters API](../../api/metering-meters)
67+
- [Features API](../../api/metering-features)
68+
- [Plans API](../../api/metering-plans)
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
---
2+
title: Features
3+
sidebar_label: Features
4+
---
5+
6+
:::warning
7+
8+
The Monetization APIs are in preview and subject to change.
9+
10+
:::
11+
12+
Features describe what your API offers to customers. They represent the
13+
capabilities in your API product - access to specific endpoints, usage
14+
allowances, premium functionality, or any other aspect you want to track or
15+
gate.
16+
17+
## Metered vs Static Features
18+
19+
Features come in two types:
20+
21+
- **Metered features** are linked to a meter and track consumption. Use these
22+
for usage-based capabilities like API calls, tokens, or data transfer.
23+
- **Static features** have no meter attached. Use these for boolean capabilities
24+
like "access to premium endpoints" or "priority support".
25+
26+
## Feature Properties
27+
28+
| Property | Required | Description |
29+
| ----------- | -------- | ---------------------------------------------------------------------- |
30+
| `key` | Yes | Unique identifier (lowercase alphanumeric and underscores, 1-64 chars) |
31+
| `name` | Yes | Human-readable display name |
32+
| `meterSlug` | No | Links this feature to a meter for usage tracking |
33+
| `metadata` | No | Custom key-value pairs for your own use |
34+
35+
:::note
36+
37+
Features cannot be updated after creation - they can only be archived. Plan your
38+
feature structure carefully before creating them.
39+
40+
:::
41+
42+
## Creating a Feature
43+
44+
Create a metered feature linked to an API requests meter:
45+
46+
```shell
47+
curl \
48+
https://dev.zuplo.com/v3/metering/$BUCKET_ID/features \
49+
--request POST \
50+
--header "Authorization: Bearer $ZAPI_KEY" \
51+
--header "Content-Type: application/json" \
52+
--data @- << EOF
53+
{
54+
"key": "api_calls",
55+
"name": "API Calls",
56+
"meterSlug": "api_requests"
57+
}
58+
EOF
59+
```
60+
61+
The response includes the created feature:
62+
63+
```json
64+
{
65+
"id": "01ARZ3NDEKTSV4RRFFQ69G5FAV",
66+
"key": "api_calls",
67+
"name": "API Calls",
68+
"meterSlug": "api_requests",
69+
"createdAt": "2024-01-01T01:01:01.001Z",
70+
"updatedAt": "2024-01-01T01:01:01.001Z"
71+
}
72+
```
73+
74+
### Creating a Static Feature
75+
76+
For features without usage tracking, omit the `meterSlug`:
77+
78+
```shell
79+
curl \
80+
https://dev.zuplo.com/v3/metering/$BUCKET_ID/features \
81+
--request POST \
82+
--header "Authorization: Bearer $ZAPI_KEY" \
83+
--header "Content-Type: application/json" \
84+
--data @- << EOF
85+
{
86+
"key": "priority_support",
87+
"name": "Priority Support"
88+
}
89+
EOF
90+
```
91+
92+
## API Reference
93+
94+
For complete API operations (list, get, archive), see the
95+
[Features API Reference](../../api/metering-features).

0 commit comments

Comments
 (0)