@ascendraa/react
v0.2.0
Published
Official React SDK for Ascendraa - usage-based billing with real-time updates
Maintainers
Readme
@ascendraa/react
Official React SDK for Ascendraa - usage-based billing with real-time updates.
Installation
npm install @ascendraa/react
# or
yarn add @ascendraa/react
# or
pnpm add @ascendraa/reactQuick Start
1. Setup Provider
Wrap your app with AscendraaProvider to enable the SDK:
import { AscendraaProvider } from '@ascendraa/react';
function App() {
return (
<AscendraaProvider
apiUrl="https://api.ascendraa.com"
publicKey="pk_test_1234567890abcdef"
customerToken="cat_24h_abcd1234efgh5678ijkl90mnop1234qrst5678"
enableRealtime={true}
reverbConfig={{
key: process.env.REACT_APP_REVERB_APP_KEY,
wsHost: process.env.REACT_APP_REVERB_HOST || 'localhost',
wsPort: parseInt(process.env.REACT_APP_REVERB_PORT || '8080', 10),
wssPort: parseInt(process.env.REACT_APP_REVERB_PORT || '8080', 10),
forceTLS: process.env.REACT_APP_REVERB_SCHEME === 'https',
}}
>
<YourApp />
</AscendraaProvider>
);
}2. Authentication
Required Credentials:
publicKey(pk_...) - Your business public key (required for API routing and identification)customerToken(cat_...) - Customer token generated server-side (required for authentication)
⚠️ Security Note:
- Never expose your secret key (
sk_...) in the browser - Tokens are short-lived (hours) and should be refreshed server-side
- Generate customer tokens on your backend using your secret key
Token Generation (Server-Side):
// On your backend
POST /api/v1/customers/generate_token
Headers: {
Authorization: 'Bearer sk_your_secret_key',
X-Public-Key: 'pk_your_public_key'
}
// Returns: { token: "cat_24h_..." }3. Basic Usage
Check Feature Access
import { useCheck } from '@ascendraa/react';
function FeatureCheck() {
const { data, isLoading, error } = useCheck('api-calls');
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<div>
<p>Allowed: {data?.allowed ? 'Yes' : 'No'}</p>
<p>Balance: {data?.balance}</p>
<p>Usage: {data?.usage} / {data?.included_usage + data?.balance}</p>
</div>
);
}Track Usage
import { useTrack } from '@ascendraa/react';
function TrackUsage() {
const { mutate, isPending } = useTrack();
const handleApiCall = () => {
mutate({
featureId: 'api-calls',
value: 1,
metadata: { requestId: '123' }
});
};
return (
<button onClick={handleApiCall} disabled={isPending}>
{isPending ? 'Tracking...' : 'Make API Call'}
</button>
);
}Set Usage Directly
import { useSetUsage } from '@ascendraa/react';
function SetUsage() {
const { mutate, isPending } = useSetUsage();
const handleSetUsage = () => {
mutate({
featureId: 'api-calls',
value: 100
});
};
return (
<button onClick={handleSetUsage} disabled={isPending}>
Set Usage to 100
</button>
);
}Checkout Flow
import { CheckoutButton } from '@ascendraa/react';
function Checkout() {
return (
<CheckoutButton
planId="01ARZ3NDEKTSV4RRFFQ69G5FAV"
amount={1000}
email="[email protected]"
name="John Doe"
currency="USD"
callbackUrl="https://yourapp.com/success"
onSuccess={(data) => {
console.log('Checkout initiated:', data);
}}
onError={(error) => {
console.error('Checkout failed:', error);
}}
>
Subscribe Now
</CheckoutButton>
);
}Real-time Updates
import { useRealtime } from '@ascendraa/react';
import { useQueryClient } from '@tanstack/react-query';
function RealtimeUsage() {
const queryClient = useQueryClient();
const customerId = 'customer-123';
const { isConnected, listen } = useRealtime(customerId, {
enableRealtime: true,
reverbConfig: {
key: process.env.REACT_APP_REVERB_APP_KEY,
wsHost: process.env.REACT_APP_REVERB_HOST,
wsPort: 8080,
},
events: ['usage.updated', 'balance.updated'],
onEvent: (event) => {
console.log('Real-time event:', event.type, event.data);
},
});
useEffect(() => {
listen('usage.updated', (data) => {
// Invalidate queries to refetch latest data
queryClient.invalidateQueries(['ascendraa', 'check']);
});
}, [listen, queryClient]);
return (
<div>
Status: {isConnected ? 'Connected' : 'Disconnected'}
</div>
);
}API Reference
Hooks
useCheck(featureIdOrEventName, options?)
Check feature access or event balance.
const { data, isLoading, error } = useCheck('api-calls', {
staleTime: 5000, // Cache for 5 seconds
enabled: true, // Enable/disable query
});Returns:
data:{ allowed, balance, usage, included_usage, unlimited, interval, next_reset_at, code }isLoading: Loading stateerror: Error object
useTrack()
Track usage events (mutation).
const { mutate, isPending, error } = useTrack();
mutate({
featureId: 'api-calls', // or eventName: 'api-calls'
value: 1,
metadata: { requestId: '123' }
});useSetUsage()
Set usage directly (mutation).
const { mutate, isPending } = useSetUsage();
mutate({
featureId: 'api-calls',
value: 100,
metadata: { source: 'manual' }
});useGetUsage(featureIdOrEventName, options?)
Get current usage (query).
const { data, isLoading } = useGetUsage('api-calls');
// data: { usage, balance, included_usage }useCheckout()
Create checkout session (mutation).
const { mutate, isPending } = useCheckout();
mutate({
planId: '01ARZ3NDEKTSV4RRFFQ69G5FAV',
amount: 1000,
email: '[email protected]',
currency: 'USD',
callbackUrl: 'https://yourapp.com/success'
});useRevokeSubscription()
Revoke/cancel subscription (mutation).
const { mutate, isPending } = useRevokeSubscription();
mutate({
subscriptionId: 'sub_123' // Optional - omitting revokes all
});useRealtime(customerId, options?)
Subscribe to real-time updates.
const { isConnected, listen, leaveChannel } = useRealtime(customerId, {
enableRealtime: true,
reverbConfig: { key, wsHost, wsPort, ... },
events: ['usage.updated', 'balance.updated'],
onEvent: (event) => { /* handle event */ }
});Components
<AscendraaProvider>
Main provider component. Required at the root of your app.
Props:
apiUrl(string, required) - API base URLpublicKey(string, required) - Business public key (pk_...)customerToken(string, required) - Customer token (cat_...)enableRealtime(boolean, optional) - Enable real-time updatesreverbConfig(object, optional) - Reverb WebSocket configurationcacheConfig(object, optional) - TanStack Query cache configuration
<UsageMeter>
Display usage information with flexible rendering.
<UsageMeter
featureIdOrEventName="api-calls"
showBalance={true}
showUsage={true}
showNextReset={true}
loadingComponent={<Spinner />}
errorComponent={(error) => <ErrorMsg error={error} />}
>
{({ allowed, balance, usage, isLoading }) => (
<div>
{/* Custom rendering */}
</div>
)}
</UsageMeter><CheckoutButton>
Button component for checkout flow.
<CheckoutButton
planId="01ARZ3NDEKTSV4RRFFQ69G5FAV"
amount={1000}
email="[email protected]"
className="btn-primary"
onSuccess={(data) => { /* handle success */ }}
onError={(error) => { /* handle error */ }}
>
Subscribe Now
</CheckoutButton>Real-time Events
When real-time is enabled, you can listen to these events:
usage.updated- Usage changedbalance.updated- Balance changedsubscription.updated- Subscription status changedtransaction.completed- Payment completed
TypeScript Support
Full TypeScript support with exported types:
import type {
CheckResponse,
TrackResponse,
UsageResponse,
CheckoutResponse,
RealtimeEvent,
} from '@ascendraa/react';Error Handling
All hooks and components provide error states:
const { data, error, isLoading } = useCheck('api-calls');
if (error) {
// Handle error
console.error('Error:', error.message);
}Caching
The SDK uses TanStack Query for intelligent caching:
- Automatic request deduplication
- Configurable cache times
- Automatic cache invalidation on mutations
- Optimistic updates support
Examples
Complete Example
import {
AscendraaProvider,
useCheck,
useTrack,
UsageMeter,
CheckoutButton
} from '@ascendraa/react';
function App() {
return (
<AscendraaProvider
apiUrl="https://api.ascendraa.com"
publicKey={process.env.REACT_APP_ASCENDRAA_PUBLIC_KEY}
customerToken={process.env.REACT_APP_ASCENDRAA_CUSTOMER_TOKEN}
>
<Dashboard />
</AscendraaProvider>
);
}
function Dashboard() {
const { data: checkData } = useCheck('api-calls');
const { mutate: track } = useTrack();
return (
<div>
<UsageMeter featureIdOrEventName="api-calls" />
<button onClick={() => track({
featureId: 'api-calls',
value: 1
})}>
Track Usage
</button>
<CheckoutButton
planId="01ARZ3NDEKTSV4RRFFQ69G5FAV"
amount={1000}
>
Upgrade Plan
</CheckoutButton>
</div>
);
}Requirements
- React >= 18
- Node.js >= 18
License
MIT
Documentation
For complete documentation, API reference, and advanced usage examples, visit:
https://docs.ascendraa.com/react-sdk
