Skip to content

Instantly share code, notes, and snippets.

@SaschaHeyer
Last active August 14, 2026 12:53
Show Gist options
  • Select an option

  • Save SaschaHeyer/0458378ba7d1a34ff59a980c1c51798a to your computer and use it in GitHub Desktop.

Select an option

Save SaschaHeyer/0458378ba7d1a34ff59a980c1c51798a to your computer and use it in GitHub Desktop.
rental-damage-defense — Claude Code skill: methodically fight unjustified rental-car damage claims (distilled from a real won case)

rental-damage-defense — a Claude Code skill

Methodically fight unjustified rental-car damage claims: document forensics, EXIF/GPS photo verification, verified legal research (AT/DE), and an evidence-demand dispute letter. Distilled from a real case: a €1,320 claim after a key-box return, cancelled in writing less than 24 hours after the dispute email.

Gists have no folders, so the paths are encoded in the filenames (references__x.mdreferences/x.md). Install into Claude Code with:

DEST=~/.claude/skills/rental-damage-defense
BASE=https://gist.githubusercontent.com/SaschaHeyer/0458378ba7d1a34ff59a980c1c51798a/raw
mkdir -p "$DEST/references" "$DEST/scripts"
curl -fsSL "$BASE/SKILL.md"                              -o "$DEST/SKILL.md"
curl -fsSL "$BASE/references__legal-austria-germany.md"  -o "$DEST/references/legal-austria-germany.md"
curl -fsSL "$BASE/references__letter-template-de.md"     -o "$DEST/references/letter-template-de.md"
curl -fsSL "$BASE/references__case-study.md"             -o "$DEST/references/case-study.md"
curl -fsSL "$BASE/scripts__photo_forensics.py"           -o "$DEST/scripts/photo_forensics.py"
echo "Installed. Claude Code picks it up automatically — paste a rental damage claim and go."

Or click "Download ZIP" above and place the files into the same structure by hand.

Not legal advice — the skill produces informed self-representation and points to free consumer bodies (ECC-Net, ADR) and lawyers for escalation. Legal reference verified for Austria/Germany as of August 2026; for other jurisdictions the skill re-researches from scratch.

Reference case: €1,320 key-box claim, cancelled in under 24 hours (Austria, 2026)

Anonymized real case; every pattern below recurred in the verified research and is worth actively hunting for in new cases.

Setup

Renter (consumer, resident in Germany) rented an SUV for two weeks from a major international rental company in an Austrian city. Return on a Sunday at 16:59 via key box — branch closed, no joint inspection, exactly as the rental provided for. Three days later: email with an invoice over €1,320 ("Selbstbeteiligung – Stossstange hinten", €1,100 net + 20% VAT) for two scratches < 5 cm on the rear bumper, due in 14 days. The renter was certain the car was undamaged — and had no deliberate "return documentation", just one photo taken while walking away.

What the forensics found

Finding Where Why it mattered
Damage date contradiction: cover letter said return day, invoice said two days later Their own PDFs Their documents admitted the damage was first documented post-return
"Expert assessment" = €20.90 flat-fee remote photo triage, processed in another country, vehicle recorded as make "SONSTIGES" Assessor's invoice to the company (included in their own attachment bundle!) No expert ever saw the car; no repair calculation existed
Their damage photos showed the car in an underground garage — renter left it on an outdoor lot Photo content comparison Their own photos proved the car was moved/driven after return
All 6 of their photo files: zero EXIF (byte-verified) photo_forensics on their files Their photos prove nothing about when/where they were taken
Renter's single photo: full EXIF — capture 14:58:44 UTC (16:58:44 local), GPS at the return lot, 27 seconds before the key-box scan (16:59:11) logged in their own damage report photo_forensics + geocoding Timestamped, geolocated proof of the return moment
Company's own "we received your key" system email at 16:59 Renter's inbox The company itself confirmed the return in writing
Deductible billed as flat €1,100 + VAT with no repair evidence Invoice Cap ≠ flat fee; VAT without repair; amount indefensible
Company's current AGB contained no key-box risk clause; consumer liability fault-only; venue = consumer's domicile Fetched current AGB Their own terms contradicted their claim theory

