Kartuu KYTH. Systems UG (haftungsbeschränkt)

Data Processing Agreement (DPA)

under Art. 28 GDPR – for the Shopify app Kartuu

This is an English translation. The legally binding version is the German one, the Vertrag über die Auftragsverarbeitung. This translation is provided for your convenience; where the two differ, the German version prevails.

Version 1.21
Date 6 October 2026
Consent record ID 1.27-2026-10-06
Applies to Kartuu, Shopify app, https://kartuu.kyth.systems
State of the software described 28 September 2026

Parties

Controller

The merchant who installs Kartuu in their Shopify shop. The merchant decides on the purposes and means of processing the data arising in their shop.

The merchant is identified towards the processor by two details, both of which are recorded when the contract is concluded under § 0:

  1. their myshopify domain – it identifies the shop unambiguously and comes from the session proof signed by Shopify, so it cannot be freely claimed;
  2. an email address as contact address, which the merchant enters themselves in the consent step (mandatory field, § 2a no. 4).

This makes it possible to keep a record of the controller's name and contact details within the meaning of Art. 30(2)(a) GDPR. KYTH does not itself collect the complete company details (company name, address, representation); they follow from the merchant's Shopify account and are requested through the contact address named above if needed.

Processor

KYTH. Systems UG (haftungsbeschränkt) Prof.-Mederer-Straße 4 92348 Berg Germany

Registered office Berg bei Neumarkt in der Oberpfalz
Register court Local Court (Amtsgericht) Nürnberg
Register number HRB 46313
Represented by Stefan Grasse and Stephan Wittmann, each with sole power of representation
Data protection contact datenschutz@kyth.systems
General contact hello@kyth.systems · +49 1575 1603446

Data protection officer: No data protection officer has been appointed. Under section 38 of the German Federal Data Protection Act (BDSG) there is no obligation to do so at the company's current size. The point of contact for data protection matters is datenschutz@kyth.systems; this is not a data protection officer within the meaning of Art. 37 GDPR.

Hereinafter “KYTH”.


§ 0 Conclusion of the contract

This contract is concluded when the merchant agrees to it in the app's installation process. The process is as follows:

  1. The merchant opens Kartuu in their Shopify admin and triggers the connection.
  2. If there is no consent for the current version, the app does not carry out the process but shows the consent step: references to this contract, to the privacy policy and to the terms of service, a field for the contact address (mandatory field) and a consent checkbox that is not pre-ticked.
  3. Only when the merchant has filled in both is the process carried out.

Without consent, nothing happens. Before consent, neither a record of the shop is created nor an access token obtained from Shopify. The check whether consent to the current version exists comes before every write access and before every call to Shopify.

One exception lies outside KYTH's influence. With the installation managed by Shopify, the app is already installed and the webhooks are already subscribed before the merchant opens the embedded page for the first time at all. If the merchant dismisses the consent step and uninstalls again, Shopify nevertheless sends app/uninstalled; if they sell something in the meantime, Shopify also sends orders/paid. KYTH receives these signed webhooks: the shop domain is converted into the search hash, looked up in the database and – if no shop belongs to it – noted in the application log for 14 days. No record of the shop is created in the process, and no voucher line either: without a shop record there is no tenant in which one could be created, and the content of the order is not evaluated further after the signature check. Only the technical webhook identifier is stored in the duplicate protection. This processing therefore takes place without a concluded contract, and for this reason it is listed as a case of its own in Annex 1 section A. The legal basis is Art. 6(1)(f) GDPR – legitimate interest in receiving, with a signature check, a webhook to which Shopify obliges us to subscribe, and in not silently swallowing an unknown shop –, additionally Art. 6(1)(c) GDPR insofar as receiving the data protection webhooks serves to fulfil the obligations under Art. 12 et seq. GDPR.

A separate signature is not required (Art. 28(9) GDPR expressly permits the electronic format).

0.2 Record

KYTH records the conclusion of the contract in the database – three details, either all or none:

Item Content
when time of consent, time-zone aware
which version the identifier of the text shown to the merchant, e.g. 1.12-2026-09-17
who the contact address given by the merchant, stored encrypted

The version identifier is set exclusively by the server; a value sent along by the browser has no effect.

The record outlasts an uninstallation. If the merchant reinstalls the app before the shop's data has been deleted – as a rule within 48 hours (§ 9.1) –, they do not have to consent again: their consent to exactly this version exists. The record disappears together with the deletion of the shop.

History: In addition to the most recently given consent on the shop row, the table zustimmungen records every consent given – append-only and without UPDATE: a record once written can no longer be changed. It is deleted together with the shop (§ 9). This keeps the record of an older consent when a version is increased. An entry carries the shop assignment, version identifier and time; it contains no personal detail.

0.3 Version in force and changes

The contract applies in the version whose identifier was recorded on consent. If KYTH changes the content of the text, KYTH increases the version identifier. Whoever installs the app afterwards agrees to the new version. For a merchant who agreed to an earlier version, it takes effect after the notice under the following paragraph, or KYTH asks them for consent again when they open the app. A mere correction of typing errors does not lead to a new identifier.

Independently of this, KYTH informs the merchant of a change to this contract at least 30 days before it takes effect in text form at the contact address stored under § 2a no. 4. If the merchant does not object within 30 days of receipt of the notice in text form, the new version is deemed accepted; if the merchant objects, either party can end the use of the app – the merchant by uninstalling.

KYTH sends this notice automatically from its own mailbox and records on the shop row which version it announced when (Annex 1 A).

0.4 Publication

The app delivers all three documents at https://kartuu.kyth.systems/rechtliches/ (/rechtliches/auftragsverarbeitung, /rechtliches/datenschutz and /rechtliches/nutzungsvertrag), without login and from the same source from which the version identifier comes. Independently of this, KYTH provides them on request sent to datenschutz@kyth.systems.


§ 1 Subject matter, duration, nature and purpose of the processing

1.1 Subject matter

KYTH provides the merchant with the Shopify app Kartuu. Kartuu is intended to generate and deliver personalised gift vouchers as PDFs from orders in the merchant's shop.

The following has been implemented:

  1. Designing the voucher card in the admin: the merchant designs the card, types in sample details and receives a preview and a PDF back. The sample details are not stored; a design is stored only if the merchant saves it as a draft.
  2. Setting up the voucher product in the merchant's shop, on the merchant's click.
  3. The card preview on the product page, if the merchant places the Kartuu block there (Annex 1 section B).
  4. The order process: Kartuu is subscribed to the orders/paid webhook. From a paid order with a voucher line item, one row per item purchased is created in the database – with the details the customer entered in the order form (recipient's name, recipient's email address, sender's name, greeting, desired delivery date), with the buyer's Shopify customer number and with a voucher code generated by Kartuu. For a value voucher, Kartuu uses it to create a real Shopify gift card through the Admin API. The card is then rendered. Only a line item whose product the merchant has set up in Kartuu as a voucher product counts as a voucher line item. If other products carry Kartuu details, the row is created in the state “Check product” – without a code, without a gift card and without a claim link – until the merchant releases or discards it in the order overview. Immediately before a voucher is issued, Kartuu queries the order's cancellation and payment status from Shopify; if it has been cancelled, fully refunded or the payment voided, no voucher is created.
  5. The Kartuu block on the thank-you and order status page, if the merchant places it: it shows the buyer the status of their vouchers and, after a successful check, the claim links (Annex 1 section B).

Delivery has been implemented – through THE MERCHANT'S mail server. The merchant enters their own SMTP account in the app under “Settings”; Kartuu hands in the email through this account. It carries the rendered PDF as an attachment and a claim link. If the buyer has chosen a preferred date, Kartuu holds the email back until then; the merchant can bring it forward in the order overview with “Send now”. If the merchant enters nothing, Kartuu sends nothing for them: the voucher is generated, can be retrieved and downloaded, and the merchant hands it over themselves.

KYTH is not a processor at this point. The email to the recipient does not go through a sending route of KYTH's and not through a sub-processor of KYTH's, but through the mail provider the merchant has chosen and engaged themselves. Kartuu has no mail account of its own or shared mail account through which vouchers for all merchants would go out. KYTH's own mailbox carries only KYTH's notices to the merchant themselves (§ 2a no. 4) and never a voucher.

The rendered PDF is not stored; it is created anew with every delivery. What Kartuu actually processes today is listed exhaustively in Annex 1.

Pictures. The merchant can upload pictures – their logo, their product photo – so that a card template can draw them. These pictures are kept permanently: the bytes in the image storage (§ 3.4), the details about them (key, type, dimensions, size, checksum) in a database table. Annex 1 section A lists them with purpose, legal basis and deletion; the check on upload is set out in Annex 2 section 2.6.

If the range of functions is extended, this contract is adapted and presented to the merchant in the new version (§ 0.3).

1.2 Nature of the processing

Collection, recording, storage, use, retrieval, encryption, transmission to the group of recipients named in § 6, erasure and restriction of processing – in each case to the extent of Annex 1.

1.3 Purpose of the processing

Exclusively:

  1. Installation and operation of the app in the merchant's shop: assigning the shop, obtaining and renewing the Shopify access tokens, authenticating calls from the embedded interface.
  2. Fulfilling the data protection webhooks required by Shopify (access, erasure of a person, erasure of a shop).
  3. Evidence of access to protected customer data (access log for protected customer data): a condition of Shopify's approval for protected customer data and our own accountability under Art. 5(2) GDPR. Art. 5(2) GDPR is the purpose here, not the legal basis; for the legal basis, see section 5.1 of the privacy policy.
  4. Determining the subscription status of the merchant's shop at Shopify and enforcing it at three points: setting up the voucher product, the proof, and the delivery lock – without an active subscription, automatic sending stops and the finished vouchers wait until a plan is running again. The plan “Kartuu Free” counts like a missing subscription as long as the merchant has not consented to a version from consent record ID 1.27-2026-10-06 on (§ 6.4). The generation of a paid voucher is expressly not locked: the gift card is created, and the merchant can download the card and hand it over themselves. The plans are managed by Shopify; KYTH reads there whether an active subscription exists, what the plan is called, whether it is a test subscription and until when the current billing period runs. The first three details are cached; the end of the billing period is only displayed. With the same query, KYTH reads Shopify's identifier of the shop. It is not stored and is needed only for the report under § 6.4.
  5. Generating the voucher card as a preview and as a PDF from details the merchant enters in the admin themselves – without storing the sample details and without access to the shop's order or customer data; only drafts the merchant expressly saves are stored.
  6. Keeping the pictures uploaded by the merchant, so that a card template can draw them.
  7. Setting up the voucher product in the merchant's shop on the merchant's click, and recording which product it is. Without this detail, a voucher order arriving through an express checkout could not be recognised as such.
  8. Handling a paid voucher order in these steps: a) receiving the paid order and creating one record per item purchased; b) taking over the customer's details about the recipient and storing them encrypted; c) for a value voucher, generating a voucher code, storing it encrypted and using it to create a gift card at Shopify; d) rendering the card and noting the process as completed; e) delivering the finished voucher, namely through the merchant's mail account (§ 1.1). If the merchant has not entered one, nothing is delivered – the voucher remains retrievable and downloadable, and the merchant hands it over themselves; f) showing the buyer the status and the claim links of their vouchers in the Kartuu block.
  9. Card preview on the shop's product page, without storage.
  10. Operational diagnostics and security to the very narrow extent described in Annex 1.

