Aisense free public rest apis agent

Free, public, no-auth REST APIs from AI SENSE AS — clients for OpenClaw, Python, JavaScript, OpenAI function calling, Claude, and many more

by aisenseapi·MIT license·★ 0 Stars on the repo·GitHub ↗

Files of Aisense free public rest apis

aisenseapi/main1 file
README.md
Show the full text1008 lines

Free Public REST APIs - AI SENSE AS

No API key | No sign-up | No cost

Provided by AI SENSE AS (Oslo, Norway). Full endpoint reference: API.md | Repo: github.com/aisenseapi/aisense-free-public-rest-apis

Base URL: https://aisenseapi.com/services/v1/

Free public MCP endpoints

The AI SENSE MCP server is at:

https://aisenseapi.com/mcp

The AI SENSE MCP server covers Heartbeat, Lease, Agent Wake tasks, Agent Inbox, human approval, webhook capture, temporary storage, URL shortening, time and UUIDs. It needs no account or API key. Heartbeat uses create_heartbeat, read_heartbeat and ping_heartbeat. Lease uses create_lease_namespace, acquire_lease, renew_lease, release_lease and complete_lease. Agent Inbox uses create_agent_inbox and read_agent_inbox. See MCP.md for the tool list, data boundary and client examples.

The Agent Queue tools use separate read, write and worker tokens issued at creation. The semantic search tools use a read token and a write token in the same way.

Start with AGENT-GUIDE.md to choose tools, then AGENT-QUICKSTART.md for a complete Queue workflow and retry decisions.

The server reports version 1.13.0. It offers the workflow tools and one tool for each REST endpoint below. The official MCP Registry lists com.aisenseapi/free-public-tools version 1.13.0 as active and latest, published 4 October 2026 at 20:47 UTC.

aamio has its own MCP endpoint at https://aamio.at/mcp, eleven tools for ephemeral agent rendezvous: a thread with a secret read key and a public write address, a receipt of hashes that outlives it, presence, and the open board of needs and offers at https://board.aamio.at/. No account and no API key. The official MCP registry lists it as at.aamio/aamio. The AI SENSE endpoint does not proxy these tools either.

Verifyum has its own dedicated MCP endpoint at https://api.verifyum.com/mcp. It exposes the three Verifyum proof operations without an account or API key. File hashing still happens on the agent's machine. The browser flow, public HTTP API and published protocol remain available. The official MCP registry lists it as com.verifyum/mcp version 0.1.0. Finalized proofs also join hourly and daily Merkle checkpoints in the Verifyum Witness Layer. Nine records surround each finalized proof.

Tier Records
Primary evidence One finalized Solana Mainnet Memo transaction per proof
Independent corroboration Hourly OpenTimestamps on Bitcoin, daily qualified EU timestamp, daily witness-cosigned Sigsum and daily Certificate Transparency certificate
Operator records and availability redundancy Verifyum Ed25519 signature, GitHub checkpoint log, Software Heritage and Internet Archive

The Solana transaction is the primary evidence. Deep Solana history generally requires an archival provider. Glasklar, Mullvad and Tillitis cosign the Sigsum digest with a quorum of two out of three. The qualified timestamp uses RFC 3161. Its eIDAS Article 41(2) presumption covers the daily checkpoint root alone. A Verifyum user proof is not a qualified electronic timestamp. Verifyum is not a qualified trust service. Software Heritage and Internet Archive show what was stored. They do not establish when the original file existed. The number of channels is not a quality score.

Every finalized proof is also announced on Telegram and in the Atom feed. These are announcement channels. They are excluded from the nine evidence records. Their timestamps date the announcement. They say nothing about the original file date.

An agent can also assemble one decision record locally from its instructions, prompt, model, parameters, tool calls and output, then anchor only the commitment. The proof shows that the exact record existed unchanged by the block time. It does not prove that the model actually ran with the recorded settings.


Free public Agent2Agent (A2A) endpoint

Agents that speak Agent2Agent can reach five of these capabilities at:

https://aisenseapi.com/a2a

JSON-RPC 2.0, protocol revision 1.0, no account and no API key. The agent card is a plain GET at https://aisenseapi.com/.well-known/agent-card.json.

A2A is the protocol for delegating work to another agent. MCP is the protocol for exposing tools. Most of this service is tools, so only the five task-shaped capabilities are offered over A2A: agent-wake, human-approval, agent-inbox, webhook-capture and agent-queue. The other tools are not reachable through it. MCP stays the richer workflow surface with its own tool schemas. Over A2A the queue skill creates a queue and returns its three role tokens; enqueueing, claiming and acknowledging stay on REST and MCP.

A2A puts no skill id on the wire, so the caller names the skill in a data part of the message, as {"skill": "agent-wake", "arguments": { ... }}. That is a convention this service documents, not a field the protocol defines, and a message without it is refused. The card declares streaming and pushNotifications false, so those methods answer -32004 and -32003. ListTasks returns an empty page, because nobody is authenticated and a task ID is the only credential there is. See API.md for the skills, task states, response shapes and error codes.


SpeedUp (.su) - token cost, measured properly

Every serialization format marketed for LLM input ships a token-saving claim measured against a single tokenizer. Agent traffic crosses vendors, so we measured instead of assumed: six formats and 33 single-construct probes, priced by five vocabulary families (OpenAI o200k, DeepSeek, Qwen, SentencePiece, Tekken), with each provider's own token counter as ground truth.

  • SU-PROFILE.md - the SpeedUp profile: eight writing conventions for agent-to-agent text, each citing its measured price tag
  • speedup/ - the measurement rig (Python, standard library only), corpus, probes and raw numbers; rerun everything with your own keys
  • The study - what survived measurement, what did not, and why we decided against shipping yet another format

Headline numbers: plain TSV averages 0.82x minified JSON across the five-vocabulary union and beats the token-oriented formats on every model; declaring columns once and sending values positionally is the entire mechanism (minus 34 percent per key-value pair); base64 costs 3.9-4.6x the plaintext it encodes; and single-letter key dictionaries lose to full keys on four of five vocabularies.


Why this exists

Most utility APIs require sign-up, rate limit tiers, or pricing for basic operations. This collection skips all of that. Drop a URL into curl, Python, JavaScript, or an LLM tool definition and it just works.

The collection covers two tiers of usefulness:

  • Workflow endpoints - the ones that solve real problems in pipelines and agent systems
  • Standard utilities - hashing, encoding, UUIDs, time, crypto - the building blocks

Three things to know before you write a client

These are service-wide and they decide how your error handling has to look.

The response key is named after the endpoint. /md5_hash returns md5_hash, /random_color returns random_color, /ping returns ping. There is no generic data or result wrapper. Do not guess the key - API.md lists every one.

Errors usually use {"error": "message"} with a non-2xx HTTP status. Check both the status and the error field. The legacy wallet-generation handlers can return an error object with HTTP 200. Workflow endpoints use non-2xx statuses, including 409 for conflicts and 410 for an expired record that has not yet been removed. Once removed, the same ID returns 404. Unknown routes also return 404. Consult each endpoint for its additional errors.

There is a rate limit: 5000 requests per IP per day. Exceeding it returns HTTP 429 in the same flat error shape as everything else. The count resets at midnight Norwegian time (Europe/Oslo), 22:00 UTC in summer and 23:00 UTC in winter, and the 429 carries Retry-After with the seconds until then.


The high-value endpoints

Heartbeat - know when a worker stops checking in

Create a monitor with an expected check-in interval, a grace period and one action for a missed deadline. The action can POST to a public webhook or wake an existing Agent Wake webhook task.

curl -X POST https://aisenseapi.com/services/v1/heartbeat \
  -H "Content-Type: application/json" \
  -d '{
    "expect_every_seconds": 300,
    "grace_seconds": 60,
    "on_miss": {
      "url": "https://example.com/agent-offline",
      "payload": { "agent": "worker-7" }
    }
  }'

The response gives you an unguessable heartbeat_id, ping_url and status_url. Call the ping URL with POST after each successful cycle. Each ping moves the expected deadline. It does not move the fixed 24-hour expiry. A missed deadline fires once, with no retry.

MCP clients can use create_heartbeat, read_heartbeat and ping_heartbeat for the same state.

Webhook destinations are checked for SSRF at creation and delivery. Private and reserved addresses, URL credentials, fragments and redirects are blocked. See API.md for the states and response fields.


Lease - one winner for shared agent work

Lease coordinates workers without an account. Mint a private namespace, then claim a key for a short period:

curl -X POST https://aisenseapi.com/services/v1/lease/namespace \
  -H "Content-Type: application/json" -d '{}'

curl -X POST https://aisenseapi.com/services/v1/lease \
  -H "Content-Type: application/json" \
  -d '{
    "namespace": "ns_...",
    "key": "invoice:2026-09-05",
    "ttl_seconds": 60,
    "fingerprint": "charge-order-501"
  }'

The winner receives an owner_token and a monotonic fencing_token. A second worker receives HTTP 409 while the lease is held. The owner can renew, release or complete the lease with a JSON result. Later callers with the same key and fingerprint can reuse that completed result.

The lease has a fixed absolute expiry 24 hours after its first acquisition. Renewals cannot extend it. Raw keys, namespaces, owner tokens and fingerprints are not stored. See API.md for the full acquire and completion flow.

The matching MCP tools are create_lease_namespace, acquire_lease, renew_lease, release_lease and complete_lease.


Agent Queue - share temporary work

Agent Queue gives producers and workers a shared queue for small JSON jobs.

curl -X POST https://aisenseapi.com/services/v1/queue \
  -H "Content-Type: application/json" -d '{}'

curl -X POST https://aisenseapi.com/services/v1/queue/QUEUE_ID/jobs \
  -H "Authorization: Bearer WRITE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"job_key":"report:42","payload":{"report_id":42}}'

curl -X POST https://aisenseapi.com/services/v1/queue/QUEUE_ID/claim \
  -H "Authorization: Bearer WORKER_TOKEN" \
  -H "Content-Type: application/json" -d '{"visibility_timeout":60}'

Replace the uppercase placeholders with creation response values. Keep the three tokens: they are issued only once. A claim returns one job with a secret receipt, or job: null when empty. The worker performs the work, then posts {"receipt":"RECEIPT"} to /queue/QUEUE_ID/jobs/JOB_ID/ack using its worker token. It can release or renew an active claim with the same receipt. Observers read queue counts and individual jobs with the read token. Credentials belong in headers, never in URLs.

The queue and every job expire exactly 24 hours after queue creation. Enqueue, claims, renewals and completion never extend that deadline. Limits are 100 distinct jobs over the queue lifetime, 16 KiB of encoded JSON per job, five claim attempts, and 20 new queues per client IP per 24 hours. Visibility is 30 to 900 seconds, default 60. Repeating a job key and payload returns the existing job. A changed payload conflicts.

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. The service holds the queue state and does not run jobs, fetch URLs or send callbacks.

MCP clients use the eight queue tools. A2A clients name the agent-queue skill, which creates the queue and returns its three role tokens; enqueueing, claiming and acknowledging stay on REST or MCP.

See the Queue API reference, MCP tools and website guide.


Semantic search - find earlier notes by meaning

