Launched this week

LinkVault
Digital downloads for Stripe Payment Links
15 followers
Digital downloads for Stripe Payment Links
15 followers
LinkVault is a Bun + React app for secure digital downloads after Stripe Payment Link checkout. Sync Stripe products, upload files, verify Checkout Sessions, generate expiring download links, and email customers via Resend.


How does the link expiration actually work in practice, like can you set different expiry windows per product or is it a single global setting across everything in LinkVault?
@sultansr23 Right now it's a single global setting, not per-product — DOWNLOAD_TOKEN_TTL_HOURS (default 7 days) and DOWNLOAD_MAX_USES (default 5), set once for the whole shop. Since LinkVault is self-hosted you can dial those to whatever you want, but today every product inherits the same window.
The thing I'd point out: the budget is enforced per order, not per link. Expiry is anchored to the moment the order is first fulfilled, and downloads are counted across every link issued for that order. So if a buyer reloads the success page they get a fresh URL, but it doesn't extend the expiry or hand them 5 more downloads — no accidental infinite-download loophole from sharing the page.
Per-product expiry windows are a fair ask though. Is your use case "some products are evergreen, some are time-limited," or more like "big files need a longer window"? Helps me scope it properly.
How does the file delivery actually get verified, like is the download link tied to the Stripe checkout session ID or are you using signed URLs with a separate token? Trying to figure out how hard it would be to share links around once they're generated.
@sedefs19749 Separate token, not the Stripe session ID. When an order is fulfilled, LinkVault mints 32 bytes of CSPRNG randomness as an opaque bearer token and stores only its SHA-256 hash — so the link isn't derived from anything guessable, and a database leak doesn't yield usable links. It's not an HMAC-signed URL either; there's no state encoded in it, just a random handle pointing at a row.
To your actual question: yes, a generated link is shareable. Possession of the URL is the auth — there's no email or IP binding on the download route. That's deliberate, because binding to IP breaks people who buy on desktop and download on their phone, and binding to a login means building accounts for a product whose whole point is not having them.
What contains it is the budget: the download cap is enforced per order, not per link, and summed across every link ever issued for that order in a single atomic UPDATE. So a buyer who posts their link publicly is spending their own 5 downloads, and the whole thing expires 7 days after fulfilment. Sharing is possible; sharing at scale isn't.
If you need it truly locked down, the hooks are there — the token is already a row you can revoke, and an email-confirmation step before the byte stream would be a small addition.
How does the expiring link window work for buyers who lose internet mid-download, and can you adjust the expiry per product or is it one global setting?
@melahatftbr Hi, thank you for your question. Loosing internet mid-session is not a problem as the link is valid for several days and for up-to N downloads configurable via .env
How does LinkVault handle files larger than the typical Resend attachment limit, or does it just send a download link either way?
@sraaf2l Thank you very much for your question. The files are not sent by resend. The files are stored on the server and only a secure link to them is sent to the client.
Finally a tool that handles the whole Stripe-to-file handoff without duct tape. The expiring link setup saved me from wiring up a separate cron job for cleanup.
the choice to verify Stripe Checkout Sessions on the server side instead of trusting client callbacks shows real care for security — wish more download tools handled it this cleanly.