openapi: 3.0.1
info:
  title: Poiint Business API
  description: >
    ## Introduction


    This is the official documentation for **Poiint Business API**.

    It contains all the information required for integration of Poiint Business
    services into your system.

    In case of any questions, do not hesitate to contact our tech support.


    ## Testing and Development


    Integration with our systems can be tested against a dedicated testing
    environment.

    Access must be requested via email.

    **You should never run your tests against Poiint Business Production API.**

    Test API url:


    ```

    https://api.integration.business.poiint.sk

    ```


    The submission and label printing are the only operations that involve
    communication with the system of external carrier.

    The thing is, that our testing environment cannot communicate with the
    production environment of the external carrier (because client would be
    charged for those orders).

    However, since not all carriers offer a dedicated testing environment that
    we can integrate with our systems, we are forced to limit testing to the GLS
    carrier only.

    **This means, that you should test order submission and label printing only
    with GLS carrier.**

    **Submission of order (or getting labels for order) that is handled by
    someone else than GLS will cause HTTP 500 error response.**

    This limitation does not apply to the production environment.


    ## Web application


    Orders created during testing can be managed via Poiint Business web
    application available here:


    ```

    https://integration.business.poiint.sk

    ```


    ## Contacts


    Technical support: **it@poiint.sk**


    ## Glossary


    The following list was created to clarify terminology that may appear in the
    documentation:


    - **Enrichment** - Represents an additional service that can be used when
    creating an order. These services may be charged, and their use is optional.

    - **Cod** - Abbreviation for Cash On Delivery service.

    - **Ins** - Abbreviation for Insurance service.

    - **Icc** - Abbreviation for ID Card Check service.

    - **Pickup type**:
        - **Regular** - The courier visits the selected address at regular intervals without the need for an explicit request of the pickup.
        - **Irregular** - The courier comes for parcels only when explicitly requested.
    - **Delivery type**:
        - **Home** - Delivery to "hands" (on specified address).
        - **Parcel Shop** - Delivery to pickup point (e.g. Packeta Z-Box, Z-Point).
    - **Consignee** - Recipient of the parcel.

    - **Create order** - Save order in our system.

    - **Submit order** - Send order to the carrier specified during order
    creation.


    ## Carriers


    Carriers in our system are identified by so called public ID. Below is a
    list of all carriers and their public IDs.


    | ID  | Carrier Name             |

    | --- | ------------------------ |

    | 1   | DPD                      |

    | 2   | GLS                      |

    | 3   | SPS                      |

    | 4   | PACKETA                  |

    | 5   | TALIANSKA POSTA HD       |

    | 6   | IE FEDEX HD CONNECT PLUS |

    | 7   | CHORVATSKA POSTA HD      |

    | 8   | TR FEDEX HD ECONOMY      |

    | 9   | BG SPEEDY HD             |

    | 10  | BG SAMEDAY HD            |

    | 11  | IE FEDEX HD PRIORITY     |

    | 12  | EE VENIPAK HD            |

    | 13  | UA MEEST POSHTA HD       |

    | 14  | LV LITHUANIAN POST HD    |

    | 15  | EE OMNIVA HD             |

    | 16  | HU EXPRESS ONE HD        |

    | 17  | EE LITHUANIAN POST HD    |

    | 18  | FR COLISPRIVE DIRECT HD  |

    | 19  | RO FANCOURIER HD         |

    | 20  | IE FASTWAY HD            |

    | 21  | PT MRW HD                |

    | 22  | ES MRW HD                |

    | 23  | US FEDEX HD PRIORITY     |

    | 24  | RO SAMEDAY HD            |

    | 25  | FI POSTNORD HD           |

    | 26  | BG ECONT HD              |

    | 27  | SI POST HD               |

    | 28  | LV OMNIVA HD             |

    | 29  | SE POSTNORD HD           |

    | 30  | DK POSTNORD HD           |

    | 31  | GB ROYALMAIL48 HD        |

    | 32  | GR ACS HD                |

    | 33  | HU MADARSKA POSTA HD     |

    | 34  | BELGICKA POSTA HD        |

    | 35  | LT VENIPAK HD            |

    | 36  | GR TAXYDROMIKI HD        |

    | 37  | NL DHL HD                |

    | 38  | ES CORREOS HD            |

    | 39  | LV VENIPAK HD            |

    | 40  | TR FEDEX HD PRIORITY     |

    | 41  | BE HOLANDSKA POSTA HD    |

    | 42  | FI MATKAHUOLTO HD        |

    | 43  | GB ROYALMAIL24 HD        |

    | 44  | IT BARTOLINI HD          |

    | 45  | GR ELTA HD               |

    | 46  | IT HRPARCEL HD           |

    | 47  | RO CARGUS HD             |

    | 48  | SWISS POST HD            |

    | 49  | LUXEMBURSKA POSTA HD     |

    | 50  | AE ARAMEX HD             |

    | 51  | HR OVERSEAS HD           |

    | 52  | DE HERMES HD             |

    | 53  | GB FEDEX HD PRIORITY     |

    | 54  | US FEDEX HD ECONOMY      |

    | 55  | NL HOLANDSKA POSTA HD    |

    | 56  | LT OMNIVA HD             |

    | 57  | LT LITHUANIAN POST HD    |

    | 58  | FR COLISSIMO HD          |

    | 59  | GR SPEEDEX HD            |

    | 60  | RAKUSKA POSTA HD         |

    | 61  | SI EXPRESSONE HD         |


    ## Security


    The system is secured using **API keys** and **JSON Web Tokens** (JWT).

    Detailed specification of the security mechanism for each endpoint is
    provided in endpoint description.

    To be able to use most of the endpoints, you need a valid access token
    (JWT).

    The basic principle involves obtaining an access token using an API key and
    the _Refresh_ operation.

    The obtained access token must be set in the HTTP header as `Authorization:
    Bearer <token>`.

    **Lifespan of an access token is 4 hours.**

    For proper functioning, it is necessary to regularly request a new token (we
    recommend doing so 30 minutes before the token expires).


    ### Access Tokens


    **What is it for?**


    - Authorization in following operations:
        - _CreateOrder_
        - _SubmitOrder_
        - _GetUnavailablePickupDates_
        - _PrintLabels_

    **What is the lifespan?**


    - 4 hours.


    **Where can I get it?**


    - Response from _Refresh_ operation.


    ### API keys


    **What is it for?**


    - Authorization in following operations:
        - _Refresh_

    **What is the lifespan?**


    - 6 months.


    **Where can I get it?**


    - By contacting a technical support.


    ## FAQ


    **Is it possible to create multiple orders with a single request?**


    - No, you need to call _CreateOrder_ operation multiple times.


    **Is it possible to submit multiple orders with a single request?**


    - No, you need to call _SubmitOrder_ operation multiple times.


    **How should the customer of the e-shop choose a carrier?**


    - The customer selects from carriers obtained via the _Refresh_ operation.
    Only carriers that meet the order's requirements for delivery country,
    enrichments etc. should be offered to the customer.


    **Is there any address validation?**


    - Yes, in addition to basic validation, we also check whether the zipcode
    actually matches the city.


    ## Validations errors


    Response body in case of a validation error have a structure of
    [ProblemDetails](https://datatracker.ietf.org/doc/html/rfc7807) object.
    Below is an example from _CreateOrder_ operation.


    ```json

    {
        "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
        "title": "One or more validation errors occurred.",
        "status": 400,
        "errors": {
            "Body.Consignee.Name": [
                "NotEmpty"
            ],
            "Body.Consignee.Email": [
                "ValidFormat"
            ],
            "Body.DeliveryAddress.Country": [
                "NotEmpty",
                "ValidFormat"
            ]
        },
        "traceId": "00-74fd6d6a0aa9734689bc534921ff5f92-0916537dea6b633a-00"
    }

    ```


    As you can see, server does not return detailed messages.

    Instead, it returns validation requirements that caused the failure.

    In the example above, attribute `Consignee.Name` cannot be empty,
    `Consignee.Email` must be a valid email format etc.

    List of all validation requirements can be found below.

    Showing user-friendly error messages is responsibility of API consumer. 


    | Validation Requirement       |
    Description                                                   |

    | ---------------------------- |
    ------------------------------------------------------------- |

    | `NotNull`                    | Value must not be
    null.                                       |

    | `NotEmpty`                   | Value must not be
    empty.                                      |

    | `Bigger[x]`                  | Value must be bigger than
    `x`.                                |

    | `BiggerOrEq[x]`              | Value must be bigger or equal to
    `x`.                         |

    | `LessOrEq[x]`                | Value must be less or equal to
    `x`.                           |

    | `MaxLength[maxLength]`       | String length must be less or equal to
    `maxLength`.           |

    | `ValidFormat[pattern]`       | Value must match the
    `pattern`.                               |

    | `Unique`                     | Value must be
    unique.                                         |

    | `ValidCurrency`              | Value must be valid currency in ISO 4217
    format.              |

    | `RequiredCurrency[currency]` | Value must be the currency specified by
    `currency` parameter. |

    | `SupportedEnrichment`        | Enrichment must be
    supported.                                 |

    | `AvailablePickupDate`        | Pickup date must be a valid date for given
    carrier.           |

    | `Number`                     | Value must be a
    number.                                       |

    | `ValidCarrier`               | Carrier must be valid for given use-case
    (order).             |
  version: 0.0.1
servers:
  - url: https://api.integration.business.poiint.sk
    description: Integration
paths:
  /integration/v1/orders:
    post:
      tags:
        - Integration
      summary: Create order
      description: >-
        Used to create an order.

        Created order is stored in our system, but not submitted to the carrier
        yet.

        Order submission is done in separate step using _SubmitOrderEndpoint_.
      operationId: CreateOrder
      parameters:
        - name: X-Sender-Profile
          in: header
          required: true
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateOrderEndpoint.RequestBody'
        required: true
      responses:
        '200':
          description: Order created successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateOrderEndpoint.Response'
        '400':
          description: Invalid request data.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
        '401':
          description: Unauthorized access (invalid access token).
      security:
        - Bearer: []
  /integration/v1/orders/{id}/submit:
    post:
      tags:
        - Integration
      summary: Submit order
      description: >-
        Used to submit existing order identified by id in the route parameter.

        Order submission means that the order is sent to the system of a carrier
        specified on the order.

        After this step, the order can no longer be modified.

        Order cannot be submitted more than once.

        For orders with a carrier that has configured an irregular pickup type,
        it is necessary to specify the pickup date in a request body.
      operationId: SubmitOrder
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: X-Sender-Profile
          in: header
          required: true
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SubmitOrderEndpoint.RequestBody'
        required: true
      responses:
        '200':
          description: OK
          content:
            application/json: {}
        '202':
          description: Submission successful.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SubmitOrderEndpoint.Response'
        '400':
          description: Pickup date is invalid or missing.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
        '401':
          description: Unauthorized access (invalid access token).
        '402':
          description: Operation blocked because of unpaid invoices.
        '404':
          description: Order with given id not found.
      security:
        - Bearer: []
  /integration/v1/orders/labels:
    get:
      tags:
        - Integration
      summary: Print labels
      description: |-
        Used to print labels for given orders.
        Labels can be printed only for submitted orders with regular pickup.
        A maximum of 100 labels can be printed at a time.
      operationId: PrintLabels
      parameters:
        - name: X-Sender-Profile
          in: header
          required: true
          schema:
            type: string
        - name: id
          in: query
          description: Orders for which you want to print labels.
          required: true
          schema:
            type: array
            items:
              type: string
              format: uuid
        - name: format
          in: query
          description: Optional label format ("A6onA4" or "A6onA6").
          schema:
            type: string
        - name: starting-position
          in: query
          description: >-
            Optional starting position of the first label. Allowed values: 0 -
            3.
          schema:
            type: integer
            format: int32
      responses:
        '200':
          description: Printing successful.
          content:
            application/pdf: {}
        '400':
          description: Request validation error.
        '405':
          description: >-
            Label printing error caused by attempt to print order that is not
            your or by attempt to print label for unsubmitted order or order
            with irregular pickup.
      security:
        - Bearer: []
  /integration/v1/refresh:
    post:
      tags:
        - Integration
      summary: Refresh
      description: >-
        Used to obtain the access token and current configuration.

        Access token is required for authorization of requests for order
        creation and submission.

        The configuration provides information about delivery options of the
        carriers (which carriers can be used for delivery in given country).

        The configuration also includes information about enrichments and
        validation rules for the given carrier.
      operationId: Refresh
      parameters:
        - name: X-Api-Key
          in: header
          required: true
          schema:
            type: string
        - name: X-Sender-Profile
          in: header
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Operation successful.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RefreshEndpoint.Response'
        '401':
          description: Unauthorized access (invalid API key).
      security:
        - ApiKey: []
  /integration/v1/unavailable-pickup-dates:
    get:
      tags:
        - Integration
      summary: Get unavailable pickup dates
      description: >-
        The function returns the days on which it is not possible to pick up the
        order by the carrier.

        Only 30 days from current date are taken into account.

        It is supposed to be used in combination with date picker component to
        ensure selection of a valid pickup date by the client.

        Note that, pickup date selection makes sense only for carriers that
        support irregular pickup type.
      operationId: GetUnavailablePickupDates
      parameters:
        - name: carrier-pid
          in: query
          required: true
          schema:
            type: integer
            format: int32
        - name: X-Sender-Profile
          in: header
          required: true
          schema:
            type: string
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: >-
                  #/components/schemas/GetUnavailablePickupDatesEndpoint.Response
      security:
        - Bearer: []
components:
  schemas:
    CreateOrderEndpoint.RequestBody:
      required:
        - carrierPid
        - clientReference
        - consignee
        - expectedWeight
        - parcelCount
      type: object
      properties:
        carrierPid:
          type: integer
          description: "Public identifier of the carrier chosen for the delivery of the package.\r\nAvailable carriers can be obtained using RefreshEndpoint."
          format: int32
        consignee:
          $ref: '#/components/schemas/Dtos.Consignee'
        parcelCount:
          type: integer
          description: Number of parcels in the shipment.
          format: int32
        expectedWeight:
          type: number
          description: Total weight in kilograms of the shipment (sum of parcel weights).
          format: double
        deliveryNote:
          maxLength: 35
          type: string
          description: Delivery note.
          nullable: true
          example: Please, leave it behind the door.
        clientReference:
          maxLength: 35
          type: string
          description: >-
            The identifier that links the package in the Poiint system with the
            order in the client's e-shop.
          example: A-1234567
        enrichments:
          $ref: '#/components/schemas/Dtos.Enrichments'
        deliveryAddress:
          $ref: '#/components/schemas/Dtos.Address'
        parcelShop:
          $ref: '#/components/schemas/Dtos.ParcelShop'
      additionalProperties: false
    CreateOrderEndpoint.Response:
      required:
        - id
        - poiintId
      type: object
      properties:
        id:
          type: string
          description: "Identifier of the order in Poiint Business database.\r\nThis identifier can be used to submit existing order."
          format: uuid
          example: 5f7d212d-de28-42fa-aa40-2eb0883cc4ce
        poiintId:
          type: string
          description: "Identifier of the order printed on the packet labels.\r\nThis identifier can be used to track the status of the order via our official website.\r\nIt has a fixed format (P + 13 digits)."
          example: P0123456789999
      additionalProperties: false
    Dtos.Address:
      required:
        - city
        - country
        - houseNumber
        - street
        - zipCode
      type: object
      properties:
        country:
          type: string
          description: ISO 3166-1 alpha-2 code of the country.
          example: SK
        zipCode:
          type: string
          description: Valid zip code of the country without whitespaces.
          example: '90901'
        city:
          type: string
          description: Name of the city.
          example: Skalica
        street:
          type: string
          description: "Name of the street.\r\nIn case of a parcel shop delivery, house number can be part of the street."
          example: Mallého
        houseNumber:
          type: string
          description: "House number.\r\nIn case of a parcel shop delivery, house number can be part of the street."
          example: '22'
      additionalProperties: false
    Dtos.Consignee:
      required:
        - email
        - firstName
        - lastName
        - name
        - phoneNumber
      type: object
      properties:
        name:
          maxLength: 35
          type: string
          description: "Name of the consignee.\r\nThis can be a company name or full name of the recipient."
          nullable: true
          example: John Doe
        firstName:
          maxLength: 35
          type: string
          description: First name of the recipient.
          example: John
        lastName:
          maxLength: 35
          type: string
          description: Last name of the recipient.
          example: Doe
        email:
          type: string
          description: Email of the recipient.
          format: email
          example: john.doe@gmail.com
        phoneNumber:
          type: string
          description: >-
            Phone number of the recipient in international format (starting with
            +).
          example: '+421907654123'
      additionalProperties: false
    Dtos.Enrichments:
      type: object
      properties:
        cod:
          $ref: '#/components/schemas/Dtos.Money'
        parcelValue:
          $ref: '#/components/schemas/Dtos.Money'
        icc:
          type: boolean
          description: True, if ID card check is requested.
      additionalProperties: false
    Dtos.Money:
      required:
        - amount
        - currency
      type: object
      properties:
        amount:
          type: number
          description: Amount of the money.
          format: double
          example: 4.99
        currency:
          type: string
          description: Currency ISO code from ISO 4217.
          example: EUR
      additionalProperties: false
    Dtos.ParcelShop:
      required:
        - address
        - id
      type: object
      properties:
        id:
          type: string
        address:
          $ref: '#/components/schemas/Dtos.Address'
      additionalProperties: false
    GetUnavailablePickupDatesEndpoint.Response:
      required:
        - dates
      type: object
      properties:
        dates:
          type: array
          items:
            type: string
          description: Array of dates in format MM/DD/YYYY.
      additionalProperties: false
    ProblemDetails:
      type: object
      properties:
        type:
          type: string
          nullable: true
        title:
          type: string
          nullable: true
        status:
          type: integer
          format: int32
          nullable: true
        detail:
          type: string
          nullable: true
        instance:
          type: string
          nullable: true
        errors:
          type: object
          additionalProperties:
            type: array
            items:
              type: string
      additionalProperties: {}
    RefreshEndpoint.Response:
      required:
        - accessToken
        - apiKeys
        - routes
      type: object
      properties:
        accessToken:
          type: string
          description: >-
            JSON Web Token required for authorization of requests for order
            creation and submission.
        apiKeys:
          $ref: '#/components/schemas/RefreshEndpoint.Response.MapComponentApiKeys'
        routes:
          type: array
          items:
            $ref: '#/components/schemas/RefreshEndpoint.Response.Route'
          description: >-
            An array of objects, where each object contains carriers and their
            configuration for a single route.
      additionalProperties: false
    RefreshEndpoint.Response.Carrier:
      required:
        - enrichments
        - logo
        - name
        - pickupType
        - publicId
        - validations
      type: object
      properties:
        publicId:
          type: integer
          description: "Public identifier of the carrier.\r\nUse this value to identify the carrier in order creation process."
          format: int32
        name:
          type: string
          description: The name of the carrier that will deliver the shipment.
          example: DHL
        logo:
          type: string
          description: URI on which logo of this carrier can be downloaded.
        cooperatingCarrierName:
          type: string
          description: Name of the carrier that will pick up the shipment.
          nullable: true
          example: Packeta
        cooperatingCarrierLogo:
          type: string
          description: URI on which logo of a cooperating carrier can be downloaded.
          nullable: true
        pickupType:
          type: string
          description: "Pickup type configured for the carrier.\r\nPossible values: R (regular), I (irregular), D (drop-off)"
          example: R
        enrichments:
          $ref: '#/components/schemas/RefreshEndpoint.Response.Enrichments'
        validations:
          $ref: '#/components/schemas/RefreshEndpoint.Response.Validations'
      additionalProperties: false
    RefreshEndpoint.Response.CarriersConfiguration:
      required:
        - homeDelivery
        - parcelShopDelivery
      type: object
      properties:
        homeDelivery:
          type: array
          items:
            $ref: '#/components/schemas/RefreshEndpoint.Response.Carrier'
          description: Carriers that support home delivery on given route.
        parcelShopDelivery:
          type: array
          items:
            $ref: '#/components/schemas/RefreshEndpoint.Response.Carrier'
          description: Carriers that support parcel shop delivery on given route.
      additionalProperties: false
    RefreshEndpoint.Response.Enrichments:
      required:
        - icc
        - maxCod
        - maxParcelValue
      type: object
      properties:
        maxCod:
          $ref: '#/components/schemas/Dtos.Money'
        maxParcelValue:
          $ref: '#/components/schemas/Dtos.Money'
        icc:
          type: boolean
          description: True, if ID card check is supported by the carrier on given route.
      additionalProperties: false
    RefreshEndpoint.Response.MapComponentApiKeys:
      required:
        - dpd
        - packeta
      type: object
      properties:
        dpd:
          type: string
          description: API key required for DPD map widget to work.
        packeta:
          type: string
          description: API key required for PACKETA map widget to work.
      additionalProperties: false
    RefreshEndpoint.Response.Route:
      required:
        - carriers
        - countryFrom
        - countryTo
      type: object
      properties:
        countryFrom:
          type: string
          description: Sender country (start of the route).
          example: SK
        countryTo:
          type: string
          description: Consignee country (end of the route).
          example: NL
        carriers:
          $ref: '#/components/schemas/RefreshEndpoint.Response.CarriersConfiguration'
      additionalProperties: false
    RefreshEndpoint.Response.Validations:
      required:
        - consigneePhoneNumberFormat
      type: object
      properties:
        consigneePhoneNumberFormat:
          type: boolean
          description: "True, if recipient's phone number format must be valid for the country.\r\nFor example, if recipient's country is SK and this value is true, then recipient's phone number must start with +421 (phone number prefix for SK)."
      additionalProperties: false
    SubmitOrderEndpoint.RequestBody:
      required:
        - pickupDate
      type: object
      properties:
        pickupDate:
          type: string
          description: "Pickup date in format YYYY-MM-DD (the date when the courier will come for the parcel).\r\nRequired only for orders with irregular pickup schedules."
          nullable: true
          example: '2026-08-20'
      additionalProperties: false
    SubmitOrderEndpoint.Response:
      required:
        - trackingUrl
      type: object
      properties:
        trackingUrl:
          type: string
          description: URL on which successfully submitted order can be tracked.
      additionalProperties: false
  securitySchemes:
    Bearer:
      type: http
      description: Access token in HTTP request header.
      scheme: bearer
      bearerFormat: JWT
    ApiKey:
      type: apiKey
      description: API key in HTTP request header.
      name: X-Api-Key
      in: header