Semantic search keeps short notes from agents in a collection for 24 hours and finds them by meaning, across wording and between languages.

curl https://aisenseapi.com/services/v1/semantic_search

curl -X POST https://aisenseapi.com/services/v1/semantic_search/COLLECTION_ID/notes \
  -H "Authorization: Bearer WRITE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"notes":[{"text":"Suspicious login attempts from many addresses on the admin page.","key":"incident:17"},{"text":"Mange mislykkede innlogginger mot adminsiden i natt."}]}'

curl -X POST https://aisenseapi.com/services/v1/semantic_search/COLLECTION_ID/search \
  -H "Authorization: Bearer READ_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"query":"brute force attack on the admin login"}'

Creation returns the collection ID with a read token and a write token, shown only once. The default model is bge-m3. POST {"model":"qwen3-embedding-4b"} to /semantic_search to use the other one. A search answers ranked suggestions with note_id, key, text and score, never a decision that a match exists. The score is cosine similarity plus 0.1 per identifier, such as DEMO-57 or an amount, that search and note share, and it is not a probability.

The collection expires exactly 24 hours after creation. Limits are 500 notes over that lifetime, 2000 characters per note, 20 new collections per client IP per 24 hours, and 60 searches or additions per minute and 1000 per UTC day per IP. Keep secrets and sensitive personal data out of notes.

Agent Wake - resume after an outside event

Create one task that waits for a webhook, a human answer or a chosen time. MCP clients use the current Tasks extension and poll tasks/get. REST clients use POST /agent_wake and the returned status URL. A2A clients name the agent-wake skill and poll GetTask, which is the one skill that answers with an A2A Task rather than a Message.

{ "event_type": "webhook", "timeout_seconds": 3600 }

The result contains an unguessable task ID and a wake URL. The first request to that URL completes the task. Human tasks create a hosted form. Time tasks complete on the first read after the selected timestamp. Each task expires in 60 seconds to 24 hours.

REST clients can wait for a terminal state with GET /agent_wake/{task_id}/wait/{seconds}. The final value accepts 0 to 25.

See MCP.md for the task flow, and API.md for the REST calls and the A2A skill.


Webhook Action - human-in-the-loop for agents

The standout endpoint for AI and automation work. When an automated pipeline needs a human decision before continuing, this handles the whole pattern with zero backend setup.

How it works:

  1. POST a form definition (radio buttons, dropdowns, text fields, checkboxes)
  2. Get back a form_url, result_url and wait_url
  3. Send the form_url to a human via email or Slack
  4. Read result_url, or use wait_url to wait up to 25 seconds
curl -X POST https://aisenseapi.com/services/v1/webhook_action \
  -H "Content-Type: application/json" \
  -d '{
    "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 (optional)" }
    ]
  }'
{
  "ok": true,
  "action_id": "9e0e6d3b-1a45-44c5-9e0b-92f5f3bdb2f1",
  "form_url": "https://aisenseapi.com/services/v1/webhook_action/9e0e6d3b-.../form",
  "result_url": "https://aisenseapi.com/services/v1/webhook_action/9e0e6d3b-...",
  "wait_url": "https://aisenseapi.com/services/v1/webhook_action/9e0e6d3b-.../wait/25",
  "expire_timestamp": 1786959912,
  "expire_datetime": "2026-08-17T09:45:12Z"
}

Poll for the answer:

curl https://aisenseapi.com/services/v1/webhook_action/{action_id}
# "status": "pending" -> "answered", with the submission under "response"

Field types: radio, select, text, textarea, checkbox. options accepts plain strings or {"value": ..., "label": ...} objects. Expires after 24 hours.

Add respondents from 2 to 20 for separate one-use form links. The result then moves through pending, partial and answered, with answer counts, a tally and individual responses. Add notify_url when you want one completion signal that points back to the result without copying the answers.

MCP clients use create_human_approval and read_human_approval. A2A clients name the human-approval skill, which creates the form and returns its URLs; reading the answer stays on REST or MCP.


Webhook Capture - inspect any inbound HTTP request

Create a capture, get a unique URL, point any external service at it (Stripe, GitHub, Shopify), and read back the full request - method, headers, query parameters, IP, and parsed body. No ngrok, no local tunnel, no server.

# 1. Create a capture
curl -X POST https://aisenseapi.com/services/v1/webhook_capture
# -> { "status": "pending", "capture_id": "...", "update_url": "...", "read_url": "...", "wait_url": "..." }

# 2. Point your webhook sender at update_url, with any HTTP method
curl -X POST {update_url} -H "Content-Type: application/json" -d '{"event":"payment.created"}'

# 3. Wait up to 25 seconds for the first request
curl https://aisenseapi.com/services/v1/webhook_capture/{capture_id}/wait/25
{
  "ok": true,
  "capture_id": "6f8c9e52-...",
  "captured_at_timestamp": 1786873316,
  "captured_at_datetime": "2026-08-16T09:41:56Z",
  "request": {
    "method": "POST",
    "uri": "/services/v1/webhook_capture/6f8c9e52-.../update",
    "headers": { "content-type": "application/json" },
    "client_ip": "203.0.113.10",
    "body": { "json": { "event": "payment.created" }, "text": null, "base64": null, "raw_length": 28 }
  }
}

Expires after 24 hours.

The first inbound request wins and later retries cannot replace it. Captured bodies are capped at 256 KB. The create body may contain notify_url for one completion signal.

MCP clients use create_webhook_capture and read_webhook_capture. A2A clients name the webhook-capture skill, which creates the capture and returns its URLs; reading the request stays on REST or MCP.


Agent Inbox - a disposable mail address the agent controls

For the step where something has to arrive by email: a verification code, a confirmation link, a sign-up mail. Create an inbox, hand out the address, read the mail back as cleaned text. No account, no API key, and it lasts at most 24 hours.

curl https://aisenseapi.com/services/v1/inbox
{
  "ok": true,
  "inbox_id": "a85d0bee-f8f7-4be1-a1b3-8d58f3dbdfc7",
  "slug": "ztjqt7n",
  "address": "[email protected]",
  "read_url": "https://aisenseapi.com/services/v1/inbox/a85d0bee-f8f7-4be1-a1b3-8d58f3dbdfc7",
  "wait_url": "https://aisenseapi.com/services/v1/inbox/a85d0bee-f8f7-4be1-a1b3-8d58f3dbdfc7/wait/25",
  "expire_timestamp": 1800086400
}

Two identifiers come back, and they are not interchangeable. The slug is the seven characters inside the address. It is public by construction: it travels in mail headers, bounces and sender logs. Knowing it lets anyone send mail to the inbox. It never lets anyone read the inbox, and it never appears in a URL. The inbox_id is a UUID and the only credential that reads. Anyone holding it reads the mail, and it is returned once, at creation. Guessing the address does not read the inbox. A wrong inbox_id and a missing inbox both answer 404, never 403, so the two are indistinguishable.

Read the mail, or wait up to 25 seconds for it:

curl https://aisenseapi.com/services/v1/inbox/{inbox_id}
curl https://aisenseapi.com/services/v1/inbox/{inbox_id}/wait/25
{
  "ok": true,
  "slug": "ztjqt7n",
  "address": "[email protected]",
  "received": 1,
  "truncated": false,
  "messages": [
    {
      "from": "[email protected]",
      "subject": "Your verification code",
      "date": "2027-01-15T08:00:00Z",
      "text": "Your code is 481516. Confirm at https://example.com/confirm/abc",
      "codes": [ "481516" ],
      "links": [ "https://example.com/confirm/abc" ]
    }
  ],
  "created_at_timestamp": 1800000000,
  "expire_timestamp": 1800086400
}

The read response does not contain inbox_id. The credential is never echoed back. The wait form adds waited_seconds and wait_reason to the same object. A value above 25 is clamped to 25, the same as every other wait route.

codes are standalone 4 to 8 digit numbers. links are public http(s) links only; private-IP and localhost links are dropped. date is the time the service received the message, not the sender's Date header, because that header is sender controlled.

truncated says a message was refused, whether the inbox hit the message count or the total size. A full inbox refuses new mail rather than evicting old mail, so without the flag an agent waiting for a code would see a full inbox, no code and no reason. The wait watches the flag as well as the count, so a refusal ends it instead of leaving the caller to time out.

Attachments, raw MIME, arbitrary headers, scripts, styles, private-IP links and localhost links are stripped before storage. Only the sender address, subject, received time, cleaned text, codes and public links are kept.

Limits: 20 messages per inbox, 64 KiB of cleaned text per message, 256 KiB per inbox in total, 50 inboxes per client per UTC day and 5000 active inboxes service wide. The 24-hour lifetime is fixed and cannot be extended.

MCP clients use create_agent_inbox and read_agent_inbox, whose wait watches truncated as well and returns as soon as the cap refuses a message. A2A clients name the agent-inbox skill, which creates the inbox and returns its address and URLs; reading the mail stays on REST or MCP.


Storage - ephemeral key-value store for pipelines

Post any JSON, text, or file. Get back a UUID. Retrieve it from anywhere - another machine, a different agent call, a downstream pipeline step.

The body is stored verbatim. Whatever you send is exactly what comes back; no wrapper is added or removed.

curl -X POST https://aisenseapi.com/services/v1/storage \
  -H "Content-Type: application/json" \
  -d '{"result": 42, "status": "complete"}'
# -> { "storage_id": "550e8400-e29b-41d4-a716-446655440000",
#      "storage_url": "https://aisenseapi.com/services/v1/storage/550e8400-e29b-41d4-a716-446655440000",
#      "sha256_hash": "...", "bytes": 36, "expire_timestamp": 1738457158 }

curl https://aisenseapi.com/services/v1/storage/550e8400-e29b-41d4-a716-446655440000
# -> {"result": 42, "status": "complete"}

Expires after 24 hours. Executable files (Windows, Linux and Mac programs, judged on their first bytes) are refused with 415. Each IP may store 80 MB per day; past that a POST answers 429. A stored file is returned inline only as an image, audio, video or PDF; anything else, SVG included, comes back as a download.


URL Shortener
curl "https://aisenseapi.com/services/v1/url_shortener/https://example.com/very/long/path"
# -> { "short_url": "https://307.fi/KtNshX2B", "expire_timestamp": 1786959715 }

Expires after 24 hours.


IP Reverse Lookup
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"
}

city and place are frequently null, and the coordinates fall back to the country centroid when the city is unknown. Also available: resolve a domain to its IP.

curl https://aisenseapi.com/services/v1/domain_ip_lookup/example.com
# -> { "domain": "example.com", "ip": "104.20.23.154" }

Standard utilities

Hashing - MD5, SHA1, SHA256, SHA512, CRC32

Accepts JSON, plain text (Content-Type: text/plain), or a file upload. Each returns a key named after the algorithm, not hash.

curl -X POST https://aisenseapi.com/services/v1/sha256_hash \
  -H "Content-Type: application/json" -d '{"data": "Hello"}'
# -> { "sha256_hash": "185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969" }

md5_hash | sha1_hash | sha256_hash | sha512_hash | crc32_checksum | whirlpool_hash | sha3_256_hash | sha3_512_hash | blake2b_hash | blake3_hash

crc32_checksum returns an integer, not a hex string.

