mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-18 21:45:31 +09:00
feat(api)!: always use localized pricing where it is offered (#2646)
This commit is contained in:
1 parent
905af5dd5a
commit
f708586c59
62 files changed
+3148
-11917
No files matched your search
@@ -236,11 +236,10 @@ A blocked purchase always fails on [create localised card preapproval](#create-l
|
||||
| country_code?<sup>1</sup> | string | Two-letter country used to select the regional price catalogue (2 characters) |
|
||||
| client_geoip_country_code?<sup>2</sup> | string | Two-letter country the client previously observed for itself (2 characters) |
|
||||
| eu_withdrawal_waiver_accepted?<sup>3</sup> | boolean | Whether the digital content withdrawal waiver was explicitly accepted |
|
||||
| pricing_mode? | string | Either `localized` or `base` (default `localized`) |
|
||||
| payment_method?<sup>4</sup> | string | Either `card`, `pix` or `upi` (default `card`) |
|
||||
| is_business? | boolean | Whether to require a billing address for tax invoicing (default false) |
|
||||
|
||||
<sup>1</sup> Required whenever the resolved price is not in USD or EUR, and validated against the price catalogue for that country
|
||||
<sup>1</sup> Read only when Fluxer cannot geolocate the request, because the request-time geolocation country wins. The resolved country is required whenever the price is not in USD or EUR, and the price is validated against the catalogue for that country, so a client cannot buy outside the catalogue of the country it is browsing from
|
||||
|
||||
<sup>2</sup> Read to resolve the effective country for the withdrawal waiver, and recorded with the payment
|
||||
|
||||
@@ -282,7 +281,7 @@ Creates a setup mode session that captures and verifies a card before a localise
|
||||
### Limitations
|
||||
|
||||
- The claimed account, verified email and purchase flag requirements of [create subscription checkout](#create-subscription-checkout) apply unchanged, with the same codes.
|
||||
- An absent `country_code`, a `pricing_mode` of `base`, and a resolved price that is not a recurring price in a currency other than USD and EUR each return 400 `STRIPE_INVALID_PRODUCT_CONFIGURATION`.
|
||||
- An unresolvable country, meaning a request Fluxer cannot geolocate that also omits `country_code`, and a resolved price that is not a recurring price in a currency other than USD and EUR each return 400 `STRIPE_INVALID_PRODUCT_CONFIGURATION`.
|
||||
- The submitted price is always recurring, so the lifetime block and the existing subscription block both apply and return 403 `PREMIUM_PURCHASE_BLOCKED` with the reason `lifetime` or `existing_subscription`.
|
||||
|
||||
### JSON body
|
||||
@@ -293,12 +292,9 @@ Creates a setup mode session that captures and verifies a card before a localise
|
||||
| country_code<sup>1</sup> | string | Two-letter country used to select the regional price catalogue (2 characters) |
|
||||
| client_geoip_country_code? | string | Two-letter country the client previously observed for itself (2 characters) |
|
||||
| eu_withdrawal_waiver_accepted? | boolean | Whether the digital content withdrawal waiver was explicitly accepted |
|
||||
| pricing_mode?<sup>2</sup> | string | Either `localized` or `base` (default `localized`) |
|
||||
| is_business? | boolean | Whether to require a billing address for tax invoicing (default false) |
|
||||
|
||||
<sup>1</sup> Declared optional by the shared request schema, and this operation refuses a request that omits it
|
||||
|
||||
<sup>2</sup> A submitted `base` returns 400 `STRIPE_INVALID_PRODUCT_CONFIGURATION`
|
||||
<sup>1</sup> Declared optional by the shared request schema, and this operation refuses a request that resolves no country. The request-time geolocation country wins, so this value is read only when Fluxer cannot geolocate the request
|
||||
|
||||
A submitted `payment_method` is validated against the enum and then discarded. The setup session is always restricted to cards.
|
||||
|
||||
@@ -307,11 +303,11 @@ A submitted `payment_method` is validated against the enum and then discarded. T
|
||||
| Status | Body | Condition |
|
||||
| --- | --- | --- |
|
||||
| 200 | [redirect URL](#redirect-url-object) object | The setup session was created |
|
||||
| 400<sup>3</sup> | [error response](/http-api/#error-response) | The country, the price, the account, or the payment provider blocks the setup session |
|
||||
| 400<sup>2</sup> | [error response](/http-api/#error-response) | The country, the price, the account, or the payment provider blocks the setup session |
|
||||
| 403 | [error response](/http-api/#error-response) | The email address is unverified, or the purchase is blocked |
|
||||
| 404 | [error response](/http-api/#error-response) | The authenticated account record no longer exists |
|
||||
|
||||
<sup>3</sup> The country or pricing mode is not localised, the price is unknown or not valid for the resolved catalogue, the account is unclaimed, the payment provider is not configured, or the payment provider rejected the request and returns `STRIPE_ERROR`
|
||||
<sup>2</sup> The country is absent, the price is unknown or not valid for the resolved catalogue, the account is unclaimed, the payment provider is not configured, or the payment provider rejected the request and returns `STRIPE_ERROR`
|
||||
|
||||
### Side effects
|
||||
|
||||
@@ -395,10 +391,9 @@ Neither the lifetime block nor the existing subscription block applies here, so
|
||||
| country_code?<sup>1</sup> | string | Two-letter country used to select the regional gift price catalogue (2 characters) |
|
||||
| client_geoip_country_code? | string | Two-letter country the client previously observed for itself (2 characters) |
|
||||
| eu_withdrawal_waiver_accepted? | boolean | Whether the digital content withdrawal waiver was explicitly accepted |
|
||||
| pricing_mode? | string | Either `localized` or `base` (default `localized`) |
|
||||
| is_business? | boolean | Whether to require a billing address for tax invoicing (default false) |
|
||||
|
||||
<sup>1</sup> Required whenever the resolved gift price is not in USD or EUR
|
||||
<sup>1</sup> Read only when Fluxer cannot geolocate the request, because the request-time geolocation country wins. The resolved country is required whenever the gift price is not in USD or EUR
|
||||
|
||||
A submitted `pix` or `upi` is validated against the enum and then discarded. The session restricts no payment method type, so the provider offers whatever the deployment's provider account accepts for the resolved currency.
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ Every route except [get price IDs](#get-price-ids) is user-only. A [self-hosted
|
||||
| [Billing subscription](#billing-subscription-object) | One mirrored subscription |
|
||||
| [Billing invoice](#billing-invoice-object) | One mirrored invoice |
|
||||
| [Billing payment method](#billing-payment-method-object) | One mirrored payment method |
|
||||
| [Premium pricing state](#premium-pricing-state-object) | Both resolved checkout catalogues |
|
||||
| [Premium pricing state](#premium-pricing-state-object) | The resolved checkout catalogue |
|
||||
|
||||
:::note[Billing history is mirrored from the payment provider]
|
||||
[Get premium state](#get-premium-state) returns the mirrored invoices, payment methods and subscription fields. [Create customer portal](#create-customer-portal) is the externally hosted interface for changing any of them.
|
||||
@@ -430,7 +430,7 @@ One mirrored stored payment method. A non-card method reports every card member
|
||||
|
||||
## Premium pricing state object
|
||||
|
||||
The checkout catalogue resolved for the request. A client can render prices without a second call to [get price IDs](#get-price-ids). Fluxer resolves both catalogues on every request, so one response has both a localised price and its USD or EUR equivalent.
|
||||
The checkout catalogue resolved for the request. A client can render prices without a second call to [get price IDs](#get-price-ids). Fluxer resolves one catalogue on every request, and a country with its own localised currency always resolves to that currency.
|
||||
|
||||
### Structure
|
||||
|
||||
@@ -438,9 +438,8 @@ The checkout catalogue resolved for the request. A client can render prices with
|
||||
| --- | --- | --- |
|
||||
| country_code<sup>1</sup> | ?string | The country used to resolve the prices |
|
||||
| localized<sup>2</sup> | ?[price IDs](#price-ids-object) object | The localised catalogue, or null when it cannot be resolved |
|
||||
| base<sup>2</sup> | ?[price IDs](#price-ids-object) object | The base USD or EUR catalogue, or null when it cannot be resolved |
|
||||
|
||||
<sup>1</sup> The `country_code` query value uppercased, or null when it was omitted
|
||||
<sup>1</sup> The request-time geolocation country, falling back to the `country_code` query value uppercased, or null when neither resolves
|
||||
|
||||
<sup>2</sup> Null unless the deployment configures a complete recurring pair and a complete gift pair for the currency preferences that apply, so one missing gift price nulls the whole catalogue. The amounts come from the mirrored price rows
|
||||
|
||||
@@ -450,7 +449,7 @@ Fluxer reports an unresolvable catalogue as null here, and the request still suc
|
||||
|
||||
<RouteHeader method="GET" path="/v1/premium/price-ids" unauthenticated />
|
||||
|
||||
Returns the [price IDs](#price-ids-object) object for a country and pricing mode. A supplied credential only keys the rate limit, so an unrecognised credential falls back to the client IP address.
|
||||
Returns the [price IDs](#price-ids-object) object for a country. A supplied credential only keys the rate limit, so an unrecognised credential falls back to the client IP address.
|
||||
|
||||
The deployment must configure a complete recurring pair and a complete gift pair for at least one currency that the requested country prefers. Fluxer answers 400 `STRIPE_ERROR` when it does not.
|
||||
|
||||
@@ -459,11 +458,8 @@ The deployment must configure a complete recurring pair and a complete gift pair
|
||||
| Field | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| country_code?<sup>1</sup> | string | The two-letter country used to select the regional price catalogue |
|
||||
| pricing_mode?<sup>2</sup> | string | Either `localized` or `base` (default `localized`) |
|
||||
|
||||
<sup>1</sup> Fluxer trims surrounding whitespace and requires exactly two characters, and any other length fails validation with `STRING_LENGTH_EXACT`. Omitting it resolves the default currency preference order
|
||||
|
||||
<sup>2</sup> `base` restricts resolution to the deployment's base currency preferences, which is how a client reads USD or EUR pricing for a country that has its own localised catalogue
|
||||
<sup>1</sup> Fluxer trims surrounding whitespace and requires exactly two characters, and any other length fails validation with `STRING_LENGTH_EXACT`. The request-time geolocation country wins, so this value is read only when Fluxer cannot geolocate the request, and the default currency preference order applies when neither resolves
|
||||
|
||||
### Response
|
||||
|
||||
@@ -498,7 +494,7 @@ This route derives `current_subscription_price` from the mirrored subscription a
|
||||
| --- | --- | --- |
|
||||
| country_code?<sup>1</sup> | string | The two-letter country used to resolve `pricing` |
|
||||
|
||||
<sup>1</sup> Fluxer trims surrounding whitespace and requires exactly two characters. Omitting it resolves `pricing` against the default currency preference order and reports `pricing.country_code` as null
|
||||
<sup>1</sup> Fluxer trims surrounding whitespace and requires exactly two characters. The request-time geolocation country wins, so this value is read only when Fluxer cannot geolocate the request. When neither resolves, `pricing` falls back to the default currency preference order and `pricing.country_code` is null
|
||||
|
||||
### Response
|
||||
|
||||
|
||||
Reference in new issue
Block a user