openapi: 3.0.0
info:
  version: 2.3.2
  title: eIM ECO Operations API
  description: |

    #### Copyright
    © Aeris Communications, Inc. 2026. All rights reserved. No part of this document may be reproduced in any form without the written permission of the copyright owner.

    #### Disclaimer

    The contents of this document are subject to revision without notice due to continued progress in methodology, design and manufacturing.
    Aeris shall have no liability for any error or damage of any kind resulting from the use of this document.

    #### Trademark List

    All trademarks mentioned herein are the property of their respective owners.
    These are shown in the document Trademark Information.

    # Introduction

    This document describes the IoT Accelerator eIM ECO Operations API that provides lifecycle operations for eCO orders
    and job status retrieval.
    The eIM ECO Operations API is based on the Representational State Transfer (REST) interface.
    From this point on, the eIM ECO Operations API is referred to as API in this document.

    ## Scope

    This document covers the following topics:

    - An overview of the API

    - A detailed description of all operations offered by the API

    ## Prerequisites
    In this document, it is assumed that the user is familiar with the following:

    - Java Script Object Notation (JSON)

    - Basic understanding of REST web services

    - The [OpenAPI Initiative](https://www.openapis.org/) for the standardized format used in this document.

    ## Related Information
    The definition and explanation of acronyms and terminology and typographic conventions can be found in the following documents:

    - IoTA Glossary of Terms and Acronyms

    - Typographic Conventions

    # General API Guidelines

    ## Compatibility

    API audience must be prepared for compatible API extensions:

    - Be tolerant with unknown fields in the payload (see also Fowler's "TolerantReader" post), i.e. ignore new fields but do not eliminate them from payload if needed for subsequent PUT requests.
    - Be prepared that "x-extensible-enum" return parameter may deliver new values. Either be agnostic or provide default behavior for unknown values.
    - Be prepared to handle HTTP status codes not explicitly specified in endpoint definitions.
    - Follow the redirect when the server returns HTTP status 301 Moved Permanently.

    ## Security

    This section describes the security measures in the API. Security measures include authentication, authorization, and encryption.

    ### Authentication and Authorization

    The API uses OAuth2 and OpenID Connect (OIDC) for authentication and authorization.

    All API endpoints require authentication, which is performed by passing a token in the Authorization header in each request, preceded by the word Bearer and a space. See the following example:
    ```
    curl -i -X GET "http://<baseURL>/iot/api/x-entities" -H "Content-Type: application/json" -H "Authorization: Bearer <TOKEN_GOES_HERE>"
    ```
    To fetch the token using e.g. curl, submit the following:
    ```
    curl -X POST "https://<baseURL>/iot/api/auth/token" -H "Accept: application/vnd.dcp-v1+json" -H "Content-Type: application/x-www-form-urlencoded" -d "grant_type=password&client_id=<client_id>&username=<username>&password=<password>"
    ```

    ### Encryption

    All API requests are encrypted using the HTTPS protocol to grant secure data transfer.

    ## Deprecation

    API deprecation will be reflected in the OpenAPI definition. If a method on a path, a whole path or even a whole API endpoint (multiple paths) should be deprecated, they will be marked as deprecated.
    During deprecation phase, a Deprecation header and a Sunset header fields will be added in the response.

    Example:
    ```
    Deprecation: Tue, 31 Dec 2024 23:59:59 GMT
    Sunset: Wed, 31 Dec 2025 23:59:59 GMT
    ```

    API audience should not start using a deprecated API.

    API audience is encouraged to monitor for Deprecation and Sunset header.

  x-audience: external-public
servers:
  - url: 'https://iot-api.aeris.com/iot/api'
    description: API server
tags:
  - name: 'EimEcoOperation'
    description: eCO eIM order operations and job status
paths:
  /eco/add-eim-order:
    post:
      tags:
        - 'EimEcoOperation'
      summary: Create add eIM order
      operationId: createAddEimOrder
      description: Creates an eCO add-eIM-order request.
      parameters:
        - $ref: '#/components/parameters/Header-Content-Type'
        - $ref: '#/components/parameters/Header-Accept-Version'
        - name: Accept
          in: header
          description: Accept content-type and schemas by the client
          content:
            application/json:
              schema:
                type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AddEimOrderRequestV1'
            examples:
              Add eIM order request:
                $ref: '#/components/examples/AddEimOrderRequestExample'
      responses:
        '200':
          description: eIM order request accepted for processing
          allOf:
            - $ref: '#/components/responses/RateLimitedResponse'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EimOrderResponseV1'
              examples:
                Add eIM order response:
                  $ref: '#/components/examples/EimOrderResponseExample'
        '400':
          $ref: '#/components/responses/400'
        '401':
          $ref: '#/components/responses/401'
        '403':
          $ref: '#/components/responses/403'
        '406':
          $ref: '#/components/responses/406'
        '415':
          $ref: '#/components/responses/415'
        '500':
          $ref: '#/components/responses/500'
        default:
          description: Internal Server Error
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
      security:
        - OAuth2:
            - 'cnx_eim_eco_add'

  /eco/update-eim-order:
    post:
      tags:
        - 'EimEcoOperation'
      summary: Create update eIM order
      operationId: createUpdateEimOrder
      description: Creates an eCO update-eIM-order request.
      parameters:
        - $ref: '#/components/parameters/Header-Content-Type'
        - $ref: '#/components/parameters/Header-Accept-Version'
        - name: Accept
          in: header
          description: Accept content-type and schemas by the client
          content:
            application/json:
              schema:
                type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateEimOrderRequestV1'
            examples:
              Update eIM order request:
                $ref: '#/components/examples/UpdateEimOrderRequestExample'
      responses:
        '200':
          description: eIM order request accepted for processing
          allOf:
            - $ref: '#/components/responses/RateLimitedResponse'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EimOrderResponseV1'
              examples:
                Update eIM order response:
                  $ref: '#/components/examples/EimOrderResponseExample'
        '400':
          $ref: '#/components/responses/400'
        '401':
          $ref: '#/components/responses/401'
        '406':
          $ref: '#/components/responses/406'
        '415':
          $ref: '#/components/responses/415'
        '500':
          $ref: '#/components/responses/500'
        default:
          description: Internal Server Error
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
      security:
        - OAuth2:
            - 'cnx_eim_eco_update'

  /eco/delete-eim-order:
    post:
      tags:
        - 'EimEcoOperation'
      summary: Create delete eIM order
      operationId: createDeleteEimOrder
      description: Creates an eCO delete-eIM-order request.
      parameters:
        - $ref: '#/components/parameters/Header-Content-Type'
        - $ref: '#/components/parameters/Header-Accept-Version'
        - name: Accept
          in: header
          description: Accept content-type and schemas by the client
          content:
            application/json:
              schema:
                type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DeleteEimOrderRequestV1'
            examples:
              Delete eIM order request:
                $ref: '#/components/examples/DeleteEimOrderRequestExample'
      responses:
        '200':
          description: eIM order request accepted for processing
          allOf:
            - $ref: '#/components/responses/RateLimitedResponse'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EimOrderResponseV1'
              examples:
                Delete eIM order response:
                  $ref: '#/components/examples/EimOrderResponseExample'
        '400':
          $ref: '#/components/responses/400'
        '401':
          $ref: '#/components/responses/401'
        '406':
          $ref: '#/components/responses/406'
        '415':
          $ref: '#/components/responses/415'
        '500':
          $ref: '#/components/responses/500'
        default:
          description: Internal Server Error
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
      security:
        - OAuth2:
            - 'cnx_eim_eco_delete'

  /eco/list-eim-order:
    post:
      tags:
        - 'EimEcoOperation'
      summary: Create list eIM order
      operationId: createListEimOrder
      description: Creates an eCO list-eIM-order request.
      parameters:
        - $ref: '#/components/parameters/Header-Content-Type'
        - $ref: '#/components/parameters/Header-Accept-Version'
        - name: Accept
          in: header
          description: Accept content-type and schemas by the client
          content:
            application/json:
              schema:
                type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ListEimOrderRequestV1'
            examples:
              List eIM order request:
                $ref: '#/components/examples/ListEimOrderRequestExample'
      responses:
        '200':
          description: eIM order request accepted for processing
          allOf:
            - $ref: '#/components/responses/RateLimitedResponse'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EimOrderResponseV1'
              examples:
                List eIM order response:
                  $ref: '#/components/examples/EimOrderResponseExample'
        '400':
          $ref: '#/components/responses/400'
        '401':
          $ref: '#/components/responses/401'
        '406':
          $ref: '#/components/responses/406'
        '415':
          $ref: '#/components/responses/415'
        '500':
          $ref: '#/components/responses/500'
        default:
          description: Internal Server Error
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
      security:
        - OAuth2:
            - 'cnx_eim_eco_view'

  /eco/job/{ecoJobId}/status:
    get:
      tags:
        - 'EimEcoOperation'
      summary: Get eCO job status
      operationId: getEimEcoJobStatus
      description: Get status for an eCO job (parent and per-resource).
      parameters:
        - $ref: '#/components/parameters/Header-Content-Type'
        - $ref: '#/components/parameters/Header-Accept-Version'
        - name: Accept
          in: header
          description: Accept content-type and schemas by the client
          content:
            application/json:
              schema:
                type: string
        - name: ecoJobId
          in: path
          description: ECO job id.
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Job status payload returned
          allOf:
            - $ref: '#/components/responses/RateLimitedResponse'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EimEcoJobStatusResponseV1'
              examples:
                eCO job status response:
                  $ref: '#/components/examples/EimEcoJobStatusResponseExample'
        '400':
          $ref: '#/components/responses/400'
        '401':
          $ref: '#/components/responses/401'
        '403':
          $ref: '#/components/responses/403'
        '404':
          $ref: '#/components/responses/404'
        '500':
          $ref: '#/components/responses/500'
        default:
          description: Internal Server Error
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
      security:
        - OAuth2:
            - 'cnx_eim_eco_view'

components:
  schemas:
    Problem:
      type: object
      properties:
        type:
          type: string
          format: uri
          description: |
            An absolute URI that identifies the problem type. When dereferenced,
            it SHOULD provide human-readable documentation for the problem type
            (e.g., using HTML).
          default: about:blank
          example: https://your.api.documentation.url
        title:
          type: string
          description: |
            A short, summary of the problem type. Written in english and readable
            for engineers (usually not suited for non technical stakeholders and
            not localized)
          example: 'Service Unavailable'
        status:
          type: integer
          format: int32
          description: |
            The HTTP status code generated by the origin server for this occurrence
            of the problem.
          minimum: 100
          maximum: 600
          exclusiveMaximum: true
          example: 503
        detail:
          type: string
          description: |
            A human readable explanation specific to this occurrence of the
            problem.
          example: Connection to database timed out
        instance:
          type: string
          description: |
            An absolute URI that identifies the specific occurrence of the problem.
            It may or may not yield further information if dereferenced.
          example: 'https://api.documentation.url/request-id'

    EimOrderRequestV1:
      type: object
      required:
        - executorEimId
      properties:
        euiccIds:
          type: array
          items:
            type: string
        companyId:
          type: string
        organizationId:
          type: string
        agreementId:
          type: string
        localeId:
          type: string
        executorEimId:
          type: string

    AddEimOrderRequestV1:
      allOf:
        - $ref: '#/components/schemas/EimOrderRequestV1'
        - type: object
          required:
            - targetEimId
          properties:
            targetEimId:
              type: string

    UpdateEimOrderRequestV1:
      allOf:
        - $ref: '#/components/schemas/EimOrderRequestV1'
        - type: object
          required:
            - targetEimId
          properties:
            targetEimId:
              type: string

    DeleteEimOrderRequestV1:
      allOf:
        - $ref: '#/components/schemas/EimOrderRequestV1'
        - type: object
          required:
            - targetEimId
          properties:
            targetEimId:
              type: string

    ListEimOrderRequestV1:
      allOf:
        - $ref: '#/components/schemas/EimOrderRequestV1'

    ResultCode:
      type: string
      enum:
        - SUCCESS
        - FAILED_RESOURCES

    EimOrderResponseV1:
      type: object
      required:
        - jobId
        - resultCode
      properties:
        jobId:
          type: string
        resultCode:
          $ref: '#/components/schemas/ResultCode'

    EimEcoJobInfoV1:
      type: object
      properties:
        createdByName:
          type: string
        createdByUserId:
          type: string
        organization:
          type: string
        status:
          type: string
          example: COMPLETED
        targetEim:
          type: string
        executorEim:
          type: string
        operation:
          type: string
          example: ADD
        size:
          type: integer
          format: int32
        errorMessage:
          type: string

    EimEcoResourceStatusV1:
      type: object
      properties:
        euiccId:
          type: string
          example: '89012345678901234567'
        status:
          type: string
          example: COMPLETED
        errorMessage:
          type: string

    EimEcoJobStatusResponseV1:
      type: object
      properties:
        jobInfo:
          $ref: '#/components/schemas/EimEcoJobInfoV1'
        success:
          type: array
          items:
            $ref: '#/components/schemas/EimEcoResourceStatusV1'
        inProgress:
          type: array
          items:
            $ref: '#/components/schemas/EimEcoResourceStatusV1'
        failure:
          type: array
          items:
            $ref: '#/components/schemas/EimEcoResourceStatusV1'

  responses:
    RateLimitedResponse:
      headers:
        X-RateLimit-Limit-Second:
          $ref: '#/components/headers/X-RateLimit-Limit-Second'
        X-RateLimit-Limit-Minute:
          $ref: '#/components/headers/X-RateLimit-Limit-Minute'
        X-RateLimit-Remaining-Second:
          $ref: '#/components/headers/X-RateLimit-Remaining-Second'
        X-RateLimit-Remaining-Minute:
          $ref: '#/components/headers/X-RateLimit-Remaining-Minute'
        Content-Type:
          $ref: '#/components/headers/Content-Type'
    '400':
      description: Bad Request
      headers:
        Content-Type:
          $ref: '#/components/headers/Content-Type'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          example:
            type: "https://your.api.documentation.url/bad-request"
            title: "Bad Request"
            status: 400
            detail: "The request could not be understood by the server due to malformed syntax"
            instance: "https://api.documentation.url/request-id"
    '401':
      description: Unauthorized
      headers:
        Content-Type:
          $ref: '#/components/headers/Content-Type'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          example:
            type: "https://your.api.documentation.url/unauthorized"
            title: "Unauthorized"
            status: 401
            detail: "Authentication credentials were missing or incorrect"
            instance: "https://api.documentation.url/request-id"
    '403':
      description: Forbidden
      headers:
        Content-Type:
          $ref: '#/components/headers/Content-Type'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          example:
            type: "https://your.api.documentation.url/forbidden"
            title: "Forbidden"
            status: 403
            detail: "The server understood the request but refuses to authorize it"
            instance: "https://api.documentation.url/request-id"
    '404':
      description: Not Found
      headers:
        Content-Type:
          $ref: '#/components/headers/Content-Type'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          example:
            type: "https://your.api.documentation.url/not-found"
            title: "Not Found"
            status: 404
            detail: "The requested resource could not be found"
            instance: "https://api.documentation.url/request-id"
    '406':
      description: Not Acceptable
      headers:
        Content-Type:
          $ref: '#/components/headers/Content-Type'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          example:
            type: "https://your.api.documentation.url/not-acceptable"
            title: "Not Acceptable"
            status: 406
            detail: "Unsupported response type"
            instance: "https://api.documentation.url/request-id"
    '415':
      description: Unsupported Media Type
      headers:
        Content-Type:
          $ref: '#/components/headers/Content-Type'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          example:
            type: "https://your.api.documentation.url/unsupported-media-type"
            title: "Unsupported Media Type"
            status: 415
            detail: "Unsupported media type"
            instance: "https://api.documentation.url/request-id"
    '500':
      description: Internal Server Error
      headers:
        Content-Type:
          $ref: '#/components/headers/Content-Type'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          example:
            type: "https://your.api.documentation.url/internal-server-error"
            title: "Internal Server Error"
            status: 500
            detail: "The server encountered an unexpected condition that prevented it from fulfilling the request"
            instance: "https://api.documentation.url/request-id"

  examples:
    AddEimOrderRequestExample:
      value:
        euiccIds:
          - "89012345678901234567"
          - "89012345678901234568"
        companyId: "company-10001"
        organizationId: "org-10001"
        agreementId: "agreement-2001"
        localeId: "locale-01"
        executorEimId: "EXEC-EIM-01"
        targetEimId: "TARGET-EIM-01"

    UpdateEimOrderRequestExample:
      value:
        euiccIds:
          - "89012345678901234567"
          - "89012345678901234568"
        companyId: "company-10001"
        organizationId: "org-10001"
        agreementId: "agreement-2001"
        localeId: "locale-01"
        executorEimId: "EXEC-EIM-01"
        targetEimId: "TARGET-EIM-02"

    DeleteEimOrderRequestExample:
      value:
        euiccIds:
          - "89012345678901234567"
          - "89012345678901234568"
        companyId: "company-10001"
        organizationId: "org-10001"
        agreementId: "agreement-2001"
        localeId: "locale-01"
        executorEimId: "EXEC-EIM-01"
        targetEimId: "TARGET-EIM-02"

    ListEimOrderRequestExample:
      value:
        euiccIds:
          - "89012345678901234567"
          - "89012345678901234568"
        companyId: "company-10001"
        organizationId: "org-10001"
        agreementId: "agreement-2001"
        localeId: "locale-01"
        executorEimId: "EXEC-EIM-01"

    EimOrderResponseExample:
      value:
        jobId: "JOB-123456"
        resultCode: "SUCCESS"

    EimEcoJobStatusResponseExample:
      value:
        jobInfo:
          createdByName: "Alex Doe"
          createdByUserId: "user-2001"
          organization: "org-10001"
          status: "IN_PROGRESS"
          targetEim: "TARGET-EIM-01"
          executorEim: "EXEC-EIM-01"
          operation: "EUICC_ADD_EIM"
          size: 2
        success:
          - euiccId: "89012345678901234567"
            status: "COMPLETED"
        inProgress:
          - euiccId: "89012345678901234568"
            status: "IN_PROGRESS"
        failure:
          - euiccId: "89012345678901234569"
            status: "FAILED"
            errorMessage: "Executor eIM rejected operation"

  parameters:
    Header-Accept:
      name: Accept
      in: header
      description: Accept content-type by the client
      schema:
        type: string
    Header-Accept-Version:
      name: Accept-Version
      in: header
      description: Accept version of the response
      schema:
        type: string
    Header-Content-Type:
      name: Content-Type
      in: header
      description: Content-Type
      schema:
        type: string

  headers:
    Content-Type:
      description: Handle Content-Type
      schema:
        type: string
    X-RateLimit-Limit-Second:
      description: The maximum number of requests allowed in a second.
      schema:
        type: integer
        format: int32
    X-RateLimit-Limit-Minute:
      description: The maximum number of requests allowed in a minute.
      schema:
        type: integer
        format: int32
    X-RateLimit-Remaining-Second:
      description: The number of requests remaining in a second.
      schema:
        type: integer
        format: int32
    X-RateLimit-Remaining-Minute:
      description: The number of requests remaining in a minute.
      schema:
        type: integer
        format: int32

  securitySchemes:
    OAuth2:
      type: oauth2
      description: The resources in the API are protected using the OAuth 2.0 protocol
      flows:
        clientCredentials:
          tokenUrl: https://iot-api.aeris.com/iot/api/auth/token
          scopes:
            cnx_eim_eco_add: Grant client access to create add eCO operations
            cnx_eim_eco_update: Grant client access to create update eCO operations
            cnx_eim_eco_delete: Grant client access to create delete eCO operations
            cnx_eim_eco_view: Grant client access to create/list eCO operations and read eCO job status
