allow underscores inside of network names (#5652)

JIRA Issues: MARATHON-7848

#%RAML 1.0 Library
uses:
  label: label.raml
  numbers: numberTypes.raml
  strings: stringTypes.raml
  pragma: pragma.raml
types:
  Endpoint:
    type: object
    description: |
      Endpoints accept connections from outside of a pod.
      Endpoints may also be advertised outside of a cluster.
    properties:
      name:
        type: string
        pattern: ^[a-z0-9]([-a-z0-9_]*[a-z0-9])?$
        maxLength: 63
        minLength: 1
        description: |
          Name of this port. Should be unique in the context of the pod.
      containerPort?:
        type: numbers.Port
        description: |
          The container port that a task's process is actually listening on.
          Required if the network mode is container
        usage: Specify 0 to tell Marathon to match the dynamically allocated host port.
      hostPort?:
        type: numbers.AnyPort
        description: |
          Mapped port on the host.
          All host ports are allocated from resource offers.
        usage: Specify 0 to tell Marathon to dynamically allocate a host port.
      protocol?:
        type: array
        (pragma.omitEmpty):
        items: strings.Name
        minItems: 1
        description: |
          The protocol of this port, advertised in Mesos DiscoveryInfo (DI).
          Specifying more than one protocol here will result in the generation
          of multiple Port DI entries.
      labels?:
        type: label.KVLabels
        (pragma.omitEmpty):
        description: |
          Metadata as key/value pair. Possible uses include VIPs,
          per-network-interface binding
      networkNames?:
        type: array
        items: strings.Name
        description: |
          List of the container networks associated with this endpoint. If
          absent, then this endpoint is associated with all defined container
          networks (for this application). A single item list is mandatory when
          `hostPort` is specified and multiple container networks are defined.
        (pragma.omitEmpty):
  NetworkMode:
    type: string
    enum: [container, "container/bridge", host]
    description: |
      `container` networks are named networks and are assigned an IP address by Mesos.
      The `container/bridge` network is a special container network that operates in a
      manner similar to Docker's "default bridge" mode, and depends on specific Mesos
      CNI support. The `host` network results in containers sharing the network namespace
      of the Mesos agent, and no IP address is allocated.
  Network:
    type: object
    properties:
      name?:
        type: strings.Name
        description: |
          Defines the name of the container network to join.
          Not for use with `host` mode networking.
      mode?:
        type: NetworkMode
        default: container
      labels?:
        type: label.KVLabels
        (pragma.omitEmpty):
        description: |
          Labels applied to the pod's NetworkInfo.
          Ignored when using `host` node networking.
  IpDiscoveryPort:
    type: object
    description: Port
    properties:
      number?:
        type: numbers.AnyPort
        description: The port number
        default: 0
      name:
        type: strings.LegacyName
        description: Name of the port
      protocol?:
        type: strings.NetworkProtocol
        default: tcp
      labels?:
        type: label.KVLabels
        (pragma.omitEmpty):
  IpDiscovery:
    type: object
    description: Information useful for service discovery
    properties:
      ports?:
        type: IpDiscoveryPort[]
        (pragma.omitEmpty):
        description: |
          Array of objects describing the ports exposed by each task
  IpAddress:
    type: object
    (pragma.deprecated): Experimental API that is now deprecated. Prefer portMappings
    description: |
      If an application definition includes the 'ipAddress' field, then Marathon
      will request a per-task IP from Mesos.
      A separate ports/portMappings configuration is then disallowed.
    properties:
      discovery?:
        type: IpDiscovery
        description: |
          DEPRECATED. Please try to use portMappings instead.
      groups?:
        type: array
        (pragma.omitEmpty):
        description: Ignored by Marathon, only exists here to preserve API compat (for now).
        items: string
        uniqueItems: true
      labels?:
        type: label.KVLabels
        (pragma.omitEmpty):
      networkName?:
        type: string
        description: |
          If present, declares the name of the network that the container should
          join.
          In practice it is up to the IPAM to decide how to interpret this field
        minLength: 1
  PortDefinition:
    type: object
    properties:
      port?:
        type: numbers.AnyPort
        default: 0
        description: |
          If requirePorts is set to true, then this port number will be used
          on the agent host. Otherwise if the requirePorts is set to false and
          this port number is not zero, then it will be used as a service port
          and a dynamic port will be used on the agent host.
          If it is set to zero, a dynamic port will be used on the host and a
          unique service port will be assigned by Marathon.
      labels?:
        type: label.KVLabels
        (pragma.omitEmpty):
      name?:
        type: strings.LegacyName
        description: |
          Name of the service hosted on this port.
          If provided, it must be unique over all port definitions.
      protocol?:
        type: strings.NetworkProtocol
        default: tcp
        description: If this port is used for tcp or udp or both.

#%RAML 1.0 Library
uses:
  label: label.raml
  numbers: numberTypes.raml
  strings: stringTypes.raml
  pragma: pragma.raml
types:
  Endpoint:
    type: object
    description: |
      Endpoints accept connections from outside of a pod.
      Endpoints may also be advertised outside of a cluster.
    properties:
      name:
        type: strings.Name
        description: |
          Name of this port. Should be unique in the context of the pod.
      containerPort?:
        type: numbers.Port
        description: |
          The container port that a task's process is actually listening on.
          Required if the network mode is container
        usage: Specify 0 to tell Marathon to match the dynamically allocated host port.
      hostPort?:
        type: numbers.AnyPort
        description: |
          Mapped port on the host.
          All host ports are allocated from resource offers.
        usage: Specify 0 to tell Marathon to dynamically allocate a host port.
      protocol?:
        type: array
        (pragma.omitEmpty):
        items: strings.Name
        minItems: 1
        description: |
          The protocol of this port, advertised in Mesos DiscoveryInfo (DI).
          Specifying more than one protocol here will result in the generation
          of multiple Port DI entries.
      labels?:
        type: label.KVLabels
        (pragma.omitEmpty):
        description: |
          Metadata as key/value pair. Possible uses include VIPs,
          per-network-interface binding
      networkNames?:
        type: array
        items: strings.Name
        description: |
          List of the container networks associated with this endpoint. If
          absent, then this endpoint is associated with all defined container
          networks (for this application). A single item list is mandatory when
          `hostPort` is specified and multiple container networks are defined.
        (pragma.omitEmpty):
  NetworkMode:
    type: string
    enum: [container, "container/bridge", host]
    description: |
      `container` networks are named networks and are assigned an IP address by Mesos.
      The `container/bridge` network is a special container network that operates in a
      manner similar to Docker's "default bridge" mode, and depends on specific Mesos
      CNI support. The `host` network results in containers sharing the network namespace
      of the Mesos agent, and no IP address is allocated.
  Network:
    type: object
    properties:
      name?:
        type: strings.Name
        description: |
          Defines the name of the container network to join.
          Not for use with `host` mode networking.
      mode?:
        type: NetworkMode
        default: container
      labels?:
        type: label.KVLabels
        (pragma.omitEmpty):
        description: |
          Labels applied to the pod's NetworkInfo.
          Ignored when using `host` node networking.
  IpDiscoveryPort:
    type: object
    description: Port
    properties:
      number?:
        type: numbers.AnyPort
        description: The port number
        default: 0
      name:
        type: strings.LegacyName
        description: Name of the port
      protocol?:
        type: strings.NetworkProtocol
        default: tcp
      labels?:
        type: label.KVLabels
        (pragma.omitEmpty):
  IpDiscovery:
    type: object
    description: Information useful for service discovery
    properties:
      ports?:
        type: IpDiscoveryPort[]
        (pragma.omitEmpty):
        description: |
          Array of objects describing the ports exposed by each task
  IpAddress:
    type: object
    (pragma.deprecated): Experimental API that is now deprecated. Prefer portMappings
    description: |
      If an application definition includes the 'ipAddress' field, then Marathon
      will request a per-task IP from Mesos.
      A separate ports/portMappings configuration is then disallowed.
    properties:
      discovery?:
        type: IpDiscovery
        description: |
          DEPRECATED. Please try to use portMappings instead.
      groups?:
        type: array
        (pragma.omitEmpty):
        description: Ignored by Marathon, only exists here to preserve API compat (for now).
        items: string
        uniqueItems: true
      labels?:
        type: label.KVLabels
        (pragma.omitEmpty):
      networkName?:
        type: string
        description: |
          If present, declares the name of the network that the container should
          join.
          In practice it is up to the IPAM to decide how to interpret this field
        minLength: 1
  PortDefinition:
    type: object
    properties:
      port?:
        type: numbers.AnyPort
        default: 0
        description: |
          If requirePorts is set to true, then this port number will be used
          on the agent host. Otherwise if the requirePorts is set to false and
          this port number is not zero, then it will be used as a service port
          and a dynamic port will be used on the agent host.
          If it is set to zero, a dynamic port will be used on the host and a
          unique service port will be assigned by Marathon.
      labels?:
        type: label.KVLabels
        (pragma.omitEmpty):
      name?:
        type: strings.LegacyName
        description: |
          Name of the service hosted on this port.
          If provided, it must be unique over all port definitions.
      protocol?:
        type: strings.NetworkProtocol
        default: tcp
        description: If this port is used for tcp or udp or both.


Fixed documentation

Fixed documentation

is: [ auth ]
type:
  collection:
    humanName: action target instance
    schemaBaseName: actionTargetInstance
    exampleGetResponse: !include ../examples/actionTargetInstances/response-array-get.json
    examplePostRequest: !include ../examples/actionTargetInstances/request-post.json
    examplePostError: !include ../examples/actionTargetInstances/response-post-error.json
get:
  securedBy: [ jwt: { type: 'owner' }, test ]
  description: |
    You can retrieve the action target instances through:
      * Event source template given through `actionTargetTemplateId`
      * Organization given through `organizationId`
      * All organizations throuhg `allOrganizations`

    At least one of these parementers **MUST** be given. In case, multiple parameters are provided, only one will be
    applied and in this order: `actionTargetTemplateId`, `organizationId` and `allOrganizations`.
  queryParameters:
    actionTargetTemplateId:
      description: |
        Filter the action target instance by action target template.

        The user **MUST** be a member of the organization where the action target instance is configured.
      type: integer
      required: true
      example: |
        `actionTargetTemplateId=1`
    organizationId:
      description: |
        Filter the action target instance by organization.

        The user **MUST** be a member of the organization where the action target instance is configured.
      type: integer
      required: true
      example: |
        `organizationId=1`
    allOrganizations:
      description: Filter the action target instances to retrieve all of them accross all the organizations where the user is member of.
      type: integer
      required: false
      example: |
        `allOrganizations` or `allOrganizations=true`
  responses:
    200:
      description: List of event types or empty list `[]`.
    422:
      description: If the `actionTargetTemplateId`, `organizationId` or `allOrganizations` is not provided.
    403:
      description: If the user is not a member of the organization that owns the action target instance.
post:
  securedBy: [ jwt: { type: 'owner' }, test ]
  responses:
    403:
      description: If the user is not a member of the organization that owns the action target instance.
    422:
      description: |
        Validation errors.

        You will receive these validations errors:

        * `{ "organizationId": [ "No organization found." ] }` when:
          * No organization found from the ID given
          * You have no access to the organization

        * `{ "actionTargetTemplateId": [ "No action target template found." ] }` when:
          * No action target template found from the ID given
          * You have no access to the action target template
          * You cannot create an event action target from an action target template in a different organization. In other words
            the organization ID is not the same as action target template organization ID.

/{actionTargetInstanceId}:
  is: [ auth ]
  type:
    member:
      humanName: action target instances
      schemaBaseName: actionTargetInstance
      identifierName: actionTargetInstanceId
      exampleGetResponse: !include ../examples/actionTargetInstances/response-get.json
      examplePatchRequest: !include ../examples/actionTargetInstances/request-patch.json
      examplePatchError: !include ../examples/actionTargetInstances/response-patch-error.json
  get:
    securedBy: [ jwt: { type: 'owner' }, test ]
    responses:
      403:
        description: If the user is not a member of the organization that owns the action target instance.
  patch:
    securedBy: [ jwt: { type: 'owner' }, test ]
    responses:
      403:
        description: If the user is not a member of the organization that owns the action target instance.

is: [ auth ]
type:
  collection:
    humanName: action target instance
    schemaBaseName: actionTargetInstance
    exampleGetResponse: !include ../examples/actionTargetInstances/response-array-get.json
    examplePostRequest: !include ../examples/actionTargetInstances/request-post.json
    examplePostError: !include ../examples/actionTargetInstances/response-post-error.json
get:
  securedBy: [ jwt: { type: 'owner' } ]
  description: |
    You can retrieve the action target instances through:
      * Event source template given through `actionTargetTemplateId`
      * Organization given through `organizationId`
      * All organizations throuhg `allOrganizations`

    At least one of these parementers **MUST** be given. In case, multiple parameters are provided, only one will be
    applied and in this order: `actionTargetTemplateId`, `organizationId` and `allOrganizations`.
  queryParameters:
    actionTargetTemplateId:
      description: |
        Filter the action target instance by action target template.

        The user **MUST** be a member of the organization where the action target instance is configured.
      type: integer
      required: true
      example: |
        `actionTargetTemplateId=1`
    organizationId:
      description: |
        Filter the action target instance by organization.

        The user **MUST** be a member of the organization where the action target instance is configured.
      type: integer
      required: true
      example: |
        `organizationId=1`
    allOrganizations:
      description: Filter the action target instances to retrieve all of them accross all the organizations where the user is member of.
      type: integer
      required: false
      example: |
        `allOrganizations` or `allOrganizations=true`
  responses:
    200:
      description: List of event types or empty list `[]`.
    422:
      description: If the `actionTargetTemplateId`, `organizationId` or `allOrganizations` is not provided.
    403:
      description: If the user is not a member of the organization that owns the action target instance.
post:
  securedBy: [ jwt: { type: 'owner' } ]
  responses:
    403:
      description: If the user is not a member of the organization that owns the action target instance.
    422:
      description: |
        Validation errors.

        You will receive these validations errors:

        * `{ "organizationId": [ "No organization found." ] }` when:
          * No organization found from the ID given
          * You have no access to the organization

        * `{ "actionTargetTemplateId": [ "No action target template found." ] }` when:
          * No action target template found from the ID given
          * You have no access to the action target template
          * You cannot create an event action target from an action target template in a different organization. In other words
            the organization ID is not the same as action target template organization ID.

/{actionTargetInstanceId}:
  is: [ auth ]
  type:
    member:
      humanName: action target instances
      schemaBaseName: actionTargetInstance
      identifierName: actionTargetInstanceId
      exampleGetResponse: !include ../examples/actionTargetInstances/response-get.json
      examplePatchRequest: !include ../examples/actionTargetInstances/request-patch.json
      examplePatchError: !include ../examples/actionTargetInstances/response-patch-error.json
  get:
    securedBy: [ jwt: { type: 'owner' } ]
    responses:
      403:
        description: If the user is not a member of the organization that owns the action target instance.
  patch:
    securedBy: [ jwt: { type: 'owner' } ]
    responses:
      403:
        description: If the user is not a member of the organization that owns the action target instance.


Added UUID to Locatopn

Added UUID to Locatopn

#%RAML 1.0
title: AquaDesk API
version: 1.0
securitySchemes:
  basic:
      description: This API supports Basic Authentication.
      type: Basic Authentication
baseUri: http://digitaldelta.aquadesk.nl
mediaType: [ application/json ]
description: Digital Delta API

protocols:
  - HTTP
  - HTTPS

# Base types
types:
  Double:
    type: number
    format: double

  KeyValuePair:
    properties:
      key:
        type: string
      value:
        type: string

  Geometry:
    properties:
      type:
        type: string
      coordinates:
        type: Double[]

  Node:
    description: Node objects contain the properties of the data node. A node is an operational implementation of the Digital Delta specification.
    type: object
    properties:
      uuid:
        type: string
        required: true
        pattern: "[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}"
      name:
        type: string
        required: true
      description:
        type: string
        required: true
      baseUrl:
        type: string
        required: true

  Location:
    description: Location that may have measurements.
    type: object
    properties:
      uuid:
        type: string
        pattern: "[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}"
      url:
        type: string
        description: Url of the location.
      code:
        type: string
        description: Code of the location.
      name:
        type: string
        description: Name of the location.
      geometry:
        type: Geometry
        description: GeoJSON formatted geometry of the location.

  LocationWithNode:
    description: Location that may have measurements including node.
    type: object
    properties:
      uuid:
        type: string
        pattern: "[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}"
      url:
        type: string
        description: Url of the location.
      code:
        type: string
        description: Code of the location.
      name:
        type: string
        description: Name of the location.
      geometry:
        type: Geometry
        description: GeoJSON formatted geometry of the location.
      node:
        type: Node

  Datasource:
    description: DataSource (“bronhouder” in Dutch) objects describe the source of the data. A node can have multiple data sources.
    type: object
    properties:
      uuid:
        type: string
        required: true
        pattern: "[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}"
      name:
        type: string
        required: true
      node:
        type: Node
        required: true

  ObservationType:
    description: Typing of a measurement.
    type: object
    properties:
      uuid:
        type: string
        required: true
        pattern: "[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}"
      quantity:
        type: string
        description: The quantity measured.
        examples: [ "ZICHT", "MONSTER", "CONCTTE", "AANTL" ]
        required: true
      unit:
        type: string
        description: Unit of measurement.
        examples: [ "cm2", "n", "n/m3" ]
        required: true
      parameter:
        type: string
        description: Parameter measured.
        required: false
        examples: [ "Pediastrum", "Tetraedron hastatum" ]
      compartment:
        type: string
        required: false
        description: Compartment in which the measurement was performed.
        examples: [ "OW" ]
      qualifier:
        type: string
        required: false
        description: 'Hoedanigheid'
        examples: [ "AD", "JU", "T20C", "KO" ]
      extra:
        type: KeyValuePair[]

  Event:
    description: |
      Event objects contain the actual value of each observation. |
      Each observation contains a timestamp and a value. There is an optional quality parameter.
    properties:
      value:
        type: number
        required: true
        example: 37.0
      timeStamp:
        type: datetime
        required: false
        example: 2016-12-31T12:45:00Z
      quality:
        type: string
        required: false
        example: "99"
      limitSymbol:
        type: string
        required: false
        examples: ["<", ">", "="]

  TimeseriesEvent:
    description: |
      Event objects contain the actual value of each observation. |
      Each observation contains a timestamp and a value. There is an optional quality parameter.
    properties:
      value:
        type: number
        required: true
        example: 37.0
      timeStamp:
        type: datetime
        required: false
        example: 2016-12-31T12:45:00Z

  TimeseriesType:
    description: |
      TimeSeriesType objects describe the type of measurement the timeseries contains. |
      These can be for example raw measurements, but also aggregations or simulations. |
      This information could be needed to correctly interpret the measurement values
    type: object
    properties:
      code:
        type: string
        required: true
        example: MEAS
      name:
        type: string
        required: true
        example: Measurement

  Timeseries:
    description: |
      Timeseries objects contain all information needed to interpret timeseries. |
      There are references to other objects, such as Node, Location, DataSource, ObservationType and TimeseriesType. |
      The TimeseriesType should be added as a reference because it can indicate if a timeseries containts a RAW dataset or makes use of the current measurements. |
      The Digital Delta specification of timeseries makes no assumptions on the nature of the series, timeseries may describe any series of data points of |
      the same observation type and datasource in time on one location. |
      This includes both equidistant series (fixed time interval between data points) and non-equidistant series (with varying time interval).
    type: object
    properties:
      url:
        type: string
        required: true
      uuid:
        type: string
        required: true
        pattern: "[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}"
      code:
        type: string
        required: true
      location:
        type: LocationWithNode
        required: true
      observationType:
        type: ObservationType
        required: true
      node:
        type: Node
        required: true
      datasource:
        type: Datasource
        required: true
      timeseriesType:
        type: TimeseriesType
        required: true
      interval:
        type: number
        required: false
      valueType:
        type: string
        required: false
      start:
        type: datetime
        required: true
        example: 2016-01-01T12:45:00Z
      end:
        type: datetime
        required: true
        example: 2016-01-01T12:45:00Z
      events:
        type: TimeseriesEvent[]

# List responses
  NodeListResponse:
    description: Response for a node list request.
    type: object
    properties:
      count:
        description: Number of records satisfying the query parameters.
        type: integer
        example: 1123
      previous:
        description: Link to the previous page
        type: string
      next:
        description: Link to the next page
        type: string
      maxpagesize:
        description: Maximum page size
        type: integer
      results:
        type: Node[]
        description: List of Nodes.

  DatasourceListResponse:
    description: Response for a data source list request.
    type: object
    properties:
      count:
        description: Number of records satisfying the query parameters.
        type: integer
        example: 1123
      previous:
        description: Link to the previous page
        type: string
      next:
        description: Link to the next page
        type: string
      maxpagesize:
        description: Maximum page size
        type: integer
      results:
        type: Datasource[]
        description: List of Datasource.

  LocationListResponse:
    description: Response for a location list request.
    type: object
    properties:
      count:
        description: Number of records satisfying the query parameters.
        type: integer
        example: 1123
      previous:
        description: Link to the previous page
        type: string
      next:
        description: Link to the next page
        type: string
      maxpagesize:
        description: Maximum page size
        type: integer
      results:
        type: LocationWithNode[]
        description: List of Locations.

  ObservationTypeListResponse:
    description: Response for a observation type list request.
    type: object
    properties:
      count:
        description: Number of records satisfying the query parameters.
        type: integer
        example: 1123
      previous:
        description: Link to the previous page
        type: string
      next:
        description: Link to the next page
        type: string
      maxpagesize:
        description: Maximum page size
        type: integer
      results:
        type: ObservationType[]
        description: List of observation types.

  TimeseriesListResponse:
    description: Response for a time series list request.
    type: object
    properties:
      count:
        description: Number of records satisfying the query parameters.
        type: integer
        example: 1123
      previous:
        description: Link to the previous page
        type: string
      next:
        description: Link to the next page
        type: string
      maxpagesize:
        description: Maximum page size
        type: integer
      results:
        type: Timeseries[]
        description: List of timeseries types.

  LocationPostRequest:
    description: Location filter request
    type: object
    properties:
      code:
        type: string[]

  TimeseriesPostRequest:
    description: Timeseries filter request
    type: object
    properties:
      code:
        type: string[]
      start:
        type: date-only
      end:
        type: date-only

# Methods
/datasources:
  get:
    queryParameters:
      page:
        description: Page number to retrieve. Starts at 1.
        required: false
        type: integer
      pagesize:
        description: Page size, minimum 1, maximum 10000.
        required: false
        type: integer
        minimum: 1
        maximum: 10000
      uuid:
        required: false
        type: string
        pattern: "[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}"
      name:
        required: false
        type: string
    responses:
      200:
        body:
          application/json:
            type: DatasourceListResponse
  /{uuid}:
    description: Request a specific datasource by its Uuid.
    uriParameters:
      uuid:
        type: string
        pattern: "[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}"
    get:
      responses:
        200:
          body:
            application/json:
              type: Datasource
        404:
          body:
            application/json:
              type: object
              example: |
                {"message": "Invalid data source"}
/nodes:
  get:
    queryParameters:
      page:
        description: Page number to retrieve. Starts at 1.
        required: false
        type: integer
      pagesize:
        description: Page size, minimum 1, maximum 10000.
        required: false
        type: integer
        minimum: 1
        maximum: 10000
      uuid:
        required: false
        type: string
        pattern: "[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}"
      name:
        required: false
        type: string
    responses:
      200:
        body:
          application/json:
            type: NodeListResponse
  /{uuid}:
    description: Request a specific node by its Uuid.
    uriParameters:
      uuid:
        type: string
    get:
      responses:
        200:
          body:
            application/json:
              type: Node
        404:
          body:
            application/json:
              type: object
              example:
                {"message": "Invalid node source"}

/observationtypes:
  description: Request a list of observation types.
  get:
    queryParameters:
      page:
        description: Page number to retrieve. Starts at 1.
        required: false
        type: integer
      pagesize:
        description: Page size, minimum 1, maximum 10000.
        required: false
        type: integer
        minimum: 1
        maximum: 10000
      parameter:
        description: Parameters
        required: false
        type: string[]
    responses:
      200:
        body:
          application/json:
            type: ObservationTypeListResponse
  /{uuid}:
    description: Request a specific observation type by its Uuid.
    uriParameters:
      uuid:
        type: string
        pattern: "[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}"
    get:
      responses:
        200:
          body:
            application/json:
              type: ObservationType
        404:
          body:
            application/json:
              type: object
              example: |
                {"message": "Invalid observation type source"}

/locations:
  description: Request a list of locations, with optional filter parameters.
  get:
    queryParameters:
      in_bbox:
        description: Bounding box representing a rectangle in which the locations must lie.
        required: false
        type: string
      page:
        description: Page number to retrieve. Starts at 1.
        required: false
        type: integer
        minimum: 1
      pagesize:
        description: Page size, minimum 1, maximum 10000.
        required: false
        type: integer
        minimum: 1
        maximum: 10000
      name:
        required: false
        type: string
        description: (Partial) location name.
      node:
        required: false
        type: string
        description: Node.
      uuid:
        type: string
        required: false
        pattern: "[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}"
        description: Node.
      code:
        required: false
        type: string
        description: (Partial) location code.
    responses:
      200:
        body:
          application/json:
            type: LocationListResponse
  /{uuid}:
    description: Request a specific location by its Uuid.
    uriParameters:
      uuid:
        type: string
        pattern: "[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}"
        description: Location code
    get:
      responses:
        200:
          body:
            application/json:
              type: Location
        404:
          body:
            application/json:
              type: object
              example: |
                {"message": "Invalid location code"}

  post:
    body:
      application/json:
        type: LocationPostRequest
    responses:
      200:
        body:
          application/json:
            type: LocationListResponse
      404:
        body:
          application/json:
            type: object
            example: |
              {"message": "Invalid filters"}
/timeseries:
  description: Retrieve timeseries.
  get:
    queryParameters:
      page:
        required: false
        type: integer
        minimum: 1
        description: Page number to retrieve. Starts at 1.
      pagesize:
        required: false
        type: integer
        minimum: 1
        maximum: 10000
        description: Page size of the page to retrieve. Minimum is 1, maximum is 10000.
      start:
        type: datetime
        required: false
        description: Retrieve measurements that are measured on or after this date.
      end:
        type: datetime
        required: false
        description: Retrieve measurements that are measured before or on this date.
      locationfilter:
        type: string
        required: false
        description: Retrieve measurements that were measured at a location with a name like the locationfilter.
      observationType:
        type: string
        required: false
        description: Uuid of the observation type.
      timeseriesType:
        type: string
        required: false
        description: Code of the time series. AquaDesk only supports MEAS.
      node:
        required: false
        type: string
        description: Node.
      code:
        required: false
        type: string
        description: Code.
      uuid:
        type: string
        required: false
        description: Node.
      valueType:
        type: string
        required: false
        description: Value type.
        example: "float"
    responses:
      200:
        body:
          application/json:
            type: TimeseriesListResponse
      404:
        body:
          application/json:
            type: object
            example: |
              {"message": "Invalid filters"}
  post: # post bodies define filters
    body:
      application/json:
        type: TimeseriesPostRequest
    responses:
      200:
        body:
          application/json:
            type: TimeseriesListResponse
      404:
        body:
          application/json:
            type: object
            example: |
              {"message": "Invalid filters"}
  /{uuid}:
    description: Request a specific timeseries by its Uuid.
    uriParameters:
      uuid:
        type: string
        description: Time series uuid
    get:
      responses:
        200:
          body:
            application/json:
              type: Timeseries
        404:
          body:
            application/json:
              type: object
              example: |
                {"message": "Invalid time series"}
    /data:
      get:
        queryParameters:
          start:
            type: date-only
            required: false
          end:
            type: date-only
            required: false
        responses:
          200:
            body:
              application/json:
                type: Event[]
          404:
            body:
              application/json:
                type: object
                example: |
                  {"message": "Invalid time series"}

#%RAML 1.0
title: AquaDesk API
version: 1.0
securitySchemes:
  basic:
      description: This API supports Basic Authentication.
      type: Basic Authentication
baseUri: http://digitaldelta.aquadesk.nl
mediaType: [ application/json ]
description: Digital Delta API

protocols:
  - HTTP
  - HTTPS

# Base types
types:
  Double:
    type: number
    format: double

  KeyValuePair:
    properties:
      key:
        type: string
      value:
        type: string

  Geometry:
    properties:
      type:
        type: string
      coordinates:
        type: Double[]

  Node:
    description: Node objects contain the properties of the data node. A node is an operational implementation of the Digital Delta specification.
    type: object
    properties:
      uuid:
        type: string
        required: true
        pattern: "[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}"
      name:
        type: string
        required: true
      description:
        type: string
        required: true
      baseUrl:
        type: string
        required: true

  Location:
    description: Location that may have measurements.
    type: object
    properties:
      url:
        type: string
        description: Url of the location.
      code:
        type: string
        description: Code of the location.
      name:
        type: string
        description: Name of the location.
      geometry:
        type: Geometry
        description: GeoJSON formatted geometry of the location.

  LocationWithNode:
    description: Location that may have measurements including node.
    type: object
    properties:
      uuid:
        type: string
        pattern: "[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}"
      url:
        type: string
        description: Url of the location.
      code:
        type: string
        description: Code of the location.
      name:
        type: string
        description: Name of the location.
      geometry:
        type: Geometry
        description: GeoJSON formatted geometry of the location.
      node:
        type: Node

  Datasource:
    description: DataSource (“bronhouder” in Dutch) objects describe the source of the data. A node can have multiple data sources.
    type: object
    properties:
      uuid:
        type: string
        required: true
        pattern: "[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}"
      name:
        type: string
        required: true
      node:
        type: Node
        required: true

  ObservationType:
    description: Typing of a measurement.
    type: object
    properties:
      uuid:
        type: string
        required: true
        pattern: "[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}"
      quantity:
        type: string
        description: The quantity measured.
        examples: [ "ZICHT", "MONSTER", "CONCTTE", "AANTL" ]
        required: true
      unit:
        type: string
        description: Unit of measurement.
        examples: [ "cm2", "n", "n/m3" ]
        required: true
      parameter:
        type: string
        description: Parameter measured.
        required: false
        examples: [ "Pediastrum", "Tetraedron hastatum" ]
      compartment:
        type: string
        required: false
        description: Compartment in which the measurement was performed.
        examples: [ "OW" ]
      qualifier:
        type: string
        required: false
        description: 'Hoedanigheid'
        examples: [ "AD", "JU", "T20C", "KO" ]
      extra:
        type: KeyValuePair[]

  Event:
    description: |
      Event objects contain the actual value of each observation. |
      Each observation contains a timestamp and a value. There is an optional quality parameter.
    properties:
      value:
        type: number
        required: true
        example: 37.0
      timeStamp:
        type: datetime
        required: false
        example: 2016-12-31T12:45:00Z
      quality:
        type: string
        required: false
        example: "99"
      limitSymbol:
        type: string
        required: false
        examples: ["<", ">", "="]

  TimeseriesEvent:
    description: |
      Event objects contain the actual value of each observation. |
      Each observation contains a timestamp and a value. There is an optional quality parameter.
    properties:
      value:
        type: number
        required: true
        example: 37.0
      timeStamp:
        type: datetime
        required: false
        example: 2016-12-31T12:45:00Z

  TimeseriesType:
    description: |
      TimeSeriesType objects describe the type of measurement the timeseries contains. |
      These can be for example raw measurements, but also aggregations or simulations. |
      This information could be needed to correctly interpret the measurement values
    type: object
    properties:
      code:
        type: string
        required: true
        example: MEAS
      name:
        type: string
        required: true
        example: Measurement

  Timeseries:
    description: |
      Timeseries objects contain all information needed to interpret timeseries. |
      There are references to other objects, such as Node, Location, DataSource, ObservationType and TimeseriesType. |
      The TimeseriesType should be added as a reference because it can indicate if a timeseries containts a RAW dataset or makes use of the current measurements. |
      The Digital Delta specification of timeseries makes no assumptions on the nature of the series, timeseries may describe any series of data points of |
      the same observation type and datasource in time on one location. |
      This includes both equidistant series (fixed time interval between data points) and non-equidistant series (with varying time interval).
    type: object
    properties:
      url:
        type: string
        required: true
      uuid:
        type: string
        required: true
        pattern: "[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}"
      code:
        type: string
        required: true
      location:
        type: LocationWithNode
        required: true
      observationType:
        type: ObservationType
        required: true
      node:
        type: Node
        required: true
      datasource:
        type: Datasource
        required: true
      timeseriesType:
        type: TimeseriesType
        required: true
      interval:
        type: number
        required: false
      valueType:
        type: string
        required: false
      start:
        type: datetime
        required: true
        example: 2016-01-01T12:45:00Z
      end:
        type: datetime
        required: true
        example: 2016-01-01T12:45:00Z
      events:
        type: TimeseriesEvent[]

# List responses
  NodeListResponse:
    description: Response for a node list request.
    type: object
    properties:
      count:
        description: Number of records satisfying the query parameters.
        type: integer
        example: 1123
      previous:
        description: Link to the previous page
        type: string
      next:
        description: Link to the next page
        type: string
      maxpagesize:
        description: Maximum page size
        type: integer
      results:
        type: Node[]
        description: List of Nodes.

  DatasourceListResponse:
    description: Response for a data source list request.
    type: object
    properties:
      count:
        description: Number of records satisfying the query parameters.
        type: integer
        example: 1123
      previous:
        description: Link to the previous page
        type: string
      next:
        description: Link to the next page
        type: string
      maxpagesize:
        description: Maximum page size
        type: integer
      results:
        type: Datasource[]
        description: List of Datasource.

  LocationListResponse:
    description: Response for a location list request.
    type: object
    properties:
      count:
        description: Number of records satisfying the query parameters.
        type: integer
        example: 1123
      previous:
        description: Link to the previous page
        type: string
      next:
        description: Link to the next page
        type: string
      maxpagesize:
        description: Maximum page size
        type: integer
      results:
        type: LocationWithNode[]
        description: List of Locations.

  ObservationTypeListResponse:
    description: Response for a observation type list request.
    type: object
    properties:
      count:
        description: Number of records satisfying the query parameters.
        type: integer
        example: 1123
      previous:
        description: Link to the previous page
        type: string
      next:
        description: Link to the next page
        type: string
      maxpagesize:
        description: Maximum page size
        type: integer
      results:
        type: ObservationType[]
        description: List of observation types.

  TimeseriesListResponse:
    description: Response for a time series list request.
    type: object
    properties:
      count:
        description: Number of records satisfying the query parameters.
        type: integer
        example: 1123
      previous:
        description: Link to the previous page
        type: string
      next:
        description: Link to the next page
        type: string
      maxpagesize:
        description: Maximum page size
        type: integer
      results:
        type: Timeseries[]
        description: List of timeseries types.

  LocationPostRequest:
    description: Location filter request
    type: object
    properties:
      code:
        type: string[]

  TimeseriesPostRequest:
    description: Timeseries filter request
    type: object
    properties:
      code:
        type: string[]
      start:
        type: date-only
      end:
        type: date-only

# Methods
/datasources:
  get:
    queryParameters:
      page:
        description: Page number to retrieve. Starts at 1.
        required: false
        type: integer
      pagesize:
        description: Page size, minimum 1, maximum 10000.
        required: false
        type: integer
        minimum: 1
        maximum: 10000
      uuid:
        required: false
        type: string
        pattern: "[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}"
      name:
        required: false
        type: string
    responses:
      200:
        body:
          application/json:
            type: DatasourceListResponse
  /{uuid}:
    description: Request a specific datasource by its Uuid.
    uriParameters:
      uuid:
        type: string
        pattern: "[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}"
    get:
      responses:
        200:
          body:
            application/json:
              type: Datasource
        404:
          body:
            application/json:
              type: object
              example: |
                {"message": "Invalid data source"}
/nodes:
  get:
    queryParameters:
      page:
        description: Page number to retrieve. Starts at 1.
        required: false
        type: integer
      pagesize:
        description: Page size, minimum 1, maximum 10000.
        required: false
        type: integer
        minimum: 1
        maximum: 10000
      uuid:
        required: false
        type: string
        pattern: "[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}"
      name:
        required: false
        type: string
    responses:
      200:
        body:
          application/json:
            type: NodeListResponse
  /{uuid}:
    description: Request a specific node by its Uuid.
    uriParameters:
      uuid:
        type: string
    get:
      responses:
        200:
          body:
            application/json:
              type: Node
        404:
          body:
            application/json:
              type: object
              example:
                {"message": "Invalid node source"}

/observationtypes:
  description: Request a list of observation types.
  get:
    queryParameters:
      page:
        description: Page number to retrieve. Starts at 1.
        required: false
        type: integer
      pagesize:
        description: Page size, minimum 1, maximum 10000.
        required: false
        type: integer
        minimum: 1
        maximum: 10000
      parameter:
        description: Parameters
        required: false
        type: string[]
    responses:
      200:
        body:
          application/json:
            type: ObservationTypeListResponse
  /{uuid}:
    description: Request a specific observation type by its Uuid.
    uriParameters:
      uuid:
        type: string
        pattern: "[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}"
    get:
      responses:
        200:
          body:
            application/json:
              type: ObservationType
        404:
          body:
            application/json:
              type: object
              example: |
                {"message": "Invalid observation type source"}

/locations:
  description: Request a list of locations, with optional filter parameters.
  get:
    queryParameters:
      in_bbox:
        description: Bounding box representing a rectangle in which the locations must lie.
        required: false
        type: string
      page:
        description: Page number to retrieve. Starts at 1.
        required: false
        type: integer
        minimum: 1
      pagesize:
        description: Page size, minimum 1, maximum 10000.
        required: false
        type: integer
        minimum: 1
        maximum: 10000
      name:
        required: false
        type: string
        description: (Partial) location name.
      node:
        required: false
        type: string
        description: Node.
      uuid:
        type: string
        required: false
        pattern: "[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}"
        description: Node.
      code:
        required: false
        type: string
        description: (Partial) location code.
    responses:
      200:
        body:
          application/json:
            type: LocationListResponse
  /{uuid}:
    description: Request a specific location by its Uuid.
    uriParameters:
      uuid:
        type: string
        pattern: "[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}"
        description: Location code
    get:
      responses:
        200:
          body:
            application/json:
              type: Location
        404:
          body:
            application/json:
              type: object
              example: |
                {"message": "Invalid location code"}

  post:
    body:
      application/json:
        type: LocationPostRequest
    responses:
      200:
        body:
          application/json:
            type: LocationListResponse
      404:
        body:
          application/json:
            type: object
            example: |
              {"message": "Invalid filters"}
/timeseries:
  description: Retrieve timeseries.
  get:
    queryParameters:
      page:
        required: false
        type: integer
        minimum: 1
        description: Page number to retrieve. Starts at 1.
      pagesize:
        required: false
        type: integer
        minimum: 1
        maximum: 10000
        description: Page size of the page to retrieve. Minimum is 1, maximum is 10000.
      start:
        type: datetime
        required: false
        description: Retrieve measurements that are measured on or after this date.
      end:
        type: datetime
        required: false
        description: Retrieve measurements that are measured before or on this date.
      locationfilter:
        type: string
        required: false
        description: Retrieve measurements that were measured at a location with a name like the locationfilter.
      observationType:
        type: string
        required: false
        description: Uuid of the observation type.
      timeseriesType:
        type: string
        required: false
        description: Code of the time series. AquaDesk only supports MEAS.
      node:
        required: false
        type: string
        description: Node.
      code:
        required: false
        type: string
        description: Code.
      uuid:
        type: string
        required: false
        description: Node.
      valueType:
        type: string
        required: false
        description: Value type.
        example: "float"
    responses:
      200:
        body:
          application/json:
            type: TimeseriesListResponse
      404:
        body:
          application/json:
            type: object
            example: |
              {"message": "Invalid filters"}
  post: # post bodies define filters
    body:
      application/json:
        type: TimeseriesPostRequest
    responses:
      200:
        body:
          application/json:
            type: TimeseriesListResponse
      404:
        body:
          application/json:
            type: object
            example: |
              {"message": "Invalid filters"}
  /{uuid}:
    description: Request a specific timeseries by its Uuid.
    uriParameters:
      uuid:
        type: string
        description: Time series uuid
    get:
      responses:
        200:
          body:
            application/json:
              type: Timeseries
        404:
          body:
            application/json:
              type: object
              example: |
                {"message": "Invalid time series"}
    /data:
      get:
        queryParameters:
          start:
            type: date-only
            required: false
          end:
            type: date-only
            required: false
        responses:
          200:
            body:
              application/json:
                type: Event[]
          404:
            body:
              application/json:
                type: object
                example: |
                  {"message": "Invalid time series"}


include response tag names to postbox and visiting address

#%RAML 0.8
---
title: Pickup Point API
baseUri: https://api.bring.com/pickuppoint/api/pickuppoint

documentation:
- title: Introduction
  content: |
      The Pickup point API provides a list of locations for package pickup. Based on a specified postal code or a geographical location, the 10 nearest pickup points are returned. Response is available as either XML or JSON.

      A pickup point is defined as any location delivering shipments on behalf of Bring and Posten, such as post offices, selected grocery stores, lockers, etc.

      It is important to note, there are two sets of addresses in the response, postbox(address, postalCode) and visiting address(visitingAddress,visitingPostalCode).Postbox address is required to get a package produced correctly, use this AS RECIPIENT address on label. Visiting address is more appropriate for user interface (Street address of the PIB).

      ### Filtering results

      In addition to postal code or location, one or more optional parameters can be added to the request, adding additional restrictions to the pickup points being returned. One such parameter is `searchForText=<texts>`, resulting in a response where all pickup points have at least a partial match with the search string given in `<texts>`. This can be the name of the pickup point, its address, city, county, municipality or location. Go to the reference table or see additional examples for more information.

      ### Rate limiting

      The Pickup point API has a rate limit, primarily considered on a per-user basis. Currently it limits API users to no more than 60 requests within a minute from a single IP address.

      Once you go over the rate limit, you will receive a response with an HTTP response code of 429 (Too Many Requests). The body of the response will consist of the following fields:

      - `code`: `429`
      - `error_message`: `The maximum number of requests per minute has been exceeded.`

      As an additional note, While accessing the Pickup point API together with Shipping Guide API, the product list should be displayed even in the case that the request has been rate limited by the Pickup point API.

      #### High-volume users

      If you're a high-volume user of the Pickup Point API, please [contact Customer Service](http://developer.bring.com/support/) to discuss your options.

      When contacting Bring support include a description of how you are using the Pickup Point API, also an estimate of current request volumes.

/{countryCode}/postalCode/{postalCode}{mediaTypeExtension}:
  displayName: Pickup points for postal code
  uriParameters:
    countryCode:
      displayName: Country
      enum: [ "NO", "DK", "SE", "FI" ]
    postalCode:
      displayName: Postal code
      type: string
    mediaTypeExtension:
      enum: [ .json, .xml ]
      description: Use .json to get application/json, .xml to get application/xml or .html to get HTML.
  get:
    description: List pickup points for postal code
    queryParameters:
      searchForText:
        displayName: Text filter
        type: string
      openingHoursSearchType:
        displayName: Filter using opening hours
        enum: [ ALL_WEEKDAYS, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY ]
      openOnOrBefore:
        description: Format `HHmm`. Return only pickup points that are open on or before the specified time.
        type: string
        pattern: ^([01][0-9]|2[0-3])[0-5][0-9]$
      openOnOrAfter:
        description: Format `HHmm`. Return only pickup points that are open on or after the specified time.
        type: string
        pattern: ^([01][0-9]|2[0-3])[0-5][0-9]$
      pickupPointType:
        displayName: Pickup-point type
        description: Currently available for Swedish, Finnish and Danish pickup point request only.
        enum: [ manned, locker ]
      numberOfResponses:
        description: Return the specified number of pickup points instead of the default.
        type: integer
        default: 10
      street:
        description: Searches for the nearest pickup points to the given street.
        type: string
      streetNumber:
        description: Searches for the nearest pickup points to the given street number.
        type: string
      callback:
        description: JSONP callback function name.
        type: string
      requestCountryCode:
        description: Country code of the requester. Only applicable for Norwegian pickup points.
        type: string
    responses:
      200:
        displayName: Example response for NO/postalCode/1407
        body:
          application/json:
            example: !include examples/by_postal_code.json
          application/xml:
            example: !include examples/by_postal_code.xml
      250:
        displayName: Using postal code and street address
        description: |
          Sometimes (especially in Denmark) it's a good idea to also specify the address when searching for pickup points, to get more accurate results.

          In [this example](https://api.bring.com/pickuppoint/api/pickuppoint/DK/postalCode/2000.json?street=Smallegade&streetNumber=3), we look for pickup points in Smallegade 3, 2000 Frederiksberg.
        body:
          application/json:
            example: !include examples/filter_address.json
          application/xml:
            example: !include examples/filter_address.xml
      251:
        displayName: Find pickup points containing a specific string
        description: |
          If you want to return only the pickup points matching a specific string, you may use the `searchForText` query param. The given text can be the name of the pickup point, its address, city, county, municipality or location. Partial matches are also allowed.

          In [this example](https://api.bring.com/pickuppoint/api/pickuppoint/NO/postalCode/1407.json?searchForText=KIWI), we look for pickup points near NO/1407 cotaining "Kiwi".
        body:
          application/json:
            example: !include examples/filter_search.json
          application/xml:
            example: !include examples/filter_search.xml
      252:
        displayName: Find pickup points open on specific days
        description: |
          If you want to return only the pickup points open on specified days, you may use the `openingHoursSearchType=<day>` query param. `<day>` be:

          - `ALL_WEEKDAYS` (default)
          - `MONDAY`
          - `TUESDAY`
          - `WEDNESDAY`
          - `THURSDAY`
          - `FRIDAY`
          - `SATURDAY`
          - `SUNDAY`

          If you want you can also add `openOnOrBefore` and / or `openOnOrAfter`, to limit the search even more.

          In [this example](https://api.bring.com/pickuppoint/api/pickuppoint/NO/postalCode/1407.json?openingHoursSearchType=SUNDAY), we look for pickup points near NO/1407 that are open Sundays.
        body:
          application/json:
            example: !include examples/filter_days.json
          application/xml:
            example: !include examples/filter_days.xml
      253:
        displayName: Find pickup points open at specific hours
        description: |
          If you want to return only the pickup points open on specific hours, you may use the `openOnOrBefore=<time>` and/or `openOnOrAfter=<time>` query params.

          The format of `<time>` is `HHmm`.

          In [this example](https://api.bring.com/pickuppoint/api/pickuppoint/NO/postalCode/1407.json?openOnOrBefore=0800), we look for pickup points near NO/1407 open on or before 08:00.
        body:
          application/json:
            example: !include examples/filter_hours.json
          application/xml:
            example: !include examples/filter_hours.xml

/{countryCode}/location/{latitude},{longitude}{mediaTypeExtension}:
  displayName: Pickup points for location
  uriParameters:
    countryCode:
      displayName: Country
      enum: [ "NO", "DK", "SE", "FI" ]
    latitude:
      displayName: Latitude
      description: Geographic coordinate specifying the north-south position.
      type: string
    longitude:
      displayName: Longitude
      description: Geographic coordinate specifying the east-west position.
      type: string
    mediaTypeExtension:
      enum: [ .json, .xml ]
      description: Use .json to get application/json or .xml to get application/xml.
  get:
    description: List pickup points closest to location
    queryParameters:
      searchForText:
        displayName: Text filter
        type: string
      openingHoursSearchType:
        displayName: Filter using opening hours
        enum: [ ALL_WEEKDAYS, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY ]
      openOnOrBefore:
        description: Format `HHmm`. Return only pickup points that are open on or before the specified time.
        type: string
        pattern: ^([01][0-9]|2[0-3])[0-5][0-9]$
      openOnOrAfter:
        description: Format `HHmm`. Return only pickup points that are open on or after the specified time.
        type: string
        pattern: ^([01][0-9]|2[0-3])[0-5][0-9]$
      pickupPointType:
        displayName: Pickup-point type
        description: Currently available for Swedish, Finnish and Danish pickup point request only.
        enum: [ manned, locker ]
      numberOfResponses:
        description: Return the specified number of pickup points instead of the default.
        type: integer
        default: 10
      street:
        description: Searches for the nearest pickup points to the given street.
        type: string
      streetNumber:
        description: Searches for the nearest pickup points to the given street number.
        type: string
      callback:
        description: JSONP callback function name.
        type: string
      requestCountryCode:
        description: Country code of the requester. Only applicable for Norwegian pickup points.
        type: string
    responses:
      200:
        displayName: Example response for location/60.395226,5.321725
        body:
          application/json:
            example: !include examples/by_coordinates.json
          application/xml:
            example: !include examples/by_coordinates.xml

/{countryCode}/id/{id}{mediaTypeExtension}:
  displayName: A specific pickup point
  uriParameters:
    countryCode:
      displayName: Country
      enum: [ "NO", DK, SE, FI ]
    mediaTypeExtension:
      enum: [ .json, .xml ]
      description: Use .json to get application/json or .xml to get application/xml.
  get:
    description: Look up a specific pickup point
    queryParameters:
      callback:
        displayName: JSONP support
        description: Callback function name.
        type: string
      requestCountryCode:
        description: Country code of the requester. Only applicable for Norwegian pickup points.
        type: string
    responses:
      200:
        displayName: Example response for id/121110
        body:
          application/json:
            example: !include examples/by_id.json
          application/xml:
            example: !include examples/by_id.xml

/{countryCode}/all{mediaTypeExtension}:
  displayName: All pickup points in a country
  uriParameters:
    countryCode:
      displayName: Country
      enum: [ "NO", DK, SE, FI ]
    mediaTypeExtension:
      enum: [ .json, .xml ]
      description: Use .json to get application/json or .xml to get application/xml.
  get:
    description: All pickup points in a country
    queryParameters:
      callback:
        displayName: JSONP support
        description: Callback function name.
        type: string
      requestCountryCode:
        description: Country code of the requester. Only applicable for Norwegian pickup points.
        type: string

#%RAML 0.8
---
title: Pickup Point API
baseUri: https://api.bring.com/pickuppoint/api/pickuppoint

documentation:
- title: Introduction
  content: |
      The Pickup point API provides a list of locations for package pickup. Based on a specified postal code or a geographical location, the 10 nearest pickup points are returned. Response is available as either XML or JSON.

      A pickup point is defined as any location delivering shipments on behalf of Bring and Posten, such as post offices, selected grocery stores, lockers, etc.

      It is important to note, there are two sets of addresses in the response, postbox and visiting address. Postbox address is required to get a package produced correctly, use this address on label. Visiting address is more appropriate for user interface.

      ### Filtering results

      In addition to postal code or location, one or more optional parameters can be added to the request, adding additional restrictions to the pickup points being returned. One such parameter is `searchForText=<texts>`, resulting in a response where all pickup points have at least a partial match with the search string given in `<texts>`. This can be the name of the pickup point, its address, city, county, municipality or location. Go to the reference table or see additional examples for more information.

      ### Rate limiting

      The Pickup point API has a rate limit, primarily considered on a per-user basis. Currently it limits API users to no more than 60 requests within a minute from a single IP address.

      Once you go over the rate limit, you will receive a response with an HTTP response code of 429 (Too Many Requests). The body of the response will consist of the following fields:

      - `code`: `429`
      - `error_message`: `The maximum number of requests per minute has been exceeded.`

      As an additional note, While accessing the Pickup point API together with Shipping Guide API, the product list should be displayed even in the case that the request has been rate limited by the Pickup point API.

      #### High-volume users

      If you're a high-volume user of the Pickup Point API, please [contact Customer Service](http://developer.bring.com/support/) to discuss your options.

      When contacting Bring support include a description of how you are using the Pickup Point API, also an estimate of current request volumes.

/{countryCode}/postalCode/{postalCode}{mediaTypeExtension}:
  displayName: Pickup points for postal code
  uriParameters:
    countryCode:
      displayName: Country
      enum: [ "NO", "DK", "SE", "FI" ]
    postalCode:
      displayName: Postal code
      type: string
    mediaTypeExtension:
      enum: [ .json, .xml ]
      description: Use .json to get application/json, .xml to get application/xml or .html to get HTML.
  get:
    description: List pickup points for postal code
    queryParameters:
      searchForText:
        displayName: Text filter
        type: string
      openingHoursSearchType:
        displayName: Filter using opening hours
        enum: [ ALL_WEEKDAYS, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY ]
      openOnOrBefore:
        description: Format `HHmm`. Return only pickup points that are open on or before the specified time.
        type: string
        pattern: ^([01][0-9]|2[0-3])[0-5][0-9]$
      openOnOrAfter:
        description: Format `HHmm`. Return only pickup points that are open on or after the specified time.
        type: string
        pattern: ^([01][0-9]|2[0-3])[0-5][0-9]$
      pickupPointType:
        displayName: Pickup-point type
        description: Currently available for Swedish, Finnish and Danish pickup point request only.
        enum: [ manned, locker ]
      numberOfResponses:
        description: Return the specified number of pickup points instead of the default.
        type: integer
        default: 10
      street:
        description: Searches for the nearest pickup points to the given street.
        type: string
      streetNumber:
        description: Searches for the nearest pickup points to the given street number.
        type: string
      callback:
        description: JSONP callback function name.
        type: string
      requestCountryCode:
        description: Country code of the requester. Only applicable for Norwegian pickup points.
        type: string
    responses:
      200:
        displayName: Example response for NO/postalCode/1407
        body:
          application/json:
            example: !include examples/by_postal_code.json
          application/xml:
            example: !include examples/by_postal_code.xml
      250:
        displayName: Using postal code and street address
        description: |
          Sometimes (especially in Denmark) it's a good idea to also specify the address when searching for pickup points, to get more accurate results.

          In [this example](https://api.bring.com/pickuppoint/api/pickuppoint/DK/postalCode/2000.json?street=Smallegade&streetNumber=3), we look for pickup points in Smallegade 3, 2000 Frederiksberg.
        body:
          application/json:
            example: !include examples/filter_address.json
          application/xml:
            example: !include examples/filter_address.xml
      251:
        displayName: Find pickup points containing a specific string
        description: |
          If you want to return only the pickup points matching a specific string, you may use the `searchForText` query param. The given text can be the name of the pickup point, its address, city, county, municipality or location. Partial matches are also allowed.

          In [this example](https://api.bring.com/pickuppoint/api/pickuppoint/NO/postalCode/1407.json?searchForText=KIWI), we look for pickup points near NO/1407 cotaining "Kiwi".
        body:
          application/json:
            example: !include examples/filter_search.json
          application/xml:
            example: !include examples/filter_search.xml
      252:
        displayName: Find pickup points open on specific days
        description: |
          If you want to return only the pickup points open on specified days, you may use the `openingHoursSearchType=<day>` query param. `<day>` be:

          - `ALL_WEEKDAYS` (default)
          - `MONDAY`
          - `TUESDAY`
          - `WEDNESDAY`
          - `THURSDAY`
          - `FRIDAY`
          - `SATURDAY`
          - `SUNDAY`

          If you want you can also add `openOnOrBefore` and / or `openOnOrAfter`, to limit the search even more.

          In [this example](https://api.bring.com/pickuppoint/api/pickuppoint/NO/postalCode/1407.json?openingHoursSearchType=SUNDAY), we look for pickup points near NO/1407 that are open Sundays.
        body:
          application/json:
            example: !include examples/filter_days.json
          application/xml:
            example: !include examples/filter_days.xml
      253:
        displayName: Find pickup points open at specific hours
        description: |
          If you want to return only the pickup points open on specific hours, you may use the `openOnOrBefore=<time>` and/or `openOnOrAfter=<time>` query params.

          The format of `<time>` is `HHmm`.

          In [this example](https://api.bring.com/pickuppoint/api/pickuppoint/NO/postalCode/1407.json?openOnOrBefore=0800), we look for pickup points near NO/1407 open on or before 08:00.
        body:
          application/json:
            example: !include examples/filter_hours.json
          application/xml:
            example: !include examples/filter_hours.xml

/{countryCode}/location/{latitude},{longitude}{mediaTypeExtension}:
  displayName: Pickup points for location
  uriParameters:
    countryCode:
      displayName: Country
      enum: [ "NO", "DK", "SE", "FI" ]
    latitude:
      displayName: Latitude
      description: Geographic coordinate specifying the north-south position.
      type: string
    longitude:
      displayName: Longitude
      description: Geographic coordinate specifying the east-west position.
      type: string
    mediaTypeExtension:
      enum: [ .json, .xml ]
      description: Use .json to get application/json or .xml to get application/xml.
  get:
    description: List pickup points closest to location
    queryParameters:
      searchForText:
        displayName: Text filter
        type: string
      openingHoursSearchType:
        displayName: Filter using opening hours
        enum: [ ALL_WEEKDAYS, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY ]
      openOnOrBefore:
        description: Format `HHmm`. Return only pickup points that are open on or before the specified time.
        type: string
        pattern: ^([01][0-9]|2[0-3])[0-5][0-9]$
      openOnOrAfter:
        description: Format `HHmm`. Return only pickup points that are open on or after the specified time.
        type: string
        pattern: ^([01][0-9]|2[0-3])[0-5][0-9]$
      pickupPointType:
        displayName: Pickup-point type
        description: Currently available for Swedish, Finnish and Danish pickup point request only.
        enum: [ manned, locker ]
      numberOfResponses:
        description: Return the specified number of pickup points instead of the default.
        type: integer
        default: 10
      street:
        description: Searches for the nearest pickup points to the given street.
        type: string
      streetNumber:
        description: Searches for the nearest pickup points to the given street number.
        type: string
      callback:
        description: JSONP callback function name.
        type: string
      requestCountryCode:
        description: Country code of the requester. Only applicable for Norwegian pickup points.
        type: string
    responses:
      200:
        displayName: Example response for location/60.395226,5.321725
        body:
          application/json:
            example: !include examples/by_coordinates.json
          application/xml:
            example: !include examples/by_coordinates.xml

/{countryCode}/id/{id}{mediaTypeExtension}:
  displayName: A specific pickup point
  uriParameters:
    countryCode:
      displayName: Country
      enum: [ "NO", DK, SE, FI ]
    mediaTypeExtension:
      enum: [ .json, .xml ]
      description: Use .json to get application/json or .xml to get application/xml.
  get:
    description: Look up a specific pickup point
    queryParameters:
      callback:
        displayName: JSONP support
        description: Callback function name.
        type: string
      requestCountryCode:
        description: Country code of the requester. Only applicable for Norwegian pickup points.
        type: string
    responses:
      200:
        displayName: Example response for id/121110
        body:
          application/json:
            example: !include examples/by_id.json
          application/xml:
            example: !include examples/by_id.xml

/{countryCode}/all{mediaTypeExtension}:
  displayName: All pickup points in a country
  uriParameters:
    countryCode:
      displayName: Country
      enum: [ "NO", DK, SE, FI ]
    mediaTypeExtension:
      enum: [ .json, .xml ]
      description: Use .json to get application/json or .xml to get application/xml.
  get:
    description: All pickup points in a country
    queryParameters:
      callback:
        displayName: JSONP support
        description: Callback function name.
        type: string
      requestCountryCode:
        description: Country code of the requester. Only applicable for Norwegian pickup points.
        type: string