{
  "openapi": "3.1.1",
  "info": {
    "title": "Pricing",
    "description": "**This API specification is a draft and is not yet implemented. Endpoints, schemas, and\nbehavior are subject to change without notice.**\n\nThis API provides services to read and maintain fare tables (pricing) for public transport in Norway.\n\nPrices live only on fare tables — products do not carry a price of their own; a fare table\nprices them via `pricesFor` (FareTable → PriceableObject). Only flat pricing is implemented\ntoday: zone-pair, stop-pair and interval selectors are documented on `FarePriceEntry` but\nrejected with 400 `PRICE_MODEL_NOT_IMPLEMENTED` until built.\n",
    "contact": {
      "name": "Team Produkt",
      "email": "teamprodukt@entur.org"
    },
    "version": "2026.10.0",
    "x-stability-level": "draft"
  },
  "servers": [
    {
      "url": "https://api.entur.io/products",
      "description": "Production environment"
    },
    {
      "url": "https://api.staging.entur.io/products",
      "description": "Staging environment"
    },
    {
      "url": "https://api.dev.entur.io/products",
      "description": "Development environment"
    }
  ],
  "security": [
    {
      "jwt": []
    }
  ],
  "tags": [
    {
      "name": "Fare table",
      "description": "A fare table holds the price(s) that a product references. A flat price is a\ntable with a single selector-less entry; per-zone or per-distance pricing use\nthe same shape with selector fields filled in. The table is versioned\nindependently of the products that reference it.\n"
    },
    {
      "name": "Version",
      "description": "Version management endpoints"
    }
  ],
  "paths": {
    "/v3/fare-tables": {
      "post": {
        "tags": [
          "Fare table"
        ],
        "summary": "Create a new fare table",
        "description": "Create a new fare table. A new version will be created with version number 1.\n\nAll prices in products-api are stored as a fare table — a flat price is a\ntable with a single selector-less entry. The table is versioned\nindependently of the products that reference it.\n\nOnly flat pricing is implemented: prices carry no zone or interval selectors, optionally\ndifferentiated by `userProfile`. Zone-pair and interval selectors are documented on\n`FarePriceEntry` and return 400 `PRICE_MODEL_NOT_IMPLEMENTED` until built.\n",
        "operationId": "createFareTable",
        "requestBody": {
          "description": "Fare table to be created.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FareTableRequest"
              },
              "examples": {
                "flat": {
                  "$ref": "#/components/examples/flat"
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Fare table created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FareTableResponse"
                },
                "examples": {
                  "flat": {
                    "$ref": "#/components/examples/flat-2"
                  }
                }
              }
            }
          },
          "400": {
            "description": "The request is invalid — either a schema violation, or a well-formed\nrequest that cannot be processed: an unsupported price `type` (only the\nflat `FlatPrice` is implemented), an amount with too many decimals for the\ncurrency, an unknown currency, or a violated fare-table invariant.\n",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "schemaViolation": {
                    "summary": "Request does not match schema",
                    "value": {
                      "type": "https://developer.entur.org/errors/bad-request",
                      "title": "Bad Request",
                      "status": 400,
                      "detail": "Field 'prices' is required."
                    }
                  },
                  "unsupportedPriceType": {
                    "summary": "Unsupported price type",
                    "value": {
                      "type": "https://developer.entur.org/errors/bad-request",
                      "title": "Bad Request",
                      "status": 400,
                      "detail": "Only the flat 'FlatPrice' price type is supported."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "409": {
            "description": "Conflict - Fare table already exists",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "conflict": {
                    "summary": "Fare table already exists",
                    "value": {
                      "type": "https://developer.entur.org/errors/conflict",
                      "title": "Conflict",
                      "status": 409,
                      "detail": "Fare table with privateCode 'bike-supplement' already exists."
                    }
                  }
                }
              }
            }
          }
        },
        "x-entur-permissions": {
          "value": "product-api-access:endre"
        }
      },
      "parameters": [
        {
          "$ref": "#/components/parameters/ET-Client-Name"
        },
        {
          "$ref": "#/components/parameters/X-Correlation-Id"
        }
      ]
    },
    "/v3/fare-tables/{id}": {
      "get": {
        "tags": [
          "Fare table"
        ],
        "summary": "Get the active version of a fare table",
        "description": "Retrieve the version of the fare table that is active on the given date.\nDefaults to the version active today when no date is given.\n",
        "operationId": "getFareTable",
        "parameters": [
          {
            "$ref": "#/components/parameters/id"
          },
          {
            "$ref": "#/components/parameters/validOnDate"
          }
        ],
        "responses": {
          "200": {
            "description": "The fare table version active on the given date.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FareTableResponse"
                },
                "examples": {
                  "flat": {
                    "$ref": "#/components/examples/flat-2"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "description": "Fare table not found, or no version is active on the given date",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "notFound": {
                    "summary": "Fare table not found",
                    "value": {
                      "type": "https://developer.entur.org/errors/not-found",
                      "title": "Not Found",
                      "status": 404,
                      "detail": "FareTable 'EXA:FareTable:bike-supplement' not found."
                    }
                  },
                  "noActiveVersion": {
                    "summary": "No version active on the given date",
                    "value": {
                      "type": "https://developer.entur.org/errors/not-found",
                      "title": "Not Found",
                      "status": 404,
                      "detail": "No version of FareTable 'EXA:FareTable:bike-supplement' is active on 2026-12-01."
                    }
                  }
                }
              }
            }
          }
        },
        "x-entur-permissions": {
          "value": "product-api-access:les"
        }
      },
      "post": {
        "tags": [
          "Fare table"
        ],
        "summary": "Create a new version of an existing fare table",
        "description": "Create a new version of an existing fare table — this is how a price\nchanges. The referencing products are not modified: they point at the\ntable's id, and the effective version is resolved by validity period.\n",
        "operationId": "createFareTableVersion",
        "parameters": [
          {
            "$ref": "#/components/parameters/id"
          }
        ],
        "requestBody": {
          "description": "The new fare table version.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FareTableRequest"
              },
              "examples": {
                "flat": {
                  "$ref": "#/components/examples/flat"
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Fare table version created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FareTableResponse"
                },
                "examples": {
                  "flat": {
                    "$ref": "#/components/examples/flat-2"
                  }
                }
              }
            }
          },
          "400": {
            "description": "The request is invalid — either a schema violation, or a well-formed\nrequest that cannot be processed: an unsupported price `type` (only the\nflat `FlatPrice` is implemented), an amount with too many decimals for the\ncurrency, an unknown currency, or a violated fare-table invariant.\n",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "schemaViolation": {
                    "summary": "Request does not match schema",
                    "value": {
                      "type": "https://developer.entur.org/errors/bad-request",
                      "title": "Bad Request",
                      "status": 400,
                      "detail": "Field 'prices' is required."
                    }
                  },
                  "unsupportedPriceType": {
                    "summary": "Unsupported price type",
                    "value": {
                      "type": "https://developer.entur.org/errors/bad-request",
                      "title": "Bad Request",
                      "status": 400,
                      "detail": "Only the flat 'FlatPrice' price type is supported."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "description": "Fare table not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "notFound": {
                    "summary": "Fare table not found",
                    "value": {
                      "type": "https://developer.entur.org/errors/not-found",
                      "title": "Not Found",
                      "status": 404,
                      "detail": "FareTable 'ENT:FareTable:bike-supplement' not found."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict - Fare table already exists",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "conflict": {
                    "summary": "Fare table already exists",
                    "value": {
                      "type": "https://developer.entur.org/errors/conflict",
                      "title": "Conflict",
                      "status": 409,
                      "detail": "Fare table with privateCode 'bike-supplement' already exists."
                    }
                  }
                }
              }
            }
          }
        },
        "x-entur-permissions": {
          "value": "product-api-access:endre"
        }
      },
      "parameters": [
        {
          "$ref": "#/components/parameters/ET-Client-Name"
        },
        {
          "$ref": "#/components/parameters/X-Correlation-Id"
        }
      ]
    },
    "/v3/fare-tables/{id}/{version}": {
      "get": {
        "tags": [
          "Fare table"
        ],
        "summary": "Get a specific fare table version",
        "description": "Retrieve the complete fare table for a specific version, identified by\nNeTEx version id or version number.\n",
        "operationId": "getFareTableVersion",
        "parameters": [
          {
            "$ref": "#/components/parameters/id"
          },
          {
            "$ref": "#/components/parameters/version"
          }
        ],
        "responses": {
          "200": {
            "description": "The fare table version",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FareTableResponse"
                },
                "examples": {
                  "flat": {
                    "$ref": "#/components/examples/flat-2"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "description": "Fare table or version not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "notFound": {
                    "summary": "Fare table version not found",
                    "value": {
                      "type": "https://developer.entur.org/errors/not-found",
                      "title": "Not Found",
                      "status": 404,
                      "detail": "Version 'ENT:Version:8f1b2c3d' not found for FareTable 'ENT:FareTable:bike-supplement'."
                    }
                  }
                }
              }
            }
          }
        },
        "x-entur-permissions": {
          "value": "product-api-access:les"
        }
      },
      "put": {
        "tags": [
          "Fare table"
        ],
        "summary": "Update an existing fare table version",
        "description": "Update the version of a fare table in place. The version will not be\nactive until a start date is set and the version is published.\n",
        "operationId": "updateFareTableVersion",
        "parameters": [
          {
            "$ref": "#/components/parameters/id"
          },
          {
            "$ref": "#/components/parameters/version"
          }
        ],
        "requestBody": {
          "description": "The updated version of the fare table. The existing data in the version will be replaced by this one.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FareTableRequest"
              },
              "examples": {
                "flat": {
                  "$ref": "#/components/examples/flat"
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Fare table version updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FareTableResponse"
                },
                "examples": {
                  "flat": {
                    "$ref": "#/components/examples/flat-2"
                  }
                }
              }
            }
          },
          "400": {
            "description": "The request is invalid — either a schema violation, or a well-formed\nrequest that cannot be processed: an unsupported price `type` (only the\nflat `FlatPrice` is implemented), an amount with too many decimals for the\ncurrency, an unknown currency, or a violated fare-table invariant.\n",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "schemaViolation": {
                    "summary": "Request does not match schema",
                    "value": {
                      "type": "https://developer.entur.org/errors/bad-request",
                      "title": "Bad Request",
                      "status": 400,
                      "detail": "Field 'prices' is required."
                    }
                  },
                  "unsupportedPriceType": {
                    "summary": "Unsupported price type",
                    "value": {
                      "type": "https://developer.entur.org/errors/bad-request",
                      "title": "Bad Request",
                      "status": 400,
                      "detail": "Only the flat 'FlatPrice' price type is supported."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "description": "Fare table or version not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "notFound": {
                    "summary": "Fare table version not found",
                    "value": {
                      "type": "https://developer.entur.org/errors/not-found",
                      "title": "Not Found",
                      "status": 404,
                      "detail": "Version 'ENT:Version:8f1b2c3d' not found for FareTable 'ENT:FareTable:bike-supplement'."
                    }
                  }
                }
              }
            }
          }
        },
        "x-entur-permissions": {
          "value": "product-api-access:endre"
        }
      },
      "parameters": [
        {
          "$ref": "#/components/parameters/ET-Client-Name"
        },
        {
          "$ref": "#/components/parameters/X-Correlation-Id"
        }
      ]
    },
    "/v3/versions/{id}": {
      "get": {
        "tags": [
          "Version"
        ],
        "summary": "Get a version by ID",
        "description": "Retrieve a specific version by its netex ID.",
        "operationId": "getVersionById",
        "parameters": [
          {
            "$ref": "#/components/parameters/id"
          }
        ],
        "responses": {
          "200": {
            "description": "Version found successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VersionResponse"
                },
                "examples": {
                  "draftVersion": {
                    "$ref": "#/components/examples/draftVersion"
                  },
                  "versionedVersion": {
                    "$ref": "#/components/examples/versionedVersion"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "invalidTransition": {
                    "summary": "Invalid ID format",
                    "value": {
                      "type": "https://example.com/probs/illegal-transition",
                      "title": "Illegal status transition",
                      "status": 400,
                      "detail": "Invalid netex ID format"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "description": "Version not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "notFound": {
                    "summary": "Version not found",
                    "value": {
                      "type": "https://example.com/probs/not-found",
                      "title": "Not Found",
                      "status": 404,
                      "detail": "Version ENT:Version:001 not found."
                    }
                  }
                }
              }
            }
          }
        },
        "x-entur-permissions": {
          "value": "product-api-access:les"
        }
      },
      "put": {
        "tags": [
          "Version"
        ],
        "summary": "Update an existing version",
        "description": "Update an existing version. Can be used to change status (e.g., from DRAFT to PROPOSED or PROPOSED to VERSIONED) or modify dates.",
        "operationId": "updateVersion",
        "parameters": [
          {
            "$ref": "#/components/parameters/id"
          }
        ],
        "requestBody": {
          "description": "The request body must include the new status and startDate. The endDate is optional. Valid status transitions are:\n  - DRAFT -> PROPOSED\n  - PROPOSED -> VERSIONED\n  - DRAFT -> DEPRECATED\n  - PROPOSED -> DEPRECATED\n",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VersionRequest"
              },
              "examples": {
                "draft": {
                  "$ref": "#/components/examples/draft"
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Version updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VersionResponse"
                },
                "examples": {
                  "draftVersion": {
                    "$ref": "#/components/examples/draftVersion"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request - Invalid data or illegal status transition",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "invalidTransition": {
                    "summary": "Illegal status transition",
                    "value": {
                      "type": "https://example.com/probs/illegal-transition",
                      "title": "Illegal status transition",
                      "status": 400,
                      "detail": "Invalid status transition: DRAFT -> $to"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "description": "Version not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "notFound": {
                    "summary": "Version not found",
                    "value": {
                      "type": "https://example.com/probs/not-found",
                      "title": "Not Found",
                      "status": 404,
                      "detail": "Version ENT:Version:001 not found."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict - Version already exists or overlaps with existing version",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "conflict": {
                    "summary": "Version already exists",
                    "value": {
                      "type": "https://example.com/probs/conflict",
                      "title": "Conflict",
                      "status": 409,
                      "detail": "Version ENT:Version:001 exists already."
                    }
                  }
                }
              }
            }
          }
        },
        "x-entur-permissions": {
          "value": "product-api-access:endre"
        }
      },
      "parameters": [
        {
          "$ref": "#/components/parameters/ET-Client-Name"
        },
        {
          "$ref": "#/components/parameters/X-Correlation-Id"
        }
      ]
    },
    "/v3/versions": {
      "post": {
        "tags": [
          "Version"
        ],
        "summary": "Create a new version",
        "description": "Create a new version in DRAFT status. The version will be assigned the current date as startDate if not provided.",
        "operationId": "createVersion",
        "requestBody": {
          "description": "The request body must include the netex ID and status (must be DRAFT). The startDate is optional and will default to the current date if not provided. The endDate is also optional.\n",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VersionRequest"
              },
              "examples": {
                "draft": {
                  "$ref": "#/components/examples/draft"
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Version created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VersionResponse"
                },
                "examples": {
                  "draftVersion": {
                    "$ref": "#/components/examples/draftVersion"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "invalidStatus": {
                    "summary": "Illegal status",
                    "value": {
                      "type": "https://example.com/probs/illegal-transition",
                      "title": "Illegal status for new version",
                      "status": 400,
                      "detail": "Invalid version status VERSIONED. New versions must be created with status DRAFT."
                    }
                  },
                  "invalidDate": {
                    "summary": "Illegal date",
                    "value": {
                      "type": "https://example.com/probs/illegal-transition",
                      "title": "Illegal date for new version",
                      "status": 400,
                      "detail": "Invalid version dates: endDate must be strictly after startDate."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "conflict": {
                    "summary": "Version already exists",
                    "value": {
                      "type": "https://example.com/probs/conflict",
                      "title": "Conflict",
                      "status": 409,
                      "detail": "Version ENT:Version:001 exists already."
                    }
                  },
                  "inProgress": {
                    "summary": "Version already in progress",
                    "value": {
                      "type": "https://example.com/probs/conflict",
                      "title": "Conflict with other in progress",
                      "status": 409,
                      "detail": "Cannot create new version: ENT:Version:001 are already in PROPOSED (only one in-progress version allowed)."
                    }
                  }
                }
              }
            }
          }
        },
        "x-entur-permissions": {
          "value": "product-api-access:endre"
        }
      },
      "parameters": [
        {
          "$ref": "#/components/parameters/ET-Client-Name"
        },
        {
          "$ref": "#/components/parameters/X-Correlation-Id"
        }
      ]
    },
    "/v3/versions/history/{id}": {
      "get": {
        "tags": [
          "Version"
        ],
        "summary": "Get version history for a versionable element by ID",
        "description": "Retrieve the list for all version that is related to the given versionable element.",
        "operationId": "getVersionHistoryById",
        "parameters": [
          {
            "$ref": "#/components/parameters/id"
          }
        ],
        "responses": {
          "200": {
            "description": "Version history found successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/VersionResponse"
                  }
                },
                "examples": {
                  "versionHistory": {
                    "$ref": "#/components/examples/versionHistory"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "invalidTransition": {
                    "summary": "Invalid ID format",
                    "value": {
                      "type": "https://example.com/probs/illegal-transition",
                      "title": "Illegal status transition",
                      "status": 400,
                      "detail": "Invalid NetEx ID format"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          }
        },
        "x-entur-permissions": {
          "value": "product-api-access:les"
        }
      },
      "parameters": [
        {
          "$ref": "#/components/parameters/ET-Client-Name"
        },
        {
          "$ref": "#/components/parameters/X-Correlation-Id"
        }
      ]
    }
  },
  "components": {
    "schemas": {
      "LocalizedString": {
        "type": "array",
        "items": {
          "required": [
            "lang",
            "value"
          ],
          "type": "object",
          "properties": {
            "lang": {
              "pattern": "^[a-z]{2}-[A-Z]{2}$",
              "type": "string",
              "description": "BCP-47 language tag (e.g., 'nb-NO', 'en-GB').",
              "examples": [
                "nb-NO"
              ]
            },
            "value": {
              "type": "string",
              "description": "The localized string value for the specified lang."
            }
          }
        }
      },
      "VersionStatus": {
        "type": "string",
        "enum": [
          "DRAFT",
          "PROPOSED",
          "VERSIONED",
          "DEPRECATED"
        ]
      },
      "FarePriceType": {
        "type": "string",
        "description": "Discriminator for a fare table price cell. Only the flat `FlatPrice` (a fixed amount with no\nselectors, NeTEx `FarePrice`) is implemented today; `DistanceMatrixElementPrice` and\n`GeographicalIntervalPrice` will be added as sibling types when the price model is extended\nbeyond flat prices.\n",
        "enum": [
          "FlatPrice"
        ],
        "examples": [
          "FlatPrice"
        ]
      },
      "FarePriceEntry": {
        "required": [
          "amount",
          "currency",
          "type"
        ],
        "type": "object",
        "properties": {
          "type": {
            "$ref": "#/components/schemas/FarePriceType"
          },
          "amount": {
            "pattern": "^[0-9]+(\\.[0-9]+)?$",
            "type": "string",
            "description": "The price in the major unit of this entry's `currency`, as a decimal string (for example\n\"49.00\"). The number of decimals must not exceed what that currency allows — 2 for NOK and\nEUR, 0 for JPY, 3 for KWD.\n",
            "examples": [
              "49.00"
            ]
          },
          "currency": {
            "pattern": "^[A-Z]{3}$",
            "type": "string",
            "description": "ISO 4217 currency code for this individual price, per NeTEx `FarePrice.Currency`. Required:\nthe flat `amount` cannot be interpreted without knowing its currency (the number of decimals\ndepends on it). Different entries in the same fare table may declare different currencies.\n",
            "examples": [
              "NOK"
            ]
          }
        },
        "description": "A single NeTEx-typed price, held as a cell of the fare table.\n\nEach price is an explicit NeTEx price object identified by its `type` (the NeTEx class). Only\nthe flat `FlatPrice` is implemented today: a fixed amount with no origin/destination, interval\nor passenger-type selectors. The richer NeTEx price types — `DistanceMatrixElementPrice` for an\norigin/destination pair, `GeographicalIntervalPrice` for a counted interval, each optionally\ncarrying a `LimitingRule` for discounts and caps — will be added as sibling `type`s when the\nmodel is extended, so clients can already branch on `type`.\n"
      },
      "FareTableRequest": {
        "required": [
          "prices",
          "startDate",
          "status"
        ],
        "type": "object",
        "properties": {
          "ownerOrganisationId": {
            "minimum": 1,
            "type": "integer",
            "description": "Internal id of the organisation that owns this element. Omit it to use the organisation in the access token, which is what a caller acting for itself should do. Supplying a different organisation requires permission to act on behalf of that organisation.",
            "format": "int64",
            "examples": [
              1
            ]
          },
          "names": {
            "$ref": "#/components/schemas/LocalizedString"
          },
          "descriptions": {
            "$ref": "#/components/schemas/LocalizedString"
          },
          "startDate": {
            "type": "string",
            "description": "First day this price version is valid.",
            "format": "date",
            "examples": [
              "2026-08-01"
            ]
          },
          "endDate": {
            "type": "string",
            "description": "Last day this price version is valid (optional). Omit for an open-ended version.",
            "format": "date",
            "examples": [
              "2026-12-31"
            ]
          },
          "status": {
            "allOf": [
              {
                "$ref": "#/components/schemas/VersionStatus"
              },
              {
                "description": "Status of the fare table version. Required; on create only DRAFT or\nPROPOSED is accepted — a new version cannot be published directly.\n\n- **DRAFT** - Under construction and not ready for operational use.\n- **PROPOSED** - Complete but pending review and approval.\n- **VERSIONED** - Finalized and frozen; a new version must be created for further modifications. Remains authoritative for its validity period even after expiry.\n- **DEPRECATED** - Explicitly withdrawn and should not be used; indicates an active decision to retract, not a natural expiry.\n",
                "examples": [
                  "DRAFT"
                ]
              }
            ]
          },
          "prices": {
            "minItems": 1,
            "type": "array",
            "description": "The prices in this table. Each entry must be uniquely identified by its selector\ncombination, so a flat price with no passenger-type differentiation is a single\nselector-less entry. Each entry carries its own optional `currency`, per NeTEx.\n",
            "items": {
              "$ref": "#/components/schemas/FarePriceEntry"
            }
          }
        }
      },
      "FareTableResponse": {
        "required": [
          "id",
          "ownerOrganisationId",
          "prices",
          "startDate",
          "status",
          "versionId"
        ],
        "type": "object",
        "properties": {
          "id": {
            "pattern": "^([A-Z]{3}):FareTable:([0-9A-Za-z_\\-]*)$",
            "type": "string",
            "description": "NeTEx id of the fare table.",
            "examples": [
              "ENT:FareTable:bike-supplement"
            ]
          },
          "versionId": {
            "pattern": "^([A-Z]{3}):Version:([0-9A-Za-z_\\-]*)$",
            "type": "string",
            "description": "NeTEx id of this fare table version.",
            "examples": [
              "ENT:Version:8f1b2c3d"
            ]
          },
          "ownerOrganisationId": {
            "type": "integer",
            "description": "Internal id of the organisation that owns this fare table.",
            "format": "int64",
            "examples": [
              1
            ]
          },
          "names": {
            "$ref": "#/components/schemas/LocalizedString"
          },
          "descriptions": {
            "$ref": "#/components/schemas/LocalizedString"
          },
          "startDate": {
            "type": "string",
            "description": "First day this price version is valid.",
            "format": "date",
            "examples": [
              "2026-08-01"
            ]
          },
          "endDate": {
            "type": "string",
            "description": "Last day this price version is valid (optional). Omit for an open-ended version.",
            "format": "date",
            "examples": [
              "2026-12-31"
            ]
          },
          "status": {
            "allOf": [
              {
                "$ref": "#/components/schemas/VersionStatus"
              },
              {
                "description": "Status of the fare table version.\n\n- **DRAFT** - Under construction and not ready for operational use.\n- **PROPOSED** - Complete but pending review and approval.\n- **VERSIONED** - Finalized and frozen; a new version must be created for further modifications. Remains authoritative for its validity period even after expiry.\n- **DEPRECATED** - Explicitly withdrawn and should not be used; indicates an active decision to retract, not a natural expiry.\n",
                "examples": [
                  "VERSIONED"
                ]
              }
            ]
          },
          "prices": {
            "type": "array",
            "description": "The prices in this table. Each entry echoes its own `currency`, per NeTEx\n`FarePrice.Currency`.\n",
            "items": {
              "$ref": "#/components/schemas/FarePriceEntry"
            }
          },
          "pricesFor": {
            "type": "array",
            "description": "NeTEx ids of the priceable objects (e.g. supplement products) this fare table prices —\nNeTEx `FareTable.pricesFor`.\n\nThe FareTable → PriceableObject link is deliberately loose: a versioned fare table prices a\npriceable object *by netex id only*, never pinned to a specific priceable object version.\nVersion resolution happens later, when the product tree is built.\n",
            "readOnly": true,
            "items": {
              "pattern": "^([A-Z]{3}):([A-Za-z]+):([0-9A-Za-z_\\-]*)$",
              "type": "string",
              "description": "NeTEx id of a priceable object this fare table prices.",
              "examples": [
                "ENT:SupplementProduct:bike"
              ]
            },
            "default": []
          }
        }
      },
      "ProblemDetails": {
        "required": [
          "detail",
          "status",
          "title",
          "type"
        ],
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "A URI reference that identifies the problem type.",
            "format": "uri",
            "examples": [
              "https://developer.entur.org/errors/bad-request"
            ]
          },
          "title": {
            "type": "string",
            "description": "Short, human-readable summary of the problem type.",
            "examples": [
              "Bad Request"
            ]
          },
          "status": {
            "type": "integer",
            "description": "The HTTP status code.",
            "format": "int32",
            "examples": [
              400
            ]
          },
          "detail": {
            "type": "string",
            "description": "Human-readable explanation specific to this occurrence.",
            "examples": [
              "The supplied ruleId is not a valid UUID."
            ]
          },
          "instance": {
            "type": "string",
            "description": "A URI reference that identifies the specific occurrence.",
            "format": "uri",
            "examples": [
              "https://api.example.com/requests/12345"
            ]
          }
        },
        "description": "RFC 9457 Problem Details"
      },
      "VersionResponse": {
        "required": [
          "changed",
          "created",
          "id",
          "startDate",
          "status"
        ],
        "type": "object",
        "properties": {
          "id": {
            "pattern": "^([A-Z]{3}):Version:([0-9A-Za-z_\\-]*)$",
            "type": "string",
            "description": "The netex id reference to the object.",
            "examples": [
              "EXA:Version:001"
            ]
          },
          "number": {
            "type": "integer",
            "description": "Version number of the version. Only present when versionStatus is VERSIONED. Starts at 1 for a new product and is incremented by 1 for each new version.",
            "format": "int64",
            "examples": [
              1
            ]
          },
          "status": {
            "$ref": "#/components/schemas/VersionStatus"
          },
          "startDate": {
            "type": "string",
            "description": "The start date of the version.",
            "format": "date"
          },
          "endDate": {
            "type": "string",
            "description": "The end date of the version.",
            "format": "date"
          },
          "published": {
            "type": "string",
            "description": "Timestamp for when the version was published (set to status VERSIONED).",
            "format": "date-time"
          },
          "created": {
            "type": "string",
            "description": "Created datetime",
            "format": "date-time"
          },
          "changed": {
            "type": "string",
            "description": "Changed datetime",
            "format": "date-time"
          }
        }
      },
      "VersionRequest": {
        "required": [
          "startDate",
          "status"
        ],
        "type": "object",
        "properties": {
          "status": {
            "allOf": [
              {
                "$ref": "#/components/schemas/VersionStatus"
              },
              {
                "description": "Must be DRAFT for new versions."
              }
            ]
          },
          "startDate": {
            "type": "string",
            "description": "The start date of the version. Defaults to current date if not provided.",
            "format": "date"
          },
          "endDate": {
            "type": "string",
            "description": "The end date of the version (optional).",
            "format": "date"
          },
          "ownerOrganisationId": {
            "minimum": 1,
            "type": "integer",
            "description": "Internal id of the organisation that owns this element. Omit it to use the organisation in the access token, which is what a caller acting for itself should do. Supplying a different organisation requires permission to act on behalf of that organisation.",
            "format": "int64"
          }
        }
      }
    },
    "responses": {
      "UnauthorizedError": {
        "description": "Unauthorized - Authentication required",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/ProblemDetails"
            },
            "examples": {
              "unauthorized": {
                "summary": "Authentication required",
                "value": {
                  "type": "https://example.com/probs/unauthorized",
                  "title": "Unauthorized",
                  "status": 401,
                  "detail": "Authentication credentials were missing or invalid."
                }
              }
            }
          }
        }
      },
      "ForbiddenError": {
        "description": "Forbidden - Insufficient permissions",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/ProblemDetails"
            },
            "examples": {
              "forbidden": {
                "summary": "Access forbidden",
                "value": {
                  "type": "https://example.com/probs/forbidden",
                  "title": "Forbidden",
                  "status": 403,
                  "detail": "You do not have permission to access this resource."
                }
              }
            }
          }
        }
      },
      "BadRequestError": {
        "description": "Bad request - Invalid data or schema violation",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/ProblemDetails"
            },
            "examples": {
              "schemaViolation": {
                "summary": "Request does not match schema",
                "value": {
                  "type": "https://developer.entur.org/errors/bad-request",
                  "title": "Bad Request",
                  "status": 400,
                  "detail": "Field 'name' is required."
                }
              },
              "purchaseWindowNotFound": {
                "summary": "Referenced purchase window not found",
                "value": {
                  "type": "https://developer.entur.org/errors/bad-request",
                  "title": "Bad Request",
                  "status": 400,
                  "detail": "PurchaseWindow with id 'ENT:PurchaseWindow:120days' not found."
                }
              }
            }
          }
        }
      }
    },
    "parameters": {
      "id": {
        "name": "id",
        "in": "path",
        "description": "The netex ID of the element to retrieve",
        "required": true,
        "style": "simple",
        "explode": false,
        "schema": {
          "pattern": "^([A-Z]{3}):([A-Za-z]*):([0-9A-Za-z_\\-]*)$",
          "type": "string"
        },
        "examples": {
          "default": {
            "value": "ENT:PreassignedFareProduct:001"
          }
        }
      },
      "validOnDate": {
        "name": "validOnDate",
        "in": "query",
        "description": "The date that the element should be valid for, e.g. the travel date.\nDefaults to the current date.\n",
        "required": false,
        "style": "form",
        "explode": true,
        "schema": {
          "type": "string",
          "format": "date"
        },
        "examples": {
          "default": {
            "value": "2026-12-01"
          }
        }
      },
      "version": {
        "name": "version",
        "in": "path",
        "description": "The netex ID or sequence number of the version to retrieve",
        "required": true,
        "style": "simple",
        "explode": false,
        "schema": {
          "pattern": "^(([A-Z]{3}):Version:([0-9A-Za-z_\\-]*)|[1-9][0-9]*)$",
          "type": "string"
        },
        "examples": {
          "default": {
            "value": "ENT:Version:001"
          }
        }
      },
      "ET-Client-Name": {
        "name": "ET-Client-Name",
        "in": "header",
        "description": "Entur Client Header.\nIt is required that all consumers identify themselves by using this header.\nEntur will deploy strict rate-limiting policies on API-consumers who do not identify with a header and reserves the right to block unidentified consumers.\nThe structure of ET-Client-Name should be: `<company>-<application>`.",
        "required": false,
        "style": "simple",
        "explode": false,
        "schema": {
          "type": "string"
        }
      },
      "X-Correlation-Id": {
        "name": "X-Correlation-Id",
        "in": "header",
        "description": "Correlation id",
        "required": false,
        "style": "simple",
        "explode": false,
        "schema": {
          "type": "string"
        }
      }
    },
    "examples": {
      "flat": {
        "summary": "Flat price",
        "value": {
          "ownerOrganisationId": 1,
          "names": [
            {
              "lang": "nb-NO",
              "value": "Sykkeltillegg"
            }
          ],
          "startDate": "2026-08-01",
          "status": "DRAFT",
          "prices": [
            {
              "type": "FlatPrice",
              "amount": "49.00",
              "currency": "NOK"
            }
          ]
        }
      },
      "flat-2": {
        "summary": "Flat price",
        "value": {
          "id": "ENT:FareTable:bike-supplement",
          "versionId": "ENT:Version:8f1b2c3d",
          "ownerOrganisationId": 1,
          "names": [
            {
              "lang": "nb-NO",
              "value": "Sykkeltillegg"
            }
          ],
          "startDate": "2026-08-01",
          "status": "VERSIONED",
          "prices": [
            {
              "type": "FlatPrice",
              "amount": "49.00",
              "currency": "NOK"
            }
          ]
        }
      },
      "draftVersion": {
        "summary": "Draft version",
        "value": {
          "id": "EXA:Version:bf4d317a-8e61-49fd-b095-906b79c05872",
          "status": "DRAFT",
          "startDate": "2025-01-01",
          "created": "2025-01-01T10:00:00Z",
          "changed": "2025-01-01T10:00:00Z"
        }
      },
      "versionedVersion": {
        "summary": "Versioned version",
        "value": {
          "id": "EXA:Version:d88d0af0-4fe1-4457-a3a6-dbe1db5b3005",
          "status": "VERSIONED",
          "startDate": "2025-01-01",
          "endDate": "2025-12-31",
          "created": "2025-01-01T10:00:00Z",
          "changed": "2025-01-01T10:00:00Z",
          "published": "2025-01-15T10:00:00Z",
          "number": 1
        }
      },
      "draft": {
        "summary": "Create a new version in DRAFT",
        "value": {
          "id": "EXA:Version:7775e5aa-eb05-4190-9330-25c7f62b0b53",
          "status": "DRAFT",
          "startDate": "2025-01-01"
        }
      },
      "versionHistory": {
        "summary": "Example version history",
        "value": [
          {
            "id": "EXA:Version:853a7d14-794e-4af5-b569-301711a26e26",
            "status": "VERSIONED",
            "startDate": "2025-01-01",
            "endDate": "2025-12-31",
            "created": "2024-12-01T10:00:00Z",
            "changed": "2024-12-01T10:00:00Z",
            "published": "2024-12-30T10:00:00Z",
            "number": 1
          },
          {
            "id": "EXA:Version:e7104d26-16a5-4db5-aa42-b32ae0a3f684",
            "status": "VERSIONED",
            "startDate": "2026-01-01",
            "created": "2025-12-01T10:00:00Z",
            "changed": "2025-12-01T10:00:00Z",
            "published": "2025-12-01T13:00:00Z",
            "number": 2
          },
          {
            "id": "EXA:Version:6be856a5-dd98-496b-b3f2-ad9939270ec3",
            "status": "PROPOSED",
            "startDate": "2026-07-01",
            "created": "2026-06-01T10:00:00Z",
            "changed": "2026-06-01T10:00:00Z"
          }
        ]
      }
    },
    "securitySchemes": {
      "jwt": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT"
      }
    }
  }
}