API Overview

Biruni resolves natural-language temporal expressions to precise, timezone-aware ISO 8601 datetimes. It is designed for agent workflows: send the extracted temporal phrase, an anchor date, and an IANA timezone.

Base URL: https://biruni.dev
Auth: Authorization: Bearer BIRUNI_API_KEY
Endpoint: POST /v1/resolve

Quickstart

Create an API key in the dashboard, then send one POST request to resolve a temporal phrase.

bash
curl -X POST https://biruni.dev/v1/resolve \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "expression": "next Monday at 9am",
    "reference_date": "2026-04-02",
    "timezone": "America/New_York"
  }'

POST /v1/resolve

Resolve a temporal phrase into a timezone-aware ISO 8601 datetime. The API is deterministic, ambiguity-aware, and intended to be called by agents during execution.

Request format

Field Type Description
expression string required Send only the temporal phrase, not surrounding prose.
Good: next Monday at 3pm
Bad: Can we meet next Monday at 3pm in the office?
reference_date string required Anchor date in YYYY-MM-DD format. Usually today's local date. For chained resolution, use the previously resolved date.
timezone string required IANA timezone identifier. Use full IANA names, not abbreviations. Example: America/New_York, not EST.
locale string optional BCP 47 locale code. Default: en-US. Only English locales supported.
options object optional Supports prefer_future (bool, default true) and business_calendar (string, default us_federal) for business day calculations.

Example request body

JSON
{
  "expression": "next Monday at 9am",
  "reference_date": "2026-04-02",
  "timezone": "America/New_York",
  "locale": "en-US",
  "options": {
    "prefer_future": true,
    "business_calendar": "us_federal"
  }
}

Response format

Field Type Description
status string "resolved" use resolved directly.
"ambiguous" inspect alternatives before acting.
"unresolvable" ask the user to rephrase.
resolved string | null ISO 8601 datetime with UTC offset. Null if unresolvable.
confidence string | null "high", "medium", or "low" confidence in the chosen interpretation.
interpretation string Human-readable explanation of how the phrase was interpreted. Useful for audit trails and agent reasoning logs.
ambiguities string[] List of ambiguity notes, if any.
alternatives object[] Alternative interpretations when status is "ambiguous". Each item includes resolved and interpretation.
metadata object Contains expression_type, timezone, calendar_used, holidays_applied, and processing_time_ms.

Example response

JSON — 200 OK
{
  "status": "resolved",
  "resolved": "2026-04-06T09:00:00-04:00",
  "confidence": "high",
  "interpretation": "Next Monday from April 2 is April 6. 9:00 AM in America/New_York.",
  "ambiguities": [],
  "alternatives": [],
  "metadata": {
    "expression_type": "weekday",
    "timezone": "America/New_York",
    "calendar_used": "us_federal",
    "holidays_applied": [],
    "processing_time_ms": 11.2
  }
}

Error codes

All errors return a consistent JSON body:

{ "error": { "code": "ERROR_CODE", "message": "..." } }
Code HTTP Description
INVALID_REQUEST 400 Malformed or missing required fields.
UNAUTHORIZED 401 Missing or invalid API key.
UNRESOLVABLE 422 Expression could not be parsed. Ask the user to rephrase.
RATE_LIMITED 429 Per-minute or monthly quota exceeded. Check the Retry-After header.
INTERNAL_ERROR 500 Unexpected server failure.
Rate limits: Free beta includes 10 requests per minute and 1,000 requests per month. On 429 RATE_LIMITED, wait for the Retry-After header before retrying.

For AI Agents

Use Biruni whenever your agent needs an exact date or time before taking an action.

Tool definition

Copy the MCP tool definition below into your agent framework. If your framework uses a different wrapper key, rename inputSchema to match (e.g. parameters for OpenAI, input_schema for Anthropic).

