{
  "openapi": "3.1.0",
  "info": {
    "title": "Qrona Newsletter API",
    "version": "1",
    "description": "Kontakter, listor, kontaktfält, distributionslistor, spärrlistan, e-handel och webhooks i Qrona Newsletter. Nycklar skapas under Inställningar → API-nycklar. Dokumentation: https://newsletter.qrona.se/developer",
    "contact": {
      "name": "Qrona",
      "email": "support@qrona.se",
      "url": "https://newsletter.qrona.se/developer"
    }
  },
  "servers": [
    {
      "url": "https://newsletter.qrona.se"
    }
  ],
  "tags": [
    {
      "name": "Nyckeln",
      "description": "Kontrollera att nyckeln fungerar, vilken arbetsyta den gäller och vad den får göra."
    },
    {
      "name": "Kontakter",
      "description": "Kontakterna är arbetsytans mottagare. En kontakt identifieras av sin e-postadress, som aldrig ändras. Skapa bara kontakter som har samtyckt till utskick (eller där ni har en annan rättslig grund): en aktiv kontakt kan nås av utskick till distributionslistor även om den inte är med på någon lista."
    },
    {
      "name": "Listor",
      "description": "Listor är publiker med eget anmälningsläge: med dubbel opt-in måste nya anmälningar bekräfta via e-post."
    },
    {
      "name": "Listmedlemmar",
      "description": "Vilka som är med på en lista, och anmälningar till den. Anmälningar via API:t följer samma regler som formulären: den som har avregistrerat sig eller spärrats kommer aldrig med utan att själv bekräfta."
    },
    {
      "name": "Kontaktfält",
      "description": "Arbetsytans egna fält – de nycklar som kan användas i fields på en kontakt."
    },
    {
      "name": "Distributionslistor",
      "description": "Distributionslistor är kontakter som uppfyller villkor (segment). Kräver att personen bakom nyckeln är administratör."
    },
    {
      "name": "Spärrlista",
      "description": "Adresser som arbetsytan aldrig skickar till: avregistrerade, studsande, skräppostanmälningar och spärrar som lagts in för hand."
    },
    {
      "name": "Butiker",
      "description": "En webbutik i arbetsytan. Allt i e-handeln hör till en butik och namnges med butikens egna id:n, som ni väljer. PUT skapar eller uppdaterar, så att samma anrop kan göras om utan att något dubbleras."
    },
    {
      "name": "Kunder",
      "description": "De som har handlat i butiken – med eller utan samtycke till utskick. En kund blir aldrig en kontakt: den kopplas till arbetsytans kontakt med samma adress så länge en sådan finns, för köpvillkor i distributionslistor."
    },
    {
      "name": "Produkter",
      "description": "Butikens produkter med varianter, för villkor som ”har köpt produkt X”."
    },
    {
      "name": "Ordrar",
      "description": "Butikens ordrar med rader. Betalda ordrar räknas som köp i villkor och som intäkt för kampanjen kunden kom från (campaign_id)."
    },
    {
      "name": "Kundkorgar",
      "description": "Öppna kundkorgar. Ta bort korgen när den har blivit en order."
    },
    {
      "name": "Intäkt",
      "description": "Intäkten per kampanj: de betalda ordrar som kom från kampanjens länkar."
    },
    {
      "name": "Batch",
      "description": "Upp till 500 anrop i ett, till exempel för att läsa in gamla ordrar. Varje operation kontrolleras och körs som om den skickats för sig."
    },
    {
      "name": "Meddelanden",
      "description": "Ett meddelande i taget till en mottagare, gjort av en Qrona-mall och meddelandets egen data. Bara för tillägget Byråstöd: Klientkommunikation, med Qronas systemnyckel – en persons nyckel kan inte skicka meddelanden."
    },
    {
      "name": "Qrona-mallar",
      "description": "Mallarna meddelandena görs av, designade i Qrona Newsletter mot ett datakontrakt. Förhandsgranska en mall med data, precis som den skickas."
    },
    {
      "name": "Webhooks",
      "description": "Adresser som får höra om anmälningar, avregistreringar, studsar och skräppostanmälningar i arbetsytan, signerade med HMAC. Kräver att personen bakom nyckeln är administratör."
    }
  ],
  "paths": {
    "/api/v1": {
      "get": {
        "operationId": "root.get",
        "summary": "Hämta nyckelns uppgifter",
        "description": "Vilken arbetsyta nyckeln gäller, vem den agerar som och vad den får göra. Bra för att testa kopplingen.\n\nAlla giltiga nycklar.",
        "tags": [
          "Nyckeln"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [],
        "responses": {
          "200": {
            "description": "Nyckelns uppgifter.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Root"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/contacts": {
      "get": {
        "operationId": "contacts.list",
        "summary": "Lista kontakter",
        "description": "Kontakterna som nyckeln får se, i id-ordning, en sida i taget.\n\nSvaret innehåller arbetsytans egna kontakter och de som delas med den från en nivå ovanför (shared: true), begränsat av de kontaktvillkor personen bakom nyckeln har.\n\nHämta nästa sida med cursor=next_cursor tills has_more är false. För löpande synk: spara tiden innan du börjar och hämta sedan med updated_since.\n\nKräver: contacts:read.",
        "tags": [
          "Kontakter"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "contacts:read"
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Hur många som högst ska komma i svaret (1–500, standard 100).",
            "schema": {
              "default": 100,
              "type": "integer",
              "minimum": 1,
              "maximum": 500
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "next_cursor från förra svaret, för nästa sida. Utelämna för första sidan.",
            "schema": {
              "type": "string",
              "maxLength": 400
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Bara kontakter med den statusen. Utan: alla utom raderade.",
            "schema": {
              "type": "string",
              "enum": [
                "active",
                "unsubscribed",
                "bounced",
                "complained",
                "deleted"
              ]
            }
          },
          {
            "name": "list_id",
            "in": "query",
            "required": false,
            "description": "Bara kontakter som är med på listan (oavsett medlemskapets 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": "Bara kontakter i distributionslistan.",
            "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": "Bara kontakter med taggen (exakt stavning).",
            "schema": {
              "type": "string",
              "maxLength": 50
            }
          },
          {
            "name": "updated_since",
            "in": "query",
            "required": false,
            "description": "Bara kontakter som ändrats sedan dess (ISO 8601). Bra för synk: spara tiden för förra hämtningen.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "origin",
            "in": "query",
            "required": false,
            "description": "own: bara arbetsytans egna · shared: bara delade från en nivå ovanför.",
            "schema": {
              "type": "string",
              "enum": [
                "own",
                "shared"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "En sida kontakter.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactPage"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: Uppgifterna stämmer inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "contacts.create",
        "summary": "Skapa kontakt",
        "description": "En ny kontakt i arbetsytan. Finns adressen redan blir svaret 409 contact_exists.\n\nconsent_source är beviset för samtycket och krävs. Kontaktfält som är obligatoriska i arbetsytan måste finnas med i fields.\n\nVill du skapa eller uppdatera i samma anrop: använd POST /contacts/upsert.\n\nKräver: contacts:write.",
        "tags": [
          "Kontakter"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "contacts:write"
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Valfri nyckel (t.ex. ett uuid). Samma nyckel och samma anrop inom 24 timmar ger samma svar igen, utan att något görs två gånger.",
            "schema": {
              "type": "string",
              "maxLength": 255
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "email": {
                    "type": "string",
                    "maxLength": 254,
                    "description": "E-postadressen.",
                    "example": "anna@example.se"
                  },
                  "first_name": {
                    "description": "Förnamn.",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 100
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "last_name": {
                    "description": "Efternamn.",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 100
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "company": {
                    "description": "Företag.",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 200
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "phone": {
                    "description": "Telefonnummer. Utan landsnummer tolkas det enligt arbetsytans land.",
                    "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": "Egna fält efter nyckel (GET /fields). Värdena kontrolleras mot fältets typ. null eller \"\" tar bort ett värde. Nycklar som inte är fält i arbetsytan sparas som fria fält. Känsliga fält (personnummer) kan inte sättas via API:t.",
                    "example": {
                      "kundnummer": "K-2041",
                      "ort": "Göteborg"
                    }
                  },
                  "tags": {
                    "maxItems": 50,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "maxLength": 50
                    },
                    "description": "Taggar.",
                    "example": [
                      "kund"
                    ]
                  },
                  "consent_source": {
                    "type": "string",
                    "minLength": 3,
                    "maxLength": 255,
                    "description": "Hur personen samtyckte till utskick, med egna ord. Sparas som bevis.",
                    "example": "Kryssade i rutan i kassan på butik.se"
                  },
                  "list_ids": {
                    "description": "Listor att lägga kontakten på direkt (som när en person lägger till en kontakt i appen).",
                    "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": "Den nya kontakten.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactDetail"
                }
              }
            }
          },
          "400": {
            "description": "bad_request: Förfrågan kunde inte läsas",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "contact_exists: Kontakten finns redan · suppressed: Adressen är spärrad · idempotency_in_progress: Anropet pågår redan",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "unsupported_media_type: Fel innehållstyp",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: Uppgifterna stämmer inte · idempotency_key_reused: Idempotency-Key används redan",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/contacts/upsert": {
      "post": {
        "operationId": "contacts.upsert",
        "summary": "Skapa eller uppdatera kontakt",
        "description": "Skapar kontakten om adressen är ny, annars uppdateras den. Det vanliga anropet för en integration.\n\nSvarar 201 när kontakten skapades och 200 när den uppdaterades. Bara de fält du skickar ändras. add_tags/remove_tags ändrar taggar utan att röra de andra.\n\nconsent_source krävs när kontakten skapas. Adressen skickas i kroppen, aldrig i adressraden, så att den inte hamnar i loggar.\n\nListmedlemskap ändras inte här: anmäl till en lista med POST /lists/{id}/members.\n\nKräver: contacts:write.",
        "tags": [
          "Kontakter"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "contacts:write"
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Valfri nyckel (t.ex. ett uuid). Samma nyckel och samma anrop inom 24 timmar ger samma svar igen, utan att något görs två gånger.",
            "schema": {
              "type": "string",
              "maxLength": 255
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "email": {
                    "type": "string",
                    "maxLength": 254,
                    "description": "E-postadressen.",
                    "example": "anna@example.se"
                  },
                  "first_name": {
                    "description": "Förnamn.",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 100
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "last_name": {
                    "description": "Efternamn.",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 100
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "company": {
                    "description": "Företag.",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 200
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "phone": {
                    "description": "Telefonnummer. Utan landsnummer tolkas det enligt arbetsytans land.",
                    "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": "Egna fält efter nyckel (GET /fields). Värdena kontrolleras mot fältets typ. null eller \"\" tar bort ett värde. Nycklar som inte är fält i arbetsytan sparas som fria fält. Känsliga fält (personnummer) kan inte sättas via API:t.",
                    "example": {
                      "kundnummer": "K-2041",
                      "ort": "Göteborg"
                    }
                  },
                  "tags": {
                    "maxItems": 50,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "maxLength": 50
                    },
                    "description": "Ersätter alla taggar. Använd inte tillsammans med add_tags/remove_tags.",
                    "example": [
                      "kund"
                    ]
                  },
                  "add_tags": {
                    "maxItems": 50,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "maxLength": 50
                    },
                    "description": "Taggar att lägga till; de andra behålls.",
                    "example": [
                      "kund"
                    ]
                  },
                  "remove_tags": {
                    "maxItems": 50,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "maxLength": 50
                    },
                    "description": "Taggar att ta bort.",
                    "example": [
                      "kund"
                    ]
                  },
                  "consent_source": {
                    "description": "Hur personen samtyckte. Krävs när kontakten skapas; ändrar inget på en befintlig kontakt.",
                    "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": "Kontakten (201 om den skapades).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactDetail"
                }
              }
            }
          },
          "400": {
            "description": "bad_request: Förfrågan kunde inte läsas",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "shared_contact: Kontakten är delad · forbidden: Inte tillåtet · insufficient_scope: Nyckeln saknar behörighet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "contact_erased: Kontakten är raderad · suppressed: Adressen är spärrad · idempotency_in_progress: Anropet pågår redan",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "unsupported_media_type: Fel innehållstyp",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: Uppgifterna stämmer inte · idempotency_key_reused: Idempotency-Key används redan",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/contacts/lookup": {
      "post": {
        "operationId": "contacts.lookup",
        "summary": "Slå upp kontakter på e-post",
        "description": "Upp till 100 adresser i ett anrop. Svaret har de kontakter som finns (alla statusar, även raderade).\n\nAdresserna skickas i kroppen så att de inte hamnar i loggar. En adress kan ge två träffar: en egen kontakt och en delad från en nivå ovanför.\n\nKräver: contacts:read.",
        "tags": [
          "Kontakter"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "contacts:read"
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Valfri nyckel (t.ex. ett uuid). Samma nyckel och samma anrop inom 24 timmar ger samma svar igen, utan att något görs två gånger.",
            "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": "Upp till 100 adresser.",
                    "example": [
                      "anna@example.se",
                      "bo@example.se"
                    ]
                  }
                },
                "required": [
                  "emails"
                ],
                "additionalProperties": false
              },
              "example": {
                "emails": [
                  "anna@example.se",
                  "bo@example.se"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Kontakterna som finns.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactList"
                }
              }
            }
          },
          "400": {
            "description": "bad_request: Förfrågan kunde inte läsas",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "idempotency_in_progress: Anropet pågår redan",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "unsupported_media_type: Fel innehållstyp",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: Uppgifterna stämmer inte · idempotency_key_reused: Idempotency-Key används redan",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/contacts/{id}": {
      "get": {
        "operationId": "contacts.get",
        "summary": "Hämta kontakt",
        "description": "En kontakt med de listor den är med på.\n\nKräver: contacts:read.",
        "tags": [
          "Kontakter"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "contacts:read"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Kontaktens id.",
            "schema": {
              "type": "string",
              "pattern": "^\\d{1,20}$",
              "example": "1042"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Kontakten.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactDetail"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Finns inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "contacts.update",
        "summary": "Ändra kontakt",
        "description": "Ändrar de fält du skickar. E-postadressen kan inte ändras.\n\nBara arbetsytans egna kontakter kan ändras: en delad kontakt ger 403 shared_contact.\n\nKräver: contacts:write.",
        "tags": [
          "Kontakter"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "contacts:write"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Kontaktens id.",
            "schema": {
              "type": "string",
              "pattern": "^\\d{1,20}$",
              "example": "1042"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "first_name": {
                    "description": "Förnamn.",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 100
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "last_name": {
                    "description": "Efternamn.",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 100
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "company": {
                    "description": "Företag.",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 200
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "phone": {
                    "description": "Telefonnummer. Utan landsnummer tolkas det enligt arbetsytans land.",
                    "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": "Egna fält efter nyckel (GET /fields). Värdena kontrolleras mot fältets typ. null eller \"\" tar bort ett värde. Nycklar som inte är fält i arbetsytan sparas som fria fält. Känsliga fält (personnummer) kan inte sättas via API:t.",
                    "example": {
                      "kundnummer": "K-2041",
                      "ort": "Göteborg"
                    }
                  },
                  "tags": {
                    "maxItems": 50,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "maxLength": 50
                    },
                    "description": "Ersätter alla taggar. Använd inte tillsammans med add_tags/remove_tags.",
                    "example": [
                      "kund"
                    ]
                  },
                  "add_tags": {
                    "maxItems": 50,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "maxLength": 50
                    },
                    "description": "Taggar att lägga till; de andra behålls.",
                    "example": [
                      "kund"
                    ]
                  },
                  "remove_tags": {
                    "maxItems": 50,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "maxLength": 50
                    },
                    "description": "Taggar att ta bort.",
                    "example": [
                      "kund"
                    ]
                  }
                },
                "additionalProperties": false
              },
              "example": {
                "last_name": "Berg",
                "fields": {
                  "ort": "Malmö"
                },
                "remove_tags": [
                  "vip"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Kontakten efter ändringen.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactDetail"
                }
              }
            }
          },
          "400": {
            "description": "bad_request: Förfrågan kunde inte läsas",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "shared_contact: Kontakten är delad · insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Finns inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "unsupported_media_type: Fel innehållstyp",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: Uppgifterna stämmer inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/contacts/{id}/unsubscribe": {
      "post": {
        "operationId": "contacts.unsubscribe",
        "summary": "Avregistrera kontakt",
        "description": "Personen vill inte ha fler utskick: kontakten lämnar alla listor, får status unsubscribed och adressen spärras.\n\nSom när personen själv avregistrerar sig. Bara personen kan anmäla sig igen, genom att bekräfta via e-post. Gör inget om kontakten redan är avregistrerad.\n\nKräver: contacts:write.",
        "tags": [
          "Kontakter"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "contacts:write"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Kontaktens id.",
            "schema": {
              "type": "string",
              "pattern": "^\\d{1,20}$",
              "example": "1042"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Valfri nyckel (t.ex. ett uuid). Samma nyckel och samma anrop inom 24 timmar ger samma svar igen, utan att något görs två gånger.",
            "schema": {
              "type": "string",
              "maxLength": 255
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Kontakten efter avregistreringen.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactDetail"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "shared_contact: Kontakten är delad · insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Finns inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "idempotency_in_progress: Anropet pågår redan",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "idempotency_key_reused: Idempotency-Key används redan",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/contacts/{id}/erase": {
      "post": {
        "operationId": "contacts.erase",
        "summary": "Radera kontakt (GDPR)",
        "description": "Raderar kontaktens personuppgifter för gott. Adressen spärras så att den aldrig får utskick igen.\n\nNamn, telefon, egna fält, taggar och svar på undersökningar tas bort, och kontakten lämnar alla listor. Kvar blir adressen i spärrlistan och en rad i samtyckesloggen om raderingen. Kan inte ångras.\n\nKräver behörigheten contacts:erase.\n\nKräver: contacts:erase.",
        "tags": [
          "Kontakter"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "contacts:erase"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Kontaktens id.",
            "schema": {
              "type": "string",
              "pattern": "^\\d{1,20}$",
              "example": "1042"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Valfri nyckel (t.ex. ett uuid). Samma nyckel och samma anrop inom 24 timmar ger samma svar igen, utan att något görs två gånger.",
            "schema": {
              "type": "string",
              "maxLength": 255
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Raderad."
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "shared_contact: Kontakten är delad · insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Finns inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "idempotency_in_progress: Anropet pågår redan",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "idempotency_key_reused: Idempotency-Key används redan",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/lists": {
      "get": {
        "operationId": "lists.list",
        "summary": "Lista listor",
        "description": "Arbetsytans listor med antal medlemmar.\n\nKräver: lists:read.",
        "tags": [
          "Listor"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "lists:read"
        ],
        "responses": {
          "200": {
            "description": "Alla listor.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListList"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "lists.create",
        "summary": "Skapa lista",
        "description": "En ny lista. Dubbel opt-in är på om du inte säger annat.\n\nKräver: lists:write.",
        "tags": [
          "Listor"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "lists:write"
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Valfri nyckel (t.ex. ett uuid). Samma nyckel och samma anrop inom 24 timmar ger samma svar igen, utan att något görs två gånger.",
            "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": "Nya anmälningar måste bekräfta via e-post. Standard: true.",
                    "type": "boolean"
                  }
                },
                "required": [
                  "name"
                ],
                "additionalProperties": false
              },
              "example": {
                "name": "Kunder från webbutiken",
                "double_opt_in": true
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Den nya listan.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/List"
                }
              }
            }
          },
          "400": {
            "description": "bad_request: Förfrågan kunde inte läsas",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "idempotency_in_progress: Anropet pågår redan",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "unsupported_media_type: Fel innehållstyp",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: Uppgifterna stämmer inte · idempotency_key_reused: Idempotency-Key används redan",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/lists/{id}": {
      "get": {
        "operationId": "lists.get",
        "summary": "Hämta lista",
        "description": "En lista med antal medlemmar.\n\nKräver: lists:read.",
        "tags": [
          "Listor"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "lists:read"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Listans 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": "Listan.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/List"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Finns inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "lists.update",
        "summary": "Ändra lista",
        "description": "Namn, beskrivning och anmälningsläge.\n\nKräver: lists:write.",
        "tags": [
          "Listor"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "lists:write"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Listans 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": "Nya anmälningar måste bekräfta via e-post. Standard: true.",
                    "type": "boolean"
                  }
                },
                "additionalProperties": false
              },
              "example": {
                "name": "Nyhetsbrev – kunder"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Listan efter ändringen.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/List"
                }
              }
            }
          },
          "400": {
            "description": "bad_request: Förfrågan kunde inte läsas",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Finns inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "unsupported_media_type: Fel innehållstyp",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: Uppgifterna stämmer inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "lists.delete",
        "summary": "Ta bort lista",
        "description": "Tar bort listan. Kontakterna finns kvar. Går inte medan en kampanj som ska skickas använder listan.\n\nKräver: lists:write.",
        "tags": [
          "Listor"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "lists:write"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Listans 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": "Borttagen."
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Finns inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "list_in_use: Listan används",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/lists/{id}/members": {
      "get": {
        "operationId": "members.list",
        "summary": "Lista medlemmar",
        "description": "Listans medlemmar, en sida i taget.\n\nKräver: lists:read, contacts:read.",
        "tags": [
          "Listmedlemmar"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "lists:read",
          "contacts:read"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Listans 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": "Hur många som högst ska komma i svaret (1–500, standard 100).",
            "schema": {
              "default": 100,
              "type": "integer",
              "minimum": 1,
              "maximum": 500
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "next_cursor från förra svaret, för nästa sida. Utelämna för första sidan.",
            "schema": {
              "type": "string",
              "maxLength": 400
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "subscribed: får utskick · pending: väntar på bekräftelse · unsubscribed: har lämnat · blocked: med men nås inte.",
            "schema": {
              "type": "string",
              "enum": [
                "subscribed",
                "pending",
                "unsubscribed",
                "blocked"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "En sida medlemmar.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MemberPage"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Finns inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: Uppgifterna stämmer inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "members.create",
        "summary": "Anmäl till lista",
        "description": "Anmäler en adress till listan, med beviset för samtycket. Kontakten skapas om den inte finns.\n\nMed status pending (standard på listor med dubbel opt-in) får personen ett bekräftelsemejl och kommer med när hen bekräftar. Med subscribed kommer personen med direkt – då intygar ni att samtycket finns.\n\nDen som tidigare har avregistrerat sig får alltid ett bekräftelsemejl, vad ni än skickar: ingen integration kan anmäla någon igen mot hens vilja. Adresser som studsar, har anmält skräppost, är raderade eller spärrade ger 409 blocked.\n\nSvarar 201 när något ändrades och 200 när personen redan var med (eller nyss fick ett bekräftelsemejl – ett nytt skickas tidigast efter tio minuter).\n\nKräver: contacts:write.",
        "tags": [
          "Listmedlemmar"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "contacts:write"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Listans 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": "Valfri nyckel (t.ex. ett uuid). Samma nyckel och samma anrop inom 24 timmar ger samma svar igen, utan att något görs två gånger.",
            "schema": {
              "type": "string",
              "maxLength": 255
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "email": {
                    "type": "string",
                    "maxLength": 254,
                    "description": "E-postadressen.",
                    "example": "anna@example.se"
                  },
                  "first_name": {
                    "description": "Förnamn. Fyller bara i det som saknas på en befintlig kontakt.",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 100
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "last_name": {
                    "description": "Efternamn.",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 100
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "company": {
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 200
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "status": {
                    "description": "subscribed: med direkt. pending: ett bekräftelsemejl skickas och personen kommer med när hen bekräftar. Standard: listans eget läge. Den som tidigare har avregistrerat sig får alltid ett bekräftelsemejl.",
                    "type": "string",
                    "enum": [
                      "subscribed",
                      "pending"
                    ]
                  },
                  "consent": {
                    "type": "object",
                    "properties": {
                      "text": {
                        "type": "string",
                        "minLength": 10,
                        "maxLength": 5000,
                        "description": "Exakt den text personen godkände.",
                        "example": "Ja, jag vill få nyhetsbrev från Exempel AB."
                      },
                      "source": {
                        "description": "Var det hände.",
                        "example": "Kassan på butik.se",
                        "type": "string",
                        "maxLength": 200
                      },
                      "ip": {
                        "description": "Personens IP-adress (inte er servers).",
                        "type": "string",
                        "maxLength": 45
                      },
                      "user_agent": {
                        "description": "Personens webbläsare.",
                        "type": "string",
                        "maxLength": 255
                      }
                    },
                    "required": [
                      "text"
                    ],
                    "additionalProperties": false,
                    "description": "Beviset för samtycket. Sparas i samtyckesloggen."
                  }
                },
                "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": "Resultatet (200 om inget ändrades).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Subscription"
                }
              }
            }
          },
          "400": {
            "description": "bad_request: Förfrågan kunde inte läsas",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Finns inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "blocked: Adressen tar inte emot utskick · sending_not_enabled: Utskick är inte godkända · idempotency_in_progress: Anropet pågår redan",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "unsupported_media_type: Fel innehållstyp",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: Uppgifterna stämmer inte · idempotency_key_reused: Idempotency-Key används redan",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/lists/{id}/members/{contact_id}": {
      "delete": {
        "operationId": "members.delete",
        "summary": "Ta bort från lista",
        "description": "Tar bort kontakten från listan (en administrativ ändring, inte en avregistrering).\n\nVill personen själv inte ha fler utskick: använd POST /contacts/{id}/unsubscribe.\n\nKräver: contacts:write.",
        "tags": [
          "Listmedlemmar"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "contacts:write"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Listans 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": "Kontaktens id.",
            "schema": {
              "type": "string",
              "pattern": "^\\d{1,20}$",
              "example": "1042"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Borttagen (även om kontakten inte var med)."
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "shared_contact: Kontakten är delad · insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Finns inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/fields": {
      "get": {
        "operationId": "fields.list",
        "summary": "Lista kontaktfält",
        "description": "Arbetsytans egna fält, även de som kommer från en nivå ovanför.\n\nKräver: fields:read.",
        "tags": [
          "Kontaktfält"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "fields:read"
        ],
        "responses": {
          "200": {
            "description": "Alla fält i bruk.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FieldList"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/segments": {
      "get": {
        "operationId": "segments.list",
        "summary": "Lista distributionslistor",
        "description": "Arbetsytans distributionslistor med antal. Kontakterna i en hämtas med GET /contacts?segment_id=.\n\nKräver: segments:read.",
        "tags": [
          "Distributionslistor"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "segments:read"
        ],
        "responses": {
          "200": {
            "description": "Alla distributionslistor.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SegmentList"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/segments/{id}": {
      "get": {
        "operationId": "segments.get",
        "summary": "Hämta distributionslista",
        "description": "En distributionslista med antal.\n\nKräver: segments:read.",
        "tags": [
          "Distributionslistor"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "segments:read"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Distributionslistans 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": "Distributionslistan.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Segment"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Finns inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/suppressions": {
      "get": {
        "operationId": "suppressions.list",
        "summary": "Lista spärrade adresser",
        "description": "Arbetsytans spärrlista, en sida i taget. Bra för att hålla en webbutik i takt med avregistreringar.\n\nKräver: contacts:read.",
        "tags": [
          "Spärrlista"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "contacts:read"
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Hur många som högst ska komma i svaret (1–500, standard 100).",
            "schema": {
              "default": 100,
              "type": "integer",
              "minimum": 1,
              "maximum": 500
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "next_cursor från förra svaret, för nästa sida. Utelämna för första sidan.",
            "schema": {
              "type": "string",
              "maxLength": 400
            }
          },
          {
            "name": "reason",
            "in": "query",
            "required": false,
            "description": "Bara spärrar av det slaget.",
            "schema": {
              "type": "string",
              "enum": [
                "unsubscribed",
                "bounced",
                "complained",
                "manual",
                "imported"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "En sida spärrade adresser.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuppressionPage"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: Uppgifterna stämmer inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/stores": {
      "get": {
        "operationId": "stores.list",
        "summary": "Lista butiker",
        "description": "Arbetsytans butiker med hur mycket var och en har skickat in.\n\nKräver: ecommerce:read.",
        "tags": [
          "Butiker"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "ecommerce:read"
        ],
        "responses": {
          "200": {
            "description": "Alla butiker.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StoreList"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/stores/{store_id}": {
      "get": {
        "operationId": "stores.get",
        "summary": "Hämta butik",
        "description": "En butik.\n\nKräver: ecommerce:read.",
        "tags": [
          "Butiker"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "ecommerce:read"
        ],
        "parameters": [
          {
            "name": "store_id",
            "in": "path",
            "required": true,
            "description": "Butikens id, som ni väljer.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,64}$",
              "example": "butik-se"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Butiken.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Store"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Finns inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "put": {
        "operationId": "stores.upsert",
        "summary": "Skapa eller uppdatera butik",
        "description": "Skapar butiken med ert id, eller uppdaterar den. Det första anropet för en webbutik.\n\nSvarar 201 när butiken skapades och 200 när den uppdaterades. Butikens id väljer ni själva (t.ex. butik-se) och det ändras aldrig: allt annat i e-handeln ligger under /stores/{store_id}.\n\nMed domain får länkar till butiken i arbetsytans utskick parametern qn_cid=<kampanjens id>. Spara den i butiken när kunden kommer och skicka den som campaign_id på ordern, så räknas ordern som kampanjens intäkt.\n\nKräver: ecommerce:write.",
        "tags": [
          "Butiker"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "ecommerce:write"
        ],
        "parameters": [
          {
            "name": "store_id",
            "in": "path",
            "required": true,
            "description": "Butikens id, som ni väljer.",
            "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": "Butikens namn, som det visas i appen.",
                    "example": "Exempelbutiken"
                  },
                  "domain": {
                    "description": "Butikens domän, t.ex. butik.se. Länkar dit (och till underdomäner) i arbetsytans utskick får qn_cid=<kampanjens id>, som butiken skickar tillbaka som campaign_id på ordern.",
                    "example": "butik.se",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 253
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "currency": {
                    "type": "string",
                    "pattern": "^[A-Z]{3}$",
                    "description": "Butikens valuta (ISO 4217). Ordrar och korgar utan egen valuta får den.",
                    "example": "SEK"
                  }
                },
                "required": [
                  "name",
                  "currency"
                ],
                "additionalProperties": false
              },
              "example": {
                "name": "Exempelbutiken",
                "domain": "butik.se",
                "currency": "SEK"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Butiken (201 om den skapades).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Store"
                }
              }
            }
          },
          "400": {
            "description": "bad_request: Förfrågan kunde inte läsas",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "limit_reached: Taket är nått",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "unsupported_media_type: Fel innehållstyp",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: Uppgifterna stämmer inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "stores.delete",
        "summary": "Ta bort butik",
        "description": "Tar bort butiken och allt i den: kunder, produkter, ordrar och kundkorgar. Kan inte ångras.\n\nKampanjernas intäkt från butiken försvinner också. Kontakterna i arbetsytan rörs inte.\n\nKräver: ecommerce:write.",
        "tags": [
          "Butiker"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "ecommerce:write"
        ],
        "parameters": [
          {
            "name": "store_id",
            "in": "path",
            "required": true,
            "description": "Butikens id, som ni väljer.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,64}$",
              "example": "butik-se"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Borttagen."
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Finns inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/stores/{store_id}/customers": {
      "get": {
        "operationId": "customers.list",
        "summary": "Lista kunder",
        "description": "Butikens kunder, en sida i taget.\n\nKräver: ecommerce:read.",
        "tags": [
          "Kunder"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "ecommerce:read"
        ],
        "parameters": [
          {
            "name": "store_id",
            "in": "path",
            "required": true,
            "description": "Butikens id, som ni väljer.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,64}$",
              "example": "butik-se"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Hur många som högst ska komma i svaret (1–500, standard 100).",
            "schema": {
              "default": 100,
              "type": "integer",
              "minimum": 1,
              "maximum": 500
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "next_cursor från förra svaret, för nästa sida. Utelämna för första sidan.",
            "schema": {
              "type": "string",
              "maxLength": 400
            }
          },
          {
            "name": "updated_since",
            "in": "query",
            "required": false,
            "description": "Bara det som ändrats sedan dess (ISO 8601).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "En sida kunder.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerPage"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Finns inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: Uppgifterna stämmer inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/stores/{store_id}/customers/{customer_id}": {
      "get": {
        "operationId": "customers.get",
        "summary": "Hämta kund",
        "description": "En kund med antal betalda ordrar och summan av dem.\n\nKräver: ecommerce:read.",
        "tags": [
          "Kunder"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "ecommerce:read"
        ],
        "parameters": [
          {
            "name": "store_id",
            "in": "path",
            "required": true,
            "description": "Butikens id, som ni väljer.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,64}$",
              "example": "butik-se"
            }
          },
          {
            "name": "customer_id",
            "in": "path",
            "required": true,
            "description": "Kundens id i er butik.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9._~:@-]{1,100}$",
              "example": "1042"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Kunden.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Customer"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Finns inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "put": {
        "operationId": "customers.upsert",
        "summary": "Skapa eller uppdatera kund",
        "description": "Skapar kunden med butikens id, eller uppdaterar den. Ordrar och korgar gör det här själva med sin kund.\n\nEn kund blir aldrig en kontakt och får aldrig utskick för att hen har handlat. Har kunden samtyckt till nyhetsbrev: anmäl hen till en lista med POST /lists/{id}/members, med beviset för samtycket.\n\nFält du utelämnar behålls; null tömmer dem. Svarar 201 när kunden skapades och 200 när den uppdaterades.\n\nKräver: ecommerce:write.",
        "tags": [
          "Kunder"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "ecommerce:write"
        ],
        "parameters": [
          {
            "name": "store_id",
            "in": "path",
            "required": true,
            "description": "Butikens id, som ni väljer.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,64}$",
              "example": "butik-se"
            }
          },
          {
            "name": "customer_id",
            "in": "path",
            "required": true,
            "description": "Kundens id i er butik.",
            "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": "Kundens e-postadress.",
                    "example": "anna@example.se"
                  },
                  "first_name": {
                    "description": "Förnamn.",
                    "example": "Anna",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 100
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "last_name": {
                    "description": "Efternamn.",
                    "example": "Svensson",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 100
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "company": {
                    "description": "Företag.",
                    "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": "Kunden (201 om den skapades).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Customer"
                }
              }
            }
          },
          "400": {
            "description": "bad_request: Förfrågan kunde inte läsas",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Finns inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "unsupported_media_type: Fel innehållstyp",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: Uppgifterna stämmer inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "customers.delete",
        "summary": "Ta bort kund",
        "description": "Tar bort kunden och hens kundkorgar. Ordrarna finns kvar utan kund, så att kampanjernas intäkt stämmer.\n\nAnvänd när en kund begär att bli raderad i butiken. Raderas en kontakt i arbetsytan (GDPR) tas kunder med samma adress bort på samma sätt.\n\nKräver: ecommerce:write.",
        "tags": [
          "Kunder"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "ecommerce:write"
        ],
        "parameters": [
          {
            "name": "store_id",
            "in": "path",
            "required": true,
            "description": "Butikens id, som ni väljer.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,64}$",
              "example": "butik-se"
            }
          },
          {
            "name": "customer_id",
            "in": "path",
            "required": true,
            "description": "Kundens id i er butik.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9._~:@-]{1,100}$",
              "example": "1042"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Borttagen."
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Finns inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/stores/{store_id}/products": {
      "get": {
        "operationId": "products.list",
        "summary": "Lista produkter",
        "description": "Butikens produkter med varianter, en sida i taget.\n\nKräver: ecommerce:read.",
        "tags": [
          "Produkter"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "ecommerce:read"
        ],
        "parameters": [
          {
            "name": "store_id",
            "in": "path",
            "required": true,
            "description": "Butikens id, som ni väljer.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,64}$",
              "example": "butik-se"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Hur många som högst ska komma i svaret (1–250, standard 100).",
            "schema": {
              "default": 100,
              "type": "integer",
              "minimum": 1,
              "maximum": 250
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "next_cursor från förra svaret, för nästa sida. Utelämna för första sidan.",
            "schema": {
              "type": "string",
              "maxLength": 400
            }
          },
          {
            "name": "updated_since",
            "in": "query",
            "required": false,
            "description": "Bara det som ändrats sedan dess (ISO 8601).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "En sida produkter.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProductPage"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Finns inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: Uppgifterna stämmer inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/stores/{store_id}/products/{product_id}": {
      "get": {
        "operationId": "products.get",
        "summary": "Hämta produkt",
        "description": "En produkt med varianter.\n\nKräver: ecommerce:read.",
        "tags": [
          "Produkter"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "ecommerce:read"
        ],
        "parameters": [
          {
            "name": "store_id",
            "in": "path",
            "required": true,
            "description": "Butikens id, som ni väljer.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,64}$",
              "example": "butik-se"
            }
          },
          {
            "name": "product_id",
            "in": "path",
            "required": true,
            "description": "Produktens id i er butik.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9._~:@-]{1,100}$",
              "example": "731"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Produkten.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Product"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Finns inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "put": {
        "operationId": "products.upsert",
        "summary": "Skapa eller uppdatera produkt",
        "description": "Skapar produkten med butikens id, eller uppdaterar den. Skickas variants ersätter de alla varianter.\n\nFält du utelämnar behålls; null tömmer dem. Svarar 201 när produkten skapades och 200 när den uppdaterades.\n\nKräver: ecommerce:write.",
        "tags": [
          "Produkter"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "ecommerce:write"
        ],
        "parameters": [
          {
            "name": "store_id",
            "in": "path",
            "required": true,
            "description": "Butikens id, som ni väljer.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,64}$",
              "example": "butik-se"
            }
          },
          {
            "name": "product_id",
            "in": "path",
            "required": true,
            "description": "Produktens id i er butik.",
            "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": "Produktens namn.",
                    "example": "T-shirt i ekologisk bomull"
                  },
                  "url": {
                    "description": "Produktens sida i butiken.",
                    "example": "https://butik.se/produkt/t-shirt",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 2048
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "image_url": {
                    "description": "Produktens bild.",
                    "example": "https://butik.se/bilder/t-shirt.jpg",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 2048
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "vendor": {
                    "description": "Tillverkare eller varumärke.",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 255
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "product_type": {
                    "description": "Produkttyp eller kategori.",
                    "example": "Kläder",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 255
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "variants": {
                    "description": "Varianterna (högst 100). Ersätter alla varianter när de skickas.",
                    "maxItems": 100,
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "pattern": "^[A-Za-z0-9._~:@-]{1,100}$",
                          "description": "Variantens id i er butik.",
                          "example": "731-blue-m"
                        },
                        "title": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 255,
                          "example": "Blå, M"
                        },
                        "sku": {
                          "description": "Artikelnummer.",
                          "example": "TS-BLU-M",
                          "anyOf": [
                            {
                              "type": "string",
                              "maxLength": 100
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "price": {
                          "anyOf": [
                            {
                              "type": "number",
                              "minimum": 0,
                              "maximum": 999999999999.99,
                              "description": "Pris per styck.",
                              "example": 249
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "inventory_quantity": {
                          "description": "Antal i lager.",
                          "anyOf": [
                            {
                              "type": "integer",
                              "minimum": -1000000,
                              "maximum": 1000000000
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "url": {
                          "description": "Variantens sida.",
                          "anyOf": [
                            {
                              "type": "string",
                              "maxLength": 2048
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "image_url": {
                          "description": "Variantens bild.",
                          "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": "Produkten (201 om den skapades).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Product"
                }
              }
            }
          },
          "400": {
            "description": "bad_request: Förfrågan kunde inte läsas",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Finns inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "unsupported_media_type: Fel innehållstyp",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: Uppgifterna stämmer inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "products.delete",
        "summary": "Ta bort produkt",
        "description": "Tar bort produkten och dess varianter. Orderrader som nämner den finns kvar.\n\nKräver: ecommerce:write.",
        "tags": [
          "Produkter"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "ecommerce:write"
        ],
        "parameters": [
          {
            "name": "store_id",
            "in": "path",
            "required": true,
            "description": "Butikens id, som ni väljer.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,64}$",
              "example": "butik-se"
            }
          },
          {
            "name": "product_id",
            "in": "path",
            "required": true,
            "description": "Produktens id i er butik.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9._~:@-]{1,100}$",
              "example": "731"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Borttagen."
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Finns inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/stores/{store_id}/orders": {
      "get": {
        "operationId": "orders.list",
        "summary": "Lista ordrar",
        "description": "Butikens ordrar med rader, en sida i taget.\n\nKräver: ecommerce:read.",
        "tags": [
          "Ordrar"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "ecommerce:read"
        ],
        "parameters": [
          {
            "name": "store_id",
            "in": "path",
            "required": true,
            "description": "Butikens id, som ni väljer.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,64}$",
              "example": "butik-se"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Hur många som högst ska komma i svaret (1–250, standard 100).",
            "schema": {
              "default": 100,
              "type": "integer",
              "minimum": 1,
              "maximum": 250
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "next_cursor från förra svaret, för nästa sida. Utelämna för första sidan.",
            "schema": {
              "type": "string",
              "maxLength": 400
            }
          },
          {
            "name": "customer_id",
            "in": "query",
            "required": false,
            "description": "Bara kundens ordrar (butikens kund-id).",
            "schema": {
              "type": "string",
              "maxLength": 100
            }
          },
          {
            "name": "campaign_id",
            "in": "query",
            "required": false,
            "description": "Bara ordrar från kampanjen.",
            "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": "Bara ordrar med den statusen.",
            "schema": {
              "type": "string",
              "enum": [
                "pending",
                "paid",
                "refunded",
                "cancelled"
              ]
            }
          },
          {
            "name": "updated_since",
            "in": "query",
            "required": false,
            "description": "Bara det som ändrats sedan dess (ISO 8601).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "En sida ordrar.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrderPage"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Finns inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: Uppgifterna stämmer inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/stores/{store_id}/orders/{order_id}": {
      "get": {
        "operationId": "orders.get",
        "summary": "Hämta order",
        "description": "En order med rader.\n\nKräver: ecommerce:read.",
        "tags": [
          "Ordrar"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "ecommerce:read"
        ],
        "parameters": [
          {
            "name": "store_id",
            "in": "path",
            "required": true,
            "description": "Butikens id, som ni väljer.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,64}$",
              "example": "butik-se"
            }
          },
          {
            "name": "order_id",
            "in": "path",
            "required": true,
            "description": "Orderns id i er butik.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9._~:@-]{1,100}$",
              "example": "50087"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Ordern.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Order"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Finns inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "put": {
        "operationId": "orders.upsert",
        "summary": "Skapa eller uppdatera order",
        "description": "Skapar ordern med butikens id, eller uppdaterar den – skicka ordern igen när den ändras (betald, återbetald, avbruten).\n\nOrdern skickas hel: kunden, totalbeloppet och alla rader. Kunden skapas eller uppdateras med den, och raderna ersätter de tidigare. campaign_id, financial_status, currency, processed_at och delbeloppen behåller sina värden om du utelämnar dem.\n\nBara betalda ordrar (paid) räknas som köp i distributionslistornas villkor och som intäkt för kampanjen i campaign_id. Delvis återbetald: skicka ordern igen med det nya totalbeloppet.\n\nSvarar 201 när ordern skapades och 200 när den uppdaterades.\n\nKräver: ecommerce:write.",
        "tags": [
          "Ordrar"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "ecommerce:write"
        ],
        "parameters": [
          {
            "name": "store_id",
            "in": "path",
            "required": true,
            "description": "Butikens id, som ni väljer.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,64}$",
              "example": "butik-se"
            }
          },
          {
            "name": "order_id",
            "in": "path",
            "required": true,
            "description": "Orderns id i er butik.",
            "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": "Kundens id i er butik.",
                        "example": "1042"
                      },
                      "email": {
                        "type": "string",
                        "maxLength": 254,
                        "description": "Kundens e-postadress.",
                        "example": "anna@example.se"
                      },
                      "first_name": {
                        "description": "Förnamn.",
                        "example": "Anna",
                        "anyOf": [
                          {
                            "type": "string",
                            "maxLength": 100
                          },
                          {
                            "type": "null"
                          }
                        ]
                      },
                      "last_name": {
                        "description": "Efternamn.",
                        "example": "Svensson",
                        "anyOf": [
                          {
                            "type": "string",
                            "maxLength": 100
                          },
                          {
                            "type": "null"
                          }
                        ]
                      },
                      "company": {
                        "description": "Företag.",
                        "anyOf": [
                          {
                            "type": "string",
                            "maxLength": 200
                          },
                          {
                            "type": "null"
                          }
                        ]
                      }
                    },
                    "required": [
                      "id",
                      "email"
                    ],
                    "additionalProperties": false,
                    "description": "Kunden. Skapas eller uppdateras med ordern (samma regler som PUT /customers/{customer_id})."
                  },
                  "campaign_id": {
                    "description": "Kampanjen kunden kom från: värdet av qn_cid på länken hen klickade på. Räknas bara för arbetsytans egna kampanjer; ett okänt id sparas inte (men ordern sparas).",
                    "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: betald – räknas som köp · pending: väntar på betalning · refunded: återbetald · cancelled: avbruten. Standard när ordern skapas: paid.",
                    "type": "string",
                    "enum": [
                      "pending",
                      "paid",
                      "refunded",
                      "cancelled"
                    ]
                  },
                  "currency": {
                    "description": "Standard: butikens valuta.",
                    "type": "string",
                    "pattern": "^[A-Z]{3}$",
                    "example": "SEK"
                  },
                  "order_total": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 999999999999.99,
                    "description": "Orderns totalbelopp, inklusive moms och frakt.",
                    "example": 548
                  },
                  "tax_total": {
                    "anyOf": [
                      {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 999999999999.99,
                        "description": "Varav moms.",
                        "example": 109.6
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "shipping_total": {
                    "anyOf": [
                      {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 999999999999.99,
                        "description": "Varav frakt.",
                        "example": 49
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "discount_total": {
                    "anyOf": [
                      {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 999999999999.99,
                        "description": "Rabatt.",
                        "example": 0
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "processed_at": {
                    "description": "När ordern lades i butiken (ISO 8601). Standard när ordern skapas: nu. Skicka den vid import av gamla ordrar.",
                    "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": "Radens id i er butik.",
                          "example": "1"
                        },
                        "product_id": {
                          "type": "string",
                          "pattern": "^[A-Za-z0-9._~:@-]{1,100}$",
                          "description": "Produktens id i er butik.",
                          "example": "731"
                        },
                        "variant_id": {
                          "anyOf": [
                            {
                              "type": "string",
                              "pattern": "^[A-Za-z0-9._~:@-]{1,100}$",
                              "description": "Variantens id i er butik.",
                              "example": "731-blue-m"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "title": {
                          "description": "Vad som köptes, som det stod på ordern.",
                          "example": "T-shirt i ekologisk bomull, blå, M",
                          "anyOf": [
                            {
                              "type": "string",
                              "maxLength": 255
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "quantity": {
                          "type": "integer",
                          "minimum": 1,
                          "maximum": 1000000,
                          "description": "Antal.",
                          "example": 2
                        },
                        "price": {
                          "type": "number",
                          "minimum": 0,
                          "maximum": 999999999999.99,
                          "description": "Pris per styck.",
                          "example": 249
                        },
                        "discount": {
                          "anyOf": [
                            {
                              "type": "number",
                              "minimum": 0,
                              "maximum": 999999999999.99,
                              "description": "Rabatt på raden.",
                              "example": 499
                            },
                            {
                              "type": "null"
                            }
                          ]
                        }
                      },
                      "required": [
                        "id",
                        "product_id",
                        "quantity",
                        "price"
                      ],
                      "additionalProperties": false
                    },
                    "description": "Orderns rader (högst 500). Ersätter alla rader. Produkterna behöver inte ha skickats in."
                  }
                },
                "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": "Ordern (201 om den skapades).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Order"
                }
              }
            }
          },
          "400": {
            "description": "bad_request: Förfrågan kunde inte läsas",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Finns inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "unsupported_media_type: Fel innehållstyp",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: Uppgifterna stämmer inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "orders.delete",
        "summary": "Ta bort order",
        "description": "Tar bort ordern. En avbruten eller återbetald order skickas hellre med sin nya status.\n\nKräver: ecommerce:write.",
        "tags": [
          "Ordrar"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "ecommerce:write"
        ],
        "parameters": [
          {
            "name": "store_id",
            "in": "path",
            "required": true,
            "description": "Butikens id, som ni väljer.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,64}$",
              "example": "butik-se"
            }
          },
          {
            "name": "order_id",
            "in": "path",
            "required": true,
            "description": "Orderns id i er butik.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9._~:@-]{1,100}$",
              "example": "50087"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Borttagen."
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Finns inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/stores/{store_id}/carts": {
      "get": {
        "operationId": "carts.list",
        "summary": "Lista kundkorgar",
        "description": "Butikens öppna kundkorgar, en sida i taget.\n\nKräver: ecommerce:read.",
        "tags": [
          "Kundkorgar"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "ecommerce:read"
        ],
        "parameters": [
          {
            "name": "store_id",
            "in": "path",
            "required": true,
            "description": "Butikens id, som ni väljer.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,64}$",
              "example": "butik-se"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Hur många som högst ska komma i svaret (1–250, standard 100).",
            "schema": {
              "default": 100,
              "type": "integer",
              "minimum": 1,
              "maximum": 250
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "next_cursor från förra svaret, för nästa sida. Utelämna för första sidan.",
            "schema": {
              "type": "string",
              "maxLength": 400
            }
          },
          {
            "name": "updated_since",
            "in": "query",
            "required": false,
            "description": "Bara det som ändrats sedan dess (ISO 8601).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "En sida kundkorgar.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CartPage"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Finns inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: Uppgifterna stämmer inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/stores/{store_id}/carts/{cart_id}": {
      "get": {
        "operationId": "carts.get",
        "summary": "Hämta kundkorg",
        "description": "En kundkorg med rader.\n\nKräver: ecommerce:read.",
        "tags": [
          "Kundkorgar"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "ecommerce:read"
        ],
        "parameters": [
          {
            "name": "store_id",
            "in": "path",
            "required": true,
            "description": "Butikens id, som ni väljer.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,64}$",
              "example": "butik-se"
            }
          },
          {
            "name": "cart_id",
            "in": "path",
            "required": true,
            "description": "Kundkorgens id i er butik.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9._~:@-]{1,100}$",
              "example": "c-8812"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Kundkorgen.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Cart"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Finns inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "put": {
        "operationId": "carts.upsert",
        "summary": "Skapa eller uppdatera kundkorg",
        "description": "Skapar korgen med butikens id, eller uppdaterar den. Raderna ersätter de tidigare.\n\nEn korg hör alltid till en kund, som skapas eller uppdateras med den. Ta bort korgen när den har blivit en order.\n\nKräver: ecommerce:write.",
        "tags": [
          "Kundkorgar"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "ecommerce:write"
        ],
        "parameters": [
          {
            "name": "store_id",
            "in": "path",
            "required": true,
            "description": "Butikens id, som ni väljer.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,64}$",
              "example": "butik-se"
            }
          },
          {
            "name": "cart_id",
            "in": "path",
            "required": true,
            "description": "Kundkorgens id i er butik.",
            "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": "Kundens id i er butik.",
                        "example": "1042"
                      },
                      "email": {
                        "type": "string",
                        "maxLength": 254,
                        "description": "Kundens e-postadress.",
                        "example": "anna@example.se"
                      },
                      "first_name": {
                        "description": "Förnamn.",
                        "example": "Anna",
                        "anyOf": [
                          {
                            "type": "string",
                            "maxLength": 100
                          },
                          {
                            "type": "null"
                          }
                        ]
                      },
                      "last_name": {
                        "description": "Efternamn.",
                        "example": "Svensson",
                        "anyOf": [
                          {
                            "type": "string",
                            "maxLength": 100
                          },
                          {
                            "type": "null"
                          }
                        ]
                      },
                      "company": {
                        "description": "Företag.",
                        "anyOf": [
                          {
                            "type": "string",
                            "maxLength": 200
                          },
                          {
                            "type": "null"
                          }
                        ]
                      }
                    },
                    "required": [
                      "id",
                      "email"
                    ],
                    "additionalProperties": false,
                    "description": "Kunden. Skapas eller uppdateras med ordern (samma regler som PUT /customers/{customer_id})."
                  },
                  "campaign_id": {
                    "description": "Kampanjen kunden kom från: värdet av qn_cid på länken hen klickade på. Räknas bara för arbetsytans egna kampanjer; ett okänt id sparas inte (men ordern sparas).",
                    "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": "Adressen där kunden kan slutföra köpet.",
                    "example": "https://butik.se/kassa?korg=c-8812",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 2048
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "currency": {
                    "description": "Standard: butikens valuta.",
                    "type": "string",
                    "pattern": "^[A-Z]{3}$",
                    "example": "SEK"
                  },
                  "order_total": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 999999999999.99,
                    "description": "Korgens totalbelopp.",
                    "example": 498
                  },
                  "tax_total": {
                    "anyOf": [
                      {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 999999999999.99,
                        "description": "Varav moms.",
                        "example": 499
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "lines": {
                    "maxItems": 500,
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "pattern": "^[A-Za-z0-9._~:@-]{1,100}$",
                          "description": "Radens id i er butik.",
                          "example": "1"
                        },
                        "product_id": {
                          "type": "string",
                          "pattern": "^[A-Za-z0-9._~:@-]{1,100}$",
                          "description": "Produktens id i er butik.",
                          "example": "731"
                        },
                        "variant_id": {
                          "anyOf": [
                            {
                              "type": "string",
                              "pattern": "^[A-Za-z0-9._~:@-]{1,100}$",
                              "description": "Variantens id i er butik.",
                              "example": "731-blue-m"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "title": {
                          "description": "Vad som köptes, som det stod på ordern.",
                          "example": "T-shirt i ekologisk bomull, blå, M",
                          "anyOf": [
                            {
                              "type": "string",
                              "maxLength": 255
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "quantity": {
                          "type": "integer",
                          "minimum": 1,
                          "maximum": 1000000,
                          "description": "Antal.",
                          "example": 2
                        },
                        "price": {
                          "type": "number",
                          "minimum": 0,
                          "maximum": 999999999999.99,
                          "description": "Pris per styck.",
                          "example": 249
                        }
                      },
                      "required": [
                        "id",
                        "product_id",
                        "quantity",
                        "price"
                      ],
                      "additionalProperties": false
                    },
                    "description": "Korgens rader. Ersätter alla rader."
                  }
                },
                "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": "Kundkorgen (201 om den skapades).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Cart"
                }
              }
            }
          },
          "400": {
            "description": "bad_request: Förfrågan kunde inte läsas",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Finns inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "unsupported_media_type: Fel innehållstyp",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: Uppgifterna stämmer inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "carts.delete",
        "summary": "Ta bort kundkorg",
        "description": "Tar bort korgen, till exempel när den har blivit en order.\n\nKräver: ecommerce:write.",
        "tags": [
          "Kundkorgar"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "ecommerce:write"
        ],
        "parameters": [
          {
            "name": "store_id",
            "in": "path",
            "required": true,
            "description": "Butikens id, som ni väljer.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,64}$",
              "example": "butik-se"
            }
          },
          {
            "name": "cart_id",
            "in": "path",
            "required": true,
            "description": "Kundkorgens id i er butik.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9._~:@-]{1,100}$",
              "example": "c-8812"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Borttagen."
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Finns inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/revenue": {
      "get": {
        "operationId": "revenue.list",
        "summary": "Intäkt per kampanj",
        "description": "Arbetsytans kampanjer med de betalda ordrar som kom från dem, nyaste kampanjen först.\n\nEn order räknas till kampanjen i sitt campaign_id (qn_cid från länken kunden klickade på). Beloppen summeras per valuta. since och until gäller orderns tid (processed_at).\n\nKräver: ecommerce:read.",
        "tags": [
          "Intäkt"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "ecommerce:read"
        ],
        "parameters": [
          {
            "name": "since",
            "in": "query",
            "required": false,
            "description": "Bara ordrar från och med den tiden (ISO 8601).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "until",
            "in": "query",
            "required": false,
            "description": "Bara ordrar före den tiden (ISO 8601).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "campaign_id",
            "in": "query",
            "required": false,
            "description": "Bara kampanjen.",
            "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": "Bara butikens ordrar.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,64}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Kampanjerna med intäkt (högst 500).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CampaignRevenueList"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: Uppgifterna stämmer inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/batch": {
      "post": {
        "operationId": "batch.run",
        "summary": "Kör flera anrop",
        "description": "Upp till 500 anrop i ett, i tur och ordning. Bra för att läsa in historik: kunder, produkter och ordrar.\n\nVarje operation är ett vanligt anrop under /api/v1 – metod, sökväg och kropp – och kontrolleras och körs precis som om det skickats för sig: med nyckelns behörigheter och samma fel. Svaren kommer i samma ordning, med status och kropp för var och en. En operation som misslyckas stoppar inte de andra.\n\nHela batchen räknas som ett anrop mot gränsen per minut, men högst 20 batchar per minut och nyckel. Upsert med PUT gör det tryggt att köra om en batch som avbröts; med Idempotency-Key får en omsänd batch samma svar utan att köras igen.\n\nAlla giltiga nycklar.",
        "tags": [
          "Batch"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Valfri nyckel (t.ex. ett uuid). Samma nyckel och samma anrop inom 24 timmar ger samma svar igen, utan att något görs två gånger.",
            "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": "Sökvägen under /api/v1, med query om anropet har en.",
                          "example": "/stores/butik-se/orders/50087"
                        },
                        "body": {
                          "description": "Anropets kropp, som ett JSON-objekt.",
                          "type": "object",
                          "propertyNames": {
                            "type": "string"
                          },
                          "additionalProperties": {}
                        }
                      },
                      "required": [
                        "method",
                        "path"
                      ],
                      "additionalProperties": false
                    },
                    "description": "Operationerna (högst 500), som körs i tur och ordning."
                  }
                },
                "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": "Svaren, i samma ordning som operationerna.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BatchResult"
                }
              }
            }
          },
          "400": {
            "description": "bad_request: Förfrågan kunde inte läsas",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "idempotency_in_progress: Anropet pågår redan",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "unsupported_media_type: Fel innehållstyp",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: Uppgifterna stämmer inte · idempotency_key_reused: Idempotency-Key används redan",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/webhooks": {
      "get": {
        "operationId": "webhooks.list",
        "summary": "Lista webhooks",
        "description": "Arbetsytans webhooks.\n\nKräver: webhooks:read.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "webhooks:read"
        ],
        "responses": {
          "200": {
            "description": "Alla webhooks.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookList"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "webhooks.create",
        "summary": "Skapa webhook",
        "description": "En ny webhook. Svaret har hemligheten som leveranserna signeras med – den visas bara nu.\n\nAdressen måste vara https, på standardporten och nåbar från internet. Varje leverans är en POST med JSON och headern Qrona-Signature; svara 2xx inom tio sekunder. Läs mer i guiden om webhooks.\n\nKräver: webhooks:write.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "webhooks:write"
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Valfri nyckel (t.ex. ett uuid). Samma nyckel och samma anrop inom 24 timmar ger samma svar igen, utan att något görs två gånger.",
            "schema": {
              "type": "string",
              "maxLength": 255
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "maxLength": 2048,
                    "description": "Adressen som tar emot händelserna (https, standardport, nåbar från 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": "Händelserna webhooken ska få: contact.subscribed (anmälan), contact.unsubscribed (avregistrering), contact.bounced (studs), contact.complained (skräppostanmälan).",
                    "example": [
                      "contact.unsubscribed",
                      "contact.bounced",
                      "contact.complained"
                    ]
                  },
                  "description": {
                    "description": "Vad webhooken är till för.",
                    "example": "Avregistreringar till WooCommerce",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 200
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "include_api": {
                    "description": "Skicka även ändringar som gjorts via API:t. Standard: false, så att en integration inte får höra om sina egna ändringar.",
                    "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": "Den nya webhooken, med hemligheten.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookCreated"
                }
              }
            }
          },
          "400": {
            "description": "bad_request: Förfrågan kunde inte läsas",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "limit_reached: Taket är nått · idempotency_in_progress: Anropet pågår redan",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "unsupported_media_type: Fel innehållstyp",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: Uppgifterna stämmer inte · idempotency_key_reused: Idempotency-Key används redan",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/webhooks/{id}": {
      "get": {
        "operationId": "webhooks.get",
        "summary": "Hämta webhook",
        "description": "En webhook och hur dess leveranser går.\n\nKräver: webhooks:read.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "webhooks:read"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Webhookens 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": "Webhooken.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Webhook"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Finns inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "webhooks.update",
        "summary": "Ändra webhook",
        "description": "Adress, händelser och beskrivning, eller stäng av och slå på den.\n\nEn webhook vars leveranser har misslyckats 100 gånger i rad stängs av. Slå på den igen med active: true när mottagaren fungerar.\n\nKräver: webhooks:write.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "webhooks:write"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Webhookens 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": "Adressen som tar emot händelserna (https, standardport, nåbar från 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": "Händelserna webhooken ska få: contact.subscribed (anmälan), contact.unsubscribed (avregistrering), contact.bounced (studs), contact.complained (skräppostanmälan).",
                    "example": [
                      "contact.unsubscribed",
                      "contact.bounced",
                      "contact.complained"
                    ]
                  },
                  "description": {
                    "description": "Vad webhooken är till för.",
                    "example": "Avregistreringar till WooCommerce",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 200
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "include_api": {
                    "description": "Skicka även ändringar som gjorts via API:t. Standard: false, så att en integration inte får höra om sina egna ändringar.",
                    "type": "boolean"
                  },
                  "active": {
                    "description": "false stänger av webhooken. true slår på den igen (och nollställer räkningen av misslyckade leveranser).",
                    "type": "boolean"
                  }
                },
                "additionalProperties": false
              },
              "example": {
                "events": [
                  "contact.subscribed",
                  "contact.unsubscribed"
                ],
                "active": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhooken efter ändringen.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Webhook"
                }
              }
            }
          },
          "400": {
            "description": "bad_request: Förfrågan kunde inte läsas",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Finns inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "unsupported_media_type: Fel innehållstyp",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: Uppgifterna stämmer inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "webhooks.delete",
        "summary": "Ta bort webhook",
        "description": "Tar bort webhooken. Leveranser som väntar skickas inte.\n\nKräver: webhooks:write.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "webhooks:write"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Webhookens 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": "Borttagen."
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Finns inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/webhooks/{id}/deliveries": {
      "get": {
        "operationId": "webhooks.deliveries",
        "summary": "Lista leveranser",
        "description": "Webhookens leveranser de senaste 30 dagarna, nyaste först: vad som skickades, hur mottagaren svarade och när nästa försök görs.\n\nKräver: webhooks:read.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "webhooks:read"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Webhookens 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": "Hur många som högst ska komma i svaret (1–100, standard 25).",
            "schema": {
              "default": 25,
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "next_cursor från förra svaret, för nästa sida. Utelämna för första sidan.",
            "schema": {
              "type": "string",
              "maxLength": 400
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Bara leveranser med den statusen.",
            "schema": {
              "type": "string",
              "enum": [
                "pending",
                "delivered",
                "failed"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "En sida leveranser.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookDeliveryPage"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Finns inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: Uppgifterna stämmer inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/webhooks/{id}/test": {
      "post": {
        "operationId": "webhooks.test",
        "summary": "Testa webhook",
        "description": "Skickar en ping till adressen direkt och svarar med hur det gick. Görs inte om.\n\nKräver: webhooks:write.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "webhooks:write"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Webhookens 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": "Valfri nyckel (t.ex. ett uuid). Samma nyckel och samma anrop inom 24 timmar ger samma svar igen, utan att något görs två gånger.",
            "schema": {
              "type": "string",
              "maxLength": 255
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Resultatet.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookTest"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Finns inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "idempotency_in_progress: Anropet pågår redan",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "idempotency_key_reused: Idempotency-Key används redan",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/messages": {
      "post": {
        "operationId": "messages.send",
        "summary": "Skicka meddelande",
        "description": "Ett meddelande till en mottagare, gjort av mallens senast publicerade version och datan. Skickas direkt.\n\nDatan kontrolleras mot mallens datakontrakt innan något skickas. Meddelandet sparar mallversionen och HTML:ens SHA-256, så att det som skickades alltid kan visas igen.\n\nidempotency_key är unik per arbetsyta: samma nyckel igen svarar 200 med det första meddelandet och skickar inget nytt, så ett omförsök blir aldrig en dubblett. Samma nyckel med annat innehåll ger 409 idempotency_conflict.\n\nEtt meddelande som inte får gå – adressen är spärrad för klassen, eller månadens pott är slut – sparas med status suppressed och reason, och kvittot message.suppressed skickas. Svaret är då ändå 201.\n\nKräver: messages:send.",
        "tags": [
          "Meddelanden"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "messages:send"
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Valfri nyckel (t.ex. ett uuid). Samma nyckel och samma anrop inom 24 timmar ger samma svar igen, utan att något görs två gånger.",
            "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": "Mallens nyckel. Meddelandet görs från mallens senast publicerade version.",
                    "example": "byra.momsunderlag"
                  },
                  "to": {
                    "type": "object",
                    "properties": {
                      "email": {
                        "type": "string",
                        "maxLength": 254,
                        "description": "Mottagarens adress.",
                        "example": "ekonomi@klienten.se"
                      },
                      "name": {
                        "description": "Mottagarens namn. Fyller {{first_name}} och {{last_name}} i mallen.",
                        "example": "Eva Ekonom",
                        "anyOf": [
                          {
                            "type": "string",
                            "maxLength": 200
                          },
                          {
                            "type": "null"
                          }
                        ]
                      }
                    },
                    "required": [
                      "email"
                    ],
                    "additionalProperties": false
                  },
                  "category": {
                    "type": "string",
                    "enum": [
                      "service",
                      "marketing"
                    ],
                    "description": "service: påminnelser och brev inom uppdraget – stoppas av studs, skräppostanmälan, radering och manuell spärr, aldrig av en avregistrering, och har ingen avregistreringslänk. marketing: planerings- och kunskapsbrev – följer arbetsytans vanliga regler, avregistreringar och månadstaket."
                  },
                  "data": {
                    "type": "object",
                    "propertyNames": {
                      "type": "string"
                    },
                    "additionalProperties": {},
                    "description": "Meddelandets data, färdig att visa (belopp formaterade, datum utskrivna). Kontrolleras mot mallens datakontrakt.",
                    "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": "Unik per arbetsyta och meddelande, t.ex. utskickets id i Qrona. Samma nyckel igen ger samma meddelande, aldrig ett nytt.",
                    "example": "occ_20261023_0042"
                  },
                  "reference": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 255,
                    "description": "Qronas referens. Kommer tillbaka i varje kvitto (webhook).",
                    "example": "occ_20261023_0042"
                  },
                  "client_ref": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 255,
                    "description": "Byråns klient, pseudonymt. Antalet olika klienter per månad är underlaget för fakturan.",
                    "example": "kl_7f3a"
                  },
                  "reply_to": {
                    "description": "Svarsadress för just det här meddelandet, t.ex. klientens konsult. Utan: tilläggets.",
                    "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": "Meddelandet (200 när idempotency_key redan använts med samma innehåll).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Message"
                }
              }
            }
          },
          "400": {
            "description": "bad_request: Förfrågan kunde inte läsas",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Finns inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "template_not_published: Mallen är inte publicerad · idempotency_conflict: idempotency_key används redan · sender_not_configured: Avsändare saknas · sending_not_enabled: Utskick är inte godkända · idempotency_in_progress: Anropet pågår redan",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "unsupported_media_type: Fel innehållstyp",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: Uppgifterna stämmer inte · idempotency_key_reused: Idempotency-Key används redan",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/messages/{id}": {
      "get": {
        "operationId": "messages.get",
        "summary": "Hämta meddelande",
        "description": "Ett meddelande och hur det har gått: skickat, levererat, studsat …\n\nKräver: messages:send.",
        "tags": [
          "Meddelanden"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "messages:send"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Meddelandets 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": "Meddelandet.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Message"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Finns inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/templates/{key}/render": {
      "post": {
        "operationId": "templates.render",
        "summary": "Rendera mall",
        "description": "Mallens senast publicerade version med datan, precis som den skickas – för förhandsvisningen i Qrona.\n\nDatan kontrolleras mot mallens datakontrakt som när ett meddelande skickas. Ingenting skickas och ingenting sparas.\n\nKräver: templates:render.",
        "tags": [
          "Qrona-mallar"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scopes": [
          "templates:render"
        ],
        "parameters": [
          {
            "name": "key",
            "in": "path",
            "required": true,
            "description": "Mallens nyckel, samma som datakontraktets.",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9][a-z0-9_.-]{1,99}$",
              "example": "byra.momsunderlag"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Valfri nyckel (t.ex. ett uuid). Samma nyckel och samma anrop inom 24 timmar ger samma svar igen, utan att något görs två gånger.",
            "schema": {
              "type": "string",
              "maxLength": 255
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "data": {
                    "type": "object",
                    "propertyNames": {
                      "type": "string"
                    },
                    "additionalProperties": {},
                    "description": "Meddelandets data, färdig att visa (belopp formaterade, datum utskrivna). Kontrolleras mot mallens datakontrakt.",
                    "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": "Klassen meddelandet ska ha (som när det skickas). Utan: service.",
                    "type": "string",
                    "enum": [
                      "service",
                      "marketing"
                    ]
                  },
                  "to": {
                    "description": "En mottagare att visa det för. Utan: ett exempelnamn.",
                    "type": "object",
                    "properties": {
                      "email": {
                        "type": "string",
                        "maxLength": 254,
                        "description": "Mottagarens adress.",
                        "example": "ekonomi@klienten.se"
                      },
                      "name": {
                        "description": "Mottagarens namn. Fyller {{first_name}} och {{last_name}} i mallen.",
                        "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": "Den renderade mallen.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderedMessage"
                }
              }
            }
          },
          "400": {
            "description": "bad_request: Förfrågan kunde inte läsas",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "unauthenticated: API-nyckel saknas · invalid_key: Okänd API-nyckel · key_revoked: API-nyckeln är återkallad · key_expired: API-nyckeln har gått ut · key_inactive: API-nyckeln gäller inte längre",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "payment_required: Abonnemang krävs",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: Nyckeln saknar behörighet · forbidden: Inte tillåtet · workspace_suspended: Arbetsytan är pausad",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not_found: Finns inte",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "template_not_published: Mallen är inte publicerad · idempotency_in_progress: Anropet pågår redan",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "unsupported_media_type: Fel innehållstyp",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed: Uppgifterna stämmer inte · idempotency_key_reused: Idempotency-Key används redan",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: För många anrop",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal_error: Något gick fel hos oss",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "qn_live_…",
        "description": "API-nyckel i Authorization: Bearer. Behörigheter: contacts:read (läsa kontakter), contacts:write (ändra kontakter), contacts:erase (radera kontakter (gdpr)), lists:read (läsa listor), lists:write (ändra listor), fields:read (läsa kontaktfält), segments:read (läsa distributionslistor), ecommerce:read (läsa e-handel), ecommerce:write (ändra e-handel), webhooks:read (läsa webhooks), webhooks:write (ändra webhooks), messages:send (skicka meddelanden), templates:render (förhandsgranska meddelanden)."
      }
    },
    "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": "Felkoden, för program. Se Felkoder."
          },
          "request_id": {
            "description": "Samma som headern X-Request-Id. Ange den om du kontaktar oss.",
            "type": "string"
          },
          "errors": {
            "description": "Vid validation_failed: vad som är fel, per fält.",
            "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": "Ett fel (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": "Personen som nyckeln agerar som, och hens roll i arbetsytan just nu. För Qronas systemnyckel är id null."
          }
        },
        "required": [
          "api_version",
          "workspace",
          "key",
          "acting_as"
        ],
        "additionalProperties": false,
        "description": "Vem nyckeln är och var den gäller.",
        "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": "Det finns fler: hämta nästa sida med cursor=next_cursor.",
            "example": false
          },
          "next_cursor": {
            "description": "Skicka som cursor för nästa sida. null på sista sidan.",
            "example": null,
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "data",
          "has_more",
          "next_cursor"
        ],
        "additionalProperties": false,
        "description": "En sida kontakter."
      },
      "Contact": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Kontaktens id."
          },
          "email": {
            "type": "string",
            "description": "E-postadressen (gemener). Ändras aldrig: samtycken och spärrar gäller adressen."
          },
          "first_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "last_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "company": {
            "type": [
              "string",
              "null"
            ]
          },
          "phone": {
            "description": "I internationellt format (E.164), t.ex. +46701234567.",
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "unsubscribed",
              "bounced",
              "complained",
              "deleted"
            ],
            "description": "active: kan få utskick · unsubscribed: har avregistrerat sig från allt · bounced: adressen studsar · complained: har anmält skräppost · deleted: raderad (GDPR), personuppgifterna är borta."
          },
          "fields": {
            "type": "object",
            "propertyNames": {
              "type": "string"
            },
            "additionalProperties": {
              "type": [
                "string",
                "number",
                "boolean"
              ]
            },
            "description": "Egna fält efter nyckel (se GET /fields). Känsliga fält, som personnummer, skickas aldrig ut."
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "source": {
            "type": "string",
            "description": "Hur kontakten kom in: manual, import, form, api …"
          },
          "consent": {
            "type": "object",
            "properties": {
              "at": {
                "anyOf": [
                  {
                    "type": "string",
                    "format": "date-time",
                    "description": "När samtycket gavs.",
                    "example": "2026-10-19T08:30:00.000Z"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "source": {
                "description": "Hur personen samtyckte, med egna ord.",
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "at",
              "source"
            ],
            "additionalProperties": false
          },
          "suppression": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "reason": {
                    "type": "string",
                    "description": "unsubscribed, bounced, complained, manual eller imported."
                  },
                  "created_at": {
                    "type": "string",
                    "format": "date-time",
                    "description": "När adressen spärrades.",
                    "example": "2026-10-19T08:30:00.000Z"
                  }
                },
                "required": [
                  "reason",
                  "created_at"
                ],
                "additionalProperties": false
              },
              {
                "type": "null"
              }
            ],
            "description": "Arbetsytans spärr på adressen. En spärrad adress får aldrig utskick, oavsett status."
          },
          "shared": {
            "type": "boolean",
            "description": "Delad från en nivå ovanför i organisationen: kan läsas och få utskick härifrån, men bara ändras där den hör hemma."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "När kontakten skapades.",
            "example": "2026-10-19T08:30:00.000Z"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "När kontakten senast ändrades.",
            "example": "2026-10-19T08:30:00.000Z"
          },
          "unsubscribed_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time",
                "description": "När personen avregistrerade sig.",
                "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": "En kontakt (mottagare) i arbetsytan.",
        "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": "Kontaktens id."
          },
          "email": {
            "type": "string",
            "description": "E-postadressen (gemener). Ändras aldrig: samtycken och spärrar gäller adressen."
          },
          "first_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "last_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "company": {
            "type": [
              "string",
              "null"
            ]
          },
          "phone": {
            "description": "I internationellt format (E.164), t.ex. +46701234567.",
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "unsubscribed",
              "bounced",
              "complained",
              "deleted"
            ],
            "description": "active: kan få utskick · unsubscribed: har avregistrerat sig från allt · bounced: adressen studsar · complained: har anmält skräppost · deleted: raderad (GDPR), personuppgifterna är borta."
          },
          "fields": {
            "type": "object",
            "propertyNames": {
              "type": "string"
            },
            "additionalProperties": {
              "type": [
                "string",
                "number",
                "boolean"
              ]
            },
            "description": "Egna fält efter nyckel (se GET /fields). Känsliga fält, som personnummer, skickas aldrig ut."
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "source": {
            "type": "string",
            "description": "Hur kontakten kom in: manual, import, form, api …"
          },
          "consent": {
            "type": "object",
            "properties": {
              "at": {
                "anyOf": [
                  {
                    "type": "string",
                    "format": "date-time",
                    "description": "När samtycket gavs.",
                    "example": "2026-10-19T08:30:00.000Z"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "source": {
                "description": "Hur personen samtyckte, med egna ord.",
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "at",
              "source"
            ],
            "additionalProperties": false
          },
          "suppression": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "reason": {
                    "type": "string",
                    "description": "unsubscribed, bounced, complained, manual eller imported."
                  },
                  "created_at": {
                    "type": "string",
                    "format": "date-time",
                    "description": "När adressen spärrades.",
                    "example": "2026-10-19T08:30:00.000Z"
                  }
                },
                "required": [
                  "reason",
                  "created_at"
                ],
                "additionalProperties": false
              },
              {
                "type": "null"
              }
            ],
            "description": "Arbetsytans spärr på adressen. En spärrad adress får aldrig utskick, oavsett status."
          },
          "shared": {
            "type": "boolean",
            "description": "Delad från en nivå ovanför i organisationen: kan läsas och få utskick härifrån, men bara ändras där den hör hemma."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "När kontakten skapades.",
            "example": "2026-10-19T08:30:00.000Z"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "När kontakten senast ändrades.",
            "example": "2026-10-19T08:30:00.000Z"
          },
          "unsubscribed_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time",
                "description": "När personen avregistrerade sig.",
                "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: med på listan · pending: väntar på att bekräfta via e-post · unsubscribed: har lämnat listan."
                },
                "subscribed_at": {
                  "anyOf": [
                    {
                      "type": "string",
                      "format": "date-time",
                      "description": "När personen kom med på listan.",
                      "example": "2026-10-19T08:30:00.000Z"
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              },
              "required": [
                "list_id",
                "name",
                "status",
                "subscribed_at"
              ],
              "additionalProperties": false
            },
            "description": "Arbetsytans listor som kontakten finns på. Tom för en delad kontakt."
          }
        },
        "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": "En kontakt med dess listor.",
        "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": "Kontakter."
      },
      "ListList": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/List"
            }
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "description": "Listor."
      },
      "List": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "double_opt_in": {
            "type": "boolean",
            "description": "Nya anmälningar måste bekräfta via e-post innan de kommer med."
          },
          "form_enabled": {
            "type": "boolean",
            "description": "Listans publika anmälningsformulär är öppet."
          },
          "counts": {
            "type": "object",
            "properties": {
              "subscribed": {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991,
                "description": "Får utskick: med på listan, aktiva och inte spärrade."
              },
              "pending": {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991,
                "description": "Har anmält sig men inte bekräftat än."
              },
              "unsubscribed": {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991
              },
              "blocked": {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991,
                "description": "Med på listan men nås inte: studsar, har anmält skräppost eller är spärrade."
              }
            },
            "required": [
              "subscribed",
              "pending",
              "unsubscribed",
              "blocked"
            ],
            "additionalProperties": false,
            "description": "Bara de kontakter som personen bakom nyckeln får se."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "När listan skapades.",
            "example": "2026-10-19T08:30:00.000Z"
          }
        },
        "required": [
          "id",
          "name",
          "description",
          "double_opt_in",
          "form_enabled",
          "counts",
          "created_at"
        ],
        "additionalProperties": false,
        "description": "En lista: en publik med eget anmälningsläge.",
        "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": "Det finns fler: hämta nästa sida med cursor=next_cursor.",
            "example": false
          },
          "next_cursor": {
            "description": "Skicka som cursor för nästa sida. null på sista sidan.",
            "example": null,
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "data",
          "has_more",
          "next_cursor"
        ],
        "additionalProperties": false,
        "description": "En sida medlemmar."
      },
      "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": "Får utskick till listan just nu (med på listan, aktiv och inte spärrad)."
          },
          "subscribed_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time",
                "description": "När personen kom med.",
                "example": "2026-10-19T08:30:00.000Z"
              },
              {
                "type": "null"
              }
            ]
          },
          "unsubscribed_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time",
                "description": "När personen lämnade listan.",
                "example": "2026-10-19T08:30:00.000Z"
              },
              {
                "type": "null"
              }
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "När medlemskapet skapades.",
            "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": "En kontakts medlemskap i en lista.",
        "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: ett bekräftelsemejl har skickats (eller skickades nyss) och personen kommer med när hen bekräftar."
          },
          "confirmation_sent": {
            "type": "boolean",
            "description": "Ett bekräftelsemejl skickades nu."
          },
          "created_contact": {
            "type": "boolean",
            "description": "Kontakten fanns inte och skapades."
          }
        },
        "required": [
          "list_id",
          "contact_id",
          "status",
          "confirmation_sent",
          "created_contact"
        ],
        "additionalProperties": false,
        "description": "Resultatet av en anmälan till en lista.",
        "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": "Kontaktfält."
      },
      "Field": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string",
            "description": "Nyckeln i fields på en kontakt, och i kopplingsfält som {{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": "Alternativen för ett fält av typen select."
          },
          "required": {
            "type": "boolean",
            "description": "Måste anges när en kontakt skapas."
          },
          "sensitive": {
            "type": "boolean",
            "description": "Känsligt fält (personnummer): kan varken läsas eller skrivas via API:t."
          },
          "inherited": {
            "type": "boolean",
            "description": "Fältet kommer från en nivå ovanför i organisationen."
          }
        },
        "required": [
          "key",
          "label",
          "type",
          "options",
          "required",
          "sensitive",
          "inherited"
        ],
        "additionalProperties": false,
        "description": "Ett eget kontaktfält.",
        "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": "Distributionslistor."
      },
      "Segment": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "matching": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991,
            "description": "Kontakter som matchar villkoren just nu (inte raderade)."
          },
          "active": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991,
            "description": "Av dem: aktiva."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "När listan skapades.",
            "example": "2026-10-19T08:30:00.000Z"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "När villkoren senast ändrades.",
            "example": "2026-10-19T08:30:00.000Z"
          }
        },
        "required": [
          "id",
          "name",
          "description",
          "matching",
          "active",
          "created_at",
          "updated_at"
        ],
        "additionalProperties": false,
        "description": "En distributionslista: kontakter som uppfyller villkor.",
        "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": "Det finns fler: hämta nästa sida med cursor=next_cursor.",
            "example": false
          },
          "next_cursor": {
            "description": "Skicka som cursor för nästa sida. null på sista sidan.",
            "example": null,
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "data",
          "has_more",
          "next_cursor"
        ],
        "additionalProperties": false,
        "description": "En sida spärrade adresser."
      },
      "Suppression": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string"
          },
          "reason": {
            "type": "string",
            "description": "unsubscribed, bounced, complained, manual eller imported."
          },
          "detail": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "När adressen spärrades.",
            "example": "2026-10-19T08:30:00.000Z"
          },
          "contact_id": {
            "description": "Kontakten med adressen, om det finns en som nyckeln får se.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "email",
          "reason",
          "detail",
          "created_at",
          "contact_id"
        ],
        "additionalProperties": false,
        "description": "En adress som arbetsytan aldrig skickar till.",
        "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": "Butiker."
      },
      "Store": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Butikens 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": "Hur mycket butiken har skickat in."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "När butiken skapades.",
            "example": "2026-10-19T08:30:00.000Z"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "När butiken senast ändrades.",
            "example": "2026-10-19T08:30:00.000Z"
          }
        },
        "required": [
          "id",
          "name",
          "domain",
          "currency",
          "counts",
          "created_at",
          "updated_at"
        ],
        "additionalProperties": false,
        "description": "En webbutik i arbetsytan.",
        "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": "Det finns fler: hämta nästa sida med cursor=next_cursor.",
            "example": false
          },
          "next_cursor": {
            "description": "Skicka som cursor för nästa sida. null på sista sidan.",
            "example": null,
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "data",
          "has_more",
          "next_cursor"
        ],
        "additionalProperties": false,
        "description": "En sida kunder."
      },
      "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": "Arbetsytans kontakt med samma adress, om det finns en. En kund blir aldrig en kontakt av sig själv.",
            "type": [
              "string",
              "null"
            ]
          },
          "orders_count": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991,
            "description": "Betalda ordrar."
          },
          "total_spent": {
            "type": "number",
            "description": "Summan av de betalda ordrarna."
          },
          "last_order_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time",
                "description": "Senaste betalda ordern.",
                "example": "2026-10-19T08:30:00.000Z"
              },
              {
                "type": "null"
              }
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "När kunden skickades in första gången.",
            "example": "2026-10-19T08:30:00.000Z"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "När kunden senast ändrades.",
            "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": "En kund i butiken – den som har handlat, med eller utan samtycke till utskick.",
        "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": "Det finns fler: hämta nästa sida med cursor=next_cursor.",
            "example": false
          },
          "next_cursor": {
            "description": "Skicka som cursor för nästa sida. null på sista sidan.",
            "example": null,
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "data",
          "has_more",
          "next_cursor"
        ],
        "additionalProperties": false,
        "description": "En sida produkter."
      },
      "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": "När produkten skickades in första gången.",
            "example": "2026-10-19T08:30:00.000Z"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "När produkten senast ändrades.",
            "example": "2026-10-19T08:30:00.000Z"
          }
        },
        "required": [
          "id",
          "title",
          "url",
          "image_url",
          "vendor",
          "product_type",
          "variants",
          "created_at",
          "updated_at"
        ],
        "additionalProperties": false,
        "description": "En produkt i butiken, med varianter.",
        "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": "Det finns fler: hämta nästa sida med cursor=next_cursor.",
            "example": false
          },
          "next_cursor": {
            "description": "Skicka som cursor för nästa sida. null på sista sidan.",
            "example": null,
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "data",
          "has_more",
          "next_cursor"
        ],
        "additionalProperties": false,
        "description": "En sida ordrar."
      },
      "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 när kunden har raderats: ordern räknas fortfarande till kampanjens intäkt."
          },
          "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": "När ordern lades.",
            "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": "När ordern skickades in första gången.",
            "example": "2026-10-19T08:30:00.000Z"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "När ordern senast ändrades.",
            "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": "En order i butiken.",
        "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": "Det finns fler: hämta nästa sida med cursor=next_cursor.",
            "example": false
          },
          "next_cursor": {
            "description": "Skicka som cursor för nästa sida. null på sista sidan.",
            "example": null,
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "data",
          "has_more",
          "next_cursor"
        ],
        "additionalProperties": false,
        "description": "En sida kundkorgar."
      },
      "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": "När korgen skickades in första gången.",
            "example": "2026-10-19T08:30:00.000Z"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "När korgen senast ändrades.",
            "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": "En öppen kundkorg.",
        "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": "Kampanjer med intäkt."
      },
      "CampaignRevenue": {
        "type": "object",
        "properties": {
          "campaign_id": {
            "type": "string"
          },
          "campaign_name": {
            "type": "string"
          },
          "started_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time",
                "description": "När kampanjen började skickas.",
                "example": "2026-10-19T08:30:00.000Z"
              },
              {
                "type": "null"
              }
            ]
          },
          "orders": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991,
            "description": "Betalda ordrar från kampanjen."
          },
          "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": "Intäkten per valuta."
          }
        },
        "required": [
          "campaign_id",
          "campaign_name",
          "started_at",
          "orders",
          "revenue"
        ],
        "additionalProperties": false,
        "description": "En kampanjs intäkt: de betalda ordrar som kom från dess länkar.",
        "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": "Operationens HTTP-status."
                },
                "body": {
                  "description": "Operationens svar: det vanliga svaret, ett fel (problem+json) eller 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": "Svaren i samma ordning som operationerna.",
        "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": "Varför webhooken stängdes av av sig själv (leveranserna misslyckades), eller null.",
            "type": [
              "string",
              "null"
            ]
          },
          "consecutive_failures": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991,
            "description": "Misslyckade leveransförsök i rad."
          },
          "last_success_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time",
                "description": "Senaste lyckade leveransen.",
                "example": "2026-10-19T08:30:00.000Z"
              },
              {
                "type": "null"
              }
            ]
          },
          "last_failure_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time",
                "description": "Senaste misslyckade försöket.",
                "example": "2026-10-19T08:30:00.000Z"
              },
              {
                "type": "null"
              }
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "När webhooken skapades.",
            "example": "2026-10-19T08:30:00.000Z"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "När webhooken senast ändrades.",
            "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": "En webhook: en adress som får arbetsytans händelser.",
        "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": "Varför webhooken stängdes av av sig själv (leveranserna misslyckades), eller null.",
            "type": [
              "string",
              "null"
            ]
          },
          "consecutive_failures": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991,
            "description": "Misslyckade leveransförsök i rad."
          },
          "last_success_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time",
                "description": "Senaste lyckade leveransen.",
                "example": "2026-10-19T08:30:00.000Z"
              },
              {
                "type": "null"
              }
            ]
          },
          "last_failure_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time",
                "description": "Senaste misslyckade försöket.",
                "example": "2026-10-19T08:30:00.000Z"
              },
              {
                "type": "null"
              }
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "När webhooken skapades.",
            "example": "2026-10-19T08:30:00.000Z"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "När webhooken senast ändrades.",
            "example": "2026-10-19T08:30:00.000Z"
          },
          "secret": {
            "type": "string",
            "description": "Hemligheten som leveranserna signeras med (Qrona-Signature). Visas bara nu – spara den hos mottagaren."
          }
        },
        "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": "Den nya webhooken, med hemligheten.",
        "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": "Det finns fler: hämta nästa sida med cursor=next_cursor.",
            "example": false
          },
          "next_cursor": {
            "description": "Skicka som cursor för nästa sida. null på sista sidan.",
            "example": null,
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "data",
          "has_more",
          "next_cursor"
        ],
        "additionalProperties": false,
        "description": "En sida leveranser."
      },
      "WebhookDelivery": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Leveransens id (headern Qrona-Delivery)."
          },
          "event_id": {
            "type": "string",
            "description": "Händelsens id (id i kroppen): samma i alla webhooks som får händelsen."
          },
          "type": {
            "type": "string",
            "description": "Händelsen, eller ping för ett test."
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "delivered",
              "failed"
            ],
            "description": "pending: väntar på (ett nytt) försök · delivered: mottagaren svarade 2xx · failed: gavs upp."
          },
          "attempts": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991
          },
          "response_status": {
            "anyOf": [
              {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ],
            "description": "Mottagarens HTTP-status vid senaste försöket."
          },
          "error": {
            "type": [
              "string",
              "null"
            ]
          },
          "next_attempt_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time",
                "description": "Nästa försök.",
                "example": "2026-10-19T08:30:00.000Z"
              },
              {
                "type": "null"
              }
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "När händelsen hände.",
            "example": "2026-10-19T08:30:00.000Z"
          },
          "delivered_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time",
                "description": "När den levererades.",
                "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": "En händelse till en 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": "Mottagaren svarade 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": "Resultatet av ett 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": "Meddelandets id."
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "sending",
              "sent",
              "delivered",
              "bounced",
              "complained",
              "failed",
              "suppressed"
            ],
            "description": "queued: väntar på ett nytt försök · sent: lämnat till utskickstjänsten · delivered: levererat · bounced: studsade · complained: skräppostanmälan · failed: kunde inte levereras · suppressed: skickades inte, se reason."
          },
          "reason": {
            "description": "Varför ett meddelande inte skickades: bounced, complained, manual, erased, unsubscribed (bara marketing), service_limit, monthly_cap eller payment.",
            "type": [
              "string",
              "null"
            ]
          },
          "template": {
            "type": "string"
          },
          "template_version": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991,
            "description": "Mallversionen meddelandet gjordes av. Publicerade versioner ändras aldrig."
          },
          "html_sha256": {
            "type": "string",
            "description": "SHA-256 av HTML:en mottagaren fick."
          },
          "category": {
            "type": "string",
            "enum": [
              "service",
              "marketing"
            ]
          },
          "reference": {
            "type": "string"
          },
          "client_ref": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "När meddelandet togs emot.",
            "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": "Ett meddelande till en mottagare.",
        "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": "Versionen som renderades: den senast publicerade, som ett meddelande skulle göras av nu."
          },
          "subject": {
            "type": "string",
            "description": "Ämnesraden, ifylld."
          },
          "html": {
            "type": "string",
            "description": "Meddelandet som HTML, precis som det skickas (länkarna till webbversion och avregistrering leder ingenstans i en förhandsvisning)."
          },
          "text": {
            "type": "string",
            "description": "Textversionen."
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Det som borde ses över, t.ex. en länk utan adress."
          }
        },
        "required": [
          "template",
          "template_version",
          "subject",
          "html",
          "text",
          "warnings"
        ],
        "additionalProperties": false,
        "description": "En Qrona-mall renderad med 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": []
        }
      }
    }
  }
}