openapi: 3.0.0
info:
  version: 1.0.1-alpha1
  termsOfService: https://exoscale.com/terms
  contact:
    email: api@exoscale.com
    name: API support
    url: https://community.exoscale.ch/support
  description: API for Partners, Distributors, and Marketplace vendors
  title: Exoscale Partner API
tags:
  - description: The Metering API enables partners to send usage data for consolidated usage-based billing.
    externalDocs:
      description: Read more
      url: https://www.exoscale.com/partner-programs/
    name: metering
    x-display-name: Metering
    x-weight: 100
    x-icon: exo-logo
  - description: Provisioning and lifecycle management of end-customer organizations for members of the Exoscale distributor program.
    externalDocs:
      description: Read more
      url: https://www.exoscale.com/partner-programs/
    name: distributor-organization
    x-display-name: Distributor organization
    x-weight: 200
    x-icon: exo-logo
components:
  schemas:
    usage-data:
      type: object
      properties:
        product:
          type: string
          description: Product name
        variable:
          type: string
          description: variable name
        quantity:
          type: number
          description: Usage quantity, unit is product dependent
      description: Usage data
    metering-batch:
      type: object
      properties:
        usage:
          type: array
          items:
            $ref: '#/components/schemas/usage-data'
          description: Usage data
        organization:
          type: string
          format: uuid
          description: Target Org
      description: A batch of metered usage quantities
    input-webhook-aiven:
      type: object
      properties:
        message_id:
          type: string
          format: uuid
          description: The UUID of the event.
        message_type:
          type: string
          description: The type of the event.
        metadata:
          type: object
          properties:
            graceful_promotion:
              type: boolean
              description: Whether the promotion was caused by a planned change of the master, or an unplanned promotion.
            username:
              type: string
              description: Username found in credentials leak database
            table_count:
              type: integer
              format: int64
              description: A set of additional fields depend on the message type
            resource_type:
              type: string
              description: Automatic detection of the associated the resource type.
            service_type:
              type: string
              description: The type of the associated resource.
            more_info:
              type: string
              description: Short user-printable text describing the problem
            leak_url:
              type: string
              description: URL where the credential leak was found
            maintenance_scheduled_at:
              type: string
              description: Maintenance trigger deadline date
            users:
              type: array
              items:
                type: object
                properties:
                  username:
                    type: string
                  old_cert_expiry_time:
                    type: string
              description: Kafka service user certificates will expire soon and have been automatically renewed
          description: A set of additional fields depend on the message type
        project_name:
          type: string
          description: Name of the Aiven project that contains the service
        service_name:
          type: string
          description: Name of the Aiven service
        service_type:
          type: string
          description: Service type in a machine-readable format
        timestamp:
          type: integer
          format: int64
          description: The timestamp of the event as Unix epoch
      required:
        - message_id
        - message_type
      description: A map representing the payload of Aiven webhooks.
    ok-map:
      type: object
      properties:
        ok:
          type: boolean
    billing-address:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          description: Name of the recipient. The organization's display name
        country:
          type: string
          maxLength: 2
          minLength: 2
          description: 'Country code. Format: ISO 3166-1 alpha-2'
        city:
          type: string
          maxLength: 255
          minLength: 1
          description: City name
        postal-code:
          type: string
          maxLength: 80
          minLength: 1
          description: Postal code
        street-name:
          type: string
          minLength: 1
          description: Street name
        building-number:
          type: string
          maxLength: 255
          description: Building number
        address:
          type: string
          minLength: 1
          description: Free-text address fallback
      required:
        - name
        - country
        - city
        - postal-code
        - street-name
      description: ISO 20022 Structured Billing Address
    organization-input:
      type: object
      properties:
        display-name:
          type: string
          maxLength: 191
          minLength: 1
          description: Organization Display Name
        billing-address:
          $ref: '#/components/schemas/billing-address'
          description: ISO 20022 Structured Billing Address
        client-id:
          type: string
          maxLength: 191
          description: Organization Client ID
        owner-email:
          type: string
          maxLength: 75
          minLength: 1
          writeOnly: true
          description: Email Address of the first Owner
      required:
        - display-name
        - billing-address
        - owner-email
      description: Organization creation request
    organization-output:
      type: object
      properties:
        id:
          type: string
          format: uuid
          readOnly: true
          description: Organization ID
        status:
          type: string
          enum:
            - suspended
            - active
            - terminated
          readOnly: true
          description: Organization Status
        billing-address:
          $ref: '#/components/schemas/billing-address'
          description: ISO 20022 Structured Billing Address
        client-id:
          type: string
          maxLength: 191
          description: Organization Client ID
      description: Organization representation
