Overview

Ananas GDS uses a tiered SaaS subscription model processed through Stripe. Each company account has one active subscription that gates feature access — the number of partner connections, API keys, photos, properties, and invoices permitted per month all depend on the active plan tier. The free tier is always available with reduced limits.

Subscription scope

Subscriptions are per owner account . Sub-users share the owner's plan and do not hold their own subscriptions.

Subscription Plans

Plans are defined in the SubscriptionPlan model and served from the database, making them configurable without a code deploy. Each plan carries a structured features JSON payload that gates behaviour at the application level.

Field Type Description
name string Unique plan name (e.g. Silver, Gold).
category enum silver | gold | platinum | diamond
price decimal Price in account currency (EUR for EU accounts).
default_cycle enum monthly | yearly
badge string Optional label shown in the UI, e.g. Popular .
features JSON Key/value feature limits (properties, photos, api_keys, invoices_per_month, etc.).
benefits JSON array Human-readable benefit strings shown on the pricing page.
is_popular boolean Highlights the plan card in the pricing UI.

Known Tier Limits

Limit Free Silver (€44/mo) Gold+
Properties 1 3 Unlimited
Photos per property 10 30 Unlimited
API Keys 1 3 Unlimited
Partner connections 3 10 Unlimited
Invoices per month 30 150 Unlimited
Data refresh interval 24 h 1 h Real-time

User Subscription

UserSubscription is a OneToOne relation from the owner user to an active plan. It tracks billing cycle, renewal state, and the Stripe subscription reference.

Field Description
plan FK to SubscriptionPlan . null means free tier.
is_active Whether the subscription is currently valid.
start_date / end_date Subscription validity window.
billing_cycle monthly or yearly .
auto_renew If true, Stripe will charge at period end.
cancel_at_period_end Stripe cancellation flag — plan remains active until end_date .
provider_subscription_id Stripe sub_xxx ID.
stripe_customer_id Stripe cus_xxx ID.
renewal_attempts Count of failed renewal attempts before cancellation.
next_billing_date Date of the next scheduled charge.

Billing & Cards

Payment cards are stored as Stripe payment method references — raw card numbers never touch Ananas GDS servers. The PaymentCard model holds the last 4 digits and expiry for display, plus the Stripe token for charges.

Model Purpose
PaymentCard Saved payment methods. One card can be marked is_primary for automatic renewals.
BillingAddress OneToOne to owner user. Stores company name, VAT number, country, and billing email for invoice generation.
BillingHistory Immutable record of every charge: amount, net, VAT, provider reference, status, and optional PDF file.

Stripe Integration

Ananas GDS uses Stripe for card tokenisation, payment intent creation, and subscription management. The flow follows Stripe's recommended Payment Intents + Setup Intents pattern to support 3D Secure.

1
Setup Intent — frontend calls POST /api/payments/stripe/setup-intent/ to get a client secret for Stripe.js card collection without storing raw numbers.
2
Attach Method — after Stripe.js confirms, POST /api/payments/stripe/attach-method/ links the payment method to the customer and saves a PaymentCard record.
3
Payment Intent — POST /api/payments/stripe/payment-intent/ initiates the charge for plan upgrade.
4
Verify — POST /api/payments/verify-payment/ confirms the payment intent succeeded and activates the new plan.
5
Webhook — Stripe posts events to /api/payments/stripe/webhook/ . Events handled: invoice.payment_succeeded , invoice.payment_failed , customer.subscription.deleted , and customer.subscription.updated .

Webhook signature verification

The Stripe webhook endpoint is CSRF-exempt and verifies every incoming request using the STRIPE_WEBHOOK_SECRET environment variable. Never expose this secret.

API Endpoints

Method Path Description
GET /api/payments/plans/ List all active subscription plans with features and pricing.
GET /api/payments/overview/ Current subscription, card list, billing address, and billing history for the authenticated user.
GET/PUT /api/payments/billing-address/ Retrieve or update billing address (company name, VAT, country, etc.).
POST /api/payments/subscription/upgrade/ Upgrade or change the current plan. Body: {plan_id, billing_cycle} .
POST /api/payments/subscription/cancel/ Schedule cancellation at period end. Does not revoke access immediately.
POST /api/payments/subscription/resume/ Resume a subscription that was set to cancel at period end.
POST /api/payments/subscription/auto-renew/ Toggle auto-renew on or off.
POST /api/payments/subscription/renew-now/ Force an immediate renewal attempt.
GET /api/payments/cards/ List saved payment cards.
DELETE /api/payments/cards/{id}/ Remove a saved card.
POST /api/payments/cards/set-primary/{id}/ Set a card as the default for auto-renewal.
GET /api/payments/invoice/{invoice_number}/download/ Download the PDF billing invoice for a past charge.
POST /api/payments/stripe/setup-intent/ Create a Stripe SetupIntent for card collection.
POST /api/payments/stripe/attach-method/ Attach a confirmed Stripe payment method to the customer.
POST /api/payments/stripe/payment-intent/ Create a PaymentIntent for a plan charge.
POST /api/payments/verify-payment/ Confirm payment succeeded and activate the plan.
POST /api/payments/stripe/webhook/ Stripe webhook receiver (CSRF-exempt, signature-verified).

Feature Gating

The FeatureAccess service reads the features JSON from the active plan and compares against current usage. Views that enforce tier limits call this service before permitting the action — for example, before creating a new API key or partner connection. When a limit is reached the API returns HTTP 403 with a message indicating which feature is restricted.

Checking your plan from the API

Call GET /api/payments/overview/ to inspect your current plan, usage counters, and next billing date in one request.