@epilot/cli 0.1.126 → 0.1.127

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.
@@ -2,7 +2,7 @@
2
2
  "openapi": "3.0.3",
3
3
  "info": {
4
4
  "title": "Pricing API",
5
- "description": "The `pricing-api` hub sets the foundations for the following Pricing APIs:\n\n### Order API\nThis api enables the management of orders in epilot 360, providing features such as:\n - Automatic calculation of totals and price breakdowns for taxes on the Order entity\n - Product and pricing data validation\n\n### Shopping Cart API\nUsed to interact with a cart during a customer's checkout session, providing:\n - An unified data model to model a Shopping Cart\n - Product and pricing data validation\n - Checkout a cart into an order or quote\n\n### Catalog API\nProvides a way to query the entire catalog of products and prices.\n\n### Availability API\nProvides endpoints for querying products availability by a set of predefined dimensions.\n\n### Spot Market API\nProvides endpoints to fetch (historic) spot market price data.\n\n### External Integrations API\nProvides endpoints for external integrations. E.g. GetAG.\n\n### External Catalog API\nProvides endpoints for external catalog.\n\n### Product Recommendations API\nProvides endpoints for product recommendations.\n",
5
+ "description": "The `pricing-api` hub sets the foundations for the following Pricing APIs:\n\n### Order API\nThis api enables the management of orders in epilot 360, providing features such as:\n - Automatic calculation of totals and price breakdowns for taxes on the Order entity\n - Product and pricing data validation\n\n### Shopping Cart API\nUsed to interact with a cart during a customer's checkout session, providing:\n - An unified data model to model a Shopping Cart\n - Product and pricing data validation\n - Checkout a cart into an order or quote\n\n### Catalog API\nProvides a way to query the entire catalog of products and prices.\n\n### Availability API\nProvides endpoints for querying products availability by a set of predefined dimensions.\n\n### Spot Market API\nProvides endpoints to fetch (historic) spot market price data.\n\n### External Integrations API\nProvides endpoints for external integrations. E.g. GetAG.\n\n### External Catalog API\nProvides endpoints for external catalog.\n\n### Product Recommendations API\nProvides endpoints for product recommendations.\n\n### Conditional Pricing API\nProvides endpoints for resolving conditional Products, Prices and Coupons, and for authoring the conditions they vary by.\n",
6
6
  "version": "1.2.1",
7
7
  "termsOfService": "https://epilot.cloud/agb",
8
8
  "contact": {
@@ -48,6 +48,10 @@
48
48
  "name": "Product Recommendations API",
49
49
  "description": "Provides endpoints for product recommendations.\n"
50
50
  },
51
+ {
52
+ "name": "Conditional Pricing API",
53
+ "description": "Provides endpoints for resolving conditional Products, Prices and Coupons — the variant of an\nentity that applies to a given context — and for authoring the conditions they vary by.\n"
54
+ },
51
55
  {
52
56
  "name": "order_schema",
53
57
  "x-displayName": "Order",
@@ -96,7 +100,8 @@
96
100
  "External Integrations API",
97
101
  "External Catalog API",
98
102
  "Product Recommendations API",
99
- "Promo Codes API"
103
+ "Promo Codes API",
104
+ "Conditional Pricing API"
100
105
  ]
101
106
  },
