{ "openapi": "3.0.2", "info": { "title": "Ferry - waterfront-backend", "version": "1.0.0" }, "servers": [ { "url": "https:\/\/waterfront.sandwaveio.dev" } ], "paths": { "\/ferry\/customers\/{customer}\/subscriptions": { "post": { "summary": "Create a batch of subscriptions for the given customer.", "description": "This endpoint is called to create a batch of placeholder subscriptions\nfor a specific customer being migrated. These placeholder may in later\nsteps be further expanded to full domain subscriptions, hosting\nsubscriptions, etc., each according to the type of product it is linked\nto. See the [general migration flow](https:\/\/sandwaveio.atlassian.net\/wiki\/spaces\/DEV\/pages\/1285095704).\n\n### Process\n\nFor each subscription in the request:\n 1. Check if a subscription link to the same reference subscription ID and reference product ID already exists\n * If so: skip it and add it to the response as a failure\n 2. Create a new subscription based on the provided information\n * `technical_status` will be `DomainStatus::ACTIVE` for subscriptions in the extension product group,\n otherwise `TechnicalStatus::OK`\n * Subscription is stored silently: subscription creation listeners are skipped\n 3. Create a MigratedSubscription for the created subscription using the reference product ID and reference\n subscription ID from the request, also link this to the MigratedCustomer\n 4. Create a placeholder technical subscription if applicable\n * For an extension product create a DomainSubscription with the placeholder domain provider\n * For an ssl product create a SslSubscription with the placeholder SSL provider\n * For a hosting product create a HostingSubscription with the placeholder hosting provider", "parameters": [ { "name": "customer", "in": "path", "description": "The customer to create the subscriptions for", "required": true, "schema": { "type": "string" } } ], "requestBody": { "description": "In addition to the request schema, the following conditions are validated:\n* The `reference_customer_id` given in the request body must match a MigratedCustomer entity linked to the customer given in the URL.\n* For domain extension products:\n * Domain must be a valid top-level ICANN domain.\n * The domain extension (TLD) must be specified.\n* Each subscription must be linked to a product in the correct product group.\n * E.g. a subscription in the `domain_extensions` group should have a product slug that points to a product in the extension product group.\n* A valid product price must be available for each subscription.\n * The subscription must specify a valid product.\n * This product must have a prolongation price that matches the contract and billing period given for this subscription.", "content": { "application\/json": { "schema": { "type": "object", "required": [ "reference_customer_id", "subscriptions" ], "properties": { "reference_customer_id": { "description": "The customer's ID at the source business, which these subscriptions will be linked to", "type": "string", "example": "yh-1542" }, "subscriptions": { "description": "The subscriptions to create, grouped by product group", "type": "object", "properties": { "domain_extensions": { "type": "array", "items": { "type": "object", "required": [ "domain", "extension", "slug", "contract_period", "billing_period", "start_date", "next_contract_date", "next_billing_date", "reference_subscription_id", "reference_product_id" ], "properties": { "domain": { "description": "The domain to connect the subscription to (required for extension products)", "type": "string", "example": "customer-domain.co.uk" }, "extension": { "description": "The TLD matching the domain (required for extension products)", "type": "string", "example": "co.uk" }, "slug": { "description": "The slug for the product that this subscription is for (should match the current product group)", "type": "string", "example": "domain-nl" }, "contract_period": { "description": "The number of months that the contract for this subscription is valid for\n\nE.g. 36 for a three-year contract.", "type": "integer", "minimum": 1, "example": 36 }, "billing_period": { "description": "The number of months ahead that this subscription is billed for at a time (should not exceed contract_period)\n\nE.g. 12 if the subscription is billed yearly.", "type": "integer", "minimum": 1, "example": 12 }, "start_date": { "description": "The date that this subscription begins", "format": "date", "type": "string", "example": "2023-01-01" }, "next_contract_date": { "description": "The date when the contract for this subscription should be renewed", "format": "date", "type": "string", "example": "2026-01-01" }, "next_billing_date": { "description": "The date when this subscription should next be billed", "format": "date", "type": "string", "example": "2024-01-01" }, "reference_subscription_id": { "description": "The ID that this subscription had at the source business - will be stored for later reference", "type": "string", "example": "domain-1234" }, "reference_product_id": { "description": "The ID that the product for this subscription had at the source business - will be stored for later reference", "type": "string", "example": ".nl-domain" }, "internal_comment": { "description": "(optional) Any business-internal notes about this subscription", "type": "string", "example": "2023-02-01: Customer called about incorrect invoice\n2023-02-02: Special discount applied to invoice for this domain" } } } }, "hosting": { "type": "array", "items": { "$ref": "#\/components\/schemas\/PlaceholderSubscription" } }, "ssl": { "type": "array", "items": { "$ref": "#\/components\/schemas\/PlaceholderSubscription" } }, "reseller-discount": { "type": "array", "items": { "$ref": "#\/components\/schemas\/PlaceholderSubscription" } }, "manual-subscription": { "type": "array", "items": { "$ref": "#\/components\/schemas\/PlaceholderSubscription" } }, "dns": { "type": "array", "items": { "$ref": "#\/components\/schemas\/PlaceholderSubscription" } }, "other": { "type": "array", "items": { "$ref": "#\/components\/schemas\/PlaceholderSubscription" } }, "server": { "type": "array", "items": { "$ref": "#\/components\/schemas\/PlaceholderSubscription" } }, "domein-uitbreiding": { "type": "array", "items": { "$ref": "#\/components\/schemas\/PlaceholderSubscription" } } } } } } } } }, "responses": { "200": { "$ref": "#\/components\/responses\/FerryResponse" } } } } }, "components": { "schemas": { "PlaceholderSubscription": { "type": "object", "required": [ "slug", "contract_period", "billing_period", "start_date", "next_contract_date", "next_billing_date", "reference_subscription_id", "reference_product_id" ], "properties": { "domain": { "description": "The domain to connect the subscription to (required for extension products)", "type": "string", "example": "customer-domain.co.uk" }, "extension": { "description": "The TLD matching the domain (required for extension products)", "type": "string", "example": "co.uk" }, "slug": { "description": "The slug for the product that this subscription is for (should match the current product group)", "type": "string", "example": "domain-nl" }, "contract_period": { "description": "The number of months that the contract for this subscription is valid for\n\nE.g. 36 for a three-year contract.", "type": "integer", "minimum": 1, "example": 36 }, "billing_period": { "description": "The number of months ahead that this subscription is billed for at a time (should not exceed contract_period)\n\nE.g. 12 if the subscription is billed yearly.", "type": "integer", "minimum": 1, "example": 12 }, "start_date": { "description": "The date that this subscription begins", "format": "date", "type": "string", "example": "2023-01-01" }, "next_contract_date": { "description": "The date when the contract for this subscription should be renewed", "format": "date", "type": "string", "example": "2026-01-01" }, "next_billing_date": { "description": "The date when this subscription should next be billed", "format": "date", "type": "string", "example": "2024-01-01" }, "reference_subscription_id": { "description": "The ID that this subscription had at the source business - will be stored for later reference", "type": "string", "example": "domain-1234" }, "reference_product_id": { "description": "The ID that the product for this subscription had at the source business - will be stored for later reference", "type": "string", "example": ".nl-domain" }, "internal_comment": { "description": "(optional) Any business-internal notes about this subscription", "type": "string", "example": "2023-02-01: Customer called about incorrect invoice\n2023-02-02: Special discount applied to invoice for this domain" } } }, "FerryResponseSchema": { "description": "This is the standard response given by Ferry API endpoints. It consists of\nany number of success and failure messages.", "type": "object", "properties": { "success": { "description": "Messages about successfully started \/ completed operations", "type": "array", "items": { "$ref": "#\/components\/schemas\/FerryResponseMessage" } }, "failures": { "description": "Messages about successfully started \/ completed operations", "type": "array", "items": { "$ref": "#\/components\/schemas\/FerryResponseMessage" } } } }, "FerryResponseMessage": { "description": "This is a standard message returned in a Ferry API response, consisting of a\nmessage with optional parameters and base parameters.", "type": "object", "required": [ "message" ], "properties": { "message": { "type": "string", "example": "Subscription 1234 was successfully processed" }, "parameters": { "type": "array", "items": { "$ref": "#\/components\/schemas\/FerryResponseMessageParameter" } }, "baseParameters": { "type": "array", "items": { "$ref": "#\/components\/schemas\/FerryResponseMessageParameter" } } } }, "FerryResponseMessageParameter": { "description": "This is a basic parameter in a Ferry API response, consisting of a key and\na value.", "type": "object", "required": [ "message" ], "properties": { "key": { "type": "string", "example": "customerId" }, "value": { "type": "string", "example": "1234" } } } }, "responses": { "FerryResponse": { "description": "A number of entities were processed - see the response body for details for each entity", "content": { "application\/json": { "schema": { "$ref": "#\/components\/schemas\/FerryResponseSchema" } } } } } } }