Private billing offers
Redeem a company-specific discount, negotiated price or trial extension with a reviewed, recoverable quote.
A private offer belongs to a specific paying company and one product: its plan, employee seats or managed-company seats. A code for one product does not purchase the other two. Only the platform administrator creates or revokes offers. The application lets that administrator copy the code; it does not send it automatically.
Benefits and eligibility
| Benefit | Conditions |
|---|---|
discount | A percentage or fixed EUR amount, with once, repeating or forever duration. No implicit stacking with another discount. |
negotiated_price | An agreed net EUR unit price, including zero, no higher than the catalogue price. It lasts forever or for 1–24 billing periods, then returns to the pinned catalogue price. |
trial_extension | 1–90 additional days on an eligible active self-service plan trial, without restarting an expired trial. The cumulative trial cannot exceed 180 days from its reliable initial activation. |
An extra trial can accompany only a permanent plan discount or permanent negotiated plan price. Negotiated prices and standalone trials select one plan and billing interval. Temporary prices disclose the return date, future amount and payment-method requirement before the subsequent charge. Monthly and yearly periods are billing cycles, not interchangeable day counts. Enterprise contract pricing, managed companies acting as a plan customer and sandbox purchases are excluded.
Trial dates use UTC. The application shows the old and new end date and any billing-anchor change. A standalone extension does not force a card. Expired, paid, grace or cancelled plans cannot use it. Revoking a code stops future redemptions while preserving an already acquired benefit and its scheduled price reversion.
Redeem in context
In the application, enter the code from the relevant plan, employee or managed-company checkout. Billing also shows acquired benefits and operations. The code is private: do not put it in URLs, tickets, logs or shared examples. There is no anonymous registration campaign or automatic invitation flow.
REST and MCP expose employee and managed-company redemptions only. Plan redemptions and offer administration remain application-only. Use employees:write for /v1/employee-seat-offer-redemptions and companies:write for /v1/gestoria-seat-offer-redemptions; reads use the corresponding :read scope. Company membership, module access, paying-company ownership and sandbox restrictions are checked again by the product owner.
Preparation sends {code, purchase} and an Idempotency-Key. Employee purchases use employee_individual (create a profile or reactivate an employee UUID) or employee_batch (an existing batch_id and its quote_version). Managed-company purchases use gestoria_purchase with create, activate or activate_batch. The server selects prices, tax and the paying customer; never send remote Stripe identifiers or totals.
Review and confirm
The code's redemption deadline is not the benefit's end date. Without a first billing anchor, a temporary price is accepted for N complete cycles from the first invoice, with benefit_end_basis = first_invoice_pending and benefit_ends_at = null. A repeating discount awaiting application uses discount_application_pending. A known anchor uses accepted_anchor; after verifying application, GET may show the exact UTC end with verified_schedule or verified_discount. This presentation information does not alter the accepted quote or its fingerprint.
When an employee-seat or managed-company-seat offer with a recurring benefit (a repeating or forever discount, or a negotiated price) is redeemed on a seat subscription that is already active, the benefit starts at the next renewal: benefit_starts_at equals next_bill_at. Today only the new seats of the purchase are charged, prorated at the current conditions, so cash_today_cents carries no benefit while recurring_total_cents already does. The current period is not credited and no customer balance is created. A once discount still applies to today's invoice. On a first purchase without a seat subscription there is no current period, and the benefit applies from the start.
The quote distinguishes the eligible amount, discount, net base, tax, fiscal total, account credit, cash due today and recurring amount. quote_complete must be true before confirmation; unknown values stay null. A zero cash charge is explained by zero_reason: account credit, a full discount, a free negotiated price and an active trial have different consequences. Review warnings, expiry, future prices and trial dates before accepting quote_version.
Each owner exposes six operations: POST on its root to prepare; GET on the root to list; GET /{id} to read; and POST /{id}/quote, POST /{id}/confirm, POST /{id}/cancel. Mutations require separate stable keys for each intent. An identical replay retrieves the existing operation; reusing a key for different input is a conflict. A changed or expired quote must be refreshed and reviewed again. If every employee seat is already covered, details.reason = offer_requires_chargeable_seats refuses the offer without consuming it; continue the ordinary batch flow to retain that coverage.
Pending states and errors
A 202 confirmation is pending, not a successful purchase. Read the same operation after reloading, a timeout or card authentication. Follow allowed_actions and an authorized, verified action_url; do not create another redemption. A missing payment method may return 402 with details.payment_setup_url. customer_offer_purchase_failed is a verified final failure; its operation remains readable.
An unavailable, expired, exhausted or reserved offer, incompatible plan or interval, existing discount or external schedule, concurrent purchase, changed trial baseline or unknown quote is a controlled rejection. Cancellation may require financial restoration. needs_review or customer_offer_legacy_outcome_unknown requires checking the existing operation before another purchase. Cancelling an operation does not promise that an invoice is instantly refunded. Applied benefits remain subject to the product's normal renewal, cancellation and refund rules.
When product access is lost, the application's minimal Billing receipt permits only reading and an allowed cancellation. It does not expose profiles or allow confirmation, refreshing, card setup or card authentication. REST and MCP continue to respect the global plan/module restriction.
MCP uses prepare_*_seat_offer_redemption, refresh_*_seat_offer_redemption, confirm_*_seat_offer_redemption, cancel_*_seat_offer_redemption, get_*_seat_offer_redemption and list_*_seat_offer_redemptions, replacing * with employee or gestoria. Mutations take idempotency_key.
The existing authenticated application endpoint GET /api/features publishes data.purchase_availability with employee_batches and customer_offers booleans from the server. These rollout switches control new purchase entry points and quote/confirm actions, not company permissions. When off or unknown, the application retains authorized history and cancellation. They are not frontend environment variables or new public API scopes.