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.
| Mode | Use Case | Auth Mechanism |
|---|---|---|
| Public | Unauthenticated reads on auction objects | No auth required |
| Authenticated (User) | Placing bids, receiving user-scoped subscriptions | JWT in Authorization header |
Since Basta does not manage users for integrating businesses, businesses generate their own bidder tokens via the Management API.
These JWT tokens:
- Contain a
userIdandttl - Give user permissions to make bids
- Are added to the
Authorizationheader on Client API requests
{
"Authorization": "Bearer <BIDDER_JWT>"
}📌 The userId embedded in the token is used to resolve bids and subscriptions in the user's context.
Retrieve auction listings, timing details, bid history, etc.
query GetAuctions {
sales {
id
title
startDate
endDate
items {
id
title
currentBid
}
}
}Place bids via BidOnItem using a bidder token:
mutation PlaceBid {
bidOnItem(input: {
saleId: "sale-123"
itemId: "item-456"
amount: 1000
}) {
bidId
amount
status
}
}Subscribe to auction events in real-time, filtered by userId in token:
subscription WatchAuction {
auctionUpdates(saleId: "sale-123") {
itemId
currentBid
bidder {
id
isMe
}
}
}Explore the Client API: client.api.basta.app
// 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();// 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();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>
);
}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
)The Client API implements rate limiting to ensure fair usage and protect the service.
- Limit: 400 requests per 10 seconds
- Scope: Per IP address and endpoint combination
- Response: HTTP
429 Too Many Requestswhen exceeded
When making requests, you can monitor your rate limit status through response headers (if available):
X-RateLimit-Limit: Maximum requests allowed in the time windowX-RateLimit-Remaining: Number of requests remainingX-RateLimit-Reset: Time when the rate limit resets
HTTP/1.1 429 Too Many Requests
Content-Type: text/plain
rate limit exceeded- Implement Retry Logic: Add exponential backoff when receiving 429 responses
- Cache Public Data: Cache auction listings and item details to reduce API calls
- Use Subscriptions: For real-time updates, use GraphQL subscriptions instead of polling
- Batch Queries: Combine multiple data requirements into a single GraphQL query
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;
}
}
}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.
- 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
userIdin token - Real-time updates via GraphQL subscriptions
- Rate limits enforce fair usage (400 requests per 10 seconds)
- Management API - For generating bidder tokens
- API Overview
- Getting Started
- Webhooks
For questions about the Client API:
- Email: hi@basta.app
- Documentation: docs.basta.ai