AI / Jarvis Block

Machine learning features for modern applications
The AI Block brings powerful machine learning capabilities to your application without the complexity of building ML infrastructure. Leverage pre-built AI features for text analysis, image recognition, recommendations, content moderation, and more—all through a simple REST API.
Features
- Text Analysis - Sentiment, entities, key phrases, and language detection
- Image Recognition - Classification, object detection, and OCR
- Smart Recommendations - Personalized suggestions based on user behavior
- Content Moderation - Detect inappropriate content and spam
- Embeddings - Vector representations for semantic search and similarity
- Language Translation - Translate text between 100+ languages
- Summarization - Generate concise summaries of long text
- Classification - Custom text and image classification
Quick Start
npm install @23blocks/sdk
API Endpoint
| Service | URL |
|---|---|
| AI (Jarvis) | https://jarvis.api.us.23blocks.com |
Environment Routing: Use the same URL for all environments. Your API key determines the environment:
pk_test_*/sk_test_*→ Routes to Stagingpk_live_*/sk_live_*→ Routes to Production
import { create23BlocksClient } from '@23blocks/sdk';
const client = create23BlocksClient({
urls: { ai: 'https://jarvis.api.us.23blocks.com' },
apiKey: 'your-api-key', // Use pk_test_* for staging, pk_live_* for production
});
// Analyze sentiment
const sentiment = await client.ai.analyzeSentiment({
text: 'This product is amazing!'
});
// { score: 0.92, label: 'positive' }
// Get recommendations
const recs = await client.ai.recommend({
userId: 'user_123',
context: 'product-page',
limit: 5
});
// Moderate content
const moderation = await client.ai.moderate({
text: 'Some user-generated content...'
});
Authentication
All API requests require authentication using your API credentials.
Required Headers
X-App-Id: your-app-id
X-Api-Key: your-api-key
Content-Type: application/json
Text Analysis API
Analyze text for sentiment, entities, and more.
Analyze Sentiment
Determine the emotional tone of text.
POST /ai/v1/text/sentiment
Request Body:
{
"data": {
"type": "sentiment_requests",
"attributes": {
"text": "I absolutely love this product! It exceeded all my expectations.",
"language": "en"
}
}
}
Response:
{
"data": {
"type": "sentiment_results",
"id": "sent_abc123",
"attributes": {
"score": 0.92,
"label": "positive",
"confidence": 0.97,
"scores": {
"positive": 0.92,
"neutral": 0.06,
"negative": 0.02
}
}
}
}
Extract Entities
Identify named entities in text.
POST /ai/v1/text/entities
Request Body:
{
"data": {
"type": "entity_requests",
"attributes": {
"text": "Apple CEO Tim Cook announced new products at the event in Cupertino, California.",
"types": ["PERSON", "ORG", "LOCATION"]
}
}
}
Response:
{
"data": {
"type": "entity_results",
"id": "ent_xyz789",
"attributes": {
"entities": [
{
"text": "Apple",
"type": "ORG",
"start": 0,
"end": 5,
"confidence": 0.98
},
{
"text": "Tim Cook",
"type": "PERSON",
"start": 10,
"end": 18,
"confidence": 0.99
},
{
"text": "Cupertino",
"type": "LOCATION",
"start": 62,
"end": 71,
"confidence": 0.96
},
{
"text": "California",
"type": "LOCATION",
"start": 73,
"end": 83,
"confidence": 0.99
}
]
}
}
}
Entity Types:
| Type | Description |
|---|---|
PERSON | People, including fictional |
ORG | Companies, agencies, institutions |
LOCATION | Countries, cities, addresses |
DATE | Dates and times |
MONEY | Monetary values |
PRODUCT | Products and vehicles |
EVENT | Named events |
WORK_OF_ART | Titles of books, songs, etc. |
Extract Key Phrases
Identify important phrases in text.
POST /ai/v1/text/key-phrases
Request Body:
{
"data": {
"type": "key_phrase_requests",
"attributes": {
"text": "The new machine learning algorithm significantly improves prediction accuracy while reducing computational costs.",
"max_phrases": 5
}
}
}
Response:
{
"data": {
"type": "key_phrase_results",
"attributes": {
"key_phrases": [
{ "phrase": "machine learning algorithm", "score": 0.95 },
{ "phrase": "prediction accuracy", "score": 0.89 },
{ "phrase": "computational costs", "score": 0.85 }
]
}
}
}
Detect Language
Identify the language of text.
POST /ai/v1/text/language
Request Body:
{
"data": {
"type": "language_requests",
"attributes": {
"text": "Bonjour, comment allez-vous?"
}
}
}
Response:
{
"data": {
"type": "language_results",
"attributes": {
"language": "fr",
"language_name": "French",
"confidence": 0.99,
"alternatives": [
{ "language": "it", "language_name": "Italian", "confidence": 0.01 }
]
}
}
}
Summarize Text
Generate a concise summary of long text.
POST /ai/v1/text/summarize
Request Body:
{
"data": {
"type": "summarize_requests",
"attributes": {
"text": "Your long article text here...",
"max_length": 100,
"style": "extractive"
}
}
}
Response:
{
"data": {
"type": "summarize_results",
"attributes": {
"summary": "A concise summary of the input text...",
"length": 85,
"compression_ratio": 0.15
}
}
}
Image Analysis API
Analyze images for classification, objects, and text.
Classify Image
Categorize an image.
POST /ai/v1/image/classify
Request Body:
{
"data": {
"type": "image_classify_requests",
"attributes": {
"image_url": "https://example.com/photo.jpg",
"max_labels": 5
}
}
}
Response:
{
"data": {
"type": "image_classify_results",
"attributes": {
"labels": [
{ "label": "dog", "confidence": 0.97 },
{ "label": "golden retriever", "confidence": 0.94 },
{ "label": "pet", "confidence": 0.92 },
{ "label": "animal", "confidence": 0.99 },
{ "label": "outdoor", "confidence": 0.78 }
]
}
}
}
Detect Objects
Identify and locate objects in an image.
POST /ai/v1/image/detect
Request Body:
{
"data": {
"type": "object_detect_requests",
"attributes": {
"image_url": "https://example.com/street.jpg",
"min_confidence": 0.7
}
}
}
Response:
{
"data": {
"type": "object_detect_results",
"attributes": {
"objects": [
{
"label": "car",
"confidence": 0.95,
"bounding_box": {
"x": 120,
"y": 200,
"width": 350,
"height": 180
}
},
{
"label": "person",
"confidence": 0.88,
"bounding_box": {
"x": 50,
"y": 100,
"width": 80,
"height": 250
}
}
]
}
}
}
Extract Text (OCR)
Extract text from images.
POST /ai/v1/image/ocr
Request Body:
{
"data": {
"type": "ocr_requests",
"attributes": {
"image_url": "https://example.com/document.jpg",
"detect_orientation": true
}
}
}
Response:
{
"data": {
"type": "ocr_results",
"attributes": {
"text": "Extracted text from the image...",
"blocks": [
{
"text": "INVOICE",
"confidence": 0.99,
"bounding_box": { "x": 50, "y": 20, "width": 150, "height": 30 }
},
{
"text": "Order #12345",
"confidence": 0.97,
"bounding_box": { "x": 50, "y": 60, "width": 200, "height": 25 }
}
],
"language": "en",
"orientation": 0
}
}
}
Recommendations API
Generate personalized recommendations.
Get Recommendations
POST /ai/v1/recommendations
Request Body:
{
"data": {
"type": "recommendation_requests",
"attributes": {
"user_id": "user_abc123",
"context": "product-page",
"item_id": "prod_xyz789",
"limit": 5,
"filters": {
"category": "electronics",
"price_max": 500
}
}
}
}
Response:
{
"data": {
"type": "recommendation_results",
"attributes": {
"recommendations": [
{
"item_id": "prod_001",
"score": 0.95,
"reason": "Users who viewed this also viewed"
},
{
"item_id": "prod_002",
"score": 0.87,
"reason": "Similar products"
},
{
"item_id": "prod_003",
"score": 0.82,
"reason": "Based on your history"
}
],
"model_version": "v2.3"
}
}
}
Track User Event
Record user interactions for better recommendations.
POST /ai/v1/recommendations/events
Request Body:
{
"data": {
"type": "recommendation_events",
"attributes": {
"user_id": "user_abc123",
"event_type": "purchase",
"item_id": "prod_xyz789",
"timestamp": "2025-01-15T10:30:00Z",
"metadata": {
"quantity": 1,
"price": 299.99
}
}
}
}
Event Types:
| Event | Description |
|---|---|
view | User viewed an item |
click | User clicked on an item |
add_to_cart | Item added to cart |
purchase | Item purchased |
rating | User rated an item |
like | User liked an item |
Content Moderation API
Detect inappropriate content.
Moderate Text
POST /ai/v1/moderation/text
Request Body:
{
"data": {
"type": "moderation_requests",
"attributes": {
"text": "User-generated content to check...",
"categories": ["hate", "violence", "sexual", "spam"]
}
}
}
Response:
{
"data": {
"type": "moderation_results",
"attributes": {
"flagged": false,
"categories": {
"hate": { "flagged": false, "score": 0.02 },
"violence": { "flagged": false, "score": 0.01 },
"sexual": { "flagged": false, "score": 0.00 },
"spam": { "flagged": false, "score": 0.05 }
},
"action": "allow"
}
}
}
Moderate Image
POST /ai/v1/moderation/image
Request Body:
{
"data": {
"type": "image_moderation_requests",
"attributes": {
"image_url": "https://example.com/user-upload.jpg",
"categories": ["adult", "violence", "hate"]
}
}
}
Response:
{
"data": {
"type": "image_moderation_results",
"attributes": {
"flagged": false,
"categories": {
"adult": { "flagged": false, "score": 0.03 },
"violence": { "flagged": false, "score": 0.01 },
"hate": { "flagged": false, "score": 0.00 }
},
"action": "allow"
}
}
}
Embeddings API
Generate vector embeddings for semantic operations.
Generate Embeddings
POST /ai/v1/embeddings
Request Body:
{
"data": {
"type": "embedding_requests",
"attributes": {
"inputs": [
"Machine learning is transforming technology",
"AI is revolutionizing software development"
],
"model": "text-embedding-3"
}
}
}
Response:
{
"data": {
"type": "embedding_results",
"attributes": {
"embeddings": [
{
"index": 0,
"embedding": [0.023, -0.045, 0.089, ...],
"dimensions": 1536
},
{
"index": 1,
"embedding": [0.031, -0.052, 0.076, ...],
"dimensions": 1536
}
],
"model": "text-embedding-3",
"usage": {
"tokens": 18
}
}
}
}
Compute Similarity
Compare text similarity.
POST /ai/v1/embeddings/similarity
Request Body:
{
"data": {
"type": "similarity_requests",
"attributes": {
"source": "How do I reset my password?",
"targets": [
"I forgot my login credentials",
"Change my account password",
"What's the weather today?"
]
}
}
}
Response:
{
"data": {
"type": "similarity_results",
"attributes": {
"similarities": [
{ "index": 0, "score": 0.89 },
{ "index": 1, "score": 0.94 },
{ "index": 2, "score": 0.12 }
]
}
}
}
Translation API
Translate text between languages.
Translate Text
POST /ai/v1/translate
Request Body:
{
"data": {
"type": "translation_requests",
"attributes": {
"text": "Hello, how are you today?",
"source_language": "en",
"target_language": "es"
}
}
}
Response:
{
"data": {
"type": "translation_results",
"attributes": {
"translated_text": "Hola, como estas hoy?",
"source_language": "en",
"target_language": "es",
"confidence": 0.98
}
}
}
Supported Languages
Get list of supported languages.
GET /ai/v1/translate/languages
Classification API
Create custom classifiers.
Create Classifier
POST /ai/v1/classifiers
Request Body:
{
"data": {
"type": "classifiers",
"attributes": {
"name": "support-ticket-classifier",
"description": "Classify customer support tickets",
"labels": ["billing", "technical", "general", "urgent"]
}
}
}
Train Classifier
POST /ai/v1/classifiers/:classifier_id/train
Request Body:
{
"data": {
"type": "training_data",
"attributes": {
"examples": [
{ "text": "I was charged twice", "label": "billing" },
{ "text": "App keeps crashing", "label": "technical" },
{ "text": "How do I change settings?", "label": "general" },
{ "text": "URGENT: Service is down!", "label": "urgent" }
]
}
}
}
Classify Text
POST /ai/v1/classifiers/:classifier_id/classify
Request Body:
{
"data": {
"type": "classification_requests",
"attributes": {
"text": "My payment didn't go through"
}
}
}
Response:
{
"data": {
"type": "classification_results",
"attributes": {
"predictions": [
{ "label": "billing", "confidence": 0.92 },
{ "label": "technical", "confidence": 0.05 },
{ "label": "general", "confidence": 0.02 },
{ "label": "urgent", "confidence": 0.01 }
]
}
}
}
Prompt Rendering API
Render dynamic prompts with variable substitution and array transformations.
Render Prompt
Render a prompt template with placeholder values.
POST /ai/v1/prompts/:unique_id/render
Request Body:
{
"placeholders": {
"simple_string": "Hello",
"string_array": ["url1", "url2", "url3"],
"nested_object": {
"title": "My Title",
"metadata": { "author": "John" }
},
"object_array": [
{ "claim": "Fact 1", "priority": "high" },
{ "claim": "Fact 2", "priority": "low" }
]
}
}
Response:
{
"data": {
"type": "rendered_prompts",
"id": 12345,
"attributes": {
"prompt_unique_id": "prompt_abc123",
"rendered_content": "The rendered prompt text with substituted values...",
"placeholders_used": ["simple_string", "string_array", "nested_object"]
}
}
}
The response id field is now an integer (previously UUID). Use prompt_unique_id for the UUID identifier.
Placeholder Syntax
| Pattern | Example | Description |
|---|---|---|
| Simple | {{name}} | Basic variable substitution |
| Nested object | {{user.email}} | Access nested object fields |
| Array index | {{items[0]}} | Access array element by index |
| Combined | {{steps[0].title}} | Index access + field access |
Pipe Transforms for Arrays
Transform array values using pipe syntax: {{placeholder\|transform}}
| Transform | Syntax | Input | Output |
|---|---|---|---|
| Default | {{urls}} | ["a", "b"] | a\nb (newline-joined) |
| Bullets | {{urls|bullets}} | ["a", "b"] | - a\n- b |
| Numbered | {{urls|numbered}} | ["a", "b"] | 1. a\n2. b |
| Join | {{urls|join:, }} | ["a", "b"] | a, b |
| Length | {{urls|length}} | ["a", "b"] | 2 |
| First | {{urls|first}} | ["a", "b"] | a |
| Last | {{urls|last}} | ["a", "b"] | b |
| Field | {{users|field:name}} | [{name: "John"}, {name: "Jane"}] | John\nJane |
Examples
Simple variable substitution:
Prompt template: "Hello {{name}}, welcome to {{company}}!"
Placeholders: { "name": "Alice", "company": "Acme Corp" }
Result: "Hello Alice, welcome to Acme Corp!"
Array with bullets:
Prompt template: "Sources:\n{{urls|bullets}}"
Placeholders: { "urls": ["https://example.com", "https://test.com"] }
Result: "Sources:\n- https://example.com\n- https://test.com"
Nested object access:
Prompt template: "Author: {{metadata.author}}, Published: {{metadata.date}}"
Placeholders: { "metadata": { "author": "John Doe", "date": "2026-01-15" } }
Result: "Author: John Doe, Published: 2026-01-15"
Object array with field extraction:
Prompt template: "Claims to verify:\n{{claims|field:text|numbered}}"
Placeholders: { "claims": [{ "text": "Fact 1" }, { "text": "Fact 2" }] }
Result: "Claims to verify:\n1. Fact 1\n2. Fact 2"
Webhooks
Configure webhooks for AI events.
Register Webhook
POST /ai/v1/webhooks
Request Body:
{
"data": {
"type": "webhooks",
"attributes": {
"url": "https://your-app.com/webhooks/ai",
"events": [
"moderation.flagged",
"classifier.trained",
"batch.completed"
],
"secret": "your-webhook-secret"
}
}
}
Webhook Events
| Event | Description |
|---|---|
moderation.flagged | Content was flagged by moderation |
classifier.trained | Custom classifier finished training |
batch.completed | Batch processing job completed |
Error Handling
Error Response Format
{
"errors": [
{
"status": "400",
"code": "invalid_image_format",
"title": "Invalid Image Format",
"detail": "The image format 'bmp' is not supported. Supported formats: jpg, png, gif, webp.",
"source": {
"parameter": "image_url"
}
}
]
}
Common Error Codes
| Code | Status | Description |
|---|---|---|
text_too_long | 400 | Input text exceeds maximum length |
invalid_image_format | 400 | Unsupported image format |
invalid_language | 400 | Language code not supported |
classifier_not_found | 404 | Custom classifier does not exist |
model_unavailable | 503 | AI model temporarily unavailable |
rate_limit_exceeded | 429 | Too many requests |
SDK Examples
React Sentiment Component
import { useState } from 'react';
import { create23BlocksClient } from '@23blocks/sdk';
const client = create23BlocksClient({
urls: { ai: 'https://jarvis.api.us.23blocks.com' },
appId: 'your-app-id',
});
function SentimentAnalyzer() {
const [text, setText] = useState('');
const [sentiment, setSentiment] = useState(null);
const [loading, setLoading] = useState(false);
const analyzeSentiment = async () => {
if (!text.trim()) return;
setLoading(true);
try {
const result = await client.ai.analyzeSentiment({ text });
setSentiment(result);
} finally {
setLoading(false);
}
};
const getSentimentColor = (label) => {
switch (label) {
case 'positive': return 'text-green-500';
case 'negative': return 'text-red-500';
default: return 'text-gray-500';
}
};
return (
<div className="sentiment-analyzer">
<textarea
value={text}
onChange={(e) => setText(e.target.value)}
placeholder="Enter text to analyze..."
rows={4}
/>
<button onClick={analyzeSentiment} disabled={loading}>
{loading ? 'Analyzing...' : 'Analyze Sentiment'}
</button>
{sentiment && (
<div className="result">
<p className={getSentimentColor(sentiment.label)}>
{sentiment.label.toUpperCase()} ({(sentiment.score * 100).toFixed(1)}%)
</p>
<div className="confidence-bar">
<div
style={{ width: `${sentiment.confidence * 100}%` }}
className="confidence-fill"
/>
</div>
</div>
)}
</div>
);
}
Content Moderation Hook
import { useState, useCallback } from 'react';
import { create23BlocksClient } from '@23blocks/sdk';
const client = create23BlocksClient({
urls: { ai: 'https://jarvis.api.us.23blocks.com' },
appId: 'your-app-id',
});
function useContentModeration() {
const [isChecking, setIsChecking] = useState(false);
const moderateContent = useCallback(async (content: string) => {
setIsChecking(true);
try {
const result = await client.ai.moderate({
text: content,
categories: ['hate', 'violence', 'sexual', 'spam']
});
return {
isApproved: !result.flagged,
flags: Object.entries(result.categories)
.filter(([_, data]) => data.flagged)
.map(([category]) => category),
action: result.action
};
} finally {
setIsChecking(false);
}
}, []);
return { moderateContent, isChecking };
}
// Usage in a form
function CommentForm() {
const { moderateContent, isChecking } = useContentModeration();
const [comment, setComment] = useState('');
const [error, setError] = useState('');
const handleSubmit = async (e) => {
e.preventDefault();
setError('');
const moderation = await moderateContent(comment);
if (!moderation.isApproved) {
setError(`Comment flagged for: ${moderation.flags.join(', ')}`);
return;
}
// Submit the comment...
};
return (
<form onSubmit={handleSubmit}>
<textarea
value={comment}
onChange={(e) => setComment(e.target.value)}
placeholder="Write a comment..."
/>
{error && <p className="error">{error}</p>}
<button type="submit" disabled={isChecking}>
{isChecking ? 'Checking...' : 'Post Comment'}
</button>
</form>
);
}
Rate Limits
| Plan | Requests/minute | Text chars/request | Images/minute |
|---|---|---|---|
| Free | 60 | 5,000 | 10 |
| Starter | 300 | 25,000 | 60 |
| Growth | 1,000 | 100,000 | 200 |
| Enterprise | Custom | Custom | Custom |
Best Practices
Text Analysis
- Batch when possible - Send multiple texts in a single request
- Specify language - Improves accuracy when you know the language
- Clean input - Remove irrelevant formatting or markup
Image Analysis
- Optimize images - Resize large images before sending
- Use URLs - Prefer image URLs over base64 for large images
- Set confidence thresholds - Filter low-confidence results
Recommendations
- Track events - The more user events, the better recommendations
- Use context - Provide page/section context for relevance
- Apply filters - Filter by availability, category, etc.
Content Moderation
- Moderate early - Check content before displaying to others
- Use appropriate categories - Only check relevant categories
- Handle flags gracefully - Provide helpful feedback to users
Related Blocks
- Search Block - Full-text search with AI-powered relevance
- Content Block - Headless CMS with AI enrichment
- Onboarding Block - Personalized onboarding with AI