Technical Documentation
Everything you need to understand, integrate with, and build on the Publica Now platform.
Overview
Publica Now is a creator economy platform for independent publishers in Latin America and beyond. Creators publish and sell articles, books, audio, visual art, and courses. Readers discover, purchase, and consume content directly on the platform.
Stack
Laravel 12 + Livewire 4
PHP 8.4 · Tailwind CSS · SQLite/MySQL
Payments
Stripe
Adaptive Pricing · Multi-currency at checkout
Content Delivery
Publica.la Reader
EPUB · PDF · Audio · SSO Auth
Design principle
Publica Now owns the storefront, payments, and creator relationships. Third-party services (Publica.la, Stripe) are pluggable infrastructure behind clean interfaces. If a provider changes, the creator and reader experience stays the same.
Architecture
The platform follows a server-rendered architecture with Livewire single-file components. No separate frontend SPA or API layer needed for the main application.
Domain Model
| Entity | Description | Key Relations |
|---|---|---|
| User | Authenticated account. Can be a reader, a creator, or both. | has one Creator, many Purchases, Subscriptions |
| Creator | Publisher profile with slug, bio, branding, and store domain. | belongs to User, has many Works, Articles, Memberships |
| Work | Marketplace content item — book, album, course, zine, etc. | belongs to Creator, has many WorkArtifacts, Reviews, Purchases |
| WorkArtifact | A file attached to a work — EPUB, PDF, audio, image. | belongs to Work |
| Article | Blog-style post by a creator. Free or behind a membership. | belongs to Creator, has many Likes, Shares |
| Membership | Subscription tier defined by a creator (e.g., "Pro", "Patron"). | belongs to Creator, has many Subscriptions |
| Purchase | One-time payment record for a work. | belongs to User and Work |
| Subscription | Active recurring subscription to a creator's membership tier. | belongs to User and Membership |
| Category / Vibe | Taxonomy for organizing works in the marketplace. | Works belong to Category, many-to-many with Vibes |
External Services
Publica.la
Content delivery and DRM. Hosts EPUB/PDF/audio reader. Accessed via REST API v3 + JWT SSO.
Stripe
Hosted Checkout with Adaptive Pricing. Buyer sees their local currency at checkout; creators settle in their chosen currency.
AWS S3
Object storage for work artifacts, covers, and generated files. Accessed via temporary signed URLs.
Content Types
Every work has a content_type that determines its presentation, CTA labels, and delivery format.
Books, essays, short stories, novellas
Formats: EPUB, PDF
Poetry collections, chapbooks
Formats: EPUB, PDF
Albums, singles, playlists, scores
Formats: Audio files
Illustrations, graphic novels, design assets
Formats: Images, PDF
Photo essays, portfolios, prints
Formats: Images, PDF
Short films, documentaries, video essays
Formats: Video files
Online courses, tutorials, workshops
Formats: Mixed media
Independent magazines, zines, pamphlets
Formats: PDF, EPUB
Pricing Models
| Model | Behavior | Fields |
|---|---|---|
free |
Instant access, no payment required | price_cents = 0 |
one_time |
Single purchase grants permanent access | price_cents, currency |
pay_what_you_want |
Buyer chooses amount (optional minimum) | price_cents (floor), currency |
subscription |
Access while subscribed to creator's membership tier | Linked via Membership |
URL Structure
All public URLs are human-readable and SEO-friendly. Works are always scoped under their creator.
| Pattern | Description | Example |
|---|---|---|
| / | Homepage with featured works | publica.now |
| /browse | Marketplace catalog with filters | /browse?content_type=literary |
| /discover | Curated discovery feed | /discover |
| /creators/{slug} | Creator public profile and catalog | /creators/pablo-laurino |
| /creators/{slug}/works/{slug} | Work landing page with embedded reader | /creators/pablo-laurino/works/mi-semana |
| /search?query={q} | Full-text search across works and creators | /search?query=poetry |
| /library | Reader's purchased/accessed works | /library |
| /dashboard/* | Creator dashboard (works, analytics, earnings, settings) | /dashboard/works |
Slugs are auto-generated from titles using spatie/laravel-sluggable and are unique per model.
Creator API
Creators manage content through the dashboard UI. Under the hood, the platform exposes a consistent data model for potential API access.
Creator Profile
{
"id": "01jk...",
"name": "Pablo Laurino",
"slug": "pablo-laurino",
"bio": "Independent publisher from Buenos Aires.",
"website": "https://example.com",
"avatar_url": "https://...",
"banner_url": "https://...",
"store_domain": "pablo.publica.now",
"branding": {
"primary_color": "#ff6b35",
"font": "inter"
}
}
Work Object
{
"id": "01jk...",
"creator_id": "01jk...",
"title": "Mi Semana",
"slug": "mi-semana",
"content_type": "literary",
"format": "EPUB",
"status": "published",
"pricing_model": "free",
"price_cents": 0,
"currency": "usd",
"description": "A weekly editorial...",
"tags": ["editorial", "weekly", "culture"],
"cover_image_url": "works/01jk.../cover.png",
"view_count": 342,
"rating_avg": 4.50,
"rating_count": 12,
"published_at": "2026-03-01T00:00:00Z",
"metadata": {
"publica_la_id": "abc123",
"publica_la_slug": "mi-semana",
"publica_la_reader_url": "https://publicanow.publica.la/reader/mi-semana"
}
}
Works Lifecycle
A work progresses through distinct stages from creation to consumption.
Upload
Creator uploads files (EPUB, PDF, images, audio) via the dashboard. Files are stored on S3. A WorkArtifact record is created per file.
Convert
If needed, content is converted: HTML to EPUB (via ContentConversionService), images to PDF gallery, and a default cover is generated if none is uploaded.
Sync to Publica.la
The SyncWorkToPublicaLa job uploads the primary artifact to Publica.la via their Content API. The returned ID, slug, and reader URL are stored in the work's metadata.
Publish
Creator sets status to "published". The work appears in the marketplace, search results, and the creator's public profile.
Purchase / Access
When a reader buys the work (or accesses a free work), a Permission Order is created on Publica.la granting reader access.
Read
The Publica.la reader is embedded in the work landing page via iframe. Users are authenticated through JWT SSO and can consume the content without leaving the site.
Content Conversion Pipeline
HTML → EPUB: Rich text body is sanitized to valid XHTML via DOMDocument, then packaged as EPUB 3.0 with metadata (title, author, language, cover).
Images → PDF: Image artifacts are read from S3, base64-encoded, and composed into a single PDF (one image per page) using DomPDF.
Cover generation: When no cover is uploaded, a 1600×2400 PNG is generated using GD with Inter TTF fonts, featuring the title, author name, content type, and platform branding.
Payments
Payments run on Stripe Checkout with Adaptive Pricing. Creators set a price in their chosen currency; Stripe presents buyers their local currency at checkout and handles the FX. The platform settles in the creator's currency.
Supported pricing currencies
Creators can price work in: USD, EUR, GBP, MXN, BRL, ARS, COP, CLP, PEN, UYU. Buyers see their local currency at checkout regardless of the creator's choice.
Payment Flow
Reader clicks "Buy" on work landing page
|
v
POST /checkout/{work}/pay
|
v
StripeService creates a Checkout Session
|-- mode: payment | subscription
|-- adaptive_pricing.enabled: true
|-- price_data with creator's currency + amount
|
v
302 redirect to Stripe-hosted checkout (checkout.stripe.com)
|
v
Buyer pays in their local currency (Stripe handles FX)
|
v
Two parallel paths fire:
(a) success_url → /checkout/{work}/callback
Best-effort idempotent purchase row for instant access
(b) checkout.session.completed webhook → ProcessStripeWebhook job
Canonical writer; dedupes on stripe_payment_intent_id
|
v
FulfillPurchaseOnPublicaLa job grants reader access
|
v
Reader can access content in embedded reader
Key design decision
Publica.la never processes payments. It only receives Permission Orders that grant content access. This keeps billing logic, refunds, disputes, and creator payouts entirely within Publica Now's control.
Content Delivery
Content is delivered through the Publica.la reader, embedded directly in the work landing page. This keeps the reading experience integrated with reviews, comments, and creator context.
Publica.la Integration
Communication with Publica.la happens via their REST API v3, authenticated with an API key (X-User-Token header).
Content API
POST /api/v3/content —
Upload new content (EPUB, PDF, audio). Returns content ID, slug, reader URL, and conversion status.
Orders API
POST /api/v3/orders —
Create permission orders to grant user access. Uses type: "permission" with external ID for idempotency.
SSO Authentication
POST /api/v3/auth-token —
JWT-based single sign-on (HS256). Token includes user UUID, email, intended reader URL, and exit URL.
Reader Embedding
The reader is embedded via iframe on the work show page. For authenticated users with access, the flow is:
1. ensureReadAccess(user, work) // Create permission order if needed
2. getReaderUrl(work) // e.g., /reader/mi-semana
3. generateAuthToken(user, url) // JWT with intended_url
4. getSsoUrl(token) // Full SSO login URL
5. Render iframe with SSO URL // User lands in reader, authenticated
The iframe uses sandbox attributes allow-same-origin allow-scripts allow-popups allow-forms for security while allowing the reader to function properly.
Authentication
Publica Now uses Laravel's built-in session authentication. For the embedded Publica.la reader, a separate JWT SSO mechanism bridges the two systems.
Platform Auth
Registration: Email + password via /register
Login: Email + password via /login
Session: Encrypted cookie-based sessions. CSRF protection on all forms (except webhooks).
Guest redirect: Unauthenticated users are redirected to /login
JWT SSO (Publica.la)
When a user needs to access the embedded reader, a short-lived JWT is generated:
{
"aud": "farfalla",
"sub": "user",
"iss": "publica-now",
"exp": 1709730000, // 60 seconds from now
"user": {
"uuid": "user-ulid",
"email": "[email protected]"
},
"intended_url": "/reader/mi-semana",
"reader_exit_url": "https://publica.now/creators/pablo/works/mi-semana"
}
Token is signed with HS256 using a shared secret. Expires in 60 seconds — only valid for the initial SSO redirect.
Webhooks
Publica Now receives webhooks from external services to stay in sync with payment status and content interactions.
| Endpoint | Source | Auth | Events |
|---|---|---|---|
| /webhooks/publica-la | Publica.la | JWT signature verification | sale, interaction |
| /webhooks/stripe | Stripe | Stripe-Signature header | checkout.session.completed, customer.subscription.deleted, invoice.paid, invoice.payment_failed |
All webhook endpoints are excluded from CSRF verification. Events are processed asynchronously via queued jobs with retry backoff (60s, 120s, 300s).
Embeds & Integrations
Publica Now supports embedding content and integrating with external systems.
Embedded Reader
The Publica.la reader is embedded directly in work pages. Authenticated users see the reader inline alongside reviews and creator info. Unauthenticated users see the cover image and a "Sign in to read" CTA.
File Storage
All files are stored on S3 and accessed via temporary signed URLs (1-hour expiry). Cover images resolve through the cover_url accessor which transparently handles both full URLs and S3 storage paths.
Queue Jobs
| Job | Trigger | Description |
|---|---|---|
| ConvertContentJob | Work published | Converts HTML to EPUB, images to PDF, generates cover |
| SyncWorkToPublicaLa | After conversion | Uploads artifact to Publica.la, stores returned metadata |
| FulfillPurchaseOnPublicaLa | Purchase completed | Creates permission order granting reader access |
| ProcessWebhookEvent | Webhook received | Processes payment and interaction events |
| SendWeeklyDigest | Scheduled (weekly) | Sends weekly activity digest to creators |
Questions or integration requests? Contact the team at [email protected]
© 2026 Publica Now. All rights reserved.