aura-labs.ai

Beacon Basics: Creating Your First Selling Agent

Version: 1.1 Date: April 14, 2026 Protocol: v2.2

Welcome to AURA! This tutorial will guide you through creating and running your first Beacon—an intelligent selling agent that responds to purchase intents from Scout buyers. By the end, you’ll have a working Beacon that can register with AURA Core, listen for buyer sessions, and submit competitive offers in real-time.

What You’ll Learn

Prerequisites

Estimated Time: ~15 minutes


What is a Beacon?

In the AURA ecosystem, a Beacon is a selling agent that represents your business. When a Scout (a buyer’s agent) searches for products or services, your Beacon can respond with offers. Think of it as your automated sales representative that:

Beacons are the foundation of the AURA marketplace—they’re how suppliers connect with buyers at scale.


Step 1: Install the SDK

Create a new directory for your Beacon and initialize Node.js:

mkdir my-first-beacon
cd my-first-beacon
npm init -y
npm install @aura-labs-ai/beacon

Step 2: Create Your First Beacon

Create a new file called beacon.js:

import { createBeacon } from '@aura-labs-ai/beacon';

const beacon = createBeacon({
  externalId: 'acme-widgets-001',
  name: 'ACME Widget Co.',
  description: 'Premium industrial widgets and components',
  capabilities: {
    products: ['industrial-widgets', 'components'],
    maxOrder: 10000,
    deliveryDays: 3
  },
  metadata: {
    rating: 4.8,
    reviewCount: 247,
    certifications: ['ISO-9001', 'ISO-14001']
  }
});

console.log('Beacon created:', beacon.name);

This configuration tells AURA about your business:


Step 3: Register with AURA Core

After creating your Beacon, register it with AURA Core:

const registered = await beacon.register();
console.log('Registration successful!');
console.log('Beacon ID:', registered.beaconId);
console.log('Status:', registered.status);

Registration returns:


Step 4: Listen for Scout Sessions

Sessions are purchase opportunities. When a Scout finds a matching buyer, it creates a session and sends it to your Beacon:

beacon.onSession(async (session) => {
  console.log('New session received!');
  console.log('Intent:', session.intent.raw);
  console.log('Region:', session.region);
  console.log('Session ID:', session.sessionId);
});

The session.intent.raw contains the buyer’s natural language request—e.g., “I need 500 industrial widgets for automotive manufacturing.”


Step 5: Submit Your First Offer

When you receive a session, use interpretIntent() to match the buyer’s intent against your product catalog and submit an offer:

// Define your product catalog
const catalog = [
  {
    name: 'Industrial Widget Pro',
    sku: 'WDG-500-PRO',
    category: 'industrial-components',
    tags: ['widget', 'industrial', 'precision'],
    price: 85.00
  },
  {
    name: 'Standard Widget',
    sku: 'WDG-100-STD',
    category: 'industrial-components',
    tags: ['widget', 'standard', 'bulk'],
    price: 45.00
  }
];

beacon.onSession(async (session) => {
  // Use NLP-powered catalog matching instead of simple string matching
  const result = await beacon.interpretIntent(session.intent.raw, catalog);

  if (result.matches.length > 0) {
    const topMatch = result.matches[0];

    const offer = {
      product: {
        name: topMatch.item.name,
        sku: topMatch.item.sku,
        description: 'High-precision industrial widget, 500-pack',
        category: topMatch.item.category
      },
      unitPrice: topMatch.item.price,
      quantity: 500,
      currency: 'USD',
      deliveryDate: '2026-03-10',
      terms: {
        warranty: '12-month manufacturer warranty',
        returnPolicy: '30-day full refund guarantee'
      }
    };

    try {
      await beacon.submitOffer(session.sessionId, offer);
      console.log('Offer submitted successfully!');
      console.log(`  Matched: ${topMatch.item.name} (score: ${topMatch.score})`);
      console.log(`  Confidence: ${result.confidence}`);
    } catch (error) {
      console.error('Failed to submit offer:', error.message);
    }
  }
});

Step 6: Start Polling

Begin polling AURA Core for new sessions. Polling checks periodically (default: every 5 seconds) for incoming opportunities:

await beacon.startPolling();
console.log('Beacon is now listening for opportunities!');

The Beacon will now:

  1. Check for new sessions every 5 seconds
  2. Trigger your onSession handler when sessions arrive
  3. Continue until you call beacon.stopPolling()

Understanding the Flow

Here’s how a transaction flows through AURA:

┌──────────────┐
│ Scout Intent │  "I need 500 widgets"
└──────┬───────┘
       │
       ▼
┌──────────────────┐
│ Session Created  │  Scout creates session, routes to Beacons
└──────┬───────────┘
       │
       ▼
┌──────────────────┐
│ Beacon Polls     │  Your beacon checks for new sessions
└──────┬───────────┘
       │
       ▼
┌──────────────────┐
│ Offer Submitted  │  Your beacon evaluates & submits offer
└──────┬───────────┘
       │
       ▼
┌──────────────────┐
│ Scout Evaluates  │  Scout compares offers from all Beacons
└──────┬───────────┘
       │
       ▼
┌──────────────────┐
│ Transaction      │  Winner is selected, order confirmed
└──────────────────┘

Complete Working Example

Here’s a complete, runnable Beacon that you can start with:

import { createBeacon } from '@aura-labs-ai/beacon';

// Define your product catalog
const catalog = [
  { name: 'Industrial Widget Pro', sku: 'WDG-500-PRO', category: 'widgets', tags: ['industrial', 'precision'], price: 85.00 },
  { name: 'Standard Widget', sku: 'WDG-100-STD', category: 'widgets', tags: ['standard', 'bulk'], price: 45.00 },
  { name: 'Micro Widget', sku: 'WDG-010-MIC', category: 'widgets', tags: ['micro', 'electronics'], price: 12.00 },
];

const beacon = createBeacon({
  externalId: 'acme-widgets-001',
  name: 'ACME Widget Co.',
  description: 'Premium industrial widgets and components',
  capabilities: {
    products: ['industrial-widgets', 'components'],
    maxOrder: 10000,
    deliveryDays: 3
  },
  metadata: {
    rating: 4.8,
    reviewCount: 247,
    certifications: ['ISO-9001', 'ISO-14001']
  }
});

// Register with AURA Core
console.log('Registering Beacon...');
const registered = await beacon.register();
console.log(`Registered as "${registered.name}" (ID: ${registered.beaconId})`);

// Listen for buyer sessions
beacon.onSession(async (session) => {
  console.log(`\nNew session from Scout!`);
  console.log(`  Intent: "${session.intent.raw}"`);

  // Use NLP-powered catalog matching
  const result = await beacon.interpretIntent(session.intent.raw, catalog);

  if (result.matches.length > 0) {
    const topMatch = result.matches[0];
    console.log(`  Matched: ${topMatch.item.name} (score: ${topMatch.score})`);

    const offer = {
      product: {
        name: topMatch.item.name,
        sku: topMatch.item.sku,
        description: `${topMatch.item.name} — matched via NLP`,
        category: topMatch.item.category
      },
      unitPrice: topMatch.item.price,
      quantity: 500,
      currency: 'USD',
      deliveryDate: '2026-03-10',
      terms: {
        warranty: '12-month manufacturer warranty',
        returnPolicy: '30-day full refund guarantee'
      }
    };

    try {
      await beacon.submitOffer(session.sessionId, offer);
      console.log(`  Offer submitted: 500 units @ $${topMatch.item.price} each`);
    } catch (error) {
      console.error(`  Failed to submit offer: ${error.message}`);
    }
  } else {
    console.log(`  No catalog match — skipping session`);
  }
});

// Handle accepted offers
beacon.onOfferAccepted((transaction) => {
  console.log(`\nOffer accepted!`);
  console.log(`  Transaction ID: ${transaction.transactionId}`);
});

// Start listening for opportunities
console.log('Starting to listen for opportunities...');
await beacon.startPolling();
console.log('Beacon is ready! Listening for buyer intents...\n');

// Keep the process running
process.on('SIGINT', () => {
  console.log('\nShutting down Beacon...');
  beacon.stopPolling();
  process.exit(0);
});

To run this example:

node beacon.js

Your Beacon will now register and start listening for opportunities. When a Scout sends a matching session, your Beacon will submit an offer.


Best Practices

✓ DO: Use interpretIntent for Smart Matching

beacon.onSession(async (session) => {
  // Use NLP-powered catalog matching for accurate results
  const result = await beacon.interpretIntent(session.intent.raw, catalog);
  if (result.matches.length > 0 && result.matches[0].score > 20) {
    await beacon.submitOffer(session.sessionId, buildOffer(result.matches[0]));
  }
});

✗ DON’T: Submit Offers for Everything

// Bad: Submitting offers you can't fulfill
beacon.onSession(async (session) => {
  await beacon.submitOffer(session.sessionId, offer); // Always submit!
});

✓ DO: Use Unique External IDs

const beacon = createBeacon({
  externalId: 'acme-widgets-001', // Include company + instance ID
  // ...
});

✗ DON’T: Hardcode Configuration

// Bad: Configuration is hardcoded
const beacon = createBeacon({
  externalId: 'beacon-123',
  // ...
});

✓ DO: Handle Errors Gracefully

try {
  await beacon.submitOffer(session.sessionId, offer);
} catch (error) {
  console.error('Failed to submit offer:', error.message);
  // Log error, alert team, or retry later
}

✗ DON’T: Ignore Submission Errors

// Bad: Silent failures
await beacon.submitOffer(session.sessionId, offer);

Troubleshooting

Issue: “Registration failed: Invalid externalId”

Solution: Ensure externalId is a non-empty string and unique to your Beacon. Try including your company name and an instance identifier.

externalId: 'my-company-beacon-001'

Issue: “Beacon is polling but not receiving sessions”

Solution:

Issue: “OfferError: Cannot submit offer without registering first”

Solution: Always call beacon.register() and wait for it to complete before calling other methods:

const registered = await beacon.register();
// Now safe to use other methods
await beacon.startPolling();

Issue: “Timeout connecting to AURA Core”

Solution: AURA Core is at https://aura-labsai-production.up.railway.app. Verify:

Issue: “session is undefined in onSession handler”

Solution: Ensure your handler is registered before calling startPolling():

beacon.onSession(async (session) => { /* ... */ }); // Register first
await beacon.startPolling();                        // Then start polling

Next Steps

You now have a working Beacon! Here’s what to learn next:

  1. Intent Interpretation - Advanced NLP catalog matching and scoring
  2. Beacon Inventory - Manage your product catalog and availability
  3. Beacon Pricing - Set dynamic prices and discounts
  4. Beacon Transactions - Handle order fulfillment and tracking

Questions?

We’re here to help! Reach out to hello@aura-labs.ai with questions, feedback, or feature requests.

Happy selling! 🚀