credly
v1.0.3
Published
Transform complex LLM token usage into simple credits. Manage user access, track consumption, and implement subscription tiers with ease.
Readme
credly
The credly package provides a simple and powerful way to manage Large Language Model (LLM) token usage as credits. With Credly, you can easily track consumption, manage user access, rate limit based on credits, and implement subscription tiers in your application with ease.
Features
- Credit-based Usage Tracking: Abstract away complex token counting and manage usage with a simple credit system.
- User Management: Keep track of your users and their credit balances.
- Tiered Access: Implement different subscription tiers with varying credit allocations and automatic credit refills.
- Transaction History: Get a full history of credit transactions.
- Developer-Focused: Designed with developers in mind for a seamless integration experience.
Quickstart
Go to credly.dev to get your API key and project ID.
Copy-paste this minimal example to get started in seconds.
import { createClient } from "credly";
const credly = createClient({
apiKey: "YOUR_API_KEY",
projectId: "YOUR_PROJECT_ID",
});
// Reserve credits, call your LLM, then finalize with actual usage
const start = await credly.startUsageTransaction({
user_id: "user_123",
model: "gpt-4",
// Optionally reserve tokens to pre-check credit availability for the following call.
provisional_tokens: {
input_tokens: 100,
output_tokens: 500,
},
});
if (!start.continue) throw new Error("Insufficient credits");
// ... call your LLM and compute usage ...
await credly.completeUsageTransaction({
transaction_id: start.transaction_id,
success: true,
finalized_tokens: { input_tokens: 10, output_tokens: 50 },
});Table of contents
Getting started
Installation
Install with your package manager of choice:
npm install credly
# or
pnpm add credlyInitialization
Create a client with your API key and project id:
import { createClient } from "credly";
const credly = createClient({
apiKey: "YOUR_API_KEY",
projectId: "YOUR_PROJECT_ID",
});Usage
credly's primary pattern is: start a usage transaction, call the LLM, then complete the transaction with the finalized token counts.
captureUsage helper
Use captureUsage to wrap start/execute/finish in one call. It creates the user if needed, reserves provisional tokens, runs your function (if allowed), extracts finalized tokens via your callback, and completes the transaction for success or failure.
Keep the example usage in the package docs; the helper returns a structured result you can branch on (status values include start_failed, insufficient_credits, executed_success, and error variants).
const response = await meteringClient.captureUsage({
// Identify the user and model for billing
user_id: userId,
model: "gpt-4o",
// Optionally reserve tokens to pre-check credit availability for the following call.
provisional_tokens: {
input_tokens: Tiktoken().encode(prompt),
output_tokens: 500,
}
// The core work to be done and metered
execute: () => await openai.chat.completions.create({
// ... your parameters
}),
// A function to extract the final token count from the result of `execute`
finalizeTokens: (result) => ({
input_tokens: result.usage.prompt_tokens,
output_tokens: result.usage.completion_tokens,
}),
});Return shape (with status):
type UsageTransactionStatus =
| "start_failed"
| "insufficient_credits"
| "executed_success"
| "executed_error"
| "execution_error_completion_failed";
type CaptureUsageReturn<T> =
| {
status: "start_failed";
started: false;
continue: false;
startError: unknown;
}
| {
status: "insufficient_credits";
started: true;
continue: false;
start: StartUsageTransactionResponse;
}
| {
status: "executed_success";
started: true;
continue: true;
start: StartUsageTransactionResponse;
finish: CompleteUsageTransactionResponse;
result: T;
}
| {
status: "executed_error" | "execution_error_completion_failed";
started: true;
continue: true;
start: StartUsageTransactionResponse;
finish?: CompleteUsageTransactionResponse;
error: unknown;
};Status meanings
| Status | Meaning |
| --------------------------------- | ------------------------------------------------------- |
| start_failed | Start call failed before creating a transaction. |
| insufficient_credits | Start succeeded but continue is false (no execution). |
| executed_success | Execution + completion (success) succeeded. |
| executed_error | Execution failed; failure completion succeeded. |
| execution_error_completion_failed | Execution failed AND failure completion also failed. |
Set rethrowOnError: true to rethrow errors; otherwise branch on the returned status.
Basic usage pattern
- Call
startUsageTransactionto check for sufficient credits and reserve provisional tokens. - If
continueis true, call your LLM. - Call
completeUsageTransactionwithfinalized_tokensandsuccess.
See the examples in this README for OpenAI integration patterns.
Error Handling
If a transaction fails, you should still complete it with success: false:
try {
const startResponse = await credly.startUsageTransaction({
user_id: userId,
model: "gpt-4",
});
if (startResponse.continue) {
// Your LLM call here
const completion = await openai.chat.completions.create({
// ... your parameters
});
await credly.completeUsageTransaction({
transaction_id: startResponse.transaction_id,
success: true,
finalized_tokens: {
input_tokens: completion.usage?.prompt_tokens,
output_tokens: completion.usage?.completion_tokens,
},
});
}
} catch (error) {
// Complete the transaction as failed if it was started
if (startResponse?.transaction_id) {
await credly.completeUsageTransaction({
transaction_id: startResponse.transaction_id,
success: false,
finalized_tokens: { input_tokens: 0, output_tokens: 0 },
});
}
throw error;
}API Reference
createClient(options)
Creates a new Credly client instance.
options.apiKey(string, required): Your API key.options.projectId(string, required): Your project ID.
startUsageTransaction(details)
Initiates a new usage transaction.
details.user_id(string, required): The ID of the user making the request.details.model(string, required): The model identifier configured in your project.details.provisional_tokens(object, optional): Estimated token usage for credit reservation.input_tokens(number, optional): Estimated input tokens.output_tokens(number, optional): Estimated output tokens.
details.feature_identifier(string, optional): Feature identifier for usage tracking.
Returns:
transaction_id(string): UUID of the created transaction.continue(boolean): Whether the user has sufficient credits to proceed.balance(number): User's remaining credit balance.credits_used(number): Credits deducted for this transaction.message(string): Status message.
completeUsageTransaction(details)
Finalizes an ongoing transaction with actual usage.
details.transaction_id(string, required): UUID of the pending transaction.details.success(boolean, required): Whether the LLM call was successful.details.finalized_tokens(object, required): Actual token usage.input_tokens(number, optional): Actual input tokens used.output_tokens(number, optional): Actual output tokens used.
Returns:
credits_used(number): Final credits charged for the transaction.balance(number): User's updated credit balance.balanceAdjustment(number): Credit adjustment (positive if refunded, negative if additional charge).
User Management
createUser(details)
Creates a new user.
details.id(string, required): External user ID.
getUser(details)
Retrieves a user by ID.
details.id(string, required): External user ID.
getUsers()
Retrieves all users in the project.
deleteUser(details)
Deletes a user.
details.id(string, required): External user ID.
Tier Management
changeUserTier(details)
Changes a user's subscription tier.
details.user_id(string, required): The ID of the user.details.tier_id(string, required): The ID of the new tier.details.reset_balance(boolean, optional): Whether to reset the user's balance to the new tier's allocation.
Transaction History
getTransactions(filters)
Retrieves transaction history with optional filtering.
filters.user_id(string, optional): Filter by user ID.- Additional pagination and filtering options available.
getTransaction(details)
Retrieves a single transaction by ID.
details.id(string, required): Transaction ID.
Error handling
The client throws CredlyApiError for API errors. Fields include status, title, detail, and type.
Example:
import { CredlyApiError } from "credly";
try {
await credly.startUsageTransaction({ user_id: "user_123", model: "gpt-4" });
} catch (err) {
if (err instanceof CredlyApiError)
console.error(`API Error ${err.status}: ${err.detail}`);
else console.error("Unexpected:", err);
}Error types
The client maps HTTP/API problems to strongly-typed error classes derived from CredlyApiError. The table below lists the known subclasses and when they are used.
| Error class | When it's thrown |
| ------------------- | --------------------------------------------------------------------------------------------------------------- |
| ValidationError | Returned for HTTP 400 responses when the request is invalid or fails schema validation. |
| UnauthorizedError | Returned for HTTP 401 responses when the API key is missing or invalid. |
| ForbiddenError | Returned for HTTP 403 responses when the caller lacks required permissions. |
| NotFoundError | Returned for HTTP 404 responses when a requested resource doesn't exist. |
| ConflictError | Returned for HTTP 409 responses when a request conflicts with current server state (e.g., duplicate resources). |
| RateLimitError | Returned for HTTP 429 responses when the client has exceeded allowed request rate limits. |
| ServerError | Returned for HTTP 5xx responses indicating server-side failure. |
| CredlyApiError | Fallback for unknown or unclassified API problems; contains RFC 7807 problem details. |
Support, feedback & feature requests
We want to improve and build credly into the exact package you need. We'd love to hear from you!
Email: [email protected]
License
MIT — see LICENSE.
