@authorizedretailers/spec 0.1.0 → 0.2.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 (209) hide show
  1. package/README.md +66 -47
  2. package/dist/constants.d.ts +25 -6
  3. package/dist/constants.js +41 -7
  4. package/dist/identity.d.ts +29 -14
  5. package/dist/identity.js +79 -39
  6. package/dist/index.d.ts +2 -0
  7. package/dist/index.js +2 -0
  8. package/dist/jws.d.ts +36 -5
  9. package/dist/jws.js +48 -14
  10. package/dist/match.d.ts +21 -0
  11. package/dist/match.js +89 -0
  12. package/dist/product.d.ts +34 -0
  13. package/dist/product.js +75 -0
  14. package/dist/published.d.ts +14 -8
  15. package/dist/published.js +32 -10
  16. package/dist/schemas.d.ts +366 -88
  17. package/dist/schemas.js +802 -178
  18. package/dist/types.d.ts +121 -47
  19. package/dist/types.js +2 -2
  20. package/dist/validate.d.ts +24 -10
  21. package/dist/validate.js +302 -82
  22. package/fixtures/list/invalid/list-all-mixed.json +53 -0
  23. package/fixtures/list/invalid/list-amazon-missing-seller-id.json +51 -0
  24. package/fixtures/list/invalid/list-amazon-on-walmart-domain.json +52 -0
  25. package/fixtures/{file/invalid/full-attached-jws.json → list/invalid/list-attached-jws.json} +14 -12
  26. package/fixtures/list/invalid/list-bad-asin.json +102 -0
  27. package/fixtures/list/invalid/list-bad-gtin.json +102 -0
  28. package/fixtures/list/invalid/list-brand-exclusion-no-catalog.json +57 -0
  29. package/fixtures/list/invalid/list-duplicate-asin.json +102 -0
  30. package/fixtures/{file/invalid/full-duplicate-authorization-id.json → list/invalid/list-duplicate-authorization-id.json} +23 -18
  31. package/fixtures/list/invalid/list-duplicate-gtin.json +102 -0
  32. package/fixtures/list/invalid/list-duplicate-product-id.json +102 -0
  33. package/fixtures/{file/invalid/full-empty-territories.json → list/invalid/list-empty-territories.json} +17 -10
  34. package/fixtures/list/invalid/list-exclude-unknown-product.json +105 -0
  35. package/fixtures/list/invalid/list-expires-field.json +53 -0
  36. package/fixtures/list/invalid/list-extra-property.json +53 -0
  37. package/fixtures/list/invalid/list-generic-web-no-territories.json +39 -0
  38. package/fixtures/list/invalid/list-gtin-11-digits.json +102 -0
  39. package/fixtures/list/invalid/list-impossible-date.json +53 -0
  40. package/fixtures/list/invalid/list-lowercase-territory.json +52 -0
  41. package/fixtures/{file/invalid/full-signature-missing-kid.json → list/invalid/list-marketplace-field.json} +14 -11
  42. package/fixtures/list/invalid/list-marketplace-territory-mismatch.json +52 -0
  43. package/fixtures/list/invalid/list-missing-revocation-id.json +51 -0
  44. package/fixtures/list/invalid/list-missing-scope.json +44 -0
  45. package/fixtures/list/invalid/list-missing-stale-until.json +51 -0
  46. package/fixtures/list/invalid/list-name-only-retailer.json +36 -0
  47. package/fixtures/list/invalid/list-no-channels.json +37 -0
  48. package/fixtures/list/invalid/list-non-utc-timestamp.json +52 -0
  49. package/fixtures/list/invalid/list-not-public-with-authorizations.json +18 -0
  50. package/fixtures/list/invalid/list-not-public-with-catalog.json +18 -0
  51. package/fixtures/list/invalid/list-physical.json +43 -0
  52. package/fixtures/list/invalid/list-product-no-identifier.json +98 -0
  53. package/fixtures/list/invalid/list-scope-no-products.json +49 -0
  54. package/fixtures/{file/valid/full-signed.json → list/invalid/list-single-domain.json} +12 -12
  55. package/fixtures/list/invalid/list-stale-over-24-hours.json +52 -0
  56. package/fixtures/list/invalid/list-territory-uk.json +52 -0
  57. package/fixtures/{file/invalid/full-unknown-channel-type.json → list/invalid/list-unknown-channel-type.json} +18 -12
  58. package/fixtures/list/invalid/list-unknown-line.json +102 -0
  59. package/fixtures/list/invalid/list-unknown-product.json +105 -0
  60. package/fixtures/{file/invalid/full-missing-authorization-expires.json → list/invalid/list-unsigned.json} +12 -9
  61. package/fixtures/list/invalid/list-valid-over-15-minutes.json +52 -0
  62. package/fixtures/{file/invalid/full-web-domain-is-url.json → list/invalid/list-web-domain-is-url.json} +18 -12
  63. package/fixtures/list/invalid/list-web-on-marketplace-domain.json +52 -0
  64. package/fixtures/{file/invalid/full-wildcard-mixed.json → list/invalid/list-wildcard-mixed.json} +17 -10
  65. package/fixtures/list/valid/list-catalog-line-scope.json +102 -0
  66. package/fixtures/list/valid/list-cctld-web.json +39 -0
  67. package/fixtures/list/valid/list-fractional-seconds.json +52 -0
  68. package/fixtures/{file/invalid/full-amazon-missing-seller-id.json → list/valid/list-generic-web-territories.json} +15 -17
  69. package/fixtures/list/valid/list-marketplace-no-territories.json +40 -0
  70. package/fixtures/list/valid/list-no-authorizations.json +18 -0
  71. package/fixtures/list/valid/list-no-catalog.json +52 -0
  72. package/fixtures/list/valid/list-no-expires.json +52 -0
  73. package/fixtures/list/valid/list-not-public.json +17 -0
  74. package/fixtures/list/valid/list-product-scope.json +103 -0
  75. package/fixtures/list/valid/list-proposed-by.json +55 -0
  76. package/fixtures/list/valid/list-with-expires.json +53 -0
  77. package/fixtures/list/valid/list-worldwide.json +52 -0
  78. package/fixtures/manifest.json +609 -154
  79. package/fixtures/match/all-scope-excluded-line.json +194 -0
  80. package/fixtures/match/all-scope-not-in-catalog.json +194 -0
  81. package/fixtures/match/as-of-before-end-date.json +194 -0
  82. package/fixtures/match/brand-exclusion-beats-named-product.json +194 -0
  83. package/fixtures/match/duplicate-asin-authorized-seller.json +192 -0
  84. package/fixtures/match/duplicate-asin-unauthorized-seller.json +191 -0
  85. package/fixtures/match/expired-end-date.json +193 -0
  86. package/fixtures/match/marketplace-territory-default.json +186 -0
  87. package/fixtures/match/marketplace-territory-mismatch.json +187 -0
  88. package/fixtures/match/match-by-channel-key.json +186 -0
  89. package/fixtures/match/product-excluded-by-authorization.json +194 -0
  90. package/fixtures/match/product-line-request.json +186 -0
  91. package/fixtures/match/product-not-in-scope.json +194 -0
  92. package/fixtures/match/seller-authorized-by-gtin.json +194 -0
  93. package/fixtures/match/seller-authorized-for-line.json +194 -0
  94. package/fixtures/match/worldwide-web.json +186 -0
  95. package/fixtures/pointer/invalid/full-form.json +11 -0
  96. package/fixtures/pointer/invalid/pointer-domain-mismatch.json +10 -0
  97. package/fixtures/{file → pointer}/invalid/pointer-http-url.json +2 -1
  98. package/fixtures/pointer/invalid/pointer-missing-verify-token.json +9 -0
  99. package/fixtures/pointer/invalid/pointer-other-host.json +10 -0
  100. package/fixtures/{file/valid/pointer.json → pointer/invalid/pointer-wrong-spec.json} +1 -0
  101. package/fixtures/pointer/invalid/private-form.json +10 -0
  102. package/fixtures/pointer/invalid/unknown-form.json +10 -0
  103. package/fixtures/pointer/valid/pointer-fetched-via-www.json +10 -0
  104. package/fixtures/pointer/valid/pointer.json +10 -0
  105. package/fixtures/revocation-feed/invalid/feed-hashed-entry.json +17 -0
  106. package/fixtures/revocation-feed/invalid/feed-valid-over-15-minutes.json +17 -0
  107. package/fixtures/revocation-feed/valid/feed-empty.json +12 -0
  108. package/fixtures/revocation-feed/valid/feed.json +17 -0
  109. package/fixtures/verify-request/invalid/bad-as-of.json +9 -0
  110. package/fixtures/verify-request/invalid/bad-gtin.json +11 -0
  111. package/fixtures/verify-request/invalid/domain-with-scheme.json +2 -4
  112. package/fixtures/verify-request/{valid/web-no-product-line.json → invalid/generic-web-no-territory.json} +1 -2
  113. package/fixtures/verify-request/invalid/gtin-and-asin.json +12 -0
  114. package/fixtures/verify-request/{valid/amazon.json → invalid/marketplace-field.json} +1 -3
  115. package/fixtures/verify-request/invalid/missing-channel.json +1 -3
  116. package/fixtures/verify-request/invalid/physical-channel.json +1 -3
  117. package/fixtures/verify-request/invalid/retailer-name-only.json +0 -2
  118. package/fixtures/verify-request/invalid/territory-uk.json +9 -0
  119. package/fixtures/verify-request/invalid/wildcard-territory.json +2 -3
  120. package/fixtures/verify-request/valid/as-of-datetime.json +9 -0
  121. package/fixtures/verify-request/valid/full.json +13 -0
  122. package/fixtures/verify-request/valid/gtin.json +11 -0
  123. package/fixtures/verify-request/valid/minimal-marketplace.json +8 -0
  124. package/fixtures/verify-request/valid/web-cctld-no-territory.json +7 -0
  125. package/fixtures/verify-request/valid/web-generic-with-territory.json +9 -0
  126. package/fixtures/verify-response/invalid/authorized-missing-revocation-id.json +18 -0
  127. package/fixtures/verify-response/invalid/authorized-with-reason.json +20 -0
  128. package/fixtures/verify-response/invalid/brand-unverified.json +13 -0
  129. package/fixtures/verify-response/invalid/expired-without-expires.json +18 -0
  130. package/fixtures/verify-response/invalid/missing-observed.json +11 -5
  131. package/fixtures/verify-response/invalid/missing-signature.json +9 -3
  132. package/fixtures/verify-response/invalid/missing-stale-until.json +18 -0
  133. package/fixtures/verify-response/invalid/not-in-catalog-with-id.json +17 -0
  134. package/fixtures/verify-response/invalid/not-registered-with-unlisted-reason.json +13 -0
  135. package/fixtures/verify-response/invalid/stale-until-over-24-hours.json +19 -0
  136. package/fixtures/verify-response/invalid/unlisted-observed.json +5 -4
  137. package/fixtures/verify-response/invalid/unlisted-with-authorization-id.json +5 -4
  138. package/fixtures/verify-response/invalid/unlisted-with-not-registered-reason.json +13 -0
  139. package/fixtures/verify-response/invalid/unlisted-with-revocation-id.json +13 -0
  140. package/fixtures/verify-response/invalid/valid-until-before-checked.json +11 -5
  141. package/fixtures/verify-response/invalid/valid-until-over-15-minutes.json +19 -0
  142. package/fixtures/verify-response/invalid/with-stale-flag.json +20 -0
  143. package/fixtures/verify-response/invalid/with-tier.json +11 -5
  144. package/fixtures/verify-response/valid/authorized-no-product.json +14 -0
  145. package/fixtures/verify-response/valid/authorized-not-in-catalog.json +22 -0
  146. package/fixtures/verify-response/valid/authorized-observed.json +11 -5
  147. package/fixtures/verify-response/valid/authorized-private-product.json +17 -0
  148. package/fixtures/verify-response/valid/authorized-with-end-date.json +20 -0
  149. package/fixtures/verify-response/valid/authorized.json +11 -5
  150. package/fixtures/verify-response/valid/disputed.json +10 -5
  151. package/fixtures/verify-response/valid/expired.json +12 -6
  152. package/fixtures/verify-response/valid/not-registered-no-reason.json +12 -0
  153. package/fixtures/verify-response/valid/not-registered-reason.json +13 -0
  154. package/fixtures/verify-response/valid/unlisted-product-excluded.json +18 -0
  155. package/fixtures/verify-response/valid/unlisted-product-not-in-catalog.json +16 -0
  156. package/fixtures/verify-response/valid/unlisted-territory-mismatch.json +13 -0
  157. package/fixtures/verify-response/valid/unlisted.json +5 -4
  158. package/fixtures/verify-response/valid/with-as-of.json +20 -0
  159. package/fixtures/verify-response/valid/with-signal.json +11 -5
  160. package/package.json +5 -4
  161. package/schemas/{common.json → 0.1/common.json} +3 -2
  162. package/schemas/0.2/common.json +761 -0
  163. package/schemas/0.2/list.json +87 -0
  164. package/schemas/0.2/pointer.json +33 -0
  165. package/schemas/0.2/revocation-feed.json +55 -0
  166. package/schemas/0.2/verify-request.json +65 -0
  167. package/schemas/0.2/verify-response.json +284 -0
  168. package/spec/spec-v0.1.md +11 -3
  169. package/spec/spec-v0.2.md +531 -0
  170. package/fixtures/file/invalid/full-all-mixed.json +0 -47
  171. package/fixtures/file/invalid/full-authorization-expires-after-file.json +0 -46
  172. package/fixtures/file/invalid/full-expires-before-issued.json +0 -46
  173. package/fixtures/file/invalid/full-expiry-over-180-days.json +0 -46
  174. package/fixtures/file/invalid/full-extra-property.json +0 -47
  175. package/fixtures/file/invalid/full-impossible-date.json +0 -46
  176. package/fixtures/file/invalid/full-lowercase-territory.json +0 -45
  177. package/fixtures/file/invalid/full-missing-file-expires.json +0 -45
  178. package/fixtures/file/invalid/full-missing-product-lines.json +0 -43
  179. package/fixtures/file/invalid/full-missing-scope.json +0 -37
  180. package/fixtures/file/invalid/full-missing-territories.json +0 -42
  181. package/fixtures/file/invalid/full-name-only-retailer.json +0 -30
  182. package/fixtures/file/invalid/full-no-channels.json +0 -31
  183. package/fixtures/file/invalid/full-non-utc-timestamp.json +0 -46
  184. package/fixtures/file/invalid/full-physical-missing-country.json +0 -50
  185. package/fixtures/file/invalid/full-web-missing-domain.json +0 -45
  186. package/fixtures/file/invalid/full-wrong-spec.json +0 -46
  187. package/fixtures/file/invalid/private-missing-verify.json +0 -8
  188. package/fixtures/file/invalid/private-with-authorizations.json +0 -45
  189. package/fixtures/file/invalid/unknown-form.json +0 -9
  190. package/fixtures/file/valid/full-fractional-seconds.json +0 -46
  191. package/fixtures/file/valid/full-max-expiry.json +0 -46
  192. package/fixtures/file/valid/full-no-authorizations.json +0 -11
  193. package/fixtures/file/valid/full-unsigned-handwritten.json +0 -46
  194. package/fixtures/file/valid/full-worldwide-physical-proposed.json +0 -82
  195. package/fixtures/file/valid/private.json +0 -9
  196. package/fixtures/verify-response/invalid/authorized-missing-authorization-id.json +0 -12
  197. package/fixtures/verify-response/invalid/missing-valid-until.json +0 -12
  198. package/fixtures/verify-response/invalid/observed-without-last-seen.json +0 -13
  199. package/fixtures/verify-response/invalid/unknown-status.json +0 -13
  200. package/fixtures/verify-response/invalid/unlisted-with-reason.json +0 -12
  201. package/fixtures/verify-response/invalid/valid-until-over-24h.json +0 -13
  202. package/fixtures/verify-response/valid/brand-unverified-no-reason.json +0 -11
  203. package/fixtures/verify-response/valid/brand-unverified-reason.json +0 -12
  204. /package/schemas/{file-full.json → 0.1/file-full.json} +0 -0
  205. /package/schemas/{file-pointer.json → 0.1/file-pointer.json} +0 -0
  206. /package/schemas/{file-private.json → 0.1/file-private.json} +0 -0
  207. /package/schemas/{file.json → 0.1/file.json} +0 -0
  208. /package/schemas/{verify-request.json → 0.1/verify-request.json} +0 -0
  209. /package/schemas/{verify-response.json → 0.1/verify-response.json} +0 -0
