Sources
Each rule is tagged with where it comes from.
- [API] products API spec, im-web
packages/openapi-client/schemas/products.jsonat d62190c. The live API docs (below) show what the team is working on now and may have moved on. - [Code] im-admin / im-public in im-web, branch
feature/LIP-1338-scopes-real-apias of 2026-10-05: d8821ea. - [UI] text or behaviour seen on screen during the tests.
- [Said] stated by the team during the tests (mostly Ferdinand, UX).
- [Today] how NTB works today, per the testers.
- [Open] undecided or unverified.
Live API docs on the test environment, one per API. They change with the team's current work; cite a schema at an im-web commit for a stable reference.
| API | Covers | Swagger | Spec |
|---|---|---|---|
| products | scopes, scope parameters, metadata fields, licenses, products, prices, subscriptions, price lists, price resolver | UI | JSON, YAML |
| sales | suppliers, supplier mappings, distributor config, downloads and purchases | UI | JSON, YAML |
| user | tenants, users, roles, workspaces, enterprise organizations | UI | JSON, YAML |
| search | media search, media objects | UI | JSON, YAML |
| indexer | tenant indices, reindexing | UI | JSON, YAML |
Content: what can be sold
- A metadata field is an asset property and its possible values, e.g.
distributor: NTB, AP, AFP. It has a key, a label and a data type (enum, multi-enum, free text, date, number). Developers set them up. [API] [UI] - A scope parameter is a filter scopes can use, built on one or more metadata fields (e.g. Credit uses
creditandowner, Dates usesdateCreatedanddateArchived). It has a field type, can be required, and is in use or unused. System admins set them up. [API] [UI] - A main group (primary scope) is a saved filter: chosen values for scope parameters, e.g. Archive = SDL and Media family = editorial. Every required parameter gets one value. [API] [Code]
- A content group (secondary scope) narrows one main group by setting more scope parameters. It keeps the main group's values. [API]
- Filter logic: AND across parameters, OR within a multi-value parameter. An unset parameter doesn't filter. [Code]
- Selections are explicit value-id lists. There is no "all except" and no "all, including future values". [API]
- A content group can be saved with no parameters. It then equals its main group. [Code]
- Content groups have a priority order within their main group. It decides which applies when groups overlap. [Code] [Open: backend semantics]
- New assets that match a filter join it automatically. [Said]
Licenses
- A license is a name plus a description (terms text). Nothing else. [API]
- Every license belongs to exactly one license group. Licenses can't be shared between groups. [API]
- A license group can be linked to scopes (
scopeIds). [API] - The license description is shown to customers on the purchase panel. [UI] [Code]
- The admin requires the description. The API doesn't. [Code]
- Licenses carry no usage dimensions (channel, duration, reach, paid promotion). [API]
Products and variants
- A product = one main group + one license group + a base price per selected license. [API]
- A product can include a subset of its license group's licenses. [UI]
- A variant is a product of type
variantwith a parent product. It points at a content group and has its own base prices. [API] - Each main group should be used by one product. Not enforced in the admin. [Said] [Open]
- A license group can serve many products. [Said]
- Product
stateisdraftorpublished. [API] - No admin screen sets the state. Every product stays Draft. [Code]
- Draft products are still priced on the public site. [UI] [Open: is that intended?]
Prices
- A base price is per license, per product, per download. [API]
- Each base price has
validFrom/validTo. [API] - The admin always saves base prices valid from now for 100 years. Price changes can't be scheduled. [Code]
- Currency: NOK only. [API]
- Prices are shown "in NOK, VAT (25%) excluded" on the public site. [UI]
- The price customers see without an agreement is the "Global" price. [Said, Test 2] [Open: exact definition]
Customer-specific terms
Both point at a customer group (customerGroupId). The admin UI calls it "Workspace". [API] [UI]
- Ferdinand: it should be "Customer Group", to choose either single companies or global. [Said]
Discounts and premiums (API: price list)
- One price list = one customer group + one product + optional validity dates. [API]
- Each item targets one base price, with either an
overridePriceor adiscountPercentage. [API] - A percentage follows base price changes. A fixed override doesn't. [Code, per audit]
- A premium is a price above base. [UI]
Subscriptions
- One subscription = one customer group + one product + a license group + included licenses + price + validity dates. [API]
- Type
time: unlimited downloads within the date range, for a fixed price. [API] [UI] - Type
quota: a fixed number of downloads for the period. Access stops when the quota is reached. [API] [UI] - Each included license can have its own
quantityLimit. [API] - A subscription can be disabled. Disabled subscriptions can't be used to resolve prices. [UI]
- A subscription customer can still buy other uses at their own price. [Said, "that's the plan"]
- After a subscription was created in Test 2, the public page still showed a purchase price, not a download. [UI] [Open: bug or not built]
Price resolution
POST /api/v1/price-resolvertakes an asset's metadata and acustomerGroupId. [API]- It returns one product for the asset, with per-license base price, validity, and any subscription and price list that apply. [API]
- It does not return a final price or which rule won. [API]
- im-public uses it on the asset page. The admin doesn't. [Code]
- Precedence between subscription, discount, variant and base price is undefined. [Open]
Customer side
- The asset page shows a purchase panel: license options with price, an instructions box, and "Add to cart". [UI]
- The last license option should be "I can't find the license I need", leading to the customer centre. [Said]
- Logged-in customers with a subscription should see a direct download. [Said, not built]
- Re-download of purchased images will have a time limit. [Said] [Open: how long]
- Private customers (e.g. a print for the wall) should be able to buy without contacting the customer centre. [Today, Test 2 wish]
- Scandinavian Creative will have a lower threshold for anyone to buy. [Said]
- Editorial images can be visible but not buyable until the customer is approved. [Said, earlier FigJam board]
- Magnum images are sold only with Magnum's approval. [Today, Test 2]
Markets and languages
- Tenants: NTB and TT (Swedish) at least. Tests ran on TT. [UI]
- The product is white label for Sweden, Finland and Denmark. [Said]
- Customer side in Norwegian and English. Admin maybe English only. [Said]
- Names and license text are single-language today. [API]
How it works today
- A legacy contract system holds customer agreements. [Today]
- Exclusions use priority layering: a broad contract plus a higher-priority "not this" contract (e.g. no NYT). [Today, Test 1]
- Most customers have tailor-made deals. [Today]
- The customer centre sets up subscriptions, "klippekort" (download bundles), per-customer prices and private customer sales. [Today, Test 2]
- Usage is negotiated per order by email: channel, duration, accounts, paid promotion. [Today, Test 1]
- Rollout is likely gradual, e.g. Amedia first, with old and new systems in parallel. [Said]
Open questions
- Price precedence: agreement, subscription, discount, variant, base.
- What Draft means for sales, and how publishing works.
- Exclude rules and "all, including future values".
- One main group per product: enforced or not.
- Content group overlap and priority semantics.
- Usage dimensions on licenses.
- An agreement object per customer or enterprise.
- Re-download rules and time limits.
- Approval gating (editorial, Magnum): who approves, where it's stored.
- "Global" customer group: what it is and how it's set.
- Which texts customers see, and in which languages.
Corrections to the order statechart assumptions
Assumptions made in the earlier order statechart prototype, and what we know now.
| Assumption in the statechart | What we now know |
|---|---|
| List price 1 200 kr, VAT 25% at checkout | Base price per license per product. Tests used 1 711 kr. Shown "VAT (25%) excluded". |
| Custom price is 15% off | Discount or premium per customer group and product, as a percentage or a fixed override per license. |
| Subscription: 12 months, 4 900 kr | Time-limited: unlimited downloads in a date range, fixed price. Any dates. |
| Pack: 3 images, 2 900 kr | "Per quota" subscription (today: "klippekort"). Download limit per subscription and per license. |
| "Select customer" step dropped | Real form selects a customer group ("Workspace" in UI, to be renamed). |
| "Choose licenses that fit usage" | Subscription picks included licenses from the product's license group. |
| Customer contacts support via phone, email, chat | Planned as a last license option: "I can't find the license I need". |
| Subscription holder downloads directly | Planned. Not built: Test 2 still showed a purchase price. |
| Editorial gating (not modelled) | Confirmed as an idea. Also supplier approval (Magnum). |