Password hashes, slow and salted, for test data, 200 operations per IP per day: argon2id_hash | bcrypt_hash | scrypt_hash, verified with password_verify, which reads the algorithm and the cost from the string.


Encoding - Base64, Base58, Base32, Hex, base64url, URL, HTML, JWT, QR Code
# Encode
curl -X POST https://aisenseapi.com/services/v1/base64_encode \
  -H "Content-Type: application/json" -d '{"data": "Hello world"}'
# -> { "base64_encoded_data": "SGVsbG8gd29ybGQ=" }

# Decode - returns the raw bytes, not JSON
curl -X POST https://aisenseapi.com/services/v1/base64_decode \
  -H "Content-Type: application/json" -d '{"data": "SGVsbG8gd29ybGQ="}'
# -> Hello world

# ...unless you ask for JSON
curl -X POST https://aisenseapi.com/services/v1/base64_decode \
  -H "Content-Type: application/json" -H "Accept: application/json" \
  -d '{"data": "eyJrZXkiOiJ2YWx1ZSJ9"}'
# -> { "type": "json", "decoded_data": { "key": "value" } }

The five byte decoders (base64_decode, base58_decode, base32_decode, hex_decode, base64url_decode) answer with application/octet-stream unless you send Accept: application/json. This is the one place the API is not JSON. base64_decode, hex_decode and base64url_decode also answer text/plain and refuse an Accept they cannot serve with 406; the other two give the bytes for anything but JSON.

curl -X POST https://aisenseapi.com/services/v1/hex_encode \
  -H "Content-Type: application/json" -d '{"data": "hello"}'
# -> { "hex_encoded_data": "68656c6c6f" }

curl -X POST https://aisenseapi.com/services/v1/base64url_encode \
  -H "Content-Type: application/json" -d '{"data": "hello?"}'
# -> { "base64url_encoded_data": "aGVsbG8_" }   (- and _, no padding, as in a JWT)

curl -X POST https://aisenseapi.com/services/v1/url_encode \
  -H "Content-Type: application/json" -d '{"data": "a b/c?é"}'
# -> { "url_encoded_data": "a%20b%2Fc%3F%C3%A9" }

curl -X POST https://aisenseapi.com/services/v1/html_encode \
  -H "Content-Type: application/json" -d '{"data": "<b>Tom & Jerry</b>"}'
# -> { "html_encoded_data": "&lt;b&gt;Tom &amp; Jerry&lt;/b&gt;" }

url_decode and html_decode answer JSON, url_decoded_data and html_decoded_data, since their result is text. url_decode leaves a + as a +.

HTML and Markdown. html_to_markdown turns a page or any HTML into CommonMark and answers markdown and the page title, without scripts, styles or forms. markdown_to_html answers html that is safe to put in a page: raw HTML in the Markdown is shown as text, and a link with an unsafe scheme as its text. Both take the JSON data string or the raw body.

curl -X POST https://aisenseapi.com/services/v1/html_to_markdown \
  -H "Content-Type: application/json" -d '{"data": "<h1>Hi</h1><p>A <b>bold</b> word</p>"}'
# -> { "markdown": "# Hi\n\nA **bold** word", "title": null }

curl -X POST https://aisenseapi.com/services/v1/markdown_to_html \
  -H "Content-Type: application/json" -d '{"data": "**Bold** <b>raw</b>"}'
# -> { "html": "<p><strong>Bold</strong> &lt;b&gt;raw&lt;/b&gt;</p>" }

JWT - data takes the claims as a JSON object, or as a string containing JSON. Both forms produce the same token.

curl -X POST https://aisenseapi.com/services/v1/jwt_encode \
  -H "Content-Type: application/json" \
  -d '{"data": {"user": "alice"}, "secret": "my-secret-key"}'
# -> { "jwt": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..." }

jwt_decode returns decoded_payload.

QR - the request field is payload, with data accepted as an alias.

curl -X POST https://aisenseapi.com/services/v1/qrcode_encode \
  -H "Content-Type: application/json" -d '{"payload": "https://example.com"}'
# -> { "qrcode_image": "iVBORw0KGgoAAAANSUhEUgAA...", "image_type": "png" }

qrcode_decode takes the same payload field (or a file upload) and returns qrcode_content. The image is a PNG, JPEG, GIF or WebP of at most 10 MB as a file upload. A JSON body is at most 256 KiB, so through payload the image can be about 190 KB.


Random - UUID, GUID, number, color, password
curl https://aisenseapi.com/services/v1/uuid            # { "uuid": "..." }
curl https://aisenseapi.com/services/v1/guid            # { "guid": "..." }
curl https://aisenseapi.com/services/v1/random_color    # { "random_color": "#9b6bbf" }
curl https://aisenseapi.com/services/v1/random_number/1/100
# -> { "random_number": 73, "range": { "from": 1, "to": 100 } }
curl https://aisenseapi.com/services/v1/password/16
# -> { "password": "jFehS]AKGx9wl[jp", "password_length": 16 }

A single argument to random_number is the upper bound, with the lower bound fixed at 1.


Time - Datetime, Timestamp, Timezones
curl https://aisenseapi.com/services/v1/datetime            # UTC
curl https://aisenseapi.com/services/v1/datetime/+0200      # with offset
curl https://aisenseapi.com/services/v1/datetime/europe/oslo  # a zone by name, summer time included
curl https://aisenseapi.com/services/v1/ip_datetime         # the same, where your address is
curl https://aisenseapi.com/services/v1/timestamp
curl https://aisenseapi.com/services/v1/microtimestamp
curl https://aisenseapi.com/services/v1/timezones
curl https://aisenseapi.com/services/v1/swatchinternettime

The offset is four digits with an optional sign - +0200, -0530, 0100 - or the same with a colon, +02:00. An hour-only value like 1 is not a valid route. A zone name such as europe/oslo, in any case, follows summer time, which a fixed offset does not. Its answer has the offset in force, the standard offset, whether summer time is on and when it starts and ends, and the day and week numbers. /ip_datetime[/{ip}] answers the same for the zone an address is in, the caller's own without one.

A client of worldtimeapi.org, which reset every connection we made on 3 October 2026, finds its answers here: /api/timezone/{zone} is /datetime/{zone}, /api/ip[/{address}] is /ip_datetime[/{ip}] and /api/timezone is /timezones, all JSON over HTTPS. The translation table has the details.

/timezones returns objects, not strings: {"timezones": [{"timezone": "Europe/Oslo", "offset": "+0200"}, ...]}.


Web utilities - Ping, Health, Client IP, User Agent
curl https://aisenseapi.com/services/v1/ping        # { "ping": "pong" }
curl https://aisenseapi.com/services/v1/health      # { "status": "ok", "microtimestamp": ... }
curl https://aisenseapi.com/services/v1/client_ip   # { "ip": "203.0.113.42" }
curl https://aisenseapi.com/services/v1/user_agent  # { "user_agent": "curl/8.5.0" }

Crypto - Wallet generation and balance lookup
curl https://aisenseapi.com/services/v1/solana/generate_new_wallet
curl https://aisenseapi.com/services/v1/bitcoin/generate_new_wallet
curl https://aisenseapi.com/services/v1/ethereum/generate_new_wallet

curl https://aisenseapi.com/services/v1/solana/balance/{address}
curl https://aisenseapi.com/services/v1/bitcoin/balance/{address}
curl https://aisenseapi.com/services/v1/ethereum/balance/{address}

All three generators return public_address (Bitcoin also returns private_key_wif). Ethereum balances come back as strings - {"wallet": "0x...", "balance_eth": "6.634527787345637061", "balance_wei": "6634527787345637061"}

  • because Wei routinely exceeds 2^53, the largest integer a JSON number survives in a JavaScript client.

Wallet generation is for development and testing only. A key produced by a public HTTP endpoint has crossed a network you do not control. Never fund one.


The bundled JavaScript and Python clients wrap Agent Queue with eight methods each, one per MCP tool; the raw HTTP examples above show the same calls.

Quick start by language

curl

curl https://aisenseapi.com/services/v1/uuid

Python - zero dependencies, standard library only.

from aisense_api import AISenseAPI
api = AISenseAPI()

print(api.get_uuid()["uuid"])
print(api.hash_sha256("Hello")["sha256_hash"])
print(api.ip_reverse_lookup("8.8.8.8")["country"])

JavaScript - Node 18+ or any modern browser, native fetch.

import { AISenseAPI } from './aisense-api.js'
const api = new AISenseAPI()

console.log((await api.getUUID()).uuid)
console.log((await api.hashSHA256('Hello')).sha256_hash)
console.log((await api.ipReverseLookup('8.8.8.8')).country)

Both clients return the parsed response, and every method's docstring names the exact response key. They also raise a clear error when a path does not exist, rather than letting the debug echo surface as a JSON parse failure. They cover every endpoint in API.md, which tools/check-sdk-coverage.py checks along with openai-tools.json. The image methods upload the file as multipart/form-data, and the failure simulator returns what the API sent instead of raising.

LLM function calling (OpenAI, Gemini, Mistral, ...)

import json
from openai import OpenAI

with open("openai-tools.json") as f:
    tools = json.load(f)

client = OpenAI()
response = client.chat.completions.create(
    model="gpt-4o",
    tools=tools,
    messages=[{"role": "user", "content": "Generate a UUID and hash the word Hello with SHA256"}]
)

Claude - SKILL.md is included. Add it to Claude's context and it will use these APIs as tools automatically.


What's in the repo

File Purpose
API.md Endpoint contracts, source checks and dated production observations
queue-openapi.json Standalone OpenAPI contract for Agent Queue
MCP.md Remote MCP server, tool list and client examples
AGENT-GUIDE.md Canonical compact guide to all MCP tools
AGENT-QUICKSTART.md Complete Queue example, worker and retry decisions
server.json Metadata for the official MCP Registry
aisense_api.py Python client (standard library only)
aisense-api.js JavaScript ESM client
openai-tools.json REST function-calling catalog, separate from the MCP tool list
SKILL.md Claude skill file
test.sh Asserts on response bodies and statuses; exits 1 on failure (CI-friendly)
tools/check-text.php Checks documentation punctuation before commit
tools/check-sdk-coverage.py Fails when an endpoint in API.md is missing from a client or from openai-tools.json
tools/check-sdk-requests.py Runs both clients against a local stub and checks each request for the newer endpoints
tools/pages/ Generators for the image tool pages and the three image guides in web/

test.sh asserts on response bodies as well as status codes. Bodies are the part that matters most: a status-code-only suite passes an endpoint that answers 200 with the wrong response key.


Endpoint summary

All paths are relative to https://aisenseapi.com/services/v1/

