diff --git a/routes/static_routes.py b/routes/static_routes.py index 112add4c..6e9114dc 100644 --- a/routes/static_routes.py +++ b/routes/static_routes.py @@ -116,6 +116,33 @@ async def terms_of_service(request: Request) -> Response: ) +@router.get("/docs/refund-policy") +@router.get("/legal/refund-policy") +@router.get("/refund-policy") +@router.get("/refund") +@limiter.exempt +async def refund_policy(request: Request) -> Response: + return templates.TemplateResponse( + request, + "legal/refund-policy.html", + {"host_url": str(request.base_url)}, + ) + + +@router.get("/docs/acceptable-use-policy") +@router.get("/legal/acceptable-use-policy") +@router.get("/acceptable-use-policy") +@router.get("/acceptable-use") +@router.get("/aup") +@limiter.exempt +async def acceptable_use_policy(request: Request) -> Response: + return templates.TemplateResponse( + request, + "legal/acceptable-use-policy.html", + {"host_url": str(request.base_url)}, + ) + + @router.get("/docs/{path:path}") @limiter.exempt async def docs_wildcard(path: str, request: Request) -> Response: diff --git a/shared/reserved_aliases.py b/shared/reserved_aliases.py index 263d41c6..b178ab24 100644 --- a/shared/reserved_aliases.py +++ b/shared/reserved_aliases.py @@ -17,8 +17,11 @@ RESERVED_ALIASES: frozenset[str] = frozenset( { "about", + "acceptable-use", + "acceptable-use-policy", "api", "apps", + "aup", "auth", "billing", "blog", @@ -59,6 +62,8 @@ "profile", "profile-pictures", "public", + "refund", + "refund-policy", "register", "restore-account", "relay", diff --git a/templates/legal/acceptable-use-policy.html b/templates/legal/acceptable-use-policy.html new file mode 100644 index 00000000..2b0e5857 --- /dev/null +++ b/templates/legal/acceptable-use-policy.html @@ -0,0 +1,96 @@ +{% extends "legal/base.html" %} + +{% block title %}Acceptable Use Policy - spoo.me{% endblock %} + +{% block content %} + Shield emoji +

Acceptable Use Policy

+
+ +

Effective 2026-09-XX.

+ +

This policy says what you may not do with spoo.me. It applies to every link, custom domain, API key, connected app, and account, free or paid. It is part of our Terms of Service. If you break it, we may block your links, slow your account down, or close it.

+ +
+ + + +

Do not shorten, share, or promote links that:

+ + + +
+ +

Every destination is checked

+ +

We screen every destination when a link is created and again over its lifetime. That includes the destination for each country when you set geo rules, every variant of a link, links behind a password, and links on custom domains.

+ +

Screening uses our own rules plus outside sources. We may block, remove, or report a link on our own judgement, even if no outside blocklist has flagged it yet. A blocked link shows a notice instead of redirecting.

+ +
+ +

Your account

+ + + +
+ + + +

No reselling. Pro is for you and your own projects or business. Do not sell access to your account, offer spoo.me link creation as a paid service of your own, or sublicense the API. If you want to build a product on top of spoo.me, email us first.

+ +

Unlimited links, in good faith. There is no cap on how many links you create for real use. Automated use that looks like abuse, such as link farms, creating and discarding links at machine speed, or using us as a load-testing target, may be throttled. Throttling slows down creating new links. It never stops your existing legitimate links from redirecting.

+ +

Custom domains you own. You may only connect a domain you own or are authorised to manage, and we verify that through DNS. Do not connect a domain that impersonates a brand, a person, or a service you do not represent. If a domain stops being yours, links on it stop and we may remove it.

+ +

Screening still applies. Paying for Pro does not exempt any destination, geo rule, or variant from the checks above.

+ +
+ +

What we do about it

+ +

Depending on how serious it is, we may warn you, throttle your account, block the links involved, or suspend or close the account. When people are being harmed, we act first and tell you afterwards. Where the law requires it or the harm is serious, we report to the relevant authorities and blocklists.

+ +

If you think we got it wrong, email support@spoo.me with the link and we will look again.

+ +
+ +

Reporting abuse

+ +

If you find a spoo.me link that breaks this policy, report it at spoo.me/report or email support@spoo.me. Reports are handled ahead of everything else.

+ +
+ +

Governing law

+ +

This policy is part of our Terms of Service and follows the same governing law, the laws of the Netherlands. If you live in the EU, nothing here affects your rights under the consumer protection laws of your country of residence.

+ +
+ +

Changes to this policy

+ +

We may update this policy. When we do, we change the effective date at the top, and we notify registered users of changes that matter.

+ +
+ +

Contact

+ +

Questions about this policy go to support@spoo.me.

+ +

Support Team, spoo.me

+{% endblock %} diff --git a/templates/legal/refund-policy.html b/templates/legal/refund-policy.html new file mode 100644 index 00000000..32e380dd --- /dev/null +++ b/templates/legal/refund-policy.html @@ -0,0 +1,97 @@ +{% extends "legal/base.html" %} + +{% block title %}Refund Policy - spoo.me{% endblock %} + +{% block content %} + Receipt emoji +

Refund Policy

+
+ +

Effective 2026-09-XX.

+ +

This policy covers payments for spoo.me Pro. It is short on purpose. If anything is unclear, email support@spoo.me and a person will answer.

+ +
+ +

Who charges your card

+ +

Paddle is our Merchant of Record. Paddle is the seller on your receipt, collects the payment, and handles any sales tax or VAT owed where you live. Paddle also issues refunds on our behalf. The charge on your bank statement shows Paddle's name next to spoo.me.

+ +

Prices on our pricing page are before tax. Paddle adds any tax at checkout based on your location.

+ +
+ +

What Pro costs

+ + + +
+ +

14 days, no questions

+ +

You can get a full refund within 14 days of your first payment, on both the monthly and the annual plan. You do not need to give a reason.

+ +

To ask for one, email support@spoo.me from the address on your account with "Refund" in the subject. We ask Paddle to refund the charge, and Paddle sends the money back to the payment method you used. Banks usually show it within 5 to 10 business days.

+ +

Your plan goes back to Free as soon as the refund is issued. Nothing is deleted. Your links keep redirecting, your click data stays, and your account stays. Pro-only features turn off, as described under Going back to Free.

+ +

The 14 days count from your first payment. Monthly renewals are not refundable, but you can cancel before a renewal and you will not be charged again.

+ +
+ +

After 14 days

+ +

Monthly. Cancel any time from Billing in your dashboard or by emailing us. Pro stays on until the end of the month you already paid for, then your account goes to Free. There are no further charges. We do not refund the remaining days of a month.

+ +

Annual. The prepaid year is non-refundable after the first 14 days. Pro stays on until the 12 months end, plus a 14-day grace window so you have time to buy another year. Because the year does not renew, there is nothing to cancel and no surprise charge.

+ +
+ +

Switching plans

+ +

To move from monthly to annual, buy the annual plan. Your monthly subscription ends at the close of the period you already paid for, and the annual plan starts from its purchase date. We do not prorate.

+ +
+ +

Failed payments

+ +

If a monthly renewal fails, Paddle retries the card for a few days and emails you. If the payment still cannot be collected, the subscription ends and your account goes to Free under the same rules as below.

+ +
+ +

Going back to Free

+ +

Whether Pro ends through a refund, a cancellation, or a year running out, the same things happen:

+ + + +
+ +

Your rights

+ +

This policy is part of our Terms of Service and follows the same governing law, the laws of the Netherlands. If you live in the EU, nothing here affects your rights under the consumer protection laws of your country of residence.

+ +
+ +

Changes to this policy

+ +

We may update this policy. When we do, we change the effective date at the top, and we email paying subscribers about changes that affect them.

+ +
+ +

Contact

+ +

Questions about a charge or a refund go to support@spoo.me. Put "Refund" in the subject and we will find your payment faster.

+ +

Support Team, spoo.me

+{% endblock %} diff --git a/tests/integration/test_static_routes.py b/tests/integration/test_static_routes.py index 8e80a700..dabf64a6 100644 --- a/tests/integration/test_static_routes.py +++ b/tests/integration/test_static_routes.py @@ -181,6 +181,36 @@ def test_terms_of_service_alias(): assert "text/html" in resp.headers["content-type"] +def test_refund_policy_renders(): + app = _build_test_app() + with TestClient(app) as c: + resp = c.get("/refund") + assert resp.status_code == 200 + assert "Paddle is our Merchant of Record" in resp.text + + +def test_refund_policy_alias(): + app = _build_test_app() + with TestClient(app) as c: + resp = c.get("/legal/refund-policy") + assert resp.status_code == 200 + + +def test_acceptable_use_policy_renders(): + app = _build_test_app() + with TestClient(app) as c: + resp = c.get("/acceptable-use") + assert resp.status_code == 200 + assert "Every destination is checked" in resp.text + + +def test_acceptable_use_policy_alias(): + app = _build_test_app() + with TestClient(app) as c: + resp = c.get("/aup") + assert resp.status_code == 200 + + # ── Contact ────────────────────────────────────────────────────────────────── diff --git a/tests/smoke/test_routes_registered.py b/tests/smoke/test_routes_registered.py index 2d0aa211..84997124 100644 --- a/tests/smoke/test_routes_registered.py +++ b/tests/smoke/test_routes_registered.py @@ -124,6 +124,11 @@ def test_all_expected_paths_registered(smoke_app: FastAPI) -> None: "/privacy", "/tos", "/terms-of-service", + "/refund", + "/refund-policy", + "/acceptable-use", + "/acceptable-use-policy", + "/aup", "/docs/{path:path}", "/contact", "/report",