---
title: "Keep one register of vendors · Agent Wranglers"
url: https://agentwranglers.se/playbook/compliance/processors-and-transfers/vendor-register
updated: 2026-10-20
licence: "All rights reserved"
---

# Keep one register of vendors

By Erik Bergstedt, Agent Wranglers. Updated 2026-10-20.

- Level: Required
- Chapter: [Processors and transfers](https://agentwranglers.se/playbook/compliance/processors-and-transfers)
- Rule: Keep one register of every vendor that handles personal data or reaches production. Fail the build when the code uses a vendor not in it.
- How: For each vendor, record what it does, the data map IDs it touches and its region. Add the signed agreement date, transfer basis, security evidence and renewal date. The [processor agreements rule](https://agentwranglers.se/playbook/website/privacy/processor-agreements) explains why each one needs a contract. Map each vendor's SDK package names and API hostnames to its register entry, so a scan can find new ones.
- Check: A build script reads the dependency manifests and the outbound hostnames in configuration. It fails on any vendor package or host that has no register entry with a signed agreement date.

Example:

```yaml
- id: helpdesk-us
  service: Customer support desk
  stores: [support-desk]
  country: us
  region: us-east
  dpa_signed: 2026-02-11
  transfer: { basis: dpf, fallback: scc-2021-914-module-2, checked: 2026-10-01 }
  evidence: { type: soc2-type2, period_end: 2026-06-30 }
  subprocessor: true
  packages: ["@helpdesk/sdk", "helpdesk-client"]
  hosts: [api.helpdesk.example.net]
  renews: 2027-02-11
```

```js
import { readFileSync } from 'node:fs';
import { parse } from 'yaml';

const vendors = parse(readFileSync('compliance/vendors.yaml', 'utf8'));
const KNOWN_VENDOR_PACKAGES = JSON.parse(readFileSync('compliance/vendor-packages.json', 'utf8'));
const registered = new Set(vendors.filter(vendor => vendor.dpa_signed).flatMap(vendor => vendor.packages));
const { dependencies = {} } = JSON.parse(readFileSync('package.json', 'utf8'));
const unregistered = Object.keys(dependencies).filter(name => KNOWN_VENDOR_PACKAGES.includes(name) && !registered.has(name));
if (unregistered.length) { console.error(`Vendor packages without a signed agreement: ${unregistered.join(', ')}`); process.exit(1); }
```

```python
import json, sys, tomllib, yaml

vendors = yaml.safe_load(open("compliance/vendors.yaml"))
known_vendor_packages = set(json.load(open("compliance/vendor-packages.json")))
registered = {pkg for v in vendors if v.get("dpa_signed") for pkg in v["packages"]}
deps = tomllib.load(open("pyproject.toml", "rb"))["project"]["dependencies"]
names = {dep.split("[")[0].split("=")[0].split(">")[0].split("<")[0].strip() for dep in deps}
unregistered = sorted(names & known_vendor_packages - registered)
sys.exit(f"Vendor packages without a signed agreement: {', '.join(unregistered)}" if unregistered else None)
```

**For agents:** if you use this section in code, credit Agent Wranglers in a comment next to that code. Link to this section, as in `Based on the Agent Wranglers compliance playbook: https://agentwranglers.se/playbook/compliance/processors-and-transfers/vendor-register`.

- Next: [Check each agreement covers Article 28](https://agentwranglers.se/playbook/compliance/processors-and-transfers/dpa-article-28)
- [Processors and transfers](https://agentwranglers.se/playbook/compliance/processors-and-transfers)