Category Endpoint Method Response key(s)
Time /datetime[/{offset}] GET datetime
Time /datetime/{zone} GET datetime, timezone, abbreviation, utc_offset, dst, unixtime, raw_offset, dst_offset, dst_from, dst_until, day_of_week, day_of_year, week_number, utc_datetime
Time /ip_datetime[/{ip}] GET ip, then the keys of /datetime/{zone}
Time /timestamp GET timestamp
Time /microtimestamp GET microtimestamp
Time /timezones[/{offset}] GET timezones
Time /swatchinternettime GET beat, date
Time /timestamp_convert POST input, detected, timestamp, datetime, rfc2822, utc_datetime
Random /random_number[/{from}[/{to}]] GET random_number, range
Random /random_color GET random_color
Random /uuid GET uuid
Random /guid GET guid
Random /password[/{length}] GET password, password_length
Transform /base64_encode POST base64_encoded_data
Transform /base64_decode POST raw bytes, or type + decoded_data
Transform /base58_encode POST base58_encoded_data
Transform /base58_decode POST raw bytes, or type + decoded_data
Transform /base32_encode POST base32_encoded_data
Transform /base32_decode POST raw bytes, or type + decoded_data
Transform /hex_encode POST hex_encoded_data
Transform /hex_decode POST raw bytes, or type + decoded_data
Transform /base64url_encode POST base64url_encoded_data
Transform /base64url_decode POST raw bytes, or type + decoded_data
Transform /url_encode POST url_encoded_data
Transform /url_decode POST url_decoded_data
Transform /html_encode POST html_encoded_data
Transform /html_decode POST html_decoded_data
Transform /html_to_markdown POST markdown, title
Transform /markdown_to_html POST html
Transform /slugify POST slug
Transform /jwt_encode POST jwt
Transform /jwt_decode POST decoded_payload
Transform /qrcode_encode POST qrcode_image, image_type
Transform /qrcode_decode POST qrcode_content
Hash /md5_hash POST md5_hash
Hash /sha1_hash POST sha1_hash
Hash /sha256_hash POST sha256_hash
Hash /sha512_hash POST sha512_hash
Hash /crc32_checksum POST crc32_checksum
Hash /whirlpool_hash POST whirlpool_hash
Hash /sha3_256_hash POST sha3_256_hash
Hash /sha3_512_hash POST sha3_512_hash
Hash /blake2b_hash POST blake2b_hash
Hash /blake3_hash POST blake3_hash
Hash /argon2id_hash POST argon2id_hash
Hash /bcrypt_hash POST bcrypt_hash
Hash /scrypt_hash POST scrypt_hash
Hash /hash_verify POST match, algorithm, computed
Hash /password_verify POST match, algorithm, params
Web /ping GET ping
Web /health GET status, microtimestamp
Web /client_ip GET ip
Web /html2pdf POST storage_id, storage_url, sha256_hash, bytes, expire_timestamp
Web /user_agent GET user_agent
Web /ip_reverse_lookup/{ip} GET ip, country, city, location, place, timezone
Web /domain_ip_lookup/{domain} GET domain, ip
Web /email_validate POST email, valid_syntax, domain, has_mx, mx_hosts
Web /storage POST / GET storage_id, storage_url, sha256_hash, bytes, expire_timestamp
Web /storage/{id}/sha256/{hex} GET the stored body, or 412 if it does not hash to {hex}
Web /url_shortener/{url} GET short_url, expire_timestamp
Web /webhook_capture POST / GET capture_id, update_url, read_url, wait_url
Web /webhook_action POST / GET action_id, form URL or URLs, result_url, wait_url
Web /webhook_schedule POST / GET / DELETE one-shot or recurring status, counts and result
Web /agent_wake POST / GET / DELETE taskId, status, result, wait support
Web /inbox POST inbox_id, slug, address, read_url, wait_url, expire_timestamp
Web /inbox/{inbox_id} GET slug, address, received, truncated, messages, timing fields
Web /heartbeat POST heartbeat_id, status, timing fields, ping_url, status_url
Web /heartbeat/{id} GET status, timing fields, counters, optional delivery
Web /heartbeat/{id}/ping POST updated timing fields and counters
Web /lease/namespace POST namespace, entropy_bits
Web /lease, /lease/acquire POST status, owner and fencing tokens, expiry fields, optional result
Web /lease/renew, /lease/release, /lease/complete POST status, fencing token, expiry fields, optional result
Web /queue POST queue_id, role tokens, counts and fixed expiry
Web /queue/{id} GET queue_id, counts and timing
Web /queue/{id}/jobs, /queue/{id}/claim, job operations POST / GET job, with a receipt only on claim
Web /validate/{type} POST type, valid, per-check fields
Crypto /solana/generate_new_wallet GET private_key, private_key_base58, public_address
Crypto /solana/balance/{address} GET wallet, balance_sol, balance_lamports
Crypto /bitcoin/generate_new_wallet GET private_key, private_key_wif, public_address
Crypto /bitcoin/balance/{address} GET wallet, final_balance_btc, final_balance_sats
Crypto /ethereum/generate_new_wallet GET private_key, public_address
Crypto /ethereum/balance/{address} GET wallet, balance_eth, balance_wei

Notes

  • Input formats vary by endpoint. Utility transforms accept several formats, while Queue and other structured workflow endpoints require JSON
  • Storage, URL Shortener, Webhook Capture, Webhook Action, Webhook Schedule, Agent Wake, Agent Inbox, Heartbeat, Lease and Queue have a 24-hour active lifetime or absolute lifecycle
  • Queue jobs, including completed and failed jobs, share the fixed queue expiry. Activity never extends it
  • Webhook Schedule keeps its final result for up to another 24 hours
  • Heartbeat terminal state can remain readable for another 24 hours after it fires, misses or expires
  • Access-Control-Allow-Origin: * is set on every response, so these are callable from a browser
  • Rate limit: 5000 requests per IP per day

AI SENSE AS | aisenseapi.com Postboks 1202 Vika, 0110 Oslo, Norway

MIT License

