Tax Required
Keep evidence of where the customer is
For digital services sold to consumers, store two pieces of evidence of the customer's country that agree, with each order.
How to do it
EU VAT on electronically supplied services follows the consumer's country. Implementing Regulation 282/2011 lets you rely on two items that do not contradict each other. Examples are the billing address, the IP address country and the card's issuing country. Collect all three. Store the country found from the IP address, not the address itself, as keep only what you need asks. When they disagree, ask the customer, or use the two that match. Several countries outside the EU tax digital services in a similar way.
Example
function customerCountry({ billingCountry, ipCountry, cardCountry }) {
const votes = [billingCountry, ipCountry, cardCountry].filter(Boolean)
const country = votes.find(candidate => votes.filter(vote => vote === candidate).length >= 2)
if (!country) throw new Error('Location evidence does not agree. Ask the customer.')
return { country, evidence: { billingCountry, ipCountry, cardCountry } }
}
from collections import Counter
def customer_country(billing_country: str | None, ip_country: str | None, card_country: str | None) -> dict:
votes = Counter(c for c in (billing_country, ip_country, card_country) if c)
country, count = votes.most_common(1)[0] if votes else (None, 0)
if count < 2:
raise LocationUnclear("Location evidence does not agree. Ask the customer.")
return {"country": country, "evidence": [billing_country, ip_country, card_country]}
How to check
A query over last month's consumer orders finds none with fewer than two matching evidence items.
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 payments playbook: https://agentwranglers.se/playbook/payments/tax/customer-location-evidence.