E-book PDF and EPUB sales on website

Our company is engaged in the development, support and maintenance of sites of any complexity. From simple one-page sites to large-scale cluster systems built on micro services. Experience of developers is confirmed by certificates from vendors.
Development and maintenance of all types of websites:
Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Showing 1 of 1 servicesAll 2065 services
E-book PDF and EPUB sales on website
Medium
~3-5 business days
FAQ
Our competencies:
Development stages
Latest works
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1041
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    822
  • image_crm_chasseurs_493_0.webp
    CRM development for Chasseurs
    847
  • image_website-sbh_0.png
    Website development for SBH Partners
    999
  • image_website-_0.png
    Website development for Red Pear
    451

Implementing Electronic Book Sales (PDF/EPUB) on a Website

Digital book sales are simpler than courses, but still require nontrivial solutions: file protection from free distribution, fast delivery after payment, optional DRM, and correct refund handling.

File Delivery Schema

Main rule: files must not be in publicly accessible directory. No /public/books/my-book.pdf. Storage — S3-compatible object storage (AWS S3, Cloudflare R2, MinIO) without public ACL.

After payment confirmation, user receives temporary signed link:

// Laravel + AWS S3
$url = Storage::disk('s3')->temporaryUrl(
    "books/{$book->file_key}",
    now()->addHours(48),
    ['ResponseContentDisposition' => 'attachment; filename="' . $book->filename . '"']
);

Link lives 48 hours. Redownload via personal account — each time generates new link. Download count can be limited: table download_attempts(purchase_id, downloaded_at), limit — e.g., 5 downloads per purchase.

Payment Integration

For digital goods, Stripe recommends payment_intent or checkout.session. Key moment — tax flag: digital books in some jurisdictions have different VAT than physical goods. Stripe Tax can auto-detect by payer IP/address.

const session = await stripe.checkout.sessions.create({
  mode: 'payment',
  line_items: [{
    price: book.stripe_price_id, // pre-created Price in Stripe Dashboard
    quantity: 1,
  }],
  automatic_tax: { enabled: true },
  metadata: { book_id: book.id, user_id: user.id },
  success_url: `${APP_URL}/library?session_id={CHECKOUT_SESSION_ID}`,
  cancel_url: `${APP_URL}/books/${book.slug}`,
});

Webhook checkout.session.completed creates purchases record and sends email with download link.

Data Structure

CREATE TABLE purchases (
    id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id     BIGINT REFERENCES users(id),
    book_id     BIGINT REFERENCES books(id),
    payment_id  VARCHAR(255) UNIQUE,
    amount_cents INT,
    currency    VARCHAR(3),
    status      VARCHAR(20) DEFAULT 'completed', -- completed | refunded
    created_at  TIMESTAMP DEFAULT NOW()
);

CREATE TABLE download_attempts (
    id          BIGSERIAL PRIMARY KEY,
    purchase_id UUID REFERENCES purchases(id),
    ip_address  VARCHAR(45),
    user_agent  TEXT,
    created_at  TIMESTAMP DEFAULT NOW()
);

Formats: PDF vs EPUB

Most customers prefer PDF for desktop reading and EPUB for mobile readers (Kindle, Apple Books, Kobo). Selling both formats in one purchase is good practice.

Store files with different suffixes in one bucket:

books/
  {uuid}-original.epub
  {uuid}-print.pdf
  {uuid}-cover.jpg

Table book_files(book_id, format, file_key, file_size_bytes).

Optional Watermark

For expensive books, add personalized watermark with buyer's email. Not DRM, but psychologically restrains distribution.

PDF watermark via pypdf (Python) or iTextSharp (.NET). In PHP ecosystem — setasign/fpdi:

use setasign\Fpdi\Fpdi;

$pdf = new Fpdi();
$pageCount = $pdf->setSourceFile($sourcePath);

for ($i = 1; $i <= $pageCount; $i++) {
    $pdf->AddPage();
    $pdf->useTemplate($pdf->importPage($i));
    $pdf->SetFont('Helvetica', '', 8);
    $pdf->SetTextColor(180, 180, 180);
    $pdf->SetXY(10, 285);
    $pdf->Write(0, "Licensed to: {$purchase->user->email}");
}

$pdf->Output($outputPath, 'F');

Generation happens async in queue (Laravel Jobs / Bull / Celery), then link updates. For books under 10 MB takes 2–5 seconds.

Email Delivery

After purchase, email with download button should arrive within 30–60 seconds. Don't do sync in HTTP request — send via queue:

// In webhook handler
ProcessPurchase::dispatch($purchase)->onQueue('purchases');

// In Job
class ProcessPurchase implements ShouldQueue {
    public function handle() {
        // 1. Generate watermark (optional)
        // 2. Create signed URL
        // 3. Send email
        Mail::to($this->purchase->user)->send(
            new BookPurchasedMail($this->purchase, $downloadUrl)
        );
    }
}

Personal Library

User should redownload book via /library. List all purchases with "Download" button, calls endpoint generating new temporary URL. Important — storing permanent link in DB is useless, it expires.

Timelines

Task Time
File upload, S3, protection 1 day
Payment integration + webhook 1–2 days
Personal library, redownload 1 day
Email delivery 0.5 day
Watermark (PDF) 1–2 days

Basic implementation without watermark — 3–4 days.