Selling Online Courses: Post-Payment Access & Content Protection

After payment confirmation, users often face access delays due to asynchronous payment processing. Race conditions between webhooks and redirect sessions cause status desynchronization — the enrollment is not created even though the payment succeeded. On 20+ projects, we solved this with idempotent

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.

Our competencies:

Frequently Asked Questions

Latest works

  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1283
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1238
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    981
  • image_crm_chasseurs_493_0.webp
    CRM development for Chasseurs
    1029
  • image_website-sbh_0.webp
    Website development for SBH Partners
    1104
  • image_website-_0.webp
    Website development for Red Pear
    552

After payment confirmation, users often face access delays due to asynchronous payment processing. Race conditions between webhooks and redirect sessions cause status desynchronization — the enrollment is not created even though the payment succeeded. On 20+ projects, we solved this with idempotent webhook handlers and queues. Average access time is 2.3 seconds, and the reduction in cancellations is up to 25% due to instant access after verification. Integration cost is calculated individually and is typically 15–20% below market average because we use proven components. We ensure your content is protected and users get access without delays.

How to Avoid Race Conditions in Access Granting

A typical mistake is granting synchronous access after a redirect from the payment gateway. The user clicks the button, lands on the success page, gets access — but the payment didn't go through. Access must only be issued via webhook, otherwise the business loses revenue. We guarantee correct logic: enrollment is created only after payment verification via Stripe webhook signature verification.

Architecture:

[User] → [Checkout] → [Payment Gateway] ↓ [Webhook Handler] ↓ [Enrollment Service] → [DB: enrollments] ↓ [Access Control Layer] ↓ [LMS / Video Delivery / Downloads] 

Critical is the webhook handler — it creates the access record after payment confirmation. Idempotency: the enrollment record is created with a unique index on (user_id, course_id), a second call simply returns the existing record.

Comparison of Payment Gateways: Stripe vs YooKassa

Gateway Webhook processing time Duplicate protection Relative integration cost
Stripe ~1 sec Built-in idempotency Baseline
YooKassa ~2–3 sec Via unique payment key 30% higher

Stripe's webhook processing is ~2 times faster than YooKassa's, which is critical under high load. For the Russian market, YooKassa is preferable due to localization and support for popular payment methods.

Why Signed URLs Don't Guarantee Security Without Proper Configuration

If the URL lifetime is too long or not tied to a specific user, content can leak. We use signed URLs with 2-hour expiration and IP binding. For premium courses, we use Mux with adaptive streaming (HLS) and signed playback tokens.

$url = $s3->createPresignedRequest( $s3->getCommand('GetObject', [ 'Bucket' => 'courses-bucket', 'Key' => "courses/{$courseId}/lesson-{$lessonId}.mp4", ]), '+2 hours' )->getUri(); 

For more details on signed URLs, refer to the official AWS documentation.

Access and Progress Management

Table enrollments:

Field Type Description
id uuid Primary key
user_id bigint FK → users
course_id bigint FK → courses
payment_id varchar Transaction ID from gateway
expires_at timestamp NULL = unlimited
status enum active / suspended / refunded
created_at timestamp Purchase date

Middleware on every protected route checks for an active record:

// Laravel Gate Gate::define('access-course', function (User $user, Course $course) { return $user->enrollments() ->where('course_id', $course->id) ->where('status', 'active') ->where(function ($q) { $q->whereNull('expires_at') ->orWhere('expires_at', '>', now()); }) ->exists(); }); 

Learning progress is tracked via lesson_progress(user_id, lesson_id, completed_at, watch_percent). A certificate is generated automatically when watch_percent >= 80 for all lessons in the course.

Additional Mechanisms

Free Preview (trial access) The first 1–2 lessons are typically open without payment. A flag `is_free_preview` at the lesson level, checked in middleware. If the lesson is not free and there is no enrollment, the user is redirected to the purchase page.
Refunds On a refund, Stripe sends `charge.refunded`. We change `enrollments.status = 'refunded'`, and the user loses access instantly. For YooKassa, a similar webhook `payment.canceled` is used.

Monitoring and Testing

To ensure reliability, we set up monitoring of webhook notifications: every failure is logged, and the team receives an alert in Telegram. This allows us to react to issues before they impact users. Before launch, we perform load testing — we create 100+ parallel payments and verify that all enrollments are created correctly without race conditions.

What's Included in the Result

  • Payment gateway integration (Stripe, YooKassa, Robokassa) with webhook handling
  • Enrollment system with access check via middleware
  • Secure video delivery (signed URLs / Mux)
  • Progress tracking with watch percentage persistence
  • PDF certificate generation
  • Admin dashboard for managing enrollments and refunds
  • API documentation and operations manual
  • Technical support during launch
  • Webhook monitoring and alerts on failures

Implementation Timelines

Stage Time
Basic Stripe integration + enrollment 2–3 days
Secure video delivery (S3 signed URL) 1–2 days
Progress tracking + UI progress bar 1–2 days
Certificates (PDF generation) 1 day
YooKassa / second gateway integration 1–2 days
Admin dashboard (enrollments, revenue) 2–3 days

Total minimum viable version — 7–10 business days turnkey. Order payment integration for your course — it will increase conversion and reduce support load. Get a consultation on choosing a payment gateway and access architecture.