@authorizedretailers/spec 0.1.0

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 (98) hide show
  1. package/LICENSE +202 -0
  2. package/LICENSE-SPEC +396 -0
  3. package/README.md +130 -0
  4. package/dist/constants.d.ts +6 -0
  5. package/dist/constants.js +7 -0
  6. package/dist/identity.d.ts +27 -0
  7. package/dist/identity.js +92 -0
  8. package/dist/index.d.ts +8 -0
  9. package/dist/index.js +8 -0
  10. package/dist/jcs.d.ts +5 -0
  11. package/dist/jcs.js +47 -0
  12. package/dist/jws.d.ts +42 -0
  13. package/dist/jws.js +90 -0
  14. package/dist/published.d.ts +15 -0
  15. package/dist/published.js +15 -0
  16. package/dist/schemas.d.ts +519 -0
  17. package/dist/schemas.js +662 -0
  18. package/dist/timestamp.d.ts +6 -0
  19. package/dist/timestamp.js +26 -0
  20. package/dist/types.d.ts +116 -0
  21. package/dist/types.js +2 -0
  22. package/dist/validate.d.ts +28 -0
  23. package/dist/validate.js +147 -0
  24. package/fixtures/file/invalid/full-all-mixed.json +47 -0
  25. package/fixtures/file/invalid/full-amazon-missing-seller-id.json +45 -0
  26. package/fixtures/file/invalid/full-attached-jws.json +50 -0
  27. package/fixtures/file/invalid/full-authorization-expires-after-file.json +46 -0
  28. package/fixtures/file/invalid/full-duplicate-authorization-id.json +80 -0
  29. package/fixtures/file/invalid/full-empty-territories.json +43 -0
  30. package/fixtures/file/invalid/full-expires-before-issued.json +46 -0
  31. package/fixtures/file/invalid/full-expiry-over-180-days.json +46 -0
  32. package/fixtures/file/invalid/full-extra-property.json +47 -0
  33. package/fixtures/file/invalid/full-impossible-date.json +46 -0
  34. package/fixtures/file/invalid/full-lowercase-territory.json +45 -0
  35. package/fixtures/file/invalid/full-missing-authorization-expires.json +45 -0
  36. package/fixtures/file/invalid/full-missing-file-expires.json +45 -0
  37. package/fixtures/file/invalid/full-missing-product-lines.json +43 -0
  38. package/fixtures/file/invalid/full-missing-scope.json +37 -0
  39. package/fixtures/file/invalid/full-missing-territories.json +42 -0
  40. package/fixtures/file/invalid/full-name-only-retailer.json +30 -0
  41. package/fixtures/file/invalid/full-no-channels.json +31 -0
  42. package/fixtures/file/invalid/full-non-utc-timestamp.json +46 -0
  43. package/fixtures/file/invalid/full-physical-missing-country.json +50 -0
  44. package/fixtures/file/invalid/full-signature-missing-kid.json +49 -0
  45. package/fixtures/file/invalid/full-unknown-channel-type.json +50 -0
  46. package/fixtures/file/invalid/full-web-domain-is-url.json +46 -0
  47. package/fixtures/file/invalid/full-web-missing-domain.json +45 -0
  48. package/fixtures/file/invalid/full-wildcard-mixed.json +46 -0
  49. package/fixtures/file/invalid/full-wrong-spec.json +46 -0
  50. package/fixtures/file/invalid/pointer-http-url.json +9 -0
  51. package/fixtures/file/invalid/private-missing-verify.json +8 -0
  52. package/fixtures/file/invalid/private-with-authorizations.json +45 -0
  53. package/fixtures/file/invalid/unknown-form.json +9 -0
  54. package/fixtures/file/valid/full-fractional-seconds.json +46 -0
  55. package/fixtures/file/valid/full-max-expiry.json +46 -0
  56. package/fixtures/file/valid/full-no-authorizations.json +11 -0
  57. package/fixtures/file/valid/full-signed.json +50 -0
  58. package/fixtures/file/valid/full-unsigned-handwritten.json +46 -0
  59. package/fixtures/file/valid/full-worldwide-physical-proposed.json +82 -0
  60. package/fixtures/file/valid/pointer.json +9 -0
  61. package/fixtures/file/valid/private.json +9 -0
  62. package/fixtures/manifest.json +434 -0
  63. package/fixtures/verify-request/invalid/domain-with-scheme.json +10 -0
  64. package/fixtures/verify-request/invalid/missing-channel.json +5 -0
  65. package/fixtures/verify-request/invalid/physical-channel.json +10 -0
  66. package/fixtures/verify-request/invalid/retailer-name-only.json +6 -0
  67. package/fixtures/verify-request/invalid/wildcard-territory.json +10 -0
  68. package/fixtures/verify-request/valid/amazon.json +10 -0
  69. package/fixtures/verify-request/valid/web-no-product-line.json +8 -0
  70. package/fixtures/verify-response/invalid/authorized-missing-authorization-id.json +12 -0
  71. package/fixtures/verify-response/invalid/missing-observed.json +12 -0
  72. package/fixtures/verify-response/invalid/missing-signature.json +9 -0
  73. package/fixtures/verify-response/invalid/missing-valid-until.json +12 -0
  74. package/fixtures/verify-response/invalid/observed-without-last-seen.json +13 -0
  75. package/fixtures/verify-response/invalid/unknown-status.json +13 -0
  76. package/fixtures/verify-response/invalid/unlisted-observed.json +13 -0
  77. package/fixtures/verify-response/invalid/unlisted-with-authorization-id.json +12 -0
  78. package/fixtures/verify-response/invalid/unlisted-with-reason.json +12 -0
  79. package/fixtures/verify-response/invalid/valid-until-before-checked.json +13 -0
  80. package/fixtures/verify-response/invalid/valid-until-over-24h.json +13 -0
  81. package/fixtures/verify-response/invalid/with-tier.json +14 -0
  82. package/fixtures/verify-response/valid/authorized-observed.json +15 -0
  83. package/fixtures/verify-response/valid/authorized.json +13 -0
  84. package/fixtures/verify-response/valid/brand-unverified-no-reason.json +11 -0
  85. package/fixtures/verify-response/valid/brand-unverified-reason.json +12 -0
  86. package/fixtures/verify-response/valid/disputed.json +13 -0
  87. package/fixtures/verify-response/valid/expired.json +13 -0
  88. package/fixtures/verify-response/valid/unlisted.json +11 -0
  89. package/fixtures/verify-response/valid/with-signal.json +19 -0
  90. package/package.json +76 -0
  91. package/schemas/common.json +170 -0
  92. package/schemas/file-full.json +23 -0
  93. package/schemas/file-pointer.json +14 -0
  94. package/schemas/file-private.json +14 -0
  95. package/schemas/file.json +13 -0
  96. package/schemas/verify-request.json +18 -0
  97. package/schemas/verify-response.json +61 -0
  98. package/spec/spec-v0.1.md +282 -0
