tripwire-server 0.3.0 → 0.3.2
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.
- checksums.yaml +4 -4
- data/README.md +27 -7
- data/lib/tripwire/server/client.rb +75 -23
- data/lib/tripwire/server/gate_delivery.rb +27 -2
- data/lib/tripwire/server/version.rb +1 -1
- data/spec/README.md +4 -4
- data/spec/fixtures/api/gate/service-create.json +2 -2
- data/spec/fixtures/api/gate/service-detail.json +2 -2
- data/spec/fixtures/api/gate/service-disable.json +2 -2
- data/spec/fixtures/api/gate/service-update.json +2 -2
- data/spec/fixtures/api/gate/services-list.json +2 -2
- data/spec/fixtures/api/organizations/api-key-create.json +27 -0
- data/spec/fixtures/api/{teams → organizations}/api-key-list.json +10 -5
- data/spec/fixtures/api/{teams → organizations}/api-key-revoke.json +10 -5
- data/spec/fixtures/api/organizations/api-key-rotate.json +27 -0
- data/spec/fixtures/api/organizations/api-key-update.json +29 -0
- data/spec/fixtures/api/{teams/team-create.json → organizations/organization-create.json} +4 -4
- data/spec/fixtures/api/{teams/team-update.json → organizations/organization-update.json} +4 -4
- data/spec/fixtures/api/{teams/team.json → organizations/organization.json} +4 -4
- data/spec/fixtures/api/sessions/detail.json +65 -36
- data/spec/fixtures/gate-delivery/approved-webhook-payload.valid.json +0 -1
- data/spec/fixtures/gate-delivery/webhook-signature.json +3 -3
- data/spec/fixtures/manifest.json +20 -14
- data/spec/openapi.json +18131 -3220
- metadata +12 -11
- data/spec/fixtures/api/teams/api-key-create.json +0 -21
- data/spec/fixtures/api/teams/api-key-rotate.json +0 -21
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3705acd09cee16f85cfc7da0a430dd203c928296265a8f412f0b0136dfa27a73
|
|
4
|
+
data.tar.gz: 79d3246ecf68eae368ec605c96cfed1f09be0427f0a9953700b5e3fde5a761a1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 04bcd559dba66a6677ef3bb2d09ff55f55b7c50598e7883d9c124edd3986213564ed8de8ebfdc351db4b1408fddf4d4403583c53949b37e9a7c1dd8c0a4db387
|
|
7
|
+
data.tar.gz: 0cf760c24506a05d64164773e5cc8c0b1c3d17607f3770b240ad4c4d0fa7400a79ccf8f37d545c2c6f3ec8240d5f7ed8e45a84dcb121f26fde60e3ba8c7524b8
|
data/README.md
CHANGED
|
@@ -4,13 +4,14 @@
|
|
|
4
4
|

|
|
5
5
|

