Happklaar API
string · requiredstring · requiredstring · date-time · requiredstring | nullstring | null · date-time string · minLength: 4 · maxLength: 32 · requiredstring · minLength: 2 · maxLength: 2 string · enum · requiredstring · uuid · requiredstring | null · date-timeinteger | nullinteger | nullstring | null · date-timeinteger | null string · uuid · requiredstring · uuid · required string · enum · requiredstring · minLength: 2 · maxLength: 2 · requiredbooleanstring | null · maxLength: 32string · enumstring · enum · requiredstring | nullstring | nullstring | nullstring | null · date-time string · uuid · requiredstring · uuid · requiredstring · requiredstring · requiredstring · requiredstring · requiredstring · requiredinteger · requiredstring · requiredinteger · requiredinteger · requiredinteger · requiredstring[] · requiredboolean · required string · uuid · requiredstring · enum · requiredstring | nullstring | null · date-timestring · requiredstring · requiredboolean · requiredstring · requiredstring[] · requiredstring[] · requiredstring | null · date-timeinteger | nullarray | null
Billing.BillingIntentStatusData
idstatusexpires_atstatus_reasonconfirmed_atBilling.BtwValidateRequest
FormRequest for POST /v1/billing/btw-validate.
Single SPA endpoint that fronts the {@see \Modules\Tax\Services\ViesValidator}.
The SPA debounces input by 400ms on-blur and posts {btw_id, country?}
with an AbortController that cancels any in-flight prior request.
`country` is optional — when absent the controller decodes the country
code from the BTW id's two-letter ISO prefix (e.g. `NL123…` → `NL`).
Callers that already know the issuing country (e.g. a multi-country B2B
onboarding form where the country is asked first) may pass it
explicitly. The validator accepts only ISO 3166-1 alpha-2 codes
uppercased downstream.
btw_idcountryBilling.CancelPaidSubscriptionRequest
Validates POST /v1/billing/cancel (D-32 + D-42).
Body:
cancellation_reason: required, one of CancellationReason enum values.
retention_pitch_shown_at: nullable ISO8601 — when the SPA last displayed
the retention copy before submit (lifecycle drip target).
Headers:
Idempotency-Key: required UUIDv7 (D-32). Forwarded to the provider so
caller-side retries collapse on Mollie's idempotency layer.
Authorization: Owner-only (D-42). See {@see PlanChangePreviewRequest}
for the inline-pivot rationale; same shape applies here.
cancellation_reasonEnum values:
too_expensive
missing_feature
temporary_break
other
idempotency_keyretention_pitch_shown_atBilling.CancellationPreviewQueryResult
recipes_countpantry_items_countplan_history_sincemembers_countBilling.ChangeTierRequest
Validates POST /v1/billing/plan-change/commit (D-32 + D-42).
Body:
to_tier_id: required UUID — target paid tier.
Headers:
Idempotency-Key: required UUIDv7 (D-32). Forwarded to Mollie + stored
on the billing_intents row so caller retries collapse server-side.
Authorization: Owner-only (D-42). Pivot lookup mirrors
{@see PlanChangePreviewRequest}.
to_tier_ididempotency_keyBilling.CheckoutPreviewRequest
FormRequest for POST /v1/billing/preview.
The SPA posts this whenever the user toggles the business switch, edits
the BTW-ID, or changes the buyer country in the checkout summary, so
the reverse-charge legend + tax breakdown stay in lock-step with the
server-side computation. The endpoint is read-side and idempotent.
`btw_status` is hint-only — the server treats the BTW status as
`unverified` whenever the client says `verified` without a cached or
fresh VIES match. The wire field exists so the client can preview the
rendering on its own state model; the server still owns the decision.
tier_slugEnum values:
free
solo
duo
household
custom
countryis_businessbtw_idbtw_statusEnum values:
verified
unverified
invalid
Billing.MandateQueryResult
mandate_statusEnum values:
none
pending
valid
revoked
providermethodlast4valid_untilBilling.PlanChangePreviewRequest
Validates POST /v1/billing/plan-change/preview (D-40 + D-42).
Body:
from_tier_id: required UUID — current paid tier the household is on.
to_tier_id: required UUID — target tier the user is considering.
Authorization: Owner-only (D-42). The pivot row on `account_household`
is looked up by (user_id, household_id) and rejected unless its `role`
casts to {@see AccountHouseholdRole::Owner}. Laravel surfaces a `false`
return as 403 Forbidden, no literal status code is touched in user-code.
Per CLAUDE.md "DI over facades" — constructor-injects the
{@see CurrentHouseholdResolver} contract so the authorize() pivot lookup
can resolve the caller's active household without touching the auth/config
facades. Laravel resolves FormRequest constructors out of the container.
from_tier_idto_tier_idBilling.PlanChangePreviewResource
change_kindeffective_atobject · required
array · required
array · required
from_tier_idto_tier_idBilling.ProjectedRenewalQueryResult
nextRenewalDateprojectedAmountCentscurrencyextraMembersperAdditionalEurCentsincludedMembersbreakdownLineshasUnsettledPendingChargesBilling.ReactivatePaidSubscriptionRequest
Validates POST /v1/billing/reactivate (D-32 + D-42).
Body: empty (the action is unconditional — caller asks to undo a pending
cancel-at-period-end).
Headers:
Idempotency-Key: required UUIDv7 (D-32). Forwarded to Mollie so retries
collapse on the provider side.
Authorization: Owner-only (D-42). Mirrors the inline-pivot pattern from
{@see PlanChangePreviewRequest}.
idempotency_keyBilling.SubscriptionReturnStatusQueryResult
statusEnum values:
pending
confirmed
failed
tier_slugconfirmed_atBilling.SubscriptionStatusQueryResult
tier_slugstatuscan_start_trialtier_nametier_capabilitiestrial_target_tierstrial_ends_atdays_remaininggrace_state