BOOK A DEMO

APIs

Client API

Powers user-facing auction interactions from web and mobile apps — public reads plus authenticated user actions via bidder tokens.

The Client API is designed for use in client-side environments such as web or mobile apps. It powers user-facing auction interactions and supports both public reads and authenticated user actions.

Access modes

ModeUse caseAuth mechanism
PublicUnauthenticated reads on auction objectsNo auth required
Authenticated (User)Placing bids, receiving user-scoped subscriptionsJWT in Authorization header

Bidder tokens (JWT)

Since Basta does not manage users for integrating businesses, businesses generate their own bidder tokens via the Management API.

These JWT tokens:

  • Contain a userId and ttl
  • Give user permissions to make bids
  • Are added to the Authorization header on Client API requests

Example header

JSON
{
  "Authorization": "Bearer <BIDDER_JWT>"
}

The userId embedded in the token is used to resolve bids and subscriptions in the user's context.

Capabilities

Unauthenticated queries

Retrieve auction listings, timing details, bid history, etc.

GraphQL
query GetAuctions {
  sales {
    id
    title
    startDate
    endDate
    items {
      id
      title
      currentBid
    }
  }
}

Authenticated mutations

Place bids via BidOnItem using a bidder token:

GraphQL
mutation PlaceBid {
  bidOnItem(input: {
    saleId: "sale-123"
    itemId: "item-456"
    amount: 1000
  }) {
    bidId
    amount
    status
  }
}

User-scoped subscriptions (WebSockets)

Subscribe to auction events in real-time, filtered by userId in token:

GraphQL
subscription WatchAuction {
  auctionUpdates(saleId: "sale-123") {
    itemId
    currentBid
    bidder {
      id
      isMe
    }
  }
}

GraphQL Explorer

Explore the Client API: client.api.basta.app

Code examples

JavaScript/TypeScript — public query

TypeScript
// No authentication needed for public queries
const response = await fetch('https://client.api.basta.app/graphql', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    query: `
      query GetAuctions {
        sales {
          id
          title
          startDate
          endDate
        }
      }
    `
  })
});

const { data } = await response.json();

JavaScript/TypeScript — authenticated mutation

TypeScript
// First, get a bidder token from your backend (which calls Management API)
const bidderToken = await fetchBidderTokenFromBackend(userId);