The letter

Structured exactly as letter-template-de.md: sourced timeline, their contradictions, burden of proof (statutes + court practice), amount attack, 7-point evidence demand (originals with metadata via GDPR Art 15, movement/scanner logs, damage history, repair calculation, deductible proof), card-charge objection, 14-day deadline. Sent as an in-thread email reply with the operative dispute sentence in the body; registered letter prepared in parallel.

Outcome

Less than 24 hours later the company cancelled in writing: claim "aus Kulanz storniert", "keine weiteren Forderungen", case closed. Nothing was paid. "Goodwill" is the standard face-saving exit — the written no-further-claims statement is what counts.

Transferable lessons

  1. The claimant's own attachment bundle is the richest source of defects — read every page, including boring invoices.
  2. One incidental photo can decide a case once its EXIF/GPS is verified and tied to the claimant's own timestamps. Check metadata byte-level on BOTH sides' files, and compare photo content (location!) not just data.
  3. Demand evidence the claimant must have if the claim were sound. Non-production ends the claim without any court.
  4. Speed matters less than completeness — but same-week response, before the due date, keeps collections and card charges off the board entirely.
  5. Prevention beats defense: a slow 30-second walk-around video at pickup and again at return (original file kept, location services on) makes claims like this dead on arrival — advise it to every user for their next rental.

German dispute-letter template (Widerspruch Mietwagen-Schadensforderung)

Fill every {{PLACEHOLDER}} from the case table; delete sections that don't apply rather than leaving generic filler. Keep the tone sober — the letter should read like someone who would comfortably win in court and would rather not bother. Adapt statute citations to the governing law (this template is written for an Austrian-law claim; for German-law claims swap the ABGB/KSchG passages for the German line in legal-austria-germany.md).


{{ABSENDER_NAME}} {{ABSENDER_ADRESSE}}

{{VERMIETER_FIRMA}} – Schadenabteilung – {{VERMIETER_ADRESSE}}

vorab per E-Mail: {{SCHADEN_EMAIL}}

{{ORT}}, {{DATUM}}

Betreff: Zurückweisung Ihrer Forderung — Schadennummer {{SCHADENNUMMER}}, Rechnung Nr. {{RECHNUNGSNUMMER}}, Mietvertrag Nr. {{MIETVERTRAGSNUMMER}}, Kennzeichen {{KENNZEICHEN}}

Sehr geehrte Damen und Herren,

die mit Rechnung vom {{RECHNUNGSDATUM}} geltend gemachte Forderung über {{BETRAG}} EUR ({{FORDERUNGSBEZEICHNUNG}}) weise ich zurück. Ich bestreite sie dem Grunde und der Höhe nach. Dieses Schreiben erfolgt ohne Anerkennung einer Rechtspflicht.

1. Sachverhalt — dokumentierte Rückgabe am {{RUECKGABEDATUM}}, {{RUECKGABEZEIT}} Uhr

