{
  "openapi": "3.0.1",
  "info": {
    "description": "This is the documentation for the Ratepay webhook subscription API. This API allows to manage webhook subscriptions by creating new subscriptions,\ngetting a list of all active subscriptions, updating specific subscriptions or cancelling active subscriptions.\n\n# Payload properties\n\nThe subscription consists of an event type that triggers the call of a URL, and a secret that is applied to the payload.\nThere is an N:M association between the event type and the URL. A subscriber can create multiple event types for one URL and\nit is possible to subscribe to the same event type with different URLs.\n\n## ID\n\nEvery subscription is identified with a [nanoid](https://github.com/ai/nanoid). The ID is required for updating and deleting a subscription.\n\n## URL\n\nThe URL is the API resource endpoint the payload is sent to.\nThe endpoint **must** be able to process **HTTP POST** requests with payload inside the body, no other HTTP method will be called.\nAs the API does not inform about an incorrect URL, the correctness should be validated by the client.\nFor example:\n* https://dev_api.important-merchant.com/customers/invoices\n* https://api-m.sandbox.baseurl.com/v2/customer/orders\n\n## Event Type\n\nEach event type is bound to **one** URL. If it is necessary to respond to different event types with the same URL,\na new subscription is required for each event type.\nThe API sends messages to each URL configured for a given event type.\n\n## Secret\n\nThe secret enables us to validate Ratepay as the originator of a received payload. The secret **must** be at least **64** characters long.\nIt is recommended to use one secret per URL to avoid a man-in-the-middle attack, but this is not required.\nThe webhook service signs the payload using the provided secret with the SHA-512 cryptographic hash function.\nThe hash is calculated on a string representation of the payload. I.e. if the payload is\n```javascript\n{\n  \"key\": \"value\"\n}\n```\nthen the input for the hash calculation is `'{\"key\":\"value\"}'`. The resulting signature for this example with the secret `abc123` would be `4c131d60caea39b5f65625b80270e5305d5a00ebc5d15a00ecf82da9de2fcc8ff45df068a11f8b336890b161eb1fdefafe452d2e452623b37e4bd3277bb348fd`.\nThe 512-bit signature is inserted in the header named **x-signature**.\n\n# Retries\n\nIf a webhook call to a configured URL fails, this API will try to repeat the identical call at a later time.\nThis process is repeated multiple times with increasing intervals between retries.\nWhen the maximum number of retries is reached, an alarm is raised and a Ratepay employee is notified.\nNo further attempts are made to reach the URL until the error is resolved.\nA webhook call is failed if it either times out or if the response code `x` is not in the range `200<=x<300`.\n",
    "title": "Subscription webhooks",
    "version": "1.0.0",
    "contact": {
      "email": "info@ratepay.com",
      "name": "Ratepay",
      "url": "https://www.ratepay.com"
    }
  },
  "servers": [
    {
      "description": "Ratepay integration platform",
      "url": "https://api-integration.ratepay.com"
    }
  ],
  "paths": {
    "/webhook/management/v1": {
      "get": {
        "tags": [
          "Endpoints"
        ],
        "summary": "Endpoint to retrieve all owned subscriptions.",
        "description": "Retrieves all subscriptions created and owned by the client identified by the JWT token.",
        "operationId": "getSubscriptions",
        "parameters": [
          {
            "name": "Authorization",
            "in": "header",
            "description": "For each request, a valid access token must be provided in the Authorization header. See                       [Authentication API](/docs/developer/authentication/authentication/) for obtaining a valid token.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Array of subscriptions",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ArraySubscriptionsDto"
                }
              }
            }
          },
          "403": {
            "description": "Bad request due to corrupt or invalid authentication information.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/status_code_403"
                }
              }
            }
          },
          "405": {
            "description": "Bad request because the HTTP method is not allowed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/status_code_405"
                }
              }
            }
          },
          "406": {
            "description": "Bad request because the server cannot produce a response matching the list of acceptable values.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/status_code_406"
                }
              }
            }
          },
          "500": {
            "description": "An internal server error occurred while processing the request.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/status_code_500"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Endpoints"
        ],
        "description": "Creates a new webhook subscription accessible only to the client.",
        "operationId": "createSubscription",
        "parameters": [
          {
            "name": "Authorization",
            "in": "header",
            "description": "For each request, a valid access token must be provided in the Authorization header. See                       [Authentication API](/docs/developer/authentication/authentication/) for obtaining a valid token.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "summary": "Endpoint to create a new subscription.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateSubscriptionDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The subscription was created.",
            "headers": {
              "Location": {
                "description": "The URL to retrieve all owned subscriptions.",
                "schema": {
                  "type": "string",
                  "format": "url"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubscriptionDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad request due to a client error in path parameters, header or body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/status_code_400"
                }
              }
            }
          },
          "405": {
            "description": "Bad request because the HTTP method is not allowed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/status_code_405"
                }
              }
            }
          },
          "406": {
            "description": "Bad request because the server cannot produce a response matching the list of acceptable values.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/status_code_406"
                }
              }
            }
          },
          "415": {
            "description": "Bad request because the payload format is not supported.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/status_code_415"
                }
              }
            }
          },
          "500": {
            "description": "An internal server error occurred while processing the request.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/status_code_500"
                }
              }
            }
          }
        }
      }
    },
    "/webhook/management/v1/{id}": {
      "put": {
        "tags": [
          "Endpoints"
        ],
        "summary": "Endpoint to update the properties of the subscription.",
        "operationId": "updateSubscription",
        "description": "# Update Subscription\n---\n\nThe request body must contain the complete information about the subscription.\n\nThe following values can be updated: The __URL__ used for the webhook, the __event type__ applied to this URL and the __secret__, which is used to sign the payload.\nIt is not possible to change the identification of the subscription.\n\nOmitting properties from the request body (e.g. secret) will result in a validation error and return the status code 400.\n",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "$ref": "#/components/schemas/id"
            },
            "required": true,
            "description": "Subscription ID received when creating a subscription."
          },
          {
            "name": "Authorization",
            "in": "header",
            "description": "For each request, a valid access token must be provided in the Authorization header. See                       [Authentication API](/docs/developer/authentication/authentication/) for obtaining a valid token.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubscriptionWihoutIdDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK. The subscription was updated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubscriptionDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad request due to a client error in path parameters, header or body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/status_code_400"
                }
              }
            }
          },
          "401": {
            "description": "Bad request because the client cannot be authorized.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/status_code_401"
                }
              }
            }
          },
          "403": {
            "description": "Bad request because the client is not allowed to update the resource.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/status_code_403"
                }
              }
            }
          },
          "404": {
            "description": "Bad request because the resource cannot be found.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/status_code_404"
                }
              }
            }
          },
          "405": {
            "description": "Bad request because the HTTP method is not allowed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/status_code_405"
                }
              }
            }
          },
          "406": {
            "description": "Bad request because the server cannot produce a response matching the list of acceptable values.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/status_code_406"
                }
              }
            }
          },
          "415": {
            "description": "Bad request because the payload format is not supported.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/status_code_415"
                }
              }
            }
          },
          "500": {
            "description": "An internal server error occured while processing the request.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/status_code_500"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Endpoints"
        ],
        "summary": "Endpoint to unsubscribe from the subscription.",
        "description": "To resubscribe, you need to create a new subscription.",
        "operationId": "deleteSubscription",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "$ref": "#/components/schemas/id"
            },
            "required": true,
            "description": "ID of the subscription to be deleted."
          },
          {
            "name": "Authorization",
            "in": "header",
            "description": "For each request, a valid access token must be provided in the Authorization header. See                       [Authentication API](/docs/developer/authentication/authentication/) for obtaining a valid token.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "OK. The subscription was successfully deleted."
          },
          "400": {
            "description": "Bad request due to a client error in path parameters, header or body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/status_code_400"
                }
              }
            }
          },
          "401": {
            "description": "Bad request because the client cannot be authorized.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/status_code_401"
                }
              }
            }
          },
          "403": {
            "description": "Bad request because the client is not allowed to delete the resource.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/status_code_403"
                }
              }
            }
          },
          "404": {
            "description": "Bad request because the resource cannot be found.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/status_code_404"
                }
              }
            }
          },
          "405": {
            "description": "Bad request because the HTTP method is not allowed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/status_code_405"
                }
              }
            }
          },
          "406": {
            "description": "Bad request because the server cannot produce a response matching the list of acceptable values.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/status_code_406"
                }
              }
            }
          },
          "500": {
            "description": "An internal server error occurred while processing the request.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/status_code_500"
                }
              }
            }
          }
        }
      }
    }
  },
  "security": [
    {
      "JSON Web Token": []
    }
  ],
  "components": {
    "securitySchemes": {
      "JSON Web Token": {
        "description": "The authorization of an API user is validated through a JSON Web Token (JWT). The token should be located in the header as:\n\n* `Authorization: Bearer <jwttoken>`\n\nThe process to request a token is described in the [ratepay authentication documentation.](/docs/developer/authentication/authentication/)\n",
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JSON Web Token"
      }
    },
    "schemas": {
      "id": {
        "type": "string",
        "description": "ID of the subscription.",
        "example": "d8znR1k1_0Kw305BsoPT",
        "minLength": 20,
        "maxLength": 20,
        "pattern": "([A-Za-z0-9_-]{20})"
      },
      "id_object": {
        "type": "object",
        "properties": {
          "id": {
            "$ref": "#/components/schemas/id"
          }
        }
      },
      "ArraySubscriptionsDto": {
        "description": "Array of subscriptions.",
        "type": "array",
        "items": {
          "$ref": "#/components/schemas/SubscriptionDto"
        }
      },
      "SubscriptionDto": {
        "type": "object",
        "description": "Subscription element.",
        "properties": {
          "id": {
            "$ref": "#/components/schemas/id"
          },
          "url": {
            "type": "string",
            "format": "url",
            "description": "HTTP URL to execute the webhook call with the POST method.",
            "example": "https://api.merchant.com/event"
          },
          "event_type": {
            "type": "string",
            "description": "Type of the event to process by calling the API endpoint.",
            "example": "INVOICE_INVOICE"
          },
          "secret": {
            "type": "string",
            "minLength": 64,
            "description": "Parameter given by the client to sign their payloads. Recommended to be unique for each URL.",
            "example": "6GHbLH4d1Nx3eIs5CyLHCW4HuFi1qttpNSDawHKHlW7kurTpaddarwEKDWUI59IU"
          }
        }
      },
      "CreateSubscriptionDto": {
        "type": "object",
        "description": "Subscription element.",
        "required": [
          "url",
          "event_type",
          "secret"
        ],
        "properties": {
          "url": {
            "$ref": "#/components/schemas/SubscriptionDto/properties/url"
          },
          "event_type": {
            "$ref": "#/components/schemas/SubscriptionDto/properties/event_type"
          },
          "secret": {
            "$ref": "#/components/schemas/SubscriptionDto/properties/secret"
          }
        }
      },
      "SubscriptionWihoutIdDto": {
        "type": "object",
        "description": "Subscription element.",
        "required": [
          "url",
          "event_type",
          "secret"
        ],
        "properties": {
          "url": {
            "$ref": "#/components/schemas/SubscriptionDto/properties/url"
          },
          "event_type": {
            "$ref": "#/components/schemas/SubscriptionDto/properties/event_type"
          },
          "secret": {
            "$ref": "#/components/schemas/SubscriptionDto/properties/secret"
          }
        }
      },
      "status_code_400": {
        "description": "Bad request due to a client error in path parameters, header or body.",
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "example": "ValidationError"
          },
          "message": {
            "type": "string",
            "example": "Error while validating the JWT token.",
            "description": "A message containing the error."
          }
        }
      },
      "status_code_401": {
        "description": "Bad request because the client could not be authorized.",
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "example": "UnauthorizedError"
          },
          "message": {
            "type": "string",
            "example": "Bad request because the client could not be authorized.",
            "description": "A message containing the error."
          }
        }
      },
      "status_code_403": {
        "description": "Bad request because the client is not allowed to access the resource.",
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "example": "ForbiddenError"
          },
          "message": {
            "type": "string",
            "example": "Bad request because the client is not allowed to update the resource.",
            "description": "A message containing the error."
          }
        }
      },
      "status_code_404": {
        "description": "Bad request because the resource cannot be found.",
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "example": "NotFoundError"
          },
          "message": {
            "type": "string",
            "example": "Bad request because the resource cannot be found.",
            "description": "A message containing the error."
          }
        }
      },
      "status_code_405": {
        "description": "Bad request because the HTTP method is not allowed.",
        "type": "object",
        "properties": {
          "message": {
            "type": "string",
            "example": "Bad request because the HTTP method is not allowed.",
            "description": "A message containing the error."
          }
        }
      },
      "status_code_406": {
        "description": "Bad request because the server cannot produce a response matching the list of acceptable values.",
        "type": "object",
        "properties": {
          "message": {
            "type": "string",
            "example": "Bad request because the server cannot produce a response matching the list of acceptable values.",
            "description": "A message containing the error."
          }
        }
      },
      "status_code_415": {
        "description": "Bad request because the payload format is not supported.",
        "type": "object",
        "properties": {
          "message": {
            "type": "string",
            "example": "Bad request because the payload format is not supported.",
            "description": "A message containing the error."
          }
        }
      },
      "status_code_500": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string",
            "example": "Invalid authorization token.",
            "description": "A message containing the error."
          }
        }
      }
    }
  }
}