102
107
  {
@@ -136,7 +141,7 @@
136
141
  "/v1/pricing:compute": {
137
142
  "post": {
138
143
  "description": "Computes a set of pricing details that can be persisted on an entity with the pricing capability enabled, e.g: Orders or Contracts.",
139
- "summary": "calculatePricingDetails",
144
+ "summary": "$calculatePricingDetails",
140
145
  "operationId": "$calculatePricingDetails",
141
146
  "tags": [
142
147
  "Order API"
@@ -876,7 +881,7 @@
876
881
  "name": "id",
877
882
  "description": "Order entity ID",
878
883
  "schema": {
879
- "type": "string"
884
+ "$ref": "#/components/schemas/EntityId"
880
885
  },
881
886
  "required": true,
882
887
  "example": "9d4602d3-03be-4d85-86b2-f3c6555fc606"
@@ -995,7 +1000,7 @@
995
1000
  "post": {
996
1001
  "description": "Checkouts a cart and executes the specified checkout `mode` process.\n\nA Checkout implicitly finalizes the provided cart (if not transient from a fast-checkout) and behaves in one of the following modes:\n- `create_order` (**default**): the payment happens at a later date or managed by 3rd-party CRM (SAP)\n- `create_invoice`: the payment happens on the online checkout (paypal, stripe, adyen)\n- `create_quote`: the checkout represents a price quote request\n\nFast checkout is also supported, by passing the Cart contents directly.\nWhen a fast checkout is performed the cart is considered transient and there is no cart persistance.\n\nIf the checkout `mode` is omitted, the `mode` will default to `create_order`.\n",
997
1002
  "operationId": "$checkoutCart",
998
- "summary": "checkoutCart",
1003
+ "summary": "$checkoutCart",
999
1004
  "security": [
1000
1005
  {},
1001
1006
  {
@@ -1064,7 +1069,7 @@
1064
1069
  "post": {
1065
1070
  "description": "Provides a querying functionalities over products and prices of the Catalog for a given organization.",
1066
1071
  "operationId": "$searchCatalog",
1067
- "summary": "searchCatalog",
1072
+ "summary": "$searchCatalog",
1068
1073
  "security": [
1069
1074
  {},
1070
1075
  {
@@ -1131,7 +1136,7 @@
1131
1136
  "post": {
1132
1137
  "description": "Provides a querying functionalities over products and prices of the Catalog for a given organization.",
1133
1138
  "operationId": "$privateSearchCatalog",
1134
- "summary": "privateSearchCatalog",
1139
+ "summary": "$privateSearchCatalog",
1135
1140
  "tags": [
1136
1141
  "Catalog API"
1137
1142
  ],
@@ -1172,7 +1177,7 @@
1172
1177
  "/v1/public/validate-promo-codes": {
1173
1178
  "post": {
1174
1179
  "description": "Validate a list of promo codes against a list of coupons",
1175
- "summary": "validatePromoCodes",
1180
+ "summary": "$validatePromoCodes",
1176
1181
  "operationId": "$validatePromoCodes",
1177
1182
  "tags": [
1178
1183
  "Promo Codes API"
@@ -1288,7 +1293,7 @@
1288
1293
  "post": {
1289
1294
  "description": "The availability check endpoint",
1290
1295
  "operationId": "$availabilityCheck",
1291
- "summary": "availabilityCheck",
1296
+ "summary": "$availabilityCheck",
1292
1297
  "security": [
1293
1298
  {
1294
1299
  "EpilotPublicAuth": []
@@ -1402,7 +1407,7 @@
1402
1407
  "get": {
1403
1408
  "description": "Validates an availability file, it returns an array of errors if the file is invalid",
1404
1409
  "operationId": "$validateAvailabilityFile",
1405
- "summary": "validateAvailabilityFile",
1410
+ "summary": "$validateAvailabilityFile",
1406
1411
  "tags": [
1407
1412
  "Availability API"
1408
1413
  ],
@@ -1483,7 +1488,7 @@
1483
1488
  "get": {
1484
1489
  "description": "Get a series of historic energy prices for a given time period, market and bidding zone.",
1485
1490
  "operationId": "$historicMarketPrices",
1486
- "summary": "historicMarketPrices",
1491
+ "summary": "$historicMarketPrices",
1487
1492
  "tags": [
1488
1493
  "Spot Market API"
1489
1494
  ],
@@ -1593,7 +1598,7 @@
1593
1598
  "get": {
1594
1599
  "description": "Get the average energy prices for a given time period, market and bidding zone.",
1595
1600
  "operationId": "$averageMarketPrice",
1596
- "summary": "averageMarketPrice",
1601
+ "summary": "$averageMarketPrice",
1597
1602
  "tags": [
1598
1603
  "Spot Market API"
1599
1604
  ],
@@ -1712,7 +1717,7 @@
1712
1717
  "example": "external-catalog"
1713
1718
  }
1714
1719
  ],
1715
- "summary": "searchExternalProducts",
1720
+ "summary": "$searchExternalProducts",
1716
1721
  "tags": [
1717
1722
  "External Integrations API"
1718
1723
  ],
@@ -1874,7 +1879,7 @@
1874
1879
  "example": "external-catalog"
1875
1880
  }
1876
1881
  ],
1877
- "summary": "searchExternalProductRecommendations",
1882
+ "summary": "$searchExternalProductRecommendations",
1878
1883
  "tags": [
1879
1884
  "External Integrations API"
1880
1885
  ],
@@ -2261,7 +2266,7 @@
2261
2266
  "example": "getag"
2262
2267
  }
2263
2268
  ],
2264
- "summary": "searchProviders",
2269
+ "summary": "$searchProviders",
2265
2270
  "tags": [
2266
2271
  "External Integrations API"
2267
2272
  ],
@@ -2413,7 +2418,7 @@
2413
2418
  "example": "getag"
2414
2419
  }
2415
2420
  ],
2416
- "summary": "searchStreets",
2421
+ "summary": "$searchStreets",
2417
2422
  "tags": [
2418
2423
  "External Integrations API"
2419
2424
  ],
@@ -2513,7 +2518,7 @@
2513
2518
  "example": "getag"
2514
2519
  }
2515
2520
  ],
2516
- "summary": "calculatePricingDetails",
2521
+ "summary": "$computePrice",
2517
2522
  "tags": [
2518
2523
  "External Integrations API"
2519
2524
  ],
@@ -2603,7 +2608,7 @@
2603
2608
  "get": {
2604
2609
  "description": "Gets the credentials for a given integration / organization",
2605
2610
  "operationId": "$getCredentials",
2606
- "summary": "getCredentials",
2611
+ "summary": "$getCredentials",
2607
2612
  "tags": [
2608
2613
  "External Integrations API"
2609
2614
  ],
@@ -2665,7 +2670,7 @@
2665
2670
  "put": {
2666
2671
  "description": "Saves the credentials for a given integration / organization",
2667
2672
  "operationId": "$saveCredentials",
2668
- "summary": "saveCredentials",
2673
+ "summary": "$saveCredentials",
2669
2674
  "tags": [
2670
2675
  "External Integrations API"
2671
2676
  ],
@@ -2719,7 +2724,7 @@
2719
2724
  "delete": {
2720
2725
  "description": "Delete the credentials for a given integration / organization",
2721
2726
  "operationId": "$deleteCredentials",
2722
- "summary": "deleteCredentials",
2727
+ "summary": "$deleteCredentials",
2723
2728
  "tags": [
2724
2729
  "External Integrations API"
2725
2730
  ],
@@ -2762,7 +2767,7 @@
2762
2767
  "EpilotPublicAuth": []
2763
2768
  }
2764
2769
  ],
2765
- "summary": "getExternalCatalogProducts",
2770
+ "summary": "$getExternalCatalogProducts",
2766
2771
  "tags": [
2767
2772
  "External Catalog API"
2768
2773
  ],
@@ -2923,7 +2928,7 @@
2923
2928
  "EpilotPublicAuth": []
2924
2929
  }
2925
2930
  ],
2926
- "summary": "getExternalCatalogProductRecommendations",
2931
+ "summary": "$getExternalCatalogProductRecommendations",
2927
2932
  "tags": [
2928
2933
  "External Catalog API"
2929
2934
  ],
@@ -3266,7 +3271,7 @@
3266
3271
  "post": {
3267
3272
  "description": "Get a list of product recommendations based on the search parameters.",
3268
3273
  "operationId": "$productRecommendations",
3269
- "summary": "productRecommendations",
3274
+ "summary": "$productRecommendations",
3270
3275
  "security": [
3271
3276
  {
3272
3277
  "EpilotPublicAuth": []
@@ -3406,45 +3411,1714 @@
3406
3411
  }
3407
3412
  }
3408
3413
  }
3409
- }
3410
- },
3411
- "components": {
3412
- "securitySchemes": {
3413
- "EpilotAuth": {
3414
- "type": "http",
3415
- "scheme": "bearer",
3416
- "description": "Epilot Bearer Token"
3417
- },
3418
- "EpilotPublicAuth": {
3419
- "type": "http",
3420
- "scheme": "bearer",
3421
- "description": "Epilot Public Access Bearer Token",
3422
- "bearerFormat": "JWT"
3414
+ },
3415
+ "/v1/conditional-pricing/{slug}/condition-sets": {
3416
+ "get": {
3417
+ "description": "Returns the condition sets built in for one conditional entity type: the situations a\nconditional Product, Price or Coupon is commonly varied by, ready to be copied into that\nschema's `conditions` array and extended or modified from there.\n\nWhich sets exist depends on the schema — an offer window is a Product's dimension, a delivery\narea is a Price's and a Coupon's — so only the sets built in for `slug` are returned.\n\nStatic, read-only reference data. The catalog is the same for every organization and is not\napplied to any schema by this endpoint — adding conditions to a schema stays an Entity API\nwrite.\n",
3418
+ "operationId": "$getConditionSets",
3419
+ "summary": "$getConditionSets",
3420
+ "tags": [
3421
+ "Conditional Pricing API"
3422
+ ],
3423
+ "parameters": [
3424
+ {
3425
+ "in": "path",
3426
+ "name": "slug",
3427
+ "description": "The conditional entity type whose built-in condition sets to return",
3428
+ "schema": {
3429
+ "$ref": "#/components/schemas/ConditionalEntitySlug"
3430
+ },
3431
+ "required": true,
3432
+ "example": "price"
3433
+ }
3434
+ ],
3435
+ "responses": {
3436
+ "200": {
3437
+ "description": "The condition sets built in for this entity type",
3438
+ "content": {
3439
+ "application/json": {
3440
+ "schema": {
3441
+ "$ref": "#/components/schemas/ConditionSetCatalog"
3442
+ }
3443
+ }
3444
+ }
3445
+ },
3446
+ "400": {
3447
+ "description": "Invalid request, e.g. the slug names no conditional entity type",
3448
+ "content": {
3449
+ "application/json": {
3450
+ "schema": {
3451
+ "$ref": "#/components/schemas/Error"
3452
+ }
3453
+ }
3454
+ }
3455
+ }
3456
+ }
3423
3457
  }
3424
3458
  },
3425
- "schemas": {
3426
- "IntegrationId": {
3427
- "type": "string",
3428
- "enum": [
3429
- "getag",
3430
- "external-catalog"
3431
- ]
3459
+ "/v1/conditional-pricing:resolve": {
3460
+ "post": {
3461
+ "description": "Resolves which of a conditional entity's variants apply to a situation, and returns each one\ncomposed: the base entity overlaid with the values of the version in effect at `as_of`.\n\nResolution is two selections in a fixed order — the variant, by matching `context` against\nthe conditions each variant pins; then the version, by `as_of`. It is always scoped to one\nlogical entity, so it stays a cheap, predictable lookup rather than an open search.\n\nMatching follows two rules worth knowing before assembling a context. A condition a variant\ndoes **not** pin matches any value, which is what lets a condition be added to a schema\nwithout breaking the variants that already exist. A condition **missing from `context`**,\nhowever, does not satisfy one a variant pinned: an incomplete integration resolves to\nnothing rather than silently matching another segment's variants.\n\nWhen nothing matches, the entity's `default` variant is returned if it has one. There is no\nimplicit fallback to the unmodified base entity — its values are the ones no variant\noverrode, which is not an answer to \"what applies here\".\n\nAvailability is a separate mechanism and is never consulted here.\n",
3462
+ "operationId": "$resolveConditionalEntity",
3463
+ "summary": "$resolveConditionalEntity",
3464
+ "tags": [
3465
+ "Conditional Pricing API"
3466
+ ],
3467
+ "requestBody": {
3468
+ "required": true,
3469
+ "content": {
3470
+ "application/json": {
3471
+ "schema": {
3472
+ "$ref": "#/components/schemas/ResolveConditionalEntityRequest"
3473
+ }
3474
+ }
3475
+ }
3476
+ },
3477
+ "responses": {
3478
+ "200": {
3479
+ "description": "The variants that apply, each composed with the version in effect. Empty when nothing\napplies and the entity has no `default` variant. With `resolve_one`, exactly one result.\n",
3480
+ "content": {
3481
+ "application/json": {
3482
+ "schema": {
3483
+ "$ref": "#/components/schemas/ResolvedVariants"
3484
+ }
3485
+ }
3486
+ }
3487
+ },
3488
+ "400": {
3489
+ "description": "The context is not usable against this schema: it names an undefined condition\n(`CONDITION_UNDEFINED`), applies an operator the condition's type does not support\n(`OPERATOR_UNSUPPORTED`), carries a value malformed for its type (`CONTEXT_FORMAT_INVALID`),\nor selects more variants than one response may carry (`TOO_MANY_MATCHES`).\n",
3490
+ "content": {
3491
+ "application/json": {
3492
+ "schema": {
3493
+ "$ref": "#/components/schemas/ConditionalPricingError"
3494
+ }
3495
+ }
3496
+ }
3497
+ },
3498
+ "404": {
3499
+ "description": "No such schema or entity, or — with `resolve_one` — nothing applied and the entity has no\n`default` variant (`NOT_FOUND`).\n",
3500
+ "content": {
3501
+ "application/json": {
3502
+ "schema": {
3503
+ "$ref": "#/components/schemas/ConditionalPricingError"
3504
+ }
3505
+ }
3506
+ }
3507
+ },
3508
+ "409": {
3509
+ "description": "Several variants apply while a single result was requested (`AMBIGUOUS_RESOLUTION`); the\ncandidates are in `details`.\n",
3510
+ "content": {
3511
+ "application/json": {
3512
+ "schema": {
3513
+ "$ref": "#/components/schemas/ConditionalPricingError"
3514
+ }
3515
+ }
3516
+ }
3517
+ }
3518
+ }
3519
+ }
3520
+ },
3521
+ "/v1/conditional-pricing/{slug}/entities/{entity_id}/variants": {
3522
+ "post": {
3523
+ "description": "Creates one variant of a conditional entity, together with the first version carrying its\nvalues. Never two calls: a variant that existed without a version would be an entity holding\na condition tuple it cannot answer with.\n\nThe body pins the situation the variant applies to. Pins are exact values only — predicates\nare a read-side concept and are rejected here — and are stored canonicalized for their\ncondition's type, so two spellings of one instant, or one town written two ways, are one\nvariant rather than two that no context can tell apart.\n\nThree write rules are worth knowing before the first call:\n\n- A variant must pin at least one condition or be marked `default`. A variant pinning nothing\n would be a universal wildcard matching every resolve, which is a far more dangerous thing\n than a fallback and far easier to create by accident.\n- `default` is a property of the variant, set by the `default` flag, and is never a value in\n `conditions` — not even `false`. A `default` variant cannot pin anything else, and an entity\n can have only one, enforced by the ordinary condition-tuple guard rather than by a rule of\n its own. Any entity may have one; nothing is declared in the schema to allow it.\n- Condition values are immutable afterwards. A variant's identity is the situation it applies\n to, and orders and contracts pin it. **A condition added to a schema that already has\n variants is effectively one-way**: every existing variant is a wildcard on the new\n dimension, but the first variant that pins it is ambiguous against all of them, and\n retro-pinning the others is blocked by this same rule.\n\nAttribute values are applied only for attributes currently carrying `overridable_attribute`.\nMetadata and non-overridable fields present in the body are ignored rather than rejected, so a\nclient working from a slightly stale schema snapshot still succeeds.\n\n`variant_id` is always server-generated and returned, and is not accepted in the body — the\nrequest schema admits no such property. It is the durable key orders and contracts pin, so it\ncannot be something two independent importers could collide on.\n",
3524
+ "operationId": "$createConditionalVariant",
3525
+ "summary": "$createConditionalVariant",
3526
+ "tags": [
3527
+ "Conditional Pricing API"
3528
+ ],
3529
+ "parameters": [
3530
+ {
3531
+ "in": "path",
3532
+ "name": "slug",
3533
+ "description": "The conditional entity type this variant belongs to",
3534
+ "schema": {
3535
+ "$ref": "#/components/schemas/ConditionalEntitySlug"
3536
+ },
3537
+ "required": true,
3538
+ "example": "price"
3539
+ },
3540
+ {
3541
+ "in": "path",
3542
+ "name": "entity_id",
3543
+ "description": "The conditional entity to add a variant to",
3544
+ "schema": {
3545
+ "type": "string"
3546
+ },
3547
+ "required": true,
3548
+ "example": "price-sp26d1yo"
3549
+ }
3550
+ ],
3551
+ "requestBody": {
3552
+ "required": true,
3553
+ "content": {
3554
+ "application/json": {
3555
+ "schema": {
3556
+ "$ref": "#/components/schemas/CreateVariantRequest"
3557
+ }
3558
+ }
3559
+ }
3560
+ },
3561
+ "responses": {
3562
+ "201": {
3563
+ "description": "The variant, as created, together with its first version",
3564
+ "content": {
3565
+ "application/json": {
3566
+ "schema": {
3567
+ "$ref": "#/components/schemas/CreatedVariant"
3568
+ }
3569
+ }
3570
+ }
3571
+ },
3572
+ "400": {
3573
+ "description": "The variant cannot be created as described: it pins nothing and is not the default, pins\na condition the schema does not declare (`CONDITION_UNDEFINED`), pins a `select` value\noutside the vocabulary the condition declares (`CONDITION_VALUE_INVALID`), pins the\nfallback marker directly under either of its names (`default` or `_default`), carries a\nvalue malformed for its condition's type, or the entity already holds every variant it\nmay hold.\n",
3574
+ "content": {
3575
+ "application/json": {
3576
+ "schema": {
3577
+ "$ref": "#/components/schemas/ConditionalPricingError"
3578
+ }
3579
+ }
3580
+ }
3581
+ },
3582
+ "404": {
3583
+ "description": "No such schema, or no such entity (`NOT_FOUND`).",
3584
+ "content": {
3585
+ "application/json": {
3586
+ "schema": {
3587
+ "$ref": "#/components/schemas/ConditionalPricingError"
3588
+ }
3589
+ }
3590
+ }
3591
+ },
3592
+ "409": {
3593
+ "description": "Another variant of this entity already pins this exact combination of condition values\n(`TUPLE_CONFLICT`, naming it in `details.conflicting_variant_id`) — which is also how a\nsecond `default` variant is refused — or the entity's items are being written\nconcurrently (`WRITE_CONFLICT`, retryable).\n",
3594
+ "content": {
3595
+ "application/json": {
3596
+ "schema": {
3597
+ "$ref": "#/components/schemas/ConditionalPricingError"
3598
+ }
3599
+ }
3600
+ }
3601
+ }
3602
+ }
3603
+ }
3604
+ },
3605
+ "/v1/conditional-pricing/{slug}/entities/{entity_id}/variants/{variant_id}": {
3606
+ "get": {
3607
+ "description": "Returns the version of this variant that is currently in effect — the one with the latest\n`valid_from` at or before now.\n\nThe \"open this variant\" read: no date arithmetic is asked of the caller, and what comes back\ncarries the `_revision` a write to that version has to be sent with, so an editing screen can\nload and save without working out which version it is looking at.\n\nWhat is returned is the version's own attribute overrides, not the base entity overlaid with\nthem. Composing the two is what `:resolve` answers.\n\nA variant staged ahead of its launch has versions but none of them in effect, and is reported\nas having none rather than as not existing — the two are fixed differently.\n",
3608
+ "operationId": "$getActiveConditionalVariantVersion",
3609
+ "summary": "$getActiveConditionalVariantVersion",
3610
+ "tags": [
3611
+ "Conditional Pricing API"
3612
+ ],
3613
+ "parameters": [
3614
+ {
3615
+ "in": "path",
3616
+ "name": "slug",
3617
+ "description": "The conditional entity type this variant belongs to",
3618
+ "schema": {
3619
+ "$ref": "#/components/schemas/ConditionalEntitySlug"
3620
+ },
3621
+ "required": true,
3622
+ "example": "price"
3623
+ },
3624
+ {
3625
+ "in": "path",
3626
+ "name": "entity_id",
3627
+ "description": "The conditional entity the variant belongs to",
3628
+ "schema": {
3629
+ "type": "string"
3630
+ },
3631
+ "required": true,
3632
+ "example": "price-sp26d1yo"
3633
+ },
3634
+ {
3635
+ "in": "path",
3636
+ "name": "variant_id",
3637
+ "description": "The variant whose timeline this call addresses",
3638
+ "schema": {
3639
+ "type": "string"
3640
+ },
3641
+ "required": true,
3642
+ "example": "var-46045"
3643
+ }
3644
+ ],
3645
+ "responses": {
3646
+ "200": {
3647
+ "description": "The version, as stored",
3648
+ "content": {
3649
+ "application/json": {
3650
+ "schema": {
3651
+ "$ref": "#/components/schemas/VariantVersion"
3652
+ }
3653
+ }
3654
+ }
3655
+ },
3656
+ "400": {
3657
+ "description": "Invalid request, e.g. the slug names no conditional entity type.\n",
3658
+ "content": {
3659
+ "application/json": {
3660
+ "schema": {
3661
+ "$ref": "#/components/schemas/ConditionalPricingError"
3662
+ }
3663
+ }
3664
+ }
3665
+ },
3666
+ "404": {
3667
+ "description": "No such variant under this schema, or it has no version at the instant addressed\n(`NOT_FOUND`). A variant whose versions are all still scheduled has none in effect, which is\nreported as such rather than as a missing variant.\n",
3668
+ "content": {
3669
+ "application/json": {
3670
+ "schema": {
3671
+ "$ref": "#/components/schemas/ConditionalPricingError"
3672
+ }
3673
+ }
3674
+ }
3675
+ }
3676
+ }
3432
3677
  },
3433
- "ConditionalPricingErrorCode": {
3434
- "type": "string",
3435
- "description": "Machine-readable failure mode of a conditional-pricing operation, allowing clients\nto branch on the kind of failure instead of parsing the error message.\n\n- `NOT_FOUND` (404): the addressed entity, variant or version does not exist\n- `AMBIGUOUS_RESOLUTION` (409): several variants match the given context while a single result was requested\n- `TUPLE_CONFLICT` (409): the condition tuple is already claimed by another variant\n- `VERSION_CONFLICT` (409): a version already exists at the given `valid_from` on that variant\n- `SUPERSEDED_VERSION` (409): the addressed version has been superseded\n- `CONDITION_UNDEFINED` (400): the context names a condition the entity's schema does not define\n- `OPERATOR_UNSUPPORTED` (400): the requested operator is not applicable to the condition's type\n- `CONTEXT_FORMAT_INVALID` (400): a context value is malformed for its condition type\n- `TOO_MANY_MATCHES` (400): a multi-match resolve exceeded its result cap\n- `WRITE_CONFLICT` (409): transient write contention, retryable unlike `TUPLE_CONFLICT`\n\nEach code is emitted with the HTTP status shown above, and only with that status.\n",
3436
- "enum": [
3437
- "NOT_FOUND",
3438
- "AMBIGUOUS_RESOLUTION",
3439
- "TUPLE_CONFLICT",
3440
- "VERSION_CONFLICT",
3441
- "SUPERSEDED_VERSION",
3442
- "CONDITION_UNDEFINED",
3443
- "OPERATOR_UNSUPPORTED",
3444
- "CONTEXT_FORMAT_INVALID",
3445
- "TOO_MANY_MATCHES",
3446
- "WRITE_CONFLICT"
3447
- ]
3678
+ "put": {
3679
+ "description": "Replaces the values of the version currently in effect, wholesale.\n\nThe body is the complete set of attribute overrides: an attribute the variant may override and\nthat is absent from it stops being overridden. Attributes the variant may **not** override are\nignored where the body carries them, and their stored value is kept rather than dropped — a\nroutine full-snapshot write must not erase an override the moment its attribute's flag happens\nto be off.\n\nEditing the version in effect is the ordinary way a live price is corrected, and warns about\nnothing: what changes is what that version *says*, not which version is in effect.\n\nNeither `valid_from` nor `conditions` can be changed here. Both are accepted when they match\nwhat is stored, so a client building its body from the version it loaded need not strip them\nout first, and both are refused when they name something else.\n",
3680
+ "operationId": "$replaceActiveConditionalVariantVersion",
3681
+ "summary": "$replaceActiveConditionalVariantVersion",
3682
+ "tags": [
3683
+ "Conditional Pricing API"
3684
+ ],
3685
+ "parameters": [
3686
+ {
3687
+ "in": "path",
3688
+ "name": "slug",
3689
+ "description": "The conditional entity type this variant belongs to",
3690
+ "schema": {
3691
+ "$ref": "#/components/schemas/ConditionalEntitySlug"
3692
+ },
3693
+ "required": true,
3694
+ "example": "price"
3695
+ },
3696
+ {
3697
+ "in": "path",
3698
+ "name": "entity_id",
3699
+ "description": "The conditional entity the variant belongs to",
3700
+ "schema": {
3701
+ "type": "string"
3702
+ },
3703
+ "required": true,
3704
+ "example": "price-sp26d1yo"
3705
+ },
3706
+ {
3707
+ "in": "path",
3708
+ "name": "variant_id",
3709
+ "description": "The variant whose timeline this call addresses",
3710
+ "schema": {
3711
+ "type": "string"
3712
+ },
3713
+ "required": true,
3714
+ "example": "var-46045"
3715
+ }
3716
+ ],
3717
+ "requestBody": {
3718
+ "required": true,
3719
+ "content": {
3720
+ "application/json": {
3721
+ "schema": {
3722
+ "$ref": "#/components/schemas/ReplaceVersionRequest"
3723
+ }
3724
+ }
3725
+ }
3726
+ },
3727
+ "responses": {
3728
+ "200": {
3729
+ "description": "The version, as the write left it, together with anything the write moved",
3730
+ "content": {
3731
+ "application/json": {
3732
+ "schema": {
3733
+ "$ref": "#/components/schemas/WrittenVariantVersion"
3734
+ }
3735
+ }
3736
+ }
3737
+ },
3738
+ "400": {
3739
+ "description": "The write cannot be applied as described: it would move the version it addresses to another\n`valid_from`, or change the conditions its variant is pinned to — both identity rather than\ncontent, and both fixed at creation. Also when `_revision` is missing or is not a revision\nmarker.\n",
3740
+ "content": {
3741
+ "application/json": {
3742
+ "schema": {
3743
+ "$ref": "#/components/schemas/ConditionalPricingError"
3744
+ }
3745
+ }
3746
+ }
3747
+ },
3748
+ "404": {
3749
+ "description": "No such variant under this schema, or it has no version at the instant addressed\n(`NOT_FOUND`). A variant whose versions are all still scheduled has none in effect, which is\nreported as such rather than as a missing variant.\n",
3750
+ "content": {
3751
+ "application/json": {
3752
+ "schema": {
3753
+ "$ref": "#/components/schemas/ConditionalPricingError"
3754
+ }
3755
+ }
3756
+ }
3757
+ },
3758
+ "409": {
3759
+ "description": "The version has been written since `_revision` was read (`WRITE_CONFLICT`, retryable after\nre-reading the version).\n",
3760
+ "content": {
3761
+ "application/json": {
3762
+ "schema": {
3763
+ "$ref": "#/components/schemas/ConditionalPricingError"
3764
+ }
3765
+ }
3766
+ }
3767
+ }
3768
+ }
3769
+ },
3770
+ "patch": {
3771
+ "description": "Changes only the fields it names on the version currently in effect.\n\nEverything the body does not mention is left as stored — the \"just nudge this number\" write. A\n`null` is a value like any other rather than a deletion; a client that wants an attribute to\nstop being overridden sends the complete snapshot without it through `PUT`.\n\nAttempting to change a pinned condition value is refused here in particular: a partial update\nis the path a caller reaches for by accident, and a variant's conditions are the situation it\napplies to, which the orders and contracts pinning it depend on not shifting.\n",
3772
+ "operationId": "$patchActiveConditionalVariantVersion",
3773
+ "summary": "$patchActiveConditionalVariantVersion",
3774
+ "tags": [
3775
+ "Conditional Pricing API"
3776
+ ],
3777
+ "parameters": [
3778
+ {
3779
+ "in": "path",
3780
+ "name": "slug",
3781
+ "description": "The conditional entity type this variant belongs to",
3782
+ "schema": {
3783
+ "$ref": "#/components/schemas/ConditionalEntitySlug"
3784
+ },
3785
+ "required": true,
3786
+ "example": "price"
3787
+ },
3788
+ {
3789
+ "in": "path",
3790
+ "name": "entity_id",
3791
+ "description": "The conditional entity the variant belongs to",
3792
+ "schema": {
3793
+ "type": "string"
3794
+ },
3795
+ "required": true,
3796
+ "example": "price-sp26d1yo"
3797
+ },
3798
+ {
3799
+ "in": "path",
3800
+ "name": "variant_id",
3801
+ "description": "The variant whose timeline this call addresses",
3802
+ "schema": {
3803
+ "type": "string"
3804
+ },
3805
+ "required": true,
3806
+ "example": "var-46045"
3807
+ }
3808
+ ],
3809
+ "requestBody": {
3810
+ "required": true,
3811
+ "content": {
3812
+ "application/json": {
3813
+ "schema": {
3814
+ "$ref": "#/components/schemas/PatchVersionRequest"
3815
+ }
3816
+ }
3817
+ }
3818
+ },
3819
+ "responses": {
3820
+ "200": {
3821
+ "description": "The version, as the write left it, together with anything the write moved",
3822
+ "content": {
3823
+ "application/json": {
3824
+ "schema": {
3825
+ "$ref": "#/components/schemas/WrittenVariantVersion"
3826
+ }
3827
+ }
3828
+ }
3829
+ },
3830
+ "400": {
3831
+ "description": "The write cannot be applied as described: it would move the version it addresses to another\n`valid_from`, or change the conditions its variant is pinned to — both identity rather than\ncontent, and both fixed at creation. Also when `_revision` is missing or is not a revision\nmarker.\n",
3832
+ "content": {
3833
+ "application/json": {
3834
+ "schema": {
3835
+ "$ref": "#/components/schemas/ConditionalPricingError"
3836
+ }
3837
+ }
3838
+ }
3839
+ },
3840
+ "404": {
3841
+ "description": "No such variant under this schema, or it has no version at the instant addressed\n(`NOT_FOUND`). A variant whose versions are all still scheduled has none in effect, which is\nreported as such rather than as a missing variant.\n",
3842
+ "content": {
3843
+ "application/json": {
3844
+ "schema": {
3845
+ "$ref": "#/components/schemas/ConditionalPricingError"
3846
+ }
3847
+ }
3848
+ }
3849
+ },
3850
+ "409": {
3851
+ "description": "The version has been written since `_revision` was read (`WRITE_CONFLICT`, retryable after\nre-reading the version).\n",
3852
+ "content": {
3853
+ "application/json": {
3854
+ "schema": {
3855
+ "$ref": "#/components/schemas/ConditionalPricingError"
3856
+ }
3857
+ }
3858
+ }
3859
+ }
3860
+ }
3861
+ },
3862
+ "delete": {
3863
+ "description": "Removes one variant of a conditional entity: the condition tuple it holds, its registration\nin the search index, and every version it accumulated.\n\nTwo phases. The first frees the tuple and deregisters the variant, and is what makes the\ncombination of condition values immediately reusable — the second removes the version rows in\nbatches afterwards. A response arrives only once both have finished for this request, but the\ntuple is reusable from the moment the first completes, whether or not the second did: a\nvariant with more versions than one transaction can carry is the ordinary case, not an edge\none. An interrupted delete is safe to send again; it picks up where it stopped.\n\nNothing is archived. A variant an order or contract pins stops resolving, and hydration drops\nthe reference leniently rather than failing the read.\n\nThis removes the **variant**, not one of its versions. To remove a single version, name it on\n`…/variants/{variant_id}/versions/{valid_from}` — including the one currently in effect, which\ndeliberately has no \"delete whichever is live\" shorthand: that is exactly the write nobody\nshould be able to ask for without saying which version they meant.\n",
3864
+ "operationId": "$deleteConditionalVariant",
3865
+ "summary": "$deleteConditionalVariant",
3866
+ "tags": [
3867
+ "Conditional Pricing API"
3868
+ ],
3869
+ "parameters": [
3870
+ {
3871
+ "in": "path",
3872
+ "name": "slug",
3873
+ "description": "The conditional entity type this variant belongs to",
3874
+ "schema": {
3875
+ "$ref": "#/components/schemas/ConditionalEntitySlug"
3876
+ },
3877
+ "required": true,
3878
+ "example": "price"
3879
+ },
3880
+ {
3881
+ "in": "path",
3882
+ "name": "entity_id",
3883
+ "description": "The conditional entity the variant belongs to",
3884
+ "schema": {
3885
+ "type": "string"
3886
+ },
3887
+ "required": true,
3888
+ "example": "price-sp26d1yo"
3889
+ },
3890
+ {
3891
+ "in": "path",
3892
+ "name": "variant_id",
3893
+ "description": "The variant to remove",
3894
+ "schema": {
3895
+ "type": "string"
3896
+ },
3897
+ "required": true,
3898
+ "example": "var-46045"
3899
+ }
3900
+ ],
3901
+ "responses": {
3902
+ "200": {
3903
+ "description": "What the delete removed",
3904
+ "content": {
3905
+ "application/json": {
3906
+ "schema": {
3907
+ "$ref": "#/components/schemas/DeletedVariant"
3908
+ }
3909
+ }
3910
+ }
3911
+ },
3912
+ "400": {
3913
+ "description": "Invalid request, e.g. the slug names no conditional entity type",
3914
+ "content": {
3915
+ "application/json": {
3916
+ "schema": {
3917
+ "$ref": "#/components/schemas/ConditionalPricingError"
3918
+ }
3919
+ }
3920
+ }
3921
+ },
3922
+ "404": {
3923
+ "description": "This entity has no such variant (`NOT_FOUND`).",
3924
+ "content": {
3925
+ "application/json": {
3926
+ "schema": {
3927
+ "$ref": "#/components/schemas/ConditionalPricingError"
3928
+ }
3929
+ }
3930
+ }
3931
+ },
3932
+ "409": {
3933
+ "description": "The variant's items are being written concurrently (`WRITE_CONFLICT`, retryable).",
3934
+ "content": {
3935
+ "application/json": {
3936
+ "schema": {
3937
+ "$ref": "#/components/schemas/ConditionalPricingError"
3938
+ }
3939
+ }
3940
+ }
3941
+ }
3942
+ }
3943
+ }
3944
+ },
3945
+ "/v1/conditional-pricing/{slug}/entities/{entity_id}/variants/{variant_id}/versions": {
3946
+ "post": {
3947
+ "description": "Appends a version to a variant: a new set of values taking effect at its own instant.\n\nThis is how a price changes. No version carries an end date and nothing is superseded\nexplicitly — the version in effect at an instant is simply the one with the latest `valid_from`\nat or before it, so appending a later version is the whole of \"this is the new price from then\non\". A version dated in the future is staged and excluded from resolution until its date.\n\n**A version is never refused for being late.** A `valid_from` in the past is written like any\nother and answered with warnings in `warnings` naming what it moved — what resolves now, what a\npast-dated read returns, or both. Correcting a price that took effect last week is ordinary\nwork; the alternative, deleting and recreating the variant, breaks every order and contract\npinning its id.\n\nWhat is refused is appending at a `valid_from` the variant already has: that write means either\n\"replace it\" or \"and also this\", and only the caller knows which. The two operations both\nexist, on the dated version path.\n\nThe variant's `conditions` are its identity and are fixed at creation; they may be sent back\nunchanged but never changed.\n",
3948
+ "operationId": "$appendConditionalVariantVersion",
3949
+ "summary": "$appendConditionalVariantVersion",
3950
+ "tags": [
3951
+ "Conditional Pricing API"
3952
+ ],
3953
+ "parameters": [
3954
+ {
3955
+ "in": "path",
3956
+ "name": "slug",
3957
+ "description": "The conditional entity type this variant belongs to",
3958
+ "schema": {
3959
+ "$ref": "#/components/schemas/ConditionalEntitySlug"
3960
+ },
3961
+ "required": true,
3962
+ "example": "price"
3963
+ },
3964
+ {
3965
+ "in": "path",
3966
+ "name": "entity_id",
3967
+ "description": "The conditional entity the variant belongs to",
3968
+ "schema": {
3969
+ "type": "string"
3970
+ },
3971
+ "required": true,
3972
+ "example": "price-sp26d1yo"
3973
+ },
3974
+ {
3975
+ "in": "path",
3976
+ "name": "variant_id",
3977
+ "description": "The variant whose timeline this call addresses",
3978
+ "schema": {
3979
+ "type": "string"
3980
+ },
3981
+ "required": true,
3982
+ "example": "var-46045"
3983
+ }
3984
+ ],
3985
+ "requestBody": {
3986
+ "required": true,
3987
+ "content": {
3988
+ "application/json": {
3989
+ "schema": {
3990
+ "$ref": "#/components/schemas/AppendVersionRequest"
3991
+ }
3992
+ }
3993
+ }
3994
+ },
3995
+ "responses": {
3996
+ "201": {
3997
+ "description": "The version, as appended, together with anything the write moved",
3998
+ "content": {
3999
+ "application/json": {
4000
+ "schema": {
4001
+ "$ref": "#/components/schemas/WrittenVariantVersion"
4002
+ }
4003
+ }
4004
+ }
4005
+ },
4006
+ "400": {
4007
+ "description": "The version cannot be appended as described: the body would change the variant's conditions,\nor `valid_from` is not a timestamp this store can sort by.\n",
4008
+ "content": {
4009
+ "application/json": {
4010
+ "schema": {
4011
+ "$ref": "#/components/schemas/ConditionalPricingError"
4012
+ }
4013
+ }
4014
+ }
4015
+ },
4016
+ "404": {
4017
+ "description": "No such schema, or no such variant under it (`NOT_FOUND`).\n",
4018
+ "content": {
4019
+ "application/json": {
4020
+ "schema": {
4021
+ "$ref": "#/components/schemas/ConditionalPricingError"
4022
+ }
4023
+ }
4024
+ }
4025
+ },
4026
+ "409": {
4027
+ "description": "The variant already has a version at that `valid_from` (`VERSION_CONFLICT`) — append means\nappend, never an implicit overwrite. Replace or patch that version instead.\n",
4028
+ "content": {
4029
+ "application/json": {
4030
+ "schema": {
4031
+ "$ref": "#/components/schemas/ConditionalPricingError"
4032
+ }
4033
+ }
4034
+ }
4035
+ }
4036
+ }
4037
+ }
4038
+ },
4039
+ "/v1/conditional-pricing/{slug}/entities/{entity_id}/variants/{variant_id}/versions/{valid_from}": {
4040
+ "get": {
4041
+ "description": "Returns one specific version of a variant, by the instant it takes effect — what a form editing\nthat version loads.\n\nExact, never nearest: an instant the variant has no version at is a not-found rather than the\nversion that would be in effect at it. That question is the shorthand read's, or `:resolve`'s.\n",
4042
+ "operationId": "$getConditionalVariantVersion",
4043
+ "summary": "$getConditionalVariantVersion",
4044
+ "tags": [
4045
+ "Conditional Pricing API"
4046
+ ],
4047
+ "parameters": [
4048
+ {
4049
+ "in": "path",
4050
+ "name": "slug",
4051
+ "description": "The conditional entity type this variant belongs to",
4052
+ "schema": {
4053
+ "$ref": "#/components/schemas/ConditionalEntitySlug"
4054
+ },
4055
+ "required": true,
4056
+ "example": "price"
4057
+ },
4058
+ {
4059
+ "in": "path",
4060
+ "name": "entity_id",
4061
+ "description": "The conditional entity the variant belongs to",
4062
+ "schema": {
4063
+ "type": "string"
4064
+ },
4065
+ "required": true,
4066
+ "example": "price-sp26d1yo"
4067
+ },
4068
+ {
4069
+ "in": "path",
4070
+ "name": "variant_id",
4071
+ "description": "The variant whose timeline this call addresses",
4072
+ "schema": {
4073
+ "type": "string"
4074
+ },
4075
+ "required": true,
4076
+ "example": "var-46045"
4077
+ },
4078
+ {
4079
+ "in": "path",
4080
+ "name": "valid_from",
4081
+ "description": "The version to address, by the instant it takes effect.\n\nAn RFC 3339 date (`2026-01-01`, read as midnight UTC) or date-time\n(`2026-01-01T00:00:00Z`), to at most millisecond precision. Written any accepted way: it is\ncanonicalized before it is matched, so the spelling a read returned and the spelling a\nhuman typed address the same version.\n",
4082
+ "schema": {
4083
+ "type": "string"
4084
+ },
4085
+ "required": true,
4086
+ "example": "2027-01-01T00:00:00.000Z"
4087
+ }
4088
+ ],
4089
+ "responses": {
4090
+ "200": {
4091
+ "description": "The version, as stored",
4092
+ "content": {
4093
+ "application/json": {
4094
+ "schema": {
4095
+ "$ref": "#/components/schemas/VariantVersion"
4096
+ }
4097
+ }
4098
+ }
4099
+ },
4100
+ "400": {
4101
+ "description": "Invalid request, e.g. a `valid_from` that is not a timestamp this store can sort by.\n",
4102
+ "content": {
4103
+ "application/json": {
4104
+ "schema": {
4105
+ "$ref": "#/components/schemas/ConditionalPricingError"
4106
+ }
4107
+ }
4108
+ }
4109
+ },
4110
+ "404": {
4111
+ "description": "This variant has no version at that instant (`NOT_FOUND`).\n",
4112
+ "content": {
4113
+ "application/json": {
4114
+ "schema": {
4115
+ "$ref": "#/components/schemas/ConditionalPricingError"
4116
+ }
4117
+ }
4118
+ }
4119
+ }
4120
+ }
4121
+ },
4122
+ "put": {
4123
+ "description": "Replaces one version's values wholesale, addressed by its `valid_from`.\n\nEditable whatever its date, at both ends of the timeline: a scheduled version must stay\neditable so a staged price can be corrected before it goes live rather than accumulating dead\nversions beside it, and a past one must stay editable because correcting history is ordinary\nwork. Writing a superseded version is answered with a warning naming what a past-dated read now\nreturns; it is not refused.\n\nAttributes the variant may not override are ignored where the body carries them, and their\nstored value is preserved rather than dropped.\n",
4124
+ "operationId": "$replaceConditionalVariantVersion",
4125
+ "summary": "$replaceConditionalVariantVersion",
4126
+ "tags": [
4127
+ "Conditional Pricing API"
4128
+ ],
4129
+ "parameters": [
4130
+ {
4131
+ "in": "path",
4132
+ "name": "slug",
4133
+ "description": "The conditional entity type this variant belongs to",
4134
+ "schema": {
4135
+ "$ref": "#/components/schemas/ConditionalEntitySlug"
4136
+ },
4137
+ "required": true,
4138
+ "example": "price"
4139
+ },
4140
+ {
4141
+ "in": "path",
4142
+ "name": "entity_id",
4143
+ "description": "The conditional entity the variant belongs to",
4144
+ "schema": {
4145
+ "type": "string"
4146
+ },
4147
+ "required": true,
4148
+ "example": "price-sp26d1yo"
4149
+ },
4150
+ {
4151
+ "in": "path",
4152
+ "name": "variant_id",
4153
+ "description": "The variant whose timeline this call addresses",
4154
+ "schema": {
4155
+ "type": "string"
4156
+ },
4157
+ "required": true,
4158
+ "example": "var-46045"
4159
+ },
4160
+ {
4161
+ "in": "path",
4162
+ "name": "valid_from",
4163
+ "description": "The version to address, by the instant it takes effect.\n\nAn RFC 3339 date (`2026-01-01`, read as midnight UTC) or date-time\n(`2026-01-01T00:00:00Z`), to at most millisecond precision. Written any accepted way: it is\ncanonicalized before it is matched, so the spelling a read returned and the spelling a\nhuman typed address the same version.\n",
4164
+ "schema": {
4165
+ "type": "string"
4166
+ },
4167
+ "required": true,
4168
+ "example": "2027-01-01T00:00:00.000Z"
4169
+ }
4170
+ ],
4171
+ "requestBody": {
4172
+ "required": true,
4173
+ "content": {
4174
+ "application/json": {
4175
+ "schema": {
4176
+ "$ref": "#/components/schemas/ReplaceVersionRequest"
4177
+ }
4178
+ }
4179
+ }
4180
+ },
4181
+ "responses": {
4182
+ "200": {
4183
+ "description": "The version, as the write left it, together with anything the write moved",
4184
+ "content": {
4185
+ "application/json": {
4186
+ "schema": {
4187
+ "$ref": "#/components/schemas/WrittenVariantVersion"
4188
+ }
4189
+ }
4190
+ }
4191
+ },
4192
+ "400": {
4193
+ "description": "The write cannot be applied as described: it would move the version it addresses to another\n`valid_from`, or change the conditions its variant is pinned to — both identity rather than\ncontent, and both fixed at creation. Also when `_revision` is missing or is not a revision\nmarker.\n",
4194
+ "content": {
4195
+ "application/json": {
4196
+ "schema": {
4197
+ "$ref": "#/components/schemas/ConditionalPricingError"
4198
+ }
4199
+ }
4200
+ }
4201
+ },
4202
+ "404": {
4203
+ "description": "This variant has no version at that instant (`NOT_FOUND`).\n",
4204
+ "content": {
4205
+ "application/json": {
4206
+ "schema": {
4207
+ "$ref": "#/components/schemas/ConditionalPricingError"
4208
+ }
4209
+ }
4210
+ }
4211
+ },
4212
+ "409": {
4213
+ "description": "The version has been written since `_revision` was read (`WRITE_CONFLICT`, retryable after\nre-reading the version).\n",
4214
+ "content": {
4215
+ "application/json": {
4216
+ "schema": {
4217
+ "$ref": "#/components/schemas/ConditionalPricingError"
4218
+ }
4219
+ }
4220
+ }
4221
+ }
4222
+ }
4223
+ },
4224
+ "patch": {
4225
+ "description": "Changes only the fields it names on one version, addressed by its `valid_from`.\n\nEverything the body does not mention is left as stored. A partial update that tries to change a\npinned condition value is refused: condition values are immutable after a variant is created,\nand this is the path that rule is most likely to be broken on by accident.\n",
4226
+ "operationId": "$patchConditionalVariantVersion",
4227
+ "summary": "$patchConditionalVariantVersion",
4228
+ "tags": [
4229
+ "Conditional Pricing API"
4230
+ ],
4231
+ "parameters": [
4232
+ {
4233
+ "in": "path",
4234
+ "name": "slug",
4235
+ "description": "The conditional entity type this variant belongs to",
4236
+ "schema": {
4237
+ "$ref": "#/components/schemas/ConditionalEntitySlug"
4238
+ },
4239
+ "required": true,
4240
+ "example": "price"
4241
+ },
4242
+ {
4243
+ "in": "path",
4244
+ "name": "entity_id",
4245
+ "description": "The conditional entity the variant belongs to",
4246
+ "schema": {
4247
+ "type": "string"
4248
+ },
4249
+ "required": true,
4250
+ "example": "price-sp26d1yo"
4251
+ },
4252
+ {
4253
+ "in": "path",
4254
+ "name": "variant_id",
4255
+ "description": "The variant whose timeline this call addresses",
4256
+ "schema": {
4257
+ "type": "string"
4258
+ },
4259
+ "required": true,
4260
+ "example": "var-46045"
4261
+ },
4262
+ {
4263
+ "in": "path",
4264
+ "name": "valid_from",
4265
+ "description": "The version to address, by the instant it takes effect.\n\nAn RFC 3339 date (`2026-01-01`, read as midnight UTC) or date-time\n(`2026-01-01T00:00:00Z`), to at most millisecond precision. Written any accepted way: it is\ncanonicalized before it is matched, so the spelling a read returned and the spelling a\nhuman typed address the same version.\n",
4266
+ "schema": {
4267
+ "type": "string"
4268
+ },
4269
+ "required": true,
4270
+ "example": "2027-01-01T00:00:00.000Z"
4271
+ }
4272
+ ],
4273
+ "requestBody": {
4274
+ "required": true,
4275
+ "content": {
4276
+ "application/json": {
4277
+ "schema": {
4278
+ "$ref": "#/components/schemas/PatchVersionRequest"
4279
+ }
4280
+ }
4281
+ }
4282
+ },
4283
+ "responses": {
4284
+ "200": {
4285
+ "description": "The version, as the write left it, together with anything the write moved",
4286
+ "content": {
4287
+ "application/json": {
4288
+ "schema": {
4289
+ "$ref": "#/components/schemas/WrittenVariantVersion"
4290
+ }
4291
+ }
4292
+ }
4293
+ },
4294
+ "400": {
4295
+ "description": "The write cannot be applied as described: it would move the version it addresses to another\n`valid_from`, or change the conditions its variant is pinned to — both identity rather than\ncontent, and both fixed at creation. Also when `_revision` is missing or is not a revision\nmarker.\n",
4296
+ "content": {
4297
+ "application/json": {
4298
+ "schema": {
4299
+ "$ref": "#/components/schemas/ConditionalPricingError"
4300
+ }
4301
+ }
4302
+ }
4303
+ },
4304
+ "404": {
4305
+ "description": "This variant has no version at that instant (`NOT_FOUND`).\n",
4306
+ "content": {
4307
+ "application/json": {
4308
+ "schema": {
4309
+ "$ref": "#/components/schemas/ConditionalPricingError"
4310
+ }
4311
+ }
4312
+ }
4313
+ },
4314
+ "409": {
4315
+ "description": "The version has been written since `_revision` was read (`WRITE_CONFLICT`, retryable after\nre-reading the version).\n",
4316
+ "content": {
4317
+ "application/json": {
4318
+ "schema": {
4319
+ "$ref": "#/components/schemas/ConditionalPricingError"
4320
+ }
4321
+ }
4322
+ }
4323
+ }
4324
+ }
4325
+ },
4326
+ "delete": {
4327
+ "description": "Removes one version of a variant.\n\nWithdrawing a scheduled adjustment is what this is for, and deleting a future version warns\nabout nothing — nothing that has resolved, or could have resolved, changes. Deleting a version\nthat has taken effect is allowed too and answered with a warning: it changes what a past-dated\nread returns, and if it was the version in effect it changes what resolves now.\n\n**A variant's last remaining version cannot be deleted.** Such a variant would still hold its\ncondition tuple and still be selectable, and then resolve to nothing — which is a variant delete\nwearing a version delete's clothes. Delete the variant instead; that frees the tuple too.\n\nThe variant itself is untouched: it keeps its conditions, its tuple and its place in the index.\n",
4328
+ "operationId": "$deleteConditionalVariantVersion",
4329
+ "summary": "$deleteConditionalVariantVersion",
4330
+ "tags": [
4331
+ "Conditional Pricing API"
4332
+ ],
4333
+ "parameters": [
4334
+ {
4335
+ "in": "path",
4336
+ "name": "slug",
4337
+ "description": "The conditional entity type this variant belongs to",
4338
+ "schema": {
4339
+ "$ref": "#/components/schemas/ConditionalEntitySlug"
4340
+ },
4341
+ "required": true,
4342
+ "example": "price"
4343
+ },
4344
+ {
4345
+ "in": "path",
4346
+ "name": "entity_id",
4347
+ "description": "The conditional entity the variant belongs to",
4348
+ "schema": {
4349
+ "type": "string"
4350
+ },
4351
+ "required": true,
4352
+ "example": "price-sp26d1yo"
4353
+ },
4354
+ {
4355
+ "in": "path",
4356
+ "name": "variant_id",
4357
+ "description": "The variant whose timeline this call addresses",
4358
+ "schema": {
4359
+ "type": "string"
4360
+ },
4361
+ "required": true,
4362
+ "example": "var-46045"
4363
+ },
4364
+ {
4365
+ "in": "path",
4366
+ "name": "valid_from",
4367
+ "description": "The version to address, by the instant it takes effect.\n\nAn RFC 3339 date (`2026-01-01`, read as midnight UTC) or date-time\n(`2026-01-01T00:00:00Z`), to at most millisecond precision. Written any accepted way: it is\ncanonicalized before it is matched, so the spelling a read returned and the spelling a\nhuman typed address the same version.\n",
4368
+ "schema": {
4369
+ "type": "string"
4370
+ },
4371
+ "required": true,
4372
+ "example": "2027-01-01T00:00:00.000Z"
4373
+ },
4374
+ {
4375
+ "in": "query",
4376
+ "name": "_revision",
4377
+ "description": "The revision marker read from the version being deleted. The delete is refused if the\nversion has been written since.\n\nA query parameter rather than a body field, since a DELETE carrying a body travels badly\nthrough clients and proxies; it is the same marker the write bodies carry as `_revision`.\n",
4378
+ "schema": {
4379
+ "type": "integer",
4380
+ "minimum": 1
4381
+ },
4382
+ "required": true,
4383
+ "example": 3
4384
+ }
4385
+ ],
4386
+ "responses": {
4387
+ "200": {
4388
+ "description": "The version removed, together with anything the delete moved",
4389
+ "content": {
4390
+ "application/json": {
4391
+ "schema": {
4392
+ "$ref": "#/components/schemas/DeletedVariantVersion"
4393
+ }
4394
+ }
4395
+ }
4396
+ },
4397
+ "400": {
4398
+ "description": "The version cannot be removed: it is the variant's only one, `_revision` is missing, or\n`valid_from` is not a timestamp this store can sort by.\n",
4399
+ "content": {
4400
+ "application/json": {
4401
+ "schema": {
4402
+ "$ref": "#/components/schemas/ConditionalPricingError"
4403
+ }
4404
+ }
4405
+ }
4406
+ },
4407
+ "404": {
4408
+ "description": "This variant has no version at that instant (`NOT_FOUND`).\n",
4409
+ "content": {
4410
+ "application/json": {
4411
+ "schema": {
4412
+ "$ref": "#/components/schemas/ConditionalPricingError"
4413
+ }
4414
+ }
4415
+ }
4416
+ },
4417
+ "409": {
4418
+ "description": "The version has been written since `_revision` was read (`WRITE_CONFLICT`, retryable after\nre-reading the version).\n",
4419
+ "content": {
4420
+ "application/json": {
4421
+ "schema": {
4422
+ "$ref": "#/components/schemas/ConditionalPricingError"
4423
+ }
4424
+ }
4425
+ }
4426
+ }
4427
+ }
4428
+ }
4429
+ }
4430
+ },
4431
+ "components": {
4432
+ "securitySchemes": {
4433
+ "EpilotAuth": {
4434
+ "type": "http",
4435
+ "scheme": "bearer",
4436
+ "description": "Epilot Bearer Token"
4437
+ },
4438
+ "EpilotPublicAuth": {
4439
+ "type": "http",
4440
+ "scheme": "bearer",
4441
+ "description": "Epilot Public Access Bearer Token",
4442
+ "bearerFormat": "JWT"
4443
+ }
4444
+ },
4445
+ "schemas": {
4446
+ "IntegrationId": {
4447
+ "type": "string",
4448
+ "enum": [
4449
+ "getag",
4450
+ "external-catalog"
4451
+ ]
4452
+ },
4453
+ "ConditionalEntitySlug": {
4454
+ "type": "string",
4455
+ "description": "Schema slug of an entity type that can be conditional — the `{slug}` of every\nconditional-pricing route.\n",
4456
+ "enum": [
4457
+ "product",
4458
+ "price",
4459
+ "coupon"
4460
+ ]
4461
+ },
4462
+ "ConditionType": {
4463
+ "type": "string",
4464
+ "description": "The kind of value a condition holds, which decides how a variant's pinned value is matched\nagainst a resolve context.\n\n- `string`: an arbitrary string, matched exactly and case-sensitively\n- `number`: a numeric value\n- `date`: a single date\n- `daterange`: a window with a from and an until timestamp; both ends may be left open\n- `boolean`: a true/false value\n- `select`: one of the values declared in `options`, unless `allow_any` is set\n- `location`: a geographic value, shaped by `format`\n\nThere is no condition type for the fallback variant. Being the entity's fallback is a\nproperty of the variant, set by the `default` flag on a variant write, and needs nothing\ndeclared in the schema.\n",
4465
+ "enum": [
4466
+ "string",
4467
+ "number",
4468
+ "date",
4469
+ "daterange",
4470
+ "boolean",
4471
+ "select",
4472
+ "location"
4473
+ ]
4474
+ },
4475
+ "ConditionDefinition": {
4476
+ "type": "object",
4477
+ "description": "One condition dimension, in the shape a schema's `conditions` array holds it — copy it in\nverbatim.\n",
4478
+ "required": [
4479
+ "name",
4480
+ "label",
4481
+ "type"
4482
+ ],
4483
+ "properties": {
4484
+ "name": {
4485
+ "type": "string",
4486
+ "description": "How variants and resolve contexts refer to this condition. Independent of attribute\nnames: a value needed as an attribute too is duplicated onto the variant.\n\n`default`, and any name beginning with `_`, are reserved for the server: a condition\ndeclared under one is ignored, since nothing could pin it and no context could address it.\n",
4487
+ "example": "postal_code"
4488
+ },
4489
+ "label": {
4490
+ "type": "string",
4491
+ "description": "Human-readable name of the condition.",
4492
+ "example": "Postal Code"
4493
+ },
4494
+ "type": {
4495
+ "$ref": "#/components/schemas/ConditionType"
4496
+ },
4497
+ "options": {
4498
+ "type": "array",
4499
+ "description": "The declared vocabulary of a `select` condition. Absent for every other type.\n\nThe same shape a `select` attribute's `options` has on the Entity API, item for item: an\nentry is either the value itself or an object carrying that value and an optional display\n`title`. A `title` is never pinned by a variant and never matched — two entries differing\nonly in their title are one vocabulary entry.\n\nEnforced on variant writes, unless `allow_any` is true: a pinned value outside the\nvocabulary is rejected with `CONDITION_VALUE_INVALID`. It is *not* enforced on resolve —\na vocabulary says what may be stored, not what may be asked for, so a context value\noutside it is a query that simply matches nothing.\n",
4500
+ "items": {
4501
+ "anyOf": [
4502
+ {
4503
+ "type": "string",
4504
+ "nullable": true
4505
+ },
4506
+ {
4507
+ "type": "object",
4508
+ "required": [
4509
+ "value"
4510
+ ],
4511
+ "properties": {
4512
+ "value": {
4513
+ "type": "string"
4514
+ },
4515
+ "title": {
4516
+ "type": "string"
4517
+ }
4518
+ }
4519
+ }
4520
+ ]
4521
+ },
4522
+ "example": [
4523
+ "private",
4524
+ "commercial"
4525
+ ]
4526
+ },
4527
+ "allow_any": {
4528
+ "type": "boolean",
4529
+ "description": "Allow arbitrary stored values in addition to the declared `options`. Absent means strict:\na variant may only pin a declared option.\n",
4530
+ "example": false
4531
+ },
4532
+ "format": {
4533
+ "type": "string",
4534
+ "description": "The value shape of a `location` condition. Absent for every other type.",
4535
+ "enum": [
4536
+ "zipcode",
4537
+ "zipcode + town"
4538
+ ]
4539
+ }
4540
+ }
4541
+ },
4542
+ "ConditionSet": {
4543
+ "type": "object",
4544
+ "description": "A named bundle of condition definitions, built in for one entity type.",
4545
+ "required": [
4546
+ "id",
4547
+ "label",
4548
+ "description",
4549
+ "conditions"
4550
+ ],
4551
+ "properties": {
4552
+ "id": {
4553
+ "type": "string",
4554
+ "description": "Identifies the set within this entity type's catalog.",
4555
+ "example": "delivery_area"
4556
+ },
4557
+ "label": {
4558
+ "type": "string",
4559
+ "description": "Human-readable name of the set.",
4560
+ "example": "Delivery Area"
4561
+ },
4562
+ "description": {
4563
+ "type": "string",
4564
+ "description": "What the set is for, and when to reach for it."
4565
+ },
4566
+ "conditions": {
4567
+ "type": "array",
4568
+ "description": "The condition definitions to copy into the schema's own `conditions` array.",
4569
+ "items": {
4570
+ "$ref": "#/components/schemas/ConditionDefinition"
4571
+ }
4572
+ }
4573
+ }
4574
+ },
4575
+ "ConditionSetCatalog": {
4576
+ "type": "object",
4577
+ "required": [
4578
+ "results"
4579
+ ],
4580
+ "properties": {
4581
+ "results": {
4582
+ "type": "array",
4583
+ "description": "The condition sets built in for the requested entity type, in the order they are offered.\n",
4584
+ "items": {
4585
+ "$ref": "#/components/schemas/ConditionSet"
4586
+ }
4587
+ }
4588
+ }
4589
+ },
4590
+ "ConditionalPricingErrorCode": {
4591
+ "type": "string",
4592
+ "description": "Machine-readable failure mode of a conditional-pricing operation, allowing clients\nto branch on the kind of failure instead of parsing the error message.\n\n- `NOT_FOUND` (404): the addressed entity, variant or version does not exist\n- `AMBIGUOUS_RESOLUTION` (409): several variants match the given context while a single result was requested\n- `TUPLE_CONFLICT` (409): the condition tuple is already claimed by another variant\n- `VERSION_CONFLICT` (409): a version already exists at the given `valid_from` on that variant\n- `CONDITION_UNDEFINED` (400): the context names a condition the entity's schema does not define\n- `OPERATOR_UNSUPPORTED` (400): the requested operator is not applicable to the condition's type\n- `CONTEXT_FORMAT_INVALID` (400): a context value is malformed for its condition type\n- `CONDITION_VALUE_INVALID` (400): a variant write pins a `select` value the condition's declared `options` do not contain\n- `TOO_MANY_MATCHES` (400): a multi-match resolve exceeded its result cap\n- `WRITE_CONFLICT` (409): transient write contention, retryable unlike `TUPLE_CONFLICT`\n\nEach code is emitted with the HTTP status shown above, and only with that status.\n",
4593
+ "enum": [
4594
+ "NOT_FOUND",
4595
+ "AMBIGUOUS_RESOLUTION",
4596
+ "TUPLE_CONFLICT",
4597
+ "VERSION_CONFLICT",
4598
+ "CONDITION_UNDEFINED",
4599
+ "OPERATOR_UNSUPPORTED",
4600
+ "CONTEXT_FORMAT_INVALID",
4601
+ "CONDITION_VALUE_INVALID",
4602
+ "TOO_MANY_MATCHES",
4603
+ "WRITE_CONFLICT"
4604
+ ]
4605
+ },
4606
+ "ResolveConditionalEntityRequest": {
4607
+ "type": "object",
4608
+ "additionalProperties": false,
4609
+ "required": [
4610
+ "schema",
4611
+ "entity_id"
4612
+ ],
4613
+ "properties": {
4614
+ "schema": {
4615
+ "$ref": "#/components/schemas/ConditionalEntitySlug"
4616
+ },
4617
+ "entity_id": {
4618
+ "type": "string",
4619
+ "description": "The conditional entity to resolve. Resolution is always scoped to exactly one.",
4620
+ "example": "price-sp26d1yo"
4621
+ },
4622
+ "context": {
4623
+ "$ref": "#/components/schemas/ResolveContext"
4624
+ },
4625
+ "as_of": {
4626
+ "type": "string",
4627
+ "description": "The instant the version is selected at — the version with the latest `valid_from` at or\nbefore it. Defaults to now. A variant whose first version is later than this is\nscheduled rather than applicable, and is excluded from resolution entirely.\n\nAn RFC 3339 date (`2026-01-01`, read as midnight UTC) or date-time\n(`2026-01-01T00:00:00Z`), to at most millisecond precision. Deliberately not declared as\n`format: date-time`, which would reject the plain-date form that this accepts.\n",
4628
+ "example": "2027-03-15T00:00:00Z"
4629
+ },
4630
+ "options": {
4631
+ "$ref": "#/components/schemas/ResolveOptions"
4632
+ }
4633
+ }
4634
+ },
4635
+ "ResolveContext": {
4636
+ "type": "object",
4637
+ "additionalProperties": true,
4638
+ "description": "The situation to resolve for: a flat map keyed by condition name, as the entity's schema\ndeclares them. A condition left out of the map is not a wildcard — it matches only variants\nthat leave that condition unpinned.\n\nEach value is either an exact value, typed by its condition, or a single-operator predicate\nobject:\n\n- `{ \"lt\": v }`, `{ \"lte\": v }`, `{ \"gt\": v }`, `{ \"gte\": v }` — order against a `number` or\n `date` condition.\n- `{ \"in\": [...] }` — membership, against a `string`, `select` or `number` condition.\n- `{ \"between\": \"2026-03-01\" }` — the explicit spelling of `daterange` containment; a plain\n date supplied for a `daterange` condition means the same thing.\n- `{ \"exists\": true }` — pinned to any value. `{ \"exists\": false }` says what leaving the key\n out says.\n\nExact values are typed by their condition: a `string` or `select` matches exactly and\ncase-sensitively, with no trimming; a `location` of format `zipcode` is the postal code\nitself, and one of format `zipcode + town` an object carrying both, whose town is compared\ncase- and whitespace-insensitively while its postal code is not.\n\n`default`, and any name beginning with `_`, are reserved for the server and cannot be\nsupplied here.\n",
4639
+ "example": {
4640
+ "postal_code": "46045",
4641
+ "consumption": {
4642
+ "lt": 5000
4643
+ }
4644
+ }
4645
+ },
4646
+ "ResolveOptions": {
4647
+ "type": "object",
4648
+ "additionalProperties": false,
4649
+ "properties": {
4650
+ "resolve_one": {
4651
+ "type": "boolean",
4652
+ "default": false,
4653
+ "description": "Ask for an unambiguous answer. Several applicable variants become `AMBIGUOUS_RESOLUTION`\nrather than a set, and nothing applicable becomes `NOT_FOUND` rather than an empty one.\nThe response shape does not change: `results` simply carries exactly one entry.\n"
4654
+ }
4655
+ }
4656
+ },
4657
+ "ResolvedVariants": {
4658
+ "type": "object",
4659
+ "required": [
4660
+ "results"
4661
+ ],
4662
+ "properties": {
4663
+ "results": {
4664
+ "type": "array",
4665
+ "description": "One composed payload per applicable variant, capped at 100 — a context selecting more\nthan that is answered with `TOO_MANY_MATCHES` instead, since each result costs its own\nversion lookup. No dominance or specificity ordering is applied between them.\n",
4666
+ "items": {
4667
+ "$ref": "#/components/schemas/ResolvedVariant"
4668
+ }
4669
+ }
4670
+ }
4671
+ },
4672
+ "ResolvedVariant": {
4673
+ "type": "object",
4674
+ "additionalProperties": true,
4675
+ "description": "The entity as this variant leaves it — every attribute of a plain entity read, with the\napplicable version's overrides applied — plus the discriminators saying where the numbers\ncame from.\n",
4676
+ "required": [
4677
+ "_id",
4678
+ "_variant_id",
4679
+ "_version_valid_from",
4680
+ "_conditions"
4681
+ ],
4682
+ "properties": {
4683
+ "_id": {
4684
+ "type": "string",
4685
+ "description": "The logical entity's id — the same one a plain entity read returns. Resolution never\nmints a new identity; a variant is a set of values for *this* entity, not another one.\n",
4686
+ "example": "price-sp26d1yo"
4687
+ },
4688
+ "_variant_id": {
4689
+ "type": "string",
4690
+ "description": "The variant these values came from. Durable: this is what an order or a contract pins to\nread the same numbers back later.\n",
4691
+ "example": "var-46045"
4692
+ },
4693
+ "_version_valid_from": {
4694
+ "type": "string",
4695
+ "description": "The `valid_from` of the version applied for the requested `as_of`.",
4696
+ "example": "2027-01-01T00:00:00.000Z"
4697
+ },
4698
+ "_conditions": {
4699
+ "allOf": [
4700
+ {
4701
+ "$ref": "#/components/schemas/VariantConditions"
4702
+ }
4703
+ ],
4704
+ "description": "The conditions this variant pins, plus the boolean `default` discriminator.\n\nUnderscore-prefixed, like every other discriminator here, so that it cannot collide with\nan attribute an organization happens to have called `conditions`.\n"
4705
+ }
4706
+ }
4707
+ },
4708
+ "CreateVariantRequest": {
4709
+ "type": "object",
4710
+ "additionalProperties": false,
4711
+ "required": [
4712
+ "values"
4713
+ ],
4714
+ "properties": {
4715
+ "conditions": {
4716
+ "$ref": "#/components/schemas/PinnedConditions"
4717
+ },
4718
+ "default": {
4719
+ "type": "boolean",
4720
+ "default": false,
4721
+ "description": "Mark this variant as the entity's fallback: the one served when no other variant applies.\n\nA property of the variant, never an entry in `conditions` — a variant claiming a value for\nthe marker would hold a real condition tuple while being permanently unmatchable, since no\nresolve context ever supplies it. A default variant cannot pin anything else, and an\nentity can have at most one.\n\nAvailable to every conditional entity: nothing has to be declared in the schema first.\nThe variant is stored pinning one reserved condition, which is what makes the ordinary\ncondition-tuple guard enforce at-most-one-per-entity with no rule of its own.\n"
4722
+ },
4723
+ "valid_from": {
4724
+ "type": "string",
4725
+ "description": "When the first version takes effect. Defaults to now.\n\nAn RFC 3339 date (`2026-01-01`, read as midnight UTC) or date-time\n(`2026-01-01T00:00:00Z`), to at most millisecond precision. Deliberately not declared as\n`format: date-time`, which would reject the plain-date form that this accepts.\n",
4726
+ "example": "2027-01-01T00:00:00Z"
4727
+ },
4728
+ "values": {
4729
+ "$ref": "#/components/schemas/VariantValues"
4730
+ }
4731
+ }
4732
+ },
4733
+ "VariantConditions": {
4734
+ "type": "object",
4735
+ "additionalProperties": true,
4736
+ "required": [
4737
+ "default"
4738
+ ],
4739
+ "description": "A variant's pinned conditions as a reader sees them: the pins the schema declares, plus a\nboolean `default` saying whether this is the entity's fallback.\n\n`default` is always present and always a boolean, so a client can branch on \"did I get the\nfallback?\" without knowing how one is stored. The reserved condition a fallback is actually\npinned under never appears here.\n",
4740
+ "properties": {
4741
+ "default": {
4742
+ "type": "boolean"
4743
+ }
4744
+ },
4745
+ "example": {
4746
+ "postal_code": "46045",
4747
+ "default": false
4748
+ }
4749
+ },
4750
+ "PinnedConditions": {
4751
+ "type": "object",
4752
+ "additionalProperties": true,
4753
+ "description": "The situation this variant applies to: a flat map keyed by condition name, as the entity's\nschema declares them. A condition left out is a wildcard — the variant applies whatever the\ncontext says for it, which is what makes adding a condition to a schema non-breaking for the\nvariants that already exist.\n\nExact values only. Predicates are accepted in a resolve context and nowhere else, so that\nmatching is decided in exactly one place.\n\nValues are typed by their condition and stored canonicalized for that type: a `date` becomes\nmillisecond-precision UTC, a `daterange` an object carrying `from` and `until` where an empty\nstring is an open end, a `location` of format `zipcode` the postal code itself and one of\nformat `zipcode + town` an object carrying both. A `select` value must be a string, and must\nbe one the condition's `options` declare unless it sets `allow_any`.\n\n`default`, and any name beginning with `_`, are reserved for the server and cannot be pinned\nhere. Whether a variant is the entity's fallback is set through the request's `default` flag.\n",
4754
+ "example": {
4755
+ "postal_code": "46045"
4756
+ }
4757
+ },
4758
+ "VariantValues": {
4759
+ "type": "object",
4760
+ "additionalProperties": true,
4761
+ "description": "The attribute values this version overrides on the base entity, keyed by attribute name.\n\nOnly attributes currently declaring `overridable_attribute` are applied. Metadata fields\n(anything underscore-prefixed), readonly attributes, hidden attributes and non-overridable\nattributes present here are ignored rather than rejected, so a client working from a slightly\nstale schema snapshot still succeeds instead of failing on fields it could not have known to\ndrop. An attribute's `render_condition` says when to show it and has no bearing on whether a\nvariant may override it.\n\nIgnored means *not updated*, never *removed*: a value already stored for an attribute that is\nnot currently overridable is preserved, so removing and restoring the flag deactivates and\nthen reactivates the same override.\n\nA composite price's `price_components` is an ordinary overridable relation attribute: a\ncomposite variant pins its component variants here the same way any other relation value is\nset, with no special handling.\n",
4762
+ "example": {
4763
+ "unit_amount": 2499,
4764
+ "unit_amount_decimal": "24.99"
4765
+ }
4766
+ },
4767
+ "CreatedVariant": {
4768
+ "type": "object",
4769
+ "required": [
4770
+ "variant_id",
4771
+ "entity_id",
4772
+ "schema",
4773
+ "conditions",
4774
+ "valid_from",
4775
+ "values",
4776
+ "warnings"
4777
+ ],
4778
+ "properties": {
4779
+ "variant_id": {
4780
+ "type": "string",
4781
+ "description": "Server-generated, always. This is the durable key orders and contracts pin, so it is never\naccepted from a client — a client-suppliable id would risk collisions between independent\nimporters.\n",
4782
+ "example": "var-46045"
4783
+ },
4784
+ "entity_id": {
4785
+ "type": "string",
4786
+ "example": "price-sp26d1yo"
4787
+ },
4788
+ "schema": {
4789
+ "$ref": "#/components/schemas/ConditionalEntitySlug"
4790
+ },
4791
+ "conditions": {
4792
+ "allOf": [
4793
+ {
4794
+ "$ref": "#/components/schemas/VariantConditions"
4795
+ }
4796
+ ],
4797
+ "description": "The situation this variant applies to, plus the boolean `default` discriminator — the\nsame shape `_conditions` has on a resolved payload.\n"
4798
+ },
4799
+ "valid_from": {
4800
+ "type": "string",
4801
+ "description": "When the first version takes effect, canonicalized to millisecond-precision UTC.",
4802
+ "example": "2027-01-01T00:00:00.000Z"
4803
+ },
4804
+ "values": {
4805
+ "$ref": "#/components/schemas/VariantValues"
4806
+ },
4807
+ "_created_at": {
4808
+ "type": "string"
4809
+ },
4810
+ "_updated_at": {
4811
+ "type": "string"
4812
+ },
4813
+ "_revision": {
4814
+ "type": "number",
4815
+ "description": "The revision a later write to this version must carry to be accepted. Genuinely current,\nunlike one read back later from an eventually-consistent read.\n"
4816
+ },
4817
+ "warnings": {
4818
+ "type": "array",
4819
+ "description": "Things worth knowing that did not stop the write. Empty in the ordinary case — a client\nreads its length rather than branching on its absence.\n",
4820
+ "items": {
4821
+ "$ref": "#/components/schemas/VariantWriteWarning"
4822
+ }
4823
+ }
4824
+ }
4825
+ },
4826
+ "VariantWriteWarning": {
4827
+ "type": "object",
4828
+ "required": [
4829
+ "code",
4830
+ "message"
4831
+ ],
4832
+ "properties": {
4833
+ "code": {
4834
+ "type": "string",
4835
+ "description": "- `VARIANT_COUNT_APPROACHING_CAP`: this entity is nearing the number of variants it may\n hold. Surfaced rather than rejected, so an importer finds out with a whole run's notice\n instead of discovering the limit halfway through a refresh.\n",
4836
+ "enum": [
4837
+ "VARIANT_COUNT_APPROACHING_CAP"
4838
+ ]
4839
+ },
4840
+ "message": {
4841
+ "type": "string"
4842
+ },
4843
+ "variant_count": {
4844
+ "type": "number",
4845
+ "description": "Variants this entity holds, including the one just created."
4846
+ },
4847
+ "cap": {
4848
+ "type": "number",
4849
+ "description": "Variants this entity may hold. Configurable per organization."
4850
+ }
4851
+ }
4852
+ },
4853
+ "DeletedVariant": {
4854
+ "type": "object",
4855
+ "required": [
4856
+ "variant_id",
4857
+ "entity_id",
4858
+ "schema",
4859
+ "tuple_released",
4860
+ "versions_deleted"
4861
+ ],
4862
+ "properties": {
4863
+ "variant_id": {
4864
+ "type": "string",
4865
+ "example": "var-46045"
4866
+ },
4867
+ "entity_id": {
4868
+ "type": "string",
4869
+ "example": "price-sp26d1yo"
4870
+ },
4871
+ "schema": {
4872
+ "$ref": "#/components/schemas/ConditionalEntitySlug"
4873
+ },
4874
+ "tuple_released": {
4875
+ "type": "boolean",
4876
+ "description": "Whether this call is the one that freed the variant's combination of condition values.\n`false` where an earlier, interrupted attempt had already freed it — the delete still\nsucceeded, and the combination was already reusable.\n"
4877
+ },
4878
+ "versions_deleted": {
4879
+ "type": "number",
4880
+ "description": "Version rows this call removed."
4881
+ }
4882
+ }
4883
+ },
4884
+ "VariantVersion": {
4885
+ "type": "object",
4886
+ "description": "One version of one variant: the attribute overrides it carries, the instant it takes effect,\nand the variant it belongs to.\n\nThese are the version's **own** overrides, not the base entity overlaid with them — this is\nwhat an editing screen loads and saves, and what it edits is the overrides. Composing them onto\nthe entity is what `:resolve` answers.\n",
4887
+ "required": [
4888
+ "variant_id",
4889
+ "entity_id",
4890
+ "schema",
4891
+ "conditions",
4892
+ "valid_from",
4893
+ "values"
4894
+ ],
4895
+ "properties": {
4896
+ "variant_id": {
4897
+ "type": "string",
4898
+ "example": "var-46045"
4899
+ },
4900
+ "entity_id": {
4901
+ "type": "string",
4902
+ "example": "price-sp26d1yo"
4903
+ },
4904
+ "schema": {
4905
+ "$ref": "#/components/schemas/ConditionalEntitySlug"
4906
+ },
4907
+ "conditions": {
4908
+ "allOf": [
4909
+ {
4910
+ "$ref": "#/components/schemas/VariantConditions"
4911
+ }
4912
+ ],
4913
+ "description": "The situation the variant applies to, plus the boolean `default` discriminator. A property\nof the variant rather than of this version: every version of a variant carries the same\none, and no version write can change it.\n"
4914
+ },
4915
+ "valid_from": {
4916
+ "type": "string",
4917
+ "description": "When this version takes effect, canonicalized to millisecond-precision UTC. A version's\nidentity within its variant — it never moves.\n",
4918
+ "example": "2027-01-01T00:00:00.000Z"
4919
+ },
4920
+ "values": {
4921
+ "$ref": "#/components/schemas/VariantValues"
4922
+ },
4923
+ "_created_at": {
4924
+ "type": "string"
4925
+ },
4926
+ "_updated_at": {
4927
+ "type": "string"
4928
+ },
4929
+ "_revision": {
4930
+ "type": "integer",
4931
+ "description": "The revision a write to this version must carry to be accepted. Always current: every read\nthat returns one is strongly consistent, so it is never a marker a write would be refused\nfor having read too early.\n",
4932
+ "example": 3
4933
+ }
4934
+ }
4935
+ },
4936
+ "WrittenVariantVersion": {
4937
+ "description": "A version as a write left it, together with anything the write moved.\n",
4938
+ "allOf": [
4939
+ {
4940
+ "$ref": "#/components/schemas/VariantVersion"
4941
+ },
4942
+ {
4943
+ "type": "object",
4944
+ "required": [
4945
+ "warnings"
4946
+ ],
4947
+ "properties": {
4948
+ "warnings": {
4949
+ "type": "array",
4950
+ "description": "What this write moved, if anything. Empty in the ordinary case — a client reads its\nlength rather than branching on its absence.\n",
4951
+ "items": {
4952
+ "$ref": "#/components/schemas/VersionWriteWarning"
4953
+ }
4954
+ }
4955
+ }
4956
+ }
4957
+ ]
4958
+ },
4959
+ "DeletedVariantVersion": {
4960
+ "type": "object",
4961
+ "required": [
4962
+ "variant_id",
4963
+ "entity_id",
4964
+ "schema",
4965
+ "valid_from",
4966
+ "warnings"
4967
+ ],
4968
+ "properties": {
4969
+ "variant_id": {
4970
+ "type": "string",
4971
+ "example": "var-46045"
4972
+ },
4973
+ "entity_id": {
4974
+ "type": "string",
4975
+ "example": "price-sp26d1yo"
4976
+ },
4977
+ "schema": {
4978
+ "$ref": "#/components/schemas/ConditionalEntitySlug"
4979
+ },
4980
+ "valid_from": {
4981
+ "type": "string",
4982
+ "description": "The version removed, canonicalized to millisecond-precision UTC.",
4983
+ "example": "2027-01-01T00:00:00.000Z"
4984
+ },
4985
+ "warnings": {
4986
+ "type": "array",
4987
+ "description": "What the delete moved, if anything. Empty when a scheduled version was withdrawn.",
4988
+ "items": {
4989
+ "$ref": "#/components/schemas/VersionWriteWarning"
4990
+ }
4991
+ }
4992
+ }
4993
+ },
4994
+ "VersionWriteWarning": {
4995
+ "type": "object",
4996
+ "description": "Something a version write moved. A version write is never refused for being late — backdating a\nversion, and editing or deleting one that has already been superseded, are both accepted — so\nwhat a caller gets instead is a warning naming exactly what changed. One write can carry both\ncodes.\n",
4997
+ "required": [
4998
+ "code",
4999
+ "message",
5000
+ "valid_from"
5001
+ ],
5002
+ "properties": {
5003
+ "code": {
5004
+ "type": "string",
5005
+ "description": "- `ACTIVE_VERSION_REPLACED`: what resolves **now** changed, other than by a newer version\n taking effect. The version in effect was written behind, or removed.\n- `SUPERSEDED_VERSION_WRITTEN`: what a past-dated (`as_of`) read returns changed. The write\n landed on, or created, a version that is not the one currently in effect.\n",
5006
+ "enum": [
5007
+ "ACTIVE_VERSION_REPLACED",
5008
+ "SUPERSEDED_VERSION_WRITTEN"
5009
+ ]
5010
+ },
5011
+ "message": {
5012
+ "type": "string"
5013
+ },
5014
+ "valid_from": {
5015
+ "type": "string",
5016
+ "description": "The version this write created, changed or removed.",
5017
+ "example": "2026-08-01T00:00:00.000Z"
5018
+ },
5019
+ "active_valid_from": {
5020
+ "type": "string",
5021
+ "description": "The version in effect when the write landed, before it did. Absent when the variant had\nnone — every version of it still scheduled.\n",
5022
+ "example": "2026-01-01T00:00:00.000Z"
5023
+ }
5024
+ }
5025
+ },
5026
+ "AppendVersionRequest": {
5027
+ "type": "object",
5028
+ "additionalProperties": false,
5029
+ "required": [
5030
+ "values"
5031
+ ],
5032
+ "properties": {
5033
+ "valid_from": {
5034
+ "type": "string",
5035
+ "description": "When this version takes effect. Defaults to now.\n\nAn RFC 3339 date (`2026-01-01`, read as midnight UTC) or date-time\n(`2026-01-01T00:00:00Z`), to at most millisecond precision. Deliberately not declared as\n`format: date-time`, which would reject the plain-date form that this accepts.\n\nA date in the past is accepted and answered with warnings, never refused. A date the\nvariant already has a version at is refused as `VERSION_CONFLICT`.\n\n**Omit this to mean \"now\"** — that is the only spelling of now that is reliably silent. A\ntimestamp taken from the caller's own clock is already some milliseconds old when the\nserver judges it, which makes it a backdate, however small, and it is answered with the\nwarnings a backdate earns.\n",
5036
+ "example": "2027-01-01T00:00:00Z"
5037
+ },
5038
+ "values": {
5039
+ "$ref": "#/components/schemas/VariantValues"
5040
+ },
5041
+ "conditions": {
5042
+ "allOf": [
5043
+ {
5044
+ "$ref": "#/components/schemas/PinnedConditions"
5045
+ }
5046
+ ],
5047
+ "description": "Optional, and never applied: a variant's conditions are fixed when it is created. Accepted\nonly so that a client building its body from the version it loaded is not forced to strip\nthem out, and refused when they describe a different situation from the stored one.\n"
5048
+ }
5049
+ }
5050
+ },
5051
+ "ReplaceVersionRequest": {
5052
+ "type": "object",
5053
+ "additionalProperties": false,
5054
+ "required": [
5055
+ "values",
5056
+ "_revision"
5057
+ ],
5058
+ "properties": {
5059
+ "values": {
5060
+ "allOf": [
5061
+ {
5062
+ "$ref": "#/components/schemas/VariantValues"
5063
+ }
5064
+ ],
5065
+ "description": "The complete set of attribute overrides this version carries. An overridable attribute\nabsent from here stops being overridden.\n\nAttributes the variant may not override are ignored where this carries them, and their\n**stored value is kept rather than dropped** — otherwise a routine full-snapshot write\nwould erase an override the moment its attribute's `overridable_attribute`, `readonly` or\n`hidden` flag happened to be off.\n"
5066
+ },
5067
+ "_revision": {
5068
+ "type": "integer",
5069
+ "minimum": 1,
5070
+ "description": "The revision marker read from the version being written. The write is refused with\n`WRITE_CONFLICT` if the version has been written since.\n\nRequired rather than optional: an optional one is a guarantee every client can opt out of\nby forgetting a field, and the write it protects is the one that overwrites somebody\nelse's edit.\n",
5071
+ "example": 3
5072
+ },
5073
+ "valid_from": {
5074
+ "type": "string",
5075
+ "description": "Optional, and never applied. Accepted when it names the version being addressed — so a\nclient building its body from what it loaded need not strip it out — and refused when it\nnames another: a version's `valid_from` is its identity, and moving it is an append and a\ndelete rather than an edit.\n"
5076
+ },
5077
+ "conditions": {
5078
+ "allOf": [
5079
+ {
5080
+ "$ref": "#/components/schemas/PinnedConditions"
5081
+ }
5082
+ ],
5083
+ "description": "Optional, and never applied: a variant's conditions are fixed when it is created. Refused\nwhen they describe a different situation from the stored one.\n"
5084
+ }
5085
+ }
5086
+ },
5087
+ "PatchVersionRequest": {
5088
+ "type": "object",
5089
+ "additionalProperties": false,
5090
+ "required": [
5091
+ "values",
5092
+ "_revision"
5093
+ ],
5094
+ "properties": {
5095
+ "values": {
5096
+ "allOf": [
5097
+ {
5098
+ "$ref": "#/components/schemas/VariantValues"
5099
+ }
5100
+ ],
5101
+ "description": "Only the attribute overrides to change. Everything not mentioned is left as stored.\n\n`null` is a value like any other here rather than a deletion; to stop overriding an\nattribute, send the complete snapshot without it through the replace operation.\n"
5102
+ },
5103
+ "_revision": {
5104
+ "type": "integer",
5105
+ "minimum": 1,
5106
+ "description": "The revision marker read from the version being written. The write is refused with\n`WRITE_CONFLICT` if the version has been written since.\n",
5107
+ "example": 3
5108
+ },
5109
+ "valid_from": {
5110
+ "type": "string",
5111
+ "description": "Optional, never applied, and refused when it names a version other than the one addressed."
5112
+ },
5113
+ "conditions": {
5114
+ "allOf": [
5115
+ {
5116
+ "$ref": "#/components/schemas/PinnedConditions"
5117
+ }
5118
+ ],
5119
+ "description": "Optional, and never applied. A partial update that tries to change a pinned condition value\nis refused — this is the path that rule is most likely to be broken on by accident.\n"
5120
+ }
5121
+ }
3448
5122
  },
3449
5123
  "Error": {
3450
5124
  "required": [