On 19 October 2026 the online nicotine retailer Haypp closed one of its Swedish shops, Snusnetto. The reason was a court ruling about a parcel locker. Sweden’s Supreme Administrative Court had declined to hear an appeal, so a Stockholm appeals court ruling now stands. That ruling says a “geo-located BankID” check at locker collection doesn’t meet the legal rule for checking the recipient’s age.
BankID is Sweden’s widely used digital ID app. If a check built on it isn’t enough, the problem isn’t the tool. The problem is what the check looks at.
This post covers what is known about the ruling, what I couldn’t confirm, and how to build a handover check that looks at the person. It isn’t only about snus. Any shop that sells age-restricted goods through lockers or pickup points has the same gap.
What happened
Haypp is a Swedish seller of nicotine products that also operates in other European countries, the US and Saudi Arabia. Its subsidiary Snusbolaget Norden AB ran Snusnetto. The ruling concerns orders collected from parcel lockers after a geo-located BankID check, meaning a BankID login plus the phone’s location.
Haypp’s press release of 19 October says the Stockholm Administrative Court of Appeal ruled on this method, and the Supreme Administrative Court did not grant leave to appeal. In Haypp’s words, the method “does not satisfy the legal requirement for secure age verification of the recipient.”
What followed, according to the same release and Tobacco Reporter:
- Snusnetto stopped all sales on 19 October. About 500 customers were active. Haypp says the group’s results won’t change in a material way.
- Haypp’s other Swedish shops are rolling out a new check that looks at the person who opens the locker. It took about six months to build. Rollout is due to finish in October.
- Orders collected at staffed pickup points are not affected, because staff check age at handover.
Haypp also says underage purchases don’t currently happen through online channels. That may be true. It doesn’t help the method. As far as I can tell, the court judged the method, not the outcome. A method can fail the test before a single minor gets a parcel.
The rule asks for two checks
Online sales have two moments: the purchase and the handover. In a shop they happen together. Online they can be days apart and done by different systems.
In a written answer to parliament on 25 February 2026, Sweden’s health minister, Elisabet Lann, said the seller is responsible for the products reaching the right person. She added that the Public Health Agency’s rules (Folkhälsomyndigheten) say age must be checked at purchase and at handover. You can read it on the Riksdag site. The answer doesn’t mention parcel lockers. She said the courts should develop practice on what a suitable online check is.
Now a court has started that practice.
Most checkouts do the first moment well. The buyer proves their age on the website. The second moment is often a code in a text message. The locker opens when the code is typed. Nobody, and nothing, looks at who is typing.
What the court looked at, and what I could not confirm
I didn’t read the judgment. I read Haypp’s release, two trade news reports and one identity industry site. I couldn’t find the date of either ruling, the case number or the statute the court applied. Check the judgment itself before you quote any of this to your board.
One report, from Mobile ID World, says the court’s worry was this. The check covered the BankID in use, and nothing more. An adult can put BankID on several devices and share it, along with the code. The buyer didn’t have to be the person collecting. That is a second-hand account of the reasoning, so treat it as a likely reading, not a quote.
Even so, the shape is clear, and it matches a problem we’ve written about before in the binding post. A login is a credential. It proves that someone holds a valid key. It doesn’t prove that the person at the door is the key’s owner, or that they are 18.
Three things a locker-side login check cannot show
Who holds the phone. An adult’s phone, and the adult’s BankID code, can sit in a teenager’s hand. Location doesn’t fix that. Location shows the phone is near the locker. It says nothing about the face above the phone.
Who the buyer was. The purchase check might have been done by a parent three days earlier. Nothing joins that check to the person at the locker unless you build the join.
Who opens the door. Even a perfect check of the phone owner doesn’t cover the person who reaches into the locker. For most goods that is fine. For nicotine, knives or alcohol, it is the point of the rule.
What each handover method proves
Before you pick a method, write down what it proves. The table is my own ranking, not a legal opinion.
| Handover method | What it proves | What it doesn’t |
|---|---|---|
| A code in a text message | Someone has the code | Anything about a person |
| Login again (BankID, app login) | The credential is valid | That its owner is the one collecting |
| Login plus phone location | The phone is near the locker | Who is holding the phone |
| Live face check on the phone, matched to the buyer | A live face matches the buyer’s check | That the same person opens the door |
| Face check by a camera at the locker | A live face at the door matches the buyer | Needs hardware in the locker |
| Staffed pickup point | A trained person looked at the person | Convenience, opening hours |
| Age estimate from a face | The face looks clearly adult | Who the buyer was. Borderline faces need a fallback |
Two things stand out. The cheap methods at the top all check an object (a code, a login, a phone). The methods that check a person are lower in the table and cost more. And none of the phone-only methods closes the last gap, the person who opens the door.
Haypp hasn’t said what its new check does. I won’t guess. The point of the table is that you can ask any vendor, including us, “which row are you in?”
A locker that opens only for a matched person
The design has one rule: the locker command “open door” can only be sent by the decision function, and the decision function refuses to treat a login as a person.
Here is a small version in TypeScript:
type Method = "code" | "credential" | "face_phone" | "face_locker";
type Purchase = { adult: boolean; policy: string };
type Handover = {
method: Method;
liveFaceMatchesBuyer: boolean; // 1:1 match against the face from the purchase check
nearLocker: boolean; // the phone is at the locker, per the locker's own event
};
export function decideHandover(p: Purchase, h: Handover) {
const base = { policy: p.policy, method: h.method };
if (!p.adult) return { ...base, unlock: false, reason: "buyer_not_adult", next: "refund" };
// A code or a login says the credential is valid. It does not look at the person.
if (h.method === "code" || h.method === "credential")
return { ...base, unlock: false, reason: "checks_login_not_person", next: "staffed_point" };
if (h.method === "face_phone" && !h.nearLocker)
return { ...base, unlock: false, reason: "not_at_locker", next: "retry" };
if (!h.liveFaceMatchesBuyer)
return { ...base, unlock: false, reason: "face_does_not_match_buyer", next: "staffed_point" };
return { ...base, unlock: true, reason: "person_matched", next: "open_door" };
}
Five tests pin the behavior. I ran them. All five pass.
test("a valid login alone never opens the door", () => {
const d = decideHandover(adult, { method: "credential", liveFaceMatchesBuyer: false, nearLocker: true });
expect(d.unlock).toBe(false);
expect(d.next).toBe("staffed_point");
});
test("a typed code alone never opens the door", () => {
expect(decideHandover(adult, { method: "code", liveFaceMatchesBuyer: true, nearLocker: true }).unlock).toBe(false);
});
test("a face on a phone that is not at the locker does not count", () => {
expect(decideHandover(adult, { method: "face_phone", liveFaceMatchesBuyer: true, nearLocker: false }).reason).toBe("not_at_locker");
});
test("a live face that matches the buyer opens the door", () => {
const d = decideHandover(adult, { method: "face_locker", liveFaceMatchesBuyer: true, nearLocker: true });
expect(d).toMatchObject({ unlock: true, next: "open_door", policy: "se-nicotine@2026-10-21" });
});
test("a face that does not match goes to a staffed point", () => {
expect(decideHandover(adult, { method: "face_phone", liveFaceMatchesBuyer: false, nearLocker: true }).next).toBe("staffed_point");
});
Three details in that code matter more than they look.
The liveFaceMatchesBuyer flag comes from a comparison against the check made at purchase. The handover system never sees a name or a document. It gets a yes or a no from the same system that made the first decision. That keeps personal data out of the locker network, and out of whichever company runs the lockers.
The policy string travels with every decision. If a regulator or a court asks what you did for a given parcel, you need to say which rule version applied. We make the same point in the per-state switch post.
And a failed check never ends in “driver decides” or “open it anyway”. It ends in a staffed point. That’s the next section.
The failure path is the product
Some honest customers will fail. The light is bad. The phone camera is cracked. The buyer sent a friend to collect. If the only outcome of a failed check is a closed door and an error message, the support queue fills up, and someone will propose a bypass.
Build three exits before launch:
- Move the parcel to a staffed point. A person checks age at handover. This is the one method the Swedish ruling leaves alone, and the retailer’s release says so.
- Allow a named collector. The buyer nominates someone, and that person goes through their own check. Don’t allow it for products where the buyer must be the collector.
- Refund automatically if the parcel isn’t collected in a fixed number of days.
Cost, as a model
This is my assumption, not customer data. Say you ship 10,000 age-restricted orders a month to lockers. Each needs a purchase check and a handover check.
If the handover is billed as a returning-user Check at the Growth list rate of €0.02, that is 10,000 × €0.02 = €200 a month. Before you count the included Check allowance, a staffed-point fallback and the cost of a locker camera, if you choose that row. Compare it with a closed shop. Snusnetto had about 500 active customers. A larger retailer with a larger share of locker orders would have far more at stake. The prices are on the pricing page.
One plan detail matters here. Basic stops when its Check allowance runs out. A stop at handover means paid-for parcels sit in lockers while the buyer can’t open them. Starter, Growth and Scale keep metering past the allowance instead. For handover, a check that stops is a worse failure than one that costs a little extra.
What I could not confirm
- The dates of the two rulings, the case number and the law the court applied.
- The court’s own words. The reasoning above is a news report’s summary.
- How Haypp’s new check works.
- Whether other Swedish retailers must change now. Haypp calls the ruling a precedent for the industry. I haven’t seen a regulator say so.
- Whether the rule reaches outside Sweden. It doesn’t, as far as I know. The UK’s rules for knives are different, and are covered in our post on delivery binding. That law rules out lockers for residential knife deliveries in England and Wales.
None of this is legal advice.
How Xident fits
What it does. Xident can run a liveness check on the phone and match the live face to the face from the purchase check. The handover step reuses the purchase identity as a returning-user Check, and the answer is yes or no. Document images are deleted within 24 hours of processing, and each decision keeps its method, result, policy version and time.
What it does not do. Xident doesn’t make locker hardware and doesn’t read a camera inside the locker. A phone check sits in the “live face on the phone” row of the table. It narrows the gap. It doesn’t close it. If you need proof about the person who opens the door, you need a locker-side camera or a staffed point, and your locker vendor has to provide the first.
The free sandbox gives a one-time allowance of 1,000 Checks and 100 document Verifications. That is enough to run a purchase-to-collection flow end to end before you change a locker contract.
Checklist for the next seven days
- List every age-restricted product that can go to a locker or pickup point. Include nicotine, vapes, alcohol, knives and medicines.
- For each, write which row of the table your handover is in today.
- If it’s “code” or “login”, mark it as the gap.
- Ask your locker vendor in writing whether a live face check, a camera or a staffed point is possible.
- Add the decision function above, or its equivalent, between “locker event” and “open door”.
- Build the three exits for failed checks.
- Store the policy version, method, result and time for every handover.
- Turn off locker delivery for the gap products until steps 4 to 7 are done, if your lawyer says you must.
The short version
Sweden’s courts said a BankID check at the locker doesn’t prove who collects the order. It proves the login. Haypp closed a shop and is rolling out a check of the person who opens the locker.
The rule behind it asks for an age check at purchase and again at handover. Most flows do the first and call a typed code the second. Look at what each of your handover methods proves, and make the locker open only for a person you checked.
Xident provides age and identity verification infrastructure, with decision records kept in place of images and a returning-user Check priced about ten times below a document Verification. Talk to us about checking the person at handover, not just the login.