Skip to content

API Reference

Complete reference for the Solenoid Meter API v1.

Base URL

https://api.solenoid.systems

All endpoints require authentication with a Bearer token. See Authentication.

Endpoints

GET /v1/meter/balance

Get the current balance for the authenticated user.

Request:

bash
curl -X GET https://api.solenoid.systems/v1/meter/balance \
  -H "Authorization: Bearer sm_your_api_key_here"

Success Response (200):

json
{
  "balance": 100,
  "user_id": "usr_abc123"
}

Fields:

  • balance (number): Current credit balance
  • user_id (string): Unique user identifier

Error Responses:

  • 401 - Invalid or missing API key

POST /v1/meter/deduct

Atomically deduct credits from the user's balance.

This operation is atomic - if the balance is insufficient, no deduction occurs and a 402 response is returned with the current balance.

Request:

bash
curl -X POST https://api.solenoid.systems/v1/meter/deduct \
  -H "Authorization: Bearer sm_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"amount": 1}'

Request Body:

json
{
  "amount": 1
}

Fields:

  • amount (number, required): Number of credits to deduct. Must be positive.

Success Response (200):

json
{
  "balance": 99,
  "user_id": "usr_abc123"
}

Fields:

  • balance (number): Remaining balance after deduction
  • user_id (string): Unique user identifier

Error Responses:

402 Payment Required - Insufficient balance:

json
{
  "error": {
    "code": "insufficient_balance",
    "message": "Insufficient balance for this operation"
  },
  "balance": 0,
  "user_id": "usr_abc123"
}

The current balance is included in the error response so you can prompt the user to add credits.

400 Bad Request - Invalid amount:

json
{
  "error": {
    "code": "invalid_request",
    "message": "Amount must be a positive number"
  }
}

401 Unauthorized - Invalid or missing API key


POST /v1/meter/refill

Add credits to the user's balance.

Request:

bash
curl -X POST https://api.solenoid.systems/v1/meter/refill \
  -H "Authorization: Bearer sm_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"amount": 100}'

Request Body:

json
{
  "amount": 100
}

Fields:

  • amount (number, required): Number of credits to add. Must be positive.

Success Response (200):

json
{
  "balance": 100,
  "user_id": "usr_abc123"
}

Fields:

  • balance (number): New balance after refill
  • user_id (string): Unique user identifier

Error Responses:

400 Bad Request - Invalid amount:

json
{
  "error": {
    "code": "invalid_request",
    "message": "Amount must be a positive number"
  }
}

401 Unauthorized - Invalid or missing API key


POST /v1/keys/rotate

Rotate your API key. The old key is immediately invalidated.

Request:

bash
curl -X POST https://api.solenoid.systems/v1/keys/rotate \
  -H "Authorization: Bearer sm_old_key_here"

Success Response (200):

json
{
  "key": "sm_new_key_here"
}

Fields:

  • key (string): Your new API key. Store this securely - the old key no longer works.

Error Responses:

401 Unauthorized - Invalid or missing API key


Response Format

All responses are flat JSON objects (no envelope wrapper).

Success responses contain the requested data directly.

Error responses include an error object with:

  • code (string): Machine-readable error code
  • message (string): Human-readable error description

Some errors include additional context fields (e.g., balance in insufficient balance errors).

Rate Limits

Free tier: 10 requests per second

Pro tier: Higher limits, no throttling on production workloads

Rate limit exceeded responses return 429 Too Many Requests:

json
{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "Rate limit exceeded"
  }
}

Atomicity Guarantees

All operations are atomic, powered by Cloudflare Durable Objects:

  • Deduct: Balance check and deduction happen atomically. No race conditions.
  • Refill: Credit addition is atomic.
  • Concurrent requests: Serialized per user. Correct balance guaranteed.

This eliminates double-spend issues and ensures consistency even under high concurrency.