@@ -0,0 +1,15 @@
1
+ {
2
+ "status": "authorized",
3
+ "authorization_id": "auth_01J9X2",
4
+ "expires": "2026-12-22T00:00:00Z",
5
+ "checked": "2026-09-23T14:02:11Z",
6
+ "valid_until": "2026-09-24T14:02:11Z",
7
+ "observed": {
8
+ "last_seen": "2026-09-20T00:00:00Z"
9
+ },
10
+ "signals": [],
11
+ "signature": {
12
+ "kid": "ar-2026-09",
13
+ "jws": "eyJhbGciOiJFZERTQSIsImtpZCI6ImFyLTIwMjYtMDkifQ..c2lnbmF0dXJlLXBsYWNlaG9sZGVy"
14
+ }
15
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "status": "authorized",
3
+ "authorization_id": "auth_01J9X2",
4
+ "expires": "2026-12-22T00:00:00Z",
5
+ "checked": "2026-09-23T14:02:11Z",
6
+ "valid_until": "2026-09-24T14:02:11Z",
7
+ "observed": null,
8
+ "signals": [],
9
+ "signature": {
10
+ "kid": "ar-2026-09",
11
+ "jws": "eyJhbGciOiJFZERTQSIsImtpZCI6ImFyLTIwMjYtMDkifQ..c2lnbmF0dXJlLXBsYWNlaG9sZGVy"
12
+ }
13
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "status": "brand_unverified",
3
+ "checked": "2026-09-23T14:02:11Z",
4
+ "valid_until": "2026-09-24T14:02:11Z",
5
+ "observed": null,
6
+ "signals": [],
7
+ "signature": {
8
+ "kid": "ar-2026-09",
9
+ "jws": "eyJhbGciOiJFZERTQSIsImtpZCI6ImFyLTIwMjYtMDkifQ..c2lnbmF0dXJlLXBsYWNlaG9sZGVy"
10
+ }
11
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "status": "brand_unverified",
3
+ "checked": "2026-09-23T14:02:11Z",
4
+ "valid_until": "2026-09-24T14:02:11Z",
5
+ "observed": null,
6
+ "signals": [],
7
+ "signature": {
8
+ "kid": "ar-2026-09",
9
+ "jws": "eyJhbGciOiJFZERTQSIsImtpZCI6ImFyLTIwMjYtMDkifQ..c2lnbmF0dXJlLXBsYWNlaG9sZGVy"
10
+ },
11
+ "reason": "domain_unlinked"
12
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "status": "disputed",
3
+ "authorization_id": "auth_01J9X2",
4
+ "expires": "2026-12-22T00:00:00Z",
5
+ "checked": "2026-09-23T14:02:11Z",
6
+ "valid_until": "2026-09-24T14:02:11Z",
7
+ "observed": null,
8
+ "signals": [],
9
+ "signature": {
10
+ "kid": "ar-2026-09",
11
+ "jws": "eyJhbGciOiJFZERTQSIsImtpZCI6ImFyLTIwMjYtMDkifQ..c2lnbmF0dXJlLXBsYWNlaG9sZGVy"
12
+ }
13
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "status": "expired",
3
+ "authorization_id": "auth_01J9X2",
4
+ "expires": "2026-09-01T00:00:00Z",
5
+ "checked": "2026-09-23T14:02:11Z",
6
+ "valid_until": "2026-09-24T14:02:11Z",
7
+ "observed": null,
8
+ "signals": [],
9
+ "signature": {
10
+ "kid": "ar-2026-09",
11
+ "jws": "eyJhbGciOiJFZERTQSIsImtpZCI6ImFyLTIwMjYtMDkifQ..c2lnbmF0dXJlLXBsYWNlaG9sZGVy"
12
+ }
13
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "status": "unlisted",
3
+ "checked": "2026-09-23T14:02:11Z",
4
+ "valid_until": "2026-09-24T14:02:11Z",
5
+ "observed": null,
6
+ "signals": [],
7
+ "signature": {
8
+ "kid": "ar-2026-09",
9
+ "jws": "eyJhbGciOiJFZERTQSIsImtpZCI6ImFyLTIwMjYtMDkifQ..c2lnbmF0dXJlLXBsYWNlaG9sZGVy"
10
+ }
11
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "status": "authorized",
3
+ "authorization_id": "auth_01J9X2",
4
+ "expires": "2026-12-22T00:00:00Z",
5
+ "checked": "2026-09-23T14:02:11Z",
6
+ "valid_until": "2026-09-24T14:02:11Z",
7
+ "observed": null,
8
+ "signals": [
9
+ {
10
+ "type": "account_name_changed",
11
+ "observed": "2026-09-20T00:00:00Z",
12
+ "detail": "Storefront name changed"
13
+ }
14
+ ],
15
+ "signature": {
16
+ "kid": "ar-2026-09",
17
+ "jws": "eyJhbGciOiJFZERTQSIsImtpZCI6ImFyLTIwMjYtMDkifQ..c2lnbmF0dXJlLXBsYWNlaG9sZGVy"
18
+ }
19
+ }
package/package.json ADDED
@@ -0,0 +1,76 @@
1
+ {
2
+ "name": "@authorizedretailers/spec",
3
+ "version": "0.1.0",
4
+ "description": "Authorized Retailers v0.1: JSON Schemas, types, validator, identifier matching, RFC 8785 canonicalization and detached-JWS reference verifier",
5
+ "license": "Apache-2.0 AND CC-BY-4.0",
6
+ "author": "Authorized Retailers",
7
+ "homepage": "https://authorizedretailers.ai/spec",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/authorizedretailers/spec.git"
11
+ },
12
+ "bugs": "https://github.com/authorizedretailers/spec/issues",
13
+ "keywords": [
14
+ "authorized-retailers",
15
+ "authorized-retailers-json",
16
+ "ai-agents",
17
+ "agentic-commerce",
18
+ "brand-protection",
19
+ "json-schema",
20
+ "jws",
21
+ "verification"
22
+ ],
23
+ "type": "module",
24
+ "sideEffects": false,
25
+ "engines": {
26
+ "node": ">=20"
27
+ },
28
+ "exports": {
29
+ ".": {
30
+ "types": "./dist/index.d.ts",
31
+ "default": "./dist/index.js"
32
+ },
33
+ "./jws": {
34
+ "types": "./dist/jws.d.ts",
35
+ "default": "./dist/jws.js"
36
+ },
37
+ "./jcs": {
38
+ "types": "./dist/jcs.d.ts",
39
+ "default": "./dist/jcs.js"
40
+ },
41
+ "./schemas/*": "./schemas/*",
42
+ "./fixtures/*": "./fixtures/*",
43
+ "./spec.md": "./spec/spec-v0.1.md",
44
+ "./package.json": "./package.json"
45
+ },
46
+ "files": [
47
+ "dist",
48
+ "schemas",
49
+ "fixtures",
50
+ "spec",
51
+ "LICENSE",
52
+ "LICENSE-SPEC"
53
+ ],
54
+ "publishConfig": {
55
+ "access": "public",
56
+ "provenance": true
57
+ },
58
+ "scripts": {
59
+ "build": "rm -rf dist && tsc -p tsconfig.build.json",
60
+ "schemas": "node scripts/embed-schemas.mjs",
61
+ "test": "vitest run",
62
+ "test:dist": "npm run build && node test/dist-smoke.mjs",
63
+ "typecheck": "tsc -p .",
64
+ "check:package": "npm run build && attw --pack . --profile esm-only --exclude-entrypoints ./spec.md",
65
+ "prepublishOnly": "npm run typecheck && npm test && npm run test:dist"
66
+ },
67
+ "dependencies": {
68
+ "@cfworker/json-schema": "^4.1.1"
69
+ },
70
+ "devDependencies": {
71
+ "@arethetypeswrong/cli": "^0.18.5",
72
+ "@types/node": "^22.0.0",
73
+ "typescript": "^5.9.0",
74
+ "vitest": "^4.1.0"
75
+ }
76
+ }
@@ -0,0 +1,170 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://authorizedretailers.ai/schemas/0.1/common.json",
4
+ "title": "Authorized Retailers v0.1 shared definitions",
5
+ "$defs": {
6
+ "specVersion": { "const": "authorized-retailers/0.1" },
7
+ "timestamp": {
8
+ "description": "RFC 3339 timestamp in UTC with a Z suffix.",
9
+ "type": "string",
10
+ "format": "date-time",
11
+ "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\\.[0-9]{1,9})?Z$"
12
+ },
13
+ "domain": {
14
+ "description": "A bare hostname: no scheme, port, path or trailing dot. Compared case-insensitively.",
15
+ "type": "string",
16
+ "maxLength": 253,
17
+ "pattern": "^(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?\\.)+(?:[A-Za-z]{2,63}|xn--[A-Za-z0-9-]{1,59})$"
18
+ },
19
+ "countryCode": {
20
+ "description": "ISO 3166-1 alpha-2, uppercase.",
21
+ "type": "string",
22
+ "pattern": "^[A-Z]{2}$"
23
+ },
24
+ "httpsUrl": {
25
+ "type": "string",
26
+ "format": "uri",
27
+ "pattern": "^https://",
28
+ "maxLength": 2048
29
+ },
30
+ "id": {
31
+ "type": "string",
32
+ "pattern": "^[A-Za-z0-9_-]{1,64}$"
33
+ },
34
+ "nonEmptyString": { "type": "string", "minLength": 1, "maxLength": 256 },
35
+ "brand": {
36
+ "type": "object",
37
+ "required": ["name", "domain"],
38
+ "additionalProperties": false,
39
+ "properties": {
40
+ "name": { "$ref": "#/$defs/nonEmptyString" },
41
+ "domain": { "$ref": "#/$defs/domain" }
42
+ }
43
+ },
44
+ "sellerId": {
45
+ "type": "string",
46
+ "pattern": "^\\S{1,128}$"
47
+ },
48
+ "marketplaceChannel": {
49
+ "type": "object",
50
+ "required": ["type", "marketplace", "seller_id"],
51
+ "additionalProperties": false,
52
+ "properties": {
53
+ "type": { "enum": ["amazon", "walmart", "ebay"] },
54
+ "marketplace": { "$ref": "#/$defs/countryCode" },
55
+ "seller_id": { "$ref": "#/$defs/sellerId" }
56
+ }
57
+ },
58
+ "webChannel": {
59
+ "type": "object",
60
+ "required": ["type", "domain"],
61
+ "additionalProperties": false,
62
+ "properties": {
63
+ "type": { "const": "web" },
64
+ "domain": { "$ref": "#/$defs/domain" }
65
+ }
66
+ },
67
+ "physicalChannel": {
68
+ "type": "object",
69
+ "required": ["type", "address", "country"],
70
+ "additionalProperties": false,
71
+ "properties": {
72
+ "type": { "const": "physical" },
73
+ "address": { "type": "string", "minLength": 1, "maxLength": 512 },
74
+ "country": { "$ref": "#/$defs/countryCode" }
75
+ }
76
+ },
77
+ "verifiableChannel": {
78
+ "description": "A channel an agent can see and match on (section 6). Excludes physical.",
79
+ "oneOf": [
80
+ { "$ref": "#/$defs/marketplaceChannel" },
81
+ { "$ref": "#/$defs/webChannel" }
82
+ ]
83
+ },
84
+ "channel": {
85
+ "oneOf": [
86
+ { "$ref": "#/$defs/marketplaceChannel" },
87
+ { "$ref": "#/$defs/webChannel" },
88
+ { "$ref": "#/$defs/physicalChannel" }
89
+ ]
90
+ },
91
+ "party": {
92
+ "type": "object",
93
+ "required": ["name"],
94
+ "additionalProperties": false,
95
+ "properties": {
96
+ "name": { "$ref": "#/$defs/nonEmptyString" },
97
+ "entity_id": { "$ref": "#/$defs/id" }
98
+ }
99
+ },
100
+ "territories": {
101
+ "description": "ISO 3166-1 alpha-2 codes, or exactly [\"*\"] for worldwide.",
102
+ "type": "array",
103
+ "minItems": 1,
104
+ "uniqueItems": true,
105
+ "anyOf": [
106
+ { "const": ["*"] },
107
+ { "items": { "$ref": "#/$defs/countryCode" } }
108
+ ]
109
+ },
110
+ "productLine": {
111
+ "type": "string",
112
+ "minLength": 1,
113
+ "maxLength": 64,
114
+ "pattern": "^\\S(.*\\S)?$"
115
+ },
116
+ "productLines": {
117
+ "description": "Named product lines, or exactly [\"all\"].",
118
+ "type": "array",
119
+ "minItems": 1,
120
+ "uniqueItems": true,
121
+ "anyOf": [
122
+ { "const": ["all"] },
123
+ { "items": { "allOf": [{ "$ref": "#/$defs/productLine" }, { "not": { "const": "all" } }] } }
124
+ ]
125
+ },
126
+ "scope": {
127
+ "type": "object",
128
+ "required": ["territories", "product_lines"],
129
+ "additionalProperties": false,
130
+ "properties": {
131
+ "territories": { "$ref": "#/$defs/territories" },
132
+ "product_lines": { "$ref": "#/$defs/productLines" }
133
+ }
134
+ },
135
+ "authorization": {
136
+ "type": "object",
137
+ "required": ["id", "retailer", "channels", "scope", "expires"],
138
+ "additionalProperties": false,
139
+ "properties": {
140
+ "id": { "$ref": "#/$defs/id" },
141
+ "retailer": { "$ref": "#/$defs/party" },
142
+ "channels": {
143
+ "description": "Section 6: every authorization MUST name at least one channel identifier.",
144
+ "type": "array",
145
+ "minItems": 1,
146
+ "items": { "$ref": "#/$defs/channel" }
147
+ },
148
+ "scope": { "$ref": "#/$defs/scope" },
149
+ "proposed_by": {
150
+ "description": "The distributor that proposed this authorization, if any (section 3).",
151
+ "oneOf": [{ "type": "null" }, { "$ref": "#/$defs/party" }]
152
+ },
153
+ "expires": { "$ref": "#/$defs/timestamp" }
154
+ }
155
+ },
156
+ "signature": {
157
+ "type": "object",
158
+ "required": ["kid", "jws"],
159
+ "additionalProperties": false,
160
+ "properties": {
161
+ "kid": { "type": "string", "pattern": "^[A-Za-z0-9._-]{1,64}$" },
162
+ "jws": {
163
+ "description": "Detached compact JWS: header..signature (empty payload segment).",
164
+ "type": "string",
165
+ "pattern": "^[A-Za-z0-9_-]+\\.\\.[A-Za-z0-9_-]+$"
166
+ }
167
+ }
168
+ }
169
+ }
170
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://authorizedretailers.ai/schemas/0.1/file-full.json",
4
+ "title": "authorized-retailers.json, full form",
5
+ "type": "object",
6
+ "required": ["spec", "form", "brand", "issued", "expires", "authorizations"],
7
+ "additionalProperties": false,
8
+ "properties": {
9
+ "spec": { "$ref": "common.json#/$defs/specVersion" },
10
+ "form": { "const": "full" },
11
+ "brand": { "$ref": "common.json#/$defs/brand" },
12
+ "issued": { "$ref": "common.json#/$defs/timestamp" },
13
+ "expires": { "$ref": "common.json#/$defs/timestamp" },
14
+ "authorizations": {
15
+ "type": "array",
16
+ "items": { "$ref": "common.json#/$defs/authorization" }
17
+ },
18
+ "signature": {
19
+ "description": "Optional in the schema: an unsigned file is well-formed but does not count (section 5).",
20
+ "$ref": "common.json#/$defs/signature"
21
+ }
22
+ }
23
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://authorizedretailers.ai/schemas/0.1/file-pointer.json",
4
+ "title": "authorized-retailers.json, pointer form",
5
+ "type": "object",
6
+ "required": ["spec", "form", "brand", "list"],
7
+ "additionalProperties": false,
8
+ "properties": {
9
+ "spec": { "$ref": "common.json#/$defs/specVersion" },
10
+ "form": { "const": "pointer" },
11
+ "brand": { "$ref": "common.json#/$defs/brand" },
12
+ "list": { "$ref": "common.json#/$defs/httpsUrl" }
13
+ }
14
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://authorizedretailers.ai/schemas/0.1/file-private.json",
4
+ "title": "authorized-retailers.json, private form",
5
+ "type": "object",
6
+ "required": ["spec", "form", "brand", "verify"],
7
+ "additionalProperties": false,
8
+ "properties": {
9
+ "spec": { "$ref": "common.json#/$defs/specVersion" },
10
+ "form": { "const": "private" },
11
+ "brand": { "$ref": "common.json#/$defs/brand" },
12
+ "verify": { "$ref": "common.json#/$defs/httpsUrl" }
13
+ }
14
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://authorizedretailers.ai/schemas/0.1/file.json",
4
+ "title": "authorized-retailers.json, any form",
5
+ "type": "object",
6
+ "required": ["form"],
7
+ "properties": { "form": { "enum": ["full", "pointer", "private"] } },
8
+ "allOf": [
9
+ { "if": { "properties": { "form": { "const": "full" } } }, "then": { "$ref": "file-full.json" } },
10
+ { "if": { "properties": { "form": { "const": "pointer" } } }, "then": { "$ref": "file-pointer.json" } },
11
+ { "if": { "properties": { "form": { "const": "private" } } }, "then": { "$ref": "file-private.json" } }
12
+ ]
13
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://authorizedretailers.ai/schemas/0.1/verify-request.json",
4
+ "title": "POST /v0/verify request (section 9)",
5
+ "description": "Canonical form. Registries normalize case and whitespace before validating (see normalizeVerifyRequest).",
6
+ "type": "object",
7
+ "required": ["brand_domain", "channel", "territory"],
8
+ "additionalProperties": false,
9
+ "properties": {
10
+ "brand_domain": { "$ref": "common.json#/$defs/domain" },
11
+ "channel": { "$ref": "common.json#/$defs/verifiableChannel" },
12
+ "territory": { "$ref": "common.json#/$defs/countryCode" },
13
+ "product_line": {
14
+ "description": "Defaults to \"all\" when omitted.",
15
+ "$ref": "common.json#/$defs/productLine"
16
+ }
17
+ }
18
+ }
@@ -0,0 +1,61 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://authorizedretailers.ai/schemas/0.1/verify-response.json",
4
+ "title": "POST /v0/verify response (section 9)",
5
+ "type": "object",
6
+ "required": ["status", "checked", "valid_until", "observed", "signals", "signature"],
7
+ "additionalProperties": false,
8
+ "properties": {
9
+ "status": { "enum": ["authorized", "unlisted", "expired", "brand_unverified", "disputed"] },
10
+ "reason": { "enum": ["not_registered", "domain_unlinked", "verification_lapsed"] },
11
+ "authorization_id": { "$ref": "common.json#/$defs/id" },
12
+ "expires": { "$ref": "common.json#/$defs/timestamp" },
13
+ "checked": { "$ref": "common.json#/$defs/timestamp" },
14
+ "valid_until": { "$ref": "common.json#/$defs/timestamp" },
15
+ "observed": {
16
+ "description": "Section 7: when the registry last saw this seller selling on the channel, within 30 days; otherwise null",
17
+ "oneOf": [
18
+ { "type": "null" },
19
+ {
20
+ "type": "object",
21
+ "required": ["last_seen"],
22
+ "additionalProperties": false,
23
+ "properties": { "last_seen": { "$ref": "common.json#/$defs/timestamp" } }
24
+ }
25
+ ]
26
+ },
27
+ "signals": {
28
+ "type": "array",
29
+ "items": {
30
+ "type": "object",
31
+ "required": ["type", "observed"],
32
+ "additionalProperties": false,
33
+ "properties": {
34
+ "type": { "type": "string", "pattern": "^[a-z][a-z0-9_]{0,63}$" },
35
+ "observed": { "$ref": "common.json#/$defs/timestamp" },
36
+ "detail": { "type": "string", "maxLength": 1024 }
37
+ }
38
+ }
39
+ },
40
+ "signature": { "$ref": "common.json#/$defs/signature" }
41
+ },
42
+ "allOf": [
43
+ {
44
+ "if": { "properties": { "status": { "const": "brand_unverified" } } },
45
+ "then": { "not": { "anyOf": [{ "required": ["authorization_id"] }, { "required": ["expires"] }] } },
46
+ "else": { "not": { "required": ["reason"] } }
47
+ },
48
+ {
49
+ "if": { "not": { "properties": { "status": { "const": "authorized" } } } },
50
+ "then": { "properties": { "observed": { "const": null } } }
51
+ },
52
+ {
53
+ "if": { "properties": { "status": { "enum": ["authorized", "expired", "disputed"] } } },
54
+ "then": { "required": ["authorization_id", "expires"] }
55
+ },
56
+ {
57
+ "if": { "properties": { "status": { "const": "unlisted" } } },
58
+ "then": { "not": { "anyOf": [{ "required": ["authorization_id"] }, { "required": ["expires"] }] } }
59
+ }
60
+ ]
61
+ }