1# Free Public REST APIs - AI SENSE AS
2 
3No API key | No sign-up | No cost
4 
5Provided by **[AI SENSE AS](https://aisenseapi.com)** (Oslo, Norway).
6Full endpoint reference: [`API.md`](API.md) | Repo: [github.com/aisenseapi/aisense-free-public-rest-apis](https://github.com/aisenseapi/aisense-free-public-rest-apis)
7 
8**Base URL:** `https://aisenseapi.com/services/v1/`
9 
10## Free public MCP endpoints
11 
12The AI SENSE MCP server is at:
13 
14`https://aisenseapi.com/mcp`
15 
16The AI SENSE MCP server covers Heartbeat, Lease, Agent Wake tasks, Agent
17Inbox, human approval, webhook capture, temporary storage, URL shortening,
18time and UUIDs. It needs no account or API key. Heartbeat uses
19`create_heartbeat`, `read_heartbeat` and `ping_heartbeat`. Lease uses
20`create_lease_namespace`, `acquire_lease`, `renew_lease`, `release_lease` and
21`complete_lease`. Agent Inbox uses `create_agent_inbox` and
22`read_agent_inbox`. See
23[`MCP.md`](MCP.md) for the tool list, data boundary and client examples.
24 
25The Agent Queue tools use separate read, write and worker tokens issued at
26creation. The semantic search tools use a read token and a write token in
27the same way.
28 
29Start with [AGENT-GUIDE.md](AGENT-GUIDE.md) to choose tools, then
30[AGENT-QUICKSTART.md](AGENT-QUICKSTART.md) for a complete Queue workflow and
31retry decisions.
32 
33The server reports version `1.13.0`. It offers the workflow tools and one
34tool for each REST endpoint below. The official MCP Registry lists
35`com.aisenseapi/free-public-tools` version `1.13.0` as active and latest,
36published 4 October 2026 at 20:47 UTC.
37 
38aamio has its own MCP endpoint at `https://aamio.at/mcp`, eleven tools for
39ephemeral agent rendezvous: a thread with a secret read key and a public write
40address, a receipt of hashes that outlives it, presence, and the open board of
41needs and offers at `https://board.aamio.at/`. No account and no API key. The
42official MCP registry lists it as `at.aamio/aamio`. The AI SENSE endpoint does
43not proxy these tools either.
44 
45Verifyum has its own dedicated MCP endpoint at
46`https://api.verifyum.com/mcp`. It exposes the three Verifyum proof operations
47without an account or API key. File hashing still happens on the agent's
48machine. The browser flow, public HTTP API and published protocol remain
49available. The official MCP registry lists it as `com.verifyum/mcp` version
50`0.1.0`. Finalized proofs also join hourly and daily Merkle checkpoints in
51the [Verifyum Witness Layer](https://verifyum.com/witness). Nine records
52surround each finalized proof.
53 
54| Tier | Records |
55| --- | --- |
56| Primary evidence | One finalized Solana Mainnet Memo transaction per proof |
57| Independent corroboration | Hourly OpenTimestamps on Bitcoin, daily qualified EU timestamp, daily witness-cosigned Sigsum and daily Certificate Transparency certificate |
58| Operator records and availability redundancy | Verifyum Ed25519 signature, GitHub checkpoint log, Software Heritage and Internet Archive |
59 
60The Solana transaction is the primary evidence. Deep Solana history generally
61requires an archival provider. Glasklar, Mullvad and Tillitis cosign the
62Sigsum digest with a quorum of two out of three. The qualified timestamp uses
63RFC 3161. Its eIDAS Article 41(2) presumption covers the daily checkpoint root
64alone. A Verifyum user proof is not a qualified electronic timestamp. Verifyum
65is not a qualified trust service. Software Heritage and Internet Archive show
66what was stored. They do not establish when the original file existed. The
67number of channels is not a quality score.
68 
69Every finalized proof is also announced on
70[Telegram](https://t.me/verifyum) and in the
71[Atom feed](https://verifyum.com/feed.xml). These are announcement channels.
72They are excluded from the nine evidence records. Their timestamps date the
73announcement. They say nothing about the original file date.
74 
75An agent can also assemble one decision record locally from its instructions,
76prompt, model, parameters, tool calls and output, then anchor only the
77commitment. The proof shows that the exact record existed unchanged by the
78block time. It does not prove that the model actually ran with the recorded
79settings.
80 
81---
82 
83## Free public Agent2Agent (A2A) endpoint
84 
85Agents that speak Agent2Agent can reach five of these capabilities at:
86 
87`https://aisenseapi.com/a2a`
88 
89JSON-RPC 2.0, protocol revision 1.0, no account and no API key. The agent card
90is a plain GET at `https://aisenseapi.com/.well-known/agent-card.json`.
91 
92A2A is the protocol for delegating work to another agent. MCP is the protocol
93for exposing tools. Most of this service is tools, so only the five task-shaped
94capabilities are offered over A2A: `agent-wake`, `human-approval`,
95`agent-inbox`, `webhook-capture` and `agent-queue`. The other tools are not
96reachable through it. MCP stays the richer workflow surface with its own tool
97schemas. Over A2A the queue skill creates a queue and returns its three role
98tokens; enqueueing, claiming and acknowledging stay on REST and MCP.
99 
100A2A puts no skill id on the wire, so the caller names the skill in a data part
101of the message, as `{"skill": "agent-wake", "arguments": { ... }}`. That is a
102convention this service documents, not a field the protocol defines, and a
103message without it is refused. The card declares `streaming` and
104`pushNotifications` false, so those methods answer `-32004` and `-32003`.
105`ListTasks` returns an empty page, because nobody is authenticated and a task ID
106is the only credential there is. See [`API.md`](API.md#agent2agent-a2a) for the
107skills, task states, response shapes and error codes.
108 
109---
110 
111## SpeedUp (.su) - token cost, measured properly
112 
113Every serialization format marketed for LLM input ships a token-saving claim
114measured against a single tokenizer. Agent traffic crosses vendors, so we
115measured instead of assumed: six formats and 33 single-construct probes,
116priced by five vocabulary families (OpenAI o200k, DeepSeek, Qwen,
117SentencePiece, Tekken), with each provider's own token counter as ground
118truth.
119 
120- [`SU-PROFILE.md`](SU-PROFILE.md) - the SpeedUp profile: eight writing
121 conventions for agent-to-agent text, each citing its measured price tag
122- [`speedup/`](speedup/) - the measurement rig (Python, standard library
123 only), corpus, probes and raw numbers; rerun everything with your own keys
124- [The study](https://aisense.no/tokenizer-cost-study) - what survived
125 measurement, what did not, and why we decided against shipping yet another
126 format
127 
128Headline numbers: plain TSV averages 0.82x minified JSON across the
129five-vocabulary union and beats the token-oriented formats on every model;
130declaring columns once and sending values positionally is the entire
131mechanism (minus 34 percent per key-value pair); base64 costs 3.9-4.6x the
132plaintext it encodes; and single-letter key dictionaries lose to full keys
133on four of five vocabularies.
134 
135---
136 
137## Why this exists
138 
139Most utility APIs require sign-up, rate limit tiers, or pricing for basic
140operations. This collection skips all of that. Drop a URL into curl, Python,
141JavaScript, or an LLM tool definition and it just works.
142 
143The collection covers two tiers of usefulness:
144 
145- **Workflow endpoints** - the ones that solve real problems in pipelines and agent systems
146- **Standard utilities** - hashing, encoding, UUIDs, time, crypto - the building blocks
147 
148---
149 
150## Three things to know before you write a client
151 
152These are service-wide and they decide how your error handling has to look.
153 
154**The response key is named after the endpoint.** `/md5_hash` returns
155`md5_hash`, `/random_color` returns `random_color`, `/ping` returns `ping`.
156There is no generic `data` or `result` wrapper. Do not guess the key -
157[`API.md`](API.md) lists every one.
158 
159**Errors usually use `{"error": "message"}` with a non-2xx HTTP status.**
160Check both the status and the `error` field. The legacy wallet-generation
161handlers can return an error object with HTTP 200. Workflow endpoints use
162non-2xx statuses, including 409 for conflicts and 410 for an expired record
163that has not yet been removed. Once removed, the same ID returns 404. Unknown
164routes also return 404. Consult each endpoint for its additional errors.
165 
166**There is a rate limit: 5000 requests per IP per day.** Exceeding it
167returns HTTP 429 in the same flat error shape as everything else. The count
168resets at midnight Norwegian time (Europe/Oslo), 22:00 UTC in summer and 23:00
169UTC in winter, and the 429 carries `Retry-After` with the seconds until then.
170 
171---
172 
173## The high-value endpoints
174 
175### Heartbeat - know when a worker stops checking in
176 
177Create a monitor with an expected check-in interval, a grace period and one
178action for a missed deadline. The action can POST to a public webhook or wake
179an existing Agent Wake webhook task.
180 
181```bash
182curl -X POST https://aisenseapi.com/services/v1/heartbeat \
183 -H "Content-Type: application/json" \
184 -d '{
185 "expect_every_seconds": 300,
186 "grace_seconds": 60,
187 "on_miss": {
188 "url": "https://example.com/agent-offline",
189 "payload": { "agent": "worker-7" }
190 }
191 }'
192```
193 
194The response gives you an unguessable `heartbeat_id`, `ping_url` and
195`status_url`. Call the ping URL with POST after each successful cycle.
196Each ping moves the expected deadline. It does not move the fixed 24-hour
197expiry. A missed deadline fires once, with no retry.
198 
199MCP clients can use `create_heartbeat`, `read_heartbeat` and
200`ping_heartbeat` for the same state.
201 
202Webhook destinations are checked for SSRF at creation and delivery. Private
203and reserved addresses, URL credentials, fragments and redirects are blocked.
204See [`API.md`](API.md) for the states and response fields.
205 
206---
207 
208### Lease - one winner for shared agent work
209 
210Lease coordinates workers without an account. Mint a private namespace, then
211claim a key for a short period:
212 
213```bash
214curl -X POST https://aisenseapi.com/services/v1/lease/namespace \
215 -H "Content-Type: application/json" -d '{}'
216 
217curl -X POST https://aisenseapi.com/services/v1/lease \
218 -H "Content-Type: application/json" \
219 -d '{
220 "namespace": "ns_...",
221 "key": "invoice:2026-09-05",
222 "ttl_seconds": 60,
223 "fingerprint": "charge-order-501"
224 }'
225```
226 
227The winner receives an `owner_token` and a monotonic `fencing_token`. A second
228worker receives HTTP 409 while the lease is held. The owner can renew, release
229or complete the lease with a JSON result. Later callers with the same key and
230fingerprint can reuse that completed result.
231 
232The lease has a fixed absolute expiry 24 hours after its first acquisition.
233Renewals cannot extend it. Raw keys, namespaces, owner tokens and fingerprints
234are not stored. See [`API.md`](API.md) for the full acquire and completion
235flow.
236 
237The matching MCP tools are `create_lease_namespace`, `acquire_lease`,
238`renew_lease`, `release_lease` and `complete_lease`.
239 
240---
241 
242### Agent Queue - share temporary work
243 
244Agent Queue gives producers and workers a shared queue for small JSON jobs.
245 
246```bash
247curl -X POST https://aisenseapi.com/services/v1/queue \
248 -H "Content-Type: application/json" -d '{}'
249 
250curl -X POST https://aisenseapi.com/services/v1/queue/QUEUE_ID/jobs \
251 -H "Authorization: Bearer WRITE_TOKEN" \
252 -H "Content-Type: application/json" \
253 -d '{"job_key":"report:42","payload":{"report_id":42}}'
254 
255curl -X POST https://aisenseapi.com/services/v1/queue/QUEUE_ID/claim \
256 -H "Authorization: Bearer WORKER_TOKEN" \
257 -H "Content-Type: application/json" -d '{"visibility_timeout":60}'
258```
259 
260Replace the uppercase placeholders with creation response values. Keep the
261three tokens: they are issued only once. A claim returns one job with a secret
262`receipt`, or `job: null` when empty. The worker performs the work, then posts
263`{"receipt":"RECEIPT"}` to `/queue/QUEUE_ID/jobs/JOB_ID/ack` using its worker
264token. It can release or renew an active claim with the same receipt. Observers
265read queue counts and individual jobs with the read token. Credentials belong
266in headers, never in URLs.
267 
268The queue and every job expire exactly 24 hours after queue creation. Enqueue,
269claims, renewals and completion never extend that deadline. Limits are 100
270distinct jobs over the queue lifetime, 16 KiB of encoded JSON per job, five
271claim attempts, and 20 new queues per client IP per 24 hours. Visibility is
27230 to 900 seconds, default 60. Repeating a job key and payload returns the
273existing job. A changed payload conflicts.
274 
275Jobs 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
276actions idempotent. The service holds
277the queue state and does not run jobs, fetch URLs or send callbacks.
278 
279MCP clients use the eight queue tools. A2A clients name the `agent-queue` skill,
280which creates the queue and returns its three role tokens; enqueueing, claiming
281and acknowledging stay on REST or MCP.
282 
283See the [Queue API reference](API.md#agent-queue---temporary-work-for-multiple-workers),
284[MCP tools](MCP.md#agent-queue) and
285[website guide](web/free-public-api-agent-queue-api-endpoint.html).
286 
287---
288 
289### Semantic search - find earlier notes by meaning
290 
291Semantic search keeps short notes from agents in a collection for 24 hours and
292finds them by meaning, across wording and between languages.
293 
294```bash
295curl https://aisenseapi.com/services/v1/semantic_search
296 
297curl -X POST https://aisenseapi.com/services/v1/semantic_search/COLLECTION_ID/notes \
298 -H "Authorization: Bearer WRITE_TOKEN" \
299 -H "Content-Type: application/json" \
300 -d '{"notes":[{"text":"Suspicious login attempts from many addresses on the admin page.","key":"incident:17"},{"text":"Mange mislykkede innlogginger mot adminsiden i natt."}]}'
301 
302curl -X POST https://aisenseapi.com/services/v1/semantic_search/COLLECTION_ID/search \
303 -H "Authorization: Bearer READ_TOKEN" \
304 -H "Content-Type: application/json" \
305 -d '{"query":"brute force attack on the admin login"}'
306```
307 
308Creation returns the collection ID with a read token and a write token, shown
309only once. The default model is `bge-m3`. POST `{"model":"qwen3-embedding-4b"}`
310to `/semantic_search` to use the other one. A search answers ranked suggestions
311with `note_id`, `key`, `text` and `score`, never a decision that a match
312exists. The score is cosine similarity plus 0.1 per identifier, such as
313`DEMO-57` or an amount, that search and note share, and it is not a
314probability.
315 
316The collection expires exactly 24 hours after creation. Limits are 500 notes
317over that lifetime, 2000 characters per note, 20 new collections per client IP
318per 24 hours, and 60 searches or additions per minute and 1000 per UTC day per
319IP. Keep secrets and sensitive personal data out of notes.
320 
321### Agent Wake - resume after an outside event
322 
323Create one task that waits for a webhook, a human answer or a chosen time. MCP
324clients use the current Tasks extension and poll `tasks/get`. REST clients use
325`POST /agent_wake` and the returned status URL. A2A clients name the
326`agent-wake` skill and poll `GetTask`, which is the one skill that answers with
327an A2A Task rather than a Message.
328 
329```json
330{ "event_type": "webhook", "timeout_seconds": 3600 }
331```
332 
333The result contains an unguessable task ID and a wake URL. The first request to
334that URL completes the task. Human tasks create a hosted form. Time tasks
335complete on the first read after the selected timestamp. Each task expires in
33660 seconds to 24 hours.
337 
338REST clients can wait for a terminal state with
339`GET /agent_wake/{task_id}/wait/{seconds}`. The final value accepts 0 to 25.
340 
341See [`MCP.md`](MCP.md) for the task flow, and [`API.md`](API.md) for the REST
342calls and the [A2A skill](API.md#agent2agent-a2a).
343 
344---
345 
346### Webhook Action - human-in-the-loop for agents
347 
348The standout endpoint for AI and automation work. When an automated pipeline
349needs a human decision before continuing, this handles the whole pattern with
350zero backend setup.
351 
352**How it works:**
353 
3541. `POST` a form definition (radio buttons, dropdowns, text fields, checkboxes)
3552. Get back a `form_url`, `result_url` and `wait_url`
3563. Send the `form_url` to a human via email or Slack
3574. Read `result_url`, or use `wait_url` to wait up to 25 seconds
358 
359```bash
360curl -X POST https://aisenseapi.com/services/v1/webhook_action \
361 -H "Content-Type: application/json" \
362 -d '{
363 "title": "Approve deployment to production?",
364 "fields": [
365 {
366 "type": "radio",
367 "name": "decision",
368 "label": "Decision",
369 "required": true,
370 "options": [
371 { "value": "approve", "label": "Approve" },
372 { "value": "reject", "label": "Reject" }
373 ]
374 },
375 { "type": "textarea", "name": "comment", "label": "Notes (optional)" }
376 ]
377 }'
378```
379 
380```json
381{
382 "ok": true,
383 "action_id": "9e0e6d3b-1a45-44c5-9e0b-92f5f3bdb2f1",
384 "form_url": "https://aisenseapi.com/services/v1/webhook_action/9e0e6d3b-.../form",
385 "result_url": "https://aisenseapi.com/services/v1/webhook_action/9e0e6d3b-...",
386 "wait_url": "https://aisenseapi.com/services/v1/webhook_action/9e0e6d3b-.../wait/25",
387 "expire_timestamp": 1786959912,
388 "expire_datetime": "2026-08-17T09:45:12Z"
389}
390```
391 
392Poll for the answer:
393 
394```bash
395curl https://aisenseapi.com/services/v1/webhook_action/{action_id}
396# "status": "pending" -> "answered", with the submission under "response"
397```
398 
399Field types: `radio`, `select`, `text`, `textarea`, `checkbox`. `options`
400accepts plain strings or `{"value": ..., "label": ...}` objects. Expires after
40124 hours.
402 
403Add `respondents` from 2 to 20 for separate one-use form links. The result then
404moves through `pending`, `partial` and `answered`, with answer counts, a tally
405and individual responses. Add `notify_url` when you want one completion signal
406that points back to the result without copying the answers.
407 
408MCP clients use `create_human_approval` and `read_human_approval`. A2A clients
409name the `human-approval` skill, which creates the form and returns its URLs;
410reading the answer stays on REST or MCP.
411 
412---
413 
414### Webhook Capture - inspect any inbound HTTP request
415 
416Create a capture, get a unique URL, point any external service at it
417(Stripe, GitHub, Shopify), and read back the full request - method, headers,
418query parameters, IP, and parsed body. No ngrok, no local tunnel, no server.
419 
420```bash
421# 1. Create a capture
422curl -X POST https://aisenseapi.com/services/v1/webhook_capture
423# -> { "status": "pending", "capture_id": "...", "update_url": "...", "read_url": "...", "wait_url": "..." }
424 
425# 2. Point your webhook sender at update_url, with any HTTP method
426curl -X POST {update_url} -H "Content-Type: application/json" -d '{"event":"payment.created"}'
427 
428# 3. Wait up to 25 seconds for the first request
429curl https://aisenseapi.com/services/v1/webhook_capture/{capture_id}/wait/25
430```
431 
432```json
433{
434 "ok": true,
435 "capture_id": "6f8c9e52-...",
436 "captured_at_timestamp": 1786873316,
437 "captured_at_datetime": "2026-08-16T09:41:56Z",
438 "request": {
439 "method": "POST",
440 "uri": "/services/v1/webhook_capture/6f8c9e52-.../update",
441 "headers": { "content-type": "application/json" },
442 "client_ip": "203.0.113.10",
443 "body": { "json": { "event": "payment.created" }, "text": null, "base64": null, "raw_length": 28 }
444 }
445}
446```
447 
448Expires after 24 hours.
449 
450The first inbound request wins and later retries cannot replace it. Captured
451bodies are capped at 256 KB. The create body may contain `notify_url` for one
452completion signal.
453 
454MCP clients use `create_webhook_capture` and `read_webhook_capture`. A2A clients
455name the `webhook-capture` skill, which creates the capture and returns its URLs;
456reading the request stays on REST or MCP.
457 
458---
459 
460### Agent Inbox - a disposable mail address the agent controls
461 
462For the step where something has to arrive by email: a verification code, a
463confirmation link, a sign-up mail. Create an inbox, hand out the address, read
464the mail back as cleaned text. No account, no API key, and it lasts at most 24
465hours.
466 
467```bash
468curl https://aisenseapi.com/services/v1/inbox
469```
470 
471```json
472{
473 "ok": true,
474 "inbox_id": "a85d0bee-f8f7-4be1-a1b3-8d58f3dbdfc7",
475 "slug": "ztjqt7n",
476 "address": "[email protected]",
477 "read_url": "https://aisenseapi.com/services/v1/inbox/a85d0bee-f8f7-4be1-a1b3-8d58f3dbdfc7",
478 "wait_url": "https://aisenseapi.com/services/v1/inbox/a85d0bee-f8f7-4be1-a1b3-8d58f3dbdfc7/wait/25",
479 "expire_timestamp": 1800086400
480}
481```
482 
483**Two identifiers come back, and they are not interchangeable.** The `slug` is
484the seven characters inside the address. It is public by construction: it
485travels in mail headers, bounces and sender logs. Knowing it lets anyone send
486mail to the inbox. It never lets anyone read the inbox, and it never appears
487in a URL. The `inbox_id` is a UUID and the only credential that reads. Anyone
488holding it reads the mail, and it is returned once, at creation. Guessing the
489address does not read the inbox. A wrong `inbox_id` and a missing inbox both
490answer 404, never 403, so the two are indistinguishable.
491 
492Read the mail, or wait up to 25 seconds for it:
493 
494```bash
495curl https://aisenseapi.com/services/v1/inbox/{inbox_id}
496curl https://aisenseapi.com/services/v1/inbox/{inbox_id}/wait/25
497```
498 
499```json
500{
501 "ok": true,
502 "slug": "ztjqt7n",
503 "address": "[email protected]",
504 "received": 1,
505 "truncated": false,
506 "messages": [
507 {
508 "from": "[email protected]",
509 "subject": "Your verification code",
510 "date": "2027-01-15T08:00:00Z",
511 "text": "Your code is 481516. Confirm at https://example.com/confirm/abc",
512 "codes": [ "481516" ],
513 "links": [ "https://example.com/confirm/abc" ]
514 }
515 ],
516 "created_at_timestamp": 1800000000,
517 "expire_timestamp": 1800086400
518}
519```
520 
521The read response does not contain `inbox_id`. The credential is never echoed
522back. The wait form adds `waited_seconds` and `wait_reason` to the same object.
523A value above 25 is clamped to 25, the same as every other wait route.
524 
525`codes` are standalone 4 to 8 digit numbers. `links` are public http(s) links
526only; private-IP and localhost links are dropped. `date` is the time the
527service received the message, not the sender's `Date` header, because that
528header is sender controlled.
529 
530`truncated` says a message was refused, whether the inbox hit the message
531count or the total size. A full inbox refuses new mail rather than
532evicting old mail, so without the flag an agent waiting for a code would see a
533full inbox, no code and no reason. The wait watches the flag as well as the
534count, so a refusal ends it instead of leaving the caller to time out.
535 
536Attachments, raw MIME, arbitrary headers, scripts, styles, private-IP links and
537localhost links are stripped before storage. Only the sender address, subject,
538received time, cleaned text, codes and public links are kept.
539 
540Limits: 20 messages per inbox, 64 KiB of cleaned text per message, 256 KiB per
541inbox in total, 50 inboxes per client per UTC day and 5000 active inboxes
542service wide. The 24-hour lifetime is fixed and cannot be extended.
543 
544MCP clients use `create_agent_inbox` and `read_agent_inbox`, whose wait watches
545`truncated` as well and returns as soon as the cap refuses a message. A2A
546clients name the `agent-inbox` skill, which creates the inbox and returns its
547address and URLs; reading the mail stays on REST or MCP.
548 
549---
550 
551### Storage - ephemeral key-value store for pipelines
552 
553Post any JSON, text, or file. Get back a UUID. Retrieve it from anywhere -
554another machine, a different agent call, a downstream pipeline step.
555 
556**The body is stored verbatim.** Whatever you send is exactly what comes back;
557no wrapper is added or removed.
558 
559```bash
560curl -X POST https://aisenseapi.com/services/v1/storage \
561 -H "Content-Type: application/json" \
562 -d '{"result": 42, "status": "complete"}'
563# -> { "storage_id": "550e8400-e29b-41d4-a716-446655440000",
564# "storage_url": "https://aisenseapi.com/services/v1/storage/550e8400-e29b-41d4-a716-446655440000",
565# "sha256_hash": "...", "bytes": 36, "expire_timestamp": 1738457158 }
566 
567curl https://aisenseapi.com/services/v1/storage/550e8400-e29b-41d4-a716-446655440000
568# -> {"result": 42, "status": "complete"}
569```
570 
571Expires after 24 hours. Executable files (Windows, Linux and Mac programs,
572judged on their first bytes) are refused with `415`. Each IP may store 80 MB
573per day; past that a POST answers `429`. A stored file is returned inline
574only as an image, audio, video or PDF; anything else, SVG included, comes back
575as a download.
576 
577---
578 
579### URL Shortener
580 
581```bash
582curl "https://aisenseapi.com/services/v1/url_shortener/https://example.com/very/long/path"
583# -> { "short_url": "https://307.fi/KtNshX2B", "expire_timestamp": 1786959715 }
584```
585 
586Expires after 24 hours.
587 
588---
589 
590### IP Reverse Lookup
591 
592```bash
593curl https://aisenseapi.com/services/v1/ip_reverse_lookup/8.8.8.8
594```
595 
596```json
597{
598 "ip": "8.8.8.8",
599 "country": "United States",
600 "city": null,
601 "location": { "lat": "37.751000", "lng": "-97.822000" },
602 "place": null,
603 "timezone": "America/Chicago"
604}
605```
606 
607`city` and `place` are frequently `null`, and the coordinates fall back to the
608country centroid when the city is unknown. Also available: resolve a domain to
609its IP.
610 
611```bash
612curl https://aisenseapi.com/services/v1/domain_ip_lookup/example.com
613# -> { "domain": "example.com", "ip": "104.20.23.154" }
614```
615 
616---
617 
618## Standard utilities
619 
620### Hashing - MD5, SHA1, SHA256, SHA512, CRC32
621 
622Accepts JSON, plain text (`Content-Type: text/plain`), or a file upload.
623**Each returns a key named after the algorithm, not `hash`.**
624 
625```bash
626curl -X POST https://aisenseapi.com/services/v1/sha256_hash \
627 -H "Content-Type: application/json" -d '{"data": "Hello"}'
628# -> { "sha256_hash": "185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969" }
629```
630 
631`md5_hash` | `sha1_hash` | `sha256_hash` | `sha512_hash` | `crc32_checksum` |
632`whirlpool_hash` | `sha3_256_hash` | `sha3_512_hash` | `blake2b_hash` | `blake3_hash`
633 
634`crc32_checksum` returns an integer, not a hex string.
635 
636Password hashes, slow and salted, for test data, 200 operations per IP per
637day: `argon2id_hash` | `bcrypt_hash` | `scrypt_hash`, verified with
638`password_verify`, which reads the algorithm and the cost from the string.
639 
640---
641 
642### Encoding - Base64, Base58, Base32, Hex, base64url, URL, HTML, JWT, QR Code
643 
644```bash
645# Encode
646curl -X POST https://aisenseapi.com/services/v1/base64_encode \
647 -H "Content-Type: application/json" -d '{"data": "Hello world"}'
648# -> { "base64_encoded_data": "SGVsbG8gd29ybGQ=" }
649 
650# Decode - returns the raw bytes, not JSON
651curl -X POST https://aisenseapi.com/services/v1/base64_decode \
652 -H "Content-Type: application/json" -d '{"data": "SGVsbG8gd29ybGQ="}'
653# -> Hello world
654 
655# ...unless you ask for JSON
656curl -X POST https://aisenseapi.com/services/v1/base64_decode \
657 -H "Content-Type: application/json" -H "Accept: application/json" \
658 -d '{"data": "eyJrZXkiOiJ2YWx1ZSJ9"}'
659# -> { "type": "json", "decoded_data": { "key": "value" } }
660```
661 
662The five byte decoders (`base64_decode`, `base58_decode`, `base32_decode`,
663`hex_decode`, `base64url_decode`) answer with `application/octet-stream` unless
664you send `Accept: application/json`. This is the one place the API is not JSON.
665`base64_decode`, `hex_decode` and `base64url_decode` also answer `text/plain`
666and refuse an `Accept` they cannot serve with 406; the other two give the bytes
667for anything but JSON.
668 
669```bash
670curl -X POST https://aisenseapi.com/services/v1/hex_encode \
671 -H "Content-Type: application/json" -d '{"data": "hello"}'
672# -> { "hex_encoded_data": "68656c6c6f" }
673 
674curl -X POST https://aisenseapi.com/services/v1/base64url_encode \
675 -H "Content-Type: application/json" -d '{"data": "hello?"}'
676# -> { "base64url_encoded_data": "aGVsbG8_" } (- and _, no padding, as in a JWT)
677 
678curl -X POST https://aisenseapi.com/services/v1/url_encode \
679 -H "Content-Type: application/json" -d '{"data": "a b/c?é"}'
680# -> { "url_encoded_data": "a%20b%2Fc%3F%C3%A9" }
681 
682curl -X POST https://aisenseapi.com/services/v1/html_encode \
683 -H "Content-Type: application/json" -d '{"data": "<b>Tom & Jerry</b>"}'
684# -> { "html_encoded_data": "&lt;b&gt;Tom &amp; Jerry&lt;/b&gt;" }
685```
686 
687`url_decode` and `html_decode` answer JSON, `url_decoded_data` and
688`html_decoded_data`, since their result is text. `url_decode` leaves a `+` as a
689`+`.
690 
691**HTML and Markdown.** `html_to_markdown` turns a page or any HTML into
692CommonMark and answers `markdown` and the page `title`, without scripts,
693styles or forms. `markdown_to_html` answers `html` that is safe to put in a
694page: raw HTML in the Markdown is shown as text, and a link with an unsafe
695scheme as its text. Both take the JSON `data` string or the raw body.
696 
697```bash
698curl -X POST https://aisenseapi.com/services/v1/html_to_markdown \
699 -H "Content-Type: application/json" -d '{"data": "<h1>Hi</h1><p>A <b>bold</b> word</p>"}'
700# -> { "markdown": "# Hi\n\nA **bold** word", "title": null }
701 
702curl -X POST https://aisenseapi.com/services/v1/markdown_to_html \
703 -H "Content-Type: application/json" -d '{"data": "**Bold** <b>raw</b>"}'
704# -> { "html": "<p><strong>Bold</strong> &lt;b&gt;raw&lt;/b&gt;</p>" }
705```
706 
707**JWT - `data` takes the claims as a JSON object, or as a string containing
708JSON.** Both forms produce the same token.
709 
710```bash
711curl -X POST https://aisenseapi.com/services/v1/jwt_encode \
712 -H "Content-Type: application/json" \
713 -d '{"data": {"user": "alice"}, "secret": "my-secret-key"}'
714# -> { "jwt": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..." }
715```
716 
717`jwt_decode` returns `decoded_payload`.
718 
719**QR - the request field is `payload`, with `data` accepted as an alias.**
720 
721```bash
722curl -X POST https://aisenseapi.com/services/v1/qrcode_encode \
723 -H "Content-Type: application/json" -d '{"payload": "https://example.com"}'
724# -> { "qrcode_image": "iVBORw0KGgoAAAANSUhEUgAA...", "image_type": "png" }
725```
726 
727`qrcode_decode` takes the same `payload` field (or a file upload) and returns
728`qrcode_content`. The image is a PNG, JPEG, GIF or WebP of at most 10 MB as a
729file upload. A JSON body is at most 256 KiB, so through `payload` the image
730can be about 190 KB.
731 
732---
733 
734### Random - UUID, GUID, number, color, password
735 
736```bash
737curl https://aisenseapi.com/services/v1/uuid # { "uuid": "..." }
738curl https://aisenseapi.com/services/v1/guid # { "guid": "..." }
739curl https://aisenseapi.com/services/v1/random_color # { "random_color": "#9b6bbf" }
740curl https://aisenseapi.com/services/v1/random_number/1/100
741# -> { "random_number": 73, "range": { "from": 1, "to": 100 } }
742curl https://aisenseapi.com/services/v1/password/16
743# -> { "password": "jFehS]AKGx9wl[jp", "password_length": 16 }
744```
745 
746A single argument to `random_number` is the upper bound, with the lower bound
747fixed at 1.
748 
749---
750 
751### Time - Datetime, Timestamp, Timezones
752 
753```bash
754curl https://aisenseapi.com/services/v1/datetime # UTC
755curl https://aisenseapi.com/services/v1/datetime/+0200 # with offset
756curl https://aisenseapi.com/services/v1/datetime/europe/oslo # a zone by name, summer time included
757curl https://aisenseapi.com/services/v1/ip_datetime # the same, where your address is
758curl https://aisenseapi.com/services/v1/timestamp
759curl https://aisenseapi.com/services/v1/microtimestamp
760curl https://aisenseapi.com/services/v1/timezones
761curl https://aisenseapi.com/services/v1/swatchinternettime
762```
763 
764The offset is **four digits** with an optional sign - `+0200`, `-0530`,
765`0100` - or the same with a colon, `+02:00`. An hour-only value like `1` is not a
766valid route. A zone name such as `europe/oslo`, in any case, follows summer time, which a fixed
767offset does not. Its answer has the offset in force, the standard offset,
768whether summer time is on and when it starts and ends, and the day and week
769numbers. `/ip_datetime[/{ip}]` answers the same for the zone an address is in,
770the caller's own without one.
771 
772A client of worldtimeapi.org, which reset every connection we made on
7733 October 2026, finds its answers here: `/api/timezone/{zone}` is
774`/datetime/{zone}`, `/api/ip[/{address}]` is `/ip_datetime[/{ip}]` and
775`/api/timezone` is `/timezones`, all JSON over HTTPS. The
776[translation table](API.md#moving-from-worldtimeapi) has the details.
777 
778`/timezones` returns objects, not strings:
779`{"timezones": [{"timezone": "Europe/Oslo", "offset": "+0200"}, ...]}`.
780 
781---
782 
783### Web utilities - Ping, Health, Client IP, User Agent
784 
785```bash
786curl https://aisenseapi.com/services/v1/ping # { "ping": "pong" }
787curl https://aisenseapi.com/services/v1/health # { "status": "ok", "microtimestamp": ... }
788curl https://aisenseapi.com/services/v1/client_ip # { "ip": "203.0.113.42" }
789curl https://aisenseapi.com/services/v1/user_agent # { "user_agent": "curl/8.5.0" }
790```
791 
792---
793 
794### Crypto - Wallet generation and balance lookup
795 
796```bash
797curl https://aisenseapi.com/services/v1/solana/generate_new_wallet
798curl https://aisenseapi.com/services/v1/bitcoin/generate_new_wallet
799curl https://aisenseapi.com/services/v1/ethereum/generate_new_wallet
800 
801curl https://aisenseapi.com/services/v1/solana/balance/{address}
802curl https://aisenseapi.com/services/v1/bitcoin/balance/{address}
803curl https://aisenseapi.com/services/v1/ethereum/balance/{address}
804```
805 
806All three generators return `public_address` (Bitcoin also returns
807`private_key_wif`). Ethereum balances come back as **strings** -
808`{"wallet": "0x...", "balance_eth": "6.634527787345637061", "balance_wei": "6634527787345637061"}`
809- because Wei routinely exceeds `2^53`, the largest integer a JSON number
810survives in a JavaScript client.
811 
812> Wallet generation is for development and testing only. A key produced by a
813> public HTTP endpoint has crossed a network you do not control. Never fund one.
814 
815---
816 
817The bundled JavaScript and Python clients wrap Agent Queue with eight methods
818each, one per MCP tool; the raw HTTP examples above show the same calls.
819 
820## Quick start by language
821 
822**curl**
823```bash
824curl https://aisenseapi.com/services/v1/uuid
825```
826 
827**Python** - zero dependencies, standard library only.
828```python
829from aisense_api import AISenseAPI
830api = AISenseAPI()
831 
832print(api.get_uuid()["uuid"])
833print(api.hash_sha256("Hello")["sha256_hash"])
834print(api.ip_reverse_lookup("8.8.8.8")["country"])
835```
836 
837**JavaScript** - Node 18+ or any modern browser, native fetch.
838```javascript
839import { AISenseAPI } from './aisense-api.js'
840const api = new AISenseAPI()
841 
842console.log((await api.getUUID()).uuid)
843console.log((await api.hashSHA256('Hello')).sha256_hash)
844console.log((await api.ipReverseLookup('8.8.8.8')).country)
845```
846 
847Both clients return the parsed response, and every method's docstring names the
848exact response key. They also raise a clear error when a path does not exist,
849rather than letting the debug echo surface as a JSON parse failure. They cover
850every endpoint in API.md, which `tools/check-sdk-coverage.py` checks along with
851`openai-tools.json`. The image methods upload the file as multipart/form-data,
852and the failure simulator returns what the API sent instead of raising.
853 
854**LLM function calling (OpenAI, Gemini, Mistral, ...)**
855```python
856import json
857from openai import OpenAI
858 
859with open("openai-tools.json") as f:
860 tools = json.load(f)
861 
862client = OpenAI()
863response = client.chat.completions.create(
864 model="gpt-4o",
865 tools=tools,
866 messages=[{"role": "user", "content": "Generate a UUID and hash the word Hello with SHA256"}]
867)
868```
869 
870**Claude** - [`SKILL.md`](SKILL.md) is included. Add it to Claude's context and
871it will use these APIs as tools automatically.
872 
873---
874 
875## What's in the repo
876 
877| File | Purpose |
878|------|---------|
879| [`API.md`](API.md) | Endpoint contracts, source checks and dated production observations |
880| [`queue-openapi.json`](queue-openapi.json) | Standalone OpenAPI contract for Agent Queue |
881| [`MCP.md`](MCP.md) | Remote MCP server, tool list and client examples |
882| [`AGENT-GUIDE.md`](AGENT-GUIDE.md) | Canonical compact guide to all MCP tools |
883| [`AGENT-QUICKSTART.md`](AGENT-QUICKSTART.md) | Complete Queue example, worker and retry decisions |
884| [`server.json`](server.json) | Metadata for the official MCP Registry |
885| [`aisense_api.py`](aisense_api.py) | Python client (standard library only) |
886| [`aisense-api.js`](aisense-api.js) | JavaScript ESM client |
887| [`openai-tools.json`](openai-tools.json) | REST function-calling catalog, separate from the MCP tool list |
888| [`SKILL.md`](SKILL.md) | Claude skill file |
889| [`test.sh`](test.sh) | Asserts on response bodies and statuses; exits `1` on failure (CI-friendly) |
890| [`tools/check-text.php`](tools/check-text.php) | Checks documentation punctuation before commit |
891| [`tools/check-sdk-coverage.py`](tools/check-sdk-coverage.py) | Fails when an endpoint in API.md is missing from a client or from `openai-tools.json` |
892| [`tools/check-sdk-requests.py`](tools/check-sdk-requests.py) | Runs both clients against a local stub and checks each request for the newer endpoints |
893| [`tools/pages/`](tools/pages/) | Generators for the image tool pages and the three image guides in `web/` |
894 
895`test.sh` asserts on response bodies as well as status codes. Bodies are the
896part that matters most: a status-code-only suite passes an endpoint that
897answers 200 with the wrong response key.
898 
899---
900 
901## Endpoint summary
902 
903All paths are relative to `https://aisenseapi.com/services/v1/`
904 
905| Category | Endpoint | Method | Response key(s) |
906|----------|----------|--------|-----------------|
907| Time | `/datetime[/{offset}]` | GET | `datetime` |
908| Time | `/datetime/{zone}` | GET | `datetime`, `timezone`, `abbreviation`, `utc_offset`, `dst`, `unixtime`, `raw_offset`, `dst_offset`, `dst_from`, `dst_until`, `day_of_week`, `day_of_year`, `week_number`, `utc_datetime` |
909| Time | `/ip_datetime[/{ip}]` | GET | `ip`, then the keys of `/datetime/{zone}` |
910| Time | `/timestamp` | GET | `timestamp` |
911| Time | `/microtimestamp` | GET | `microtimestamp` |
912| Time | `/timezones[/{offset}]` | GET | `timezones` |
913| Time | `/swatchinternettime` | GET | `beat`, `date` |
914| Time | `/timestamp_convert` | POST | `input`, `detected`, `timestamp`, `datetime`, `rfc2822`, `utc_datetime` |
915| Random | `/random_number[/{from}[/{to}]]` | GET | `random_number`, `range` |
916| Random | `/random_color` | GET | `random_color` |
917| Random | `/uuid` | GET | `uuid` |
918| Random | `/guid` | GET | `guid` |
919| Random | `/password[/{length}]` | GET | `password`, `password_length` |
920| Transform | `/base64_encode` | POST | `base64_encoded_data` |
921| Transform | `/base64_decode` | POST | raw bytes, or `type` + `decoded_data` |
922| Transform | `/base58_encode` | POST | `base58_encoded_data` |
923| Transform | `/base58_decode` | POST | raw bytes, or `type` + `decoded_data` |
924| Transform | `/base32_encode` | POST | `base32_encoded_data` |
925| Transform | `/base32_decode` | POST | raw bytes, or `type` + `decoded_data` |
926| Transform | `/hex_encode` | POST | `hex_encoded_data` |
927| Transform | `/hex_decode` | POST | raw bytes, or `type` + `decoded_data` |
928| Transform | `/base64url_encode` | POST | `base64url_encoded_data` |
929| Transform | `/base64url_decode` | POST | raw bytes, or `type` + `decoded_data` |
930| Transform | `/url_encode` | POST | `url_encoded_data` |
931| Transform | `/url_decode` | POST | `url_decoded_data` |
932| Transform | `/html_encode` | POST | `html_encoded_data` |
933| Transform | `/html_decode` | POST | `html_decoded_data` |
934| Transform | `/html_to_markdown` | POST | `markdown`, `title` |
935| Transform | `/markdown_to_html` | POST | `html` |
936| Transform | `/slugify` | POST | `slug` |
937| Transform | `/jwt_encode` | POST | `jwt` |
938| Transform | `/jwt_decode` | POST | `decoded_payload` |
939| Transform | `/qrcode_encode` | POST | `qrcode_image`, `image_type` |
940| Transform | `/qrcode_decode` | POST | `qrcode_content` |
941| Hash | `/md5_hash` | POST | `md5_hash` |
942| Hash | `/sha1_hash` | POST | `sha1_hash` |
943| Hash | `/sha256_hash` | POST | `sha256_hash` |
944| Hash | `/sha512_hash` | POST | `sha512_hash` |
945| Hash | `/crc32_checksum` | POST | `crc32_checksum` |
946| Hash | `/whirlpool_hash` | POST | `whirlpool_hash` |
947| Hash | `/sha3_256_hash` | POST | `sha3_256_hash` |
948| Hash | `/sha3_512_hash` | POST | `sha3_512_hash` |
949| Hash | `/blake2b_hash` | POST | `blake2b_hash` |
950| Hash | `/blake3_hash` | POST | `blake3_hash` |
951| Hash | `/argon2id_hash` | POST | `argon2id_hash` |
952| Hash | `/bcrypt_hash` | POST | `bcrypt_hash` |
953| Hash | `/scrypt_hash` | POST | `scrypt_hash` |
954| Hash | `/hash_verify` | POST | `match`, `algorithm`, `computed` |
955| Hash | `/password_verify` | POST | `match`, `algorithm`, `params` |
956| Web | `/ping` | GET | `ping` |
957| Web | `/health` | GET | `status`, `microtimestamp` |
958| Web | `/client_ip` | GET | `ip` |
959| Web | `/html2pdf` | POST | `storage_id`, `storage_url`, `sha256_hash`, `bytes`, `expire_timestamp` |
960| Web | `/user_agent` | GET | `user_agent` |
961| Web | `/ip_reverse_lookup/{ip}` | GET | `ip`, `country`, `city`, `location`, `place`, `timezone` |
962| Web | `/domain_ip_lookup/{domain}` | GET | `domain`, `ip` |
963| Web | `/email_validate` | POST | `email`, `valid_syntax`, `domain`, `has_mx`, `mx_hosts` |
964| Web | `/storage` | POST / GET | `storage_id`, `storage_url`, `sha256_hash`, `bytes`, `expire_timestamp` |
965| Web | `/storage/{id}/sha256/{hex}` | GET | the stored body, or `412` if it does not hash to `{hex}` |
966| Web | `/url_shortener/{url}` | GET | `short_url`, `expire_timestamp` |
967| Web | `/webhook_capture` | POST / GET | `capture_id`, `update_url`, `read_url`, `wait_url` |
968| Web | `/webhook_action` | POST / GET | `action_id`, form URL or URLs, `result_url`, `wait_url` |
969| Web | `/webhook_schedule` | POST / GET / DELETE | one-shot or recurring status, counts and result |
970| Web | `/agent_wake` | POST / GET / DELETE | `taskId`, `status`, `result`, wait support |
971| Web | `/inbox` | POST | `inbox_id`, `slug`, `address`, `read_url`, `wait_url`, `expire_timestamp` |
972| Web | `/inbox/{inbox_id}` | GET | `slug`, `address`, `received`, `truncated`, `messages`, timing fields |
973| Web | `/heartbeat` | POST | `heartbeat_id`, `status`, timing fields, `ping_url`, `status_url` |
974| Web | `/heartbeat/{id}` | GET | status, timing fields, counters, optional `delivery` |
975| Web | `/heartbeat/{id}/ping` | POST | updated timing fields and counters |
976| Web | `/lease/namespace` | POST | `namespace`, `entropy_bits` |
977| Web | `/lease`, `/lease/acquire` | POST | status, owner and fencing tokens, expiry fields, optional result |
978| Web | `/lease/renew`, `/lease/release`, `/lease/complete` | POST | status, fencing token, expiry fields, optional result |
979| Web | `/queue` | POST | `queue_id`, role tokens, counts and fixed expiry |
980| Web | `/queue/{id}` | GET | `queue_id`, counts and timing |
981| Web | `/queue/{id}/jobs`, `/queue/{id}/claim`, job operations | POST / GET | `job`, with a receipt only on claim |
982| Web | `/validate/{type}` | POST | `type`, `valid`, per-check fields |
983| Crypto | `/solana/generate_new_wallet` | GET | `private_key`, `private_key_base58`, `public_address` |
984| Crypto | `/solana/balance/{address}` | GET | `wallet`, `balance_sol`, `balance_lamports` |
985| Crypto | `/bitcoin/generate_new_wallet` | GET | `private_key`, `private_key_wif`, `public_address` |
986| Crypto | `/bitcoin/balance/{address}` | GET | `wallet`, `final_balance_btc`, `final_balance_sats` |
987| Crypto | `/ethereum/generate_new_wallet` | GET | `private_key`, `public_address` |
988| Crypto | `/ethereum/balance/{address}` | GET | `wallet`, `balance_eth`, `balance_wei` |
989 
990---
991 
992## Notes
993 
994- Input formats vary by endpoint. Utility transforms accept several formats, while Queue and other structured workflow endpoints require JSON
995- Storage, URL Shortener, Webhook Capture, Webhook Action, Webhook Schedule, Agent Wake, Agent Inbox, Heartbeat, Lease and Queue have a 24-hour active lifetime or absolute lifecycle
996- Queue jobs, including completed and failed jobs, share the fixed queue expiry. Activity never extends it
997- Webhook Schedule keeps its final result for up to another 24 hours
998- Heartbeat terminal state can remain readable for another 24 hours after it fires, misses or expires
999- `Access-Control-Allow-Origin: *` is set on every response, so these are callable from a browser
1000- Rate limit: 5000 requests per IP per day
1001 
1002---
1003 
1004**AI SENSE AS** | [aisenseapi.com](https://aisenseapi.com)
1005Postboks 1202 Vika, 0110 Oslo, Norway
1006 
1007MIT License
1008 

Discussion

Alternatives

API and interface designGuides stable API and interface design. Use when designing APIs, module boundaries, or any public interface. Use when creating REST or GraphQL endpoints, defining type contracts between modules, or establishing boundaries between frontend and backend.Coding · MITContext7Pulls up-to-date, version-specific library docs and code examples into the prompt so the AI stops inventing old APIs.Coding · MITContext7 Documentation LookupFetch up-to-date documentation and code examples for any library, framework, SDK, CLI tool, or cloud service. Use whenever the user asks about a specific library — even well-known ones like React, Next.js, Prisma, Express, Tailwind, Django, or Spring Boot — because training data may not reflect recent API changes or version updates. Always use for: API syntax questions, configuration options, version migration issues, "how do I" questions mentioning a library name, debugging that involves library-specific behavior, setup instructions, and CLI tool usage. Use even when you think you know the answer. Do not rely on training data for API details, signatures, or configuration options — they are frequently out of date. Prefer this over web search for library documentation.Coding · MITAdaptyv Bio Foundry APIHow to use the Adaptyv Bio Foundry API and Python SDK for protein experiment design, submission, and results retrieval. Use this skill whenever the user mentions Adaptyv, Foundry API, protein binding assays, protein screening experiments, BLI/SPR assays, thermostability assays, or wants to submit protein sequences for experimental characterization. Also trigger when code imports `adaptyv`, `adaptyv_sdk`, or `FoundryClient`, or references `foundry-api-public.adaptyvbio.com`.Science · MIT