Payments & Subscriptions
Manage subscription plans, billing, payment cards, and Stripe integration for Ananas GDS accounts.
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.
POST /api/payments/stripe/setup-intent/
to get a client secret for Stripe.js card collection without storing raw numbers.
POST /api/payments/stripe/attach-method/
links the payment method to the customer and saves a
PaymentCard
record.
POST /api/payments/stripe/payment-intent/
initiates the charge for plan upgrade.
POST /api/payments/verify-payment/
confirms the payment intent succeeded and activates the new plan.
/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.