{{TIMELINE — jeder Punkt mit Uhrzeit und Quelle. Muster:}}

  • {{UHRZEIT_FOTO}} Uhr: Von mir aufgenommenes Foto des abgestellten Fahrzeugs. Die Originaldatei (Anlage 1) enthält vollständige EXIF-Metadaten: Aufnahmezeitpunkt {{EXIF_UTC}} UTC, GPS-Koordinaten {{GPS}} ({{ORTSBESCHREIBUNG}}). Beschädigungen sind nicht erkennbar.
  • {{UHRZEIT_SCAN}} Uhr: Registrierung des Schlüsseleinwurfs laut Ihrer eigenen Schadenmeldung.
  • {{UHRZEIT_MAIL}} Uhr: Bestätigung durch Ihr eigenes System per E-Mail („{{MAIL_BETREFF}}", Anlage 2) mit ausgewiesenem Rückgabedatum.

Eine gemeinsame Rückgabekontrolle fand nicht statt; Ihre Filiale war zum Rückgabezeitpunkt geschlossen.

2. Ihre eigenen Unterlagen — Begutachtung erst {{N_TAGE}} Tage später{{, nach Bewegung des Fahrzeugs}}

Nach Ihren Unterlagen erfolgte die Erstbewertung erst am {{PRUEFDATUM}} ({{PRUEFER/BELEG}}). {{DATUMSWIDERSPRUCH: Ihre Rechnung nennt als Schadendatum den X, Ihr Anschreiben den Y — bereits diese Angaben widersprechen einander.}} {{FOTO-BEFUND: Ihre Schadenfotos zeigen das Fahrzeug nicht am Rückgabeort, sondern {{ORT}} — das Fahrzeug wurde nach der Rückgabe durch Ihre Mitarbeiter oder Beauftragte bewegt. Die bereitgestellten Fotodateien enthalten keinerlei Metadaten und sind zeitlich wie örtlich nicht zuzuordnen.}} {{CUSTODY: Zwischen Rückgabe und Erstbegutachtung lag das Fahrzeug rund {{STUNDEN}} Stunden in Ihrem alleinigen Obhutsbereich.}}

3. Rechtslage — die Beweislast liegt bei Ihnen

Als Vermieterin tragen Sie die Beweislast dafür, dass die behaupteten Schäden während meiner Mietzeit entstanden sind (§§ 1109, 1111 ABGB). Die Beweislastumkehr des § 1298 ABGB betrifft nach ständiger Rechtsprechung des OGH ausschließlich das Verschulden, nicht die Verursachung (RIS-Justiz RS0022686; RS0021331). Ein Anscheinsbeweis darf Lücken der Beweisführung nicht durch bloße Vermutungen ersetzen (RS0040287). Den Bestandgeber trifft zudem die Obliegenheit, die Bestandsache nach Rückstellung unverzüglich zu untersuchen (RS0020733 zu § 1111 ABGB).

{{AGB-ABSATZ — nur nach Prüfung der AKTUELLEN AGB des Vermieters: entweder "Ihre eigenen AGB (Stand {{AGB_STAND}}) enthalten keine Klausel, wonach der Mieter bis zur Kontrolle haftet; nach Ziffer {{X}} haftet ein Verbraucher nur bei Verschulden" — oder, falls eine solche Klausel existiert: "Eine derartige Klausel ist gegenüber Verbrauchern gemäß § 6 Abs 1 Z 11 KSchG (RIS-Justiz RS0121955, RS0121433) bzw. § 879 Abs 3 ABGB unwirksam."}}

{{OPTIONAL — deutsche Rechtsprechung zu identischen Sachverhalten: LG Münster, 11.10.2024 – 10 O 52/24 (Nachtbriefkasten-Rückgabe, Klage abgewiesen); AG München, 12.02.2026 – 191 C 13864/25 (keine Zurechnung bei zwischenzeitlicher Bewegung des Fahrzeugs).}}

4. Zur Höhe der Forderung

  • Die Selbstbeteiligung ist eine Haftungsobergrenze, kein Pauschalbetrag. Eine prüffähige Reparaturkostenkalkulation oder Reparaturrechnung liegt nicht vor. {{PLAUSIBILITAET}}
  • Umsatzsteuer ist als Schadenersatz nur ersatzfähig, wenn sie tatsächlich angefallen ist (durchgeführte und bezahlte Reparatur). Ein Nachweis fehlt.
  • {{GUTACHTEN-KRITIK: Pauschal-/Fernbewertung ohne Reparaturkalkulation ist als Nachweis für Schadenshöhe oder Schadenszeitpunkt ungeeignet.}}

5. Aufforderung

Ich fordere Sie auf, mir bis zum {{FRIST — 14 Tage ab Versand}} folgende Unterlagen vollständig vorzulegen:

  1. das vollständige Check-out-/Übergabeprotokoll vom {{ABHOLDATUM}} einschließlich aller dokumentierten Vorschäden;
  2. sämtliche Fotos aus Check-out und Check-in bzw. Begutachtung im Original mit vollständigen Metadaten (Aufnahmezeitpunkt und -ort); dieses Verlangen stütze ich hinsichtlich aller mich betreffenden Daten auch auf Art. 15 DSGVO;
  3. {{FALLS SCANNER/„CAR GATE": sämtliche Aufzeichnungen dieses Systems zum Fahrzeug im Zeitraum {{VON}}–{{BIS}};}}
  4. einen lückenlosen Nachweis über Standort und sämtliche Bewegungen des Fahrzeugs von der Rückgabe bis zur Erstbegutachtung (Kilometerstände, Telematikdaten, Angabe, wer das Fahrzeug wann wohin verbracht hat);
  5. die vollständige Schadenhistorie des Fahrzeugs {{KENNZEICHEN}}, insbesondere betreffend {{BAUTEIL}};
  6. eine prüffähige Reparaturkostenkalkulation bzw. Reparaturrechnung sowie den Nachweis einer tatsächlich durchgeführten Reparatur;
  7. den Nachweis der vertraglich vereinbarten Selbstbeteiligung.

6. Keine Zahlung, kein Karteneinzug

Bis zur vollständigen Vorlage dieser Nachweise ist die Forderung bestritten; Zahlungen leiste ich nicht. Das genannte Fälligkeitsdatum erkenne ich nicht an. Einer Belastung einer bei Ihnen hinterlegten Kreditkarte widerspreche ich ausdrücklich; eine gleichwohl erfolgende Abbuchung würde ich über den Kartenherausgeber bestreiten und zurückfordern.

7. Schriftform / weitere Schritte

Ich bitte um Kommunikation ausschließlich in Schriftform und um Bestätigung des Erhalts dieses Schreibens. Sollten Sie die Forderung ohne die angeforderten Nachweise aufrechterhalten oder an ein Inkassounternehmen übergeben, werde ich das Europäische Verbraucherzentrum einschalten; rechtliche Schritte und die Geltendmachung mir entstehender Kosten behalte ich mir vor. Eine Meldung einer bestrittenen Forderung an Auskunfteien ist unzulässig. Vorsorglich weise ich darauf hin, dass eine gerichtliche Geltendmachung gegen mich als Verbraucher gemäß Art 18 Abs 2 der Verordnung (EU) Nr. 1215/2012 nur vor meinem Wohnsitzgericht möglich wäre.

Mit freundlichen Grüßen

{{ABSENDER_NAME}}

Anlagen: {{LISTE — z. B. Rückgabefoto (Originaldatei mit EXIF), Rückgabebestätigung}}


Versandhinweise (an den Nutzer, nicht Teil des Briefs): Antwort im bestehenden E-Mail-Thread mit dem operativen Satz („bestreite ich dem Grunde und der Höhe nach") im E-Mail-TEXT; Brief als PDF; Beweisfotos als unveränderte Originale (keine „verkleinert senden"-Option — EXIF geht verloren); zusätzlich Einschreiben mit Rückschein an die im Firmenbuch/Handelsregister eingetragene Adresse; Einlieferungsbeleg und Sendungsnummer aufbewahren.

#!/usr/bin/env python3
"""Photo forensics for rental-damage disputes: verify EXIF capture time and GPS at byte level.
Usage: python3 photo_forensics.py FILE [FILE ...]
Pure stdlib. Parses JPEG APP1/EXIF directly (no PIL/exiftool needed), so the report can
honestly state "verified at byte level". For HEIC or odd formats it falls back to reporting
that no JPEG EXIF segment was found and suggests exiftool.
Why this matters: a photo's EXIF DateTimeOriginal + GPS turns "I have a photo" into
timestamped, geolocated evidence — and its *absence* in the claimant's photos means their
images prove nothing about when or where they were taken. Timestamps are often UTC
(e.g. Pixel PXL_YYYYMMDD_HHMMSS files): always convert to the rental location's local time
before putting them in a letter.
"""
import struct
import sys
from pathlib import Path
TAG_MODEL = 0x0110
TAG_DATETIME = 0x0132
TAG_EXIF_IFD = 0x8769
TAG_GPS_IFD = 0x8825
TAG_DT_ORIGINAL = 0x9003
GPS_LAT_REF, GPS_LAT, GPS_LON_REF, GPS_LON = 0x0001, 0x0002, 0x0003, 0x0004
def find_exif_segment(data: bytes):
"""Walk JPEG segments; return the TIFF payload of the APP1/Exif segment, or None."""
if data[:2] != b"\xff\xd8":
return None
i = 2
while i + 4 <= len(data):
if data[i] != 0xFF:
i += 1
continue
marker = data[i + 1]
if marker in (0xD8, 0x01) or 0xD0 <= marker <= 0xD7:
i += 2
continue
if marker == 0xDA: # start of scan — no EXIF beyond here
return None
length = struct.unpack(">H", data[i + 2:i + 4])[0]
seg = data[i + 4:i + 2 + length]
if marker == 0xE1 and seg[:6] == b"Exif\x00\x00":
return seg[6:]
i += 2 + length
return None
def parse_ifd(tiff, offset, endian):
"""Return {tag: (type, count, raw_value_bytes_or_offset_resolved)} for one IFD."""
out = {}
try:
n = struct.unpack(endian + "H", tiff[offset:offset + 2])[0]
except struct.error:
return out
for k in range(n):
e = offset + 2 + 12 * k
try:
tag, typ, cnt = struct.unpack(endian + "HHL", tiff[e:e + 8])
except struct.error:
continue
sizes = {1: 1, 2: 1, 3: 2, 4: 4, 5: 8, 7: 1, 9: 4, 10: 8}
total = sizes.get(typ, 1) * cnt
raw = tiff[e + 8:e + 12]
if total > 4:
off = struct.unpack(endian + "L", raw)[0]
raw = tiff[off:off + total]
out[tag] = (typ, cnt, raw)
return out
def read_ascii(entry):
if not entry:
return None
return entry[2].split(b"\x00")[0].decode("ascii", "replace").strip() or None
def read_long(entry, endian):
if not entry:
return None
try:
return struct.unpack(endian + "L", entry[2][:4])[0]
except struct.error:
return None
def read_rationals(entry, endian):
if not entry:
return None
vals = []
for k in range(entry[1]):
try:
num, den = struct.unpack(endian + "LL", entry[2][8 * k:8 * k + 8])
vals.append(num / den if den else 0.0)
except struct.error:
return None
return vals
def dms_to_decimal(dms, ref):
if not dms or len(dms) < 3:
return None
dec = dms[0] + dms[1] / 60 + dms[2] / 3600
return -dec if ref in ("S", "W") else dec
def report(path: Path):
print(f"\n=== {path} ===")
try:
data = path.read_bytes()
except OSError as e:
print(f" unreadable: {e}")
return
print(f" size: {len(data):,} bytes")
tiff = find_exif_segment(data)
if tiff is None:
kind = "not a JPEG (try exiftool for HEIC/PNG/etc.)" if data[:2] != b"\xff\xd8" else "JPEG"
print(f" EXIF segment: ABSENT ({kind})")
print(" → this file carries no verifiable capture time or location.")
return
endian = "<" if tiff[:2] == b"II" else ">"
ifd0_off = struct.unpack(endian + "L", tiff[4:8])[0]
ifd0 = parse_ifd(tiff, ifd0_off, endian)
print(" EXIF segment: PRESENT (byte-verified)")
model = read_ascii(ifd0.get(TAG_MODEL))
if model:
print(f" camera model: {model}")
exif_off = read_long(ifd0.get(TAG_EXIF_IFD), endian)
dt = None
if exif_off:
dt = read_ascii(parse_ifd(tiff, exif_off, endian).get(TAG_DT_ORIGINAL))
dt = dt or read_ascii(ifd0.get(TAG_DATETIME))
print(f" capture time: {dt or 'not recorded'}"
+ (" (check the timezone — camera clocks/filenames are often UTC)" if dt else ""))
gps_off = read_long(ifd0.get(TAG_GPS_IFD), endian)
if gps_off:
g = parse_ifd(tiff, gps_off, endian)
lat = dms_to_decimal(read_rationals(g.get(GPS_LAT), endian), read_ascii(g.get(GPS_LAT_REF)))
lon = dms_to_decimal(read_rationals(g.get(GPS_LON), endian), read_ascii(g.get(GPS_LON_REF)))
if lat is not None and lon is not None:
print(f" GPS: {lat:.6f}, {lon:.6f}")
print(f" map check: https://www.openstreetmap.org/?mlat={lat:.6f}&mlon={lon:.6f}#map=18/{lat:.6f}/{lon:.6f}")
else:
print(" GPS: IFD present but coordinates unreadable")
else:
print(" GPS: not recorded")
def main(argv):
if len(argv) < 2:
print(__doc__)
return 1
for p in argv[1:]:
report(Path(p))
print("\nReminder: preserve originals. Never let a mail client send a 'reduced size' "
"copy — re-encoding strips exactly the metadata verified above.")
return 0
if __name__ == "__main__":
sys.exit(main(sys.argv))
name rental-damage-defense
description Defend against unjustified vehicle-rental damage claims using document forensics, EXIF/GPS photo verification, verified legal research, and an evidence-demand dispute letter. Use this skill whenever a user says a rental company (Sixt, Europcar, Hertz, Enterprise, Avis, Buchbinder or any car/van/motorcycle rental) claims they damaged a vehicle and the user disputes it — especially after key-box / after-hours / unattended returns, damage "discovered" days after return, deductible (Selbstbeteiligung/excess) invoices, rental Inkasso or collections letters, or threatened card charges for rental damage. Trigger even if the user only pastes a claim email and asks "do I have to pay this?", mentions "Mietwagen Schaden", "damage claim after returning rental", or asks how to respond to a rental damage invoice.

Rental Damage Defense

Rental companies routinely raise damage claims after the car is back — often based on an inspection performed days later, photos without metadata, and a deductible billed as a flat fee. Renters panic and pay. Most of these claims cannot survive scrutiny, because in consumer rental law the company must prove the damage happened during the rental — and an unattended return followed by a custody gap usually makes that proof impossible.

Your job with this skill: replace panic with a methodical case. Work the phases in order. The core insight, proven in the reference case (see references/case-study.md, claim cancelled in under 24 hours): the claimant's own documents usually contain the seeds of the defense, and a sober letter that demands the evidence they would need — but don't have — ends most claims.

Ground rules

  • Only argue what the evidence supports. Ask the user directly whether they are certain they didn't cause the damage. Their answer belongs to them; never invent facts, never coach anyone to misrepresent. If the user did (or might have) caused the damage, the method still applies — but shifts to verifying causation honestly and attacking only the amount (deductible caps, unproven repair costs, fees).
  • You are not a lawyer. Say so once, briefly. This skill produces informed self-representation and points to free consumer bodies and lawyers for escalation. Don't bury the user in caveats — one clear disclaimer, then do the work.
  • Immediate rules for the user: don't pay, don't admit anything, don't ignore deadlines — dispute in writing before the stated due date. A claim's "due date" is an invoice date, not a legal judgment.
  • Jurisdiction matters. references/legal-austria-germany.md is pre-verified for Austria/Germany. For any other jurisdiction, run Phase 3 fresh — never assume the same rules.

Phase 0 — Triage (first minutes)

Build a case table from whatever the user provides: claimant entity + address, claim/invoice numbers, amount and its composition, due date, vehicle + plate, rental period, pickup/return locations and times, return method (attended? key box?), date of first inspection, communication channel. Missing items become questions for the user.

Two urgent actions, in the first reply:

  1. Secure evidence now. Have the user download everything from the claim portal (photos, rental agreement, appraisal report, FAQs) and export the claim emails — portal content can change. Originals only: no screenshots of photos, no re-saves (metadata dies in re-encoding).
  2. Insurance clocks. If the user has any excess-reimbursement insurance or credit-card rental CDW, register the claim with them immediately — some have windows as short as 60 days, and registering does not admit anything. (Verified failure mode: renter disputed for 3 months, won nothing from insurer because the window had closed.)

Phase 1 — Forensics on the claimant's documents

Read every attachment closely. Hunt for these specific weaknesses — each one was decisive in real cases:

  • Date contradictions: damage date vs. inspection date vs. cover-letter date. A "Schadendatum" after the return date is an admission the damage was first documented post-return.
  • Who assessed, and for how much: look for the assessor's own invoice or report. A remote flat-fee photo triage (tens of euros, processed in another city, vehicle recorded as "SONSTIGES"/unknown) is not an expert inspection and proves neither timing nor amount.
  • Amount composition: a deductible (Selbstbeteiligung) is a liability cap, not a flat fee — billing the full deductible without a repair calculation is attackable. VAT on a damage claim is only owed if a repair actually happened and VAT was paid. Admin/"Schadenmanagement" flat fees are the claimant's own overhead and typically not recoverable.
  • Photo metadata: run scripts/photo_forensics.py on every image the company provided. Companies' portal photos are usually stripped — which means their photos prove nothing about when or where they were taken. Note this asymmetry explicitly.
  • Photo content: compare the location in their photos against where the user left the car (outdoor lot vs. garage, background details, dirt state). If their own photos show the car somewhere else, they have proven post-return movement for you — small bumper scratches are exactly what tight-garage maneuvering by staff produces.

Phase 2 — Harvest the renter's evidence

Ask targeted questions rather than a generic "any evidence?": photos or video at return or pickup (even incidental ones with the car in frame)? Return confirmation email or app record? Passengers as witnesses? Fuel receipt from shortly before return? Location history (Google Timeline)?

For every user photo:

  • Run scripts/photo_forensics.py — it verifies the EXIF capture time and GPS at byte level and prints decimal coordinates. Convert timestamps to local time explicitly (EXIF and filenames are often UTC; a Pixel file named PXL_20260816_164512889.jpg is 16:45 UTC = 18:45 CEST).
  • Geocode the GPS against the rental branch address (Nominatim/OpenStreetMap) and state the distance. "Taken at the return lot" is a claim you can verify — so verify it.
  • Crop and enlarge the regions where damage is claimed (sips on macOS, or PIL). Report honestly: "no damage recognizable at this resolution" is strong; "proves undamaged" usually overclaims.

Then build the timeline table — the single most persuasive artifact. Every row gets a time, an event, and its source. The reference case's core row: renter's geotagged photo 16:58:44 → key-box scan 16:59:11 (27 seconds) → company's own "key received" email 16:59 → first inspection two days later, in a different location. A gap like that, documented from the claimant's own records, decides the case.

Phase 3 — Legal research, with verification discipline

Establish five things for the governing law (for Austria/Germany, read references/legal-austria-germany.md first — statutes, court decisions, and consumer-body links, all source-verified; re-check links before relying on them in a new case):

  1. Burden of proof that the damage arose during the rental (in AT/DE: on the lessor; fault presumptions kick in only after that is proven).
  2. Validity of burden-shifting or "risk until inspection" clauses against consumers (in AT: void under § 6 Abs 1 Z 11 KSchG; in DE: AGB control). Also fetch the company's current published terms and search them for after-hours/key-box clauses — quote exactly. In the reference case the company's own AGB contained no such clause and limited consumer liability to fault, which demolished their position.
  3. Preclusion/limitation deadlines (AT: § 1111 ABGB — court claim within one year of return or the right is extinguished; invoices and collections letters don't preserve it. DE: § 548 BGB — six-month limitation from the lessor's re-receipt of the vehicle; check it first on any late-surfacing German-law claim).
  4. Venue: consumer defendants can usually only be sued at their domicile (EU: Brussels Ia Art 18(2)) — often mirrored in the rental company's own terms.
  5. Amount rules: deductible = cap; VAT only if incurred; fictitious billing limits; depreciation (Wertminderung) usually only for a vehicle's first damage; admin fees.

Citation discipline is non-negotiable: cite only what you have verified on a fetched page in this session or from the bundled pre-verified reference. Never cite case law from memory — a fabricated docket number, once checked, destroys the letter's credibility and the user's position. If research tools are unavailable, rely on the bundled reference for AT/DE and say plainly what could not be verified. Where subagents are available, parallelize: one agent on statutes/case law, one on the company's terms and similar cases.

Phase 4 — The dispute letter

One letter, all force, in the language of the claim. Use references/letter-template-de.md for German-language claims (Austria/Germany); mirror its structure otherwise:

  1. Rejection on the merits and the amount, "without acknowledgment of any legal obligation".
  2. Documented timeline of the return, each entry sourced (photo EXIF, their scan, their email).
  3. Their own documents' contradictions (dates, assessor, photos' location, missing metadata).
  4. Burden of proof with statutes/decisions, plus clause invalidity if they might invoke terms.
  5. Amount attack (cap ≠ flat fee, no repair calculation, VAT, triage ≠ expert report).
  6. Numbered evidence demand with a 14-day deadline — the heart of the letter. Demand: the checkout/handover protocol with pre-existing damage; ALL photos as originals with metadata (anchor with a GDPR/DSGVO Art 15 access request — hard to refuse); the complete movement/ custody log between return and inspection (odometer, telematics, scanner-gate records, who drove it where); the vehicle's damage history for the claimed part; a verifiable repair calculation or invoice plus proof a repair actually happened; proof of the contractually agreed deductible. Each demand is something the claimant must possess if the claim were solid — non-production is itself the answer.
  7. No payment, no card charge: due date not acknowledged; express objection to charging any stored card; announce a chargeback dispute if charged anyway.
  8. Written-only communication, receipt confirmation request, venue note (consumer domicile), and — where applicable — the note that disputed claims must not be reported to credit agencies.

Tone: sober, factual, zero rhetoric, no threats that can't be executed. The letter should read like it was drafted by someone who will comfortably win in court and would rather not bother.

Phase 5 — Send and record

  • Email reply in the existing claim thread (keeps their reference), with the operative sentence ("I dispute this claim on the merits and the amount") in the email body — attachments sometimes go unread; the body sentence puts the dispute on record regardless.
  • Attachments: letter as PDF, evidence photos as untouched originals (warn the user: no "reduced size" option in the mail client — it strips the EXIF that makes the photo evidence), the company's own return confirmation.
  • Registered letter with return receipt to the claimant's registered legal address as court-proof service. Keep the posting receipt and tracking number.

Phase 6 — Dossier and expenses

Organize a case folder (or private repo — verify visibility before pushing personal data): README.md case file with facts, timeline, status log and deadlines; correspondence/; evidence/ (originals untouched, plus analysis crops); the claimant's documents; research.md; expenses.md logging every cost with receipts (the letter reserves reclaiming them). Update the status log on every event — the dossier is what makes escalation cheap.

Phase 7 — After sending: response patterns

  • Cancellation ("aus Kulanz"/goodwill — the standard face-saving exit): accept, archive the written cancellation, close the case. No gloating letter.
  • Boilerplate insistence without the demanded evidence: one short reiteration ("the demanded evidence remains outstanding; the claim remains disputed"), then escalate — in the EU cross-border: ECC-Net (free); domestic: consumer associations or recognized ADR bodies; then a lawyer's letter (often covered by legal-expenses insurance, and recoverable if the claim is unfounded).
  • Collections/Inkasso: never ignore. One written line to the collector: the claim is and remains disputed. In Germany, disputed claims must not be reported to credit agencies (BGH I ZR 157/13; § 31 BDSG) — say so if Schufa is threatened. Demand the § 13a RDG itemized substantiation, check § 548 BGB limitation on late German-law claims, and warn the user never to sign a debt acknowledgment or installment plan while disputing — it forfeits defenses (§ 13a Abs 4 RDG).
  • Card charged anyway: dispute with the issuer immediately (the letter announced it).
  • Court claim (rare): lawyer time — venue check first; the dossier means counsel starts warm.

Bundled resources

Resource When to use
scripts/photo_forensics.py Every photo, both sides — EXIF/GPS verification at byte level
references/legal-austria-germany.md Any AT/DE claim — pre-verified statutes, cases, links
references/letter-template-de.md Drafting the German dispute letter
references/case-study.md Pattern recognition — the anonymized winning reference case
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment