This guide shows you how to create an auction using the Management API and how to bid on an item using the Client API. This guide uses the GraphQL UIs in the browser.
Prerequisites: Ensure that you have either a valid cookie in the browser or the API key and account ID headers set. See 🔓 API Access
A sale is a grouping of 1 or more items.
title: Short title for the saledescription: Further details for the salecurrency: Only "USD" is supportedbidIncrementTable: Defines increments by which bids can increase (optional at sale level, applies to all items)closingMethod: Only 'OVERLAPPING' is currently supportedclosingTimeCountdown: Optional value that applies to all items within the sale
mutation CreateSale {
createSale(accountId: "ACCOUNT_ID", input: {
title: "Test Sale",
description: "Description for the sale",
currency: "USD",
bidIncrementTable: {
rules: [
{ lowRange: 0, highRange: 100000, step: 10000 },
{ lowRange: 100000, highRange: 500000, step: 25000 },
]
}
closingMethod: OVERLAPPING,
closingTimeCountdown: 60000
}) {
id
status
}
}Response:
{
"data": {
"createSale": {
"id": "GENERATED_SALE_ID",
"status": "UNPUBLISHED"
}
}
}Create a standalone item that can be added to sales.
title: Title for the itemdescription: Description for the itemtags: Optional tags for categorization
mutation CreateItem {
createItem(accountId: "ACCOUNT_ID", input: {
title: "David Gilmour's 1969 Stratocaster"
description: "David Gilmour purchased the guitar, a 1969 model with a maple cap fingerboard and large headstock, in 1970 from Manny's Music in New York City to replace a similar guitar his parents bought him for his 21st birthday, which had been lost while touring with Pink Floyd in the United States in 1968. The Black Strat was originally a sunburst colour, but had been repainted black at Manny's. Since then, it has undergone numerous modifications."
tags: ["guitars", "vintage", "pink-floyd"]
}) {
id
title
description
}
}Response:
{
"data": {
"createItem": {
"id": "GENERATED_ITEM_ID",
"title": "David Gilmour's 1969 Stratocaster",
"description": "David Gilmour purchased the guitar..."
}
}
}Add the previously created item to the sale with auction-specific settings.
saleId: The sale ID to add the item toitemId: The item ID from the previous stepstartingBid: Minimum first bid (1000 cents = $10)reserve: Minimum selling price (200000000 cents = $2,000,000)allowedBidTypes: Bid types allowed (e.g., MAX, NORMAL)openDate: When bidding opens (RFC3339 timestamp)closingDate: When item moves to closing status (RFC3339 timestamp)
mutation AddItemToSale {
addItemToSale(accountId: "ACCOUNT_ID", input: {
saleId: "GENERATED_SALE_ID"
itemId: "GENERATED_ITEM_ID"
startingBid: 1000
reserve: 200000000
allowedBidTypes: [MAX]
openDate: "2024-02-01T15:00:00Z"
closingDate: "2024-02-01T16:00:00Z"
}) {
id
dates {
openDate
closingStart
closingEnd
}
status
}
}Response:
{
"data": {
"addItemToSale": {
"id": "GENERATED_ITEM_ID",
"dates": {
"openDate": "2024-02-01T15:00:00Z",
"closingStart": "2024-02-01T16:00:00Z",
"closingEnd": "2024-02-01T16:01:00Z"
},
"status": "ITEM_NOT_OPEN"
}
}
}After a sale is created and items have been added, it is initially in status UNPUBLISHED.
If the sale should go live, it needs to be published. After a sale has been published, Basta will manage the lifecycle of the sale and handle opening and closing of the sale and its items.
mutation PublishSale {
publishSale(accountId: "ACCOUNT_ID", input: {
saleId: "GENERATED_SALE_ID"
}) {
id
status
}
}Response:
{
"data": {
"publishSale": {
"id": "GENERATED_SALE_ID",
"status": "PUBLISHED"
}
}
}Verify your sale was created successfully:
query GetSale {
sale(accountId: "ACCOUNT_ID", id: "GENERATED_SALE_ID") {
id
status
items {
edges {
node {
id
dates {
openDate
closingStart
closingEnd
}
}
}
}
}
}Response:
{
"data": {
"sale": {
"id": "GENERATED_SALE_ID",
"status": "PUBLISHED",
"items": {
"edges": [
{
"node": {
"id": "GENERATED_ITEM_ID",
"dates": {
"openDate": "2024-02-01T15:00:00Z",
"closingStart": "2024-02-01T16:00:00Z",
"closingEnd": "2024-02-01T16:01:00Z"
}
}
}
]
}
}
}
}The owner of a sale must create a bidder token for each bidder, typically after bidder verification. A bid can only be executed if an authorization header with the corresponding bidder token is present.
userId: The userId of the bidderttl: Time to live for the bidder token in minutes
mutation CreateBidderToken($accountID: String!) {
createBidderToken(accountId: $accountID, input: {
metadata: {
userId: "user-1",
ttl: 60
}
}) {
token
expiration
}
}Response:
{
"data": {
"createBidderToken": {
"token": "GENERATED_BIDDER_TOKEN",
"expiration": "2023-04-19T17:20:10Z"
}
}
}Now switch to the Client API to place a bid.
To execute a bid, an Authorization header must be present:
{
"Authorization": "Bearer GENERATED_BIDDER_TOKEN"
}mutation MaxBid {
bidOnItem(
saleId: "GENERATED_SALE_ID",
itemId: "GENERATED_ITEM_ID",
amount: 10000,
type: MAX
) {
__typename
...on BidPlacedSuccess {
amount
bidStatus
date
bidType
}
...on BidPlacedError {
errorCode
error
}
}
}Response:
{
"data": {
"bidOnItem": {
"__typename": "BidPlacedSuccess",
"amount": 10000,
"bidStatus": "WINNING",
"date": "2024-02-01T15:30:00Z",
"bidType": "MAX"
}
}
}Here's a complete Node.js/TypeScript example:
import fetch from 'node-fetch';
const MANAGEMENT_API = 'https://management-api.basta.app/graphql';
const CLIENT_API = 'https://client.api.basta.app/graphql';
const ACCOUNT_ID = process.env.BASTA_ACCOUNT_ID;
const API_KEY = process.env.BASTA_API_KEY;
// Helper function for Management API calls
async function managementApiCall(query: string, variables = {}) {
const response = await fetch(MANAGEMENT_API, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-account-id': ACCOUNT_ID,
'x-api-key': API_KEY
},
body: JSON.stringify({ query, variables })
});
return response.json();
}
// Helper function for Client API calls
async function clientApiCall(query: string, variables = {}, bidderToken?: string) {
const headers: any = {
'Content-Type': 'application/json'
};
if (bidderToken) {
headers['Authorization'] = `Bearer ${bidderToken}`;
}
const response = await fetch(CLIENT_API, {
method: 'POST',
headers,
body: JSON.stringify({ query, variables })
});
return response.json();
}
async function createFirstAuction() {
// 1. Create Sale
const saleResult = await managementApiCall(`
mutation CreateSale($accountId: String!) {
createSale(accountId: $accountId, input: {
title: "Test Sale",
description: "My first auction",
currency: "USD",
closingMethod: OVERLAPPING,
closingTimeCountdown: 60000
}) {
id
status
}
}
`, { accountId: ACCOUNT_ID });
const saleId = saleResult.data.createSale.id;
console.log('Sale created:', saleId);
// 2. Create Item
const itemResult = await managementApiCall(`
mutation CreateItem($accountId: String!) {
createItem(accountId: $accountId, input: {
title: "Test Item",
description: "A test item for auction",
tags: ["test", "demo"]
}) {
id
}
}
`, { accountId: ACCOUNT_ID });
const itemId = itemResult.data.createItem.id;
console.log('Item created:', itemId);
// 3. Add Item to Sale
await managementApiCall(`
mutation AddItemToSale($accountId: String!, $saleId: ID!, $itemId: ID!) {
addItemToSale(accountId: $accountId, input: {
saleId: $saleId,
itemId: $itemId,
startingBid: 1000,
reserve: 10000,
allowedBidTypes: [MAX],
openDate: "${new Date(Date.now() + 60000).toISOString()}",
closingDate: "${new Date(Date.now() + 3600000).toISOString()}"
}) {
id
}
}
`, { accountId: ACCOUNT_ID, saleId, itemId });
console.log('Item added to sale');
// 4. Publish Sale
await managementApiCall(`
mutation PublishSale($accountId: String!, $saleId: ID!) {
publishSale(accountId: $accountId, input: {
saleId: $saleId
}) {
id
status
}
}
`, { accountId: ACCOUNT_ID, saleId });
console.log('Sale published');
// 5. Create Bidder Token
const tokenResult = await managementApiCall(`
mutation CreateBidderToken($accountId: String!) {
createBidderToken(accountId: $accountId, input: {
metadata: {
userId: "user-1",
ttl: 60
}
}) {
token
expiration
}
}
`, { accountId: ACCOUNT_ID });
const bidderToken = tokenResult.data.createBidderToken.token;
console.log('Bidder token created');
// 6. Place Bid (wait for sale to open)
await new Promise(resolve => setTimeout(resolve, 65000)); // Wait for sale to open
const bidResult = await clientApiCall(`
mutation BidOnItem($saleId: ID!, $itemId: ID!, $amount: Int!) {
bidOnItem(saleId: $saleId, itemId: $itemId, amount: $amount, type: MAX) {
__typename
...on BidPlacedSuccess {
amount
bidStatus
}
}
}
`, { saleId, itemId, amount: 5000 }, bidderToken);
console.log('Bid placed:', bidResult.data.bidOnItem);
}
createFirstAuction().catch(console.error);- Learn about Webhooks to receive real-time updates
- Explore GraphQL Subscriptions for live auction feeds
- Read the Management API documentation for advanced features
- Check out the Client API documentation for user-facing features
Need help? Contact us at hi@basta.app