|
|
6
6
|
|
|
7
|
-
The Tripwire Ruby library provides convenient access to the Tripwire API from applications written in Ruby. It includes a client for Sessions, visitor fingerprints,
|
|
7
|
+
The Tripwire Ruby library provides convenient access to the Tripwire API from applications written in Ruby. It includes a client for Sessions, visitor fingerprints, Organizations, Organization API key management, sealed token verification, Gate, and Gate delivery/webhook helpers.
|
|
8
8
|
|
|
9
9
|
The library also provides:
|
|
10
10
|
|
|
11
11
|
- a fast configuration path using `TRIPWIRE_SECRET_KEY`
|
|
12
12
|
- lazy helpers for cursor-based pagination
|
|
13
13
|
- structured API errors and built-in sealed token verification
|
|
14
|
+
- webhook endpoint management, test sends, and event delivery history
|
|
14
15
|
- public, bearer-token, and secret-key auth modes for Gate flows
|
|
15
16
|
- Gate delivery/webhook helpers
|
|
16
17
|
|
|
@@ -72,20 +73,39 @@ fingerprint = client.fingerprints.get("vid_0123456789abcdefghjkmnpqrs")
|
|
|
72
73
|
puts fingerprint[:id]
|
|
73
74
|
```
|
|
74
75
|
|
|
75
|
-
###
|
|
76
|
+
### Organizations
|
|
76
77
|
|
|
77
78
|
```ruby
|
|
78
|
-
|
|
79
|
-
updated = client.
|
|
79
|
+
organization = client.organizations.get("org_0123456789abcdefghjkmnpqrs")
|
|
80
|
+
updated = client.organizations.update("org_0123456789abcdefghjkmnpqrs", name: "New Name")
|
|
80
81
|
|
|
81
82
|
puts updated[:name]
|
|
82
83
|
```
|
|
83
84
|
|
|
84
|
-
###
|
|
85
|
+
### Organization API keys
|
|
85
86
|
|
|
86
87
|
```ruby
|
|
87
|
-
created = client.
|
|
88
|
-
client.
|
|
88
|
+
created = client.organizations.api_keys.create("org_0123456789abcdefghjkmnpqrs", name: "Production", type: "secret", environment: "live")
|
|
89
|
+
client.organizations.api_keys.revoke("org_0123456789abcdefghjkmnpqrs", created[:id])
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Webhooks
|
|
93
|
+
|
|
94
|
+
```ruby
|
|
95
|
+
endpoint = client.webhooks.create_endpoint(
|
|
96
|
+
"org_0123456789abcdefghjkmnpqrs",
|
|
97
|
+
name: "Production alerts",
|
|
98
|
+
url: "https://example.com/tripwire/webhook",
|
|
99
|
+
event_types: ["session.result.persisted", "gate.session.approved"]
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
events = client.webhooks.list_events(
|
|
103
|
+
"org_0123456789abcdefghjkmnpqrs",
|
|
104
|
+
endpoint_id: endpoint[:id],
|
|
105
|
+
type: "session.result.persisted"
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
puts events.items.first[:webhook_deliveries].first[:status]
|
|
89
109
|
```
|
|
90
110
|
|
|
91
111
|
### Gate APIs
|
|
@@ -10,7 +10,7 @@ module Tripwire
|
|
|
10
10
|
DEFAULT_TIMEOUT = 30
|
|
11
11
|
SDK_CLIENT_HEADER = "tripwire-server-ruby/0.1.0".freeze
|
|
12
12
|
|
|
13
|
-
attr_reader :sessions, :fingerprints, :
|
|
13
|
+
attr_reader :sessions, :fingerprints, :organizations, :gate, :webhooks, :timeout
|
|
14
14
|
|
|
15
15
|
def initialize(secret_key: ENV["TRIPWIRE_SECRET_KEY"], base_url: DEFAULT_BASE_URL, timeout: DEFAULT_TIMEOUT, user_agent: nil, transport: nil)
|
|
16
16
|
@secret_key = secret_key
|
|
@@ -21,8 +21,9 @@ module Tripwire
|
|
|
21
21
|
|
|
22
22
|
@sessions = SessionsResource.new(self)
|
|
23
23
|
@fingerprints = FingerprintsResource.new(self)
|
|
24
|
-
@
|
|
24
|
+
@organizations = OrganizationsResource.new(self)
|
|
25
25
|
@gate = GateResource.new(self)
|
|
26
|
+
@webhooks = WebhooksResource.new(self)
|
|
26
27
|
end
|
|
27
28
|
|
|
28
29
|
def request_json(method, path, query: {}, body: nil, expect_content: true, auth: { kind: :secret })
|
|
@@ -220,30 +221,39 @@ module Tripwire
|
|
|
220
221
|
end
|
|
221
222
|
|
|
222
223
|
class ApiKeysResource < BaseResource
|
|
223
|
-
def create(
|
|
224
|
-
payload = @client.request_json("POST", "/v1/
|
|
224
|
+
def create(organization_id, name:, type: nil, environment: nil, allowed_origins: nil, scopes: nil)
|
|
225
|
+
payload = @client.request_json("POST", "/v1/organizations/#{CGI.escape(organization_id)}/api-keys", body: compact({
|
|
225
226
|
name: name,
|
|
227
|
+
type: type,
|
|
226
228
|
environment: environment,
|
|
227
229
|
allowed_origins: allowed_origins,
|
|
228
|
-
|
|
230
|
+
scopes: scopes
|
|
229
231
|
}))
|
|
230
232
|
payload[:data]
|
|
231
233
|
end
|
|
232
234
|
|
|
233
|
-
def list(
|
|
234
|
-
payload = @client.request_json("GET", "/v1/
|
|
235
|
+
def list(organization_id, limit: nil, cursor: nil)
|
|
236
|
+
payload = @client.request_json("GET", "/v1/organizations/#{CGI.escape(organization_id)}/api-keys", query: {
|
|
235
237
|
limit: limit,
|
|
236
238
|
cursor: cursor
|
|
237
239
|
})
|
|
238
240
|
list_result(payload)
|
|
239
241
|
end
|
|
240
242
|
|
|
241
|
-
def
|
|
242
|
-
@client.request_json("
|
|
243
|
+
def update(organization_id, key_id, name: nil, allowed_origins: nil, scopes: nil)
|
|
244
|
+
@client.request_json("PATCH", "/v1/organizations/#{CGI.escape(organization_id)}/api-keys/#{CGI.escape(key_id)}", body: compact({
|
|
245
|
+
name: name,
|
|
246
|
+
allowed_origins: allowed_origins,
|
|
247
|
+
scopes: scopes
|
|
248
|
+
}))[:data]
|
|
243
249
|
end
|
|
244
250
|
|
|
245
|
-
def
|
|
246
|
-
|
|
251
|
+
def revoke(organization_id, key_id)
|
|
252
|
+
@client.request_json("DELETE", "/v1/organizations/#{CGI.escape(organization_id)}/api-keys/#{CGI.escape(key_id)}")[:data]
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
def rotate(organization_id, key_id)
|
|
256
|
+
payload = @client.request_json("POST", "/v1/organizations/#{CGI.escape(organization_id)}/api-keys/#{CGI.escape(key_id)}/rotations")
|
|
247
257
|
payload[:data]
|
|
248
258
|
end
|
|
249
259
|
|
|
@@ -254,7 +264,7 @@ module Tripwire
|
|
|
254
264
|
end
|
|
255
265
|
end
|
|
256
266
|
|
|
257
|
-
class
|
|
267
|
+
class OrganizationsResource < BaseResource
|
|
258
268
|
attr_reader :api_keys
|
|
259
269
|
|
|
260
270
|
def initialize(client)
|
|
@@ -263,15 +273,15 @@ module Tripwire
|
|
|
263
273
|
end
|
|
264
274
|
|
|
265
275
|
def create(name:, slug:)
|
|
266
|
-
@client.request_json("POST", "/v1/
|
|
276
|
+
@client.request_json("POST", "/v1/organizations", body: { name: name, slug: slug })[:data]
|
|
267
277
|
end
|
|
268
278
|
|
|
269
|
-
def get(
|
|
270
|
-
@client.request_json("GET", "/v1/
|
|
279
|
+
def get(organization_id)
|
|
280
|
+
@client.request_json("GET", "/v1/organizations/#{CGI.escape(organization_id)}")[:data]
|
|
271
281
|
end
|
|
272
282
|
|
|
273
|
-
def update(
|
|
274
|
-
@client.request_json("PATCH", "/v1/
|
|
283
|
+
def update(organization_id, name: nil, status: nil)
|
|
284
|
+
@client.request_json("PATCH", "/v1/organizations/#{CGI.escape(organization_id)}", body: {
|
|
275
285
|
name: name,
|
|
276
286
|
status: status
|
|
277
287
|
}.reject { |_key, value| value.nil? })[:data]
|
|
@@ -310,7 +320,7 @@ module Tripwire
|
|
|
310
320
|
@client.request_json("GET", "/v1/gate/services/#{CGI.escape(service_id)}")[:data]
|
|
311
321
|
end
|
|
312
322
|
|
|
313
|
-
def create(id:, name:, description:, website:,
|
|
323
|
+
def create(id:, name:, description:, website:, webhook_endpoint_id:, discoverable: nil, dashboard_login_url: nil, env_vars: nil, docs_url: nil, sdks: nil, branding: nil, consent: nil)
|
|
314
324
|
@client.request_json("POST", "/v1/gate/services", body: compact({
|
|
315
325
|
id: id,
|
|
316
326
|
discoverable: discoverable,
|
|
@@ -318,8 +328,7 @@ module Tripwire
|
|
|
318
328
|
description: description,
|
|
319
329
|
website: website,
|
|
320
330
|
dashboard_login_url: dashboard_login_url,
|
|
321
|
-
|
|
322
|
-
webhook_secret: webhook_secret,
|
|
331
|
+
webhook_endpoint_id: webhook_endpoint_id,
|
|
323
332
|
env_vars: env_vars,
|
|
324
333
|
docs_url: docs_url,
|
|
325
334
|
sdks: sdks,
|
|
@@ -328,15 +337,14 @@ module Tripwire
|
|
|
328
337
|
}))[:data]
|
|
329
338
|
end
|
|
330
339
|
|
|
331
|
-
def update(service_id, discoverable: nil, name: nil, description: nil, website: nil, dashboard_login_url: nil,
|
|
340
|
+
def update(service_id, discoverable: nil, name: nil, description: nil, website: nil, dashboard_login_url: nil, webhook_endpoint_id: nil, env_vars: nil, docs_url: nil, sdks: nil, branding: nil, consent: nil)
|
|
332
341
|
@client.request_json("PATCH", "/v1/gate/services/#{CGI.escape(service_id)}", body: compact({
|
|
333
342
|
discoverable: discoverable,
|
|
334
343
|
name: name,
|
|
335
344
|
description: description,
|
|
336
345
|
website: website,
|
|
337
346
|
dashboard_login_url: dashboard_login_url,
|
|
338
|
-
|
|
339
|
-
webhook_secret: webhook_secret,
|
|
347
|
+
webhook_endpoint_id: webhook_endpoint_id,
|
|
340
348
|
env_vars: env_vars,
|
|
341
349
|
docs_url: docs_url,
|
|
342
350
|
sdks: sdks,
|
|
@@ -356,6 +364,50 @@ module Tripwire
|
|
|
356
364
|
end
|
|
357
365
|
end
|
|
358
366
|
|
|
367
|
+
class WebhooksResource < BaseResource
|
|
368
|
+
def list_endpoints(organization_id)
|
|
369
|
+
payload = @client.request_json("GET", "/v1/organizations/#{CGI.escape(organization_id)}/webhooks/endpoints")
|
|
370
|
+
list_result(payload)
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
def create_endpoint(organization_id, name:, url:, event_types:)
|
|
374
|
+
@client.request_json("POST", "/v1/organizations/#{CGI.escape(organization_id)}/webhooks/endpoints", body: {
|
|
375
|
+
name: name,
|
|
376
|
+
url: url,
|
|
377
|
+
event_types: event_types
|
|
378
|
+
})[:data]
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
def update_endpoint(organization_id, endpoint_id, **updates)
|
|
382
|
+
@client.request_json("PATCH", "/v1/organizations/#{CGI.escape(organization_id)}/webhooks/endpoints/#{CGI.escape(endpoint_id)}", body: updates)[:data]
|
|
383
|
+
end
|
|
384
|
+
|
|
385
|
+
def disable_endpoint(organization_id, endpoint_id)
|
|
386
|
+
@client.request_json("DELETE", "/v1/organizations/#{CGI.escape(organization_id)}/webhooks/endpoints/#{CGI.escape(endpoint_id)}")[:data]
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
def rotate_secret(organization_id, endpoint_id)
|
|
390
|
+
@client.request_json("POST", "/v1/organizations/#{CGI.escape(organization_id)}/webhooks/endpoints/#{CGI.escape(endpoint_id)}/rotations")[:data]
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
def send_test(organization_id, endpoint_id)
|
|
394
|
+
@client.request_json("POST", "/v1/organizations/#{CGI.escape(organization_id)}/webhooks/endpoints/#{CGI.escape(endpoint_id)}/test")[:data]
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
def list_events(organization_id, endpoint_id: nil, type: nil, limit: nil)
|
|
398
|
+
payload = @client.request_json("GET", "/v1/organizations/#{CGI.escape(organization_id)}/events", query: {
|
|
399
|
+
endpoint_id: endpoint_id,
|
|
400
|
+
type: type,
|
|
401
|
+
limit: limit
|
|
402
|
+
})
|
|
403
|
+
list_result(payload)
|
|
404
|
+
end
|
|
405
|
+
|
|
406
|
+
def retrieve_event(organization_id, event_id)
|
|
407
|
+
@client.request_json("GET", "/v1/organizations/#{CGI.escape(organization_id)}/events/#{CGI.escape(event_id)}")[:data]
|
|
408
|
+
end
|
|
409
|
+
end
|
|
410
|
+
|
|
359
411
|
class GateSessionsResource < BaseResource
|
|
360
412
|
def create(service_id:, account_name:, delivery:, metadata: nil)
|
|
361
413
|
body = {
|
|
@@ -39,6 +39,12 @@ module Tripwire
|
|
|
39
39
|
XDG_CONFIG_HOME
|
|
40
40
|
].freeze
|
|
41
41
|
BLOCKED_GATE_ENV_VAR_PREFIXES = %w[NPM_CONFIG_ BUN_CONFIG_ GIT_CONFIG_].freeze
|
|
42
|
+
WEBHOOK_EVENT_TYPES = %w[
|
|
43
|
+
session.fingerprint.calculated
|
|
44
|
+
session.result.persisted
|
|
45
|
+
gate.session.approved
|
|
46
|
+
webhook.test
|
|
47
|
+
].freeze
|
|
42
48
|
GATE_DELIVERY_HKDF_INFO = "tripwire-gate-delivery:v1".b.freeze
|
|
43
49
|
X25519_SPKI_PREFIX = ["302a300506032b656e032100"].pack("H*").freeze
|
|
44
50
|
|
|
@@ -217,7 +223,7 @@ module Tripwire
|
|
|
217
223
|
|
|
218
224
|
def validate_gate_approved_webhook_payload(value)
|
|
219
225
|
candidate = symbolize(value)
|
|
220
|
-
raise ArgumentError, "
|
|
226
|
+
raise ArgumentError, "webhook payload must not include event; use the webhook event envelope type" if candidate.key?(:event)
|
|
221
227
|
raise ArgumentError, "service_id is required" if candidate[:service_id].to_s.empty?
|
|
222
228
|
raise ArgumentError, "gate_session_id is required" if candidate[:gate_session_id].to_s.empty?
|
|
223
229
|
raise ArgumentError, "gate_account_id is required" if candidate[:gate_account_id].to_s.empty?
|
|
@@ -230,7 +236,6 @@ module Tripwire
|
|
|
230
236
|
raise ArgumentError, "tripwire.score must be a number or null" unless score.nil? || score.is_a?(Numeric)
|
|
231
237
|
|
|
232
238
|
{
|
|
233
|
-
event: "gate.session.approved",
|
|
234
239
|
service_id: candidate[:service_id],
|
|
235
240
|
gate_session_id: candidate[:gate_session_id],
|
|
236
241
|
gate_account_id: candidate[:gate_account_id],
|
|
@@ -255,6 +260,26 @@ module Tripwire
|
|
|
255
260
|
false
|
|
256
261
|
end
|
|
257
262
|
|
|
263
|
+
def parse_webhook_event(raw_body)
|
|
264
|
+
envelope = symbolize(JSON.parse(raw_body))
|
|
265
|
+
raise ArgumentError, "webhook event object must be webhook_event" unless envelope[:object] == "webhook_event"
|
|
266
|
+
raise ArgumentError, "webhook event id is required" if envelope[:id].to_s.empty?
|
|
267
|
+
raise ArgumentError, "webhook event type is required" if envelope[:type].to_s.empty?
|
|
268
|
+
raise ArgumentError, "unsupported webhook event type: #{envelope[:type]}" unless WEBHOOK_EVENT_TYPES.include?(envelope[:type])
|
|
269
|
+
raise ArgumentError, "webhook event created timestamp is required" if envelope[:created].to_s.empty?
|
|
270
|
+
raise ArgumentError, "webhook event data must be an object" unless envelope[:data].is_a?(Hash)
|
|
271
|
+
|
|
272
|
+
envelope[:data] = validate_gate_approved_webhook_payload(envelope[:data]) if envelope[:type] == "gate.session.approved"
|
|
273
|
+
envelope
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
def verify_and_parse_webhook_event(secret:, timestamp:, raw_body:, signature:, max_age_seconds: 300, now_seconds: nil)
|
|
277
|
+
unless verify_gate_webhook_signature(secret: secret, timestamp: timestamp, raw_body: raw_body, signature: signature, max_age_seconds: max_age_seconds, now_seconds: now_seconds)
|
|
278
|
+
raise ArgumentError, "Invalid Tripwire webhook signature"
|
|
279
|
+
end
|
|
280
|
+
parse_webhook_event(raw_body)
|
|
281
|
+
end
|
|
282
|
+
|
|
258
283
|
def symbolize(value)
|
|
259
284
|
case value
|
|
260
285
|
when Array
|
data/spec/README.md
CHANGED
|
@@ -15,8 +15,8 @@ Server SDKs include only customer-facing APIs:
|
|
|
15
15
|
|
|
16
16
|
- `/v1/sessions`
|
|
17
17
|
- `/v1/fingerprints`
|
|
18
|
-
- `/v1/
|
|
19
|
-
- `/v1/
|
|
18
|
+
- `/v1/organizations`
|
|
19
|
+
- `/v1/organizations/:organizationId/api-keys`
|
|
20
20
|
- `/v1/gate/registry`
|
|
21
21
|
- `/v1/gate/services`
|
|
22
22
|
- `/v1/gate/sessions`
|
|
@@ -44,11 +44,11 @@ Every server SDK should expose these top-level capabilities:
|
|
|
44
44
|
- list
|
|
45
45
|
- get
|
|
46
46
|
- iterator / auto-pagination helper
|
|
47
|
-
-
|
|
47
|
+
- Organizations
|
|
48
48
|
- create
|
|
49
49
|
- get
|
|
50
50
|
- update
|
|
51
|
-
-
|
|
51
|
+
- Organization API keys
|
|
52
52
|
- create
|
|
53
53
|
- list
|
|
54
54
|
- revoke
|
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
"description": "Acme production signup flow",
|
|
9
9
|
"website": "https://acme.example.com",
|
|
10
10
|
"dashboard_login_url": "https://dashboard.acme.example.com/auth/gate",
|
|
11
|
-
"webhook_url": "https://api.acme.example.com/v1/gate/webhook",
|
|
12
11
|
"env_vars": [
|
|
13
12
|
{
|
|
14
13
|
"name": "Publishable key",
|
|
@@ -41,7 +40,8 @@
|
|
|
41
40
|
"privacy_url": "https://acme.example.com/privacy"
|
|
42
41
|
},
|
|
43
42
|
"created_at": "2026-04-03T20:00:00.000Z",
|
|
44
|
-
"updated_at": "2026-04-03T20:00:00.000Z"
|
|
43
|
+
"updated_at": "2026-04-03T20:00:00.000Z",
|
|
44
|
+
"webhook_endpoint_id": "we_0123456789abcdef0123456789abcdef"
|
|
45
45
|
},
|
|
46
46
|
"meta": {
|
|
47
47
|
"request_id": "req_0123456789abcdef0123456789abcdef"
|
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
"description": "Acme production signup flow",
|
|
9
9
|
"website": "https://acme.example.com",
|
|
10
10
|
"dashboard_login_url": "https://dashboard.acme.example.com/auth/gate",
|
|
11
|
-
"webhook_url": "https://api.acme.example.com/v1/gate/webhook",
|
|
12
11
|
"env_vars": [
|
|
13
12
|
{
|
|
14
13
|
"name": "Publishable key",
|
|
@@ -41,7 +40,8 @@
|
|
|
41
40
|
"privacy_url": "https://acme.example.com/privacy"
|
|
42
41
|
},
|
|
43
42
|
"created_at": "2026-04-03T20:00:00.000Z",
|
|
44
|
-
"updated_at": "2026-04-03T20:05:00.000Z"
|
|
43
|
+
"updated_at": "2026-04-03T20:05:00.000Z",
|
|
44
|
+
"webhook_endpoint_id": "we_0123456789abcdef0123456789abcdef"
|
|
45
45
|
},
|
|
46
46
|
"meta": {
|
|
47
47
|
"request_id": "req_0123456789abcdef0123456789abcdef"
|
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
"description": "Acme production signup flow",
|
|
9
9
|
"website": "https://acme.example.com",
|
|
10
10
|
"dashboard_login_url": "https://dashboard.acme.example.com/auth/gate",
|
|
11
|
-
"webhook_url": "https://api.acme.example.com/v1/gate/webhook",
|
|
12
11
|
"env_vars": [
|
|
13
12
|
{
|
|
14
13
|
"name": "Publishable key",
|
|
@@ -41,7 +40,8 @@
|
|
|
41
40
|
"privacy_url": "https://acme.example.com/privacy"
|
|
42
41
|
},
|
|
43
42
|
"created_at": "2026-04-03T20:00:00.000Z",
|
|
44
|
-
"updated_at": "2026-04-03T20:15:00.000Z"
|
|
43
|
+
"updated_at": "2026-04-03T20:15:00.000Z",
|
|
44
|
+
"webhook_endpoint_id": "we_0123456789abcdef0123456789abcdef"
|
|
45
45
|
},
|
|
46
46
|
"meta": {
|
|
47
47
|
"request_id": "req_0123456789abcdef0123456789abcdef"
|
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
"description": "Acme production signup flow",
|
|
9
9
|
"website": "https://acme.example.com",
|
|
10
10
|
"dashboard_login_url": "https://dashboard.acme.example.com/auth/gate",
|
|
11
|
-
"webhook_url": "https://api.acme.example.com/v1/gate/webhook",
|
|
12
11
|
"env_vars": [
|
|
13
12
|
{
|
|
14
13
|
"name": "Publishable key",
|
|
@@ -41,7 +40,8 @@
|
|
|
41
40
|
"privacy_url": "https://acme.example.com/privacy"
|
|
42
41
|
},
|
|
43
42
|
"created_at": "2026-04-03T20:00:00.000Z",
|
|
44
|
-
"updated_at": "2026-04-03T20:10:00.000Z"
|
|
43
|
+
"updated_at": "2026-04-03T20:10:00.000Z",
|
|
44
|
+
"webhook_endpoint_id": "we_0123456789abcdef0123456789abcdef"
|
|
45
45
|
},
|
|
46
46
|
"meta": {
|
|
47
47
|
"request_id": "req_0123456789abcdef0123456789abcdef"
|
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
"description": "Acme production signup flow",
|
|
10
10
|
"website": "https://acme.example.com",
|
|
11
11
|
"dashboard_login_url": "https://dashboard.acme.example.com/auth/gate",
|
|
12
|
-
"webhook_url": "https://api.acme.example.com/v1/gate/webhook",
|
|
13
12
|
"env_vars": [
|
|
14
13
|
{
|
|
15
14
|
"name": "Publishable key",
|
|
@@ -42,7 +41,8 @@
|
|
|
42
41
|
"privacy_url": "https://acme.example.com/privacy"
|
|
43
42
|
},
|
|
44
43
|
"created_at": "2026-04-03T20:00:00.000Z",
|
|
45
|
-
"updated_at": "2026-04-03T20:05:00.000Z"
|
|
44
|
+
"updated_at": "2026-04-03T20:05:00.000Z",
|
|
45
|
+
"webhook_endpoint_id": "we_0123456789abcdef0123456789abcdef"
|
|
46
46
|
}
|
|
47
47
|
],
|
|
48
48
|
"meta": {
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"data": {
|
|
3
|
+
"object": "api_key",
|
|
4
|
+
"id": "key_2y4grs8zpxb7n1q3dm5kc9wfta",
|
|
5
|
+
"type": "secret",
|
|
6
|
+
"name": "Production Backend",
|
|
7
|
+
"environment": "live",
|
|
8
|
+
"status": "active",
|
|
9
|
+
"allowed_origins": null,
|
|
10
|
+
"scopes": [
|
|
11
|
+
"sessions:list",
|
|
12
|
+
"sessions:read",
|
|
13
|
+
"api_keys:read"
|
|
14
|
+
],
|
|
15
|
+
"rate_limit": null,
|
|
16
|
+
"key_preview": "sk_live_[example]...",
|
|
17
|
+
"revealed_key": "sk_live_[example_secret_key]",
|
|
18
|
+
"last_used_at": null,
|
|
19
|
+
"created_at": "2026-03-24T19:00:00.000Z",
|
|
20
|
+
"rotated_at": null,
|
|
21
|
+
"revoked_at": null,
|
|
22
|
+
"grace_expires_at": null
|
|
23
|
+
},
|
|
24
|
+
"meta": {
|
|
25
|
+
"request_id": "req_0123456789abcdef0123456789abcdef"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -3,17 +3,22 @@
|
|
|
3
3
|
{
|
|
4
4
|
"object": "api_key",
|
|
5
5
|
"id": "key_6789abcdefghjkmnpqrstvwxyz",
|
|
6
|
-
"
|
|
7
|
-
"name": "
|
|
6
|
+
"type": "publishable",
|
|
7
|
+
"name": "Acme Web App",
|
|
8
8
|
"environment": "live",
|
|
9
|
+
"status": "active",
|
|
9
10
|
"allowed_origins": [
|
|
10
11
|
"https://example.com"
|
|
11
12
|
],
|
|
12
|
-
"
|
|
13
|
-
"
|
|
13
|
+
"scopes": null,
|
|
14
|
+
"rate_limit": null,
|
|
15
|
+
"key_preview": "pk_live_[example]...",
|
|
16
|
+
"display_key": "pk_live_[example_publishable_key]",
|
|
17
|
+
"last_used_at": "2026-03-24T19:30:00.000Z",
|
|
14
18
|
"created_at": "2026-03-24T19:00:00.000Z",
|
|
15
19
|
"rotated_at": null,
|
|
16
|
-
"revoked_at": null
|
|
20
|
+
"revoked_at": null,
|
|
21
|
+
"grace_expires_at": null
|
|
17
22
|
}
|
|
18
23
|
],
|
|
19
24
|
"pagination": {
|
|
@@ -2,17 +2,22 @@
|
|
|
2
2
|
"data": {
|
|
3
3
|
"object": "api_key",
|
|
4
4
|
"id": "key_6789abcdefghjkmnpqrstvwxyz",
|
|
5
|
-
"
|
|
6
|
-
"name": "
|
|
5
|
+
"type": "publishable",
|
|
6
|
+
"name": "Acme Web App",
|
|
7
7
|
"environment": "live",
|
|
8
|
+
"status": "revoked",
|
|
8
9
|
"allowed_origins": [
|
|
9
10
|
"https://example.com"
|
|
10
11
|
],
|
|
11
|
-
"
|
|
12
|
-
"
|
|
12
|
+
"scopes": null,
|
|
13
|
+
"rate_limit": null,
|
|
14
|
+
"key_preview": "pk_live_[example]...",
|
|
15
|
+
"display_key": "pk_live_[example_publishable_key]",
|
|
16
|
+
"last_used_at": "2026-03-24T19:30:00.000Z",
|
|
13
17
|
"created_at": "2026-03-24T19:00:00.000Z",
|
|
14
18
|
"rotated_at": null,
|
|
15
|
-
"revoked_at": "2026-03-24T20:05:00.000Z"
|
|
19
|
+
"revoked_at": "2026-03-24T20:05:00.000Z",
|
|
20
|
+
"grace_expires_at": null
|
|
16
21
|
},
|
|
17
22
|
"meta": {
|
|
18
23
|
"request_id": "req_0123456789abcdef0123456789abcdef"
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"data": {
|
|
3
|
+
"object": "api_key",
|
|
4
|
+
"id": "key_789abcdefghjkmnpqrstvwxyz0",
|
|
5
|
+
"type": "secret",
|
|
6
|
+
"name": "Production Backend",
|
|
7
|
+
"environment": "live",
|
|
8
|
+
"status": "active",
|
|
9
|
+
"allowed_origins": null,
|
|
10
|
+
"scopes": [
|
|
11
|
+
"sessions:list",
|
|
12
|
+
"sessions:read",
|
|
13
|
+
"api_keys:manage"
|
|
14
|
+
],
|
|
15
|
+
"rate_limit": null,
|
|
16
|
+
"key_preview": "sk_live_[rotated_example]...",
|
|
17
|
+
"revealed_key": "sk_live_[rotated_example_secret_key]",
|
|
18
|
+
"last_used_at": null,
|
|
19
|
+
"created_at": "2026-03-24T19:00:00.000Z",
|
|
20
|
+
"rotated_at": null,
|
|
21
|
+
"revoked_at": null,
|
|
22
|
+
"grace_expires_at": null
|
|
23
|
+
},
|
|
24
|
+
"meta": {
|
|
25
|
+
"request_id": "req_0123456789abcdef0123456789abcdef"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"data": {
|
|
3
|
+
"object": "api_key",
|
|
4
|
+
"id": "key_6789abcdefghjkmnpqrstvwxyz",
|
|
5
|
+
"type": "publishable",
|
|
6
|
+
"name": "Updated Web App",
|
|
7
|
+
"environment": "live",
|
|
8
|
+
"status": "active",
|
|
9
|
+
"allowed_origins": [
|
|
10
|
+
"https://example.com",
|
|
11
|
+
"https://app.example.com"
|
|
12
|
+
],
|
|
13
|
+
"scopes": [
|
|
14
|
+
"sessions:list",
|
|
15
|
+
"sessions:read"
|
|
16
|
+
],
|
|
17
|
+
"rate_limit": null,
|
|
18
|
+
"key_preview": "pk_live_[example]...",
|
|
19
|
+
"display_key": "pk_live_[example_publishable_key]",
|
|
20
|
+
"last_used_at": "2026-03-24T19:30:00.000Z",
|
|
21
|
+
"created_at": "2026-03-24T19:00:00.000Z",
|
|
22
|
+
"rotated_at": null,
|
|
23
|
+
"revoked_at": null,
|
|
24
|
+
"grace_expires_at": null
|
|
25
|
+
},
|
|
26
|
+
"meta": {
|
|
27
|
+
"request_id": "req_0123456789abcdef0123456789abcdef"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"data": {
|
|
3
|
-
"object": "
|
|
4
|
-
"id": "
|
|
5
|
-
"name": "Example
|
|
6
|
-
"slug": "example-
|
|
3
|
+
"object": "organization",
|
|
4
|
+
"id": "org_56789abcdefghjkmnpqrstvwxy",
|
|
5
|
+
"name": "Example Organization",
|
|
6
|
+
"slug": "example-organization",
|
|
7
7
|
"status": "active",
|
|
8
8
|
"created_at": "2026-03-24T19:00:00.000Z",
|
|
9
9
|
"updated_at": "2026-03-24T19:10:00.000Z"
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"data": {
|
|
3
|
-
"object": "
|
|
4
|
-
"id": "
|
|
5
|
-
"name": "Example
|
|
6
|
-
"slug": "example-
|
|
3
|
+
"object": "organization",
|
|
4
|
+
"id": "org_56789abcdefghjkmnpqrstvwxy",
|
|
5
|
+
"name": "Example Organization",
|
|
6
|
+
"slug": "example-organization",
|
|
7
7
|
"status": "suspended",
|
|
8
8
|
"created_at": "2026-03-24T19:00:00.000Z",
|
|
9
9
|
"updated_at": "2026-03-24T19:12:00.000Z"
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"data": {
|
|
3
|
-
"object": "
|
|
4
|
-
"id": "
|
|
5
|
-
"name": "Example
|
|
6
|
-
"slug": "example-
|
|
3
|
+
"object": "organization",
|
|
4
|
+
"id": "org_56789abcdefghjkmnpqrstvwxy",
|
|
5
|
+
"name": "Example Organization",
|
|
6
|
+
"slug": "example-organization",
|
|
7
7
|
"status": "active",
|
|
8
8
|
"created_at": "2026-03-24T19:00:00.000Z",
|
|
9
9
|
"updated_at": "2026-03-24T19:10:00.000Z"
|