Using API Keys

Using API Keys

What are API Keys?

API keys allow you to access http://boisestate.ai programmatically through code—instead of using the web interface. This enables you to:

  • Automate workflows: Process multiple requests without manual interaction

  • Build custom applications: Create software that uses http://boisestate.ai as an AI backbone

  • Integrate AI into existing tools: Connect http://boisestate.ai to your applications, scripts, or platforms

  • Batch process requests: Send many requests at once rather than one at a time

  • Enable real-time interactions: Use streaming responses for live, word-by-word feedback

Common use cases:

  • A faculty member auto-grading 200 student submissions with consistent rubrics

  • A research team processing text data through AI analysis at scale

  • A custom application that provides AI assistance to users without exposing http://boisestate.ai directly

  • A script that generates weekly reports with AI summaries

  • A chatbot that uses http://boisestate.ai as its AI engine

Who should use API keys?

  • Developers and programmers

  • IT staff building integrations

  • Faculty with technical projects

  • Researchers processing large datasets

  • Anyone comfortable with basic code and APIs

Important note: This guide assumes basic familiarity with HTTP requests, programming, or API concepts. If you're new to these, consider starting with the web interface or asking IT support for help.

Quick Reference: Prompt Templates vs. System Instructions vs. Assistants

Feature

Prompt Templates

System Instructions

Assistants

Feature

Prompt Templates

System Instructions

Assistants

What it is

Pre-written prompts with form fields

Behavioral guidelines for AI

Instructions + Documents + Web content

Purpose

Reusable structured questions

Consistent AI behavior/tone

Specialized expertise + resources

Setup time

10-20 minutes

5-10 minutes

20-30+ minutes

Best for

Repetitive prompts, workflows

Personal preferences, tone

Complex tasks with supporting materials

Example

"Research paper outline with [TOPIC] and [COURSE]"

"Always be encouraging"

"Grade lab reports using this rubric"

User fills in

Form fields each time

Nothing (applies automatically)

Nothing (applies automatically)

Can share

Yes (with others)

Yes (with others)

Yes (with others)

Contains supporting docs

No

No

Yes

Contains web content

No

No

Yes (via crawler)

Good for collaboration

Yes (standardize workflows)

Somewhat

Yes (standardize approaches + resources)

Key Characteristics & Limitations

Understanding these important characteristics will help you plan your API usage:

Characteristic

What It Means

Implication

Characteristic

What It Means

Implication

One active key per user

You can have only one API key at a time (can regenerate to get a new one)

Plan your API key distribution and rotation carefully

Keys expire after 90 days

API keys automatically stop working after 90 days

Set a calendar reminder to regenerate keys before they expire

Usage counts against monthly quota

Every API call uses part of your Boise State monthly token allocation

Monitor your usage; batch requests thoughtfully to avoid running out of quota

API conversations not saved

Requests via API are NOT logged to your web interface chat history

Keep your own logs if you need to maintain records

No default behavior

Unlike the web interface, API requests have no default system instructions

You must explicitly provide systemPrompt if you want to guide AI behavior

No conversation memory

Each API request is independent; context is not maintained between requests

Include previous messages in the messages array if you need multi-turn conversations

Important security notes:

  • ✅ API keys should be treated like passwords

  • ✅ Store keys in environment variables, not in code

  • ✅ Never commit API keys to version control (git, GitHub, etc.)

  • ✅ Rotate keys periodically for security

Pro tip: Use AI to help you troubleshoot your code! This can be useful if you come across “invalid key” or 401 errors during the process. You can paste your code into the prompt window without the API key to get feedback on your code.

Getting Your API Key

Step-by-step process:

  1. Log in to http://boisestate.ai using your Boise State credentials

  2. Go to https://boisestate.ai/settings/api-keys (or navigate through Settings → API Keys)

  3. Click/tap Create API Key

  4. Give your key a descriptive name

    • Example: "Research_Data_Processing_Q4_2025"

    • Example: "Course_Grading_Script_Fall2025"

    • Good names help you identify keys if you need to manage or regenerate them

  5. ⚠️ CRITICAL: Save your key immediately

    • Your API key will display only once after creation

    • Copy it to a secure location (password manager, secure note, environment variable file)

    • You CANNOT retrieve it later—if you lose it, you'll need to regenerate a new one

  6. Store your key securely:

    • Best practice: Store in an environment variable

    • Example: export BOISESTATE_API_KEY="your_key_here"

    • Never: Paste into your code directly

    • Never: Commit to version control (git, GitHub, etc.)

  7. Test your key (optional but recommended)

    • Run a simple API request with your key to verify it works

    • See the "Quick Start Examples" section below

Managing your API key:

From the API Keys settings page, you can:

  • View your key's creation date and last usage date

  • Regenerate your key (creates a new one; old one becomes invalid)

  • Delete your key (removes it immediately; API requests will fail)

When to regenerate your key:

  • ✅ If you suspect the key has been compromised

  • ✅ If you want to rotate keys for security

  • ✅ Before the 90-day expiration (set a reminder!)

  • ✅ If you need a fresh start after testing

What happens if your key expires?

  • API requests will fail with a 401 Unauthorized error

  • Regenerate a new key

  • Update your applications/scripts with the new key

Understanding the Two Endpoints

boisestate.ai offers two different endpoints for different use cases. Choose based on your needs:

Endpoint

Best For

Response Style

Latency

Use Case

Endpoint

Best For

Response Style

Latency

Use Case

/chat/api-converse

Batch processing, simple requests, non-interactive scenarios

Complete response delivered at once as JSON

Slightly higher (full response generated first)

Grading scripts, batch data analysis, backend processing

/chat/api-chat

Interactive apps, real-time feedback, streaming display

Streaming responses (word-by-word, SSE format)

Lower (starts responding immediately)

Live chatbots, user-facing applications, interactive tools

Decision framework:

Use /chat/api-converse if:

  • You're processing multiple items in a script (no user waiting)

  • You want a complete, finished response before proceeding

  • You're building a backend service (not interactive)

  • You need the full response to analyze or store

  • You're doing batch grading or data processing

Use /chat/api-chat if:

  • You're building a user-facing application

  • The user is waiting for a response in real-time

  • You want to show progress (streaming output)

  • You want a more interactive experience

  • You need lower latency for responsive interactions

Example scenarios:

Scenario

Endpoint

Why

Scenario

Endpoint

Why

Faculty auto-grading 100 essays

/chat/api-converse

No user waiting; process all in batch

Student uses chatbot in your application

/chat/api-chat

Student waits for response; streaming is better UX

Research processing 1000 documents

/chat/api-converse

Batch processing; full response needed

Live writing assistant app

/chat/api-chat

Real-time feedback; streaming is more responsive

Automated report generation

/chat/api-converse

Background process; full response needed

Choosing an AI Model

The modelId parameter specifies which AI model to use. Boise State currently supports several models with different capabilities and costs:

Model ID

Speed

Accuracy

Cost

Best For

Model ID

Speed

Accuracy

Cost

Best For

us.amazon.nova-pro-v1:0

Fast

High

Lower

General tasks, most use cases

us.amazon.nova-lite-v1:0

Very Fast

Good

Very Low

Simple tasks, high volume

us.amazon.nova-premier-v1:0

Slower

Highest

Higher

Complex tasks, research

Recommendation: Start with us.amazon.nova-pro-v1:0 (good balance of speed, quality, and cost). Switch to other models based on your specific needs.

Setting model parameters:

{ "modelId": "us.amazon.nova-pro-v1:0", "temperature": 0.7, "maxTokens": 1000, "topP": 0.9 }

Parameter guide:

  • temperature (0.0 - 1.0): Controls response creativity

    • 0.0 = Very focused, deterministic (same output every time)

    • 0.5 = Balanced (recommended for most tasks)

    • 1.0 = Very creative, unpredictable

    • For grading: Use lower (0.3-0.5)

    • For creative tasks: Use higher (0.7-1.0)

  • maxTokens (integer): Maximum response length

    • 1 token ≈ 4 characters

    • Use smaller values for summaries, larger for essays

    • Default/recommended: 1000-2000

  • topP (0.0 - 1.0): Sampling diversity

    • Usually leave at default (0.9)

    • Lower = more focused; Higher = more diverse

    • Rarely needs adjustment