There is no processing of the data under this contract for KYTH's own purposes – in particular for advertising, profiling, resale, training models or evaluation across merchants. Separately, KYTH, as a controller in its own right, attributes the installation of the app to an advertisement if the merchant consented to this on kyth.systems (privacy policy section 5.7). Only identifiers from the merchant's browser are processed for this, no data from the shop and no data of the customers.

1.4 Duration

Processing begins with consent under § 0 and the subsequent connection of the app. The contract runs for an indefinite period as long as the app is installed.

The contract ends, without the need for termination, with the uninstallation of the app. For data still present at that time, the obligations of this contract continue to apply until it is deleted under § 9.

Maximum duration. The data remaining in the database is deleted at the latest 30 days after uninstallation – as a rule earlier, namely with the shop/redact webhook, which Shopify as a rule sends 48 hours after uninstallation. If this webhook does not arrive, the clean-up run under § 9.3 no. 1 applies. Deleted data continues to exist in the backups until the periods there expire (§ 9.3 no. 2).


§ 2 Type of personal data and categories of data subjects

2.1 Categories of data subjects

Category Current state
Merchants and the people acting for them in the Shopify admin affected – through the shop domain, the short-lived session token and the contact address given in the consent step. The latter is typically the address of a natural person and is therefore stored encrypted. In passing, also the name Shopify holds as the owner of the shop: KYTH reads it for the salutation of the setup email and does not store it (§ 2a no. 4, Annex 1 section B)
The merchant's end customers (buyers) affected, with storage: if a customer buys a voucher, their name and email address are stored encrypted in the voucher row – the merchant sees both in the detail view of their own order, not in the list of orders. In addition, their Shopify customer number is stored in the voucher row – in plain text, because it is the search key of the two data protection webhooks. For a guest purchase it is missing; the person is then found through a non-reversible search value of their address, stored next to the ciphertext. The customer number is not transmitted to Shopify: the call to create the gift card carries exclusively the voucher code, the face value with the currency of the purchase, the expiry date if the merchant has set an expiry period in Shopify, and a note for assignment (§ 3.4). In passing, there are also the customer number from the data protection webhooks and, if the buyer uses the Kartuu block on the thank-you or order status page, their session token and, where applicable, the email address entered there (Annex 1 section B)
Recipients of vouchers affected, with storage, and in two roles at once. As a data subject: recipient's name, email address and the greeting addressed to them are taken over from the order and stored encrypted; they can be found through a non-reversible search value of the address. As the recipient of the voucher: this is precisely why the address is collected – the card is delivered to them through the merchant's mail account and carries the greeting and sender's name (§ 1.1). If the merchant has not entered an account, nothing is delivered and the merchant hands over the card themselves. The recipient did not order, therefore has no customer number, and Shopify does not know them – the consequence for their data subject rights is set out in § 7.2
Givers affected, with storage, insofar as a sender's name was given: encrypted in the same row. The giver is typically, but not necessarily, the buyer
People who can be seen in an uploaded picture or appear in its metadata affected, and here with storage. What an uploaded picture shows is decided by the merchant alone; KYTH does not look through it and does not evaluate it. In a picture from a mobile phone, the embedded capture data (EXIF) can contain, among other things, the time of capture, the device and the location. Kartuu removes this data from every picture on upload; only the orientation is kept (§ 2.2). If the picture belongs to the design of a voucher product, any person who opens that product page with the card preview can retrieve the image file (Annex 1 section B); it carries no capture data (Annex 2 section 2.6)

2.2 Type of data

Listed exhaustively in Annex 1. In brief:

On pictures: What an uploaded picture shows and which capture data it contains is determined by the merchant. A picture can show people, and the embedded capture data (EXIF) of a mobile phone can carry a location. KYTH checks the picture for format, dimensions and harmlessness (Annex 2 section 2.6) and does not evaluate its content.

The capture data is dropped on upload, from every picture. If the longer edge measures more than 2000 pixels, the picture is scaled down to this edge and re-encoded in the process; the orientation is applied to the pixels. If the picture is smaller, Kartuu only discards the parts of the file that contain capture data and does not re-encode – the pixels remain unchanged, and the orientation remains as the only detail, so that a photo taken upright does not lie on its side. Time of capture, device and location are dropped completely in both cases. Pictures uploaded before 23 September 2026 have been cleaned in the same way.

Who can retrieve a picture. There is no generally readable address of the image storage. The merchant receives their pictures in the admin after their session has been checked. Outside of it, a picture is delivered only through a signed address that is bound to the shop and the key and becomes invalid after one to two hours: in the preview in the admin and – if picture or logo belong to the design of a voucher product – to any person who opens that product page with the card preview. That person can download the image file as it is stored – without capture data. What a merchant chooses to load into a picture is their responsibility.

2.3 Permissions granted and their use

This section separates two things: what KYTH may do and what KYTH does.

What the merchant grants. The following are requested in the Shopify app configuration:

Permission Purpose Use
read_orders recognising voucher orders and reading the details the customer provides as additional details on the line item used – through the orders/paid webhook. read_all_orders is expressly not requested
write_gift_cards creating the value voucher as a real Shopify gift card, with a code generated by Kartuu used, for every value voucher. For creating and for deactivating: if the merchant cancels an order or fully refunds a voucher line item, the associated gift card is deactivated through the Admin API; after a partial refund and for a card already partly used, only when the merchant chooses so in the order overview. Only the card's identifier is transmitted. The app reads the balance at the merchant's request and displays it; it is not stored
write_products creating the voucher product in the merchant's shop: product, one option, one variant per amount or service, and the metafields by which the order process recognises the voucher line items used, but only on a click by the merchant. Nothing is created on installation and nothing in the background. An existing product is not changed and none is deleted; if the merchant changes title, price or pictures, it stays that way. write_publications is expressly not requested – whether the product becomes visible in the online store is for the merchant to decide
write_merchant_managed_fulfillment_orders reporting the voucher line item of a paid order as fulfilled as soon as the voucher has been released – the merchant should not have to tick off the order manually used, on every release. The identifier of the fulfillment order and the lines with quantities are transmitted (§ 3.4); Kartuu expressly does not trigger a notification to the customer. Other line items of the same order remain unaffected
protected customer data field name recipient's name and giver's name are printed on the voucher used – the names come from the line item and are stored encrypted
protected customer data field email the finished voucher is to be delivered as a PDF to the recipient; the buyer's email address serves for matching in the Kartuu block used. The recipient's email address is received, stored encrypted and stored as a search value; the buyer's email address is stored encrypted. Delivery is through the mail account entered by the merchant; without an account entered, nothing is delivered

What KYTH still does not do. Kartuu does not query any customer data field through the Admin API – no address, no phone number, no payment data. The personal order data comes exclusively from the webhook Shopify delivers. An order is indeed queried, but only as to its state: on release, Kartuu queries the fulfillment orders and the open quantities for the order from which the voucher comes, in order to report the voucher line item as fulfilled. The order identifier is transmitted; back come identifiers, states and quantities – no customer data field. Immediately before a voucher is issued, Kartuu also asks whether the order has been cancelled and what its payment status is; again only the order identifier is transmitted. The complete list of the twenty-seven calls to the Admin API is in § 3.4.

Origin of the data. Personal data reaches Kartuu by these routes:

  1. From the merchant's shop – through the order webhook. This data is stored (Annex 1 section A). For it, the merchant is the controller and KYTH the processor; the instruction for it is this contract together with setting up the voucher product.
  2. From the merchant's input when designing – sample details are not stored (Annex 1 section B); saved drafts are stored (Annex 1 section A).
  3. From an upload by the merchant – the pictures are stored (Annex 1 section A).
  4. From the browser of the buyer or visitor – through the Kartuu block and the card preview in the shop. These details are not stored (Annex 1 section B).

If this changes. Before every extension that changes the range of data processed, this contract is presented in a new version and the version identifier increased – it takes effect for the merchant under § 0.3 (§ 11 no. 6).

2.4 Special categories of data

Special categories of data under Art. 9 GDPR and data under Art. 10 GDPR are not the subject of the processing. KYTH will not request them in future either.


§ 2a Obligations and rights of the controller

Art. 28(3), first sentence, GDPR requires that a data processing agreement also sets out the obligations and rights of the controller. This is done here.

  1. Lawfulness of processing. The merchant alone is responsible for ensuring that the processing they instruct is lawful and that there is a legal basis under Art. 6 GDPR. They decide on purposes and means. KYTH does not and cannot check the legal basis.
  2. Information obligations. The information obligations under Art. 13 and Art. 14 GDPR towards the merchant's customers and towards recipients lie with the merchant. Recipients typically do not provide their data themselves; the giver provides it – for this, Art. 14 GDPR applies.
  3. Instructions. The merchant is entitled and obliged to give instructions under § 3; their instructions must be lawful. They name to KYTH the people authorised to give instructions on their behalf and keep this information up to date. If they name no one, the merchant's bodies authorised to represent it are deemed authorised to give instructions.
  4. Contact address. In the consent step under § 0, the merchant gives an email address at which KYTH can reach them. The information is mandatory; without it, the app is not connected. The notices under § 0.3, § 6.6 and § 8.2 go to this address. If the merchant has set up a mail account, Kartuu also sends a note to this address through that account at most once a day when orders need their attention; the note names only counts and a link into the app, no names, addresses, codes or amounts. In addition, once after installation, KYTH sends them the setup email with the steps still missing before the first voucher sale – only if they have chosen a plan and a step is still missing, without advertising, and through KYTH's own mailbox at INWX GmbH, not through the merchant's mail account; exactly when is stated in the privacy policy (5.3). For the salutation, KYTH reads the name Shopify holds as the owner of the shop (§ 3.4) and takes the first name from it; it does not appear in the database or in the log (on bounces, Annex 1 B). The merchant keeps the address up to date and notifies a change in text form to datenschutz@kyth.systems. In the app it can be changed in the consent step: when the version of these texts increases, Kartuu asks again and shows the stored address for editing; the value entered is stored. There is no separate screen for it. If the address becomes undeliverable, KYTH can no longer reach the merchant directly – not even in the event of a personal data breach, for whose notification the merchant has only 72 hours under Art. 33(1) GDPR. Keeping it up to date is therefore in their own interest.
  5. Evidence and audits. The merchant has the rights to evidence and audits under § 10.
  6. Notification of data breaches. Notifying the supervisory authority of a personal data breach (Art. 33 GDPR) and informing the data subjects (Art. 34 GDPR) are the merchant's responsibility. KYTH supports them in this under § 8.2.
  7. Own review. Before processing begins and regularly thereafter, the merchant satisfies themselves of the technical and organisational measures under Annex 2. Annex 2 expressly names the known gaps in section 7.

On handling the contact address. KYTH stores it encrypted, uses it exclusively for the notices, notes and the setup email named in number 4 and for forwarding requests from data subjects under § 7.1, does not pass it on and does not use it for advertising. It is deleted together with the shop row (§ 9).


§ 3 Processing only on documented instructions

3.1 Principle

KYTH processes personal data exclusively on documented instructions from the merchant. This also applies to transfers to a third country.

3.2 What counts as an instruction

Instructions are:

  1. this contract including its annexes – it is the basic declaration of instructions; consent under § 0 is the giving of this basic declaration,
  2. the installation of the app and the granting of permissions in the Shopify admin,
  3. settings and actions of the merchant in the app – in particular uploading a picture, saving a draft, setting up the voucher product, entering the mail account, choosing the language, changing or completing card details and releasing a voucher. Sample details for a preview apply only to that one rendering run and are not stored,
  4. individual instructions in text form to datenschutz@kyth.systems.

The merchant confirms instructions given orally without delay in text form. KYTH documents individual instructions and keeps them for the duration of the contract.

3.3 Limits of instructions

