API
Intertext provides a RESTful API that allows you to integrate Intertext’s services into your own applications, scripts, and workflows. It is NOT intended to be an api you can build public services from. The API is rate limited so you can only send a few commands per minute, but enough to feel interactive and responsive.
It is intended to be used in fun and/or useful applications, like bringing a TRS-80, Commodore PET or a PiDP-11 to the Internet. By using a serial connection to a Raspberry Pi running a small gateway software, you can build software to explore how it would have been if the Internet was available in 1977, or use it like an advanced BBS. You could use it to build a great Pebble Time application.
There is no in-between user messaging or any forums where you can interact with other users. It would have been fun, but then we would have to monitor it and log the messaging in case of misuse. “Misusers” are why we can’t have nice things. Be good.
The AI is limited to one question - one answer, so no AI chat history. The answers are quite short so there is not room for getting complete instuctions on how to build an interstellar rocketship.
It’s possible for a teacher to sign up and then register a token to hand out in a class API programming excercises. Afterwards the teacher can revoke the API key. The students may also set up their own accounts if they want to continue after the lessons ended.
Table of Contents
- Overview
- Getting Started
- Authentication
- API Endpoints
- Request & Response Format
- Error Handling
- Rate Limits
- Code Examples
- Best Practices
Overview
What is the Intertext API?
The Intertext API allows programmatic access to all Intertext services without using Signal messaging. Perfect for:
- Web applications: Integrate weather, time, or news into your website
- Mobile apps: Build native apps powered by Intertext services
- IoT devices: Connect smart home devices to Intertext
- Automation scripts: Automate tasks with Intertext’s intelligence
- Dashboard integrations: Display Intertext data in your business dashboards
Why Use the API?
- Programmatic access: No Signal messaging required
- Real-time responses: Instant HTTP responses (no polling)
- Flexible integration: Use any programming language with HTTP support
- Same features: Access all services available via Signal
- Token-based auth: Secure API key authentication
Prerequisites
- Active Intertext account (register via Signal: +46737609889)
- API access enabled on your account (Pro plan required for API access)
- API token generated via Signal
Getting Started
1. Enable API Access
API access requires a Pro plan subscription.
Check your current plan:
You: settings
Intertext: Account Plan: Pro
API Access: Enabled ✓
Upgrade if needed: Contact support@yourdomain.com to upgrade to Pro plan.
2. Generate API Token
Use Signal to generate your API token:
You: create api token
Intertext: API Token created successfully!
Name: My API Token
Token: hal_sk_abc123def456ghi789jkl012mno345pqr678stu901
Keep this token secret! It grants full access to your account.
Use in API requests:
Authorization: Bearer hal_sk_abc123...
You: create api token "Production App"
Intertext: API Token created successfully!
Name: Production App
Token: hal_sk_xyz...
Token naming: Give your tokens descriptive names to track usage:
- “Production App”
- “Development”
- “Mobile App”
- “Personal Scripts”
3. List Your Tokens
View all active API tokens:
You: list api tokens
Intertext: Your API Tokens:
1. Production App
Created: Jan 1, 2026
Last used: 2 hours ago
2. Development
Created: Dec 15, 2025
Last used: Never
4. Revoke a Token
Delete tokens you no longer need:
You: revoke api token "Development"
Intertext: API Token "Development" has been revoked.
It can no longer be used for API access.
Authentication
API Token
All API requests require authentication using your API token.
Header format:
Authorization: Bearer hal_sk_abc123def456ghi789jkl012mno345pqr678stu901
Example request:
curl -H "Authorization: Bearer hal_sk_abc123..." \
https://api.hal.yourdomain.com/v1/weather?location=Stockholm
Base URL
Production: https://api.hal.yourdomain.com/v1
Staging: https://staging-api.hal.yourdomain.com/v1
For self-hosted deployments:
http://your-server-ip:20001/api/v1
API Endpoints
Weather
Get current weather conditions.
Endpoint: GET /v1/weather
Parameters:
location(required) - City name or “lat:X,lon:Y”units(optional) - “metric” or “imperial” (default: your account setting)
Example:
curl -H "Authorization: Bearer YOUR_TOKEN" \
"https://api.hal.yourdomain.com/v1/weather?location=Stockholm"
Response:
{
"status": "success",
"data": {
"location": {
"city": "Stockholm",
"country": "Sweden",
"coordinates": {
"lat": 59.33,
"lon": 18.07
}
},
"current": {
"temperature": 5,
"feels_like": 2,
"conditions": "Partly cloudy",
"humidity": 78,
"wind_speed": 12,
"wind_direction": "NW"
},
"units": "metric",
"timestamp": "2026-01-03T14:30:00Z"
}
}
Time
Get current time for a location or timezone.
Endpoint: GET /v1/time
Parameters:
location(optional) - City name or timezone (default: your account setting)
Example:
curl -H "Authorization: Bearer YOUR_TOKEN" \
"https://api.hal.yourdomain.com/v1/time?location=Tokyo"
Response:
{
"status": "success",
"data": {
"location": "Tokyo, Japan",
"timezone": "Asia/Tokyo",
"datetime": "2026-01-03T23:30:00+09:00",
"date": "2026-01-03",
"time": "23:30:00",
"day_of_week": "Friday",
"unix_timestamp": 1735916400
}
}
News
Get latest news headlines.
Endpoint: GET /v1/news
Parameters:
category(optional) - News category (default: “general”)limit(optional) - Number of articles (default: 5, max: 20)
Categories: general, technology, business, sports, entertainment
Example:
curl -H "Authorization: Bearer YOUR_TOKEN" \
"https://api.hal.yourdomain.com/v1/news?category=technology&limit=3"
Response:
{
"status": "success",
"data": {
"category": "technology",
"articles": [
{
"title": "New AI breakthrough announced",
"summary": "Researchers unveil significant advancement...",
"published_at": "2026-01-03T12:00:00Z",
"source": "BBC News"
},
{
"title": "Tech company launches new product",
"summary": "Industry leader releases innovative...",
"published_at": "2026-01-03T10:30:00Z",
"source": "BBC News"
}
],
"count": 2
}
}
Pollen Forecast (Base/Pro Plans)
Get pollen and air quality information.
Endpoint: GET /v1/pollen
Parameters:
location(required) - City name or coordinates
Example:
curl -H "Authorization: Bearer YOUR_TOKEN" \
"https://api.hal.yourdomain.com/v1/pollen?location=Stockholm"
Response:
{
"status": "success",
"data": {
"location": "Stockholm, Sweden",
"pollen": {
"level": "medium",
"dominant_types": ["birch", "grass"],
"birch": 3,
"grass": 2,
"ragweed": 0
},
"air_quality": {
"index": 42,
"category": "good",
"pm25": 8,
"pm10": 15
},
"timestamp": "2026-01-03T14:30:00Z"
}
}
Navigation (Pro Plan)
Get directions between two points.
Endpoint: GET /v1/navigate
Parameters:
from(required) - Starting locationto(required) - Destinationmode(optional) - “driving”, “walking”, “cycling” (default: “driving”)
Example:
curl -H "Authorization: Bearer YOUR_TOKEN" \
"https://api.hal.yourdomain.com/v1/navigate?from=Stockholm&to=Uppsala&mode=driving"
Response:
{
"status": "success",
"data": {
"from": {
"name": "Stockholm, Sweden",
"coordinates": {"lat": 59.33, "lon": 18.07}
},
"to": {
"name": "Uppsala, Sweden",
"coordinates": {"lat": 59.86, "lon": 17.64}
},
"route": {
"distance": 71.2,
"duration": 3600,
"mode": "driving"
},
"maps_url": "https://www.google.com/maps/dir/?api=1&origin=59.33,18.07&destination=59.86,17.64"
}
}
Nearby Places (Pro Plan)
Find nearby points of interest.
Endpoint: GET /v1/nearby
Parameters:
location(required) - City, address, or coordinatestype(required) - Place type (restaurant, atm, cafe, etc.)radius(optional) - Search radius in km (default: 1, max: 5)limit(optional) - Number of results (default: 5, max: 20)
Example:
curl -H "Authorization: Bearer YOUR_TOKEN" \
"https://api.hal.yourdomain.com/v1/nearby?location=Stockholm&type=restaurant&radius=2"
Response:
{
"status": "success",
"data": {
"query": {
"location": "Stockholm, Sweden",
"type": "restaurant",
"radius": 2
},
"places": [
{
"name": "Restaurant ABC",
"distance": 0.3,
"address": "123 Main Street",
"coordinates": {"lat": 59.33, "lon": 18.07}
},
{
"name": "Bistro XYZ",
"distance": 0.5,
"address": "456 Oak Avenue",
"coordinates": {"lat": 59.34, "lon": 18.08}
}
],
"count": 2
}
}
Account Information
Get your account details.
Endpoint: GET /v1/account
Example:
curl -H "Authorization: Bearer YOUR_TOKEN" \
https://api.hal.yourdomain.com/v1/account
Response:
{
"status": "success",
"data": {
"phone": "+46737609889",
"plan": "pro",
"locale": "en-US",
"units": "metric",
"created_at": "2025-12-01T10:00:00Z",
"api_enabled": true
}
}
Request & Response Format
Request Headers
Required:
Authorization: Bearer YOUR_API_TOKEN
Optional:
Content-Type: application/json
Accept: application/json
Response Format
All responses use JSON format with this structure:
Success:
{
"status": "success",
"data": { /* endpoint-specific data */ }
}
Error:
{
"status": "error",
"error": {
"code": "ERROR_CODE",
"message": "Human-readable error message"
}
}
HTTP Status Codes
| Code | Meaning | Description |
|---|---|---|
| 200 | OK | Request successful |
| 400 | Bad Request | Invalid parameters |
| 401 | Unauthorized | Missing or invalid API token |
| 403 | Forbidden | Feature not available on your plan |
| 404 | Not Found | Resource not found |
| 429 | Too Many Requests | Rate limit exceeded |
| 500 | Internal Server Error | Server error (contact support) |
Error Handling
Common Error Codes
Authentication Errors:
{
"status": "error",
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid or missing API token"
}
}
Plan Restriction:
{
"status": "error",
"error": {
"code": "PLAN_REQUIRED",
"message": "This feature requires Pro plan"
}
}
Invalid Parameters:
{
"status": "error",
"error": {
"code": "INVALID_PARAMETER",
"message": "Location parameter is required"
}
}
Rate Limit:
{
"status": "error",
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded. Retry after 60 seconds."
}
}
Resource Not Found:
{
"status": "error",
"error": {
"code": "NOT_FOUND",
"message": "Location 'Atlantis' not found"
}
}
Rate Limits
Default Limits
| Plan | Requests per Hour | Burst Limit |
|---|---|---|
| Free | N/A (API not available) | N/A |
| Base | N/A (API not available) | N/A |
| Pro | 1,000 | 100/minute |
| Enterprise | Custom | Custom |
Rate Limit Headers
Every response includes rate limit information:
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 987
X-RateLimit-Reset: 1735920000
Handling Rate Limits
When you exceed the rate limit:
Response:
HTTP/1.1 429 Too Many Requests
Retry-After: 60
{
"status": "error",
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded. Retry after 60 seconds."
}
}
Best practices:
- Implement exponential backoff
- Cache responses when possible
- Monitor rate limit headers
- Spread requests over time
Code Examples
cURL
Weather request:
curl -X GET \
-H "Authorization: Bearer hal_sk_abc123..." \
"https://api.hal.yourdomain.com/v1/weather?location=Stockholm"
Python
Using requests library:
import requests
API_TOKEN = "hal_sk_abc123..."
BASE_URL = "https://api.hal.yourdomain.com/v1"
headers = {
"Authorization": f"Bearer {API_TOKEN}"
}
# Get weather
response = requests.get(
f"{BASE_URL}/weather",
headers=headers,
params={"location": "Stockholm"}
)
if response.status_code == 200:
data = response.json()
print(f"Temperature: {data['data']['current']['temperature']}°C")
else:
print(f"Error: {response.json()['error']['message']}")
# Get news
response = requests.get(
f"{BASE_URL}/news",
headers=headers,
params={"category": "technology", "limit": 5}
)
news = response.json()
for article in news['data']['articles']:
print(f"- {article['title']}")
JavaScript (Node.js)
Using fetch:
const API_TOKEN = 'hal_sk_abc123...';
const BASE_URL = 'https://api.hal.yourdomain.com/v1';
async function getWeather(location) {
const response = await fetch(
`${BASE_URL}/weather?location=${encodeURIComponent(location)}`,
{
headers: {
'Authorization': `Bearer ${API_TOKEN}`
}
}
);
if (!response.ok) {
const error = await response.json();
throw new Error(error.error.message);
}
return await response.json();
}
async function main() {
try {
const weather = await getWeather('Stockholm');
console.log(`Temperature: ${weather.data.current.temperature}°C`);
} catch (error) {
console.error('Error:', error.message);
}
}
main();
JavaScript (Browser)
Fetch API:
const API_TOKEN = 'hal_sk_abc123...';
async function displayWeather() {
const location = document.getElementById('location').value;
try {
const response = await fetch(
`https://api.hal.yourdomain.com/v1/weather?location=${location}`,
{
headers: {
'Authorization': `Bearer ${API_TOKEN}`
}
}
);
const data = await response.json();
if (data.status === 'success') {
document.getElementById('result').innerHTML = `
<h3>${data.data.location.city}</h3>
<p>Temperature: ${data.data.current.temperature}°C</p>
<p>Conditions: ${data.data.current.conditions}</p>
`;
} else {
alert(data.error.message);
}
} catch (error) {
console.error('Error:', error);
}
}
PHP
Using cURL:
<?php
$api_token = 'hal_sk_abc123...';
$base_url = 'https://api.hal.yourdomain.com/v1';
function getWeather($location) {
global $api_token, $base_url;
$url = $base_url . '/weather?location=' . urlencode($location);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer ' . $api_token
]);
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$data = json_decode($response, true);
if ($http_code === 200) {
return $data['data'];
} else {
throw new Exception($data['error']['message']);
}
}
try {
$weather = getWeather('Stockholm');
echo "Temperature: " . $weather['current']['temperature'] . "°C\n";
} catch (Exception $e) {
echo "Error: " . $e->getMessage() . "\n";
}
?>
Ruby
Using net/http:
require 'net/http'
require 'json'
require 'uri'
API_TOKEN = 'hal_sk_abc123...'
BASE_URL = 'https://api.hal.yourdomain.com/v1'
def get_weather(location)
uri = URI("#{BASE_URL}/weather?location=#{URI.encode_www_form_component(location)}")
request = Net::HTTP::Get.new(uri)
request['Authorization'] = "Bearer #{API_TOKEN}"
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
data = JSON.parse(response.body)
if response.code == '200'
data['data']
else
raise data['error']['message']
end
end
begin
weather = get_weather('Stockholm')
puts "Temperature: #{weather['current']['temperature']}°C"
rescue => e
puts "Error: #{e.message}"
end
Best Practices
Security
- Keep tokens secret:
- Never commit tokens to version control
- Use environment variables or secret managers
- Rotate tokens regularly
- Use HTTPS:
- Always use HTTPS endpoints
- Verify SSL certificates
- Token per application:
- Create separate tokens for each app/environment
- Name tokens descriptively
- Revoke unused tokens
Performance
- Cache responses:
- Cache weather data for 10-30 minutes
- Cache news for 10-15 minutes
- Cache time data for 1 minute
- Implement retries:
- Use exponential backoff
- Retry on 429, 500, 503 errors
- Don’t retry on 400, 401, 403 errors
- Monitor rate limits:
- Track
X-RateLimit-Remainingheader - Slow down when approaching limit
- Implement request queuing
- Track
Error Handling
- Check HTTP status codes:
- Don’t assume 200 OK
- Handle all error codes appropriately
- Parse error messages:
- Display helpful messages to users
- Log detailed errors for debugging
- Implement fallbacks:
- Graceful degradation when API is unavailable
- Cached data as fallback
Example: Production-Ready Request
import requests
import time
from functools import wraps
API_TOKEN = os.getenv('INTERTEXT_API_TOKEN')
BASE_URL = 'https://api.hal.yourdomain.com/v1'
CACHE = {}
def retry_with_backoff(max_retries=3):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
for attempt in range(max_retries):
try:
return func(*args, **kwargs)
except requests.exceptions.RequestException as e:
if attempt == max_retries - 1:
raise
wait = 2 ** attempt
time.sleep(wait)
return wrapper
return decorator
@retry_with_backoff()
def api_request(endpoint, params=None):
cache_key = f"{endpoint}:{str(params)}"
# Check cache
if cache_key in CACHE:
cached_data, timestamp = CACHE[cache_key]
if time.time() - timestamp < 600: # 10 min TTL
return cached_data
# Make request
response = requests.get(
f"{BASE_URL}/{endpoint}",
headers={'Authorization': f'Bearer {API_TOKEN}'},
params=params,
timeout=10
)
# Check rate limit
remaining = int(response.headers.get('X-RateLimit-Remaining', 999))
if remaining < 10:
print(f"Warning: Only {remaining} requests remaining")
# Handle errors
if response.status_code == 429:
retry_after = int(response.headers.get('Retry-After', 60))
raise Exception(f"Rate limited. Retry after {retry_after}s")
response.raise_for_status()
data = response.json()
if data['status'] != 'success':
raise Exception(data['error']['message'])
# Cache result
CACHE[cache_key] = (data['data'], time.time())
return data['data']
Support
Getting Help
- Documentation: This page
- Email support: api-support@yourdomain.com
- Status page: status.hal.yourdomain.com
- Signal: +46737609889
Reporting Issues
When reporting API issues, include:
- Your account phone number (last 4 digits only)
- API endpoint and parameters
- Request timestamp
- Error message received
- Expected vs actual behavior
Feature Requests
Have an idea for a new API endpoint or feature?
- Email: api-feedback@yourdomain.com
- GitHub: github.com/yourorg/hal_system/issues
| Back to Home | View Features | Privacy Policy |