@taprootio/integration-sdk 0.0.0-stage → 0.1.1

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.
Files changed (48) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +141 -2
  3. package/fixtures/manifest.valid.json +28 -0
  4. package/fixtures/webhooks/v1/common.schema.json +45 -0
  5. package/fixtures/webhooks/v1/examples/installation.created.json +1 -0
  6. package/fixtures/webhooks/v1/examples/installation.resumed.json +1 -0
  7. package/fixtures/webhooks/v1/examples/installation.suspended.json +1 -0
  8. package/fixtures/webhooks/v1/examples/installation.uninstalled.json +1 -0
  9. package/fixtures/webhooks/v1/examples/installation.updated.json +1 -0
  10. package/fixtures/webhooks/v1/examples/page.deleted.json +1 -0
  11. package/fixtures/webhooks/v1/examples/page.published.json +1 -0
  12. package/fixtures/webhooks/v1/examples/ping.json +1 -0
  13. package/fixtures/webhooks/v1/examples/placement.created.json +1 -0
  14. package/fixtures/webhooks/v1/examples/placement.deleted.json +1 -0
  15. package/fixtures/webhooks/v1/examples/placement.updated.json +1 -0
  16. package/fixtures/webhooks/v1/examples/publish.completed.json +1 -0
  17. package/fixtures/webhooks/v1/examples/publish.failed.json +1 -0
  18. package/fixtures/webhooks/v1/examples/sync.requested.json +1 -0
  19. package/fixtures/webhooks/v1/installation.created.schema.json +22 -0
  20. package/fixtures/webhooks/v1/installation.resumed.schema.json +8 -0
  21. package/fixtures/webhooks/v1/installation.suspended.schema.json +8 -0
  22. package/fixtures/webhooks/v1/installation.uninstalled.schema.json +8 -0
  23. package/fixtures/webhooks/v1/installation.updated.schema.json +8 -0
  24. package/fixtures/webhooks/v1/page.deleted.schema.json +23 -0
  25. package/fixtures/webhooks/v1/page.published.schema.json +23 -0
  26. package/fixtures/webhooks/v1/ping.schema.json +18 -0
  27. package/fixtures/webhooks/v1/placement.created.schema.json +23 -0
  28. package/fixtures/webhooks/v1/placement.deleted.schema.json +23 -0
  29. package/fixtures/webhooks/v1/placement.updated.schema.json +23 -0
  30. package/fixtures/webhooks/v1/publish.completed.schema.json +21 -0
  31. package/fixtures/webhooks/v1/publish.failed.schema.json +22 -0
  32. package/fixtures/webhooks/v1/schema-index.json +19 -0
  33. package/fixtures/webhooks/v1/signature-vector.json +9 -0
  34. package/fixtures/webhooks/v1/sync.requested.schema.json +22 -0
  35. package/index.d.ts +258 -0
  36. package/package.json +42 -4
  37. package/schema/taproot-integration-manifest.v1.schema.json +82 -0
  38. package/src/bytes.js +51 -0
  39. package/src/client.js +409 -0
  40. package/src/constants.js +17 -0
  41. package/src/errors.js +18 -0
  42. package/src/handoff.js +223 -0
  43. package/src/index.js +16 -0
  44. package/src/json.js +56 -0
  45. package/src/manifest.js +284 -0
  46. package/src/openapi-contract.d.ts +73 -0
  47. package/src/openapi-contract.js +1035 -0
  48. package/src/webhooks.js +269 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Taproot
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,142 @@
1
- # Temporary Holding Version
1
+ # @taprootio/integration-sdk
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ `@taprootio/integration-sdk` is the public Node 22 kit for integrations that push their own content into Taproot. It has no third-party runtime dependencies and is versioned independently from the Taproot application.
4
+
5
+ Taproot publishes accepted, immutable content; it does not call an integration during rendering or publishing. An integration receives signed webhooks that request reconciliation, then uses its installation credential to push pages, media, JSON documents, and placement fragments.
6
+
7
+ ## Install
8
+
9
+ ```sh
10
+ npm install @taprootio/integration-sdk@0.1.1
11
+ ```
12
+
13
+ The public manifest schema is exported at `@taprootio/integration-sdk/schema`. The fixtures under `@taprootio/integration-sdk/fixtures/...` are contract examples, not a local fixture host or a production deployment recipe.
14
+
15
+ ## Manifest
16
+
17
+ The manifest is declarative data for registration, review, and owner consent. It does not cause Taproot to run integration code.
18
+
19
+ ```js
20
+ import { assertValidManifest } from "@taprootio/integration-sdk";
21
+
22
+ const manifest = assertValidManifest({
23
+ slug: "class-schedule",
24
+ displayName: "Class Schedule",
25
+ webhookEndpointUrl: "https://integration.example/webhooks/taproot",
26
+ settingsUrl: "https://integration.example/settings",
27
+ requestedCapabilities: ["pages.manage_own", "data.manage_own", "publish"],
28
+ offeredComponents: [],
29
+ externalScriptOrigins: [],
30
+ defaultPublishPolicy: "stage",
31
+ recommendedUninstallDisposition: "freeze",
32
+ contractVersion: "1",
33
+ pricingOptions: [{ id: "free", version: "1", quantityMin: 1, quantityMax: null, cadence: "free", catalogueItemKey: null }],
34
+ });
35
+ ```
36
+
37
+ `validateManifest` is a bounded local preflight. Taproot remains authoritative for DNS resolution, public-route validation, registry status, consent, and authorization. Do not treat a successful local validation as registration.
38
+
39
+ ## Credentials and content
40
+
41
+ Publisher and installation credentials are separate authorities. Never put a browser session, a site-authoring key, or an owner credential in this client. Pass credentials when constructing the client; each method uses only the credential appropriate to its contract scope.
42
+
43
+ ```js
44
+ import { TaprootIntegrationClient, createIdempotencyKey } from "@taprootio/integration-sdk";
45
+
46
+ const client = new TaprootIntegrationClient({
47
+ // Canonical API base: include /api when Taproot serves its API beneath it.
48
+ baseUrl: "https://app.example/api",
49
+ installationCredential: process.env.TAPROOT_INSTALLATION_CREDENTIAL,
50
+ publisherCredential: process.env.TAPROOT_PUBLISHER_CREDENTIAL,
51
+ });
52
+
53
+ const sync = await client.createSync({
54
+ installationId,
55
+ mode: "full",
56
+ requestedSyncId: webhook.event.data.syncId,
57
+ idempotencyKey: createIdempotencyKey(),
58
+ });
59
+
60
+ await client.putManagedPage({
61
+ installationId,
62
+ syncId: sync.syncId,
63
+ idempotencyKey: createIdempotencyKey(),
64
+ page: {
65
+ externalId: "class-101", path: "/classes/class-101/", title: "Strength 101",
66
+ description: "A beginner strength class.", indexable: true, fragments: ["<p>Bring water.</p>"],
67
+ structuredData: [JSON.stringify({ "@context": "https://schema.org", "@type": "WebPage", "@id": "https://integration.example/classes#primary", name: "Classes" })],
68
+ primaryStructuredDataId: "https://integration.example/classes#primary", folder: "classes", tagIds: [],
69
+ includeInNavigation: false, publicationDate: "", archiveDate: "", includeInLatestPosts: false,
70
+ },
71
+ });
72
+ await client.completeSync({ installationId, syncId: sync.syncId, idempotencyKey: createIdempotencyKey() });
73
+ ```
74
+
75
+ Keep an idempotency key with its one logical operation in durable application state. Content, sync, and fragment mutations retry a bounded number of transient failures with that same key. The SDK does not retry validation or authorization failures.
76
+
77
+ `claimInstallation` deliberately does not retry after a transport failure or an unreadable successful response. The installation credential secret is returned only once; a lost successful claim response cannot recover it. Persist the secret before replying to the webhook. If the response is unknown, validate the installation and use the owner-visible claim reissue workflow when appropriate; do not submit the claim code repeatedly.
78
+
79
+ Bundle admission is publisher-scoped. `requestBundleUpload` and `confirmBundleUpload` only create and confirm an immutable upload. Operator approval and owner pinning are separate Taproot-side authorities and are not SDK operations.
80
+
81
+ ## Webhooks
82
+
83
+ Read request bytes with a size limit, then verify those same bytes before parsing JSON. The HMAC is over the ASCII timestamp, a period, and the exact body bytes: `ASCII(t + ".") + body`.
84
+
85
+ ```js
86
+ import { claimWebhookReceipt, finishWebhookReceipt, verifyWebhookSignature } from "@taprootio/integration-sdk";
87
+
88
+ const verified = verifyWebhookSignature({
89
+ headers: request.headers,
90
+ body: rawRequestBytes,
91
+ signingSecrets: signingSecretsByKeyId,
92
+ });
93
+ const claimed = await claimWebhookReceipt({ store: postgresWebhookReceipts, verified });
94
+ if (claimed.state === "duplicate") return new Response(null, { status: 204 });
95
+ if (claimed.state === "in_progress") return new Response(null, { status: 503, headers: { "Retry-After": "1" } });
96
+ if (claimed.state === "conflict") return new Response(null, { status: 409 });
97
+
98
+ try {
99
+ await process(verified.event);
100
+ await finishWebhookReceipt({ store: postgresWebhookReceipts, verified, token: claimed.token, status: "delivered" });
101
+ return new Response(null, { status: 204 });
102
+ } catch (error) {
103
+ await finishWebhookReceipt({ store: postgresWebhookReceipts, verified, token: claimed.token, status: "failed" });
104
+ throw error;
105
+ }
106
+ ```
107
+
108
+ `WebhookReceiptStore` is intentionally an interface. Its `claim` operation must be atomic and durable across process restarts, keyed by delivery id and immutable signed metadata. An in-memory `Set` is not receipt persistence. Return `duplicate` only after the same immutable receipt is delivered. A current processing lease returns `in_progress`, so respond `503` rather than acknowledge it: Taproot must redeliver if that worker fails. A failed receipt or expired lease must be claimed again with a fresh token. A durable receipt gives at-least-once processing; it does not make external side effects exactly once. Recover expired processing leases in your database and make every downstream effect idempotent.
109
+
110
+ During key rotation, keep active and overlapping retired HMAC secrets in `signingSecrets` until Taproot no longer sends either key id. Unknown key ids, stale timestamps, malformed signatures, modified body bytes, and mismatched delivery headers are rejected.
111
+
112
+ ## Settings handoff
113
+
114
+ The owner settings redirect contains a five-minute RS256 handoff token. Strip it from the browser URL immediately and never log it, put it in analytics, or use it as a session. Verify the token, place a short-lived pending record in your service, then call the authoritative one-time confirmation before creating an integration-owned session.
115
+
116
+ ```js
117
+ import { confirmHandoff, verifyHandoff } from "@taprootio/integration-sdk";
118
+
119
+ const claims = await verifyHandoff({
120
+ token: handoffToken,
121
+ issuer: "https://app.taproot.io",
122
+ audience: integrationId,
123
+ installationId,
124
+ jwksUrl: "https://app.taproot.io/api/.well-known/taproot-integrations-jwks.json",
125
+ });
126
+
127
+ // Delete the local pending record before this request. If its response is lost,
128
+ // do not replay the token: begin a new owner handoff.
129
+ const session = await confirmHandoff({ client, claims, token: handoffToken });
130
+ ```
131
+
132
+ `verifyHandoff` checks the token's exact RS256 header, JWK key selection, issuer, audience, installation binding, issued/expiry times, role, and claim shape. Set `issuer` to the exact operator-published `iss` value, not an API base URL, and configure the operator-published JWKS URL explicitly. The default `<issuer>/.well-known/taproot-integrations-jwks.json` is only suitable when the operator publishes keys at that derived URL. The JWKS cache observes the published lifetime, capped at five minutes. Confirmation checks the returned identity against verified claims and bounds the integration-owned session to 24 hours by default. There is no refresh credential.
133
+
134
+ ## Fragments and placements
135
+
136
+ `validateFragment` is advisory feedback for obvious unsafe markup. It is not a copy of Taproot's sanitizer and cannot promise the same result. Send the original fragment to `putFragment`; the server validates final bytes, links them to the exact requested placement configuration revision, and selects them only through immutable publication. A static fragment must remain useful when an optional browser bundle is unavailable.
137
+
138
+ `listPlacements` returns only the installation's placement identities and configuration. It never grants access to host page content. For stale configuration or fragment revision conflicts, fetch the latest placement, render against its exact configuration revision, and write a new idempotent operation rather than overwriting an older fragment.
139
+
140
+ ## Public boundaries
141
+
142
+ This SDK deliberately excludes owner, administrator, operator, billing, registry-management, bundle-approval, and internal RPCs. It does not store credentials, execute integration bundles, provide an HTML sanitizer, or call Taproot from the published-site render path.
@@ -0,0 +1,28 @@
1
+ {
2
+ "slug": "fixture-fitness",
3
+ "displayName": "Fixture Fitness Publisher",
4
+ "webhookEndpointUrl": "https://receiver.example.test/webhooks",
5
+ "settingsUrl": "https://receiver.example.test/settings",
6
+ "requestedCapabilities": [
7
+ "pages.manage_own",
8
+ "data.manage_own",
9
+ "media.manage_own",
10
+ "publish",
11
+ "site.pages.read"
12
+ ],
13
+ "offeredComponents": [],
14
+ "externalScriptOrigins": [],
15
+ "defaultPublishPolicy": "stage",
16
+ "recommendedUninstallDisposition": "freeze",
17
+ "contractVersion": "1",
18
+ "pricingOptions": [
19
+ {
20
+ "id": "free",
21
+ "version": "1",
22
+ "quantityMin": 1,
23
+ "quantityMax": null,
24
+ "cadence": "free",
25
+ "catalogueItemKey": null
26
+ }
27
+ ]
28
+ }
@@ -0,0 +1,45 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://schemas.taproot.test/integrations/webhooks/v1/common.schema.json",
4
+ "$defs": {
5
+ "envelope": {
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": ["id", "type", "version", "occurredAt", "integrationId", "installationId", "siteId", "data"],
9
+ "properties": {
10
+ "id": { "type": "string", "format": "uuid" },
11
+ "type": { "type": "string" },
12
+ "version": { "const": "1" },
13
+ "occurredAt": { "type": "string", "format": "date-time" },
14
+ "integrationId": { "type": "string", "format": "uuid" },
15
+ "installationId": { "type": "string", "format": "uuid" },
16
+ "siteId": { "type": "string", "format": "uuid" },
17
+ "data": true
18
+ }
19
+ },
20
+ "installationState": {
21
+ "type": "object",
22
+ "additionalProperties": false,
23
+ "required": ["status", "revision", "grantedCapabilities", "publishPolicy", "contractVersion", "sourceKind", "sourceEngagementId", "sourceTerminationReason"],
24
+ "properties": {
25
+ "status": { "type": "string" },
26
+ "revision": { "type": "integer", "minimum": 0 },
27
+ "grantedCapabilities": { "type": "array", "items": { "type": "string" } },
28
+ "publishPolicy": { "enum": ["auto", "stage"] },
29
+ "contractVersion": { "type": "string" },
30
+ "sourceKind": { "enum": ["owner", "engagement"] },
31
+ "sourceEngagementId": { "type": ["string", "null"], "format": "uuid" },
32
+ "sourceTerminationReason": { "type": ["string", "null"] }
33
+ }
34
+ },
35
+ "publishedCandidate": {
36
+ "type": "object",
37
+ "additionalProperties": false,
38
+ "required": ["candidateId", "revision"],
39
+ "properties": {
40
+ "candidateId": { "type": "string", "format": "uuid" },
41
+ "revision": { "type": "integer", "minimum": 0 }
42
+ }
43
+ }
44
+ }
45
+ }
@@ -0,0 +1 @@
1
+ {"id":"00000000-0000-4000-8000-000000000002","type":"installation.created","version":"1","occurredAt":"2025-01-01T00:00:00Z","integrationId":"10000000-0000-4000-8000-000000000001","installationId":"20000000-0000-4000-8000-000000000001","siteId":"30000000-0000-4000-8000-000000000001","data":{"installation":{"status":"pending_claim","revision":1,"grantedCapabilities":[],"publishPolicy":"stage","contractVersion":"1","sourceKind":"owner","sourceEngagementId":null,"sourceTerminationReason":null},"claimCode":"fixture-claim-code","claimExpiresAt":"2025-01-02T00:00:00Z"}}
@@ -0,0 +1 @@
1
+ {"id":"00000000-0000-4000-8000-000000000005","type":"installation.resumed","version":"1","occurredAt":"2025-01-01T00:03:00Z","integrationId":"10000000-0000-4000-8000-000000000001","installationId":"20000000-0000-4000-8000-000000000001","siteId":"30000000-0000-4000-8000-000000000001","data":{"status":"active","revision":4,"grantedCapabilities":[],"publishPolicy":"stage","contractVersion":"1","sourceKind":"owner","sourceEngagementId":null,"sourceTerminationReason":null}}
@@ -0,0 +1 @@
1
+ {"id":"00000000-0000-4000-8000-000000000004","type":"installation.suspended","version":"1","occurredAt":"2025-01-01T00:02:00Z","integrationId":"10000000-0000-4000-8000-000000000001","installationId":"20000000-0000-4000-8000-000000000001","siteId":"30000000-0000-4000-8000-000000000001","data":{"status":"suspended","revision":3,"grantedCapabilities":[],"publishPolicy":"stage","contractVersion":"1","sourceKind":"owner","sourceEngagementId":null,"sourceTerminationReason":null}}
@@ -0,0 +1 @@
1
+ {"id":"00000000-0000-4000-8000-000000000006","type":"installation.uninstalled","version":"1","occurredAt":"2025-01-01T00:04:00Z","integrationId":"10000000-0000-4000-8000-000000000001","installationId":"20000000-0000-4000-8000-000000000001","siteId":"30000000-0000-4000-8000-000000000001","data":{"status":"uninstalled","revision":5,"grantedCapabilities":[],"publishPolicy":"stage","contractVersion":"1","sourceKind":"owner","sourceEngagementId":null,"sourceTerminationReason":"owner_request"}}
@@ -0,0 +1 @@
1
+ {"id":"00000000-0000-4000-8000-000000000003","type":"installation.updated","version":"1","occurredAt":"2025-01-01T00:01:00Z","integrationId":"10000000-0000-4000-8000-000000000001","installationId":"20000000-0000-4000-8000-000000000001","siteId":"30000000-0000-4000-8000-000000000001","data":{"status":"active","revision":2,"grantedCapabilities":[],"publishPolicy":"stage","contractVersion":"1","sourceKind":"owner","sourceEngagementId":null,"sourceTerminationReason":null}}
@@ -0,0 +1 @@
1
+ {"id":"00000000-0000-4000-8000-000000000014","type":"page.deleted","version":"1","occurredAt":"2025-01-01T00:12:00Z","integrationId":"10000000-0000-4000-8000-000000000001","installationId":"20000000-0000-4000-8000-000000000001","siteId":"30000000-0000-4000-8000-000000000001","data":{"pageId":"80000000-0000-4000-8000-000000000001","externalId":"class-101","revision":15,"url":"/classes/class-101/"}}
@@ -0,0 +1 @@
1
+ {"id":"00000000-0000-4000-8000-000000000013","type":"page.published","version":"1","occurredAt":"2025-01-01T00:11:00Z","integrationId":"10000000-0000-4000-8000-000000000001","installationId":"20000000-0000-4000-8000-000000000001","siteId":"30000000-0000-4000-8000-000000000001","data":{"pageId":"80000000-0000-4000-8000-000000000001","externalId":"class-101","publishedRevision":14,"url":"/classes/class-101/"}}
@@ -0,0 +1 @@
1
+ {"id":"00000000-0000-4000-8000-000000000001","type":"ping","version":"1","occurredAt":"2025-01-01T00:00:00Z","integrationId":"10000000-0000-4000-8000-000000000001","installationId":"20000000-0000-4000-8000-000000000001","siteId":"30000000-0000-4000-8000-000000000001","data":{"purpose":"endpoint_verification"}}
@@ -0,0 +1 @@
1
+ {"id":"00000000-0000-4000-8000-000000000008","type":"placement.created","version":"1","occurredAt":"2025-01-01T00:06:00Z","integrationId":"10000000-0000-4000-8000-000000000001","installationId":"20000000-0000-4000-8000-000000000001","siteId":"30000000-0000-4000-8000-000000000001","data":{"placementId":"60000000-0000-4000-8000-000000000001","componentId":"schedule","placementRevision":7,"config":{"location":"downtown","showCapacity":true}}}
@@ -0,0 +1 @@
1
+ {"id":"00000000-0000-4000-8000-000000000010","type":"placement.deleted","version":"1","occurredAt":"2025-01-01T00:08:00Z","integrationId":"10000000-0000-4000-8000-000000000001","installationId":"20000000-0000-4000-8000-000000000001","siteId":"30000000-0000-4000-8000-000000000001","data":{"placementId":"60000000-0000-4000-8000-000000000001","componentId":"schedule","placementRevision":9,"config":null}}
@@ -0,0 +1 @@
1
+ {"id":"00000000-0000-4000-8000-000000000009","type":"placement.updated","version":"1","occurredAt":"2025-01-01T00:07:00Z","integrationId":"10000000-0000-4000-8000-000000000001","installationId":"20000000-0000-4000-8000-000000000001","siteId":"30000000-0000-4000-8000-000000000001","data":{"placementId":"60000000-0000-4000-8000-000000000001","componentId":"schedule","placementRevision":8,"config":{"location":"uptown","showCapacity":false}}}
@@ -0,0 +1 @@
1
+ {"id":"00000000-0000-4000-8000-000000000011","type":"publish.completed","version":"1","occurredAt":"2025-01-01T00:09:00Z","integrationId":"10000000-0000-4000-8000-000000000001","installationId":"20000000-0000-4000-8000-000000000001","siteId":"30000000-0000-4000-8000-000000000001","data":{"deploymentId":"70000000-0000-4000-8000-000000000001","candidates":[{"candidateId":"50000000-0000-4000-8000-000000000001","revision":12}]}}
@@ -0,0 +1 @@
1
+ {"id":"00000000-0000-4000-8000-000000000012","type":"publish.failed","version":"1","occurredAt":"2025-01-01T00:10:00Z","integrationId":"10000000-0000-4000-8000-000000000001","installationId":"20000000-0000-4000-8000-000000000001","siteId":"30000000-0000-4000-8000-000000000001","data":{"deploymentId":"70000000-0000-4000-8000-000000000002","candidateIds":["50000000-0000-4000-8000-000000000002"],"code":"render_failed"}}
@@ -0,0 +1 @@
1
+ {"id":"00000000-0000-4000-8000-000000000007","type":"sync.requested","version":"1","occurredAt":"2025-01-01T00:05:00Z","integrationId":"10000000-0000-4000-8000-000000000001","installationId":"20000000-0000-4000-8000-000000000001","siteId":"30000000-0000-4000-8000-000000000001","data":{"reason":"reconcile","syncId":"40000000-0000-4000-8000-000000000001","candidateIds":["50000000-0000-4000-8000-000000000001","50000000-0000-4000-8000-000000000002"]}}
@@ -0,0 +1,22 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://schemas.taproot.test/integrations/webhooks/v1/installation.created.schema.json",
4
+ "allOf": [
5
+ { "$ref": "common.schema.json#/$defs/envelope" },
6
+ {
7
+ "properties": {
8
+ "type": { "const": "installation.created" },
9
+ "data": {
10
+ "type": "object",
11
+ "additionalProperties": false,
12
+ "required": ["installation", "claimCode", "claimExpiresAt"],
13
+ "properties": {
14
+ "installation": { "$ref": "common.schema.json#/$defs/installationState" },
15
+ "claimCode": { "type": "string", "minLength": 1, "maxLength": 256 },
16
+ "claimExpiresAt": { "type": "string", "format": "date-time" }
17
+ }
18
+ }
19
+ }
20
+ }
21
+ ]
22
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://schemas.taproot.test/integrations/webhooks/v1/installation.resumed.schema.json",
4
+ "allOf": [
5
+ { "$ref": "common.schema.json#/$defs/envelope" },
6
+ { "properties": { "type": { "const": "installation.resumed" }, "data": { "$ref": "common.schema.json#/$defs/installationState" } } }
7
+ ]
8
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://schemas.taproot.test/integrations/webhooks/v1/installation.suspended.schema.json",
4
+ "allOf": [
5
+ { "$ref": "common.schema.json#/$defs/envelope" },
6
+ { "properties": { "type": { "const": "installation.suspended" }, "data": { "$ref": "common.schema.json#/$defs/installationState" } } }
7
+ ]
8
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://schemas.taproot.test/integrations/webhooks/v1/installation.uninstalled.schema.json",
4
+ "allOf": [
5
+ { "$ref": "common.schema.json#/$defs/envelope" },
6
+ { "properties": { "type": { "const": "installation.uninstalled" }, "data": { "$ref": "common.schema.json#/$defs/installationState" } } }
7
+ ]
8
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://schemas.taproot.test/integrations/webhooks/v1/installation.updated.schema.json",
4
+ "allOf": [
5
+ { "$ref": "common.schema.json#/$defs/envelope" },
6
+ { "properties": { "type": { "const": "installation.updated" }, "data": { "$ref": "common.schema.json#/$defs/installationState" } } }
7
+ ]
8
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://schemas.taproot.test/integrations/webhooks/v1/page.deleted.schema.json",
4
+ "allOf": [
5
+ { "$ref": "common.schema.json#/$defs/envelope" },
6
+ {
7
+ "properties": {
8
+ "type": { "const": "page.deleted" },
9
+ "data": {
10
+ "type": "object",
11
+ "additionalProperties": false,
12
+ "required": ["pageId", "externalId", "revision", "url"],
13
+ "properties": {
14
+ "pageId": { "type": "string", "format": "uuid" },
15
+ "externalId": { "type": "string", "minLength": 1 },
16
+ "revision": { "type": "integer", "minimum": 0 },
17
+ "url": { "type": "string", "format": "uri-reference" }
18
+ }
19
+ }
20
+ }
21
+ }
22
+ ]
23
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://schemas.taproot.test/integrations/webhooks/v1/page.published.schema.json",
4
+ "allOf": [
5
+ { "$ref": "common.schema.json#/$defs/envelope" },
6
+ {
7
+ "properties": {
8
+ "type": { "const": "page.published" },
9
+ "data": {
10
+ "type": "object",
11
+ "additionalProperties": false,
12
+ "required": ["pageId", "externalId", "publishedRevision", "url"],
13
+ "properties": {
14
+ "pageId": { "type": "string", "format": "uuid" },
15
+ "externalId": { "type": "string", "minLength": 1 },
16
+ "publishedRevision": { "type": "integer", "minimum": 0 },
17
+ "url": { "type": "string", "format": "uri-reference" }
18
+ }
19
+ }
20
+ }
21
+ }
22
+ ]
23
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://schemas.taproot.test/integrations/webhooks/v1/ping.schema.json",
4
+ "allOf": [
5
+ { "$ref": "common.schema.json#/$defs/envelope" },
6
+ {
7
+ "properties": {
8
+ "type": { "const": "ping" },
9
+ "data": {
10
+ "type": "object",
11
+ "additionalProperties": false,
12
+ "required": ["purpose"],
13
+ "properties": { "purpose": { "type": "string", "minLength": 1 } }
14
+ }
15
+ }
16
+ }
17
+ ]
18
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://schemas.taproot.test/integrations/webhooks/v1/placement.created.schema.json",
4
+ "allOf": [
5
+ { "$ref": "common.schema.json#/$defs/envelope" },
6
+ {
7
+ "properties": {
8
+ "type": { "const": "placement.created" },
9
+ "data": {
10
+ "type": "object",
11
+ "additionalProperties": false,
12
+ "required": ["placementId", "componentId", "placementRevision", "config"],
13
+ "properties": {
14
+ "placementId": { "type": "string", "format": "uuid" },
15
+ "componentId": { "type": "string", "minLength": 1 },
16
+ "placementRevision": { "type": "integer", "minimum": 0 },
17
+ "config": true
18
+ }
19
+ }
20
+ }
21
+ }
22
+ ]
23
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://schemas.taproot.test/integrations/webhooks/v1/placement.deleted.schema.json",
4
+ "allOf": [
5
+ { "$ref": "common.schema.json#/$defs/envelope" },
6
+ {
7
+ "properties": {
8
+ "type": { "const": "placement.deleted" },
9
+ "data": {
10
+ "type": "object",
11
+ "additionalProperties": false,
12
+ "required": ["placementId", "componentId", "placementRevision", "config"],
13
+ "properties": {
14
+ "placementId": { "type": "string", "format": "uuid" },
15
+ "componentId": { "type": "string", "minLength": 1 },
16
+ "placementRevision": { "type": "integer", "minimum": 0 },
17
+ "config": true
18
+ }
19
+ }
20
+ }
21
+ }
22
+ ]
23
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://schemas.taproot.test/integrations/webhooks/v1/placement.updated.schema.json",
4
+ "allOf": [
5
+ { "$ref": "common.schema.json#/$defs/envelope" },
6
+ {
7
+ "properties": {
8
+ "type": { "const": "placement.updated" },
9
+ "data": {
10
+ "type": "object",
11
+ "additionalProperties": false,
12
+ "required": ["placementId", "componentId", "placementRevision", "config"],
13
+ "properties": {
14
+ "placementId": { "type": "string", "format": "uuid" },
15
+ "componentId": { "type": "string", "minLength": 1 },
16
+ "placementRevision": { "type": "integer", "minimum": 0 },
17
+ "config": true
18
+ }
19
+ }
20
+ }
21
+ }
22
+ ]
23
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://schemas.taproot.test/integrations/webhooks/v1/publish.completed.schema.json",
4
+ "allOf": [
5
+ { "$ref": "common.schema.json#/$defs/envelope" },
6
+ {
7
+ "properties": {
8
+ "type": { "const": "publish.completed" },
9
+ "data": {
10
+ "type": "object",
11
+ "additionalProperties": false,
12
+ "required": ["deploymentId", "candidates"],
13
+ "properties": {
14
+ "deploymentId": { "type": "string", "format": "uuid" },
15
+ "candidates": { "type": "array", "items": { "$ref": "common.schema.json#/$defs/publishedCandidate" } }
16
+ }
17
+ }
18
+ }
19
+ }
20
+ ]
21
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://schemas.taproot.test/integrations/webhooks/v1/publish.failed.schema.json",
4
+ "allOf": [
5
+ { "$ref": "common.schema.json#/$defs/envelope" },
6
+ {
7
+ "properties": {
8
+ "type": { "const": "publish.failed" },
9
+ "data": {
10
+ "type": "object",
11
+ "additionalProperties": false,
12
+ "required": ["deploymentId", "candidateIds", "code"],
13
+ "properties": {
14
+ "deploymentId": { "type": "string", "format": "uuid" },
15
+ "candidateIds": { "type": "array", "items": { "type": "string", "format": "uuid" } },
16
+ "code": { "type": "string", "minLength": 1 }
17
+ }
18
+ }
19
+ }
20
+ }
21
+ ]
22
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "version": "1",
3
+ "events": {
4
+ "ping": "ping.schema.json",
5
+ "installation.created": "installation.created.schema.json",
6
+ "installation.updated": "installation.updated.schema.json",
7
+ "installation.suspended": "installation.suspended.schema.json",
8
+ "installation.resumed": "installation.resumed.schema.json",
9
+ "installation.uninstalled": "installation.uninstalled.schema.json",
10
+ "sync.requested": "sync.requested.schema.json",
11
+ "placement.created": "placement.created.schema.json",
12
+ "placement.updated": "placement.updated.schema.json",
13
+ "placement.deleted": "placement.deleted.schema.json",
14
+ "publish.completed": "publish.completed.schema.json",
15
+ "publish.failed": "publish.failed.schema.json",
16
+ "page.published": "page.published.schema.json",
17
+ "page.deleted": "page.deleted.schema.json"
18
+ }
19
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "algorithm": "HMAC-SHA256",
3
+ "signingSecretBase64": "SmVmZQ==",
4
+ "timestamp": 1735689600,
5
+ "keyId": "90000000-0000-4000-8000-000000000001",
6
+ "bodyFile": "examples/installation.created.json",
7
+ "bodySha256": "01a0fcd0a324d46ede4a7ba87dcd2a3239996f1b1b17cb44abcd24d3a9a19114",
8
+ "header": "t=1735689600,k=90000000-0000-4000-8000-000000000001,v1=b13fa92de238838f31de4b2ac3f9149ce87c5f5061893b194cd2104f918ddccf"
9
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://schemas.taproot.test/integrations/webhooks/v1/sync.requested.schema.json",
4
+ "allOf": [
5
+ { "$ref": "common.schema.json#/$defs/envelope" },
6
+ {
7
+ "properties": {
8
+ "type": { "const": "sync.requested" },
9
+ "data": {
10
+ "type": "object",
11
+ "additionalProperties": false,
12
+ "required": ["reason", "syncId", "candidateIds"],
13
+ "properties": {
14
+ "reason": { "enum": ["scheduled", "owner", "placement_changed", "reconcile"] },
15
+ "syncId": { "type": "string", "format": "uuid" },
16
+ "candidateIds": { "type": "array", "items": { "type": "string", "format": "uuid" } }
17
+ }
18
+ }
19
+ }
20
+ }
21
+ ]
22
+ }