KYTH informs the merchant without delay if, in KYTH's opinion, an instruction infringes the GDPR or other data protection provisions. KYTH may suspend the execution of such an instruction until the merchant confirms or changes it.

If KYTH is legally obliged to carry out processing, KYTH informs the merchant of the legal requirement before processing, unless the law prohibits such information on important grounds of public interest.

3.4 Place of processing and third-country transfers

Processing by KYTH itself takes place in Germany: application and database run on a single virtual server at IONOS SE at the Berlin location. The daily database backups are stored in IONOS's object storage in the region eu-central-3, also Berlin. The pictures uploaded by the merchant are stored on the server itself – in a file storage on a persistent storage medium. See § 6.3. There is no other processing environment. The object storage does not create any third-country reference.

Transfers to parties outside KYTH arise exclusively from the group named in § 6:

Call What is transmitted
Query of the subscription status nothing but the token – the query carries no details. Besides the subscription status, Shopify's identifier of the shop comes back (§ 2.3 no. 4); it is not stored
Query of the shop name nothing but the token. What comes back is the name of the shop as stored at Shopify – a detail about a business and not about a person. It is shown to the merchant as a suggestion for the field “Name on the card” and stored only if they confirm it. When building the setup email (§ 2a no. 4), KYTH queries the name a second time and names the shop that way in the email; it is not stored in that case either
Query of the owner's name, before the setup email is created nothing but the token. What comes back is the name Shopify holds as the owner of the shop – unlike the shop name, a detail about a person. KYTH takes only the first name from it for the salutation of the setup email (§ 2a no. 4), at the moment the email is created; it is neither stored nor logged. This is KYTH's own processing as a contracting party and not processing on the merchant's behalf
Query of the shop's country at the first consent nothing but the token. What comes back is only the country code of the shop's billing address (for example “US”), not the address itself – for a sole trader it would carry street, town and their name. KYTH then sets the language and paper of the cards: English on US Letter in the United States and Canada, German in Germany, Austria, Switzerland and Liechtenstein, otherwise English, each on A4. Only this setting is stored, and the merchant can change it at any time; KYTH neither stores nor logs the country code itself. For shops in the United States and Canada, however, the stored setting (“English (US)”) reveals the country. Consenting again to a new version does not ask again. This is KYTH's own processing as a contracting party and not processing on the merchant's behalf
Query of the expiry period for gift cards nothing but the token. What comes back is the period the merchant has set in Shopify under Settings → Payments → Gift card expiration date (such as three years), or that gift cards do not expire – no personal data. Of this, only the expiry date calculated from it is stored on the individual voucher
Creating a gift card the voucher code, the face value with the currency of the purchase, the expiry date if the merchant has set an expiry period in Shopify, and a note for assignment – and expressly not the buyer's Shopify customer number. The note contains no personal data: who receives the voucher is stored in the encrypted column at KYTH and not in a free-text field at Shopify
Deactivating a gift card on cancellation only the card's identifier, no customer details. Kartuu queries the balance beforehand with its own call further below. The call is made from the cancellation path or – after a partial refund or for a partly used card – at the push of the merchant's button in the order overview, and it is final – Shopify cannot re-activate a deactivated card
Checking whether the product handle already exists in the shop the handle and the names of two metafields
Checking whether a stored product ID still exists the product ID
Query of title, status and main image of a voucher product for the list in the admin the product ID. What comes back is the title, status, the address of the main image and, per variant, whether Shopify charges tax on sale – details about goods, not about people. None of it is stored
Creating the voucher product product title, description, options, variants with prices and the metafields – details about goods, not about people
Updating the two inventory fields of a variant product and variant ID
Query of the variant identifiers of a voucher product before its tax liability is switched the product ID. What comes back are the identifiers of the variants – no personal data. None of it is stored
Switching the tax liability on sale, at the push of the merchant's button product and variant IDs and a yes or no per variant
Query of the variants of a value voucher and the price lists of the shop's markets the product ID. What comes back are variants with prices and option values as well as the price lists with their currency – details about goods, not about people. None of it is stored
Setting fixed prices for a value voucher in a price list (a voucher for 25 costs exactly 25 in euros, dollars, francs and pounds) identifier of the price list, variant IDs, amounts and currency
Renaming the option values of a value voucher (“25” instead of “€25.00”) product, option and value identifiers and the new option values
Query of the balance of a gift card the identifiers of the cards of an order – on cancellation those of the cards affected, before they are deactivated, and for the export under “Export” the identifiers of all value vouchers of the shop, in batches. What comes back is the balance, the initial value and whether the card is still valid – no code, no personal data. The value is passed through and not stored
Query of the state of the order on release the order identifier. What comes back are fulfillment orders, states and open quantities – no customer data field
Query of the cancellation and payment status of an order, immediately before a voucher is issued the order identifier. What comes back is whether the order has been cancelled and its payment status (such as paid or refunded) – no customer data field. If it has been cancelled, fully refunded or the payment voided, no voucher is created. None of it is stored
Reporting the voucher line item as fulfilled (fulfilling the order) the identifier of the fulfillment order and the lines with quantities. A notification to the customer is expressly not triggered
Requesting an upload target for the product image file name, MIME type and size of the image – no image data yet
Transferring the product image to Shopify's storage the bytes of a PNG: the whole voucher card as the buyer is to see it in the shop, filled with made-up sample details – a sample name, a sample amount, a code beginning with “MUSTER” and a sample greeting. It carries the shop's display name, its logo and the picture chosen by the merchant – no details of a real person and no valid code
Attaching the product image to the voucher product product ID, the identifier of the uploaded file and an alt text
Query of the product's media status the product ID. What comes back are the identifiers and states of the attached images
Detaching surplus product images product ID and the identifiers of the images to be removed
Query of the identifier of the app installation nothing but the token. What comes back is the identifier under which Kartuu is installed in the shop
Setting the delivery flag on the app installation only a yes or no: whether the merchant has set up email sending – no mail server, no address, no credentials. The Kartuu block in the shop shows the fields for the recipient's email address and the preferred date only if sending has been set up

Order and customer data are not queried through the Admin API; they arrive incoming through the orders/paid webhook that Shopify delivers. Shopify is at the same time the platform on which the merchant's shop is operated anyway; the merchant maintains their own contractual relationship with Shopify for this. The contracting party for merchants in the European Economic Area is as a rule Shopify International Ltd., based in Ireland; processing by affiliated companies outside the EEA, in particular Shopify Inc. in Canada, cannot be ruled out.

Instruction. By concluding this contract, the merchant instructs KYTH to call the token endpoint and the Admin API of their own shop at Shopify and to receive the incoming webhooks from Shopify, also insofar as a transfer to Shopify entities outside the EEA takes place in the process (Art. 28(3)(a) GDPR). Without this data flow, the app cannot be operated.

Canada. For Canada there is an adequacy decision of the European Commission (Decision 2002/2/EC) for private-sector organisations subject to the Canadian data protection law PIPEDA.

Other third countries, in particular the USA: standard contractual clauses. Shopify incorporates the EU standard contractual clauses into its Data Processing Addendum in the version of 7 July 2026 – the clauses from Commission Implementing Decision (EU) 2021/914 of 4 June 2021. Transfers to Shopify entities outside the European Economic Area, including entities in the USA, are based on them. The addendum is publicly available at https://www.shopify.com/legal/dpa; the merchant receives a copy of the clauses on request to datenschutz@kyth.systems (Art. 13(1)(f) GDPR). The same basis is set out in section 8 of the privacy policy.

No other transfers of data under this contract to third countries take place. In particular, the backups are stored in Germany (§ 6.3).


§ 4 Confidentiality of the people engaged

KYTH engages for processing only people who have committed themselves to confidentiality or are under an appropriate statutory obligation of confidentiality (Art. 28(3)(b) GDPR). The obligation continues beyond the end of their activity.

KYTH ensures that these people process personal data exclusively on the merchant's instructions and are familiar with the data protection requirements relevant to them.

The group of people with access. Access to the production environment – server, Coolify, database and the Shopify Partner Dashboard – is limited exclusively to KYTH's two managing directors, Stefan Grasse and Stephan Wittmann.

Beyond this, no one has access. There are no employees, no freelancers and no service providers with access to the production environment. The sub-processors under § 6.3 are not affected by this: they provide infrastructure and have no access to the application.

Confidentiality. Art. 28(3)(b) GDPR requires a commitment to confidentiality or an appropriate statutory obligation of confidentiality. For the managing directors, the obligation of confidentiality follows from their fiduciary duty as officers (section 43 of the German Limited Liability Companies Act, GmbHG; for the UG via section 5a(1) GmbHG). If a further person is given access, they are committed to confidentiality in writing beforehand.


§ 5 Technical and organisational measures (Art. 32 GDPR)

KYTH takes the technical and organisational measures described in Annex 2. Annex 2 contains only measures that have been implemented and names the known gaps in a section of its own.

The measures are subject to technical progress. KYTH may adapt them as long as the level of protection is not undercut. Significant changes are documented and communicated to the merchant on request.

KYTH holds no data protection or security certification (neither ISO/IEC 27001 nor SOC 2 nor a certification under Art. 42 GDPR) and does not claim any. Annex 2 is a self-assessment, not an audit report.


§ 6 Sub-processors

By concluding this contract, the merchant consents to the engagement of the sub-processors named under 6.3 (general written authorisation under Art. 28(2), second sentence, GDPR).

6.2 Conditions

KYTH contractually binds every sub-processor to data protection obligations corresponding to the obligations under this contract, in particular to sufficient guarantees under Art. 28(4) GDPR. If the sub-processor fails to fulfil its data protection obligations, KYTH is liable to the merchant for its compliance in accordance with Art. 28(4), second sentence, GDPR.

With IONOS, IONOS's data processing agreement applies (see below).

6.3 List of sub-processors

Company Registered office / place of processing Purpose Which data
IONOS SE Elgendorfer Straße 57, 56410 Montabaur, Germany (Local Court Montabaur, HRB 24498); place of processing: data centre Berlin hosting: a virtual server (VPS), on it the application containers, the PostgreSQL databases for test and production operation, and the file storage of the uploaded pictures on a persistent storage medium all data designated as stored in Annex 1, and the application logs
IONOS Cloud GmbH (object storage) Elgendorfer Straße 57, 56410 Montabaur, Germany (Local Court Montabaur, HRB 31110); place of processing: region eu-central-3, data centre Berlin; endpoint s3.eu-central-3.ionoscloud.com storage of the daily database backups in the bucket kaspar-kyth-db-backup-worm (with Object Lock); backups up to 4 August 2026 remain in the predecessor bucket kaspar-kyth-db-backup until their period expires the complete database backup, i.e. all data designated as stored in Annex 1 in the state in which it is in the database – the field-level encrypted values encrypted; periods in § 9.3 no. 2

On the contracts under Art. 28(4) GDPR:

IONOS. IONOS's “Agreement on processing on behalf under Art. 28(3) GDPR” (“Vereinbarung zur Auftragsverarbeitung nach Art. 28 Abs. 3 DSGVO”), version 1.2, as of 06/2023, applies, publicly available at https://www.ionos.de/terms-gtc/avv/. KYTH keeps a copy in its contract documents. Under its § 1.1 it covers “all activities that the contractor performs to fulfil the order and that constitute processing on behalf”, and thus covers server and object storage insofar as both are obtained under the same main contract.

The object storage is provided by IONOS Cloud GmbH (Local Court Montabaur, HRB 31110); the provider identification of the service at s3.eu-central-3.ionoscloud.com names it. Server, database and backups run at IONOS SE (HRB 24498). Both can be reached at the same address; which company is the contracting party in a given case follows from the respective contract.