Quick Start Examples

Choose the example that matches your use case. All examples use curl, Python, and JavaScript.

Before you start:

  • Replace YOUR_API_KEY with your actual API key

  • Choose the appropriate modelId (see "Choosing an AI Model" above)

  • Test examples with simple messages first before scaling up

Complete Code Examples (Production-Ready)

The quick start examples above show basic usage. Here are more complete, production-ready examples with error handling:

Python: Batch Grading Script

import requests import json import os from datetime import datetime # Load API key from environment variable (don't hardcode!) API_KEY = os.getenv('BOISESTATE_API_KEY') if not API_KEY: raise ValueError("API key not found. Set BOISESTATE_API_KEY environment variable.") def grade_submission(student_name, submission_text, rubric): """Grade a single submission and return feedback.""" url = 'https://api.boisestate.ai/chat/api-converse' headers = { 'X-API-Key': API_KEY, 'Content-Type': 'application/json' } system_prompt = f"You are an expert instructor grading assignments. Use this rubric: {rubric}" payload = { 'message': f"Grade this submission:\n\n{submission_text}", 'modelId': 'us.amazon.nova-pro-v1:0', 'systemPrompt': system_prompt, 'temperature': 0.5, 'maxTokens': 1500 } try: response = requests.post(url, headers=headers, json=payload, timeout=30) response.raise_for_status() # Raise error for bad status codes data = response.json() return { 'student': student_name, 'feedback': data['text'], 'tokens_used': data['usage']['outputTokens'], 'timestamp': datetime.now().isoformat() } except requests.exceptions.Timeout: return {'student': student_name, 'error': 'Request timed out'} except requests.exceptions.HTTPError as e: return {'student': student_name, 'error': f'HTTP error: {e.response.status_code}'} except Exception as e: return {'student': student_name, 'error': str(e)} # Example usage submissions = [ {'name': 'Alice', 'text': 'My essay about climate change...'}, {'name': 'Bob', 'text': 'My essay about climate change...'}, # Add more submissions ] rubric = "Grade on: clarity (25%), argument strength (50%), evidence use (25%)" results = [] for submission in submissions: result = grade_submission(submission['name'], submission['text'], rubric) results.append(result) print(f"Graded {submission['name']}: {result.get('error') or 'Success'}") # Save results with open('grading_results.json', 'w') as f: json.dump(results, f, indent=2)

JavaScript: Interactive Chat App

