{
  "openapi": "3.1.0",
  "info": {
    "title": "Qrona Newsletter API",
    "version": "1",
    "description": "Contacts, lists, contact fields, distribution lists, the suppression list, e-commerce and webhooks in Qrona Newsletter. Keys are created under Settings → API keys. Documentation: https://newsletter.qrona.se/en/developer",
    "contact": {
      "name": "Qrona",
      "email": "support@qrona.se",
      "url": "https://newsletter.qrona.se/en/developer"
    }
  },
  "servers": [
    {
      "url": "https://newsletter.qrona.se"
    }
  ],
  "tags": [
    {
      "name": "The key",
      "description": "Check that the key works, which workspace it applies to and what it is allowed to do."
    },
    {
      "name": "Contacts",
      "description": "Contacts are the workspace's recipients. A contact is identified by its email address, which never changes. Only create contacts who have consented to mailings (or where you have another legal basis): an active contact can be reached by mailings to distribution lists even if it is not on any list."
    },
    {
      "name": "Lists",
      "description": "Lists are audiences with their own sign-up mode: with double opt-in, new sign-ups must confirm by email."
    },
    {
      "name": "List members",
      "description": "Who is on a list, and sign-ups to it. Sign-ups via the API follow the same rules as the forms: anyone who has unsubscribed or been suppressed is never added without confirming themselves."
    },
    {
      "name": "Contact fields",
      "description": "The workspace's own fields – the keys that can be used in fields on a contact."
    },
    {
      "name": "Distribution lists",
      "description": "Distribution lists are contacts that meet conditions (segments). Requires the person behind the key to be an administrator."
    },
    {
      "name": "Suppression list",
      "description": "Addresses the workspace never sends to: unsubscribed, bouncing, spam complaints and suppressions added manually."
    },
    {
      "name": "Stores",
      "description": "A web shop in the workspace. Everything in e-commerce belongs to a store and is identified by the store's own IDs, which you choose. PUT creates or updates, so the same call can be repeated without anything being duplicated."
    },
    {
      "name": "Customers",
      "description": "People who have bought from the shop – with or without consent to mailings. A customer never becomes a contact: it is linked to the workspace contact with the same address as long as one exists, for purchase conditions in distribution lists."
    },
    {
      "name": "Products",
      "description": "The store's products with variants, for conditions such as “has bought product X”."
    },
    {
      "name": "Orders",
      "description": "The store's orders with lines. Paid orders count as purchases in conditions and as revenue for the campaign the customer came from (campaign_id)."
    },
    {
      "name": "Carts",
      "description": "Open carts. Delete the cart once it has become an order."
    },
    {
      "name": "Revenue",
      "description": "Revenue per campaign: the paid orders that came from the campaign's links."
    },
    {
      "name": "Batch",
      "description": "Up to 500 calls in one, for example to import old orders. Each operation is validated and run as if it had been sent on its own."
    },
    {
      "name": "Messages",
      "description": "One message at a time to one recipient, made from a Qrona template and the message's own data. Only for the add-on Byråstöd: Klientkommunikation, with Qrona's system key – a person's key cannot send messages."
    },
    {
      "name": "Qrona templates",
      "description": "The templates the messages are made from, designed in Qrona Newsletter against a data contract. Preview a template with data, exactly as it is sent."
    },
    {
      "name": "Webhooks",
      "description": "URLs that are notified of sign-ups, unsubscriptions, bounces and spam complaints in the workspace, signed with HMAC. Requires the person behind the key to be an administrator."
    }
  ],
  "paths": {
    "/api/v1": {
      "get": {
        "operationId": "root.get",
        "summary": "Get the key's details",
        "description": "Which workspace the key applies to, who it acts as and what it is allowed to do. Useful for testing the connection.\n\nAll valid keys.",
        "tags": [
          "The key"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [],
        "responses": {
          "200": {
            "description": "The key's details.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Root"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/contacts": {
      "get": {
        "operationId": "contacts.list",
        "summary": "List contacts",
        "description": "The contacts the key is allowed to see, in ID order, one page at a time.\n\nThe response contains the workspace's own contacts and those shared with it from a level above (shared: true), limited by the contact rules of the person behind the key.\n\nFetch the next page with cursor=next_cursor until has_more is false. For ongoing sync: save the time before you start and then fetch with updated_since.\n\nRequires: contacts:read.",
        "tags": [
          "Contacts"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "contacts:read"
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "The maximum number of items in the response (1–500, default 100).",
            "schema": {
              "default": 100,
              "type": "integer",
              "minimum": 1,
              "maximum": 500
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "next_cursor from the previous response, for the next page. Omit for the first page.",
            "schema": {
              "type": "string",
              "maxLength": 400
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Only contacts with this status. If omitted: all except deleted.",
            "schema": {
              "type": "string",
              "enum": [
                "active",
                "unsubscribed",
                "bounced",
                "complained",
                "deleted"
              ]
            }
          },
          {
            "name": "list_id",
            "in": "query",
            "required": false,
            "description": "Only contacts who are on the list (regardless of the membership's status).",
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
            }
          },
          {
            "name": "segment_id",
            "in": "query",
            "required": false,
            "description": "Only contacts in the distribution list.",
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
            }
          },
          {
            "name": "tag",
            "in": "query",
            "required": false,
            "description": "Only contacts with this tag (exact spelling).",
            "schema": {
              "type": "string",
              "maxLength": 50
            }
          },
          {
            "name": "updated_since",
            "in": "query",
            "required": false,
            "description": "Only contacts changed since then (ISO 8601). Useful for sync: save the time of the previous fetch.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "origin",
            "in": "query",
            "required": false,
            "description": "own: only the workspace's own · shared: only those shared from a level above.",
            "schema": {
              "type": "string",
              "enum": [
                "own",
                "shared"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of contacts.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactPage"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: The details are invalid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "contacts.create",
        "summary": "Create contact",
        "description": "A new contact in the workspace. If the address already exists, the response is 409 contact_exists.\n\nconsent_source is the proof of consent and is required. Contact fields that are mandatory in the workspace must be included in fields.\n\nTo create or update in the same call: use POST /contacts/upsert.\n\nRequires: contacts:write.",
        "tags": [
          "Contacts"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "contacts:write"
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "A key of your choice (e.g. a UUID). The same key and the same call within 24 hours gives the same response again, without anything being done twice.",
            "schema": {
              "type": "string",
              "maxLength": 255
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "email": {
                    "type": "string",
                    "maxLength": 254,
                    "description": "The email address.",
                    "example": "anna@example.se"
                  },
                  "first_name": {
                    "description": "First name.",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 100
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "last_name": {
                    "description": "Last name.",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 100
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "company": {
                    "description": "Company.",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 200
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "phone": {
                    "description": "Phone number. Without a country code, it is interpreted according to the workspace's country.",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 50
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "fields": {
                    "type": "object",
                    "propertyNames": {
                      "type": "string",
                      "pattern": "^[a-z0-9_]{1,40}$"
                    },
                    "additionalProperties": {
                      "anyOf": [
                        {
                          "type": "string",
                          "maxLength": 1000
                        },
                        {
                          "type": "number"
                        },
                        {
                          "type": "boolean"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "description": "Custom fields by key (GET /fields). The values are checked against the field's type. null or \"\" removes a value. Keys that are not fields in the workspace are saved as free-form fields. Sensitive fields (personal identity numbers) cannot be set via the API.",
                    "example": {
                      "kundnummer": "K-2041",
                      "ort": "Göteborg"
                    }
                  },
                  "tags": {
                    "maxItems": 50,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "maxLength": 50
                    },
                    "description": "Tags.",
                    "example": [
                      "kund"
                    ]
                  },
                  "consent_source": {
                    "type": "string",
                    "minLength": 3,
                    "maxLength": 255,
                    "description": "How the person consented to mailings, in your own words. Saved as proof.",
                    "example": "Kryssade i rutan i kassan på butik.se"
                  },
                  "list_ids": {
                    "description": "Lists to add the contact to directly (as when a person adds a contact in the app).",
                    "maxItems": 100,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
                    }
                  }
                },
                "required": [
                  "email",
                  "consent_source"
                ],
                "additionalProperties": false
              },
              "example": {
                "email": "anna@example.se",
                "first_name": "Anna",
                "last_name": "Svensson",
                "fields": {
                  "kundnummer": "K-2041"
                },
                "tags": [
                  "kund"
                ],
                "consent_source": "Kryssade i rutan i kassan på butik.se"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The new contact.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactDetail"
                }
              }
            }
          },
          "400": {
            "description": "bad_request: The request could not be read",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "contact_exists: The contact already exists · suppressed: The address is suppressed · idempotency_in_progress: The request is already in progress",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "unsupported_media_type: Wrong content type",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: The details are invalid · idempotency_key_reused: Idempotency-Key already in use",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/contacts/upsert": {
      "post": {
        "operationId": "contacts.upsert",
        "summary": "Create or update contact",
        "description": "Creates the contact if the address is new; otherwise it is updated. The usual call for an integration.\n\nResponds 201 when the contact was created and 200 when it was updated. Only the fields you send are changed. add_tags/remove_tags change tags without touching the others.\n\nconsent_source is required when the contact is created. The address is sent in the body, never in the URL, so that it does not end up in logs.\n\nList membership is not changed here: sign up to a list with POST /lists/{id}/members.\n\nRequires: contacts:write.",
        "tags": [
          "Contacts"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "contacts:write"
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "A key of your choice (e.g. a UUID). The same key and the same call within 24 hours gives the same response again, without anything being done twice.",
            "schema": {
              "type": "string",
              "maxLength": 255
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "email": {
                    "type": "string",
                    "maxLength": 254,
                    "description": "The email address.",
                    "example": "anna@example.se"
                  },
                  "first_name": {
                    "description": "First name.",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 100
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "last_name": {
                    "description": "Last name.",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 100
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "company": {
                    "description": "Company.",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 200
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "phone": {
                    "description": "Phone number. Without a country code, it is interpreted according to the workspace's country.",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 50
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "fields": {
                    "type": "object",
                    "propertyNames": {
                      "type": "string",
                      "pattern": "^[a-z0-9_]{1,40}$"
                    },
                    "additionalProperties": {
                      "anyOf": [
                        {
                          "type": "string",
                          "maxLength": 1000
                        },
                        {
                          "type": "number"
                        },
                        {
                          "type": "boolean"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "description": "Custom fields by key (GET /fields). The values are checked against the field's type. null or \"\" removes a value. Keys that are not fields in the workspace are saved as free-form fields. Sensitive fields (personal identity numbers) cannot be set via the API.",
                    "example": {
                      "kundnummer": "K-2041",
                      "ort": "Göteborg"
                    }
                  },
                  "tags": {
                    "maxItems": 50,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "maxLength": 50
                    },
                    "description": "Replaces all tags. Do not use together with add_tags/remove_tags.",
                    "example": [
                      "kund"
                    ]
                  },
                  "add_tags": {
                    "maxItems": 50,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "maxLength": 50
                    },
                    "description": "Tags to add; the others are kept.",
                    "example": [
                      "kund"
                    ]
                  },
                  "remove_tags": {
                    "maxItems": 50,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "maxLength": 50
                    },
                    "description": "Tags to remove.",
                    "example": [
                      "kund"
                    ]
                  },
                  "consent_source": {
                    "description": "How the person consented. Required when the contact is created; changes nothing on an existing contact.",
                    "type": "string",
                    "minLength": 3,
                    "maxLength": 255,
                    "example": "Kryssade i rutan i kassan på butik.se"
                  }
                },
                "required": [
                  "email"
                ],
                "additionalProperties": false
              },
              "example": {
                "email": "anna@example.se",
                "first_name": "Anna",
                "fields": {
                  "kundnummer": "K-2041"
                },
                "add_tags": [
                  "kund"
                ],
                "consent_source": "Kryssade i rutan i kassan på butik.se"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The contact (201 if it was created).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactDetail"
                }
              }
            }
          },
          "400": {
            "description": "bad_request: The request could not be read",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "shared_contact: The contact is shared · forbidden: Not allowed · insufficient_scope: The key lacks the required scope · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "contact_erased: The contact has been erased · suppressed: The address is suppressed · idempotency_in_progress: The request is already in progress",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "unsupported_media_type: Wrong content type",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: The details are invalid · idempotency_key_reused: Idempotency-Key already in use",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/contacts/lookup": {
      "post": {
        "operationId": "contacts.lookup",
        "summary": "Look up contacts by email",
        "description": "Up to 100 addresses in one call. The response has the contacts that exist (all statuses, including deleted).\n\nThe addresses are sent in the body so that they do not end up in logs. An address can give two matches: a contact of your own and a shared one from a level above.\n\nRequires: contacts:read.",
        "tags": [
          "Contacts"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "contacts:read"
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "A key of your choice (e.g. a UUID). The same key and the same call within 24 hours gives the same response again, without anything being done twice.",
            "schema": {
              "type": "string",
              "maxLength": 255
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "emails": {
                    "minItems": 1,
                    "maxItems": 100,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "maxLength": 254
                    },
                    "description": "Up to 100 addresses.",
                    "example": [
                      "anna@example.se",
                      "bo@example.se"
                    ]
                  }
                },
                "required": [
                  "emails"
                ],
                "additionalProperties": false
              },
              "example": {
                "emails": [
                  "anna@example.se",
                  "bo@example.se"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The contacts that exist.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactList"
                }
              }
            }
          },
          "400": {
            "description": "bad_request: The request could not be read",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "idempotency_in_progress: The request is already in progress",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "unsupported_media_type: Wrong content type",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: The details are invalid · idempotency_key_reused: Idempotency-Key already in use",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/contacts/{id}": {
      "get": {
        "operationId": "contacts.get",
        "summary": "Get contact",
        "description": "A contact with the lists it is on.\n\nRequires: contacts:read.",
        "tags": [
          "Contacts"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "contacts:read"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The contact's ID.",
            "schema": {
              "type": "string",
              "pattern": "^\\d{1,20}$",
              "example": "1042"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The contact.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactDetail"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "contacts.update",
        "summary": "Update contact",
        "description": "Changes the fields you send. The email address cannot be changed.\n\nOnly the workspace's own contacts can be changed: a shared contact returns 403 shared_contact.\n\nRequires: contacts:write.",
        "tags": [
          "Contacts"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "contacts:write"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The contact's ID.",
            "schema": {
              "type": "string",
              "pattern": "^\\d{1,20}$",
              "example": "1042"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "first_name": {
                    "description": "First name.",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 100
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "last_name": {
                    "description": "Last name.",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 100
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "company": {
                    "description": "Company.",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 200
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "phone": {
                    "description": "Phone number. Without a country code, it is interpreted according to the workspace's country.",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 50
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "fields": {
                    "type": "object",
                    "propertyNames": {
                      "type": "string",
                      "pattern": "^[a-z0-9_]{1,40}$"
                    },
                    "additionalProperties": {
                      "anyOf": [
                        {
                          "type": "string",
                          "maxLength": 1000
                        },
                        {
                          "type": "number"
                        },
                        {
                          "type": "boolean"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "description": "Custom fields by key (GET /fields). The values are checked against the field's type. null or \"\" removes a value. Keys that are not fields in the workspace are saved as free-form fields. Sensitive fields (personal identity numbers) cannot be set via the API.",
                    "example": {
                      "kundnummer": "K-2041",
                      "ort": "Göteborg"
                    }
                  },
                  "tags": {
                    "maxItems": 50,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "maxLength": 50
                    },
                    "description": "Replaces all tags. Do not use together with add_tags/remove_tags.",
                    "example": [
                      "kund"
                    ]
                  },
                  "add_tags": {
                    "maxItems": 50,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "maxLength": 50
                    },
                    "description": "Tags to add; the others are kept.",
                    "example": [
                      "kund"
                    ]
                  },
                  "remove_tags": {
                    "maxItems": 50,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "maxLength": 50
                    },
                    "description": "Tags to remove.",
                    "example": [
                      "kund"
                    ]
                  }
                },
                "additionalProperties": false
              },
              "example": {
                "last_name": "Berg",
                "fields": {
                  "ort": "Malmö"
                },
                "remove_tags": [
                  "vip"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The contact after the change.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactDetail"
                }
              }
            }
          },
          "400": {
            "description": "bad_request: The request could not be read",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "shared_contact: The contact is shared · insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "unsupported_media_type: Wrong content type",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: The details are invalid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/contacts/{id}/unsubscribe": {
      "post": {
        "operationId": "contacts.unsubscribe",
        "summary": "Unsubscribe contact",
        "description": "The person does not want any more mailings: the contact leaves all lists, gets the status unsubscribed and the address is suppressed.\n\nSame as when the person unsubscribes themselves. Only the person can sign up again, by confirming by email. Does nothing if the contact is already unsubscribed.\n\nRequires: contacts:write.",
        "tags": [
          "Contacts"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "contacts:write"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The contact's ID.",
            "schema": {
              "type": "string",
              "pattern": "^\\d{1,20}$",
              "example": "1042"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "A key of your choice (e.g. a UUID). The same key and the same call within 24 hours gives the same response again, without anything being done twice.",
            "schema": {
              "type": "string",
              "maxLength": 255
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The contact after the unsubscription.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactDetail"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "shared_contact: The contact is shared · insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "idempotency_in_progress: The request is already in progress",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "idempotency_key_reused: Idempotency-Key already in use",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/contacts/{id}/erase": {
      "post": {
        "operationId": "contacts.erase",
        "summary": "Erase contact (GDPR)",
        "description": "Permanently erases the contact's personal data. The address is suppressed so that it never receives mailings again.\n\nName, phone, custom fields, tags and survey responses are removed, and the contact leaves all lists. What remains is the address in the suppression list and an entry in the consent log about the erasure. Cannot be undone.\n\nRequires the contacts:erase scope.\n\nRequires: contacts:erase.",
        "tags": [
          "Contacts"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "contacts:erase"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The contact's ID.",
            "schema": {
              "type": "string",
              "pattern": "^\\d{1,20}$",
              "example": "1042"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "A key of your choice (e.g. a UUID). The same key and the same call within 24 hours gives the same response again, without anything being done twice.",
            "schema": {
              "type": "string",
              "maxLength": 255
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Erased."
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "shared_contact: The contact is shared · insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "idempotency_in_progress: The request is already in progress",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "idempotency_key_reused: Idempotency-Key already in use",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/lists": {
      "get": {
        "operationId": "lists.list",
        "summary": "List lists",
        "description": "The workspace's lists with member counts.\n\nRequires: lists:read.",
        "tags": [
          "Lists"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "lists:read"
        ],
        "responses": {
          "200": {
            "description": "All lists.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListList"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "lists.create",
        "summary": "Create list",
        "description": "A new list. Double opt-in is on unless you say otherwise.\n\nRequires: lists:write.",
        "tags": [
          "Lists"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "lists:write"
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "A key of your choice (e.g. a UUID). The same key and the same call within 24 hours gives the same response again, without anything being done twice.",
            "schema": {
              "type": "string",
              "maxLength": 255
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  "description": {
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 1000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "double_opt_in": {
                    "description": "New sign-ups must confirm by email. Default: true.",
                    "type": "boolean"
                  }
                },
                "required": [
                  "name"
                ],
                "additionalProperties": false
              },
              "example": {
                "name": "Kunder från webbutiken",
                "double_opt_in": true
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The new list.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/List"
                }
              }
            }
          },
          "400": {
            "description": "bad_request: The request could not be read",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "idempotency_in_progress: The request is already in progress",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "unsupported_media_type: Wrong content type",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: The details are invalid · idempotency_key_reused: Idempotency-Key already in use",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/lists/{id}": {
      "get": {
        "operationId": "lists.get",
        "summary": "Get list",
        "description": "A list with member counts.\n\nRequires: lists:read.",
        "tags": [
          "Lists"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "lists:read"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The list's ID.",
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$",
              "example": "3f1c2a4e-8b7d-4c1e-9f0a-2d6b5e7c8a91"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The list.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/List"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "lists.update",
        "summary": "Update list",
        "description": "Name, description and sign-up mode.\n\nRequires: lists:write.",
        "tags": [
          "Lists"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "lists:write"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The list's ID.",
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$",
              "example": "3f1c2a4e-8b7d-4c1e-9f0a-2d6b5e7c8a91"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  "description": {
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 1000
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "double_opt_in": {
                    "description": "New sign-ups must confirm by email. Default: true.",
                    "type": "boolean"
                  }
                },
                "additionalProperties": false
              },
              "example": {
                "name": "Nyhetsbrev – kunder"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The list after the change.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/List"
                }
              }
            }
          },
          "400": {
            "description": "bad_request: The request could not be read",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "unsupported_media_type: Wrong content type",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: The details are invalid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "lists.delete",
        "summary": "Delete list",
        "description": "Deletes the list. The contacts remain. Not possible while a campaign that is due to be sent uses the list.\n\nRequires: lists:write.",
        "tags": [
          "Lists"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "lists:write"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The list's ID.",
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$",
              "example": "3f1c2a4e-8b7d-4c1e-9f0a-2d6b5e7c8a91"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted."
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "list_in_use: The list is in use",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/lists/{id}/members": {
      "get": {
        "operationId": "members.list",
        "summary": "List members",
        "description": "The list's members, one page at a time.\n\nRequires: lists:read, contacts:read.",
        "tags": [
          "List members"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "lists:read",
          "contacts:read"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The list's ID.",
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$",
              "example": "3f1c2a4e-8b7d-4c1e-9f0a-2d6b5e7c8a91"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "The maximum number of items in the response (1–500, default 100).",
            "schema": {
              "default": 100,
              "type": "integer",
              "minimum": 1,
              "maximum": 500
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "next_cursor from the previous response, for the next page. Omit for the first page.",
            "schema": {
              "type": "string",
              "maxLength": 400
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "subscribed: receives mailings · pending: awaiting confirmation · unsubscribed: has left · blocked: on the list but cannot be reached.",
            "schema": {
              "type": "string",
              "enum": [
                "subscribed",
                "pending",
                "unsubscribed",
                "blocked"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of members.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MemberPage"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: The details are invalid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "members.create",
        "summary": "Sign up to list",
        "description": "Signs an address up to the list, with proof of consent. The contact is created if it does not exist.\n\nWith status pending (the default on lists with double opt-in), the person receives a confirmation email and is added when they confirm. With subscribed, the person is added immediately – you then certify that consent exists.\n\nAnyone who has previously unsubscribed always gets a confirmation email, whatever you send: no integration can sign someone up again against their will. Addresses that bounce, have made a spam complaint, are deleted or are suppressed give 409 blocked.\n\nResponds 201 when something changed and 200 when the person was already a member (or has just been sent a confirmation email – a new one is sent no sooner than ten minutes later).\n\nRequires: contacts:write.",
        "tags": [
          "List members"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "contacts:write"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The list's ID.",
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$",
              "example": "3f1c2a4e-8b7d-4c1e-9f0a-2d6b5e7c8a91"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "A key of your choice (e.g. a UUID). The same key and the same call within 24 hours gives the same response again, without anything being done twice.",
            "schema": {
              "type": "string",
              "maxLength": 255
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "email": {
                    "type": "string",
                    "maxLength": 254,
                    "description": "The email address.",
                    "example": "anna@example.se"
                  },
                  "first_name": {
                    "description": "First name. Only fills in what is missing on an existing contact.",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 100
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "last_name": {
                    "description": "Last name.",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 100
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "company": {
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 200
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "status": {
                    "description": "subscribed: added immediately. pending: a confirmation email is sent and the person is added when they confirm. Default: the list's own mode. Anyone who has previously unsubscribed always receives a confirmation email.",
                    "type": "string",
                    "enum": [
                      "subscribed",
                      "pending"
                    ]
                  },
                  "consent": {
                    "type": "object",
                    "properties": {
                      "text": {
                        "type": "string",
                        "minLength": 10,
                        "maxLength": 5000,
                        "description": "Exactly the text the person agreed to.",
                        "example": "Ja, jag vill få nyhetsbrev från Exempel AB."
                      },
                      "source": {
                        "description": "Where it happened.",
                        "example": "Kassan på butik.se",
                        "type": "string",
                        "maxLength": 200
                      },
                      "ip": {
                        "description": "The person's IP address (not your server's).",
                        "type": "string",
                        "maxLength": 45
                      },
                      "user_agent": {
                        "description": "The person's browser.",
                        "type": "string",
                        "maxLength": 255
                      }
                    },
                    "required": [
                      "text"
                    ],
                    "additionalProperties": false,
                    "description": "The proof of consent. Saved in the consent log."
                  }
                },
                "required": [
                  "email",
                  "consent"
                ],
                "additionalProperties": false
              },
              "example": {
                "email": "anna@example.se",
                "first_name": "Anna",
                "consent": {
                  "text": "Ja, jag vill få nyhetsbrev från Exempel AB.",
                  "source": "Kassan på butik.se",
                  "ip": "203.0.113.7"
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The result (200 if nothing changed).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Subscription"
                }
              }
            }
          },
          "400": {
            "description": "bad_request: The request could not be read",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "blocked: The address does not receive mailings · sending_not_enabled: Mailings are not approved · idempotency_in_progress: The request is already in progress",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "unsupported_media_type: Wrong content type",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: The details are invalid · idempotency_key_reused: Idempotency-Key already in use",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/lists/{id}/members/{contact_id}": {
      "delete": {
        "operationId": "members.delete",
        "summary": "Remove from list",
        "description": "Removes the contact from the list (an administrative change, not an unsubscription).\n\nIf it is the person who no longer wants mailings: use POST /contacts/{id}/unsubscribe.\n\nRequires: contacts:write.",
        "tags": [
          "List members"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "contacts:write"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The list's ID.",
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$",
              "example": "3f1c2a4e-8b7d-4c1e-9f0a-2d6b5e7c8a91"
            }
          },
          {
            "name": "contact_id",
            "in": "path",
            "required": true,
            "description": "The contact's ID.",
            "schema": {
              "type": "string",
              "pattern": "^\\d{1,20}$",
              "example": "1042"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Removed (even if the contact was not a member)."
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "shared_contact: The contact is shared · insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/fields": {
      "get": {
        "operationId": "fields.list",
        "summary": "List contact fields",
        "description": "The workspace's custom fields, including those that come from a level above.\n\nRequires: fields:read.",
        "tags": [
          "Contact fields"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "fields:read"
        ],
        "responses": {
          "200": {
            "description": "All fields in use.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FieldList"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/segments": {
      "get": {
        "operationId": "segments.list",
        "summary": "List distribution lists",
        "description": "The workspace's distribution lists with counts. The contacts in one are fetched with GET /contacts?segment_id=.\n\nRequires: segments:read.",
        "tags": [
          "Distribution lists"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "segments:read"
        ],
        "responses": {
          "200": {
            "description": "All distribution lists.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SegmentList"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/segments/{id}": {
      "get": {
        "operationId": "segments.get",
        "summary": "Get distribution list",
        "description": "A distribution list with counts.\n\nRequires: segments:read.",
        "tags": [
          "Distribution lists"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "segments:read"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The distribution list's ID.",
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$",
              "example": "3f1c2a4e-8b7d-4c1e-9f0a-2d6b5e7c8a91"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The distribution list.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Segment"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/suppressions": {
      "get": {
        "operationId": "suppressions.list",
        "summary": "List suppressed addresses",
        "description": "The workspace's suppression list, one page at a time. Useful for keeping a web shop in sync with unsubscriptions.\n\nRequires: contacts:read.",
        "tags": [
          "Suppression list"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "contacts:read"
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "The maximum number of items in the response (1–500, default 100).",
            "schema": {
              "default": 100,
              "type": "integer",
              "minimum": 1,
              "maximum": 500
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "next_cursor from the previous response, for the next page. Omit for the first page.",
            "schema": {
              "type": "string",
              "maxLength": 400
            }
          },
          {
            "name": "reason",
            "in": "query",
            "required": false,
            "description": "Only suppressions of that type.",
            "schema": {
              "type": "string",
              "enum": [
                "unsubscribed",
                "bounced",
                "complained",
                "manual",
                "imported"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of suppressed addresses.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuppressionPage"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: The details are invalid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/stores": {
      "get": {
        "operationId": "stores.list",
        "summary": "List stores",
        "description": "The workspace's stores with how much each one has sent in.\n\nRequires: ecommerce:read.",
        "tags": [
          "Stores"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "ecommerce:read"
        ],
        "responses": {
          "200": {
            "description": "All stores.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StoreList"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/stores/{store_id}": {
      "get": {
        "operationId": "stores.get",
        "summary": "Get store",
        "description": "A store.\n\nRequires: ecommerce:read.",
        "tags": [
          "Stores"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "ecommerce:read"
        ],
        "parameters": [
          {
            "name": "store_id",
            "in": "path",
            "required": true,
            "description": "The store's ID, which you choose.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,64}$",
              "example": "butik-se"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The store.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Store"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "put": {
        "operationId": "stores.upsert",
        "summary": "Create or update store",
        "description": "Creates the store with your ID, or updates it. The first call for a web shop.\n\nResponds 201 when the store was created and 200 when it was updated. You choose the store's ID yourself (e.g. butik-se) and it never changes: everything else in e-commerce sits under /stores/{store_id}.\n\nWith domain, links to the shop in the workspace's mailings get the parameter qn_cid=<campaign id>. Save it in the shop when the customer arrives and send it as campaign_id on the order, and the order counts as the campaign's revenue.\n\nRequires: ecommerce:write.",
        "tags": [
          "Stores"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "ecommerce:write"
        ],
        "parameters": [
          {
            "name": "store_id",
            "in": "path",
            "required": true,
            "description": "The store's ID, which you choose.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,64}$",
              "example": "butik-se"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200,
                    "description": "The store's name, as shown in the app.",
                    "example": "Exempelbutiken"
                  },
                  "domain": {
                    "description": "The store's domain, e.g. butik.se. Links there (and to subdomains) in the workspace's mailings get qn_cid=<campaign ID>, which the shop sends back as campaign_id on the order.",
                    "example": "butik.se",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 253
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "currency": {
                    "type": "string",
                    "pattern": "^[A-Z]{3}$",
                    "description": "The store's currency (ISO 4217). Orders and carts without a currency of their own get it.",
                    "example": "SEK"
                  }
                },
                "required": [
                  "name",
                  "currency"
                ],
                "additionalProperties": false
              },
              "example": {
                "name": "Exempelbutiken",
                "domain": "butik.se",
                "currency": "SEK"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The store (201 if it was created).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Store"
                }
              }
            }
          },
          "400": {
            "description": "bad_request: The request could not be read",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "limit_reached: The limit has been reached",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "unsupported_media_type: Wrong content type",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: The details are invalid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "stores.delete",
        "summary": "Delete store",
        "description": "Deletes the store and everything in it: customers, products, orders and carts. Cannot be undone.\n\nThe campaigns' revenue from the store also disappears. The contacts in the workspace are not touched.\n\nRequires: ecommerce:write.",
        "tags": [
          "Stores"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "ecommerce:write"
        ],
        "parameters": [
          {
            "name": "store_id",
            "in": "path",
            "required": true,
            "description": "The store's ID, which you choose.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,64}$",
              "example": "butik-se"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted."
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/stores/{store_id}/customers": {
      "get": {
        "operationId": "customers.list",
        "summary": "List customers",
        "description": "The store's customers, one page at a time.\n\nRequires: ecommerce:read.",
        "tags": [
          "Customers"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "ecommerce:read"
        ],
        "parameters": [
          {
            "name": "store_id",
            "in": "path",
            "required": true,
            "description": "The store's ID, which you choose.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,64}$",
              "example": "butik-se"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "The maximum number of items in the response (1–500, default 100).",
            "schema": {
              "default": 100,
              "type": "integer",
              "minimum": 1,
              "maximum": 500
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "next_cursor from the previous response, for the next page. Omit for the first page.",
            "schema": {
              "type": "string",
              "maxLength": 400
            }
          },
          {
            "name": "updated_since",
            "in": "query",
            "required": false,
            "description": "Only what has changed since then (ISO 8601).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of customers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerPage"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: The details are invalid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/stores/{store_id}/customers/{customer_id}": {
      "get": {
        "operationId": "customers.get",
        "summary": "Get customer",
        "description": "A customer with the number of paid orders and their total.\n\nRequires: ecommerce:read.",
        "tags": [
          "Customers"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "ecommerce:read"
        ],
        "parameters": [
          {
            "name": "store_id",
            "in": "path",
            "required": true,
            "description": "The store's ID, which you choose.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,64}$",
              "example": "butik-se"
            }
          },
          {
            "name": "customer_id",
            "in": "path",
            "required": true,
            "description": "The customer's ID in your shop.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9._~:@-]{1,100}$",
              "example": "1042"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The customer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Customer"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "put": {
        "operationId": "customers.upsert",
        "summary": "Create or update customer",
        "description": "Creates the customer with the shop's ID, or updates it. Orders and carts do this themselves with their customer.\n\nA customer never becomes a contact and never receives mailings because they have made a purchase. If the customer has consented to newsletters: sign them up to a list with POST /lists/{id}/members, with the proof of consent.\n\nFields you omit are kept; null clears them. Returns 201 when the customer was created and 200 when it was updated.\n\nRequires: ecommerce:write.",
        "tags": [
          "Customers"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "ecommerce:write"
        ],
        "parameters": [
          {
            "name": "store_id",
            "in": "path",
            "required": true,
            "description": "The store's ID, which you choose.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,64}$",
              "example": "butik-se"
            }
          },
          {
            "name": "customer_id",
            "in": "path",
            "required": true,
            "description": "The customer's ID in your shop.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9._~:@-]{1,100}$",
              "example": "1042"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "email": {
                    "type": "string",
                    "maxLength": 254,
                    "description": "The customer's email address.",
                    "example": "anna@example.se"
                  },
                  "first_name": {
                    "description": "First name.",
                    "example": "Anna",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 100
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "last_name": {
                    "description": "Last name.",
                    "example": "Svensson",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 100
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "company": {
                    "description": "Company.",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 200
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                },
                "required": [
                  "email"
                ],
                "additionalProperties": false
              },
              "example": {
                "email": "anna@example.se",
                "first_name": "Anna",
                "last_name": "Svensson"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The customer (201 if it was created).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Customer"
                }
              }
            }
          },
          "400": {
            "description": "bad_request: The request could not be read",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "unsupported_media_type: Wrong content type",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: The details are invalid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "customers.delete",
        "summary": "Delete customer",
        "description": "Deletes the customer and their carts. The orders remain without a customer, so that the campaigns' revenue stays correct.\n\nUse when a customer asks to be erased from the shop. If a contact is erased in the workspace (GDPR), customers with the same address are removed in the same way.\n\nRequires: ecommerce:write.",
        "tags": [
          "Customers"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "ecommerce:write"
        ],
        "parameters": [
          {
            "name": "store_id",
            "in": "path",
            "required": true,
            "description": "The store's ID, which you choose.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,64}$",
              "example": "butik-se"
            }
          },
          {
            "name": "customer_id",
            "in": "path",
            "required": true,
            "description": "The customer's ID in your shop.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9._~:@-]{1,100}$",
              "example": "1042"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted."
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/stores/{store_id}/products": {
      "get": {
        "operationId": "products.list",
        "summary": "List products",
        "description": "The store's products with variants, one page at a time.\n\nRequires: ecommerce:read.",
        "tags": [
          "Products"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "ecommerce:read"
        ],
        "parameters": [
          {
            "name": "store_id",
            "in": "path",
            "required": true,
            "description": "The store's ID, which you choose.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,64}$",
              "example": "butik-se"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "The maximum number of items in the response (1–250, default 100).",
            "schema": {
              "default": 100,
              "type": "integer",
              "minimum": 1,
              "maximum": 250
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "next_cursor from the previous response, for the next page. Omit for the first page.",
            "schema": {
              "type": "string",
              "maxLength": 400
            }
          },
          {
            "name": "updated_since",
            "in": "query",
            "required": false,
            "description": "Only what has changed since then (ISO 8601).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of products.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProductPage"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: The details are invalid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/stores/{store_id}/products/{product_id}": {
      "get": {
        "operationId": "products.get",
        "summary": "Get product",
        "description": "A product with variants.\n\nRequires: ecommerce:read.",
        "tags": [
          "Products"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "ecommerce:read"
        ],
        "parameters": [
          {
            "name": "store_id",
            "in": "path",
            "required": true,
            "description": "The store's ID, which you choose.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,64}$",
              "example": "butik-se"
            }
          },
          {
            "name": "product_id",
            "in": "path",
            "required": true,
            "description": "The product's ID in your shop.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9._~:@-]{1,100}$",
              "example": "731"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The product.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Product"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "put": {
        "operationId": "products.upsert",
        "summary": "Create or update product",
        "description": "Creates the product with the shop's ID, or updates it. If variants is sent, it replaces all variants.\n\nFields you omit are kept; null clears them. Returns 201 when the product was created and 200 when it was updated.\n\nRequires: ecommerce:write.",
        "tags": [
          "Products"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "ecommerce:write"
        ],
        "parameters": [
          {
            "name": "store_id",
            "in": "path",
            "required": true,
            "description": "The store's ID, which you choose.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,64}$",
              "example": "butik-se"
            }
          },
          {
            "name": "product_id",
            "in": "path",
            "required": true,
            "description": "The product's ID in your shop.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9._~:@-]{1,100}$",
              "example": "731"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "title": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 255,
                    "description": "The product's name.",
                    "example": "T-shirt i ekologisk bomull"
                  },
                  "url": {
                    "description": "The product's page in the shop.",
                    "example": "https://butik.se/produkt/t-shirt",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 2048
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "image_url": {
                    "description": "The product's image.",
                    "example": "https://butik.se/bilder/t-shirt.jpg",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 2048
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "vendor": {
                    "description": "Manufacturer or brand.",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 255
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "product_type": {
                    "description": "Product type or category.",
                    "example": "Kläder",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 255
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "variants": {
                    "description": "The variants (at most 100). Replaces all variants when sent.",
                    "maxItems": 100,
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "pattern": "^[A-Za-z0-9._~:@-]{1,100}$",
                          "description": "The variant's ID in your shop.",
                          "example": "731-blue-m"
                        },
                        "title": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 255,
                          "example": "Blå, M"
                        },
                        "sku": {
                          "description": "SKU.",
                          "example": "TS-BLU-M",
                          "anyOf": [
                            {
                              "type": "string",
                              "maxLength": 100
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "price": {
                          "anyOf": [
                            {
                              "type": "number",
                              "minimum": 0,
                              "maximum": 999999999999.99,
                              "description": "Price per unit.",
                              "example": 249
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "inventory_quantity": {
                          "description": "Quantity in stock.",
                          "anyOf": [
                            {
                              "type": "integer",
                              "minimum": -1000000,
                              "maximum": 1000000000
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "url": {
                          "description": "The variant's page.",
                          "anyOf": [
                            {
                              "type": "string",
                              "maxLength": 2048
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "image_url": {
                          "description": "The variant's image.",
                          "anyOf": [
                            {
                              "type": "string",
                              "maxLength": 2048
                            },
                            {
                              "type": "null"
                            }
                          ]
                        }
                      },
                      "required": [
                        "id",
                        "title"
                      ],
                      "additionalProperties": false
                    }
                  }
                },
                "required": [
                  "title"
                ],
                "additionalProperties": false
              },
              "example": {
                "title": "T-shirt i ekologisk bomull",
                "url": "https://butik.se/produkt/t-shirt",
                "image_url": "https://butik.se/bilder/t-shirt.jpg",
                "product_type": "Kläder",
                "variants": [
                  {
                    "id": "731-blue-m",
                    "title": "Blå, M",
                    "sku": "TS-BLU-M",
                    "price": 249,
                    "inventory_quantity": 12
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The product (201 if it was created).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Product"
                }
              }
            }
          },
          "400": {
            "description": "bad_request: The request could not be read",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "unsupported_media_type: Wrong content type",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: The details are invalid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "products.delete",
        "summary": "Delete product",
        "description": "Deletes the product and its variants. Order lines that mention it remain.\n\nRequires: ecommerce:write.",
        "tags": [
          "Products"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "ecommerce:write"
        ],
        "parameters": [
          {
            "name": "store_id",
            "in": "path",
            "required": true,
            "description": "The store's ID, which you choose.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,64}$",
              "example": "butik-se"
            }
          },
          {
            "name": "product_id",
            "in": "path",
            "required": true,
            "description": "The product's ID in your shop.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9._~:@-]{1,100}$",
              "example": "731"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted."
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/stores/{store_id}/orders": {
      "get": {
        "operationId": "orders.list",
        "summary": "List orders",
        "description": "The store's orders with lines, one page at a time.\n\nRequires: ecommerce:read.",
        "tags": [
          "Orders"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "ecommerce:read"
        ],
        "parameters": [
          {
            "name": "store_id",
            "in": "path",
            "required": true,
            "description": "The store's ID, which you choose.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,64}$",
              "example": "butik-se"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "The maximum number of items in the response (1–250, default 100).",
            "schema": {
              "default": 100,
              "type": "integer",
              "minimum": 1,
              "maximum": 250
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "next_cursor from the previous response, for the next page. Omit for the first page.",
            "schema": {
              "type": "string",
              "maxLength": 400
            }
          },
          {
            "name": "customer_id",
            "in": "query",
            "required": false,
            "description": "Only the customer's orders (the store's customer ID).",
            "schema": {
              "type": "string",
              "maxLength": 100
            }
          },
          {
            "name": "campaign_id",
            "in": "query",
            "required": false,
            "description": "Only orders from the campaign.",
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
            }
          },
          {
            "name": "financial_status",
            "in": "query",
            "required": false,
            "description": "Only orders with that status.",
            "schema": {
              "type": "string",
              "enum": [
                "pending",
                "paid",
                "refunded",
                "cancelled"
              ]
            }
          },
          {
            "name": "updated_since",
            "in": "query",
            "required": false,
            "description": "Only what has changed since then (ISO 8601).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of orders.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrderPage"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: The details are invalid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/stores/{store_id}/orders/{order_id}": {
      "get": {
        "operationId": "orders.get",
        "summary": "Get order",
        "description": "An order with lines.\n\nRequires: ecommerce:read.",
        "tags": [
          "Orders"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "ecommerce:read"
        ],
        "parameters": [
          {
            "name": "store_id",
            "in": "path",
            "required": true,
            "description": "The store's ID, which you choose.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,64}$",
              "example": "butik-se"
            }
          },
          {
            "name": "order_id",
            "in": "path",
            "required": true,
            "description": "The order's ID in your shop.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9._~:@-]{1,100}$",
              "example": "50087"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The order.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Order"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "put": {
        "operationId": "orders.upsert",
        "summary": "Create or update order",
        "description": "Creates the order with the store's ID, or updates it – send the order again when it changes (paid, refunded, cancelled).\n\nThe order is sent in full: the customer, the total amount and all lines. The customer is created or updated with it, and the lines replace the previous ones. campaign_id, financial_status, currency, processed_at and the partial amounts keep their values if you omit them.\n\nOnly paid orders (paid) count as purchases in the distribution lists' conditions and as revenue for the campaign in campaign_id. Partially refunded: send the order again with the new total amount.\n\nResponds 201 when the order was created and 200 when it was updated.\n\nRequires: ecommerce:write.",
        "tags": [
          "Orders"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "ecommerce:write"
        ],
        "parameters": [
          {
            "name": "store_id",
            "in": "path",
            "required": true,
            "description": "The store's ID, which you choose.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,64}$",
              "example": "butik-se"
            }
          },
          {
            "name": "order_id",
            "in": "path",
            "required": true,
            "description": "The order's ID in your shop.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9._~:@-]{1,100}$",
              "example": "50087"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "customer": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string",
                        "pattern": "^[A-Za-z0-9._~:@-]{1,100}$",
                        "description": "The customer's ID in your shop.",
                        "example": "1042"
                      },
                      "email": {
                        "type": "string",
                        "maxLength": 254,
                        "description": "The customer's email address.",
                        "example": "anna@example.se"
                      },
                      "first_name": {
                        "description": "First name.",
                        "example": "Anna",
                        "anyOf": [
                          {
                            "type": "string",
                            "maxLength": 100
                          },
                          {
                            "type": "null"
                          }
                        ]
                      },
                      "last_name": {
                        "description": "Last name.",
                        "example": "Svensson",
                        "anyOf": [
                          {
                            "type": "string",
                            "maxLength": 100
                          },
                          {
                            "type": "null"
                          }
                        ]
                      },
                      "company": {
                        "description": "Company.",
                        "anyOf": [
                          {
                            "type": "string",
                            "maxLength": 200
                          },
                          {
                            "type": "null"
                          }
                        ]
                      }
                    },
                    "required": [
                      "id",
                      "email"
                    ],
                    "additionalProperties": false,
                    "description": "The customer. Created or updated with the order (same rules as PUT /customers/{customer_id})."
                  },
                  "campaign_id": {
                    "description": "The campaign the customer came from: the value of qn_cid on the link they clicked. Only counts for the workspace's own campaigns; an unknown ID is not saved (but the order is).",
                    "example": "6d1f0c3a-2b4e-4f6a-8c9d-0e1f2a3b4c5d",
                    "anyOf": [
                      {
                        "type": "string",
                        "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "financial_status": {
                    "description": "paid: paid – counts as a purchase · pending: awaiting payment · refunded: refunded · cancelled: cancelled. Default when the order is created: paid.",
                    "type": "string",
                    "enum": [
                      "pending",
                      "paid",
                      "refunded",
                      "cancelled"
                    ]
                  },
                  "currency": {
                    "description": "Default: the store's currency.",
                    "type": "string",
                    "pattern": "^[A-Z]{3}$",
                    "example": "SEK"
                  },
                  "order_total": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 999999999999.99,
                    "description": "The order's total amount, including VAT and shipping.",
                    "example": 548
                  },
                  "tax_total": {
                    "anyOf": [
                      {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 999999999999.99,
                        "description": "Of which VAT.",
                        "example": 109.6
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "shipping_total": {
                    "anyOf": [
                      {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 999999999999.99,
                        "description": "Of which shipping.",
                        "example": 49
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "discount_total": {
                    "anyOf": [
                      {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 999999999999.99,
                        "description": "Discount.",
                        "example": 0
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "processed_at": {
                    "description": "When the order was placed in the shop (ISO 8601). Default when the order is created: now. Send it when importing old orders.",
                    "example": "2026-10-12T14:03:00Z",
                    "type": "string"
                  },
                  "lines": {
                    "minItems": 1,
                    "maxItems": 500,
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "pattern": "^[A-Za-z0-9._~:@-]{1,100}$",
                          "description": "The line's ID in your shop.",
                          "example": "1"
                        },
                        "product_id": {
                          "type": "string",
                          "pattern": "^[A-Za-z0-9._~:@-]{1,100}$",
                          "description": "The product's ID in your shop.",
                          "example": "731"
                        },
                        "variant_id": {
                          "anyOf": [
                            {
                              "type": "string",
                              "pattern": "^[A-Za-z0-9._~:@-]{1,100}$",
                              "description": "The variant's ID in your shop.",
                              "example": "731-blue-m"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "title": {
                          "description": "What was bought, as it appeared on the order.",
                          "example": "T-shirt i ekologisk bomull, blå, M",
                          "anyOf": [
                            {
                              "type": "string",
                              "maxLength": 255
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "quantity": {
                          "type": "integer",
                          "minimum": 1,
                          "maximum": 1000000,
                          "description": "Quantity.",
                          "example": 2
                        },
                        "price": {
                          "type": "number",
                          "minimum": 0,
                          "maximum": 999999999999.99,
                          "description": "Price per unit.",
                          "example": 249
                        },
                        "discount": {
                          "anyOf": [
                            {
                              "type": "number",
                              "minimum": 0,
                              "maximum": 999999999999.99,
                              "description": "Discount on the line.",
                              "example": 499
                            },
                            {
                              "type": "null"
                            }
                          ]
                        }
                      },
                      "required": [
                        "id",
                        "product_id",
                        "quantity",
                        "price"
                      ],
                      "additionalProperties": false
                    },
                    "description": "The order's lines (at most 500). Replaces all lines. The products do not need to have been submitted."
                  }
                },
                "required": [
                  "customer",
                  "order_total",
                  "lines"
                ],
                "additionalProperties": false
              },
              "example": {
                "customer": {
                  "id": "1042",
                  "email": "anna@example.se",
                  "first_name": "Anna",
                  "last_name": "Svensson"
                },
                "campaign_id": "6d1f0c3a-2b4e-4f6a-8c9d-0e1f2a3b4c5d",
                "financial_status": "paid",
                "currency": "SEK",
                "order_total": 548,
                "tax_total": 109.6,
                "shipping_total": 49,
                "processed_at": "2026-10-12T14:03:00Z",
                "lines": [
                  {
                    "id": "1",
                    "product_id": "731",
                    "variant_id": "731-blue-m",
                    "title": "T-shirt i ekologisk bomull, blå, M",
                    "quantity": 2,
                    "price": 249
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The order (201 if it was created).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Order"
                }
              }
            }
          },
          "400": {
            "description": "bad_request: The request could not be read",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "unsupported_media_type: Wrong content type",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: The details are invalid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "orders.delete",
        "summary": "Delete order",
        "description": "Deletes the order. A cancelled or refunded order is better sent with its new status.\n\nRequires: ecommerce:write.",
        "tags": [
          "Orders"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "ecommerce:write"
        ],
        "parameters": [
          {
            "name": "store_id",
            "in": "path",
            "required": true,
            "description": "The store's ID, which you choose.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,64}$",
              "example": "butik-se"
            }
          },
          {
            "name": "order_id",
            "in": "path",
            "required": true,
            "description": "The order's ID in your shop.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9._~:@-]{1,100}$",
              "example": "50087"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted."
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/stores/{store_id}/carts": {
      "get": {
        "operationId": "carts.list",
        "summary": "List carts",
        "description": "The store's open carts, one page at a time.\n\nRequires: ecommerce:read.",
        "tags": [
          "Carts"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "ecommerce:read"
        ],
        "parameters": [
          {
            "name": "store_id",
            "in": "path",
            "required": true,
            "description": "The store's ID, which you choose.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,64}$",
              "example": "butik-se"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "The maximum number of items in the response (1–250, default 100).",
            "schema": {
              "default": 100,
              "type": "integer",
              "minimum": 1,
              "maximum": 250
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "next_cursor from the previous response, for the next page. Omit for the first page.",
            "schema": {
              "type": "string",
              "maxLength": 400
            }
          },
          {
            "name": "updated_since",
            "in": "query",
            "required": false,
            "description": "Only what has changed since then (ISO 8601).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of carts.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CartPage"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: The details are invalid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/stores/{store_id}/carts/{cart_id}": {
      "get": {
        "operationId": "carts.get",
        "summary": "Get cart",
        "description": "A cart with lines.\n\nRequires: ecommerce:read.",
        "tags": [
          "Carts"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "ecommerce:read"
        ],
        "parameters": [
          {
            "name": "store_id",
            "in": "path",
            "required": true,
            "description": "The store's ID, which you choose.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,64}$",
              "example": "butik-se"
            }
          },
          {
            "name": "cart_id",
            "in": "path",
            "required": true,
            "description": "The cart's ID in your shop.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9._~:@-]{1,100}$",
              "example": "c-8812"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The cart.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Cart"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "put": {
        "operationId": "carts.upsert",
        "summary": "Create or update cart",
        "description": "Creates the cart with the shop's ID, or updates it. The lines replace the previous ones.\n\nA cart always belongs to a customer, who is created or updated with it. Delete the cart once it has become an order.\n\nRequires: ecommerce:write.",
        "tags": [
          "Carts"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "ecommerce:write"
        ],
        "parameters": [
          {
            "name": "store_id",
            "in": "path",
            "required": true,
            "description": "The store's ID, which you choose.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,64}$",
              "example": "butik-se"
            }
          },
          {
            "name": "cart_id",
            "in": "path",
            "required": true,
            "description": "The cart's ID in your shop.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9._~:@-]{1,100}$",
              "example": "c-8812"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "customer": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string",
                        "pattern": "^[A-Za-z0-9._~:@-]{1,100}$",
                        "description": "The customer's ID in your shop.",
                        "example": "1042"
                      },
                      "email": {
                        "type": "string",
                        "maxLength": 254,
                        "description": "The customer's email address.",
                        "example": "anna@example.se"
                      },
                      "first_name": {
                        "description": "First name.",
                        "example": "Anna",
                        "anyOf": [
                          {
                            "type": "string",
                            "maxLength": 100
                          },
                          {
                            "type": "null"
                          }
                        ]
                      },
                      "last_name": {
                        "description": "Last name.",
                        "example": "Svensson",
                        "anyOf": [
                          {
                            "type": "string",
                            "maxLength": 100
                          },
                          {
                            "type": "null"
                          }
                        ]
                      },
                      "company": {
                        "description": "Company.",
                        "anyOf": [
                          {
                            "type": "string",
                            "maxLength": 200
                          },
                          {
                            "type": "null"
                          }
                        ]
                      }
                    },
                    "required": [
                      "id",
                      "email"
                    ],
                    "additionalProperties": false,
                    "description": "The customer. Created or updated with the order (same rules as PUT /customers/{customer_id})."
                  },
                  "campaign_id": {
                    "description": "The campaign the customer came from: the value of qn_cid on the link they clicked. Only counts for the workspace's own campaigns; an unknown ID is not saved (but the order is).",
                    "example": "6d1f0c3a-2b4e-4f6a-8c9d-0e1f2a3b4c5d",
                    "anyOf": [
                      {
                        "type": "string",
                        "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "checkout_url": {
                    "description": "The URL where the customer can complete the purchase.",
                    "example": "https://butik.se/kassa?korg=c-8812",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 2048
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "currency": {
                    "description": "Default: the store's currency.",
                    "type": "string",
                    "pattern": "^[A-Z]{3}$",
                    "example": "SEK"
                  },
                  "order_total": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 999999999999.99,
                    "description": "The cart's total amount.",
                    "example": 498
                  },
                  "tax_total": {
                    "anyOf": [
                      {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 999999999999.99,
                        "description": "Of which VAT.",
                        "example": 499
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "lines": {
                    "maxItems": 500,
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "pattern": "^[A-Za-z0-9._~:@-]{1,100}$",
                          "description": "The line's ID in your shop.",
                          "example": "1"
                        },
                        "product_id": {
                          "type": "string",
                          "pattern": "^[A-Za-z0-9._~:@-]{1,100}$",
                          "description": "The product's ID in your shop.",
                          "example": "731"
                        },
                        "variant_id": {
                          "anyOf": [
                            {
                              "type": "string",
                              "pattern": "^[A-Za-z0-9._~:@-]{1,100}$",
                              "description": "The variant's ID in your shop.",
                              "example": "731-blue-m"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "title": {
                          "description": "What was bought, as it appeared on the order.",
                          "example": "T-shirt i ekologisk bomull, blå, M",
                          "anyOf": [
                            {
                              "type": "string",
                              "maxLength": 255
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "quantity": {
                          "type": "integer",
                          "minimum": 1,
                          "maximum": 1000000,
                          "description": "Quantity.",
                          "example": 2
                        },
                        "price": {
                          "type": "number",
                          "minimum": 0,
                          "maximum": 999999999999.99,
                          "description": "Price per unit.",
                          "example": 249
                        }
                      },
                      "required": [
                        "id",
                        "product_id",
                        "quantity",
                        "price"
                      ],
                      "additionalProperties": false
                    },
                    "description": "The cart's lines. Replaces all lines."
                  }
                },
                "required": [
                  "customer",
                  "order_total",
                  "lines"
                ],
                "additionalProperties": false
              },
              "example": {
                "customer": {
                  "id": "1042",
                  "email": "anna@example.se"
                },
                "checkout_url": "https://butik.se/kassa?korg=c-8812",
                "order_total": 498,
                "lines": [
                  {
                    "id": "1",
                    "product_id": "731",
                    "variant_id": "731-blue-m",
                    "quantity": 2,
                    "price": 249
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The cart (201 if it was created).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Cart"
                }
              }
            }
          },
          "400": {
            "description": "bad_request: The request could not be read",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "unsupported_media_type: Wrong content type",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: The details are invalid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "carts.delete",
        "summary": "Delete cart",
        "description": "Deletes the cart, for example when it has become an order.\n\nRequires: ecommerce:write.",
        "tags": [
          "Carts"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "ecommerce:write"
        ],
        "parameters": [
          {
            "name": "store_id",
            "in": "path",
            "required": true,
            "description": "The store's ID, which you choose.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,64}$",
              "example": "butik-se"
            }
          },
          {
            "name": "cart_id",
            "in": "path",
            "required": true,
            "description": "The cart's ID in your shop.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9._~:@-]{1,100}$",
              "example": "c-8812"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted."
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/revenue": {
      "get": {
        "operationId": "revenue.list",
        "summary": "Revenue per campaign",
        "description": "The workspace's campaigns with the paid orders that came from them, newest campaign first.\n\nAn order counts towards the campaign in its campaign_id (qn_cid from the link the customer clicked). Amounts are summed per currency. since and until apply to the order's time (processed_at).\n\nRequires: ecommerce:read.",
        "tags": [
          "Revenue"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "ecommerce:read"
        ],
        "parameters": [
          {
            "name": "since",
            "in": "query",
            "required": false,
            "description": "Only orders from that time onwards (ISO 8601).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "until",
            "in": "query",
            "required": false,
            "description": "Only orders before that time (ISO 8601).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "campaign_id",
            "in": "query",
            "required": false,
            "description": "Only the campaign.",
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
            }
          },
          {
            "name": "store_id",
            "in": "query",
            "required": false,
            "description": "Only the store's orders.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,64}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The campaigns with revenue (at most 500).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CampaignRevenueList"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: The details are invalid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/batch": {
      "post": {
        "operationId": "batch.run",
        "summary": "Run multiple calls",
        "description": "Up to 500 calls in one, in sequence. Useful for importing history: customers, products and orders.\n\nEach operation is an ordinary call under /api/v1 – method, path and body – and is checked and run exactly as if it had been sent on its own: with the key's scopes and the same errors. The responses come in the same order, with the status and body for each one. An operation that fails does not stop the others.\n\nThe whole batch counts as one call towards the per-minute limit, but at most 20 batches per minute per key. Upsert with PUT makes it safe to rerun an interrupted batch; with Idempotency-Key, a resent batch gets the same response without being run again.\n\nAll valid keys.",
        "tags": [
          "Batch"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "A key of your choice (e.g. a UUID). The same key and the same call within 24 hours gives the same response again, without anything being done twice.",
            "schema": {
              "type": "string",
              "maxLength": 255
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "operations": {
                    "minItems": 1,
                    "maxItems": 500,
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "method": {
                          "type": "string",
                          "enum": [
                            "GET",
                            "POST",
                            "PUT",
                            "PATCH",
                            "DELETE"
                          ],
                          "example": "PUT"
                        },
                        "path": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 2048,
                          "description": "The path under /api/v1, with the query string if the call has one.",
                          "example": "/stores/butik-se/orders/50087"
                        },
                        "body": {
                          "description": "The request body, as a JSON object.",
                          "type": "object",
                          "propertyNames": {
                            "type": "string"
                          },
                          "additionalProperties": {}
                        }
                      },
                      "required": [
                        "method",
                        "path"
                      ],
                      "additionalProperties": false
                    },
                    "description": "The operations (at most 500), which are run in sequence."
                  }
                },
                "required": [
                  "operations"
                ],
                "additionalProperties": false
              },
              "example": {
                "operations": [
                  {
                    "method": "PUT",
                    "path": "/stores/butik-se/products/731",
                    "body": {
                      "title": "T-shirt i ekologisk bomull",
                      "variants": [
                        {
                          "id": "731-blue-m",
                          "title": "Blå, M",
                          "price": 249
                        }
                      ]
                    }
                  },
                  {
                    "method": "PUT",
                    "path": "/stores/butik-se/orders/50087",
                    "body": {
                      "customer": {
                        "id": "1042",
                        "email": "anna@example.se"
                      },
                      "order_total": 548,
                      "processed_at": "2024-11-29T10:12:00Z",
                      "lines": [
                        {
                          "id": "1",
                          "product_id": "731",
                          "quantity": 2,
                          "price": 249
                        }
                      ]
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The responses, in the same order as the operations.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BatchResult"
                }
              }
            }
          },
          "400": {
            "description": "bad_request: The request could not be read",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "idempotency_in_progress: The request is already in progress",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "unsupported_media_type: Wrong content type",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: The details are invalid · idempotency_key_reused: Idempotency-Key already in use",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/webhooks": {
      "get": {
        "operationId": "webhooks.list",
        "summary": "List webhooks",
        "description": "The workspace's webhooks.\n\nRequires: webhooks:read.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "webhooks:read"
        ],
        "responses": {
          "200": {
            "description": "All webhooks.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookList"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "webhooks.create",
        "summary": "Create webhook",
        "description": "A new webhook. The response contains the secret that deliveries are signed with – it is shown only now.\n\nThe URL must be https, on the standard port and reachable from the internet. Each delivery is a POST with JSON and the header Qrona-Signature; respond with 2xx within ten seconds. Read more in the webhooks guide.\n\nRequires: webhooks:write.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "webhooks:write"
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "A key of your choice (e.g. a UUID). The same key and the same call within 24 hours gives the same response again, without anything being done twice.",
            "schema": {
              "type": "string",
              "maxLength": 255
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "maxLength": 2048,
                    "description": "The URL that receives the events (https, standard port, reachable from the internet).",
                    "example": "https://butik.se/wp-json/qrona/v1/webhook"
                  },
                  "events": {
                    "minItems": 1,
                    "maxItems": 4,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "contact.subscribed",
                        "contact.unsubscribed",
                        "contact.bounced",
                        "contact.complained"
                      ]
                    },
                    "description": "The events the webhook should receive: contact.subscribed (sign-up), contact.unsubscribed (unsubscription), contact.bounced (bounce), contact.complained (spam complaint).",
                    "example": [
                      "contact.unsubscribed",
                      "contact.bounced",
                      "contact.complained"
                    ]
                  },
                  "description": {
                    "description": "What the webhook is for.",
                    "example": "Avregistreringar till WooCommerce",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 200
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "include_api": {
                    "description": "Also send changes made via the API. Default: false, so that an integration is not told about its own changes.",
                    "type": "boolean"
                  }
                },
                "required": [
                  "url",
                  "events"
                ],
                "additionalProperties": false
              },
              "example": {
                "url": "https://butik.se/wp-json/qrona/v1/webhook",
                "events": [
                  "contact.unsubscribed",
                  "contact.bounced",
                  "contact.complained"
                ],
                "description": "Avregistreringar till WooCommerce"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The new webhook, with the secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookCreated"
                }
              }
            }
          },
          "400": {
            "description": "bad_request: The request could not be read",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "limit_reached: The limit has been reached · idempotency_in_progress: The request is already in progress",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "unsupported_media_type: Wrong content type",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: The details are invalid · idempotency_key_reused: Idempotency-Key already in use",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/webhooks/{id}": {
      "get": {
        "operationId": "webhooks.get",
        "summary": "Get webhook",
        "description": "A webhook and how its deliveries are going.\n\nRequires: webhooks:read.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "webhooks:read"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The webhook's ID.",
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$",
              "example": "5e2d9b7c-1a3f-4c6e-8d0b-2f4a6c8e0b1d"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The webhook.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Webhook"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "webhooks.update",
        "summary": "Update webhook",
        "description": "URL, events and description, or disable and enable it.\n\nA webhook whose deliveries have failed 100 times in a row is disabled. Turn it back on with active: true when the receiver is working.\n\nRequires: webhooks:write.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "webhooks:write"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The webhook's ID.",
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$",
              "example": "5e2d9b7c-1a3f-4c6e-8d0b-2f4a6c8e0b1d"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "maxLength": 2048,
                    "description": "The URL that receives the events (https, standard port, reachable from the internet).",
                    "example": "https://butik.se/wp-json/qrona/v1/webhook"
                  },
                  "events": {
                    "minItems": 1,
                    "maxItems": 4,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "contact.subscribed",
                        "contact.unsubscribed",
                        "contact.bounced",
                        "contact.complained"
                      ]
                    },
                    "description": "The events the webhook should receive: contact.subscribed (sign-up), contact.unsubscribed (unsubscription), contact.bounced (bounce), contact.complained (spam complaint).",
                    "example": [
                      "contact.unsubscribed",
                      "contact.bounced",
                      "contact.complained"
                    ]
                  },
                  "description": {
                    "description": "What the webhook is for.",
                    "example": "Avregistreringar till WooCommerce",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 200
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "include_api": {
                    "description": "Also send changes made via the API. Default: false, so that an integration is not told about its own changes.",
                    "type": "boolean"
                  },
                  "active": {
                    "description": "false disables the webhook. true enables it again (and resets the count of failed deliveries).",
                    "type": "boolean"
                  }
                },
                "additionalProperties": false
              },
              "example": {
                "events": [
                  "contact.subscribed",
                  "contact.unsubscribed"
                ],
                "active": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The webhook after the change.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Webhook"
                }
              }
            }
          },
          "400": {
            "description": "bad_request: The request could not be read",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "unsupported_media_type: Wrong content type",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: The details are invalid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "webhooks.delete",
        "summary": "Delete webhook",
        "description": "Deletes the webhook. Pending deliveries are not sent.\n\nRequires: webhooks:write.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "webhooks:write"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The webhook's ID.",
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$",
              "example": "5e2d9b7c-1a3f-4c6e-8d0b-2f4a6c8e0b1d"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted."
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/webhooks/{id}/deliveries": {
      "get": {
        "operationId": "webhooks.deliveries",
        "summary": "List deliveries",
        "description": "The webhook's deliveries over the last 30 days, newest first: what was sent, how the receiver responded and when the next attempt will be made.\n\nRequires: webhooks:read.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "webhooks:read"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The webhook's ID.",
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$",
              "example": "5e2d9b7c-1a3f-4c6e-8d0b-2f4a6c8e0b1d"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "The maximum number of items in the response (1–100, default 25).",
            "schema": {
              "default": 25,
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "next_cursor from the previous response, for the next page. Omit for the first page.",
            "schema": {
              "type": "string",
              "maxLength": 400
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Only deliveries with that status.",
            "schema": {
              "type": "string",
              "enum": [
                "pending",
                "delivered",
                "failed"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of deliveries.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookDeliveryPage"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: The details are invalid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/webhooks/{id}/test": {
      "post": {
        "operationId": "webhooks.test",
        "summary": "Test webhook",
        "description": "Sends a ping to the URL immediately and responds with the result. Not retried.\n\nRequires: webhooks:write.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "webhooks:write"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The webhook's ID.",
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$",
              "example": "5e2d9b7c-1a3f-4c6e-8d0b-2f4a6c8e0b1d"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "A key of your choice (e.g. a UUID). The same key and the same call within 24 hours gives the same response again, without anything being done twice.",
            "schema": {
              "type": "string",
              "maxLength": 255
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The result.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookTest"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "idempotency_in_progress: The request is already in progress",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "idempotency_key_reused: Idempotency-Key already in use",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/messages": {
      "post": {
        "operationId": "messages.send",
        "summary": "Send message",
        "description": "One message to one recipient, made from the template's latest published version and the data. Sent at once.\n\nThe data is checked against the template's data contract before anything is sent. The message keeps the template version and the HTML's SHA-256, so what was sent can always be shown again.\n\nidempotency_key is unique per workspace: the same key again answers 200 with the first message and sends nothing new, so a retry never becomes a duplicate. The same key with other content gives 409 idempotency_conflict.\n\nA message that may not go – the address is blocked for its class, or the month's allowance is used up – is kept with the status suppressed and a reason, and the receipt message.suppressed is sent. The answer is still 201.\n\nRequires: messages:send.",
        "tags": [
          "Messages"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "messages:send"
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "A key of your choice (e.g. a UUID). The same key and the same call within 24 hours gives the same response again, without anything being done twice.",
            "schema": {
              "type": "string",
              "maxLength": 255
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "template": {
                    "type": "string",
                    "pattern": "^[a-z0-9][a-z0-9_.-]{1,99}$",
                    "description": "The template's key. The message is made from the template's latest published version.",
                    "example": "byra.momsunderlag"
                  },
                  "to": {
                    "type": "object",
                    "properties": {
                      "email": {
                        "type": "string",
                        "maxLength": 254,
                        "description": "The recipient's address.",
                        "example": "ekonomi@klienten.se"
                      },
                      "name": {
                        "description": "The recipient's name. Fills {{first_name}} and {{last_name}} in the template.",
                        "example": "Eva Ekonom",
                        "anyOf": [
                          {
                            "type": "string",
                            "maxLength": 200
                          },
                          {
                            "type": "null"
                          }
                        ]
                      }
                    },
                    "required": [
                      "email"
                    ],
                    "additionalProperties": false
                  },
                  "category": {
                    "type": "string",
                    "enum": [
                      "service",
                      "marketing"
                    ],
                    "description": "service: reminders and letters within the engagement – stopped by a bounce, a spam complaint, erasure and a manual block, never by an unsubscribe, and has no unsubscribe link. marketing: planning and knowledge letters – follows the workspace's usual rules, unsubscribes and the monthly cap."
                  },
                  "data": {
                    "type": "object",
                    "propertyNames": {
                      "type": "string"
                    },
                    "additionalProperties": {},
                    "description": "The message's data, ready to show (amounts formatted, dates written out). Checked against the template's data contract.",
                    "example": {
                      "klient": {
                        "namn": "Exempel AB"
                      },
                      "period": {
                        "etikett": "september 2026",
                        "intern_deadline": "fredag 2 oktober"
                      },
                      "konsult": {
                        "namn": "Karin Konsult"
                      },
                      "knapp": {
                        "url": "https://byran.q.qrona.se/portal/underlag",
                        "text": "Ladda upp underlaget"
                      },
                      "saknas": [
                        {
                          "typ": "Kvitton",
                          "beskrivning": "Inköp med företagskortet",
                          "belopp": "4 312 kr"
                        }
                      ]
                    }
                  },
                  "idempotency_key": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 255,
                    "pattern": "^[\\x21-\\x7e]+$",
                    "description": "Unique per workspace and message, e.g. the mailing's id in Qrona. The same key again gives the same message, never a new one.",
                    "example": "occ_20261023_0042"
                  },
                  "reference": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 255,
                    "description": "Qrona's reference. Comes back in every receipt (webhook).",
                    "example": "occ_20261023_0042"
                  },
                  "client_ref": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 255,
                    "description": "The firm's client, pseudonymously. The number of different clients per month is the basis of the invoice.",
                    "example": "kl_7f3a"
                  },
                  "reply_to": {
                    "description": "The reply address for this message, e.g. the client's consultant. Without: the add-on's.",
                    "example": "karin@byran.se",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 320
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                },
                "required": [
                  "template",
                  "to",
                  "category",
                  "data",
                  "idempotency_key",
                  "reference",
                  "client_ref"
                ],
                "additionalProperties": false
              },
              "example": {
                "template": "byra.momsunderlag",
                "to": {
                  "email": "ekonomi@klienten.se",
                  "name": "Eva Ekonom"
                },
                "category": "service",
                "data": {
                  "klient": {
                    "namn": "Exempel AB"
                  },
                  "period": {
                    "etikett": "september 2026",
                    "intern_deadline": "fredag 2 oktober"
                  },
                  "konsult": {
                    "namn": "Karin Konsult"
                  },
                  "knapp": {
                    "url": "https://byran.q.qrona.se/portal/underlag",
                    "text": "Ladda upp underlaget"
                  },
                  "saknas": [
                    {
                      "typ": "Kvitton",
                      "beskrivning": "Inköp med företagskortet",
                      "belopp": "4 312 kr"
                    }
                  ]
                },
                "idempotency_key": "occ_20261023_0042",
                "reference": "occ_20261023_0042",
                "client_ref": "kl_7f3a"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The message (200 when idempotency_key has already been used with the same content).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Message"
                }
              }
            }
          },
          "400": {
            "description": "bad_request: The request could not be read",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "template_not_published: The template is not published · idempotency_conflict: idempotency_key is already used · sender_not_configured: Sender missing · sending_not_enabled: Mailings are not approved · idempotency_in_progress: The request is already in progress",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "unsupported_media_type: Wrong content type",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: The details are invalid · idempotency_key_reused: Idempotency-Key already in use",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/messages/{id}": {
      "get": {
        "operationId": "messages.get",
        "summary": "Get message",
        "description": "A message and how it went: sent, delivered, bounced …\n\nRequires: messages:send.",
        "tags": [
          "Messages"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "messages:send"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The message's id.",
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$",
              "example": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Message"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/templates/{key}/render": {
      "post": {
        "operationId": "templates.render",
        "summary": "Render template",
        "description": "The template's latest published version with the data, exactly as it is sent – for the preview in Qrona.\n\nThe data is checked against the template's data contract as when a message is sent. Nothing is sent and nothing is kept.\n\nRequires: templates:render.",
        "tags": [
          "Qrona templates"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "templates:render"
        ],
        "parameters": [
          {
            "name": "key",
            "in": "path",
            "required": true,
            "description": "The template's key, the same as its data contract's.",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9][a-z0-9_.-]{1,99}$",
              "example": "byra.momsunderlag"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "A key of your choice (e.g. a UUID). The same key and the same call within 24 hours gives the same response again, without anything being done twice.",
            "schema": {
              "type": "string",
              "maxLength": 255
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "data": {
                    "type": "object",
                    "propertyNames": {
                      "type": "string"
                    },
                    "additionalProperties": {},
                    "description": "The message's data, ready to show (amounts formatted, dates written out). Checked against the template's data contract.",
                    "example": {
                      "klient": {
                        "namn": "Exempel AB"
                      },
                      "period": {
                        "etikett": "september 2026",
                        "intern_deadline": "fredag 2 oktober"
                      },
                      "konsult": {
                        "namn": "Karin Konsult"
                      },
                      "knapp": {
                        "url": "https://byran.q.qrona.se/portal/underlag",
                        "text": "Ladda upp underlaget"
                      },
                      "saknas": [
                        {
                          "typ": "Kvitton",
                          "beskrivning": "Inköp med företagskortet",
                          "belopp": "4 312 kr"
                        }
                      ]
                    }
                  },
                  "category": {
                    "description": "The class the message is to have (as when it is sent). Without: service.",
                    "type": "string",
                    "enum": [
                      "service",
                      "marketing"
                    ]
                  },
                  "to": {
                    "description": "A recipient to show it for. Without: an example name.",
                    "type": "object",
                    "properties": {
                      "email": {
                        "type": "string",
                        "maxLength": 254,
                        "description": "The recipient's address.",
                        "example": "ekonomi@klienten.se"
                      },
                      "name": {
                        "description": "The recipient's name. Fills {{first_name}} and {{last_name}} in the template.",
                        "example": "Eva Ekonom",
                        "anyOf": [
                          {
                            "type": "string",
                            "maxLength": 200
                          },
                          {
                            "type": "null"
                          }
                        ]
                      }
                    },
                    "required": [
                      "email"
                    ],
                    "additionalProperties": false
                  }
                },
                "required": [
                  "data"
                ],
                "additionalProperties": false
              },
              "example": {
                "data": {
                  "klient": {
                    "namn": "Exempel AB"
                  },
                  "knapp": {
                    "url": "https://byran.q.qrona.se/portal/underlag",
                    "text": "Ladda upp underlaget"
                  }
                },
                "category": "service"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The rendered template.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderedMessage"
                }
              }
            }
          },
          "400": {
            "description": "bad_request: The request could not be read",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API key missing · invalid_key: Unknown API key · key_revoked: The API key has been revoked · key_expired: The API key has expired · key_inactive: The API key is no longer valid",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Subscription required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: The key lacks the required scope · forbidden: Not allowed · workspace_suspended: The workspace is paused",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "template_not_published: The template is not published · idempotency_in_progress: The request is already in progress",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "unsupported_media_type: Wrong content type",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: The details are invalid · idempotency_key_reused: Idempotency-Key already in use",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Something went wrong on our side",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "qn_live_…",
        "description": "API key in Authorization: Bearer. Scopes: contacts:read (read contacts), contacts:write (edit contacts), contacts:erase (erase contacts (gdpr)), lists:read (read lists), lists:write (edit lists), fields:read (read contact fields), segments:read (read distribution lists), ecommerce:read (read e-commerce), ecommerce:write (edit e-commerce), webhooks:read (read webhooks), webhooks:write (edit webhooks), messages:send (send messages), templates:render (preview messages)."
      }
    },
    "schemas": {
      "Problem": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991
          },
          "detail": {
            "type": "string"
          },
          "code": {
            "type": "string",
            "description": "The error code, for programs. See Error codes."
          },
          "request_id": {
            "description": "Same as the X-Request-Id header. Include it if you contact us.",
            "type": "string"
          },
          "errors": {
            "description": "On validation_failed: what is wrong, per field.",
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "field": {
                  "type": "string"
                },
                "message": {
                  "type": "string"
                }
              },
              "required": [
                "field",
                "message"
              ],
              "additionalProperties": false
            }
          }
        },
        "required": [
          "type",
          "title",
          "status",
          "code"
        ],
        "additionalProperties": false,
        "description": "An error (application/problem+json, RFC 9457).",
        "example": {
          "type": "https://newsletter.qrona.se/developer/api/errors#validation_failed",
          "title": "Uppgifterna stämmer inte",
          "status": 422,
          "code": "validation_failed",
          "request_id": "6c0e1f5a-…",
          "errors": [
            {
              "field": "email",
              "message": "Ange en giltig e-postadress."
            }
          ]
        }
      },
      "Root": {
        "type": "object",
        "properties": {
          "api_version": {
            "type": "string"
          },
          "workspace": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              }
            },
            "required": [
              "id",
              "name"
            ],
            "additionalProperties": false
          },
          "key": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "prefix": {
                "type": "string"
              },
              "scopes": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "contacts:read",
                    "contacts:write",
                    "contacts:erase",
                    "lists:read",
                    "lists:write",
                    "fields:read",
                    "segments:read",
                    "ecommerce:read",
                    "ecommerce:write",
                    "webhooks:read",
                    "webhooks:write",
                    "messages:send",
                    "templates:render"
                  ]
                }
              }
            },
            "required": [
              "id",
              "name",
              "prefix",
              "scopes"
            ],
            "additionalProperties": false
          },
          "acting_as": {
            "type": "object",
            "properties": {
              "id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "name": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "role": {
                "type": "string",
                "enum": [
                  "owner",
                  "admin",
                  "editor",
                  "viewer"
                ]
              }
            },
            "required": [
              "id",
              "name",
              "role"
            ],
            "additionalProperties": false,
            "description": "The person the key acts as, and their role in the workspace right now. For Qrona's system key, id is null."
          }
        },
        "required": [
          "api_version",
          "workspace",
          "key",
          "acting_as"
        ],
        "additionalProperties": false,
        "description": "Which key it is and where it applies.",
        "example": {
          "api_version": "1",
          "workspace": {
            "id": "0b8f…",
            "name": "Exempel AB"
          },
          "key": {
            "id": "5d1e…",
            "name": "Webbutiken (WooCommerce)",
            "prefix": "qn_live_AbCd",
            "scopes": [
              "contacts:read",
              "contacts:write",
              "fields:read",
              "lists:read"
            ]
          },
          "acting_as": {
            "id": "7a2c…",
            "name": "Anna Svensson",
            "role": "admin"
          }
        }
      },
      "ContactPage": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Contact"
            }
          },
          "has_more": {
            "type": "boolean",
            "description": "There are more: fetch the next page with cursor=next_cursor.",
            "example": false
          },
          "next_cursor": {
            "description": "Send as cursor for the next page. null on the last page.",
            "example": null,
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "data",
          "has_more",
          "next_cursor"
        ],
        "additionalProperties": false,
        "description": "A page of contacts."
      },
      "Contact": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The contact's ID."
          },
          "email": {
            "type": "string",
            "description": "The email address (lower case). Never changes: consents and suppressions apply to the address."
          },
          "first_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "last_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "company": {
            "type": [
              "string",
              "null"
            ]
          },
          "phone": {
            "description": "In international format (E.164), e.g. +46701234567.",
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "unsubscribed",
              "bounced",
              "complained",
              "deleted"
            ],
            "description": "active: can receive mailings · unsubscribed: has unsubscribed from everything · bounced: the address bounces · complained: has reported spam · deleted: erased (GDPR), the personal data is gone."
          },
          "fields": {
            "type": "object",
            "propertyNames": {
              "type": "string"
            },
            "additionalProperties": {
              "type": [
                "string",
                "number",
                "boolean"
              ]
            },
            "description": "Custom fields by key (see GET /fields). Sensitive fields, such as personal identity numbers, are never sent out."
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "source": {
            "type": "string",
            "description": "How the contact was added: manual, import, form, api …"
          },
          "consent": {
            "type": "object",
            "properties": {
              "at": {
                "anyOf": [
                  {
                    "type": "string",
                    "format": "date-time",
                    "description": "When consent was given.",
                    "example": "2026-10-19T08:30:00.000Z"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "source": {
                "description": "How the person consented, in your own words.",
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "at",
              "source"
            ],
            "additionalProperties": false
          },
          "suppression": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "reason": {
                    "type": "string",
                    "description": "unsubscribed, bounced, complained, manual or imported."
                  },
                  "created_at": {
                    "type": "string",
                    "format": "date-time",
                    "description": "When the address was suppressed.",
                    "example": "2026-10-19T08:30:00.000Z"
                  }
                },
                "required": [
                  "reason",
                  "created_at"
                ],
                "additionalProperties": false
              },
              {
                "type": "null"
              }
            ],
            "description": "The workspace's suppression of the address. A suppressed address never receives mailings, regardless of status."
          },
          "shared": {
            "type": "boolean",
            "description": "Shared from a level above in the organisation: can be read and receive mailings from here, but can only be changed where it belongs."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the contact was created.",
            "example": "2026-10-19T08:30:00.000Z"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the contact was last changed.",
            "example": "2026-10-19T08:30:00.000Z"
          },
          "unsubscribed_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time",
                "description": "When the person unsubscribed.",
                "example": "2026-10-19T08:30:00.000Z"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "id",
          "email",
          "first_name",
          "last_name",
          "company",
          "phone",
          "status",
          "fields",
          "tags",
          "source",
          "consent",
          "suppression",
          "shared",
          "created_at",
          "updated_at",
          "unsubscribed_at"
        ],
        "additionalProperties": false,
        "description": "A contact (recipient) in the workspace.",
        "example": {
          "id": "1042",
          "email": "anna@example.se",
          "first_name": "Anna",
          "last_name": "Svensson",
          "company": "Exempel AB",
          "phone": "+46701234567",
          "status": "active",
          "fields": {
            "kundnummer": "K-2041",
            "ort": "Göteborg"
          },
          "tags": [
            "kund",
            "vip"
          ],
          "source": "api",
          "consent": {
            "at": "2026-10-19T08:30:00.000Z",
            "source": "Kryssade i rutan i kassan på butik.se"
          },
          "suppression": null,
          "shared": false,
          "created_at": "2026-10-19T08:30:00.000Z",
          "updated_at": "2026-10-19T08:30:00.000Z",
          "unsubscribed_at": null
        }
      },
      "ContactDetail": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The contact's ID."
          },
          "email": {
            "type": "string",
            "description": "The email address (lower case). Never changes: consents and suppressions apply to the address."
          },
          "first_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "last_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "company": {
            "type": [
              "string",
              "null"
            ]
          },
          "phone": {
            "description": "In international format (E.164), e.g. +46701234567.",
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "unsubscribed",
              "bounced",
              "complained",
              "deleted"
            ],
            "description": "active: can receive mailings · unsubscribed: has unsubscribed from everything · bounced: the address bounces · complained: has reported spam · deleted: erased (GDPR), the personal data is gone."
          },
          "fields": {
            "type": "object",
            "propertyNames": {
              "type": "string"
            },
            "additionalProperties": {
              "type": [
                "string",
                "number",
                "boolean"
              ]
            },
            "description": "Custom fields by key (see GET /fields). Sensitive fields, such as personal identity numbers, are never sent out."
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "source": {
            "type": "string",
            "description": "How the contact was added: manual, import, form, api …"
          },
          "consent": {
            "type": "object",
            "properties": {
              "at": {
                "anyOf": [
                  {
                    "type": "string",
                    "format": "date-time",
                    "description": "When consent was given.",
                    "example": "2026-10-19T08:30:00.000Z"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "source": {
                "description": "How the person consented, in your own words.",
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "at",
              "source"
            ],
            "additionalProperties": false
          },
          "suppression": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "reason": {
                    "type": "string",
                    "description": "unsubscribed, bounced, complained, manual or imported."
                  },
                  "created_at": {
                    "type": "string",
                    "format": "date-time",
                    "description": "When the address was suppressed.",
                    "example": "2026-10-19T08:30:00.000Z"
                  }
                },
                "required": [
                  "reason",
                  "created_at"
                ],
                "additionalProperties": false
              },
              {
                "type": "null"
              }
            ],
            "description": "The workspace's suppression of the address. A suppressed address never receives mailings, regardless of status."
          },
          "shared": {
            "type": "boolean",
            "description": "Shared from a level above in the organisation: can be read and receive mailings from here, but can only be changed where it belongs."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the contact was created.",
            "example": "2026-10-19T08:30:00.000Z"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the contact was last changed.",
            "example": "2026-10-19T08:30:00.000Z"
          },
          "unsubscribed_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time",
                "description": "When the person unsubscribed.",
                "example": "2026-10-19T08:30:00.000Z"
              },
              {
                "type": "null"
              }
            ]
          },
          "lists": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "list_id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "subscribed",
                    "pending",
                    "unsubscribed"
                  ],
                  "description": "subscribed: on the list · pending: waiting to confirm by email · unsubscribed: has left the list."
                },
                "subscribed_at": {
                  "anyOf": [
                    {
                      "type": "string",
                      "format": "date-time",
                      "description": "When the person joined the list.",
                      "example": "2026-10-19T08:30:00.000Z"
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              },
              "required": [
                "list_id",
                "name",
                "status",
                "subscribed_at"
              ],
              "additionalProperties": false
            },
            "description": "The workspace's lists that the contact is on. Empty for a shared contact."
          }
        },
        "required": [
          "id",
          "email",
          "first_name",
          "last_name",
          "company",
          "phone",
          "status",
          "fields",
          "tags",
          "source",
          "consent",
          "suppression",
          "shared",
          "created_at",
          "updated_at",
          "unsubscribed_at",
          "lists"
        ],
        "additionalProperties": false,
        "description": "A contact with its lists.",
        "example": {
          "id": "1042",
          "email": "anna@example.se",
          "first_name": "Anna",
          "last_name": "Svensson",
          "company": "Exempel AB",
          "phone": "+46701234567",
          "status": "active",
          "fields": {
            "kundnummer": "K-2041",
            "ort": "Göteborg"
          },
          "tags": [
            "kund",
            "vip"
          ],
          "source": "api",
          "consent": {
            "at": "2026-10-19T08:30:00.000Z",
            "source": "Kryssade i rutan i kassan på butik.se"
          },
          "suppression": null,
          "shared": false,
          "created_at": "2026-10-19T08:30:00.000Z",
          "updated_at": "2026-10-19T08:30:00.000Z",
          "unsubscribed_at": null,
          "lists": [
            {
              "list_id": "3f1c2a4e-8b7d-4c1e-9f0a-2d6b5e7c8a91",
              "name": "Nyhetsbrev",
              "status": "subscribed",
              "subscribed_at": "2026-10-19T08:30:00.000Z"
            }
          ]
        }
      },
      "ContactList": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Contact"
            }
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "description": "Contacts."
      },
      "ListList": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/List"
            }
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "description": "Lists."
      },
      "List": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "double_opt_in": {
            "type": "boolean",
            "description": "New sign-ups must confirm by email before they are added."
          },
          "form_enabled": {
            "type": "boolean",
            "description": "The list's public sign-up form is open."
          },
          "counts": {
            "type": "object",
            "properties": {
              "subscribed": {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991,
                "description": "Receive mailings: on the list, active and not suppressed."
              },
              "pending": {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991,
                "description": "Has signed up but not confirmed yet."
              },
              "unsubscribed": {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991
              },
              "blocked": {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991,
                "description": "On the list but not reachable: they bounce, have made a spam complaint or are suppressed."
              }
            },
            "required": [
              "subscribed",
              "pending",
              "unsubscribed",
              "blocked"
            ],
            "additionalProperties": false,
            "description": "Only the contacts that the person behind the key may see."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the list was created.",
            "example": "2026-10-19T08:30:00.000Z"
          }
        },
        "required": [
          "id",
          "name",
          "description",
          "double_opt_in",
          "form_enabled",
          "counts",
          "created_at"
        ],
        "additionalProperties": false,
        "description": "A list: an audience with its own sign-up mode.",
        "example": {
          "id": "3f1c2a4e-8b7d-4c1e-9f0a-2d6b5e7c8a91",
          "name": "Nyhetsbrev",
          "description": "Månadsbrevet till kunder",
          "double_opt_in": true,
          "form_enabled": true,
          "counts": {
            "subscribed": 1840,
            "pending": 12,
            "unsubscribed": 96,
            "blocked": 7
          },
          "created_at": "2026-09-01T10:00:00.000Z"
        }
      },
      "MemberPage": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Member"
            }
          },
          "has_more": {
            "type": "boolean",
            "description": "There are more: fetch the next page with cursor=next_cursor.",
            "example": false
          },
          "next_cursor": {
            "description": "Send as cursor for the next page. null on the last page.",
            "example": null,
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "data",
          "has_more",
          "next_cursor"
        ],
        "additionalProperties": false,
        "description": "A page of members."
      },
      "Member": {
        "type": "object",
        "properties": {
          "contact_id": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "first_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "last_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "subscribed",
              "pending",
              "unsubscribed"
            ]
          },
          "contact_status": {
            "type": "string",
            "enum": [
              "active",
              "unsubscribed",
              "bounced",
              "complained",
              "deleted"
            ]
          },
          "sendable": {
            "type": "boolean",
            "description": "Currently receives mailings to the list (on the list, active and not suppressed)."
          },
          "subscribed_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time",
                "description": "When the person joined.",
                "example": "2026-10-19T08:30:00.000Z"
              },
              {
                "type": "null"
              }
            ]
          },
          "unsubscribed_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time",
                "description": "When the person left the list.",
                "example": "2026-10-19T08:30:00.000Z"
              },
              {
                "type": "null"
              }
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the membership was created.",
            "example": "2026-10-19T08:30:00.000Z"
          }
        },
        "required": [
          "contact_id",
          "email",
          "first_name",
          "last_name",
          "status",
          "contact_status",
          "sendable",
          "subscribed_at",
          "unsubscribed_at",
          "created_at"
        ],
        "additionalProperties": false,
        "description": "A contact's membership of a list.",
        "example": {
          "contact_id": "1042",
          "email": "anna@example.se",
          "first_name": "Anna",
          "last_name": "Svensson",
          "status": "subscribed",
          "contact_status": "active",
          "sendable": true,
          "subscribed_at": "2026-10-19T08:30:00.000Z",
          "unsubscribed_at": null,
          "created_at": "2026-10-19T08:30:00.000Z"
        }
      },
      "Subscription": {
        "type": "object",
        "properties": {
          "list_id": {
            "type": "string"
          },
          "contact_id": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "subscribed",
              "pending"
            ],
            "description": "pending: a confirmation email has been sent (or was just sent) and the person joins when they confirm."
          },
          "confirmation_sent": {
            "type": "boolean",
            "description": "A confirmation email was sent just now."
          },
          "created_contact": {
            "type": "boolean",
            "description": "The contact did not exist and was created."
          }
        },
        "required": [
          "list_id",
          "contact_id",
          "status",
          "confirmation_sent",
          "created_contact"
        ],
        "additionalProperties": false,
        "description": "The result of a sign-up to a list.",
        "example": {
          "list_id": "3f1c2a4e-8b7d-4c1e-9f0a-2d6b5e7c8a91",
          "contact_id": "1042",
          "status": "pending",
          "confirmation_sent": true,
          "created_contact": true
        }
      },
      "FieldList": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Field"
            }
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "description": "Contact fields."
      },
      "Field": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string",
            "description": "The key in fields on a contact, and in merge fields such as {{attr.kundnummer}}."
          },
          "label": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "text",
              "number",
              "date",
              "boolean",
              "select",
              "email",
              "phone",
              "url",
              "personnummer"
            ]
          },
          "options": {
            "anyOf": [
              {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              {
                "type": "null"
              }
            ],
            "description": "The options for a field of type select."
          },
          "required": {
            "type": "boolean",
            "description": "Must be provided when a contact is created."
          },
          "sensitive": {
            "type": "boolean",
            "description": "Sensitive field (personal identity number): can be neither read nor written via the API."
          },
          "inherited": {
            "type": "boolean",
            "description": "The field comes from a level above in the organisation."
          }
        },
        "required": [
          "key",
          "label",
          "type",
          "options",
          "required",
          "sensitive",
          "inherited"
        ],
        "additionalProperties": false,
        "description": "A custom contact field.",
        "example": {
          "key": "kundnummer",
          "label": "Kundnummer",
          "type": "text",
          "options": null,
          "required": false,
          "sensitive": false,
          "inherited": false
        }
      },
      "SegmentList": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Segment"
            }
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "description": "Distribution lists."
      },
      "Segment": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "matching": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991,
            "description": "Contacts that match the conditions right now (not deleted)."
          },
          "active": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991,
            "description": "Of those: active."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the list was created.",
            "example": "2026-10-19T08:30:00.000Z"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the conditions were last changed.",
            "example": "2026-10-19T08:30:00.000Z"
          }
        },
        "required": [
          "id",
          "name",
          "description",
          "matching",
          "active",
          "created_at",
          "updated_at"
        ],
        "additionalProperties": false,
        "description": "A distribution list: contacts that meet conditions.",
        "example": {
          "id": "9b2e4c1a-7d3f-4e8a-b6c5-1f0e2d3c4b5a",
          "name": "Kunder i Göteborg",
          "description": null,
          "matching": 412,
          "active": 398,
          "created_at": "2026-09-12T09:00:00.000Z",
          "updated_at": "2026-10-02T14:20:00.000Z"
        }
      },
      "SuppressionPage": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Suppression"
            }
          },
          "has_more": {
            "type": "boolean",
            "description": "There are more: fetch the next page with cursor=next_cursor.",
            "example": false
          },
          "next_cursor": {
            "description": "Send as cursor for the next page. null on the last page.",
            "example": null,
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "data",
          "has_more",
          "next_cursor"
        ],
        "additionalProperties": false,
        "description": "A page of suppressed addresses."
      },
      "Suppression": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string"
          },
          "reason": {
            "type": "string",
            "description": "unsubscribed, bounced, complained, manual or imported."
          },
          "detail": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the address was suppressed.",
            "example": "2026-10-19T08:30:00.000Z"
          },
          "contact_id": {
            "description": "The contact with the address, if there is one that the key may see.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "email",
          "reason",
          "detail",
          "created_at",
          "contact_id"
        ],
        "additionalProperties": false,
        "description": "An address the workspace never sends to.",
        "example": {
          "email": "nej-tack@example.se",
          "reason": "unsubscribed",
          "detail": "Avregistrerad via länk",
          "created_at": "2026-10-01T07:00:00.000Z",
          "contact_id": "877"
        }
      },
      "StoreList": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Store"
            }
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "description": "Stores."
      },
      "Store": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The store's ID."
          },
          "name": {
            "type": "string"
          },
          "domain": {
            "type": [
              "string",
              "null"
            ]
          },
          "currency": {
            "type": "string"
          },
          "counts": {
            "type": "object",
            "properties": {
              "customers": {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991
              },
              "products": {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991
              },
              "orders": {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991
              },
              "carts": {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991
              }
            },
            "required": [
              "customers",
              "products",
              "orders",
              "carts"
            ],
            "additionalProperties": false,
            "description": "How much the store has sent in."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the store was created.",
            "example": "2026-10-19T08:30:00.000Z"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the store was last changed.",
            "example": "2026-10-19T08:30:00.000Z"
          }
        },
        "required": [
          "id",
          "name",
          "domain",
          "currency",
          "counts",
          "created_at",
          "updated_at"
        ],
        "additionalProperties": false,
        "description": "A web shop in the workspace.",
        "example": {
          "id": "butik-se",
          "name": "Exempelbutiken",
          "domain": "butik.se",
          "currency": "SEK",
          "counts": {
            "customers": 1840,
            "products": 312,
            "orders": 5120,
            "carts": 14
          },
          "created_at": "2026-10-19T08:30:00.000Z",
          "updated_at": "2026-10-19T08:30:00.000Z"
        }
      },
      "CustomerPage": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Customer"
            }
          },
          "has_more": {
            "type": "boolean",
            "description": "There are more: fetch the next page with cursor=next_cursor.",
            "example": false
          },
          "next_cursor": {
            "description": "Send as cursor for the next page. null on the last page.",
            "example": null,
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "data",
          "has_more",
          "next_cursor"
        ],
        "additionalProperties": false,
        "description": "A page of customers."
      },
      "Customer": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "first_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "last_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "company": {
            "type": [
              "string",
              "null"
            ]
          },
          "contact_id": {
            "description": "The workspace's contact with the same address, if there is one. A customer never becomes a contact on its own.",
            "type": [
              "string",
              "null"
            ]
          },
          "orders_count": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991,
            "description": "Paid orders."
          },
          "total_spent": {
            "type": "number",
            "description": "The total of the paid orders."
          },
          "last_order_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time",
                "description": "The most recent paid order.",
                "example": "2026-10-19T08:30:00.000Z"
              },
              {
                "type": "null"
              }
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the customer was first sent in.",
            "example": "2026-10-19T08:30:00.000Z"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the customer was last changed.",
            "example": "2026-10-19T08:30:00.000Z"
          }
        },
        "required": [
          "id",
          "email",
          "first_name",
          "last_name",
          "company",
          "contact_id",
          "orders_count",
          "total_spent",
          "last_order_at",
          "created_at",
          "updated_at"
        ],
        "additionalProperties": false,
        "description": "A customer in the store – someone who has made a purchase, with or without consent to mailings.",
        "example": {
          "id": "1042",
          "email": "anna@example.se",
          "first_name": "Anna",
          "last_name": "Svensson",
          "company": null,
          "contact_id": "877",
          "orders_count": 3,
          "total_spent": 1847,
          "last_order_at": "2026-10-12T14:03:00.000Z",
          "created_at": "2026-03-02T09:00:00.000Z",
          "updated_at": "2026-10-12T14:03:00.000Z"
        }
      },
      "ProductPage": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Product"
            }
          },
          "has_more": {
            "type": "boolean",
            "description": "There are more: fetch the next page with cursor=next_cursor.",
            "example": false
          },
          "next_cursor": {
            "description": "Send as cursor for the next page. null on the last page.",
            "example": null,
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "data",
          "has_more",
          "next_cursor"
        ],
        "additionalProperties": false,
        "description": "A page of products."
      },
      "Product": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "url": {
            "type": [
              "string",
              "null"
            ]
          },
          "image_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "vendor": {
            "type": [
              "string",
              "null"
            ]
          },
          "product_type": {
            "type": [
              "string",
              "null"
            ]
          },
          "variants": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                },
                "sku": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "price": {
                  "type": [
                    "number",
                    "null"
                  ]
                },
                "inventory_quantity": {
                  "anyOf": [
                    {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "url": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "image_url": {
                  "type": [
                    "string",
                    "null"
                  ]
                }
              },
              "required": [
                "id",
                "title",
                "sku",
                "price",
                "inventory_quantity",
                "url",
                "image_url"
              ],
              "additionalProperties": false
            }
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the product was first sent in.",
            "example": "2026-10-19T08:30:00.000Z"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the product was last changed.",
            "example": "2026-10-19T08:30:00.000Z"
          }
        },
        "required": [
          "id",
          "title",
          "url",
          "image_url",
          "vendor",
          "product_type",
          "variants",
          "created_at",
          "updated_at"
        ],
        "additionalProperties": false,
        "description": "A product in the store, with variants.",
        "example": {
          "id": "731",
          "title": "T-shirt i ekologisk bomull",
          "url": "https://butik.se/produkt/t-shirt",
          "image_url": "https://butik.se/bilder/t-shirt.jpg",
          "vendor": null,
          "product_type": "Kläder",
          "variants": [
            {
              "id": "731-blue-m",
              "title": "Blå, M",
              "sku": "TS-BLU-M",
              "price": 249,
              "inventory_quantity": 12,
              "url": null,
              "image_url": null
            }
          ],
          "created_at": "2026-10-19T08:30:00.000Z",
          "updated_at": "2026-10-19T08:30:00.000Z"
        }
      },
      "OrderPage": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Order"
            }
          },
          "has_more": {
            "type": "boolean",
            "description": "There are more: fetch the next page with cursor=next_cursor.",
            "example": false
          },
          "next_cursor": {
            "description": "Send as cursor for the next page. null on the last page.",
            "example": null,
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "data",
          "has_more",
          "next_cursor"
        ],
        "additionalProperties": false,
        "description": "A page of orders."
      },
      "Order": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "customer": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string"
                  },
                  "email": {
                    "type": "string"
                  }
                },
                "required": [
                  "id",
                  "email"
                ],
                "additionalProperties": false
              },
              {
                "type": "null"
              }
            ],
            "description": "null when the customer has been erased: the order still counts towards the campaign's revenue."
          },
          "campaign_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "financial_status": {
            "type": "string",
            "enum": [
              "pending",
              "paid",
              "refunded",
              "cancelled"
            ]
          },
          "currency": {
            "type": "string"
          },
          "order_total": {
            "type": "number"
          },
          "tax_total": {
            "type": [
              "number",
              "null"
            ]
          },
          "shipping_total": {
            "type": [
              "number",
              "null"
            ]
          },
          "discount_total": {
            "type": [
              "number",
              "null"
            ]
          },
          "processed_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the order was placed.",
            "example": "2026-10-19T08:30:00.000Z"
          },
          "lines": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "product_id": {
                  "type": "string"
                },
                "variant_id": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "title": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "quantity": {
                  "type": "integer",
                  "minimum": -9007199254740991,
                  "maximum": 9007199254740991
                },
                "price": {
                  "type": "number"
                },
                "discount": {
                  "type": [
                    "number",
                    "null"
                  ]
                }
              },
              "required": [
                "id",
                "product_id",
                "variant_id",
                "title",
                "quantity",
                "price",
                "discount"
              ],
              "additionalProperties": false
            }
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the order was first sent in.",
            "example": "2026-10-19T08:30:00.000Z"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the order was last changed.",
            "example": "2026-10-19T08:30:00.000Z"
          }
        },
        "required": [
          "id",
          "customer",
          "campaign_id",
          "financial_status",
          "currency",
          "order_total",
          "tax_total",
          "shipping_total",
          "discount_total",
          "processed_at",
          "lines",
          "created_at",
          "updated_at"
        ],
        "additionalProperties": false,
        "description": "An order in the store.",
        "example": {
          "id": "50087",
          "customer": {
            "id": "1042",
            "email": "anna@example.se"
          },
          "campaign_id": "6d1f0c3a-2b4e-4f6a-8c9d-0e1f2a3b4c5d",
          "financial_status": "paid",
          "currency": "SEK",
          "order_total": 548,
          "tax_total": 109.6,
          "shipping_total": 49,
          "discount_total": 0,
          "processed_at": "2026-10-12T14:03:00.000Z",
          "lines": [
            {
              "id": "1",
              "product_id": "731",
              "variant_id": "731-blue-m",
              "title": "T-shirt i ekologisk bomull, blå, M",
              "quantity": 2,
              "price": 249,
              "discount": null
            }
          ],
          "created_at": "2026-10-12T14:03:05.000Z",
          "updated_at": "2026-10-12T14:03:05.000Z"
        }
      },
      "CartPage": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Cart"
            }
          },
          "has_more": {
            "type": "boolean",
            "description": "There are more: fetch the next page with cursor=next_cursor.",
            "example": false
          },
          "next_cursor": {
            "description": "Send as cursor for the next page. null on the last page.",
            "example": null,
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "data",
          "has_more",
          "next_cursor"
        ],
        "additionalProperties": false,
        "description": "A page of carts."
      },
      "Cart": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "customer": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "email": {
                "type": "string"
              }
            },
            "required": [
              "id",
              "email"
            ],
            "additionalProperties": false
          },
          "campaign_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "checkout_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "currency": {
            "type": "string"
          },
          "order_total": {
            "type": "number"
          },
          "tax_total": {
            "type": [
              "number",
              "null"
            ]
          },
          "lines": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "product_id": {
                  "type": "string"
                },
                "variant_id": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "title": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "quantity": {
                  "type": "integer",
                  "minimum": -9007199254740991,
                  "maximum": 9007199254740991
                },
                "price": {
                  "type": "number"
                }
              },
              "required": [
                "id",
                "product_id",
                "variant_id",
                "title",
                "quantity",
                "price"
              ],
              "additionalProperties": false
            }
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the cart was first sent in.",
            "example": "2026-10-19T08:30:00.000Z"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the cart was last changed.",
            "example": "2026-10-19T08:30:00.000Z"
          }
        },
        "required": [
          "id",
          "customer",
          "campaign_id",
          "checkout_url",
          "currency",
          "order_total",
          "tax_total",
          "lines",
          "created_at",
          "updated_at"
        ],
        "additionalProperties": false,
        "description": "An open cart.",
        "example": {
          "id": "c-8812",
          "customer": {
            "id": "1042",
            "email": "anna@example.se"
          },
          "campaign_id": null,
          "checkout_url": "https://butik.se/kassa?korg=c-8812",
          "currency": "SEK",
          "order_total": 498,
          "tax_total": 99.6,
          "lines": [
            {
              "id": "1",
              "product_id": "731",
              "variant_id": "731-blue-m",
              "title": "T-shirt i ekologisk bomull, blå, M",
              "quantity": 2,
              "price": 249
            }
          ],
          "created_at": "2026-10-19T08:30:00.000Z",
          "updated_at": "2026-10-19T08:30:00.000Z"
        }
      },
      "CampaignRevenueList": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CampaignRevenue"
            }
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "description": "Campaigns with revenue."
      },
      "CampaignRevenue": {
        "type": "object",
        "properties": {
          "campaign_id": {
            "type": "string"
          },
          "campaign_name": {
            "type": "string"
          },
          "started_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time",
                "description": "When the campaign started sending.",
                "example": "2026-10-19T08:30:00.000Z"
              },
              {
                "type": "null"
              }
            ]
          },
          "orders": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991,
            "description": "Paid orders from the campaign."
          },
          "revenue": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "currency": {
                  "type": "string"
                },
                "amount": {
                  "type": "number"
                },
                "orders": {
                  "type": "integer",
                  "minimum": -9007199254740991,
                  "maximum": 9007199254740991
                }
              },
              "required": [
                "currency",
                "amount",
                "orders"
              ],
              "additionalProperties": false
            },
            "description": "Revenue per currency."
          }
        },
        "required": [
          "campaign_id",
          "campaign_name",
          "started_at",
          "orders",
          "revenue"
        ],
        "additionalProperties": false,
        "description": "A campaign's revenue: the paid orders that came from its links.",
        "example": {
          "campaign_id": "6d1f0c3a-2b4e-4f6a-8c9d-0e1f2a3b4c5d",
          "campaign_name": "Höstrean",
          "started_at": "2026-10-10T07:00:00.000Z",
          "orders": 41,
          "revenue": [
            {
              "currency": "SEK",
              "amount": 28640,
              "orders": 41
            }
          ]
        }
      },
      "BatchResult": {
        "type": "object",
        "properties": {
          "results": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "status": {
                  "type": "integer",
                  "minimum": -9007199254740991,
                  "maximum": 9007199254740991,
                  "description": "The operation's HTTP status."
                },
                "body": {
                  "description": "The operation's response: the usual response, an error (problem+json) or null (204)."
                }
              },
              "required": [
                "status",
                "body"
              ],
              "additionalProperties": false
            }
          },
          "succeeded": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991
          },
          "failed": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991
          }
        },
        "required": [
          "results",
          "succeeded",
          "failed"
        ],
        "additionalProperties": false,
        "description": "The responses in the same order as the operations.",
        "example": {
          "results": [
            {
              "status": 201,
              "body": {
                "id": "50087",
                "financial_status": "paid",
                "order_total": 548
              }
            },
            {
              "status": 422,
              "body": {
                "type": "https://newsletter.qrona.se/developer/api/errors#validation_failed",
                "status": 422,
                "code": "validation_failed",
                "errors": [
                  {
                    "field": "lines",
                    "message": "En order har minst en rad."
                  }
                ]
              }
            }
          ],
          "succeeded": 1,
          "failed": 1
        }
      },
      "WebhookList": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Webhook"
            }
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "description": "Webhooks."
      },
      "Webhook": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "url": {
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "contact.subscribed",
                "contact.unsubscribed",
                "contact.bounced",
                "contact.complained"
              ]
            }
          },
          "include_api": {
            "type": "boolean"
          },
          "active": {
            "type": "boolean"
          },
          "disabled_reason": {
            "description": "Why the webhook disabled itself (the deliveries failed), or null.",
            "type": [
              "string",
              "null"
            ]
          },
          "consecutive_failures": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991,
            "description": "Failed delivery attempts in a row."
          },
          "last_success_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time",
                "description": "The last successful delivery.",
                "example": "2026-10-19T08:30:00.000Z"
              },
              {
                "type": "null"
              }
            ]
          },
          "last_failure_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time",
                "description": "The most recent failed attempt.",
                "example": "2026-10-19T08:30:00.000Z"
              },
              {
                "type": "null"
              }
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the webhook was created.",
            "example": "2026-10-19T08:30:00.000Z"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the webhook was last changed.",
            "example": "2026-10-19T08:30:00.000Z"
          }
        },
        "required": [
          "id",
          "url",
          "description",
          "events",
          "include_api",
          "active",
          "disabled_reason",
          "consecutive_failures",
          "last_success_at",
          "last_failure_at",
          "created_at",
          "updated_at"
        ],
        "additionalProperties": false,
        "description": "A webhook: a URL that receives the workspace's events.",
        "example": {
          "id": "5e2d9b7c-1a3f-4c6e-8d0b-2f4a6c8e0b1d",
          "url": "https://butik.se/wp-json/qrona/v1/webhook",
          "description": "Avregistreringar till WooCommerce",
          "events": [
            "contact.bounced",
            "contact.complained",
            "contact.unsubscribed"
          ],
          "include_api": false,
          "active": true,
          "disabled_reason": null,
          "consecutive_failures": 0,
          "last_success_at": "2026-10-19T08:31:00.000Z",
          "last_failure_at": null,
          "created_at": "2026-10-19T08:30:00.000Z",
          "updated_at": "2026-10-19T08:30:00.000Z"
        }
      },
      "WebhookCreated": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "url": {
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "contact.subscribed",
                "contact.unsubscribed",
                "contact.bounced",
                "contact.complained"
              ]
            }
          },
          "include_api": {
            "type": "boolean"
          },
          "active": {
            "type": "boolean"
          },
          "disabled_reason": {
            "description": "Why the webhook disabled itself (the deliveries failed), or null.",
            "type": [
              "string",
              "null"
            ]
          },
          "consecutive_failures": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991,
            "description": "Failed delivery attempts in a row."
          },
          "last_success_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time",
                "description": "The last successful delivery.",
                "example": "2026-10-19T08:30:00.000Z"
              },
              {
                "type": "null"
              }
            ]
          },
          "last_failure_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time",
                "description": "The most recent failed attempt.",
                "example": "2026-10-19T08:30:00.000Z"
              },
              {
                "type": "null"
              }
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the webhook was created.",
            "example": "2026-10-19T08:30:00.000Z"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the webhook was last changed.",
            "example": "2026-10-19T08:30:00.000Z"
          },
          "secret": {
            "type": "string",
            "description": "The secret that the deliveries are signed with (Qrona-Signature). Only shown now – store it with the receiver."
          }
        },
        "required": [
          "id",
          "url",
          "description",
          "events",
          "include_api",
          "active",
          "disabled_reason",
          "consecutive_failures",
          "last_success_at",
          "last_failure_at",
          "created_at",
          "updated_at",
          "secret"
        ],
        "additionalProperties": false,
        "description": "The new webhook, with the secret.",
        "example": {
          "id": "5e2d9b7c-1a3f-4c6e-8d0b-2f4a6c8e0b1d",
          "url": "https://butik.se/wp-json/qrona/v1/webhook",
          "description": "Avregistreringar till WooCommerce",
          "events": [
            "contact.bounced",
            "contact.complained",
            "contact.unsubscribed"
          ],
          "include_api": false,
          "active": true,
          "disabled_reason": null,
          "consecutive_failures": 0,
          "last_success_at": "2026-10-19T08:31:00.000Z",
          "last_failure_at": null,
          "created_at": "2026-10-19T08:30:00.000Z",
          "updated_at": "2026-10-19T08:30:00.000Z",
          "secret": "whsec_…"
        }
      },
      "WebhookDeliveryPage": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WebhookDelivery"
            }
          },
          "has_more": {
            "type": "boolean",
            "description": "There are more: fetch the next page with cursor=next_cursor.",
            "example": false
          },
          "next_cursor": {
            "description": "Send as cursor for the next page. null on the last page.",
            "example": null,
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "data",
          "has_more",
          "next_cursor"
        ],
        "additionalProperties": false,
        "description": "A page of deliveries."
      },
      "WebhookDelivery": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The delivery's ID (the Qrona-Delivery header)."
          },
          "event_id": {
            "type": "string",
            "description": "The event's ID (ID in the body): the same in all webhooks that receive the event."
          },
          "type": {
            "type": "string",
            "description": "The event, or ping for a test."
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "delivered",
              "failed"
            ],
            "description": "pending: waiting for a (new) attempt · delivered: the receiver responded 2xx · failed: given up."
          },
          "attempts": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991
          },
          "response_status": {
            "anyOf": [
              {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ],
            "description": "The receiver's HTTP status on the latest attempt."
          },
          "error": {
            "type": [
              "string",
              "null"
            ]
          },
          "next_attempt_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time",
                "description": "Next attempt.",
                "example": "2026-10-19T08:30:00.000Z"
              },
              {
                "type": "null"
              }
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the event happened.",
            "example": "2026-10-19T08:30:00.000Z"
          },
          "delivered_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time",
                "description": "When it was delivered.",
                "example": "2026-10-19T08:30:00.000Z"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "id",
          "event_id",
          "type",
          "status",
          "attempts",
          "response_status",
          "error",
          "next_attempt_at",
          "created_at",
          "delivered_at"
        ],
        "additionalProperties": false,
        "description": "An event sent to a webhook.",
        "example": {
          "id": "9a8b7c6d-5e4f-4a3b-2c1d-0e9f8a7b6c5d",
          "event_id": "7f3c1a2e-5b4d-4e6f-8a9b-0c1d2e3f4a5b",
          "type": "contact.unsubscribed",
          "status": "delivered",
          "attempts": 1,
          "response_status": 200,
          "error": null,
          "next_attempt_at": null,
          "created_at": "2026-10-19T08:30:00.000Z",
          "delivered_at": "2026-10-19T08:30:04.000Z"
        }
      },
      "WebhookTest": {
        "type": "object",
        "properties": {
          "delivery_id": {
            "type": "string"
          },
          "ok": {
            "type": "boolean",
            "description": "The receiver responded 2xx."
          },
          "response_status": {
            "anyOf": [
              {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "error": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "delivery_id",
          "ok",
          "response_status",
          "error"
        ],
        "additionalProperties": false,
        "description": "The result of a test.",
        "example": {
          "delivery_id": "1b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e",
          "ok": true,
          "response_status": 200,
          "error": null
        }
      },
      "Message": {
        "type": "object",
        "properties": {
          "message_id": {
            "type": "string",
            "description": "The message's id."
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "sending",
              "sent",
              "delivered",
              "bounced",
              "complained",
              "failed",
              "suppressed"
            ],
            "description": "queued: waiting for another attempt · sent: handed to the sending service · delivered: delivered · bounced: bounced · complained: spam complaint · failed: could not be delivered · suppressed: not sent, see reason."
          },
          "reason": {
            "description": "Why a message was not sent: bounced, complained, manual, erased, unsubscribed (marketing only), service_limit, monthly_cap or payment.",
            "type": [
              "string",
              "null"
            ]
          },
          "template": {
            "type": "string"
          },
          "template_version": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991,
            "description": "The template version the message was made from. Published versions never change."
          },
          "html_sha256": {
            "type": "string",
            "description": "SHA-256 of the HTML the recipient got."
          },
          "category": {
            "type": "string",
            "enum": [
              "service",
              "marketing"
            ]
          },
          "reference": {
            "type": "string"
          },
          "client_ref": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the message was received.",
            "example": "2026-10-23T08:30:00.000Z"
          }
        },
        "required": [
          "message_id",
          "status",
          "reason",
          "template",
          "template_version",
          "html_sha256",
          "category",
          "reference",
          "client_ref",
          "created_at"
        ],
        "additionalProperties": false,
        "description": "A message to one recipient.",
        "example": {
          "message_id": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
          "status": "sent",
          "reason": null,
          "template": "byra.momsunderlag",
          "template_version": 3,
          "html_sha256": "f3b1c2d4e5a6978812345678909abcdef0123456789abcdef0123456789abcde",
          "category": "service",
          "reference": "occ_20261023_0042",
          "client_ref": "kl_7f3a",
          "created_at": "2026-10-23T08:30:00.000Z"
        }
      },
      "RenderedMessage": {
        "type": "object",
        "properties": {
          "template": {
            "type": "string"
          },
          "template_version": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991,
            "description": "The version that was rendered: the latest published one, which a message would be made from now."
          },
          "subject": {
            "type": "string",
            "description": "The subject line, filled in."
          },
          "html": {
            "type": "string",
            "description": "The message as HTML, exactly as it is sent (the links to the web version and to unsubscribe lead nowhere in a preview)."
          },
          "text": {
            "type": "string",
            "description": "The plain-text version."
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "What should be looked at, e.g. a link without an address."
          }
        },
        "required": [
          "template",
          "template_version",
          "subject",
          "html",
          "text",
          "warnings"
        ],
        "additionalProperties": false,
        "description": "A Qrona template rendered with data.",
        "example": {
          "template": "byra.momsunderlag",
          "template_version": 3,
          "subject": "Underlag till momsen för september 2026",
          "html": "<!doctype html><html>…</html>",
          "text": "Hej Eva! …",
          "warnings": []
        }
      }
    }
  }
}