Shopify is not a sub-processor, but the merchant's own processor; see 6.4.

6.4 Further recipients who are not sub-processors

For the sake of completeness, because there is a data flow or involvement:

What actually flows: platform: obtaining and renewing the access tokens through the shop's token endpoint; twenty-seven calls to the shop's Admin API (§ 3.4); transferring the product image; setting the delivery flag (§ 3.4); delivery of the incoming webhooks to Kartuu, including the paid orders; forwarding of requests from the shop to Kartuu (card preview on the product page, Kartuu block on the thank-you and order status page); management and billing of the app plans

Which data: the app's credentials, session token or refresh token, access token, shop domain, the voucher code, the face value and, where applicable, the expiry date when a gift card is created, the details of the voucher product, the product image and the delivery flag (whether email sending has been set up, yes or no). The buyer's customer number is not included. Recipient's name, recipient's email address and greeting do not go back to Shopify; they come from there and remain encrypted at KYTH

Classification. Sub-processing presupposes that KYTH engages the service provider. Here the merchant has engaged Shopify – Shopify runs their shop. When Kartuu creates a gift card through the Admin API, it writes data into the merchant's shop, and Shopify processes it there as the merchant's processor, under the merchant's own contract.

This is evidenced in two places:

Billing of the app plans is to be seen separately. There, KYTH is itself Shopify's customer; this is a contractual relationship of KYTH's own and not processing on the merchant's behalf. If the merchant is on the plan “Kartuu Free”, KYTH reports to Shopify, for this billing, the value of each voucher issued and, for each cancellation, the value back. Transmitted are Shopify's identifier of the shop, the time, an identifier of the report and the value in US dollars. Not transmitted are details about buyers or recipients, and no voucher code. Reports are made only for shops that have consented from consent record ID 1.27-2026-10-06 on. The same applies to the Partner API, which Shopify provides to KYTH as the app's developer: through it, KYTH learns that, and for what reason, a shop has uninstalled Kartuu (Annex 1 section A), and, for shops on the plan “Kartuu Free”, once a day which total Shopify keeps for the current billing period; KYTH compares it with its own reports. KYTH's own access goes there and, for this comparison, Shopify's identifier of the shop. If the totals differ, KYTH receives a notice with the internal identifier of the shop and the two totals.

The situation is different for KYTH's company website at kyth.systems and www.kyth.systems: these names run in proxy mode, and there Cloudflare processes connection data. This does not concern Kartuu and is the subject of the privacy policy of that website, not of this contract.

Switching the app to proxy mode would make Cloudflare a sub-processor; it will only be done after the list under 6.3 has been supplemented and the merchant informed under 6.6. - GitHub, Inc. (San Francisco, USA; a subsidiary of Microsoft Corporation) – private source code repository and deployment keys. GitHub processes no merchant, customer or voucher data. Access secrets are stored exclusively in the deployment environment and are excluded from the repository and the container image. - cdn.shopify.com – the embedded interface loads Shopify's “App Bridge” library directly from the Shopify CDN. This request is made from the merchant's browser, not from KYTH's server. The connection data of the merchant's browser (IP address, browser identifier) and the origin are transmitted. No customer, order or voucher data and no token are transmitted; the only attribute given is the public application identifier. The origin is limited to https://kartuu.kyth.systems by the policy Referrer-Policy: strict-origin-when-cross-origin, so the ?shop= parameter is not transmitted. The recipient is Shopify – the same party that delivers the surrounding admin interface. No additional group of recipients arises as a result.

6.5 Expressly not involved

Searched for and not present: no email delivery service – the voucher emails go through the merchant's mail account, KYTH's own notices through KYTH's mailbox (§ 6.4) –, no external font or icon service, no analytics or tag service, no external error-tracking service. The only HTTP library in the application code is used in seven places: two address the merchant's shop – the token endpoint and the Admin API –, the third uploads the product image to the storage location Shopify names for it (§ 3.4), the fourth reports an installation to Meta – without data under this contract (§ 3.4). Three more serve to bill the plan “Kartuu Free”: the fifth obtains KYTH's access at Shopify, the sixth reports voucher values there (§ 6.4), the seventh retrieves the reference rates of the European Central Bank (§ 3.4). In addition, the application connects via SMTP to the mail server the merchant has entered (§ 3.4, § 6.4).

Object storage is used exclusively at IONOS for the database backups (6.3). The application does not talk to it; the transfer there is handled by a separate backup script on the server, which encrypts the dump before it leaves the server (§ 9.3 no. 2).

Nor does the application talk to KYTH's mailbox at INWX GmbH: it only builds the setup email and the announcement under § 0.3; they are sent by scripts on the server (§ 3.4). The application holds no credentials for it.

6.6 Changes and right to object

KYTH informs the merchant of the intended engagement of a further sub-processor or the replacement of an existing one at least 30 days in advance in text form at the contact address stored by the merchant under § 2a no. 4. If this address has become undeliverable, the information is additionally given by publication at https://kartuu.kyth.systems/rechtliches/auftragsverarbeitung; the period then runs from publication.

The merchant can object to the change in text form within 30 days of receipt of the notice on an objective ground relating to data protection. If the parties do not reach agreement, the merchant can end the use of the app by uninstalling it; deletion is then governed by § 9. If the merchant does not object, the change is deemed approved.

If a change requires immediate action because of an immediate threat to security or availability, KYTH informs the merchant at the same time as the measure, at the latest within 24 hours. The merchant can object to the measure within 14 days of receipt of the notice. In the event of an objection, KYTH ends the engagement of the sub-processor without delay, or the merchant can terminate the contract with immediate effect; deletion is then governed by § 9. The right to object under Art. 28(2), second sentence, GDPR is thus preserved.


§ 7 Assistance with the rights of data subjects

7.1 Principle

Requests from data subjects are addressed to the merchant as controller. If a data subject contacts KYTH directly, KYTH forwards the request to the merchant without delay and does not answer it itself.

KYTH assists the merchant with appropriate technical and organisational measures in fulfilling their obligation to respond (Art. 12 to 23 GDPR), insofar as the merchant cannot already do so through their own Shopify access.

7.2 What is technically available

Kartuu is connected to the data protection webhooks required by Shopify:

Webhook Effect today
customers/data_request (Art. 15 GDPR) Two details are read from the signature-checked content: the customer identifier and the email address. The access function uses them to search the voucher table – through the customer identifier the buyer, through the search values of the addresses the recipient and a buyer without a customer number. Recipient's name and email address, sender's name, greeting and the buyer's name and email address are compiled, decrypted. Not included are the voucher code and claim token, because they open access to the voucher itself. An entry is created in the access log for protected customer data. The webhook delivers the access information to no one. There is no page in the app on which the merchant could retrieve it, and no message goes to their contact address. The fact of the request and the number of records found are recorded; the content is discarded with the call. It is handed over at the merchant's request in text form to datenschutz@kyth.systems and manually, from the same rows and with the same function (§ 7.1, § 7.4). The gap is set out in Annex 2 section 7.
customers/redact (Art. 17 GDPR) Same search route. The rows found are anonymised and not deleted: recipient's name, email address with search value, sender's name, greeting and the buyer's name and email address with search value are emptied, the customer number only if it belongs to the person searched for. The voucher itself remains – code, status, value and template copy –, because it has been paid for and can be redeemed. A reprint then no longer carries a recipient's name.
shop/redact Deletes all of the shop's data, see § 9.

Limit regarding recipients. Shopify's customers/redact and customers/data_request carry the customer identifier and address of exactly one person – the person Shopify knows. A recipient has not ordered and does not appear there; their rows are only affected by these webhooks if their email address is the same. The search route through the address has been built, a trigger for a third person has not. If a recipient requests access or erasure, KYTH carries it out manually on the merchant's instructions (§ 7.1). This is also stated in Annex 2 section 7.

Buyers without a customer number. For a guest purchase, the customer number is missing. The buyer's address therefore also carries a non-reversible search value, and the two webhooks find their details through it. Vouchers created before 23 September 2026 have this search value added by the daily clean-up run, as long as their email address is still stored.

7.3 Rectification, restriction, portability

For the shop's technical data (shop domain, tokens, timestamps), there are no details that could be incorrect in content and that the merchant cannot correct themselves through Shopify. If the merchant requests a restriction of processing, KYTH implements it by arrangement; the practically effective means is uninstalling the app.

The situation is different for the details of an ordered card. Recipient's name, recipient's email address, sender's name and greeting can be incorrect – they come from a form a customer filled in. The merchant can correct them in the app as long as the voucher has not yet been issued. In the order overview, every item in the state “prepared” carries the button “Change details”; if the details are missing entirely, the same button is called “Complete details”. It opens a form covering all four fields, and all four are stored together – including one the merchant has deliberately emptied. The address is stored encrypted and its search value rewritten, so that a later erasure request still finds the row.

Not after issuance. Once the card has been rendered, the voucher counts as delivered and is no longer rewritten. If anyone requests a rectification beyond this, a message in text form to datenschutz@kyth.systems is sufficient; KYTH carries it out manually. The route open to the merchant themselves is a newly issued item.

The delivery address is excepted from this. It does not appear on the card but is solely the destination of the delivery. It can therefore also be changed after issuance – through “Send to another address” on the “Delivery” screen – without the document changing by a single character.

Exception: the uploaded pictures. For them there is no deletion option in the app – neither for an individual picture nor for all. If the merchant requests the removal of a picture, for instance because it shows a person who has objected, a message in text form to datenschutz@kyth.systems is sufficient; KYTH removes the object and its row manually and confirms this. Until there is a deletion function in the app, this is the only way.

7.4 Effort

KYTH provides the assistance under this section free of charge, within the scope of what Art. 28(3)(e) GDPR requires. Remuneration for effort beyond this has not been agreed and is not charged.


§ 8 Assistance with security, data breaches and data protection impact assessments

8.1 Security of processing (Art. 32 GDPR)

KYTH maintains the measures described in Annex 2 and reviews them as the occasion arises, in particular with every extension of the range of functions.

8.2 Personal data breaches (Art. 33, 34 GDPR)

KYTH notifies the merchant of every personal data breach affecting data from their shop without delay after becoming aware of it in text form at the contact address stored by the merchant under § 2a no. 4. The notification contains, as far as known:

If not all information is available yet, KYTH first reports the known facts and supplies the rest without delay. Notifying the supervisory authority and informing data subjects are the merchant's responsibility (§ 2a no. 6); KYTH assists them with the information available.

Limit of this commitment. The channel to the merchant exists because the contact address is collected when the contract is concluded (§ 0.2, § 2a no. 4). It depends, however, on the merchant keeping it up to date. If the stored address has become undeliverable, KYTH can no longer reach them directly; KYTH then publishes the notification at https://kartuu.kyth.systems/rechtliches/auftragsverarbeitung and points to it in the embedded interface. This does not replace a direct notification – the merchant's 72-hour period under Art. 33(1) GDPR cannot be reliably met this way.

KYTH maintains a documented response plan for security incidents with escalation levels, named responsibilities, the 72-hour period of Art. 33 GDPR and the competent supervisory authority (Bayerisches Landesamt für Datenschutzaufsicht, BayLDA).

8.3 Data protection impact assessment and prior consultation (Art. 35, 36 GDPR)

If the merchant carries out a data protection impact assessment or consults the supervisory authority, KYTH provides on request the information about the processing by Kartuu required for this – in particular Annexes 1 and 2 of this contract and information about the sub-processors engaged.