servers:
  - url: https://partner-api.exoscale.com/v1.alpha
paths:
  /distributor/organization/{id}:schedule-purge:
    put:
      tags:
        - distributor-organization
      responses:
        "200":
          description: "200"
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    description: The message indicating that the Organization has been successfully purged.
        "202":
          description: "202"
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    description: The message indicating that the Organization has been successfully scheduled to be purged.
      description: Schedule the purge of an Organization linked to your Distributor Organization.
      parameters:
        - in: path
          required: true
          name: id
          schema:
            type: string
            format: uuid
      summary: ""
      operationId: schedule-purge-distributor-organization
  /metering:apply:
    post:
      tags:
        - metering
      responses:
        "204":
          description: "204"
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ok-map'
      description: |2+


        Submit usage metering for the given organization. The API accepts a set of
        `usage` entries. Each entry represents a product, its variable and a metering
        value. The value might be negative or decimal (up to five
        decimal places). Sample payload:

        ```json
        {
          'usage': [
            {
              'product': 'partner',
              'variable': 'license_product',
              'quantity': 3.1415
            },
            {
              'product': 'partner',
              'variable': 'commission',
              'quantity': -42.00005
            }
          ],
          'organization': 'bf9bbc88-71ea-407c-9920-fc1101d86183'
        }
        ```

      parameters: []
      summary: Apply metering transaction
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/metering-batch'
      operationId: metering-transaction
  /distributor/organization/{id}:suspend:
    put:
      tags:
        - distributor-organization
      responses:
        "200":
          description: "200"
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/organization-output'
      description: Suspend an Organization linked to your Distributor Organization.
      parameters:
        - in: path
          required: true
          name: id
          schema:
            type: string
            format: uuid
      summary: ""
      operationId: suspend-distributor-organization
  /distributor/organization:
    post:
      tags:
        - distributor-organization
      responses:
        "200":
          description: "200"
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/organization-output'
      description: Create an Organization linked to your Distributor Organization.
      parameters: []
      summary: ""
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/organization-input'
      operationId: create-distributor-organization
    get:
      tags:
        - distributor-organization
      responses:
        "200":
          description: "200"
          content:
            application/json:
              schema:
                type: object
                properties:
                  organizations:
                    type: array
                    items:
                      $ref: '#/components/schemas/organization-output'
                    description: The list of organizations.
      description: List Organizations linked to your Distributor Organization.
      parameters: []
      summary: ""
      operationId: list-distributor-organizations
  /distributor/organization/{id}:terminate:
    delete:
      tags:
        - distributor-organization
      responses:
        "200":
          description: "200"
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    description: The message indicating that the Organization has been successfully terminated.
      description: Terminate an Organization linked to your Distributor Organization.
      parameters:
        - in: path
          required: true
          name: id
          schema:
            type: string
            format: uuid
      summary: ""
      operationId: terminate-distributor-organization
  /distributor/organization/{id}/usage:
    get:
      tags:
        - distributor-organization
      responses:
        "200":
          description: "200"
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    code:
                      type: string
                      description: Usage Code
                    currency:
                      type: string
                      maxLength: 3
                      minLength: 3
                      description: 'Allowed values are: CHF, EUR, USD.'
                    total-excl-vat:
                      type: number
                      description: Expressed in the currency of the Organization.
                    total-incl-vat:
                      type: number
                      description: Expressed in the currency of the Organization.
                    start-date:
                      type: string
                      format: date-time
                      description: The start date for Usage statements
                    end-date:
                      type: string
                      format: date-time
                      description: The end date for Usage statements
                    usage:
                      type: array
                      items:
                        type: object
                        properties:
                          product:
                            type: string
                            description: The name of the product
                          variable:
                            type: string
                            description: The variable of the product
                          description:
                            type: string
                            description: Additional information about the usage statement
                          quantity:
                            type: number
                          unit:
                            type: string
                            description: Unit used for this usage statement
                          total-excl-vat:
                            type: number
                            description: The total amount of this Usage statement without VAT
                          total-incl-vat:
                            type: number
                            description: The total amount of this Usage statement with VAT
                      description: The usage statements
      description: List usage records of a sub-Organization.
      parameters:
        - in: path
          required: true
          name: id
          schema:
            type: string
            format: uuid
        - in: query
          required: false
          name: period
          schema:
            type: string
            maxLength: 7
            minLength: 7
      summary: ""
      operationId: list-distributor-organization-usage
  /distributor/organization/{id}:activate:
    put:
      tags:
        - distributor-organization
      responses:
        "200":
          description: "200"
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/organization-output'
      description: Activate an Organization linked to your Distributor Organization.
      parameters:
        - in: path
          required: true
          name: id
          schema:
            type: string
            format: uuid
      summary: ""
      operationId: activate-distributor-organization
  /distributor/organization/{id}:
    get:
      tags:
        - distributor-organization
      responses:
        "200":
          description: "200"
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/organization-output'
      description: Get an Organization linked to your Distributor Organization.
      parameters:
        - in: path
          required: true
          name: id
          schema:
            type: string
            format: uuid
      summary: ""
      operationId: get-distributor-organization