@@ -0,0 +1,87 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://authorizedretailers.ai/schemas/0.2/list.json",
4
+ "title": "Signed list (section 5.2)",
5
+ "type": "object",
6
+ "required": [
7
+ "spec",
8
+ "brand",
9
+ "public",
10
+ "issued",
11
+ "valid_until",
12
+ "stale_until",
13
+ "signature"
14
+ ],
15
+ "additionalProperties": false,
16
+ "properties": {
17
+ "spec": {
18
+ "$ref": "common.json#/$defs/specVersion"
19
+ },
20
+ "brand": {
21
+ "$ref": "common.json#/$defs/listBrand"
22
+ },
23
+ "public": {
24
+ "type": "boolean"
25
+ },
26
+ "issued": {
27
+ "$ref": "common.json#/$defs/timestamp"
28
+ },
29
+ "valid_until": {
30
+ "$ref": "common.json#/$defs/timestamp"
31
+ },
32
+ "stale_until": {
33
+ "$ref": "common.json#/$defs/timestamp"
34
+ },
35
+ "catalog": {
36
+ "type": "array",
37
+ "items": {
38
+ "$ref": "common.json#/$defs/product"
39
+ }
40
+ },
41
+ "exclusions": {
42
+ "$ref": "common.json#/$defs/exclusions"
43
+ },
44
+ "authorizations": {
45
+ "type": "array",
46
+ "items": {
47
+ "$ref": "common.json#/$defs/authorization"
48
+ }
49
+ },
50
+ "signature": {
51
+ "$ref": "common.json#/$defs/signature"
52
+ }
53
+ },
54
+ "if": {
55
+ "properties": {
56
+ "public": {
57
+ "const": true
58
+ }
59
+ }
60
+ },
61
+ "then": {
62
+ "required": [
63
+ "authorizations"
64
+ ]
65
+ },
66
+ "else": {
67
+ "not": {
68
+ "anyOf": [
69
+ {
70
+ "required": [
71
+ "authorizations"
72
+ ]
73
+ },
74
+ {
75
+ "required": [
76
+ "catalog"
77
+ ]
78
+ },
79
+ {
80
+ "required": [
81
+ "exclusions"
82
+ ]
83
+ }
84
+ ]
85
+ }
86
+ }
87
+ }
@@ -0,0 +1,33 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://authorizedretailers.ai/schemas/0.2/pointer.json",
4
+ "title": "authorized-retailers.json pointer (section 5.1)",
5
+ "type": "object",
6
+ "required": [
7
+ "spec",
8
+ "form",
9
+ "brand",
10
+ "verify_token",
11
+ "list"
12
+ ],
13
+ "additionalProperties": false,
14
+ "properties": {
15
+ "spec": {
16
+ "$ref": "common.json#/$defs/specVersion"
17
+ },
18
+ "form": {
19
+ "const": "pointer"
20
+ },
21
+ "brand": {
22
+ "$ref": "common.json#/$defs/brand"
23
+ },
24
+ "verify_token": {
25
+ "description": "The domain's public verification token (section 4).",
26
+ "type": "string",
27
+ "pattern": "^[A-Za-z0-9_-]{16,128}$"
28
+ },
29
+ "list": {
30
+ "$ref": "common.json#/$defs/registryUrl"
31
+ }
32
+ }
33
+ }
@@ -0,0 +1,55 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://authorizedretailers.ai/schemas/0.2/revocation-feed.json",
4
+ "title": "Revocation feed (section 10.3)",
5
+ "type": "object",
6
+ "required": [
7
+ "spec",
8
+ "feed",
9
+ "issued",
10
+ "valid_until",
11
+ "stale_until",
12
+ "entries",
13
+ "signature"
14
+ ],
15
+ "additionalProperties": false,
16
+ "properties": {
17
+ "spec": {
18
+ "$ref": "common.json#/$defs/specVersion"
19
+ },
20
+ "feed": {
21
+ "const": "revocations"
22
+ },
23
+ "issued": {
24
+ "$ref": "common.json#/$defs/timestamp"
25
+ },
26
+ "valid_until": {
27
+ "$ref": "common.json#/$defs/timestamp"
28
+ },
29
+ "stale_until": {
30
+ "$ref": "common.json#/$defs/timestamp"
31
+ },
32
+ "entries": {
33
+ "type": "array",
34
+ "items": {
35
+ "type": "object",
36
+ "required": [
37
+ "revocation_id",
38
+ "revoked"
39
+ ],
40
+ "additionalProperties": false,
41
+ "properties": {
42
+ "revocation_id": {
43
+ "$ref": "common.json#/$defs/revocationId"
44
+ },
45
+ "revoked": {
46
+ "$ref": "common.json#/$defs/timestamp"
47
+ }
48
+ }
49
+ }
50
+ },
51
+ "signature": {
52
+ "$ref": "common.json#/$defs/signature"
53
+ }
54
+ }
55
+ }
@@ -0,0 +1,65 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://authorizedretailers.ai/schemas/0.2/verify-request.json",
4
+ "title": "POST /v0/verify request (section 9)",
5
+ "description": "Canonical form. Call normalizeVerifyRequest on raw input first.",
6
+ "type": "object",
7
+ "required": [
8
+ "brand_domain",
9
+ "channel"
10
+ ],
11
+ "additionalProperties": false,
12
+ "properties": {
13
+ "brand_domain": {
14
+ "$ref": "common.json#/$defs/domain"
15
+ },
16
+ "channel": {
17
+ "$ref": "common.json#/$defs/channel"
18
+ },
19
+ "territory": {
20
+ "$ref": "common.json#/$defs/countryCode"
21
+ },
22
+ "product_line": {
23
+ "$ref": "common.json#/$defs/productLine"
24
+ },
25
+ "product": {
26
+ "description": "Exactly one of gtin or asin.",
27
+ "oneOf": [
28
+ {
29
+ "type": "object",
30
+ "required": [
31
+ "gtin"
32
+ ],
33
+ "additionalProperties": false,
34
+ "properties": {
35
+ "gtin": {
36
+ "$ref": "common.json#/$defs/gtin"
37
+ }
38
+ }
39
+ },
40
+ {
41
+ "type": "object",
42
+ "required": [
43
+ "asin"
44
+ ],
45
+ "additionalProperties": false,
46
+ "properties": {
47
+ "asin": {
48
+ "$ref": "common.json#/$defs/asin"
49
+ }
50
+ }
51
+ }
52
+ ]
53
+ },
54
+ "as_of": {
55
+ "anyOf": [
56
+ {
57
+ "$ref": "common.json#/$defs/date"
58
+ },
59
+ {
60
+ "$ref": "common.json#/$defs/timestamp"
61
+ }
62
+ ]
63
+ }
64
+ }
65
+ }
@@ -0,0 +1,284 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://authorizedretailers.ai/schemas/0.2/verify-response.json",
4
+ "title": "POST /v0/verify response (section 9)",
5
+ "type": "object",
6
+ "required": [
7
+ "status",
8
+ "checked",
9
+ "valid_until",
10
+ "stale_until",
11
+ "observed",
12
+ "signals",
13
+ "signature"
14
+ ],
15
+ "additionalProperties": false,
16
+ "properties": {
17
+ "status": {
18
+ "enum": [
19
+ "authorized",
20
+ "unlisted",
21
+ "expired",
22
+ "brand_not_registered",
23
+ "disputed"
24
+ ]
25
+ },
26
+ "reason": {
27
+ "enum": [
28
+ "not_registered",
29
+ "domain_unlinked",
30
+ "verification_lapsed",
31
+ "territory_mismatch",
32
+ "product_excluded",
33
+ "product_not_in_scope",
34
+ "product_not_in_catalog"
35
+ ]
36
+ },
37
+ "authorization_id": {
38
+ "$ref": "common.json#/$defs/id"
39
+ },
40
+ "revocation_id": {
41
+ "$ref": "common.json#/$defs/revocationId"
42
+ },
43
+ "expires": {
44
+ "$ref": "common.json#/$defs/timestamp"
45
+ },
46
+ "checked": {
47
+ "$ref": "common.json#/$defs/timestamp"
48
+ },
49
+ "as_of": {
50
+ "$ref": "common.json#/$defs/timestamp"
51
+ },
52
+ "valid_until": {
53
+ "$ref": "common.json#/$defs/timestamp"
54
+ },
55
+ "stale_until": {
56
+ "$ref": "common.json#/$defs/timestamp"
57
+ },
58
+ "product": {
59
+ "type": "object",
60
+ "required": [
61
+ "in_catalog"
62
+ ],
63
+ "additionalProperties": false,
64
+ "properties": {
65
+ "in_catalog": {
66
+ "type": "boolean"
67
+ },
68
+ "id": {
69
+ "$ref": "common.json#/$defs/id"
70
+ },
71
+ "product_line": {
72
+ "$ref": "common.json#/$defs/productLine"
73
+ }
74
+ },
75
+ "if": {
76
+ "properties": {
77
+ "in_catalog": {
78
+ "const": false
79
+ }
80
+ }
81
+ },
82
+ "then": {
83
+ "not": {
84
+ "anyOf": [
85
+ {
86
+ "required": [
87
+ "id"
88
+ ]
89
+ },
90
+ {
91
+ "required": [
92
+ "product_line"
93
+ ]
94
+ }
95
+ ]
96
+ }
97
+ }
98
+ },
99
+ "observed": {
100
+ "description": "Section 7: when the registry last saw this seller selling on the channel, within 30 days; otherwise null",
101
+ "oneOf": [
102
+ {
103
+ "type": "null"
104
+ },
105
+ {
106
+ "type": "object",
107
+ "required": [
108
+ "last_seen"
109
+ ],
110
+ "additionalProperties": false,
111
+ "properties": {
112
+ "last_seen": {
113
+ "$ref": "common.json#/$defs/timestamp"
114
+ }
115
+ }
116
+ }
117
+ ]
118
+ },
119
+ "signals": {
120
+ "type": "array",
121
+ "items": {
122
+ "type": "object",
123
+ "required": [
124
+ "type",
125
+ "observed"
126
+ ],
127
+ "additionalProperties": false,
128
+ "properties": {
129
+ "type": {
130
+ "type": "string",
131
+ "pattern": "^[a-z][a-z0-9_]{0,63}$"
132
+ },
133
+ "observed": {
134
+ "$ref": "common.json#/$defs/timestamp"
135
+ },
136
+ "detail": {
137
+ "type": "string",
138
+ "maxLength": 1024
139
+ }
140
+ }
141
+ }
142
+ },
143
+ "signature": {
144
+ "$ref": "common.json#/$defs/signature"
145
+ }
146
+ },
147
+ "allOf": [
148
+ {
149
+ "if": {
150
+ "properties": {
151
+ "status": {
152
+ "enum": [
153
+ "authorized",
154
+ "expired",
155
+ "disputed"
156
+ ]
157
+ }
158
+ }
159
+ },
160
+ "then": {
161
+ "required": [
162
+ "authorization_id"
163
+ ]
164
+ },
165
+ "else": {
166
+ "not": {
167
+ "anyOf": [
168
+ {
169
+ "required": [
170
+ "authorization_id"
171
+ ]
172
+ },
173
+ {
174
+ "required": [
175
+ "expires"
176
+ ]
177
+ }
178
+ ]
179
+ }
180
+ }
181
+ },
182
+ {
183
+ "if": {
184
+ "properties": {
185
+ "status": {
186
+ "const": "expired"
187
+ }
188
+ }
189
+ },
190
+ "then": {
191
+ "required": [
192
+ "expires"
193
+ ]
194
+ }
195
+ },
196
+ {
197
+ "if": {
198
+ "properties": {
199
+ "status": {
200
+ "const": "authorized"
201
+ }
202
+ }
203
+ },
204
+ "then": {
205
+ "required": [
206
+ "revocation_id"
207
+ ]
208
+ },
209
+ "else": {
210
+ "properties": {
211
+ "observed": {
212
+ "const": null
213
+ }
214
+ },
215
+ "not": {
216
+ "required": [
217
+ "revocation_id"
218
+ ]
219
+ }
220
+ }
221
+ },
222
+ {
223
+ "if": {
224
+ "properties": {
225
+ "status": {
226
+ "const": "brand_not_registered"
227
+ }
228
+ }
229
+ },
230
+ "then": {
231
+ "properties": {
232
+ "reason": {
233
+ "enum": [
234
+ "not_registered",
235
+ "domain_unlinked",
236
+ "verification_lapsed"
237
+ ]
238
+ }
239
+ }
240
+ }
241
+ },
242
+ {
243
+ "if": {
244
+ "properties": {
245
+ "status": {
246
+ "const": "unlisted"
247
+ }
248
+ }
249
+ },
250
+ "then": {
251
+ "properties": {
252
+ "reason": {
253
+ "enum": [
254
+ "territory_mismatch",
255
+ "product_excluded",
256
+ "product_not_in_scope",
257
+ "product_not_in_catalog"
258
+ ]
259
+ }
260
+ }
261
+ }
262
+ },
263
+ {
264
+ "if": {
265
+ "properties": {
266
+ "status": {
267
+ "enum": [
268
+ "authorized",
269
+ "expired",
270
+ "disputed"
271
+ ]
272
+ }
273
+ }
274
+ },
275
+ "then": {
276
+ "not": {
277
+ "required": [
278
+ "reason"
279
+ ]
280
+ }
281
+ }
282
+ }
283
+ ]
284
+ }
package/spec/spec-v0.1.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Authorized Retailers Specification v0.1
2
2
 