§ 9 Deletion or return after the end of processing

9.1 What happens when

Event Effect
Uninstallation of the app (app/uninstalled webhook) Access token and refresh token are set to NULL immediately, and the time of uninstallation is recorded. Access to the shop has thus ended. The shop's data row remains for the time being – including contact address and record of consent, so that a reinstallation before the deletion under the next row, i.e. as a rule within 48 hours, does not require renewed consent.
Deletion of the shop (shop/redact webhook, which Shopify as a rule sends 48 hours after uninstallation) First the uploaded pictures in the image storage, then the data in the database. The latter in one transaction: first all rows of every table assigned to a shop, then the shop's data row itself – either the shop disappears completely or not at all. The order is mandatory, see 9.3 no. 6.
Non-arrival of shop/redact A clean-up run deletes the shop row 30 days after uninstallation through the same deletion path – including the pictures in the image storage and in the same order: first the objects, then the rows. It runs daily, see § 9.3 no. 1.
The connection never came about (consent given, obtaining the token failed – there is therefore no time of uninstallation) The same clean-up run deletes the shop row 90 days after the last sign of life, provided neither access nor refresh token is stored. See 9.3 no. 1.
Completed webhook identifiers are removed 30 days after completion, regardless of the shop. See 9.3 no. 3.
Erasure of an individual person (customers/redact webhook) This person's voucher rows are anonymised, not deleted: recipient's name, sender's name, greeting and the names and email addresses of recipient and buyer, each with search value, are emptied, the customer number only if it belongs to this person. The paid voucher remains. Details in § 7.2.
Three years after a voucher was created Its personal details are emptied; code, status and value remain. See § 9.3 no. 7.
Cancellation or refund of an order The associated Shopify gift card is deactivated – after a partial refund or for a card already partly used, only on the merchant's decision (§ 2.3). The voucher row remains until the period under § 9.3 no. 7 expires or until the shop is deleted.

The tables to be emptied are not determined from a maintained list but at runtime from the database catalogue. All tables in the schema public that have a column named shop_id are covered; the current data set falls entirely under this. The clean-up run under 9.3 no. 1 uses exactly the same path. Foreign keys between these tables are only checked at the end of the transaction, so that the deletion succeeds in any order.

The bytes of the uploaded pictures are not in the database but in the image storage (§ 6.3); they are deleted by a route of their own, see 9.3 no. 6.

9.2 Deletion or return – the merchant chooses

After the end of processing, KYTH deletes all of the merchant's data or hands it over at the merchant's choice (Art. 28(3)(g) GDPR).

The choice belongs before uninstallation. Shopify requests deletion as a rule 48 hours after uninstallation, and KYTH then carries it out (§ 9.1). If the merchant requests the handover, they therefore notify this before uninstalling in text form to datenschutz@kyth.systems and uninstall the app only after they have received the data. KYTH can fulfil a notice given after uninstallation only as long as the data has not yet been deleted. Without a notice, KYTH deletes.

If the merchant requests the handover, KYTH provides the data stored for their shop within 14 days of receipt of the notice in a common machine-readable format (JSON). An automatic export has not been implemented; in this case KYTH compiles the data manually.

For classification: regarding the shop's technical data – shop domain, its hash, encrypted access tokens, encrypted contact address, record of consent, last read subscription status, technical timestamps and the entries of the access log for protected customer data – the following applies: the access tokens are invalid after uninstallation. The choice remains with the merchant.

Voucher data. If the merchant requests the handover, KYTH hands it over in JSON, with the encrypted fields decrypted. The voucher code is expressly included. The handover goes exclusively to the merchant as controller and exclusively to the contact address stored under § 2a no. 4.

Uploaded pictures. If the merchant requests the handover, KYTH hands them over as files – in the uploaded format, i.e. not packed in JSON. An exception applies to SVG pictures: the cleaned version is handed over, because only that is stored (Annex 2 section 2.6). The original file is with the merchant and has not been kept at KYTH at any time.

9.3 Destruction of existing copies – binding periods

Art. 28(3)(g) GDPR requires that, after the end of processing, KYTH also destroys existing copies, unless there is a statutory retention obligation. KYTH commits to the following periods for this.

Overview:

What Period By what means
Shop row with all data assigned to the shop with shop/redact, at the latest 30 days after uninstallation webhook, alternatively clean-up run (no. 1)
Shop row for which a connection never came about (no time of uninstallation, no token) 90 days after the last sign of life the same clean-up run, second rule (no. 1)
Personal details of a voucher (recipient, sender, greeting, buyer, customer number) three years after the voucher was created; at the latest with the shop daily clean-up run, otherwise deletion path (no. 7)
Other voucher data including the code with the shop according to the first row of this table deletion path (no. 7)
Recipient and sender details of an individual person on receipt of an erasure request under Art. 17 anonymisation through customers/redact or manually (no. 7, § 7.2)
Uploaded pictures in the image storage with shop/redact; if the webhook does not arrive, with the clean-up run under no. 1, which runs daily a deletion step of its own through the shop's namespace, the same in both cases (no. 6)
Backup on the server 30 days clean-up step in the backup script (no. 2)
Backup in the object storage 95 days (of which 90 days cannot be deleted) lifecycle rule in the bucket; the backup script deletes nothing there (no. 2)
Identifiers of incoming webhooks 30 days after completion a clean-up run of its own (no. 3)
Application and container logs 14 days setting in the operations tool (no. 4)
  1. If shop/redact does not arrive: 30 days. If the webhook does not arrive – delivery is lost, the endpoint is temporarily unreachable, Shopify never reports it –, a clean-up run deletes the shop row completely 30 days after the time of uninstallation, through the same deletion path as shop/redact. The period is a safety net for the missing webhook and not a window for returning: as a rule, shop/redact deletes after 48 hours, and anyone who reinstalls after that consents again and gives their contact address again. Second case of the same clean-up run: connections that never came about – 90 days. If obtaining the access token from Shopify fails after consent, there is no time of uninstallation. The same clean-up run therefore deletes, through the same deletion path, a record that has no time of uninstallation, no access and no refresh token, and whose last sign of life lies more than 90 days back.

Key rotation. After every key rotation, the search hashes are recalculated so that the app/uninstalled webhook still finds its shop.

The clean-up run starts with the application and calls both rules every 24 hours; nos. 3 and 7 use the same run. 2. Backups: 30 days on the server, 95 days in the object storage – of which 90 days cannot be deleted. A complete backup of the database is created every night and encrypted with AES-256 before it leaves the server. It is stored on the server and in IONOS's object storage in Berlin, in the bucket kaspar-kyth-db-backup-worm.

On the server: 30 days. This is enforced by the backup script itself, on every run.

In the object storage, two mechanisms act one after the other. First, the backup cannot be deleted by anyone for 90 days thanks to Object Lock in COMPLIANCE mode – not even by KYTH itself and not by someone who takes over the server together with its credentials. After that, a lifecycle rule of the bucket (sicherungen-nach-95-tagen-loeschen, entire bucket, 95 days after creation and likewise 95 days for non-current versions) deletes it at storage level. The five-day gap ensures that the deletion does not hit a backup that is still locked.

The backup script deletes nothing in the object storage; clean-up there takes place exclusively through the bucket's lifecycle rule.

The dump is encrypted. It is encrypted symmetrically with AES-256 before it leaves the server; the password is stored on the server and not in the object storage. Transfer to the object storage uses TLS 1.3. Within the backup, the fields requiring protection are additionally encrypted field by field with AES-256-GCM; the key for this is only in the application's environment on the server, not in the backup and not in the object storage. Restorability has been verified by an actual restoration, and a daily check run reports missing backups.

Deleted data in backups. If a shop is deleted – through shop/redact, through the clean-up run under no. 1 or at the merchant's request –, its data remains contained in backups already made and disappears from them only when the periods named expire: at the latest 30 days later on the server, at the latest 95 days later in the object storage. Individual records are not cut out of existing backups. As long as the data is there, it is used exclusively for restoration in the event of a fault. 3. Technical webhook identifiers: 30 days after completion. The table with the identifiers of incoming webhooks (duplicate protection) has no shop assignment and is not covered by the shop's deletion. A clean-up run of its own removes a completed entry 30 days after its completion. In content, these are exclusively technical identifiers assigned by Shopify, without personal reference. Entries whose processing was never completed remain, so that the same webhook is not processed a second time; they too have no personal reference. 4. Application and container logs: 14 days. They contain the shop domain, the internal shop identifier, in the order process additionally order, line item and voucher identifiers and the error reason as a short identifier of our own, and the type of exceptions that occurred – no tokens, no contact address, no voucher code, no recipient's or sender's name, no greeting and no customer address. They are discarded after 14 days. The period is set in the operations tool. 5. Access log for protected customer data. It has a shop assignment and disappears completely with the shop – through shop/redact and through the clean-up run under no. 1. There is no separate, shorter period, because the log serves as evidence towards Shopify. 6. Uploaded pictures: with shop/redact, and before everything else. The pictures have no period of their own. They are kept as long as the merchant uses the app and are deleted with the shop.

How deletion works. Every object of a shop is stored under a key that begins with the identifier of that shop. Everything under this prefix is deleted – including an object whose upload was aborted before its row was written. The objects are deleted before the database rows; if that fails, the shop remains, and the deletion is repeated.

a) The clean-up run under no. 1 takes the same route, in the same order: first the objects, then the database rows.

b) Pictures no longer in use are not cleaned up. If a merchant uploads a picture and never uses it or no longer uses it, it remains as long as their shop exists. There is no place in the app where a merchant can delete an individual picture. Anyone who requests this contacts datenschutz@kyth.systems (§ 7.3); the deletion is then carried out manually. 7. Vouchers: personal details three years after creation. Three years after a voucher was created, its personal details are emptied: recipient, their email address and its search value, sender, greeting, buyer, their email address with search value, and the customer number. The voucher itself remains – code, status and value –, because it is the record of an obligation entered into. The period corresponds to the regular limitation period for the claim arising from the voucher (section 195 of the German Civil Code, BGB); the merchant keeps accounting records in their Shopify account. This is carried out daily by the same clean-up run as nos. 1 and 3. A voucher's claim link is not valid for longer than this period.

The rows have a shop assignment and disappear completely with the shop, through shop/redact as well as through the clean-up run under no. 1.

a) The erasure of an individual person does not delete the row. It empties the personal fields and leaves code, status, value and template copy in place (§ 7.2), because the voucher has been paid for and can be redeemed.

b) There is no trigger through Shopify for the recipient. If they request erasure before the period expires, KYTH carries it out manually on the merchant's instructions (§ 7.2).

9.4 Statutory retention

If, exceptionally, there is a statutory obligation to retain data further, deletion does not take place to that extent; the data is restricted in its processing and used exclusively for this purpose. KYTH informs the merchant of such retention.


§ 10 Evidence and audit rights of the controller

10.1 Evidence

On request to datenschutz@kyth.systems, KYTH makes available to the merchant all information necessary to demonstrate compliance with the obligations under Art. 28 GDPR. As a rule, the following suffice:

10.2 Audits

If this evidence is not sufficient in an individual case, KYTH allows for and contributes to audits, including inspections (Art. 28(3)(h) GDPR). The merchant can carry out the audit themselves or engage an auditor of their choice who is not in competition with KYTH and is bound to confidentiality.

Audits take place after notice with reasonable lead time – as a rule 30 days –, during normal business hours, without disrupting operations and at most once per calendar year; if there is a specific reason, in particular after a personal data breach or at the request of a supervisory authority, also beyond this and at short notice.

10.3 What an audit cannot cover

