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.