zuplo 7.6.4 → 7.6.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/ai-gateway/getting-started.mdx +6 -6
- package/docs/ai-gateway/managing-teams.mdx +3 -2
- package/docs/ai-gateway/overview.mdx +10 -9
- package/docs/ai-gateway/policy-templates.mdx +17 -11
- package/docs/ai-gateway/teams.mdx +1 -1
- package/docs/ai-gateway/usage-limits.mdx +95 -44
- package/docs/articles/api-key-administration.mdx +2 -2
- package/docs/articles/api-key-api.mdx +26 -5
- package/docs/articles/api-key-authentication.mdx +1 -1
- package/docs/articles/api-key-buckets.mdx +27 -4
- package/docs/articles/api-key-consumer-bucket-portal-ui.mdx +13 -11
- package/docs/articles/api-key-leak-detection.mdx +2 -2
- package/docs/articles/api-key-self-serve-integration.mdx +19 -19
- package/docs/articles/audit-logs.mdx +11 -10
- package/docs/articles/monetization/api-access.mdx +1 -1
- package/docs/articles/monetization/going-to-production.mdx +1 -1
- package/docs/concepts/ai-gateway.mdx +4 -3
- package/docs/concepts/api-keys.md +1 -1
- package/docs/dedicated/akamai/ai-powered-applications.mdx +11 -8
- package/docs/dev-portal/dev-portal-create-consumer-on-auth.mdx +10 -5
- package/docs/policies/ai-gateway-configuration-executor-v2-inbound/doc.md +1 -1
- package/docs/policies/ai-gateway-metering-v2-inbound/schema.json +1 -1
- package/docs/policies/semantic-cache-inbound/schema.json +6 -2
- package/package.json +5 -5
|
@@ -98,17 +98,17 @@ account, Zuplo project, and AI Gateway team roles control access.
|
|
|
98
98
|
|
|
99
99
|
4. **Create a team**
|
|
100
100
|
|
|
101
|
-
Teams organize users and carry
|
|
102
|
-
|
|
101
|
+
Teams organize users and carry their own budget rules and policy templates.
|
|
102
|
+
Even if you're starting solo, you need at least one team.
|
|
103
103
|
|
|
104
104
|
Open the **Apps & Teams** tab and click **New Team**. Name your team (for
|
|
105
105
|
example, "Root" or your company name), choose an icon, and click **Create
|
|
106
106
|
Team**. This is your first team, so there's no parent picker yet—it appears
|
|
107
107
|
on later teams, letting you nest them. To set gateway-wide spending limits
|
|
108
|
-
across this Zuplo project, open the gateway's **Settings → Usage Limits
|
|
109
|
-
|
|
110
|
-
[Usage Limits](./usage-limits.mdx). Gateway and team limits
|
|
111
|
-
app regardless of its policy chain.
|
|
108
|
+
across this Zuplo project, open the gateway's **Settings → Usage Limits**.
|
|
109
|
+
Team budgets—shared and per-expression—are set on the team's **Usage &
|
|
110
|
+
Limits** tab. See [Usage Limits](./usage-limits.mdx). Gateway and team limits
|
|
111
|
+
apply to every app regardless of its policy chain.
|
|
112
112
|
|
|
113
113
|
5. **Create an app**
|
|
114
114
|
|
|
@@ -41,8 +41,9 @@ After creating a team, use its tabs to configure it:
|
|
|
41
41
|
|
|
42
42
|
- **Policy Template**—the team's [policy template](./policy-templates.mdx), the
|
|
43
43
|
starting policy chain for apps created in the team.
|
|
44
|
-
- **Usage & Limits**—
|
|
45
|
-
|
|
44
|
+
- **Usage & Limits**—the team's budgets, shared and per-expression, applying to
|
|
45
|
+
the team, its sub-teams, and their apps. See
|
|
46
|
+
[Usage Limits](./usage-limits.mdx).
|
|
46
47
|
- **Members**—who belongs to the team.
|
|
47
48
|
|
|
48
49
|
## Adding Team Members
|
|
@@ -30,9 +30,9 @@ Google, Mistral, xAI, and more) dynamically without modifying app code.
|
|
|
30
30
|
Configure model access through the gateway rather than hard coding it into your
|
|
31
31
|
apps.
|
|
32
32
|
|
|
33
|
-
**Cost Control**: Set spending limits at gateway, team, and app
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
**Cost Control**: Set independent spending limits at the gateway, team, and app
|
|
34
|
+
levels. Configure hourly, daily, weekly, or monthly rules that warn or block
|
|
35
|
+
when usage reaches a limit.
|
|
36
36
|
|
|
37
37
|
**Security & Compliance**: Apply guardrails to detect and block prompt injection
|
|
38
38
|
attempts and prevent PII leakage in both requests and responses through
|
|
@@ -99,13 +99,14 @@ a consistent starting pipeline. See [Policy Chains](./policy-chains.mdx) and
|
|
|
99
99
|
|
|
100
100
|
### Team Hierarchy & Budgets
|
|
101
101
|
|
|
102
|
-
Organize users into teams with hierarchical structures. Set budget
|
|
103
|
-
|
|
102
|
+
Organize users into teams with hierarchical structures. Set a budget at each
|
|
103
|
+
node. Each node totals its own usage and all descendant usage, and any exceeded
|
|
104
|
+
**Block** limit rejects the request:
|
|
104
105
|
|
|
105
|
-
- **Gateway**: Limits across the Zuplo project (for example, $1,000/day)
|
|
106
|
-
- **Teams**:
|
|
107
|
-
$500/day for the Credit Team)
|
|
108
|
-
- **Apps**:
|
|
106
|
+
- **Gateway**: Limits across the Zuplo project (for example, $1,000/day).
|
|
107
|
+
- **Teams**: Limits across the team, its sub-teams, and their apps (for example,
|
|
108
|
+
$500/day for the Credit Team).
|
|
109
|
+
- **Apps**: Limits for one app's traffic.
|
|
109
110
|
|
|
110
111
|
See [Usage Limits](./usage-limits.mdx).
|
|
111
112
|
|
|
@@ -34,11 +34,17 @@ Policies tab.
|
|
|
34
34
|
|
|
35
35
|
:::
|
|
36
36
|
|
|
37
|
+
Everything on the **Policy Template** tab is template content, budgets included:
|
|
38
|
+
a **Budgets and Costs** entry in the template sets the default budget each new
|
|
39
|
+
app starts with in its own chain, and doesn't enforce anything on the team. The
|
|
40
|
+
team's own budgets—shared and per-expression—live on the team's **Usage &
|
|
41
|
+
Limits** tab. See [Usage Limits](./usage-limits.mdx).
|
|
42
|
+
|
|
37
43
|
## Editing a template
|
|
38
44
|
|
|
39
|
-
Open a team and select its **
|
|
40
|
-
app chain editor: add policies from the gateway's declared menu, order
|
|
41
|
-
configure their options.
|
|
45
|
+
Open a team and select its **Policy Template** tab. The template editor works
|
|
46
|
+
like the app chain editor: add policies from the gateway's declared menu, order
|
|
47
|
+
them, and configure their options.
|
|
42
48
|
|
|
43
49
|
Each policy in the template carries two checkboxes that control what an app
|
|
44
50
|
starting from the template may do with that entry. Both start checked—a policy
|
|
@@ -55,14 +61,14 @@ by the team policy template".
|
|
|
55
61
|
## Inheriting from a parent team
|
|
56
62
|
|
|
57
63
|
A sub-team can use its parent team's template instead of defining its own,
|
|
58
|
-
controlled by the **Inherit from parent** switch on the sub-team's
|
|
59
|
-
The switch drafts like the page's other edits and applies when
|
|
60
|
-
changes**. While inheriting, the sub-team's template is
|
|
61
|
-
parent's effective template. Turn the switch off to give
|
|
62
|
-
template: the editor starts from a copy of the parent's
|
|
63
|
-
which you then adjust. Turning inheritance back on and
|
|
64
|
-
sub-team's own template in favor of the parent's—before you
|
|
65
|
-
switch again to restore your draft.
|
|
64
|
+
controlled by the **Inherit from parent** switch on the sub-team's **Policy
|
|
65
|
+
Template** tab. The switch drafts like the page's other edits and applies when
|
|
66
|
+
you click **Save changes**. While inheriting, the sub-team's template is
|
|
67
|
+
read-only—it shows the parent's effective template. Turn the switch off to give
|
|
68
|
+
the sub-team its own template: the editor starts from a copy of the parent's
|
|
69
|
+
effective template, which you then adjust. Turning inheritance back on and
|
|
70
|
+
saving discards the sub-team's own template in favor of the parent's—before you
|
|
71
|
+
save, flip the switch again to restore your draft.
|
|
66
72
|
|
|
67
73
|
## Next steps
|
|
68
74
|
|
|
@@ -18,7 +18,7 @@ on that member's role.
|
|
|
18
18
|
|
|
19
19
|
Teams also carry a [policy template](./policy-templates.mdx)—the policy chain
|
|
20
20
|
that apps created in the team start with—and [usage limits](./usage-limits.mdx)
|
|
21
|
-
that apply to
|
|
21
|
+
that apply to the team's own usage and all descendant sub-teams and apps.
|
|
22
22
|
|
|
23
23
|
## Members
|
|
24
24
|
|
|
@@ -12,55 +12,94 @@ gateway, team, and app levels.
|
|
|
12
12
|
|
|
13
13
|
## Budget Hierarchy
|
|
14
14
|
|
|
15
|
-
Limits at every level apply together
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
Limits at every level apply together. A request is blocked when the gateway, an
|
|
16
|
+
ancestor team, or the app is over a **Block** limit. The error identifies
|
|
17
|
+
whether a shared node budget or an expression-specific budget ran out:
|
|
18
18
|
|
|
19
19
|
- **Gateway** - Limits across the Zuplo project (for example, $1,000/day),
|
|
20
|
-
covering all teams and apps combined
|
|
21
|
-
- **Teams** -
|
|
22
|
-
example, $500/day for the Engineering team)
|
|
20
|
+
covering all teams, sub-teams, and apps combined
|
|
21
|
+
- **Teams** - Limits covering the team's own usage and every descendant sub-team
|
|
22
|
+
and app (for example, $500/day for the Engineering team)
|
|
23
23
|
- **Apps** - Per-app limits for granular control (for example, $10/day for a
|
|
24
24
|
hackathon app)
|
|
25
25
|
|
|
26
|
+
Budgets at different levels don't constrain each other's values, and app budgets
|
|
27
|
+
under a team may add up to more than the team's own budget - the team's budget
|
|
28
|
+
is the aggregate cap. For example, take a $100/month team containing a $50/month
|
|
29
|
+
sub-team with two apps capped at $25/month and $40/month. When the apps have
|
|
30
|
+
spent $40 and $10, the sub-team's aggregate reaches $50 and requests through
|
|
31
|
+
**both** apps are blocked - including the app that is still under its own $25
|
|
32
|
+
cap. Apps elsewhere in the $100/month team keep working until that team's own
|
|
33
|
+
aggregate reaches $100.
|
|
34
|
+
|
|
35
|
+
<Diagram direction="vertical" height="h-96">
|
|
36
|
+
<DiagramNode id="team" variant="green">
|
|
37
|
+
Team · spent $50 of $100
|
|
38
|
+
</DiagramNode>
|
|
39
|
+
<DiagramNode id="subteam" variant="red">
|
|
40
|
+
Sub-team · spent $50 of $50
|
|
41
|
+
</DiagramNode>
|
|
42
|
+
<DiagramNode id="appa" variant="red">
|
|
43
|
+
App A · spent $10 of $25
|
|
44
|
+
</DiagramNode>
|
|
45
|
+
<DiagramNode id="appb" variant="red">
|
|
46
|
+
App B · spent $40 of $40
|
|
47
|
+
</DiagramNode>
|
|
48
|
+
<DiagramNode id="other" variant="green">
|
|
49
|
+
Other apps in the team
|
|
50
|
+
</DiagramNode>
|
|
51
|
+
<DiagramEdge from="team" to="subteam" label="at its Block limit" />
|
|
52
|
+
<DiagramEdge from="team" to="other" label="still serving" />
|
|
53
|
+
<DiagramEdge from="subteam" to="appa" label="blocked — under its own cap" />
|
|
54
|
+
<DiagramEdge from="subteam" to="appb" label="blocked" />
|
|
55
|
+
</Diagram>
|
|
56
|
+
|
|
26
57
|
## Where limits are configured
|
|
27
58
|
|
|
28
|
-
| Level |
|
|
29
|
-
| ------- | --------------------------------------------------------------------------------- |
|
|
30
|
-
| Gateway | **Settings → Usage Limits** |
|
|
31
|
-
| Team | The team's **Usage & Limits** tab |
|
|
32
|
-
| App | The **Budgets and Costs** policy in the app's [policy chain](./policy-chains.mdx) |
|
|
59
|
+
| Level | Shared budget | Per-expression budgets |
|
|
60
|
+
| ------- | --------------------------------------------------------------------------------- | ------------------------------------------------------------ |
|
|
61
|
+
| Gateway | **Settings → Usage Limits** | Supported in configuration, but not authorable in the Portal |
|
|
62
|
+
| Team | The team's **Usage & Limits** tab | The team's **Usage & Limits** tab |
|
|
63
|
+
| App | The **Budgets and Costs** policy in the app's [policy chain](./policy-chains.mdx) | The **Budgets and Costs** policy |
|
|
33
64
|
|
|
34
|
-
Gateway and team limits
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
65
|
+
Gateway and team limits apply independently to every descendant app; they aren't
|
|
66
|
+
copied into the app's configuration. Each node meters its own usage plus all
|
|
67
|
+
descendant usage. A request is blocked if any node in its path is over a
|
|
68
|
+
**Block** limit. An app's own limits live on the Budgets and Costs policy.
|
|
38
69
|
|
|
39
70
|
:::note
|
|
40
71
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
72
|
+
Everything a team enforces lives on its **Usage & Limits** tab. The **Policy
|
|
73
|
+
Template** tab is only the template: a Budgets and Costs entry there is copied
|
|
74
|
+
into each new app as the app's own starting budget and doesn't enforce the
|
|
75
|
+
team's budget.
|
|
44
76
|
|
|
45
77
|
:::
|
|
46
78
|
|
|
47
79
|
## How a budget rule works
|
|
48
80
|
|
|
49
|
-
|
|
50
|
-
|
|
81
|
+
Every node's budgets are a list of rules. Each rule answers two questions—what
|
|
82
|
+
it budgets, and what the caps are.
|
|
51
83
|
|
|
52
84
|
**Scope** decides who shares the budget:
|
|
53
85
|
|
|
54
|
-
| Scope
|
|
55
|
-
|
|
|
56
|
-
| **
|
|
57
|
-
| **By metadata** | A separate budget for every distinct value of an expression |
|
|
86
|
+
| Scope | What it budgets |
|
|
87
|
+
| ------------------------------------------ | ------------------------------------------------------------------------ |
|
|
88
|
+
| **Shared** (`budgetBy: "app"`) | One shared budget for the gateway, team, or app and its descendants |
|
|
89
|
+
| **By metadata** (`budgetBy: "expression"`) | A separate budget at that node for every distinct value of an expression |
|
|
90
|
+
|
|
91
|
+
A **By metadata** rule gives each distinct expression value its own allowance.
|
|
92
|
+
With the expression `request.headers.get("x-user")` and a $5 daily cap, every
|
|
93
|
+
distinct `x-user` value gets its own $5 per day—one user exhausting their budget
|
|
94
|
+
doesn't affect anyone else. A node can combine a shared rule with several
|
|
95
|
+
expression rules.
|
|
58
96
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
97
|
+
Ancestor rules of both kinds apply to every request through the node's subtree.
|
|
98
|
+
The difference is who gets blocked: a team's **Shared** rule blocks all of the
|
|
99
|
+
team's traffic once the team's aggregate is over, while a team's **By metadata**
|
|
100
|
+
rule meters each value across all of the team's apps combined and blocks only
|
|
101
|
+
the exhausted value—the same `x-user` shares one budget whether it calls App A
|
|
102
|
+
or App B.
|
|
64
103
|
|
|
65
104
|
**Limit rows** set the caps. Each row is a meter, a period, an amount, and an
|
|
66
105
|
action:
|
|
@@ -108,8 +147,9 @@ doesn't reset the period's usage.
|
|
|
108
147
|
|
|
109
148
|
</Stepper>
|
|
110
149
|
|
|
111
|
-
|
|
112
|
-
|
|
150
|
+
The app editor groups gateway and ancestor team rules under **Inherited**. Those
|
|
151
|
+
rules remain stored and enforced at the gateway or team; edit them where they
|
|
152
|
+
were created.
|
|
113
153
|
|
|
114
154
|
### Budget expressions
|
|
115
155
|
|
|
@@ -140,22 +180,32 @@ but budget separately.
|
|
|
140
180
|
|
|
141
181
|
:::
|
|
142
182
|
|
|
143
|
-
|
|
144
|
-
|
|
183
|
+
App rules are stored in `options.budgetRules` on the app's own Budgets and Costs
|
|
184
|
+
policy entry. For the app rule schema, see the
|
|
145
185
|
[Budgets and Costs policy reference](../policies/ai-gateway-metering-v2-inbound.mdx).
|
|
146
186
|
|
|
147
187
|
## Setting team and gateway limits
|
|
148
188
|
|
|
149
|
-
Team and gateway limits cover
|
|
150
|
-
whether or not its chain includes Budgets and
|
|
189
|
+
Team and gateway limits cover the node's own usage and all descendant usage.
|
|
190
|
+
They apply to every descendant app whether or not its chain includes Budgets and
|
|
191
|
+
Costs.
|
|
192
|
+
|
|
193
|
+
Team rules—shared and per-expression—are added on the team's **Usage & Limits**
|
|
194
|
+
tab, using the same meter, period, amount, and action rows as the app editor.
|
|
195
|
+
|
|
196
|
+
To add a shared gateway rule, open **Settings → Usage Limits**. The gateway root
|
|
197
|
+
supports per-expression rules in `metadata.budgetRules`, but the Portal doesn't
|
|
198
|
+
author them. It displays a stored expression rule as read-only and lets you
|
|
199
|
+
delete it.
|
|
151
200
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
201
|
+
Each `budgetBy: "app"` rule is a shared budget for the node where the rule is
|
|
202
|
+
stored. At the gateway or team level, `app` means that gateway or team node, not
|
|
203
|
+
an app policy configuration. A team's usage includes its sub-teams and apps, and
|
|
204
|
+
the gateway's usage includes the whole project.
|
|
155
205
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
206
|
+
Gateway and team rules are stored in `metadata.budgetRules` on that node. The
|
|
207
|
+
editor groups ancestor rules under **Inherited**, but each rule remains enforced
|
|
208
|
+
at the node where it was created.
|
|
159
209
|
|
|
160
210
|
## When a limit is exceeded
|
|
161
211
|
|
|
@@ -184,9 +234,10 @@ Without a fallback, the request is rejected with `429 Too Many Requests` and a
|
|
|
184
234
|
}
|
|
185
235
|
```
|
|
186
236
|
|
|
187
|
-
The `scope` tells the caller which budget they hit
|
|
188
|
-
|
|
189
|
-
|
|
237
|
+
The `scope` tells the caller which budget they hit. It is `application` when the
|
|
238
|
+
gateway, a team, or the app exhausts a shared node budget. It is `dimension`
|
|
239
|
+
when a value exhausts an expression budget. Quote the `ruleId` when raising a
|
|
240
|
+
support request.
|
|
190
241
|
|
|
191
242
|
:::caution{title="Budgets fail open by default"}
|
|
192
243
|
|
|
@@ -13,8 +13,8 @@ environments.
|
|
|
13
13
|

|
|
14
14
|
|
|
15
15
|
To view the bucket for a different environment, use the **Dev / Preview / Prod**
|
|
16
|
-
switcher at the top of the sidebar.
|
|
17
|
-
|
|
16
|
+
switcher at the top of the sidebar. Copy the active bucket's ID from the
|
|
17
|
+
**Bucket ID** pill under the **API Key Service** heading.
|
|
18
18
|
|
|
19
19
|
To add a new API Key Consumer, click **Create Consumer** and complete the form.
|
|
20
20
|
|
|
@@ -84,12 +84,33 @@ inside Zuplo)
|
|
|
84
84
|
```bash
|
|
85
85
|
# Your Zuplo Account Name
|
|
86
86
|
export ACCOUNT_NAME=my-account
|
|
87
|
-
# Your bucket
|
|
88
|
-
export
|
|
87
|
+
# Your bucket ID (Found in Services > API Keys > Consumers)
|
|
88
|
+
export BUCKET_ID=bckt_2HaK3odRyJle6NJSu8mzNKBC30BYxllxL
|
|
89
89
|
# Your Zuplo API Key (Found in Account Settings > Zuplo API Keys)
|
|
90
90
|
export API_KEY=zpka_YOUR_API_KEY
|
|
91
91
|
```
|
|
92
92
|
|
|
93
|
+
For more information about finding the bucket ID, see
|
|
94
|
+
[Bucket identifiers](./api-key-buckets.mdx#bucket-identifiers).
|
|
95
|
+
|
|
96
|
+
<details>
|
|
97
|
+
<summary>Legacy: identifying a bucket by name (deprecated)</summary>
|
|
98
|
+
|
|
99
|
+
The consumer, key, and manager endpoints also accept a bucket name in place of
|
|
100
|
+
the bucket ID, so existing scripts keep working:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
export BUCKET_NAME=my-bucket
|
|
104
|
+
curl \
|
|
105
|
+
https://dev.zuplo.com/v1/accounts/$ACCOUNT_NAME/key-buckets/$BUCKET_NAME/consumers \
|
|
106
|
+
--header "Authorization: Bearer $API_KEY"
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
The Zuplo Portal doesn't display bucket names, so use the bucket ID in new code.
|
|
110
|
+
When a value matches both a bucket name and a bucket ID, the name wins.
|
|
111
|
+
|
|
112
|
+
</details>
|
|
113
|
+
|
|
93
114
|
### Creating a Consumer with a Key
|
|
94
115
|
|
|
95
116
|
When creating a new Consumer, it's a good idea to include some useful metadata
|
|
@@ -101,7 +122,7 @@ external identifier that links this consumer to your internal data as a tag.
|
|
|
101
122
|
|
|
102
123
|
```shell
|
|
103
124
|
curl \
|
|
104
|
-
https://dev.zuplo.com/v1/accounts/$ACCOUNT_NAME/key-buckets/$
|
|
125
|
+
https://dev.zuplo.com/v1/accounts/$ACCOUNT_NAME/key-buckets/$BUCKET_ID/consumers?with-api-key=true \
|
|
105
126
|
--request POST \
|
|
106
127
|
--header "Content-type: application/json" \
|
|
107
128
|
--header "Authorization: Bearer $API_KEY" \
|
|
@@ -156,7 +177,7 @@ You can use this API Key to call your Zuplo Gateway that's protected by the
|
|
|
156
177
|
```shell
|
|
157
178
|
export ORG_ID=1234
|
|
158
179
|
curl \
|
|
159
|
-
https://dev.zuplo.com/v1/accounts/$ACCOUNT_NAME/key-buckets/$
|
|
180
|
+
https://dev.zuplo.com/v1/accounts/$ACCOUNT_NAME/key-buckets/$BUCKET_ID/consumers/?include-api-keys=true&key-format=visible&tag.orgId=$ORG_ID \
|
|
160
181
|
--header "Authorization: Bearer $API_KEY"
|
|
161
182
|
```
|
|
162
183
|
|
|
@@ -248,7 +269,7 @@ creates a new key without an expiration.
|
|
|
248
269
|
export ORG_ID=1234
|
|
249
270
|
export CONSUMER_NAME=my-consumer
|
|
250
271
|
curl \
|
|
251
|
-
https://dev.zuplo.com/v1/accounts/$ACCOUNT_NAME/key-buckets/$
|
|
272
|
+
https://dev.zuplo.com/v1/accounts/$ACCOUNT_NAME/key-buckets/$BUCKET_ID/consumers/$CONSUMER_NAME/roll-key?tag.orgId=$ORG_ID \
|
|
252
273
|
--request POST \
|
|
253
274
|
--header "Authorization: Bearer $API_KEY" \
|
|
254
275
|
--header "Content-Type: application/json" \
|
|
@@ -144,7 +144,7 @@ development.
|
|
|
144
144
|
Either locally or in CI/CD you can specify any API Key bucket on the
|
|
145
145
|
[API Key Authentication](../policies/api-key-inbound.mdx) policy by setting the
|
|
146
146
|
`bucketId` property. Every environment can then share a single bucket that holds
|
|
147
|
-
the consumers your tests need. Find a bucket's ID
|
|
147
|
+
the consumers your tests need. Find a bucket's ID on the **Bucket ID** pill on
|
|
148
148
|
the
|
|
149
149
|
[**Services → API Keys → Consumers**](https://portal.zuplo.com/+/account/project/services)
|
|
150
150
|
page in the Zuplo Portal. You can use the
|
|
@@ -21,6 +21,31 @@ Zuplo automatically creates three buckets for each project:
|
|
|
21
21
|
For more information on how environments relate to Git branches, see
|
|
22
22
|
[Branch-Based Deployments](./branch-based-deployments.mdx).
|
|
23
23
|
|
|
24
|
+
## Bucket identifiers
|
|
25
|
+
|
|
26
|
+
Every bucket has an ID that starts with `bckt_`, and a name. Use the bucket ID
|
|
27
|
+
whenever you identify a bucket, both in the
|
|
28
|
+
[Zuplo Developer API](./api-key-api.mdx) and in policy configuration. To copy
|
|
29
|
+
it, open
|
|
30
|
+
[**Services → API Keys → Consumers**](https://portal.zuplo.com/+/account/project/services)
|
|
31
|
+
in the Zuplo Portal and select the environment with the **Dev / Preview / Prod**
|
|
32
|
+
switcher. The **Bucket ID** pill sits beside the environment badge under the
|
|
33
|
+
**API Key Service** heading, with a copy button.
|
|
34
|
+
|
|
35
|
+
:::caution{title="Deprecated"}
|
|
36
|
+
|
|
37
|
+
The bucket name is a legacy identifier. The Zuplo Portal doesn't display it, and
|
|
38
|
+
the Developer API accepts it only for backward compatibility on the consumer,
|
|
39
|
+
key, and manager endpoints. Pass the bucket ID instead.
|
|
40
|
+
|
|
41
|
+
Three endpoints are the exception and still require the bucket name:
|
|
42
|
+
|
|
43
|
+
- `GET /v1/accounts/{accountName}/key-buckets/{bucketName}`
|
|
44
|
+
- `PATCH /v1/accounts/{accountName}/key-buckets/{bucketName}`
|
|
45
|
+
- `DELETE /v1/accounts/{accountName}/key-buckets/{bucketName}`
|
|
46
|
+
|
|
47
|
+
:::
|
|
48
|
+
|
|
24
49
|
## Custom bucket configuration
|
|
25
50
|
|
|
26
51
|
To use a custom bucket, specify its `bucketId` in your API Key policy options:
|
|
@@ -36,10 +61,8 @@ To use a custom bucket, specify its `bucketId` in your API Key policy options:
|
|
|
36
61
|
}
|
|
37
62
|
```
|
|
38
63
|
|
|
39
|
-
|
|
40
|
-
[
|
|
41
|
-
in the Zuplo Portal, select the environment with the **Dev / Preview / Prod**
|
|
42
|
-
switcher, then click **Bucket Details**.
|
|
64
|
+
For more information about finding a bucket ID, see
|
|
65
|
+
[Bucket identifiers](#bucket-identifiers).
|
|
43
66
|
|
|
44
67
|
When the configuration sets no bucket, the policy uses the default bucket for
|
|
45
68
|
the current environment.
|
|
@@ -65,20 +65,20 @@ For deeper detail, see [Buckets and Environments](./api-key-buckets.mdx).
|
|
|
65
65
|
1. Use the **Dev / Preview / Prod** switcher at the top of the sidebar to select
|
|
66
66
|
the environment whose bucket you want.
|
|
67
67
|
|
|
68
|
-
1.
|
|
69
|
-
|
|
68
|
+
1. Copy the active bucket's ID from the **Bucket ID** pill beside the
|
|
69
|
+
environment badge under the **API Key Service** heading.
|
|
70
70
|
|
|
71
71
|
</Stepper>
|
|
72
72
|
|
|
73
73
|
<ModalScreenshot size="md">
|
|
74
74
|
|
|
75
|
-

|
|
76
76
|
|
|
77
77
|
</ModalScreenshot>
|
|
78
78
|
|
|
79
|
-
**Bucket
|
|
80
|
-
|
|
81
|
-
|
|
79
|
+
The **Bucket ID** pill shows the ID of the bucket that's currently active for
|
|
80
|
+
the selected environment. Bucket IDs start with `bckt_` — this is the value the
|
|
81
|
+
API Key Authentication policy's `bucketId` option takes.
|
|
82
82
|
|
|
83
83
|
## Create a consumer in a specific bucket
|
|
84
84
|
|
|
@@ -157,7 +157,7 @@ the [Zuplo Developer API](./api-key-api.mdx):
|
|
|
157
157
|
|
|
158
158
|
```bash
|
|
159
159
|
curl \
|
|
160
|
-
https://dev.zuplo.com/v1/accounts/$ACCOUNT_NAME/key-buckets/$
|
|
160
|
+
https://dev.zuplo.com/v1/accounts/$ACCOUNT_NAME/key-buckets/$BUCKET_ID/consumers?with-api-key=true \
|
|
161
161
|
--request POST \
|
|
162
162
|
--header "Content-type: application/json" \
|
|
163
163
|
--header "Authorization: Bearer $ZAPI_KEY" \
|
|
@@ -168,10 +168,12 @@ curl \
|
|
|
168
168
|
}'
|
|
169
169
|
```
|
|
170
170
|
|
|
171
|
-
Replace `$ACCOUNT_NAME` with your Zuplo account name, `$
|
|
172
|
-
target bucket
|
|
173
|
-
[Zuplo API key](./accounts/zuplo-api-keys.mdx).
|
|
174
|
-
|
|
171
|
+
Replace `$ACCOUNT_NAME` with your Zuplo account name, `$BUCKET_ID` with the
|
|
172
|
+
target bucket's ID, and `$ZAPI_KEY` with your
|
|
173
|
+
[Zuplo API key](./accounts/zuplo-api-keys.mdx). The bucket name also works here,
|
|
174
|
+
but it's deprecated. For more information, see
|
|
175
|
+
[Bucket identifiers](./api-key-buckets.mdx#bucket-identifiers). Full reference
|
|
176
|
+
at the [Developer API documentation](https://dev.zuplo.com/docs).
|
|
175
177
|
|
|
176
178
|
## Troubleshooting
|
|
177
179
|
|
|
@@ -64,12 +64,12 @@ their integration, or omit it to revoke the old key immediately.
|
|
|
64
64
|
|
|
65
65
|
```bash
|
|
66
66
|
export ACCOUNT_NAME="your-account-name"
|
|
67
|
-
export
|
|
67
|
+
export BUCKET_ID="your-bucket-id"
|
|
68
68
|
export CONSUMER_NAME="your-consumer-name"
|
|
69
69
|
export ZUPLO_API_KEY="your-zuplo-api-key"
|
|
70
70
|
|
|
71
71
|
curl --request POST \
|
|
72
|
-
--url https://dev.zuplo.com/v1/accounts/$ACCOUNT_NAME/key-buckets/$
|
|
72
|
+
--url https://dev.zuplo.com/v1/accounts/$ACCOUNT_NAME/key-buckets/$BUCKET_ID/consumers/$CONSUMER_NAME/roll-key \
|
|
73
73
|
--header 'Authorization: Bearer $ZUPLO_API_KEY' \
|
|
74
74
|
--header 'Content-Type: application/json' \
|
|
75
75
|
--data '
|
|
@@ -51,12 +51,12 @@ Before you start, you need:
|
|
|
51
51
|
under
|
|
52
52
|
[**Account Settings → Zuplo API Keys**](https://portal.zuplo.com/+/account/settings/api-keys).
|
|
53
53
|
[More information](./accounts/zuplo-api-keys).
|
|
54
|
-
- Your **account name** and **bucket
|
|
54
|
+
- Your **account name** and **bucket ID**. A bucket groups consumers for an
|
|
55
55
|
environment - each project has buckets for production, preview, and
|
|
56
|
-
development.
|
|
56
|
+
development. Copy the bucket ID from the **Bucket ID** pill next to the **API
|
|
57
|
+
Key Service** heading on your project's
|
|
57
58
|
[**Services → API Keys → Consumers**](https://portal.zuplo.com/+/account/project/services)
|
|
58
|
-
page
|
|
59
|
-
the account name in
|
|
59
|
+
page, and the account name from
|
|
60
60
|
[**Project Settings → General**](https://portal.zuplo.com/+/account/project/settings/general).
|
|
61
61
|
- An application with server-side code and existing user authentication.
|
|
62
62
|
|
|
@@ -65,8 +65,8 @@ All examples in this guide use these environment variables:
|
|
|
65
65
|
```bash
|
|
66
66
|
# Your Zuplo Account Name
|
|
67
67
|
export ZUPLO_ACCOUNT=my-account
|
|
68
|
-
# Your bucket
|
|
69
|
-
export
|
|
68
|
+
# Your bucket ID (found on the Services → API Keys → Consumers page)
|
|
69
|
+
export ZUPLO_BUCKET_ID=bckt_2HaK3odRyJle6NJSu8mzNKBC30BYxllxL
|
|
70
70
|
# Your Zuplo API Key (found in Account Settings > Zuplo API Keys)
|
|
71
71
|
export ZUPLO_API_KEY=zpka_YOUR_API_KEY
|
|
72
72
|
```
|
|
@@ -128,7 +128,7 @@ initial API key in a single call by passing `?with-api-key=true`:
|
|
|
128
128
|
|
|
129
129
|
```shell
|
|
130
130
|
curl \
|
|
131
|
-
https://dev.zuplo.com/v1/accounts/$ZUPLO_ACCOUNT/key-buckets/$
|
|
131
|
+
https://dev.zuplo.com/v1/accounts/$ZUPLO_ACCOUNT/key-buckets/$ZUPLO_BUCKET_ID/consumers?with-api-key=true \
|
|
132
132
|
--request POST \
|
|
133
133
|
--header "Content-Type: application/json" \
|
|
134
134
|
--header "Authorization: Bearer $ZUPLO_API_KEY" \
|
|
@@ -189,7 +189,7 @@ To render an "API Keys" page in your settings, fetch the consumer's keys:
|
|
|
189
189
|
|
|
190
190
|
```shell
|
|
191
191
|
curl \
|
|
192
|
-
https://dev.zuplo.com/v1/accounts/$ZUPLO_ACCOUNT/key-buckets/$
|
|
192
|
+
https://dev.zuplo.com/v1/accounts/$ZUPLO_ACCOUNT/key-buckets/$ZUPLO_BUCKET_ID/consumers/org_123/keys?key-format=masked \
|
|
193
193
|
--header "Authorization: Bearer $ZUPLO_API_KEY"
|
|
194
194
|
```
|
|
195
195
|
|
|
@@ -224,7 +224,7 @@ staging and production), create a key directly:
|
|
|
224
224
|
|
|
225
225
|
```shell
|
|
226
226
|
curl \
|
|
227
|
-
https://dev.zuplo.com/v1/accounts/$ZUPLO_ACCOUNT/key-buckets/$
|
|
227
|
+
https://dev.zuplo.com/v1/accounts/$ZUPLO_ACCOUNT/key-buckets/$ZUPLO_BUCKET_ID/consumers/org_123/keys \
|
|
228
228
|
--request POST \
|
|
229
229
|
--header "Content-Type: application/json" \
|
|
230
230
|
--header "Authorization: Bearer $ZUPLO_API_KEY" \
|
|
@@ -238,7 +238,7 @@ the user a transition period to switch over. Use the roll-key endpoint:
|
|
|
238
238
|
|
|
239
239
|
```shell
|
|
240
240
|
curl \
|
|
241
|
-
https://dev.zuplo.com/v1/accounts/$ZUPLO_ACCOUNT/key-buckets/$
|
|
241
|
+
https://dev.zuplo.com/v1/accounts/$ZUPLO_ACCOUNT/key-buckets/$ZUPLO_BUCKET_ID/consumers/org_123/roll-key \
|
|
242
242
|
--request POST \
|
|
243
243
|
--header "Content-Type: application/json" \
|
|
244
244
|
--header "Authorization: Bearer $ZUPLO_API_KEY" \
|
|
@@ -261,7 +261,7 @@ To let users revoke a specific key immediately:
|
|
|
261
261
|
|
|
262
262
|
```shell
|
|
263
263
|
curl \
|
|
264
|
-
https://dev.zuplo.com/v1/accounts/$ZUPLO_ACCOUNT/key-buckets/$
|
|
264
|
+
https://dev.zuplo.com/v1/accounts/$ZUPLO_ACCOUNT/key-buckets/$ZUPLO_BUCKET_ID/consumers/org_123/keys/key_AM7eAiR0BiaXTam951XmC9kK \
|
|
265
265
|
--request DELETE \
|
|
266
266
|
--header "Authorization: Bearer $ZUPLO_API_KEY"
|
|
267
267
|
```
|
|
@@ -282,7 +282,7 @@ runtime, patch the consumer:
|
|
|
282
282
|
|
|
283
283
|
```shell
|
|
284
284
|
curl \
|
|
285
|
-
https://dev.zuplo.com/v1/accounts/$ZUPLO_ACCOUNT/key-buckets/$
|
|
285
|
+
https://dev.zuplo.com/v1/accounts/$ZUPLO_ACCOUNT/key-buckets/$ZUPLO_BUCKET_ID/consumers/org_123 \
|
|
286
286
|
--request PATCH \
|
|
287
287
|
--header "Content-Type: application/json" \
|
|
288
288
|
--header "Authorization: Bearer $ZUPLO_API_KEY" \
|
|
@@ -305,12 +305,12 @@ append `?tag.orgId=org_123` to every call:
|
|
|
305
305
|
```shell
|
|
306
306
|
# List only consumers belonging to org_123
|
|
307
307
|
curl \
|
|
308
|
-
"https://dev.zuplo.com/v1/accounts/$ZUPLO_ACCOUNT/key-buckets/$
|
|
308
|
+
"https://dev.zuplo.com/v1/accounts/$ZUPLO_ACCOUNT/key-buckets/$ZUPLO_BUCKET_ID/consumers?tag.orgId=org_123&include-api-keys=true&key-format=masked" \
|
|
309
309
|
--header "Authorization: Bearer $ZUPLO_API_KEY"
|
|
310
310
|
|
|
311
311
|
# Delete a consumer - fails if the consumer doesn't have tag orgId=org_123
|
|
312
312
|
curl \
|
|
313
|
-
"https://dev.zuplo.com/v1/accounts/$ZUPLO_ACCOUNT/key-buckets/$
|
|
313
|
+
"https://dev.zuplo.com/v1/accounts/$ZUPLO_ACCOUNT/key-buckets/$ZUPLO_BUCKET_ID/consumers/org_123?tag.orgId=org_123" \
|
|
314
314
|
--request DELETE \
|
|
315
315
|
--header "Authorization: Bearer $ZUPLO_API_KEY"
|
|
316
316
|
```
|
|
@@ -333,7 +333,7 @@ app.use(express.json());
|
|
|
333
333
|
|
|
334
334
|
const ZUPLO_BASE = "https://dev.zuplo.com/v1/accounts";
|
|
335
335
|
const ZUPLO_ACCOUNT = process.env.ZUPLO_ACCOUNT;
|
|
336
|
-
const
|
|
336
|
+
const ZUPLO_BUCKET_ID = process.env.ZUPLO_BUCKET_ID;
|
|
337
337
|
const ZUPLO_API_KEY = process.env.ZUPLO_API_KEY;
|
|
338
338
|
|
|
339
339
|
// TODO: Replace with your real auth middleware
|
|
@@ -351,7 +351,7 @@ app.get("/api/keys", async (req, res) => {
|
|
|
351
351
|
if (!orgId) return res.status(401).json({ error: "Unauthorized" });
|
|
352
352
|
|
|
353
353
|
const response = await fetch(
|
|
354
|
-
`${ZUPLO_BASE}/${ZUPLO_ACCOUNT}/key-buckets/${
|
|
354
|
+
`${ZUPLO_BASE}/${ZUPLO_ACCOUNT}/key-buckets/${ZUPLO_BUCKET_ID}/consumers/${orgId}/keys?key-format=masked`,
|
|
355
355
|
{
|
|
356
356
|
headers: { Authorization: `Bearer ${ZUPLO_API_KEY}` },
|
|
357
357
|
},
|
|
@@ -366,7 +366,7 @@ app.post("/api/keys", async (req, res) => {
|
|
|
366
366
|
if (!orgId) return res.status(401).json({ error: "Unauthorized" });
|
|
367
367
|
|
|
368
368
|
const response = await fetch(
|
|
369
|
-
`${ZUPLO_BASE}/${ZUPLO_ACCOUNT}/key-buckets/${
|
|
369
|
+
`${ZUPLO_BASE}/${ZUPLO_ACCOUNT}/key-buckets/${ZUPLO_BUCKET_ID}/consumers/${orgId}/keys`,
|
|
370
370
|
{
|
|
371
371
|
method: "POST",
|
|
372
372
|
headers: {
|
|
@@ -386,7 +386,7 @@ app.post("/api/keys/rotate", async (req, res) => {
|
|
|
386
386
|
if (!orgId) return res.status(401).json({ error: "Unauthorized" });
|
|
387
387
|
|
|
388
388
|
const response = await fetch(
|
|
389
|
-
`${ZUPLO_BASE}/${ZUPLO_ACCOUNT}/key-buckets/${
|
|
389
|
+
`${ZUPLO_BASE}/${ZUPLO_ACCOUNT}/key-buckets/${ZUPLO_BUCKET_ID}/consumers/${orgId}/roll-key?tag.orgId=${orgId}`,
|
|
390
390
|
{
|
|
391
391
|
method: "POST",
|
|
392
392
|
headers: {
|
|
@@ -406,7 +406,7 @@ app.delete("/api/keys/:keyId", async (req, res) => {
|
|
|
406
406
|
if (!orgId) return res.status(401).json({ error: "Unauthorized" });
|
|
407
407
|
|
|
408
408
|
const response = await fetch(
|
|
409
|
-
`${ZUPLO_BASE}/${ZUPLO_ACCOUNT}/key-buckets/${
|
|
409
|
+
`${ZUPLO_BASE}/${ZUPLO_ACCOUNT}/key-buckets/${ZUPLO_BUCKET_ID}/consumers/${orgId}/keys/${req.params.keyId}?tag.orgId=${orgId}`,
|
|
410
410
|
{
|
|
411
411
|
method: "DELETE",
|
|
412
412
|
headers: { Authorization: `Bearer ${ZUPLO_API_KEY}` },
|
|
@@ -121,12 +121,13 @@ The events view lets you:
|
|
|
121
121
|
Everything in the portal is backed by the Zuplo API, so you can query audit logs
|
|
122
122
|
programmatically — for scripting, custom dashboards, or exporting to other
|
|
123
123
|
systems. Authenticate with a [Zuplo API key](./accounts/zuplo-api-keys.mdx) and
|
|
124
|
-
query events by bucket
|
|
125
|
-
|
|
126
|
-
|
|
124
|
+
query events by bucket ID. Copy the bucket ID from the copyable **Bucket ID**
|
|
125
|
+
pill under the **API Key Service** heading on the
|
|
126
|
+
[**Services → API Keys → Consumers**](https://portal.zuplo.com/+/account/project/services)
|
|
127
|
+
page in the portal (it's the same bucket used by the API Key Service).
|
|
127
128
|
|
|
128
129
|
```bash
|
|
129
|
-
curl "https://dev.zuplo.com/v1/audit-logs/$
|
|
130
|
+
curl "https://dev.zuplo.com/v1/audit-logs/$BUCKET_ID/events?type=com.zuplo.api.request&startDate=2026-07-01T00:00:00Z&endDate=2026-07-07T00:00:00Z" \
|
|
130
131
|
-H "Authorization: Bearer $ZUPLO_API_KEY"
|
|
131
132
|
```
|
|
132
133
|
|
|
@@ -163,10 +164,10 @@ Two endpoints are available:
|
|
|
163
164
|
- **Aggregated stats** — `GET /v1/audit-logs/{bucketId}/stats` returns top-N
|
|
164
165
|
event counts grouped by event type or actor.
|
|
165
166
|
|
|
166
|
-
The `bucketId` path parameter
|
|
167
|
-
Each query is limited to a 30-day window between `startDate` and
|
|
168
|
-
the [Audit Logs API reference](../api/audit-logs) for all
|
|
169
|
-
response schemas.
|
|
167
|
+
The `bucketId` path parameter takes the bucket ID; these endpoints don't accept
|
|
168
|
+
a bucket name. Each query is limited to a 30-day window between `startDate` and
|
|
169
|
+
`endDate`. See the [Audit Logs API reference](../api/audit-logs) for all
|
|
170
|
+
parameters and response schemas.
|
|
170
171
|
|
|
171
172
|
## Exporting audit logs to a SIEM
|
|
172
173
|
|
|
@@ -182,14 +183,14 @@ const BASE_URL = "https://dev.zuplo.com/v1/audit-logs";
|
|
|
182
183
|
// Run on a schedule (e.g. every 5 minutes). `startDate` is the checkpoint
|
|
183
184
|
// saved by the previous run; `endDate` is the current time.
|
|
184
185
|
async function exportAuditLogs(
|
|
185
|
-
|
|
186
|
+
bucketId: string,
|
|
186
187
|
startDate: string,
|
|
187
188
|
endDate: string,
|
|
188
189
|
) {
|
|
189
190
|
let offset = 0;
|
|
190
191
|
let hasMore = true;
|
|
191
192
|
while (hasMore) {
|
|
192
|
-
const url = new URL(`${BASE_URL}/${
|
|
193
|
+
const url = new URL(`${BASE_URL}/${bucketId}/events`);
|
|
193
194
|
url.searchParams.set("startDate", startDate);
|
|
194
195
|
url.searchParams.set("endDate", endDate);
|
|
195
196
|
url.searchParams.set("limit", "100");
|
|
@@ -37,7 +37,7 @@ are set in your terminal:
|
|
|
37
37
|
|
|
38
38
|
```bash
|
|
39
39
|
# Your Bucket ID (could be working-copy, preview, or production)
|
|
40
|
-
# (Copy it from Bucket
|
|
40
|
+
# (Copy it from the Bucket ID pill on Services > API Keys > Consumers — https://portal.zuplo.com/+/account/project/services)
|
|
41
41
|
export BUCKET_ID=your-bucket-id
|
|
42
42
|
# Your Zuplo API Key (Found in Account Settings > Zuplo API Keys —
|
|
43
43
|
# https://portal.zuplo.com/+/account/settings/api-keys)
|
|
@@ -459,7 +459,7 @@ To help the team resolve your issue quickly, include:
|
|
|
459
459
|
| ------------------ | ------------------------------------------------------ |
|
|
460
460
|
| Account slug | Your Zuplo account identifier |
|
|
461
461
|
| Project slug | The project with monetization enabled |
|
|
462
|
-
| Bucket ID | Bucket
|
|
462
|
+
| Bucket ID | The Bucket ID pill on Services → API Keys → Consumers |
|
|
463
463
|
| Stripe account ID | Stripe Dashboard → Settings, starts with `acct_` |
|
|
464
464
|
| Plan keys | The plan keys involved in the issue |
|
|
465
465
|
| Subscription ID | If the issue is subscription-specific |
|
|
@@ -21,9 +21,10 @@ Three building blocks organize an AI Gateway:
|
|
|
21
21
|
can route to. Administrators configure providers once, including any
|
|
22
22
|
[custom OpenAI-compatible providers](../ai-gateway/custom-providers.mdx), and
|
|
23
23
|
consumers never see the underlying credentials.
|
|
24
|
-
- **[Teams](../ai-gateway/teams.mdx)** group users and carry budget limits
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
- **[Teams](../ai-gateway/teams.mdx)** group users and carry budget limits. Each
|
|
25
|
+
team totals usage across its sub-teams and apps. A request must remain within
|
|
26
|
+
the gateway, ancestor team, and app limits. See
|
|
27
|
+
[Usage Limits](../ai-gateway/usage-limits.mdx).
|
|
27
28
|
- **[Apps](../ai-gateway/apps.mdx)** are the pieces of software that call the
|
|
28
29
|
gateway — a support chatbot is one app, an internal coding agent is another.
|
|
29
30
|
Each app gets its own gateway URL, its own Zuplo-managed API key, and its own
|
|
@@ -187,7 +187,7 @@ Each project has separate buckets for production, preview, and working copy
|
|
|
187
187
|
environments. This means API keys created in production don't work in preview,
|
|
188
188
|
and vice versa.
|
|
189
189
|
|
|
190
|
-
For testing, you can specify a custom bucket
|
|
190
|
+
For testing, you can specify a custom bucket ID on the
|
|
191
191
|
[API Key Authentication](../policies/api-key-inbound.mdx) policy to share keys
|
|
192
192
|
across environments. Enterprise customers can share buckets across projects or
|
|
193
193
|
accounts.
|
|
@@ -165,14 +165,17 @@ When the firewall detects a threat, it can take one of three actions:
|
|
|
165
165
|
|
|
166
166
|
## Cost and Usage Controls
|
|
167
167
|
|
|
168
|
-
The Zuplo AI Gateway provides
|
|
169
|
-
spending:
|
|
170
|
-
|
|
171
|
-
- **
|
|
172
|
-
usage
|
|
173
|
-
- **Team budgets** -
|
|
174
|
-
-
|
|
175
|
-
- **
|
|
168
|
+
The Zuplo AI Gateway provides budget controls at every level of the hierarchy to
|
|
169
|
+
manage AI spending:
|
|
170
|
+
|
|
171
|
+
- **Gateway budgets** - Hourly, daily, weekly, or monthly limits across all AI
|
|
172
|
+
Gateway usage.
|
|
173
|
+
- **Team budgets** - Shared or per-expression limits across a team, its
|
|
174
|
+
sub-teams, and their apps.
|
|
175
|
+
- **App budgets** - Shared or per-expression limits for one app.
|
|
176
|
+
- **Rate limiting** - Request throttling to prevent abuse.
|
|
177
|
+
|
|
178
|
+
For more information, see [Usage Limits](../../ai-gateway/usage-limits.mdx).
|
|
176
179
|
|
|
177
180
|
## Security Model
|
|
178
181
|
|
|
@@ -56,14 +56,19 @@ secret `API_KEY` and set the value.
|
|
|
56
56
|
|
|
57
57
|
:::info
|
|
58
58
|
|
|
59
|
-
In the code below set the variable `
|
|
60
|
-
your Zuplo Gateway.
|
|
59
|
+
In the code below set the variable `API_KEY_BUCKET_ID` to the ID of the bucket
|
|
60
|
+
being used by your Zuplo Gateway. Copy it from the **Bucket ID** pill on your
|
|
61
|
+
project's
|
|
62
|
+
[**Services → API Keys → Consumers**](https://portal.zuplo.com/+/account/project/services)
|
|
63
|
+
page, or
|
|
61
64
|
[list your buckets using the Developer API](https://dev.zuplo.com/docs/routes#apikeybucketsservice_list).
|
|
65
|
+
For more information, see
|
|
66
|
+
[Bucket identifiers](../articles/api-key-buckets.mdx#bucket-identifiers).
|
|
62
67
|
|
|
63
68
|
:::
|
|
64
69
|
|
|
65
70
|
Next, add the following code to your custom action. Be sure to replace the
|
|
66
|
-
placeholder values with your actual account and bucket
|
|
71
|
+
placeholder values with your actual account name and bucket ID. Click the
|
|
67
72
|
**Deploy** button when you are finished.
|
|
68
73
|
|
|
69
74
|
```ts
|
|
@@ -71,7 +76,7 @@ const { fetch } = require("undici");
|
|
|
71
76
|
const { randomUUID } = require("crypto");
|
|
72
77
|
|
|
73
78
|
const ZUPLO_ACCOUNT = "my-zuplo-account";
|
|
74
|
-
const
|
|
79
|
+
const API_KEY_BUCKET_ID = "bckt_2HaK3odRyJle6NJSu8mzNKBC30BYxllxL";
|
|
75
80
|
|
|
76
81
|
/**
|
|
77
82
|
* Handler that will be called during the execution of a PostLogin flow.
|
|
@@ -100,7 +105,7 @@ exports.onExecutePostLogin = async (event, api) => {
|
|
|
100
105
|
try {
|
|
101
106
|
// Create the consumer
|
|
102
107
|
const response = await fetch(
|
|
103
|
-
`https://dev.zuplo.com/v1/accounts/${ZUPLO_ACCOUNT}/key-buckets/${
|
|
108
|
+
`https://dev.zuplo.com/v1/accounts/${ZUPLO_ACCOUNT}/key-buckets/${API_KEY_BUCKET_ID}/consumers?with-api-key=true`,
|
|
104
109
|
{
|
|
105
110
|
method: "POST",
|
|
106
111
|
body: JSON.stringify(body),
|
|
@@ -319,7 +319,7 @@ selected from the request. Each expression rule requires one or more meter rows:
|
|
|
319
319
|
| `meter` | `cost`, `requests`, `tokens` |
|
|
320
320
|
| `period` | `hourly`, `daily`, `weekly`, `monthly` |
|
|
321
321
|
| `action` | `warn` records a warning; `block` returns HTTP `429` |
|
|
322
|
-
| `value` | A finite number greater than
|
|
322
|
+
| `value` | A finite number greater than zero |
|
|
323
323
|
|
|
324
324
|
A rule cannot repeat the same meter, period, and action. When a meter and period
|
|
325
325
|
have both actions, the `warn` value must be less than the `block` value. The
|
|
@@ -61,8 +61,12 @@
|
|
|
61
61
|
},
|
|
62
62
|
"cacheByPropertyPath": {
|
|
63
63
|
"type": "string",
|
|
64
|
-
"description": "
|
|
65
|
-
"examples": [
|
|
64
|
+
"description": "A light path selector into the JSON request body to use as the cache key. Start with `.` for dot notation or `[` for a quoted key containing dots or slashes, for example `.userId`, `.data.customerId`, or `[\"https://example.com/cache-key\"]`. Only works with cacheBy=propertyPath.",
|
|
65
|
+
"examples": [
|
|
66
|
+
".userId",
|
|
67
|
+
".data.customerId",
|
|
68
|
+
"[\"https://example.com/cache-key\"]"
|
|
69
|
+
]
|
|
66
70
|
},
|
|
67
71
|
"cacheByFunction": {
|
|
68
72
|
"type": "object",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zuplo",
|
|
3
|
-
"version": "7.6.
|
|
3
|
+
"version": "7.6.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "The official Zuplo CLI for local development and platform management",
|
|
6
6
|
"homepage": "https://zuplo.com/docs/cli/overview",
|
|
@@ -32,9 +32,9 @@
|
|
|
32
32
|
"zuplo": "zuplo.js"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@zuplo/cli": "7.6.
|
|
36
|
-
"@zuplo/core": "7.6.
|
|
37
|
-
"@zuplo/runtime": "7.6.
|
|
38
|
-
"@zuplo/test": "7.6.
|
|
35
|
+
"@zuplo/cli": "7.6.5",
|
|
36
|
+
"@zuplo/core": "7.6.5",
|
|
37
|
+
"@zuplo/runtime": "7.6.5",
|
|
38
|
+
"@zuplo/test": "7.6.5"
|
|
39
39
|
}
|
|
40
40
|
}
|