10.4 Authorities

KYTH assists the merchant in audits by the competent supervisory authority and provides it with information directly on request (Art. 31 GDPR). KYTH informs the merchant without delay of official measures concerning their data, insofar as this is legally permissible.


§ 11 Order of precedence and final provisions

  1. This contract takes precedence over the other contractual terms between the parties insofar as processing of personal data on behalf is concerned.
  2. Annexes 1 and 2 form part of this contract.
  3. Amendments and additions require text form. This also applies to waiving this form requirement.
  4. If a provision is invalid, the rest of the contract remains effective. The parties replace the invalid provision with a valid one that comes closest to the purpose pursued.
  5. German law applies. The place of jurisdiction is, insofar as legally permissible, KYTH's registered office.
  6. Obligation to keep it up to date: contract and annexes reflect the state of the software named in the header. Before every extension that changes the range of data processed, Annex 1 and Annex 2 are compiled anew and the contract is presented in a new version under § 0.3.

§ 12 What you as a merchant must do

The obligations under § 2a are set out there in contractual language. Here they are again, briefly and in plain terms, so that after reading you know what you have taken on.

  1. Keep your contact address up to date. The email address you gave when connecting the app is our only way to reach you – in the event of a data breach, a change of contract, a change of sub-processor. Once after installation, we also send you the setup email there if you have chosen a plan and steps are still missing before the first voucher sale (§ 2a no. 4). If the address changes, write to us at datenschutz@kyth.systems. If it becomes undeliverable, we can no longer reach you, and the 72 hours under Art. 33(1) GDPR still run (§ 2a no. 4, § 8.2).
  2. Make sure there is a legal basis. For processing your customers' data you need a legal basis under Art. 6 GDPR. We do not and cannot check it.
  3. Inform your customers and the recipients. The information obligations under Art. 13 and Art. 14 GDPR lie with you, not with us. Recipients do not provide their data themselves – for this, Art. 14 GDPR applies. Include Kartuu in your own privacy policy.
  4. Answer requests from data subjects yourself. If someone contacts us, we forward the request to you and do not answer it (§ 7.1).
  5. Report data breaches to your supervisory authority yourself. We report the incident to you; you make the notification under Art. 33 GDPR and inform the data subjects under Art. 34 GDPR (§ 8.2).
  6. Give instructions in text form. Individual instructions go to datenschutz@kyth.systems. Please confirm anything you say orally to us in text form without delay (§ 3.2).

Annex 1 – Processing overview

Reflects the state of the software named in the header. The merchant receives evidence for individual details under § 10 on request to datenschutz@kyth.systems; KYTH presents it to a supervisory authority on request (Art. 31 GDPR).

Information under Art. 30(2) GDPR

Item Content
Processor KYTH. Systems UG (haftungsbeschränkt), Prof.-Mederer-Straße 4, 92348 Berg, Germany, datenschutz@kyth.systems
Controllers on whose behalf processing takes place the merchants who have connected Kartuu – recorded per shop through the myshopify domain (name) and the email address stored when the contract was concluded (contact details), Art. 30(2)(a) GDPR
Categories of processing installation and operation of the app, fulfilment of the data protection webhooks, evidence of access to protected customer data, determination of the subscription status, generation of the voucher card from the merchant's input, keeping the pictures uploaded by the merchant, setting up the voucher product, handling a paid voucher order, card preview on the product page, operational diagnostics (§ 1.3)
Categories of data subjects the merchant and the people acting for them, buyers, recipients, givers, people in an uploaded picture (§ 2.1)
Transfers to third countries to Shopify entities outside the EEA, see § 3.4
Measures under Art. 32(1) GDPR Annex 2

KYTH does not collect the merchant's complete company details (company name, address, representation); they follow from the merchant's Shopify account and are requested through the stored contact address in the event of a request under Art. 31 GDPR.

Safeguards under Art. 30(2)(c) GDPR. For transfers to Shopify entities outside the EEA: the EU standard contractual clauses under Implementing Decision (EU) 2021/914, incorporated through Shopify's Data Processing Addendum in the version of 7 July 2026. For Canada, in addition, adequacy decision 2002/2/EC. Details are in § 3.4.

A. Data actually stored

The data named is stored in the PostgreSQL database on the server in Berlin and goes into the backups under § 9.3 no. 2 – with two exceptions: of the uploaded pictures, only the description is in the database. The bytes are in the image storage (§ 6.3) and are not part of the database backup. There is no backup for them; if the storage is lost, they are gone. And the message about an uninstallation to KYTH and the preview and report on the announcement under § 0.3 are not in the database but in KYTH's mailbox as emails (last rows).

