Skip to Content
Engineering & Design

Engineering Principles & Design

This document outlines the key engineering principles, architectural decisions, and trade-offs made during the development of EarnKit.


Part 1: Core SDK Philosophy & Best Practices

We started with a clear philosophy for the earnkit-sdk: it should be lightweight, flexible, and completely focused on providing a best-in-class developer experience (DX).

A Focus on Developer Experience (DX)

  • Performant and Reliable: The EarnKit Backend is designed to be extremely performant and reliable, making sure the developer’s application is not hindered by the backend.

  • Lightweight and Dependency-Free: A core tenet of the SDK’s design is its minimal footprint. It is intentionally built with zero production dependencies, ensuring it is lean, easy to integrate, and will not bloat a developer’s application. The final production bundle is a mere ~15 KB (and ~4 KB gzipped), making its impact on load times negligible.

  • Decoupled & Wallet-Agnostic: To maximize compatibility across the web3 ecosystem, the SDK is completely wallet-agnostic. Instead of bundling a specific wallet connector, it requires the developer to pass in the walletAddress. This crucial design choice grants developers the freedom to use any wallet connection library they prefer (e.g., Privy, RainbowKit, Web3Modal).

  • Instant Agent Configuration Change: The SDK is designed in such a way that the developer doesn’t need to redeploy their application to change the agent configuration.

  • Clear & Actionable Errors: The SDK features a set of custom error classes (EarnKitInitializationError, EarnKitInputError, EarnKitApiError). This empowers developers to move beyond generic error handling and build robust, programmatic responses to specific failures, such as prompting a user to top up when an EarnKitApiError with a status of 402 is caught.

  • Resilience Through Automatic Retries: The SDK is built to be resilient against transient network and server issues. It incorporates a built-in retry mechanism with exponential backoff. If a request fails with a server-side error (5xx), the SDK will automatically retry the request up to two more times, preventing temporary glitches from impacting the user experience.

  • Configurable & Transparent:

    • To maintain a clean developer console, all internal SDK logging is disabled by default and can be enabled via a debug: true flag.
    • To handle varying network conditions, the global API request timeout is configurable (requestTimeoutMs), making the developer’s application more resilient.
  • Client-Server Separation: The SDK’s sole responsibility is to act as a secure and efficient messenger to the EarnKit backend. All business logic (fee calculations, balance updates) resides on the server. This is a paramount design choice, as it allows for pricing models and features to be updated without requiring developers to update their installed SDK package.

  • Support for Multiple Instances: The SDK was explicitly designed as a standard class, not a singleton. This allows developers to instantiate multiple EarnKit clients in a single application, each configured for a different agent. This is essential for applications that need to manage multiple distinct AI agents simultaneously.

  • High-Level Helpers for Common Workflows: Beyond providing core API methods, the SDK includes high-level utility functions to simplify complex tasks. The pollForBalanceUpdate method, for instance, encapsulates the entire asynchronous workflow of checking for a balance change after a top-up, saving the developer from writing boilerplate polling code.

Part 2: Architectural Deep Dive

These core principles directly informed the key architectural decisions of the platform.

1. Hybrid Billing Model: On-Chain vs. Off-Chain

To provide a seamless user experience with instant, gas-free interactions, EarnKit uses a hybrid billing model. This approach addresses the challenge of processing high-frequency, low-value transactions for each AI interaction, which would be slow and costly if handled purely on-chain.

  • Off-Chain Micro-transactions: Per-prompt fees and credit deductions are handled as atomic updates in our own database. This allows for instantaneous transactions without gas fees.
  • On-Chain Macro-transactions: User top-ups are standard blockchain transactions (e.g., sending ETH on Base Sepolia) directly to the developer’s wallet, ensuring security and user control over their funds.

2. The track/capture/release Transaction Lifecycle

To guarantee that a user is never charged for a failed AI call and to ensure the developer is credited for a successful one, EarnKit implements a two-step transaction flow.

  • track() is called before the AI operation to place a temporary hold on the user’s balance.
  • capture() is called only after a successful AI response to finalize the charge.
  • If the AI call fails, release() is called to cancel the hold and refund the user.

This pattern adds a minor complexity to the SDK integration, as the developer must remember to call capture or release. However, this is a necessary trade-off for achieving a fair and reliable billing system, which is fundamental to user and developer trust.

3. Asynchronous Top-Up Confirmation

On-chain transactions can take time to confirm. To avoid forcing the user to wait on a loading screen, the top-up flow is fully asynchronous. The client submits the txHash to the backend, and the UI can respond immediately. A separate background process on the server monitors the blockchain for confirmation and updates the user’s balance once verified.

4. Idempotency for Safe Retries

Network requests can time out, and clients may retry a request. To prevent accidental double-charging in such scenarios, the track endpoint accepts an optional idempotencyKey. If a developer provides a unique key for an operation (e.g., a UUID), our backend can recognize and discard any duplicate requests, guaranteeing that the user is only charged once for the same operation.

Last updated on