Time
See the time API guide for datetime, timestamp and timezone examples.
Datetime REST API Endpoint
GET /datetime[/{offset}] - /datetime/{zone}
Current date and time in ISO 8601. The optional offset is a four-digit UTC offset with an optional sign - +0200, -0530 or 0100 - or +02:00. An hour-only value such as 1 is not a valid route. An IANA zone such as europe/oslo, in any case, follows summer time and answers the zone, its abbreviation, the offset in force, whether summer time is on and when it starts and ends, the day and week numbers and the time in UTC as well. Clients of WorldTimeAPI find which path answers each of theirs on the WorldTimeAPI alternative page.
curl https://aisenseapi.com/services/v1/datetime/+0200
{ "datetime": "2026-08-16T11:44:35+02:00" }
GET /ip_datetime[/{ip}]
The time where an IPv4 or IPv6 address is: ip, then the same fields as /datetime/{zone} for the zone an address lookup places it in. Without an address, the caller's own. An address with no zone known, such as a private one, is HTTP 404.
curl https://aisenseapi.com/services/v1/ip_datetime/8.8.8.8
{"ip":"8.8.8.8","datetime":"2026-10-03T05:41:07-05:00","timezone":"America/Chicago","abbreviation":"CDT","utc_offset":"-05:00","dst":true, ...}
Timestamp REST API Endpoint
GET /timestamp
Current Unix timestamp in seconds. Response key: timestamp.
{ "timestamp": 1786873261 }
Microtimestamp REST API Endpoint
GET /microtimestamp
Unix timestamp with microsecond precision. Response key: microtimestamp.
{ "microtimestamp": 1786873474.745043 }
Timezones REST API Endpoint
GET /timezones[/{offset}]
All available timezones, optionally filtered by a four-digit offset. The list contains objects, not strings.
{
"timezones": [
{ "timezone": "Africa/Abidjan", "offset": "+0000" },
{ "timezone": "Africa/Blantyre", "offset": "+0200" }
]
}
Swatchinternettime REST API Endpoint
GET /swatchinternettime
Swatch Internet Time. The day is divided into 1000 .beats of 86.4 seconds each, based on Biel Meantime, with no time zones. beat is a string with a leading @, not a number.
{ "beat": "@444", "date": "2026-08-16" }
Timestamp Convert REST API Endpoint
POST /timestamp_convert
One time value in, every representation out. Accepts unix seconds, unix milliseconds (13 digits and up, the Date.now() format, detected automatically), ISO 8601, RFC 2822, or "now". The optional offset uses the same four digit form as /datetime. Bad input returns HTTP 400.
Request: { "data": "1700000000123", "offset": "+0100" }
Response: { "input": "1700000000123", "detected": "unix_ms", "timestamp": 1700000000,
"datetime": "2023-11-14T23:13:20+01:00", "rfc2822": "Tue, 14 Nov 2023 23:13:20 +0100",
"utc_datetime": "2023-11-14T22:13:20+00:00" }
All Transform endpoints are POST and accept JSON, plain text with Content-Type: text/plain, or a file upload.
Use the encoding API guide for Base32, Base58 and Base64. The QR code API guide covers image encoding and decoding.
Base64 Encode REST API Endpoint
POST /base64_encode
{ "data": "Hello world" }
{ "base64_encoded_data": "SGVsbG8gd29ybGQ=" }
Base64 Decode REST API Endpoint
POST /base64_decode
Returns the decoded bytes as application/octet-stream - the payload and nothing else. Send Accept: application/json to get a typed envelope instead.
# default: raw bytes
Request: { "data": "SGVsbG8gd29ybGQ=" }
Response: Hello world
# with Accept: application/json
{ "data": "eyJrZXkiOiJ2YWx1ZSJ9" }
Response: { "type": "json", "decoded_data": { "key": "value" } }
# non-JSON content, with Accept: application/json
Response: { "type": "binary", "encoding": "base64", "decoded_data": "iVBORw0KGgo..." }
Base58 Encode REST API Endpoint
POST /base58_encode
Request: { "data": "Hello" }
Response: { "base58_encoded_data": "9Ajdvzr" }
Base58 Decode REST API Endpoint
POST /base58_decode
Same Accept behaviour as Base64 Decode. An invalid Base58 character returns HTTP 400 with {"error": "Invalid Base58 input."}.
Request: { "data": "9Ajdvzr" }
Response: Hello
Base32 Encode REST API Endpoint
POST /base32_encode
Request: { "data": "Hello" }
Response: { "base32_encoded_data": "JBSWY3DP" }
Base32 Decode REST API Endpoint
POST /base32_decode
Same Accept behaviour as Base64 Decode.
Request: { "data": "JBSWY3DP" }
Response: Hello
POST /hex_encode
Any bytes to lower-case hex. Response key: hex_encoded_data.
Request: { "data": "hello" }
Response: { "hex_encoded_data": "68656c6c6f" }
POST /hex_decode
Hex in either case, with an optional 0x and spaces, back to bytes. Same Accept behaviour as Base64 Decode.
Request: { "data": "68656C6C6F" }
Response: hello
POST /base64url_encode
The URL-safe alphabet, - and _, without padding, as JWT writes it. Response key: base64url_encoded_data.
Request: { "data": "hello?" }
Response: { "base64url_encoded_data": "aGVsbG8_" }
POST /base64url_decode
With or without padding. Same Accept behaviour as Base64 Decode; a + or / is HTTP 400.
Request: { "data": "aGVsbG8_" }
Response: hello?
POST /url_encode
RFC 3986 percent-encoding for one path segment or query value: a space is %20. Response key: url_encoded_data.
Request: { "data": "a b/c?é" }
Response: { "url_encoded_data": "a%20b%2Fc%3F%C3%A9" }
POST /url_decode
Percent-encoding back to UTF-8 text; a + stays a +. Response key: url_decoded_data.
Request: { "data": "a%20b%2Fc+%C3%A9" }
Response: { "url_decoded_data": "a b/c+é" }
POST /html_encode
& < > " ' as entities, so text can go into a page or an attribute. Response key: html_encoded_data.
Request: { "data": "<b>Tom & Jerry</b>" }
Response: { "html_encoded_data": "<b>Tom & Jerry</b>" }
POST /html_decode
Every named HTML5 entity and every numeric one back to its character. Response key: html_decoded_data.
Request: { "data": "<b> é" }
Response: { "html_decoded_data": "<b> é" }
POST /html_to_markdown
A web page or any HTML as CommonMark with GitHub tables, without scripts, styles, forms or media, and the page title. At most 1 MiB and 40000 tags. Response keys: markdown, title.
Request: { "data": "<h1>Hi</h1><p>A <b>bold</b> word</p>" }
Response: { "markdown": "# Hi\n\nA **bold** word", "title": null }
POST /markdown_to_html
CommonMark with GitHub tables, strikethrough and task lists to an HTML fragment that is safe to put in a page: raw HTML is shown as text and a link with an unsafe scheme as its text. At most 256 KiB and 20000 lines. Response key: html.
Request: { "data": "**Bold** <b>raw</b>" }
Response: { "html": "<p><strong>Bold</strong> <b>raw</b></p>" }
Slugify REST API Endpoint
POST /slugify
Text to URL slug. Scandinavian letters and common Latin diacritics are transliterated by a fixed table, so the same input gives the same slug on every machine. Input with no sluggable characters returns HTTP 400 rather than an empty slug.
{ "data": "Blåbærsyltetøy på Ås!" } -> { "slug": "blabaersyltetoy-pa-as" }
JWT Encode REST API Endpoint
POST /jwt_encode
Encodes claims into an HS256 JSON Web Token. data takes the claims as a JSON object directly, or as a string containing JSON - both forms produce the same token. A string that does not parse as JSON returns HTTP 400.
{ "data": { "user": "alice" }, "secret": "your_secret_key" } # object form
{ "data": "{\"user\":\"alice\"}", "secret": "your_secret_key" } # string form, same token
{ "jwt": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiYWxpY2UifQ..." }
Also accepts plain text with an X-Secret header, or a file upload in a jwt_data field.
JWT Decode REST API Endpoint
POST /jwt_decode
{ "data": "eyJ0eXAiOiJKV1Qi...", "secret": "your_secret_key" }
{ "decoded_payload": { "user": "alice" } }
QR Code Encode REST API Endpoint
POST /qrcode_encode
Generates a QR code as a Base64 PNG. Encodes URLs, plain text, vCards, Wi-Fi credentials and calendar events. The request field is payload, with data accepted as an alias.
{ "payload": "https://aisenseapi.com/" }
{ "qrcode_image": "iVBORw0KGgoAAAANSUhEUg...", "image_type": "png" }
QR Code Decode REST API Endpoint
POST /qrcode_decode
Accepts a Base64 image in the payload field, or a file upload in a qrcode_image field.
{ "payload": "iVBORw0KGgoAAAANSUhEUg..." }
{ "qrcode_content": "https://aisenseapi.com/" }
Convert
All Convert endpoints are POST with a JSON body of at most 256 KB. None of them returns the result in the answer. Each one stores its result in Storage for 24 hours and answers with the Storage fields plus content_type, filename and operation. Read the result with a GET on storage_url. Anyone with that link can read it, and stored results count against the Storage budget of 80 MB per IP address per day.
The answer to the JSON to CSV example below, from a test run. The id and the expiry are different on every call:
{
"storage_id": "b5b3016f-52df-43a7-801c-7b7d0baa4b94",
"storage_url": "https://aisenseapi.com/services/v1/storage/b5b3016f-52df-43a7-801c-7b7d0baa4b94",
"sha256_hash": "3e749b9bff583e347820dee8435476eca0ca58fe2e4639c53cc13c8cc9925c1c",
"bytes": 44,
"expire_timestamp": 1790760065,
"expire_datetime": "2026-09-30T09:21:05+00:00",
"content_type": "text/csv; charset=utf-8",
"filename": "result.csv",
"operation": "json_to_csv"
}
JSON to CSV REST API Endpoint
POST /json_to_csv
JSON records to CSV, with the columns in the order you name them. Every cell is quoted, text such as 00123 stays text, and nested values are refused. Optional delimiter (comma, semicolon or tab) and spreadsheet_safe. Guide and browser tool.
{"columns": ["customer_id", "name"], "rows": [{"customer_id": "00123", "name": "Nordlys AS"}], "delimiter": ";"}
# stored as result.csv
"customer_id";"name"
"00123";"Nordlys AS"
CSV to JSON REST API Endpoint
POST /csv_to_json
CSV text to JSON with the column names and one object per row. Every cell stays a string. The first line is the header, and malformed quoting or a row of the wrong width is refused rather than guessed at. Guide and browser tool.
{"data": "customer_id,name\n00123,Nordlys AS\n"}
# stored as result.json
{"columns":["customer_id","name"],"rows":[{"customer_id":"00123","name":"Nordlys AS"}]}
Table Matching REST API Endpoint
POST /table_match
Compares two lists of rows on one or more pairs of key columns. Every row lands in matched, only_left, only_right or ambiguous, and duplicate keys are reported, never paired at random. Keys are compared exactly. Guide and browser tool.
{"left": [{"id": "1"}, {"id": "2"}], "right": [{"id": "2"}, {"id": "3"}], "keys": [{"left": "id", "right": "id"}]}
# stored as matches.json
{"matched":[{"left_index":1,"right_index":0}],"only_left":[0],"only_right":[1],"ambiguous":[]}
JSON Format REST API Endpoint
POST /json_format
Pretty prints or minifies JSON text sent as a string. Only whitespace changes, so number spelling, escapes, key order and duplicate keys stay as sent. Invalid JSON answers 400. Guide and browser tool.
{"data": "{\"price\":1.50,\"tags\":[\"a\"]}", "mode": "pretty"}
# stored as result.json
{
"price": 1.50,
"tags": [
"a"
]
}
JSON Validate REST API Endpoint
POST /json_validate
Checks JSON syntax. Invalid JSON is a result, not an error: the answer adds valid, and the stored report carries the parser message. Guide and browser tool.
{"data": "{\"a\":1,}"}
# stored as validation.json
{"valid":false,"error":"Syntax error","input_bytes":8,"max_depth":128}
Images
All seven image endpoints are POST with multipart/form-data: the image in a field named file, a JPEG, PNG or WebP of at most 10 MB, and the options as form fields. image_convert and image_resize also read HEIC. Like the Convert endpoints, they store the result in Storage for 24 hours and answer with the Storage fields, plus operation and what the result is.
image_convert, image_compress, image_resize, image_colors and image_favicon decode the image, so it may be at most 25 megapixels. ImageMagick does that work in a sandbox without network access, two images at a time. Every converted image is turned upright, and EXIF, XMP, IPTC and comments are removed while the color profile is kept. image_metadata and image_strip only read and rewrite the file, so they have no pixel limit and never change a pixel.
The answer to the image_convert example below, from a test run with a test image of 1600 x 1200 pixels. The id, the expiry and the sizes differ from call to call and image to image:
{
"storage_id": "1ddd4269-b51c-4209-a4de-6908926f672b",
"storage_url": "https://aisenseapi.com/services/v1/storage/1ddd4269-b51c-4209-a4de-6908926f672b",
"sha256_hash": "97350f282284446cbb19db5a0695a654e0162fafd52db766fb12099b6497202d",
"bytes": 195648,
"expire_timestamp": 1790767674,
"expire_datetime": "2026-09-30T11:27:54+00:00",
"content_type": "image/webp",
"filename": "result.webp",
"operation": "image_convert",
"format": "webp",
"width": 1600,
"height": 1200,
"input_format": "jpeg",
"input_bytes": 641358
}
Image Convert REST API Endpoint
POST /image_convert
Converts between JPEG, PNG and WebP, and reads HEIC from an iPhone, turned the way the phone stored it. format is required. quality, 40 to 95 and 82 by default, applies to JPEG and WebP, and lossless=true makes a lossless WebP. Transparent pixels become white in a JPEG. Guide and browser tool, and a HEIC to JPG converter for iPhone photos.
curl -s -X POST https://aisenseapi.com/services/v1/image_convert \
-F "file=@photo.jpg" \
-F "format=webp"
Image Compress REST API Endpoint
POST /image_compress
Saves a JPEG, PNG or WebP again in its own format. JPEG and WebP take a quality, which is lossy; PNG is saved again losslessly. input_bytes and bytes in the answer show what was saved. Guide and browser tool.
curl -s -X POST https://aisenseapi.com/services/v1/image_compress \
-F "file=@photo.jpg" \
-F "quality=70"
Image Resize REST API Endpoint
POST /image_resize
Gives a JPEG, PNG, WebP or HEIC a new width, height or both. fit=contain keeps all of the picture inside the box, and fit=cover fills it and cuts the rest from the centre, for thumbnails. Nothing is enlarged unless upscale=true. The answer adds input_width, input_height, fit and upscaled. Guide and browser tool.
curl -s -X POST https://aisenseapi.com/services/v1/image_resize \
-F "file=@photo.jpg" \
-F "width=800"
Image Metadata REST API Endpoint
POST /image_metadata
Reports what an image carries besides its pixels: EXIF with the GPS position in decimal degrees, XMP, IPTC, the color profile, comments, thumbnails and data after the image, with a privacy summary. The report is stored as metadata.json, and the answer adds format, width, height, gps and findings. Guide and browser tool.
curl -s -X POST https://aisenseapi.com/services/v1/image_metadata \
-F "file=@photo.jpg"
Image Strip REST API Endpoint
POST /image_strip
Removes EXIF, GPS, XMP, IPTC and comments without saving the image again: the image data is copied byte for byte. The color profile is kept, and so is the orientation, written back alone. The answer adds removed and kept. Guide and browser tool.
curl -s -X POST https://aisenseapi.com/services/v1/image_strip \
-F "file=@photo.jpg"
Image Colors REST API Endpoint
POST /image_colors
The dominant colors of an image with the share each covers, the average color and a 16 pixel placeholder as a data URI, stored as colors.json. count is 2 to 16, and 8 by default. The answer adds average, dominant and count. Guide and browser tool.
curl -s -X POST https://aisenseapi.com/services/v1/image_colors \
-F "file=@photo.jpg" \
-F "count=6"
Image Favicon REST API Endpoint
POST /image_favicon
A ZIP with favicon.ico, PNG icons from 16 to 512 pixels, an iOS icon, a web manifest and the head tags. crop is fit, trim or center, and name goes into the manifest. The answer adds files, crop and upscaled. Guide and browser tool.
curl -s -X POST https://aisenseapi.com/services/v1/image_favicon \
-F "file=@logo.png" \
-F "crop=trim" \
-F "name=Example site"
Web
Ping REST API Endpoint
GET /ping
Connectivity check. Response key: ping.
{ "ping": "pong" }
Health REST API Endpoint
GET /health
Service health with a high-precision timestamp. The second key is microtimestamp, not timestamp.
{ "status": "ok", "microtimestamp": 1786873258.589068 }
Client IP REST API Endpoint
GET /client_ip
The public IP address of the caller.
{ "ip": "203.0.113.42" }
User Agent REST API Endpoint
GET /user_agent
{ "user_agent": "curl/8.5.0" }
GET /ip_reverse_lookup/{ip}
Geolocates an IP address. city and place are frequently null, and the coordinates fall back to the country centroid when the city is unknown. Latitude and longitude are strings.
curl https://aisenseapi.com/services/v1/ip_reverse_lookup/8.8.8.8
{
"ip": "8.8.8.8",
"country": "United States",
"city": null,
"location": { "lat": "37.751000", "lng": "-97.822000" },
"place": null,
"timezone": "America/Chicago"
}
Domain IP Lookup REST API Endpoint
GET /domain_ip_lookup/{domain}
{ "domain": "example.com", "ip": "104.20.23.154" }
Email Validate REST API Endpoint
POST /email_validate
Syntax check, then DNS through the host resolver - nothing goes to a third party. has_mx means the domain publishes MX records; has_address_record covers the RFC 5321 fallback, so a missing MX alone does not prove an address dead. A failing address is a result with valid_syntax: false, and the endpoint never opens an SMTP conversation.
Request: { "data": "test@gmail.com" }
Response: { "email": "test@gmail.com", "valid_syntax": true, "domain": "gmail.com",
"has_mx": true, "mx_hosts": ["gmail-smtp-in.l.google.com", "..."], "has_address_record": true }
Validate REST API Endpoint
POST /validate/{type}
Check-digit validation for iban, card, orgnr, kontonummer and phone. Pure arithmetic - nothing is looked up, so valid means well-formed with a correct check digit. An invalid value is a result with valid: false, and the card number is never echoed back. Full details.
POST /validate/iban { "data": "NO9386011117947" }
-> { "type": "iban", "valid": true, "country": "NO", "checksum_ok": true }
POST /storage - GET /storage/{storage_id}
Temporary key-value storage for JSON, text or files. Post any body, get a UUID, retrieve it from anywhere - another machine, a later pipeline step, a different agent call. No database to set up and no sign-up. The storage_id is the only thing that reads the item, so treat its URL as a capability link and send it only to the intended recipient.
The body is stored verbatim: whatever you send is exactly what comes back, with no wrapper added or removed. Everything expires after 24 hours.
The answer carries the link to hand on and the digest of the bytes as stored. Put that digest in the link, as /storage/{storage_id}/sha256/{64 hex}, and the bytes come back only if they still hash to it; if they do not, the answer is 412 and nothing is served.
curl -X POST https://aisenseapi.com/services/v1/storage \
-H "Content-Type: application/json" -d '{"result": 42}'
{ "storage_id": "123e4567-e89b-12d3-a456-426614174000",
"storage_url": "https://aisenseapi.com/services/v1/storage/123e4567-e89b-12d3-a456-426614174000",
"sha256_hash": "7ecbd6ed72a9632423e471e35dfa32b41e4a44b94c4e1be3a771696a73f05db4",
"bytes": 14, "expire_timestamp": 1738457158 }
curl https://aisenseapi.com/services/v1/storage/123e4567-e89b-12d3-a456-426614174000
Response: {"result": 42}
GET /url_shortener/{url}
The target URL goes inline in the path. Links expire after 24 hours.
curl "https://aisenseapi.com/services/v1/url_shortener/https://example.com/some/long/path"
{ "short_url": "https://307.fi/KtNshX2B", "expire_timestamp": 1786959715 }
GET /dns/{ip}
The address goes last in the path, in place of <YOUR_PUBLIC_IP>; private, reserved and documentation ranges are refused. The name is on 53for24h.com and expires after 24 hours.
curl "https://aisenseapi.com/services/v1/dns/<YOUR_PUBLIC_IP>"
{ "name": "aisense-t1mpdqk.53for24h.com", "ttl": 60, "dns_token": "shown once" }
POST /webhook_capture - GET /webhook_capture/{capture_id}
Create a capture session, point a sender at its unique URL and read back the first inbound request. The result includes method, headers, client IP and parsed body. Wait for up to 25 seconds or ask for one completion signal. No tunnel or server is needed. Expires after 24 hours.
# 1. create
curl -X POST https://aisenseapi.com/services/v1/webhook_capture
{ "ok": true, "capture_id": "6f8c9e52-...", "update_url": ".../update", "read_url": "...", "expire_timestamp": ... }
# 2. point any HTTP method at update_url
# 3. read it back
{
"ok": true,
"capture_id": "6f8c9e52-...",
"captured_at_datetime": "2026-08-16T09:41:56Z",
"request": {
"method": "POST",
"headers": { "content-type": "application/json" },
"client_ip": "203.0.113.10",
"body": { "json": { "event": "payment.created" }, "text": null, "base64": null, "raw_length": 28 }
}
}
POST /webhook_action - GET /webhook_action/{action_id}
Post a form definition and send the returned link to one person. Set respondents from 2 to 20 for separate one-use links and an aggregate result. Read immediately, wait for up to 25 seconds or add notify_url for one completion signal.
Field types are radio, select, text, textarea and checkbox. Group status moves through pending, partial and answered. Expires after 24 hours.
{
"title": "Approve deployment to production?",
"fields": [
{ "type": "radio", "name": "decision", "label": "Decision", "required": true,
"options": [ { "value": "approve", "label": "Approve" },
{ "value": "reject", "label": "Reject" } ] },
{ "type": "textarea", "name": "comment", "label": "Notes" }
]
}
{ "ok": true, "action_id": "9e0e6d3b-...", "form_url": ".../form", "result_url": "...",
"expire_timestamp": ..., "expire_datetime": "2026-08-17T09:45:12Z" }
# poll the result
{ "ok": true, "action_id": "9e0e6d3b-...", "status": "answered",
"answered_at_datetime": "2026-08-16T15:13:20Z",
"response": { "decision": "approve", "comment": "Looks good" } }
POST /webhook_schedule - GET /webhook_schedule/{schedule_id}
POST a URL and payload with delay_seconds or fire_at. Add every for a recurring job. Read, wait for or cancel it through the returned bearer URL. Delivery runs once a minute. Public-address checks run at creation and delivery, and redirects are not followed. Full details.
POST /webhook_schedule { "url": "https://example.com/hook", "delay_seconds": 1200, "payload": { "job": 42 } }
-> { "ok": true, "schedule_id": "1f1d7b8b-...", "status": "scheduled", "result_url": "..." }
GET /webhook_schedule/{id}
-> { "status": "fired", "attempts": 1, "http_status": 200 }
POST /agent_wake - GET /agent_wake/{task_id}
Create one durable wait state for a webhook, a person or a time. The first matching event completes the task. REST clients may wait up to 25 seconds for a terminal result, and MCP clients use the Tasks extension.
POST /agent_wake { "event_type": "webhook", "timeout_seconds": 3600 }
-> { "resultType": "task", "taskId": "2eb1a08d-...", "status": "working",
"_meta": { "com.aisenseapi/agentWake": { "wakeUrl": ".../wake" } } }
GET /agent_wake/{task_id}
-> { "resultType": "complete", "status": "completed", "result": { ... } }
POST /heartbeat - POST /heartbeat/{heartbeat_id}/ping
Watch a process that should check in on a fixed rhythm. The first missed deadline fires one public webhook or wakes an Agent Wake task. A ping moves the next expected time but never moves the fixed 24-hour expiry.
POST /heartbeat
{ "expect_every_seconds": 300, "grace_seconds": 60,
"on_miss": { "url": "https://example.com/agent-offline",
"payload": { "agent": "worker-7" } } }
POST /heartbeat/{heartbeat_id}/ping
-> { "status": "armed", "ping_count": 1, "next_expected_at_datetime": "..." }
The heartbeat ID is a bearer secret. Webhook destinations are checked for SSRF at creation and again at delivery. Miss actions run once with no retry. Read the Heartbeat guide.
POST /lease - POST /lease/complete
Let one worker claim a shared key. The winner receives an owner token and a monotonic fencing token. Other workers get HTTP 409 while it is held. A completed JSON result can be returned to later callers with the same key and fingerprint.
POST /lease/namespace {}
-> { "namespace": "ns_...", "entropy_bits": 256 }
POST /lease
{ "namespace": "ns_...", "key": "invoice:2026-09-05",
"ttl_seconds": 60, "fingerprint": "charge-order-501" }
-> { "status": "held", "owner_token": "own_...", "fencing_token": 184 }
A lease can be renewed, released or completed. The absolute lifecycle ends 24 hours after its first acquisition and cannot be extended. Read the Lease guide.
POST /queue - POST /queue/{id}/claim
Pass JSON jobs from producers to workers with separate read, write and worker tokens.
POST /queue {}
-> queue_id, read_token, write_token, worker_token, expire_timestamp
POST /queue/{queue_id}/jobs
Authorization: Bearer WRITE_TOKEN
{ "job_key": "report:42", "payload": { "report_id": 42 } }
POST /queue/{queue_id}/claim
Authorization: Bearer WORKER_TOKEN
{ "visibility_timeout": 60 }
Claim returns a job with a receipt, or job: null. Use the worker token and receipt to acknowledge, release or renew. Observers read counts and jobs with the read token. Credentials belong in headers, never in URLs.
The queue and all job state expire exactly 24 hours after creation. No activity extends it. Limits are 100 distinct jobs, 16 KiB per JSON payload and five claim attempts. Jobs can be delivered again after a claim expires or is released. Queue expiry and the attempt limit may leave jobs unfinished. Initial delivery and exactly-once execution are not guaranteed. Make external actions idempotent. Read the Agent Queue guide.
GET /semantic_search - POST /semantic_search/{id}/search
Keep short notes in a collection for 24 hours and find them by meaning, across wording and between languages, with bge-m3 or qwen3-embedding-4b. Creation returns a read token and a write token, once.
GET /semantic_search
-> collection_id, model, read_token, write_token, expire_timestamp
POST /semantic_search/{collection_id}/notes
Authorization: Bearer WRITE_TOKEN
{ "notes": [ { "text": "Suspicious login attempts on the admin page.", "key": "incident:17" } ] }
POST /semantic_search/{collection_id}/search
Authorization: Bearer READ_TOKEN
{ "query": "brute force attack on the admin login", "limit": 3 }
A search answers ranked suggestions with note ID, key, text and score, never a decision that a match exists. The score is not a probability.
The collection expires exactly 24 hours after creation. Limits are 500 notes over that lifetime, 2000 characters per note and 20 new collections per client IP per 24 hours. Adding and searching allow 60 calls per minute and 1000 per UTC day per IP. Read the semantic search guide, or try it in your browser.
GET /inbox - GET /inbox/{inbox_id}
Create a disposable mail address an agent can read for up to 24 hours. Verification codes and public links are extracted from the cleaned text. Attachments, raw MIME and arbitrary headers are never stored.
GET /inbox
-> { "ok": true, "inbox_id": "a85d0bee-...", "slug": "ztjqt7n",
"address": "aisense+ztjqt7n@aisenseapi.com" }
GET /inbox/{inbox_id}
-> { "received": 1, "truncated": false,
"messages": [ { "from": "...", "codes": ["481516"], "links": ["..."] } ] }
The slug in the address is public and only lets someone send mail. The inbox_id is a bearer secret and is the only value that reads the inbox. A wrong ID and a missing inbox both answer 404. A read can wait up to 25 seconds for the next message. A full inbox, at 20 messages or 256 KiB, refuses new mail and keeps the old, which is what truncated reports. Read the Agent Inbox guide.