Data category Data subjects Purpose Form of storage Duration / deletion
Shop domain in plain text (e.g. beispielshop.myshopify.com) merchant (indirectly) assigning the tenant, addressing the Shopify token endpoint, assigning incoming webhooks table shops, unencrypted Not on uninstallation. With shop/redact, at the latest 30 days after uninstallation – through the daily clean-up run under § 9.3 no. 1 even if Shopify does not deliver the webhook
Shop domain as HMAC hash merchant (indirectly) search index: every query in production runs over the hash instead of the plain text table shops, non-reversible as shop domain
Shopify access token (a credential; not personal data in the narrow sense, but a key to personal data in the shop) — access to the Shopify Admin API on the merchant's behalf. Used for all twenty-seven calls to the Admin API (§ 3.4), including the query of the subscription status (§ 2.3; see the row Subscription status of the shop) – not for retrieving order or customer data fields table shops, encrypted with AES-256-GCM set to NULL immediately on uninstallation; expires after 1 hour anyway; finally with the row
Shopify refresh token (a credential) — renewing the one-hour access token without the merchant logging in again table shops, encrypted with AES-256-GCM set to NULL on uninstallation; immediately if discarded by Shopify; regular expiry after 90 days; finally with the row
Appearance of the shop: freely chosen display name for the voucher card and the key of the picture chosen as logo merchant (directly – they enter both themselves) putting the shop's name instead of the technical shop address on the card and showing its logo there. Without an entry, the designation derived from the shop address remains there, and the card carries no logo table shops, unencrypted – both appear on every printed card the merchant hands out themselves and are therefore not secret. Nevertheless named as a category: for a sole trader, the display name can be the name of a person. Enforced by the database: at most 60 characters and not empty, and the logo key must be in the namespace of exactly this shop as shop domain
Subscription status of the shop: whether an active subscription exists, plan name, flag “test subscription issued by Shopify”, time of the last query merchant (indirectly) enforcing the paywall at three points – setting up the voucher product, the proof, and the delivery lock, which stops automatic sending without a plan – and displaying the plan in the admin. The generation of a paid voucher is expressly not locked. Cached, so that not every one of these requests triggers a call to Shopify table shops, unencrypted. Enforced by the database: “active” only with a check time as shop domain
Redeemed promo code of the shop: the code and the time of redemption merchant evidence that and when the merchant accepted a promotional offer; KYTH then enters the discount manually at Shopify (terms of service § 5). A message with shop domain, code, time, subscription status and whether Kartuu is installed goes from the server to KYTH's own mailbox at INWX GmbH, Berlin (deploy/server/aktionscodes-melden.sh). This is KYTH's own processing as a contracting party, not processing on the merchant's behalf; the message contains no customer data, and INWX is therefore not a sub-processor under this contract table shops, unencrypted. Enforced by the database: code only with time. On the server, a note of redemptions already reported (domain and time), which is cut back to the redemptions in the database on every hourly run as shop domain
Contact address of the merchant (email) merchant or the natural person they name notices under § 0.3, § 6.6 and § 8.2; at most a daily note about orders needing attention, through the merchant's mail account (§ 2a no. 4); once the setup email through KYTH's own mailbox at INWX GmbH (§ 2a no. 4) – for this, the application decrypts the address and passes it with the finished email to a script on the server that sends it; forwarding requests from data subjects under § 7.1; information under Art. 30(2)(a) GDPR table shops, encrypted with AES-256-GCM. Without search hash – no one searches by the address; it is found through the shop domain as shop domain
Record of consent: time and version identifier merchant (indirectly) evidence of the conclusion of the contract under § 0.2 table shops, unencrypted. Enforced by the database: either all three consent details or none as shop domain
Language of the Kartuu interface when consenting: German or English merchant (indirectly) writing the setup email and the announcement under § 0.3 in the language in which the merchant sees Kartuu (§ 2a no. 4); if it is not known, in German. Unknown values do not overwrite a stored value table shops, unencrypted. Enforced by the database: only de or en as shop domain
State of the setup email: whether it is being sent, was sent or was not needed, and the time of it merchant (indirectly) sending the setup email exactly once, even if two runs overlap; a sending that has not been completed for an hour counts as failed and is repeated table shops, unencrypted. Enforced by the database: a fixed vocabulary for the state, state and time only together as shop domain
State of the announcement: which version of the legal texts KYTH last announced to the merchant under § 0.3 and when, plus the time since which a run is sending it merchant (indirectly) showing from when a new version is deemed accepted (§ 0.3); announcing each version only once, even if two runs overlap; a sending that has not finished within an hour counts as failed and is repeated table shops, unencrypted. Enforced by the database: version and time only together as shop domain
Technical metadata of the shop: expiry and rotation times of the tokens, token version, time of installation and uninstallation, scope of permissions (scopes) merchant (indirectly) controlling the token life cycle, resolving races in simultaneous installations, recognising late uninstall webhooks table shops, unencrypted as shop domain
Settings and setup state of the shop: language of the vouchers, chosen or preset from the shop's country at the first consent, whether and when the setup was completed, when the Kartuu blocks in the theme were first seen, technical times of notes sent merchant (indirectly) issuing cards, emails and claim page in the chosen language; showing the merchant which setup steps have been done table shops, unencrypted as shop domain
House colours of the shop: up to twelve colour values (hex codes) saved by the merchant merchant offering them for a click at every colour choice in the design; none of it is printed – a card's colours are in its document table shops, unencrypted. Enforced by the database: a list with at most twelve entries as shop domain
State of the review request: when Kartuu called Shopify's own request for a review and Shopify's response to it (such as “not right now” or “already reviewed”) merchant (indirectly) not asking more often than Shopify allows, and no longer once a review has been given. Kartuu does not see the text of the request or any review table shops, unencrypted as shop domain
The merchant's credentials for the sending route (SMTP): mail server and port, sender address and reply-to address, optionally user name and password, plus the switch for automatic sending merchant or the natural person they name delivery of the finished voucher on the merchant's behalf through their mail account (§ 1.1). Without an account entered, nothing is delivered table shops. User name and password encrypted with AES-256-GCM – the same encryption as the access tokens; the password is never delivered again. Mail server, port, sender address and reply-to address are stored in plain text; they appear in every mail header the merchant sends anyway. Whether a sending route has been set up is stored by Kartuu as a yes or no on the app installation at Shopify (§ 3.4). Enforced by the database: either no mail server – or mail server, port, sender and reply-to address; user name and password only as a pair; as port exclusively 465, 587 or 2525 as shop domain
Saved designs (drafts): name and the complete design document of a card template, for a design created in the “Card” tab additionally the settings from which it was made (template, fold, colour wishes, position of the pictures), and the times of creation and last change merchant (directly – they design them in the editor) the merchant should be able to find a design they started and reuse it. The document describes layers, texts, placeholders and the chosen picture – no details about a person; the placeholders are only filled when rendering table entwuerfe assigned to a shop, unencrypted. Row protection at database level as shop domain
Pictures of a voucher: the keys of the pictures belonging to an individual voucher merchant (indirectly) a voucher already issued must be able to be drawn again unchanged, even if the merchant has changed their design in the meantime table gutschein_assets assigned to a shop, unencrypted. Row protection at database level as shop domain
Incidents of an order: order and line item identifier, a reason as a short identifier and the times of noticing and resolving own application making visible to the merchant that a paid order is stuck – for instance because details are missing. No free text and no personal detail; the reason comes from a fixed vocabulary table bestellvorfaelle assigned to a shop, unencrypted. Row protection at database level as shop domain
Failed attempts of the guest check: order identifier and time of an attempt in the Kartuu block in which the email address entered did not match the order buyer (indirectly) limiting the failed attempts per order and per shop, so that addresses cannot be tried out. An attempt with a matching address does not count table gastnachweis_fehlversuche assigned to a shop, unencrypted. No address, not even a search value of it. Row protection at database level. No right to change deleted after one hour at the next attempt in the same shop, otherwise by the daily clean-up run – at the latest after one day; with the shop in any case
Webhook identifiers: the webhook ID assigned by Shopify with status and the times of claim and completion header of the incoming request duplicate protection – the same message must not be processed twice. No personal reference; the identifier describes the delivery and not its content table webhook_claims, without shop assignment and unencrypted 30 days after completion (§ 9.3 no. 3)
Consents – the history: per consent given, the shop assignment, the version identifier and the time merchant (indirectly) evidence under § 0.2 over time, including for older versions table zustimmungen assigned to a shop, unencrypted. No personal detail – the contact address is not stored there as shop domain
Origin of an installation: way of attribution, from the cookie kyth_klick the random visitor identifier, the Meta identifiers _fbc and _fbp, the campaign details (utm), the landing page and the times of click and consent; IP address and browser identifier of the request; status of the report to Meta person opening the app for the merchant KYTH's own processing as a controller, not on behalf of the merchant (§ 1.3): attributing the installation to an advertisement, only with consent on kyth.systems and only for shops that agreed from identifier 1.26-2026-09-28 (privacy policy section 5.7). No customer data table installationsherkunft assigned to a shop, unencrypted IP address and browser identifier: until the report has been sent or it is certain that it will not be sent, at the latest eight days after the installation; the rest as shop domain
Reports for the plan “Kartuu Free”: internal identifier of the voucher, kind (issued or cancelled), amount and currency of the purchase, value in US dollars and rate, status and time of the report, open credit merchant KYTH's own processing as contracting party, not on the merchant's behalf (§ 6.4): billing of the plan, only for shops that have consented from consent record ID 1.27-2026-10-06 on. No customer data table abrechnungsmeldungen with shop assignment, unencrypted with the shop (deletion request from Shopify after uninstallation)
Access log for protected customer data: shop assignment, time, actor, purpose, field categories touched, number of records merchant (indirectly) a condition of Shopify's approval for protected customer data; evidence under Art. 5(2) GDPR. It proves that access took place, not which content a table of its own, deliberately without any column that could hold a name, a postal address, an email address or a voucher number completely with the shop – foreign key with cascading deletion and additional explicit deletion. See § 9.3 no. 5
Uploaded pictures – the bytes. The picture in the form in which it was stored: for raster images (JPEG, PNG, WebP) scaled to at most 2000 pixels edge length if the picture was larger, then re-encoded; in every case without the embedded capture data (EXIF, XMP, IPTC) except for the orientation; for SVG, the version cleaned of everything executable (Annex 2 section 2.6) merchant (indirectly). In addition, every person who can be seen in the picture or appears in its capture data – what that is, is determined by the merchant alone drawing the picture on the voucher card, in the preview and in the PDF (§ 1.3 no. 6). KYTH does not look through or evaluate the content in ongoing operation, a file storage on the server in Berlin, on a persistent storage medium (§ 6.3). No generally readable address; a picture is delivered after the merchant's session has been checked or through a signed address that becomes invalid after one to two hours – also to visitors of the product page if it belongs to the design of a voucher product (§ 2.2). Key <shop identifier>/<checksum>.<extension>, formed on the server from the identifier of the uploading shop and never from a detail in the request – the prefix thus belongs to exactly one shop. Not in the database backup with shop/redact or the clean-up run under § 9.3 no. 1, through the shop's namespace and before the rows. Pictures no longer used are not cleaned up, and the app has no deletion function for individual pictures (§ 9.3 no. 6)
Uploaded pictures – the details about them: key, MIME type, size in bytes, width and height in pixels, checksum (SHA-256 of the stored bytes), time of upload. Size and checksum describe the file at upload; for pictures from before 23 September 2026, therefore, the version that still carried capture data merchant (indirectly) listing a shop's pictures and showing their aspect ratio without having to fetch every picture from the image storage for it a table of its own assigned to a shop, unencrypted. Row protection at database level. Enforced by the database: key form, checksum form, a fixed vocabulary for the MIME type, positive dimensions, uniqueness per shop and key. No right to change – a key describes the content under which it is stored as shop domain (foreign key with cascading deletion and explicit deletion)
Voucher – the details of the recipient and the giver: recipient's name, recipient's email address, sender's name, greeting recipients (both as data subjects and as recipients of the voucher, § 2.1), givers printing the card; the address for the intended delivery. The origin is the paid order, not the merchant's input table gutscheine, each field individually encrypted with AES-256-GCM. Next to it, a non-reversible search value of the email address – the only way to find a recipient again, because they have no customer number. Enforced by the database: ciphertext form for each encrypted column, 64 hex characters per search value. Row protection at database level with the shop (§ 9.3 no. 7). Three years after creation, these fields are emptied (§ 9.3 no. 7). On an erasure request under Art. 17 they are emptied immediately, the row remains (§ 7.2)
Voucher – the details of the buyer: Shopify customer number, plus buyer's name and buyer's email address buyer the customer number is the search key of the two data protection webhooks and shows in the Kartuu block whether the logged-in person may see the vouchers of their order. The merchant sees name and email address in the detail view of the order; the email address also serves for matching if a person without a customer account enters their address in the Kartuu block (section B) table gutscheine. The customer number in plain text, so that a request under Art. 15 or 17 finds it; for a guest purchase it is missing. Name and email address encrypted with AES-256-GCM, next to them a non-reversible search value of the address – through it, a request under Art. 15 or 17 also finds a buyer without a customer number emptied three years after creation (§ 9.3 no. 7), otherwise with the shop. On erasure under Art. 17, name and address with search value are emptied, the customer number only if it belongs to the person searched for
Voucher – the code and the claim token no direct personal reference; both are keys to an asset of a data subject the code is on the card and is redeemed at the checkout; Shopify releases it exactly once and never again afterwards. The claim token addresses the later retrieval of the PDF table gutscheine, both encrypted with AES-256-GCM, each with a non-reversible search value next to it. The code's search value is at the same time the lock against issuing the same code twice. Enforced by the database: ciphertext and hash form, code and search value only as a pair, no right to change the claim token – the link may already have gone out: to the recipient with the delivery email, if the merchant has entered a sending route, and to the buyer in the Kartuu block, if the merchant has placed it and the check under section B succeeds. It does not go out through Shopify's order confirmation as above. On erasure under Art. 17, both remain (§ 7.2, § 9.3 no. 7 a)
Voucher – the details about the order and the process: order identifier, line item identifier, running number of the item, type, face value and currency, printed amount as text, shop name, validity date, identifier of the Shopify gift card, status, time of the last status change, flags “details incomplete” and “changed after sending”, error counter, error reason as a short identifier, an open question to the merchant after a refund (which question, for a partial refund the number of items still to be decided, since when), identifier of the chosen card template, delivery route of the item, the start of the claim period (the time of the last sending; without sending, the time of creation applies), the desired delivery date (the buyer's entry from the line item – without an entry, the voucher goes out as soon as it is finished; the merchant can override the date with “Send now”), the time the delivery was reserved for sending (a technical note that prevents several worker processes from sending the same card at the same time), the language of the item (fixed from the shop's setting on issue and unchangeable afterwards – card, email and claim page follow it), the order header: order number, time of the order, total amount with currency, payment method and sales channel, and the discount with which the item was bought: amount with currency, code or title of the discount and whether it applied to the whole order (for display only – the card keeps its full value) buyer (indirectly) assigning the order to the voucher, controlling the process – including the day on which the voucher is to go out; it only holds back sending, not generation – and being able to finish the card without the webhook body. No balance is stored here, and none gets a column – that is kept by Shopify alone table gutscheine, unencrypted. Enforced by the database: a fixed vocabulary for type and status, positive identifiers, running number from 1, error reason only as an [a-z0-9_] identifier – never a passed-through external message, which could quote recipient's name and code, face value only for value vouchers and only together with a currency, and completeness from the state “ready” as above
Voucher – the frozen copy of the card template no personal reference a reprint should produce the same card, even if the merchant has changed their template table gutscheine, JSONB. It carries placeholders instead of values; the personal values are next to it in separate, individually encrypted columns as above
Assignment of pictures to a voucher: key of the picture used indirectly through the picture (see the row on pictures) a picture used by an issued voucher must not be deleted – and the merchant should learn how many vouchers are affected a table of its own assigned to a shop, row protection at database level, no right to change: which pictures are in an issued card is a fact about the past. Foreign key to voucher and picture, the latter only checked at the end of the transaction as above
Voucher product of the shop: type, Shopify product ID, handle, chosen card template, time of creation no personal reference – a product ID, a handle and two identifiers from our own vocabulary preventing creation twice; showing the set-up state; recognising a voucher line item even if a theme does not send additional details a table of its own assigned to a shop, unencrypted, row protection at database level. Any number of rows per shop, each Shopify product ID only once. No right to change the details describing the product – type, product ID, handle and chosen template are fixed once created. Only the fields that track the state of the product image can be changed (draft, media identifier, state, due time, attempts and reason) – they describe an ongoing work step and not the product as shop domain
Identifiers of incoming webhooks: webhook identifier assigned by Shopify, status, times no personal reference duplicate protection – prevents repeats from Shopify from processing the same webhook more than once a table of its own without shop assignment 30 days after completion, see § 9.3 no. 3
Application logs: shop domain, internal shop identifier, for the access log additionally actor and purpose, whether a subscription is active or a test subscription, for a rejected input in the voucher editor the name of the field objected to – never its content –, for an image upload the MIME type of the accepted picture or the reason for a rejection (format, dimensions, result of the SVG cleaning) – never the key, never the checksum, never a file name and never an excerpt of the picture –, and the type of exceptions that occurred merchant (indirectly) operational diagnostics (failed creation of a shop, failed token exchange, unknown shop in webhooks, failed writing of the access log, subscription status not retrievable, failed rendering, object storage unreachable) standard output of the container, collected on the server. Access, refresh and session tokens and the contact address are not logged – not even shortened. In the event of an error, as a rule only the type of exception is written; Annex 2 section 1.4 names the cases in which the message is also logged 14 days, see § 9.3 no. 4
Signed webhooks for shops without consent: shop domain from the signed content, webhook identifier assigned by Shopify merchant (indirectly) receiving the webhooks to which Shopify obliges us to subscribe, before or without the merchant having agreed to the contract (§ 0.1). Legal basis Art. 6(1)(f), additionally (c) GDPR no record of the shop. The webhook identifier in the duplicate protection table; the shop domain only in the application log if no shop belongs to it webhook identifier 30 days after completion (§ 9.3 no. 3), log line 14 days (§ 9.3 no. 4)
Message about an uninstallation to KYTH: shop domain, time of uninstallation, the reason the merchant selects in Shopify's uninstall dialog and their free text on it; as long as the shop row still exists, supplemented by time of installation, plan and setup state merchant; in the free text, where applicable, a person the merchant names themselves KYTH is to learn why merchants remove Kartuu again, and to improve the app. Shopify provides the reason to KYTH as the app's developer through the Partner API (§ 6.4); a script on the server queries it every hour and sends the new uninstallations per run in one email to KYTH's own mailbox at INWX GmbH (deploy/server/deinstallationen-melden.sh). This is KYTH's own processing as a contracting party, not processing on the merchant's behalf; none of the data Kartuu processes on the merchant's behalf goes into it. Anyone who removes Kartuu before consenting is also reported – then without the supplement Not in the database. The email is in KYTH's mailbox; on the server there is a note of uninstallations already reported (domain and time), cut back to the last 30 days on every run, and the script's log with the shop domain per run KYTH deletes the email after 30 days; the note lapses after 30 days, the log after 14 days (deploy/server/logrotate-kaspar)
Preview and report on the announcement under § 0.3: for each shop that receives the announcement, the shop domain, the language of the email and the versions announced, plus the exact text of the email; the report names the shop domains it went to or did not merchant (indirectly) KYTH sees before sending what goes to whom and can stop it; afterwards, whether it succeeded (§ 0.3). This is KYTH's own processing as a contracting party Not in the database. The emails are in KYTH's mailbox; on the server are the version in force with a checksum of the text and the time of the preview, any stop note and the identifiers of sendings not yet confirmed, plus the script's log with the shop domain per run KYTH deletes the emails after 30 days; the log after 14 days (deploy/server/logrotate-kaspar)