// Then use it to place a bid
const response = await fetch('https://client.api.basta.app/graphql', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${bidderToken}`
  },
  body: JSON.stringify({
    query: `
      mutation PlaceBid($input: BidInput!) {
        bidOnItem(input: $input) {
          bidId
          amount
          status
        }
      }
    `,
    variables: {
      input: {
        saleId: 'sale-123',
        itemId: 'item-456',
        amount: 1000
      }
    }
  })
});

const { data } = await response.json();

React example with Apollo Client

TypeScript
import { ApolloClient, InMemoryCache, gql, useQuery, useMutation } from '@apollo/client';

// Configure Apollo Client
const client = new ApolloClient({
  uri: 'https://client.api.basta.app/graphql',
  cache: new InMemoryCache(),
  headers: {
    // Add authorization header if user is authenticated
    ...(bidderToken && { Authorization: `Bearer ${bidderToken}` })
  }
});

// Query component
function AuctionList() {
  const { loading, error, data } = useQuery(gql`
    query GetAuctions {
      sales {
        id
        title
        items {
          id
          title
          currentBid
        }
      }
    }
  `);

  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;

  return (
    <div>
      {data.sales.map(sale => (
        <div key={sale.id}>
          <h2>{sale.title}</h2>
          {sale.items.map(item => (
            <div key={item.id}>
              {item.title} - Current bid: ${item.currentBid}
            </div>
          ))}
        </div>
      ))}
    </div>
  );
}

// Mutation component
function BidButton({ saleId, itemId, amount }) {
  const [placeBid, { loading }] = useMutation(gql`
    mutation PlaceBid($input: BidInput!) {
      bidOnItem(input: $input) {
        bidId
        amount
        status
      }
    }
  `);

  const handleBid = async () => {
    try {
      const result = await placeBid({
        variables: {
          input: { saleId, itemId, amount }
        }
      });
      console.log('Bid placed:', result.data.bidOnItem);
    } catch (error) {
      console.error('Bid failed:', error);
    }
  };

  return (
    <button onClick={handleBid} disabled={loading}>
      {loading ? 'Placing bid...' : `Bid $${amount}`}
    </button>
  );
}

Ruby example

Ruby
require 'net/http'
require 'json'

class BastaClientAPI
  API_URL = 'https://client.api.basta.app/graphql'

  def initialize(bidder_token = nil)
    @bidder_token = bidder_token
  end

  # Public query - no auth needed
  def get_auctions
    query = <<~GRAPHQL
      query GetAuctions {
        sales {
          id
          title
          startDate
          endDate
        }
      }
    GRAPHQL

    execute_query(query)
  end

  # Authenticated mutation - requires bidder token
  def place_bid(sale_id:, item_id:, amount:)
    raise 'Bidder token required' unless @bidder_token

    query = <<~GRAPHQL
      mutation PlaceBid($input: BidInput!) {
        bidOnItem(input: $input) {
          bidId
          amount
          status
        }
      }
    GRAPHQL

    variables = {
      input: {
        saleId: sale_id,
        itemId: item_id,
        amount: amount
      }
    }

    execute_query(query, variables, authenticated: true)
  end

  private

  def execute_query(query, variables = {}, authenticated: false)
    uri = URI(API_URL)
    request = Net::HTTP::Post.new(uri)
    request['Content-Type'] = 'application/json'
    request['Authorization'] = "Bearer #{@bidder_token}" if authenticated && @bidder_token

    request.body = JSON.generate({
      query: query,
      variables: variables
    })

    response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
      http.request(request)
    end

    JSON.parse(response.body)
  end
end

# Usage
# Public access
public_api = BastaClientAPI.new
auctions = public_api.get_auctions

# Authenticated access
bidder_token = get_token_from_your_backend(user_id)
authenticated_api = BastaClientAPI.new(bidder_token)
result = authenticated_api.place_bid(
  sale_id: 'sale-123',
  item_id: 'item-456',
  amount: 1000
)

Rate limiting

The Client API implements rate limiting to ensure fair usage and protect the service.

Rate limit details

  • Limit: 400 requests per 10 seconds
  • Scope: Per IP address and endpoint combination
  • Response: HTTP 429 Too Many Requests when exceeded

Rate limit headers

When making requests, you can monitor your rate limit status through response headers (if available):

  • X-RateLimit-Limit: Maximum requests allowed in the time window
  • X-RateLimit-Remaining: Number of requests remaining
  • X-RateLimit-Reset: Time when the rate limit resets

Example response when rate limited

HTTP
HTTP/1.1 429 Too Many Requests
Content-Type: text/plain

rate limit exceeded

Best practices

  1. Implement retry logic: Add exponential backoff when receiving 429 responses
  2. Cache public data: Cache auction listings and item details to reduce API calls
  3. Use subscriptions: For real-time updates, use GraphQL subscriptions instead of polling
  4. Batch queries: Combine multiple data requirements into a single GraphQL query

Example: retry logic

TypeScript
async function queryWithRetry(query: string, variables: any, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      const response = await fetch('https://client.api.basta.app/graphql', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ query, variables })
      });

      if (response.status === 429) {
        // Exponential backoff: 1s, 2s, 4s
        const waitTime = Math.pow(2, i) * 1000;
        console.log(`Rate limited. Retrying in ${waitTime}ms...`);
        await new Promise(resolve => setTimeout(resolve, waitTime));
        continue;
      }

      return await response.json();
    } catch (error) {
      if (i === maxRetries - 1) throw error;
    }
  }
}

Summary

The Client API offers full auction interactivity while keeping your users' identity management under your control. Basta provides a secure and flexible token-based mechanism that fits well with existing auth stacks.

Key points

  • No auth required for public auction browsing
  • Bidder tokens (JWT) enable authenticated actions
  • Your backend generates tokens via Management API
  • User context is preserved via userId in token
  • Real-time updates via GraphQL subscriptions
  • Rate limits enforce fair usage (400 requests per 10 seconds)

Related documentation

For questions about the Client API, email us at hi@basta.app.