Billing Service API
Base URLโ
/api (via gateway) o http://billing:8088 (interno)
๐ TypeScript Interfacesโ
// Subscription Object
interface Subscription {
id: number;
user_id: number;
provider: 'stripe' | 'apple' | 'google';
plan_id: string;
plan_name: string | null;
status: SubscriptionStatus;
current_period_start: string | null; // ISO 8601
current_period_end: string | null; // ISO 8601
canceled_at: string | null; // ISO 8601
created_at: string; // ISO 8601
}
// Normalized subscription status
type SubscriptionStatus =
| 'ACTIVE'
| 'EXPIRED'
| 'GRACE_PERIOD'
| 'CANCELED'
| 'PAST_DUE';
// Get Subscriptions Response
interface GetSubscriptionsResponse {
user_id: number;
subscriptions: Subscription[];
has_active_subscription: boolean;
}
// Check Subscription Response
interface CheckSubscriptionResponse {
user_id: number;
is_subscribed: boolean;
status: SubscriptionStatus | null;
provider: string | null;
plan_id: string | null;
expires_at: string | null; // ISO 8601
}
// Webhook Response
interface WebhookResponse {
status: 'processed' | 'duplicate' | 'skipped';
subscription_id?: number;
subscription_status?: SubscriptionStatus;
reason?: string;
}
// Health Response
interface HealthResponse {
status: 'ok' | 'degraded';
service: 'billing';
database?: 'connected' | string;
}
๐ก Endpointsโ
1. Subscription APIโ
Get User Subscriptionsโ
GET /api/subscriptions/{user_id}
Restituisce tutte le subscription di un utente.
Response: GetSubscriptionsResponse
{
"user_id": 123,
"subscriptions": [
{
"id": 1,
"user_id": 123,
"provider": "stripe",
"plan_id": "price_xxx",
"plan_name": "Pro Monthly",
"status": "ACTIVE",
"current_period_start": "2025-12-15T00:00:00Z",
"current_period_end": "2026-01-15T00:00:00Z",
"canceled_at": null,
"created_at": "2025-12-15T10:00:00Z"
}
],
"has_active_subscription": true
}
Check Subscription Statusโ
GET /api/subscriptions/check/{user_id}
Check veloce per service-to-service calls.
Response: CheckSubscriptionResponse
{
"user_id": 123,
"is_subscribed": true,
"status": "ACTIVE",
"provider": "stripe",
"plan_id": "price_xxx",
"expires_at": "2026-01-15T00:00:00Z"
}
Uso tipico:
# Dal device-service, prima di restituire dati premium
response = httpx.get(f"http://billing:8088/api/subscriptions/check/{user_id}")
if response.json()["is_subscribed"]:
# Mostra contenuti premium
Get by Provider IDโ
GET /api/subscriptions/by-provider/{provider}/{subscription_id}
Cerca subscription per ID del provider (debug/admin).
Esempio:
GET /api/subscriptions/by-provider/stripe/sub_xxx
Response: Subscription o 404
2. Webhook Endpointsโ
I webhook NON richiedono autenticazione JWT ma validano la firma del provider.
Stripe Webhookโ
POST /webhooks/stripe
Riceve eventi Stripe (subscription, invoice).
Headers richiesti:
Stripe-Signature: Firma HMAC
Eventi gestiti:
customer.subscription.createdcustomer.subscription.updatedcustomer.subscription.deletedinvoice.paidinvoice.payment_failed
Response:
{
"status": "processed",
"subscription_id": 1,
"subscription_status": "ACTIVE"
}
Apple Webhookโ
POST /webhooks/apple
Riceve App Store Server Notifications v2.
Body:
{
"signedPayload": "eyJhbGciOiJFUzI1NiJ9..."
}
Eventi gestiti:
SUBSCRIBEDDID_RENEWDID_FAIL_TO_RENEWEXPIREDDID_CHANGE_RENEWAL_STATUS- E altri...
Google Webhookโ
POST /webhooks/google
Riceve Real-time Developer Notifications via Pub/Sub.
Body (Pub/Sub push):
{
"message": {
"messageId": "xxx",
"data": "base64_encoded_notification"
}
}
Notification types gestiti:
| Type | Nome | Stato risultante |
|---|---|---|
| 1 | SUBSCRIPTION_RECOVERED | ACTIVE |
| 2 | SUBSCRIPTION_RENEWED | ACTIVE |
| 3 | SUBSCRIPTION_CANCELED | CANCELED |
| 4 | SUBSCRIPTION_PURCHASED | ACTIVE |
| 5 | SUBSCRIPTION_ON_HOLD | PAST_DUE |
| 6 | SUBSCRIPTION_IN_GRACE_PERIOD | GRACE_PERIOD |
| 12 | SUBSCRIPTION_REVOKED | EXPIRED |
| 13 | SUBSCRIPTION_EXPIRED | EXPIRED |
3. Health Checkโ
Healthโ
GET /health
Response:
{
"status": "ok",
"service": "billing",
"database": "connected"
}
๐ Integrazione Frontendโ
Verificare se utente รจ abbonatoโ
async function checkSubscription(userId: number): Promise<boolean> {
const response = await fetch(
`${API_BASE_URL}/api/subscriptions/check/${userId}`,
{
headers: {
'Authorization': `Bearer ${accessToken}`
}
}
);
const data = await response.json();
return data.is_subscribed;
}
Mostrare dettagli abbonamentoโ
async function getSubscriptionDetails(userId: number): Promise<Subscription[]> {
const response = await fetch(
`${API_BASE_URL}/api/subscriptions/${userId}`,
{
headers: {
'Authorization': `Bearer ${accessToken}`
}
}
);
const data = await response.json();
return data.subscriptions;
}
โ ๏ธ Error Codesโ
| Status | Significato |
|---|---|
| 200 | Successo |
| 400 | Payload invalido o firma errata |
| 404 | Subscription non trovata |
| 500 | Errore interno |