B. Data touched only briefly – no storage

Data category Data subjects Purpose Why no storage
Shopify session token of the logged-in merchant user (JWT) merchant and the people acting for them authenticating the call, determining the shop domain, passing it to the Shopify token exchange not in the database, not in the log, not in browser storage, not in the address bar. The error path expressly logs only “session token rejected”, without reason and without content. The token itself is short-lived
Name of the shop owner as held by Shopify merchant (the owner of the shop) salutation of the setup email (§ 2a no. 4). Only the first name is taken, and only if it is recognisable as such; otherwise the email greets without a name read at the moment the email is created (§ 3.4). The first name then appears only in the email to the merchant – not in the database and not in the log; if the email does not arrive, also in the bounce to KYTH's mailbox, which KYTH deletes after 30 days at the latest. This is KYTH's own processing as a contracting party and not processing on the merchant's behalf
Country code of the shop as Shopify holds it from the billing address (for example “US”) merchant (indirectly) default for the language and paper of the cards at the first consent (§ 3.4) Read once, at the first consent. Only the language of the vouchers chosen from it is stored (section A, settings of the shop); the code itself is neither in the database nor in the log. This is KYTH's own processing as a contracting party
Shopify customer identifier and email address from the customers/data_request and customers/redact webhooks the merchant's end customers; through the address, indirectly also a recipient handling access and erasure requests under Art. 15 and Art. 17 GDPR the webhook content is read in completely for the signature check and then discarded. Shopify sends further customer data in these webhooks (among other things phone number and postal address); only the customer identifier and email address are read out. The address is not stored, only converted into the search value – without it, the request would find no row of a recipient and none of a buyer without a customer number
The content of an incoming order, insofar as it is not taken over into a voucher row – in particular line items without a voucher, postal addresses, phone numbers and payment details the merchant's end customers recognising which line items of a paid order are vouchers the body is read in completely for the signature check. Only what is listed in section A is taken over; everything else is not evaluated and is discarded in memory. There is no column for any of it
The rendered PDF of an ordered voucher recipients, givers checking that the card can be printed – “ready” means “PDF rendered” it is created in the work run and discarded afterwards; there is no column for it. The frozen template copy and the stored values produce the document again at any time
Sample details when designing: recipient's name, sender's name, greeting, voucher code, amount, shop name, validity date – and the HTML preview and PDF generated from them recipients, givers (insofar as the merchant enters such names) generating the voucher card as a preview and as a PDF (§ 1.3 no. 5) the values come from the body of the same merchant's request, are put into the chosen template and returned with the response. There is no table and no file for them; in the event of an error, the log contains only the name of the field objected to, never its content. Saved drafts are in section A
Kartuu block on the thank-you and order status page: the short-lived session token issued by Shopify with the reference to the order and – for logged-in buyers – the Shopify customer number; for buyers without a customer account, the email address they entered; the browser's IP address buyer showing the buyer the status of their vouchers and releasing the claim links only if the customer number belongs to every still valid voucher of the order or the address entered matches the one given in the order the token is checked and discarded. The address entered is only compared with the stored one and not stored. If it does not match, this failed attempt is counted with order identifier and time to limit the attempts per order and per shop (section A, row Failed attempts of the guest check). The IP address is not stored by the application
Card preview on the product page: the request Shopify forwards from the shop to Kartuu, with signature, shop domain and – for logged-in customers – their Shopify customer number visitors to the shop delivering a card with empty placeholder fields for the preview the details serve only to check the signature and are not stored. What the visitor types into the order form is inserted into the preview by their browser itself; it is not transmitted to Kartuu for this. The browser loads the fonts and the design's pictures directly from KYTH's server, the pictures through signed addresses that become invalid after one to two hours; the browser's IP address arises in the process and is not stored by the application. The visitor can download the design's image files – without capture data, which Kartuu removes from every picture on upload (§ 2.2)

C. Not processed

Data category State
Postal addresses, phone numbers and payment data of customers They arrive with the order webhook and are discarded under section B. Kartuu does not query any customer data field through the Admin API.
Balance of a Shopify gift card Read but not stored. If the merchant asks for the redemption status in the order overview or opens the export, Kartuu fetches it from Shopify and passes it through; on cancellation, Kartuu reads it before deactivating in order to recognise a partly used card. There is no column for it. What is available on a gift card is kept by Shopify alone.
Claim link in the order confirmation Shopify's order confirmation does not contain the claim link. It becomes known through the delivery email, which goes out through the merchant's mail account, and through the Kartuu block on the thank-you and order status page.

Annex 2 – Technical and organisational measures (Art. 32 GDPR)

Reflects the state of the software named in the header. Only measures that have been implemented are listed; section 7 names the known gaps.

1. Confidentiality

1.1 Encryption of stored data

1.2 Separation of tenants

1.3 Permissions limited to what is necessary

Database permissions are granted per column instead of per table:

For the vouchers:

1.4 No secrets in the wrong place

1.5 Access log for protected customer data

The log is free of content: the permitted values for actor and field category are secured twice (check in the code and check rule in the database). An error when logging does not bring down the functional call.

Entries arise, among other things, when a paid order is received and with the data protection webhooks. Only the categories actually touched are recorded; an order without any personal detail writes no entry. The entry for the order is created on receipt and not on rendering, so that a repeat run does not create a second entry for the same access.

2. Integrity

2.1 Checking incoming calls

2.2 Securing the embedded interface

Security headers: content security policy with dynamic framing restriction, whose shop parameter is checked against a fully anchored pattern and responds with rejection if given more than once; X-Content-Type-Options; Referrer-Policy: strict-origin-when-cross-origin.

2.3 Keeping the attack surface small

The interface's schema description and interactive documentation are switched off in production (the routes do not exist there).

The contact address entered in the consent step is checked on the server against a fully anchored pattern (no line breaks, no separators, no angle-bracket-style appendix, domain with a dot, length limit); leading and trailing spaces are removed, upper and lower case is preserved. Consent must be transmitted as a genuine boolean – strings or numbers do not count as consent. The server accepts the interface language sent along only as German or English; any other value does not overwrite a stored value.

Limiting the request body. The body of this request must not exceed 4 kilobytes. The limit works in two places: in advance against the length announced by the caller, and during reading itself, which is aborted as soon as the limit is exceeded – even if a request conceals its length.

The same mechanism for the other requests with a body, each with its own cap: 256 kilobytes for the rendering calls (preview and PDF) and when saving a draft, because there the body carries the complete design document; considerably less for all others. All limits come from one common implementation. A body above the cap ends in a rejection and not in a response with empty values.

2.5 Checking the input of the voucher editor

Texts and designs from the editor are checked on the server before a document is made from them; the server does not rely on a check in the browser.

2.6 Checking uploaded pictures

An uploaded picture is checked once on upload, before it is stored; what does not pass the check is never stored.

2.7 Measures in the order process

2.8 Traceability of changes

The database schema is changed exclusively through migrations and in a separate process before the application starts; no worker process sees a half-finished schema.

3. Availability and resilience

4. Resilience of the configuration

The application does not start without the required configuration values; the encryption key is checked for the correct format. Misconfiguration leads to an abort, not to silent continued running.

5. Separation of test and production

Two separate applications, each with its own database, own encryption key, own database role with its own password, own domain and own Shopify application. The addresses of the legal texts are also derived per environment from the respective application's own address.

6. Procedures for review and evaluation

7. Known gaps

These points are not or not completely fulfilled.

Gap State
The access information under Art. 15 does not reach the merchant by itself. The customers/data_request webhook compiles it and writes a log entry with the number of records; after that, the content is discarded. There is no page in the app on which the merchant could retrieve it, and no sending to their contact address. It is handed over on request in text form and manually (§ 7.2), within the 30 days required by Shopify open, with a named alternative route
No external error tracking connected. The external monitoring (section 3) is located at KYTH and falls silent if power or network fail there; it does not see whether the backup is running – that remains the check run on the same server, which does not cover that server's total failure open
No row protection on shops – the table with the productive merchant data carries no policy; the application role can read and delete it completely. What it contains today: the shop domain in plain text and as search hash, the encrypted tokens with their times, the scope of permissions, the encrypted contact address, the record of consent together with the administration language (in which language the merchant saw Kartuu when consenting), the state of the setup email (whether and when it was sent), the state of the announcement (which version of the legal texts was announced when), the cached subscription status with plan name, a redeemed promo code with time, the merchant's sending route (mail server, port, sender and reply-to address in plain text, user name and password encrypted), their appearance on the card (display name and the keys of the two logo versions), their house colours (hex codes offered for a click at every colour choice in the design), the shop's output language (in which language cards are printed and emails sent), the setup state together with the steps they confirmed, the state of the review request (when Shopify's request for a review was shown and with what result) and the times of installation and uninstallation, the time of the last daily merchant message and the two times at which the theme blocks were first used. Separation there works only through the application and column-level permissions open
Remaining window in the clean-up run for orphaned shops – between the check immediately before deletion and the deletion itself, the same merchant can reinstall the app. The window is small; if the rare case occurs, the merchant reinstalls the app open, with manageable consequences
Unfinished webhook claims are never removed. No personal reference, they only take up space (§ 9.3 no. 3) deliberately open
Pictures no longer used are not cleaned up, and a merchant cannot delete an individual picture. A picture uploaded and never or no longer used remains as long as the shop exists; deletion on request is carried out manually (§ 7.3, § 9.3 no. 6 b) open
No backup of the pictures. The daily backup covers the database, not the image storage. If the storage is lost, the pictures are gone (section 3) open
No trigger for the erasure of a recipient. They have no customer number and only appear in Shopify's customers/redact if their email address is the same. The search route through the search value of their address has been built, a way for the merchant to trigger it has not. Until then, KYTH carries out the erasure manually on instruction (§ 7.2, § 9.3 no. 7 b) open
A gift card can be orphaned. If Shopify rejects a voucher code that has already been stored as taken, the card exists, but its identifier is unknown and it cannot be deactivated on cancellation. For this, the voucher ends in a visible error state instead of a silent second card (2.7) deliberately open