3
- Draft v0.1 · 23 September 2026, updated 25 September 2026
3
+ Draft v0.1 · 23 September 2026, updated 26 September 2026
4
4
  Editor: Ed Jacobs
5
5
 
6
6
  Licensed under [CC BY 4.0](https://github.com/authorizedretailers/spec/blob/main/LICENSE-SPEC). JSON Schemas and reference code: Apache-2.0.
@@ -13,6 +13,8 @@ Status: draft v0.1, for discussion with brands, retailers and agent developers.
13
13
 
14
14
  The spec asserts one thing: whether a brand has authorized a given seller, on a given channel, in a given territory, for a given product scope, as of a given date.
15
15
 
16
+ Scope: the spec covers consumer-facing online channels: marketplaces and web stores, including omnichannel retailers, which are identified by their web domain. Trade, wholesale and practitioner-only channels are out of scope. Sellers there are not listed, so their resale on consumer channels verifies as unlisted.
17
+
16
18
  It does not assert:
17
19
 
18
20
  - **Authenticity.** An authorized seller can still sell counterfeit goods or have its account compromised. Authorization and authenticity are separate questions.
@@ -123,7 +125,7 @@ An individual authorization's `expires` MUST NOT be later than the file's `expir
123
125
 
124
126
  ## 6. Seller identity and channel identifiers
125
127
 
126
- Agents see sellers as channel identifiers, not company names, so every authorization MUST name at least one channel identifier. A name alone is not verifiable.
128
+ Agents see sellers as channel identifiers, not company names, so every authorization MUST name at least one online channel identifier (`amazon`, `walmart`, `ebay` or `web`). A name alone is not verifiable, and a `physical` identifier alone does not authorize anything.
127
129
 
128
130
  | Channel type | Required fields | Identifier |
129
131
  | --- | --- | --- |
@@ -131,7 +133,7 @@ Agents see sellers as channel identifiers, not company names, so every authoriza
131
133
  | `walmart` | `marketplace`, `seller_id` | Walmart Marketplace partner ID |
132
134
  | `ebay` | `marketplace`, `seller_id` | eBay user ID |
133
135
  | `web` | `domain` | The retailer's store domain |
134
- | `physical` | `address`, `country` | Store location, for completeness; not verifiable by agents |
136
+ | `physical` | `address`, `country` | Optional storefront detail. Not a channel agents can verify, and never sufficient on its own |
135
137
 
136
138
  New channel types are added by registry proposal and published in the spec changelog.
137
139
 
@@ -260,6 +262,8 @@ The registry's liability position, dispute timelines and data handling are set o
260
262
  - [ ] Observation on channels beyond Amazon: Walmart and retailer web domains first?
261
263
  - [ ] Alignment with UCP and ACP: an extension field that points agents to a brand's authorized-retailers file.
262
264
  - [ ] Brand-declared `unauthorized`: a status for sellers the brand has explicitly said are not authorized, as distinct from `unlisted`, with a dispute path for the seller.
265
+ - [ ] Dispensary and multi-seller platforms (e.g. practitioner dispensaries hosted on one platform domain): how to authorize individual sellers when agents only see the platform domain.
266
+ - [ ] Channel audience: whether a channel needs an `audience` field (consumer, trade, practitioner) or whether consumer-only scope is enough.
263
267
 
264
268
  ## 14. Changelog
265
269
 
@@ -280,3 +284,7 @@ The registry's liability position, dispute timelines and data handling are set o
280
284
  - A registry MAY warn brands about sellers at PO boxes or commercial mailboxes. Verify answers don't change (section 12).
281
285
  - Corrected: the reference registry doesn't observe sellers yet (section 7).
282
286
  - Examples use reserved `.example` domains.
287
+ - **2026-09-26**
288
+ - Scope: the spec covers consumer-facing online channels, including omnichannel retailers identified by their web domain. Trade, wholesale and practitioner-only channels are out of scope (section 1).
289
+ - Every authorization MUST name at least one online channel identifier (`amazon`, `walmart`, `ebay` or `web`). A `physical` identifier alone no longer authorizes anything (section 6).
290
+ - Two open questions: dispensary and multi-seller platforms, and a channel `audience` field (section 13).