const API_KEY = process.env.BOISESTATE_API_KEY; if (!API_KEY) { throw new Error('API key not found. Set BOISESTATE_API_KEY environment variable.'); } async function streamChat(userMessage, conversationHistory) { /** * Send a message and stream the response word-by-word */ const url = 'https://api.boisestate.ai/chat/api-chat'; // Add new user message to history const messages = [ ...conversationHistory, { role: 'user', content: userMessage } ]; const payload = { messages: messages, modelId: 'us.amazon.nova-pro-v1:0', temperature: 0.7, maxTokens: 1000 }; try { const response = await fetch(url, { method: 'POST', headers: { 'X-API-Key': API_KEY, 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const reader = response.body.getReader(); const decoder = new TextDecoder(); let assistantMessage = ''; while (true) { const { done, value } = await reader.read(); if (done) break; const chunk = decoder.decode(value); const lines = chunk.split('\n'); for (const line of lines) { if (line.startsWith('data: ')) { try { const data = JSON.parse(line.slice(6)); if (data.type === 'content_delta') { process.stdout.write(data.delta); // Print to console assistantMessage += data.delta; } } catch (e) { // Skip parsing errors for malformed JSON } } } } return assistantMessage; } catch (error) { console.error('Error streaming chat:', error); throw error; } } // Example usage const history = []; const userInput = "What is machine learning?"; streamChat(userInput, history).then(response => { history.push({ role: 'user', content: userInput }); history.push({ role: 'assistant', content: response }); console.log('\n\n--- Next message ---'); // User can continue with the same conversation history });

Common Patterns & Best Practices

Pattern 1: Batch Processing with Error Handling

When processing many items (grading, analysis, etc.):

def batch_process(items, processor_function, max_retries=3): """Process items with error handling and retry logic.""" results = [] for i, item in enumerate(items): retries = 0 while retries < max_retries: try: result = processor_function(item) results.append(result) print(f"✓ Processed {i+1}/{len(items)}") break except Exception as e: retries += 1 if retries < max_retries: print(f"⚠ Retry {retries}/{max_retries} for item {i+1}: {e}") time.sleep(2 ** retries) # Exponential backoff else: results.append({'item': item, 'error': str(e)}) print(f"✗ Failed to process item {i+1}") return results

Pattern 2: Rate Limiting

To avoid overwhelming the API:

import time from datetime import datetime, timedelta class RateLimiter: def __init__(self, requests_per_minute=60): self.requests_per_minute = requests_per_minute self.request_times = [] def wait_if_needed(self): now = datetime.now() # Remove requests older than 1 minute self.request_times = [t for t in self.request_times if now - t < timedelta(minutes=1)] if len(self.request_times) >= self.requests_per_minute: # Need to wait oldest = self.request_times[0] wait_time = (oldest + timedelta(minutes=1) - now).total_seconds() if wait_time > 0: print(f"Rate limit reached. Waiting {wait_time:.1f}s...") time.sleep(wait_time) self.request_times.append(now) # Usage limiter = RateLimiter(requests_per_minute=60) for item in items: limiter.wait_if_needed() result = process_item(item)

Best practices:

  • Use environment variables for API keys (never hardcode)

  • Implement timeout values to avoid hanging requests

  • Handle all error codes (401, 403, 400, 429, 500+)

  • Log results for debugging and auditing

  • Batch requests when processing multiple items (more efficient)

  • Monitor token usage to avoid exceeding monthly quota

  • Test with small datasets first before scaling to production

  • Implement rate limiting to respect API limits

  • Set reasonable timeouts (30 seconds is a good default)

Things to avoid:

  • ❌ Committing API keys to version control

  • ❌ Sending secrets (passwords, SSNs) to the API

  • ❌ Making too many simultaneous requests (use rate limiting)

  • ❌ Ignoring error responses (handle gracefully)

  • ❌ Not monitoring quota usage (you might hit limits unexpectedly)


Security Best Practices

API keys are powerful and need to be protected like passwords. Follow these practices:

DO:

  • ✅ Store API keys in environment variables

    • Example: export BOISESTATE_API_KEY="your_key"

    • Then access: api_key = os.getenv('BOISESTATE_API_KEY')

  • ✅ Store API keys in secure configuration files that are .gitignored

    • Create .env file with your key (add to .gitignore)

    • Use a library like python-dotenv to load it

  • ✅ Regenerate your key periodically

    • Consider rotating every 3 months

    • Regenerate immediately if you suspect compromise

  • ✅ Treat API keys like passwords

  • ✅ Use HTTPS only (all http://boisestate.ai API endpoints use HTTPS)

  • ✅ Monitor API key usage and activity

DON'T:

  • ❌ Commit API keys to version control (git, GitHub, etc.)

    • Even if you delete them later, they're in history forever

    • Use .gitignore to prevent accidental commits

  • ❌ Paste API keys in Slack, email, or public forums

  • ❌ Hardcode API keys in your source code

  • ❌ Share your API key with others (each user should get their own)

  • ❌ Display API keys in logs or error messages

  • ❌ Use API keys in client-side code (JavaScript in browsers)

    • This exposes them to anyone viewing your page source

    • Always keep keys on the server-side

If you think your key was compromised:

  1. Go to https://boisestate.ai/api-keys

  2. Regenerate your key immediately (old key becomes invalid)

  3. Update all applications/scripts with the new key

  4. Monitor activity for suspicious requests

  5. Contact IT if you notice unauthorized usage

Using with Git:

To prevent accidental key commits:

# Create .gitignore file echo ".env" >> .gitignore echo "secrets.json" >> .gitignore git add .gitignore git commit -m "Add .gitignore" # Your .env file (in .gitignore, never committed) # BOISESTATE_API_KEY=your_key_here

Monitoring & Debugging

Monitoring API Usage:

  1. Check your quota:

    • Visit