MCP tool schema
{
  "name": "biruni_resolve",
  "description": "Resolve a natural-language temporal phrase to a timezone-aware ISO 8601 datetime. Send only the temporal phrase, not surrounding prose. If status is ambiguous, inspect alternatives before acting.",
  "inputSchema": {
    "type": "object",
    "properties": {
      "expression": {
        "type": "string",
        "description": "The temporal phrase to resolve, e.g. 'next Tuesday at 10am' or 'in 5 business days'. Extract only the time expression from the user's message."
      },
      "reference_date": {
        "type": "string",
        "description": "Anchor date in YYYY-MM-DD format. Usually today's local date. For chained resolution, use the previously resolved date."
      },
      "timezone": {
        "type": "string",
        "description": "IANA timezone identifier, e.g. 'America/New_York' or 'Europe/London'. Do not use abbreviations like EST or PST."
      },
      "options": {
        "type": "object",
        "description": "Optional resolution overrides.",
        "properties": {
          "prefer_future": {
            "type": "boolean",
            "description": "Bias ambiguous expressions toward the next upcoming occurrence."
          },
          "business_calendar": {
            "type": "string",
            "description": "Business calendar for business day arithmetic. Use 'us_federal' for the MVP."
          }
        }
      }
    },
    "required": ["expression", "reference_date", "timezone"]
  }
}

Integration guide

Register the tool definition above with your agent framework, then paste the rules below into your agent's system prompt or instruction layer so it knows when and how to call the tool.

Usage rules

Copy into your agent's instructions:

Agent instructions
When the user mentions a date, time, or deadline, call biruni_resolve instead of
doing date math yourself.

1. Extract only the temporal phrase from the user's message.
   Good: "next Monday at 3pm"  Bad: "Can we meet next Monday at 3pm?"
2. Map informal timezone names to IANA identifiers ("Eastern" → America/New_York).
3. Set reference_date to today's local date (YYYY-MM-DD), or the output of a
   previous call for chained resolution.
4. If status is "resolved", use the resolved datetime directly.
5. If status is "ambiguous", present the alternatives to the user before acting.
6. If status is "unresolvable", ask the user to rephrase.
7. Never fall back to LLM date arithmetic — retry with a cleaner expression instead.
Authentication: Each request requires an Authorization: Bearer <BIRUNI_API_KEY> header. Store the key as an environment variable and inject it when your agent makes the HTTP call to POST https://biruni.dev/v1/resolve.

Common mistakes

Mistake What happens Fix
Sending the full user message as expression Parser fails or returns unresolvable Extract only the temporal phrase first
Using timezone abbreviations (EST, PST) Rejected or mapped incorrectly Use IANA names: America/New_York
Defaulting to UTC when user implies local time Result is correct but in the wrong timezone Infer and map the user's timezone
Ignoring status: "ambiguous" Silently uses wrong interpretation Check alternatives and present options
Not checking metadata.holidays_applied for business-day results Deadlines can look surprising around federal holidays Inspect calendar_used and holidays_applied before overriding the output
Falling back to LLM date math when Biruni returns an error Hallucinated dates, wrong holidays Retry with a cleaner expression or ask user to rephrase

Expression types

Common patterns Biruni can resolve. Use these as representative examples, not exhaustive limits.

Expression Type Notes
tomorrow Relative day Resolves to the next calendar day from reference_date.
in 10 business days Business day Skips weekends and holidays per the selected business calendar. Default: us_federal.
March 30, 2026 Absolute date Resolves directly in the supplied timezone.
next Friday at 3pm Weekday + time Finds the next matching weekday and attaches the time.
first Monday of April Ordinal pattern Uses the year implied by reference_date.
next Friday on a Friday Ambiguous Returns status: "ambiguous" with alternatives.

Ambiguous response example

JSON — ambiguous response
{
  "status": "ambiguous",
  "resolved": "2026-04-10T00:00:00-04:00",
  "confidence": "medium",
  "interpretation": "'next Friday' on a Friday — interpreted as next week's Friday.",
  "ambiguities": ["'next Friday' on a Friday is ambiguous."],
  "alternatives": [
    {
      "resolved": "2026-04-03T00:00:00-04:00",
      "interpretation": "Today (this Friday)"
    }
  ]
}