x-topics:
  - title: API Request Signature
    content: |2

      In order to authenticate legitimate users, the Exoscale API requires incoming requests to be signed using valid Exoscale API account credentials with the following mechanism.


      ## Signature Mechanism

      The *message* (i.e. content) to sign contains several segments concatenated using a line return character (`\n`). All segments must be included and in the described order, including empty ones depending on the context of the request (e.g. no request body).

      * Request method and request URL (path only), separated by a space character
      * Request body
      * Request URL parameters (Query String) values, concatenated without separator. The matching parameter names have to be specified in the resulting signature header `signed-query-args=` pragma, separated by semicolons (e.g. `p1;p2;pN`).
      * Request header values, concatenated without separator (none at the moment, leave empty)
      * Request expiration date in UNIX timestamp format

      Example *message* to sign for `GET /v2/resource/a02baf5a-a3e4-49a0-857b-8a08d276c1c0?p1=v1&p2=v2` :

      ```
      GET /v2/resource/a02baf5a-a3e4-49a0-857b-8a08d276c1c0

      v1v2

      1599140767
      ```

      The request signature consists of the [HMAC][hmac] hash of the base64-encoded *message* and the Exoscale API secret using the SHA265 function:

      ```
      signature = HMAC_SHA256(Exoscale API secret, BASE64_ENCODE(message))
      ```

      Finally, the computed signature must be added to the API request in a `Authorization` header such as:

      ```
      Authorization: EXO2-HMAC-SHA256 credential=<Exoscale API key>,expires=<expiration date UNIX timestamp>,signature=<signature>
      ```

      Example API query:

      ```
      GET /v2/resource/a02baf5a-a3e4-49a0-857b-8a08d276c1c0?p1=v1&p2=v2 HTTP/1.1
      Host: api-ch-gva-2.exoscale.com
      Authorization: EXO2-HMAC-SHA256 credential=EXO29147e9f89102b7ac1e88514,signed-query-args=p1;p2,expires=1599140767,signature=2AOBQsbElQb4FpKT/FM/9T4NobjlmZkSGvvdUth/xlY=
      ```


      ## Reference Implementations

      You can look up the following existing reference implementations:

      * Go: [github.com/exoscale/egoscale/api/v2 > `SecurityProviderExoscale.signRequest`](https://github.com/exoscale/egoscale/blob/master/v2/api/security.go)
      * Python: [requests-exoscale-auth > `ExoscaleV2Auth`](https://github.com/exoscale/requests-exoscale-auth/blob/master/exoscale_auth.py)

      [hmac]: https://en.wikipedia.org/wiki/HMAC
