Haptica API

Physics perception from video. Send a clip, get structured physics signals back.

curl
curl https://api.haptica.io/v1/analyze \
  -H "Authorization: Bearer hp_live_..." \
  -F "video=@clip.mp4"
Response
{
  "video_id": "a1b2c3d4e5...",
  "provenance": {
    "model_version": "v3.1",
    "encoder": "haptica-physics",
    "checkpoint": "v3.1-prod"
  },
  "input": {
    "fps_source": 30,
    "duration_ms": 4800,
    "window_frames": 16
  },
  "availability": {
    "force_index": "active",
    "contact": "active",
    "impact": "active",
    "rotation": "active",
    "bind_jam": { "status": "null", "reason": "no_context" },
    "human_risk": { "status": "null", "reason": "no_context" }
  },
  "windows": [{
    "index": 0,
    "timing": { "start_ms": 0, "end_ms": 1600, "canonical_fps": 10.0 },
    "physics": {
      "force_index": 0.723,
      "contact": { "detected": true, "confidence": 0.94 },
      "impact": { "detected": false, "confidence": 0.12 },
      "rotation": { "detected": true, "confidence": 0.87 },
      "bind_jam": null,
      "human_risk": null
    },
    "evidence": {
      "dominant_primitive": "contact",
      "dominant_candidate": "contact",
      "activity_regime": "clear",
      "dominant_margin": 0.07,
      "stability_score": 0.72,
      "tokens": { "contact": 0.94, "impact": 0.12, "rotation": 0.87 }
    }
  }]
}
Get your API key

Authentication

All requests require a Bearer token in the Authorization header.

Header format
Authorization: Bearer hp_live_abc123def456...

API keys are prefixed with hp_live_. Keys are shown once at creation and stored as SHA-256 hashes. Treat them like passwords. Use POST /v1/demo/analyze (no auth) to test with pre-computed sample output.

POST /v1/analyze

Analyze a video clip for physical interactions. Returns per-window physics signals.

Content type: multipart/form-data. Max video size: 100 MB. Supported formats: mp4, webm, mov.

Parameters

ParameterTypeDescription
videofileVideo file upload (mp4, webm, mov, avi). Max 100 MB, max 60s.
video_urlstringHTTPS URL pointing to a video file. Provide either video or video_url.
contextstringTask context JSON. Activates configured channels (bind_jam, human_risk).

Full example

Python
import requests

resp = requests.post(
    "https://api.haptica.io/v1/analyze",
    headers={"Authorization": "Bearer hp_live_..."},
    files={"video": open("clip.mp4", "rb")},
)
result = resp.json()

for w in result["windows"]:
    t = w["timing"]
    p = w["physics"]
    print(f"[{t['start_ms']}–{t['end_ms']}ms] "
          f"force={p['force_index']:.2f} "
          f"contact={p['contact']['detected']} "
          f"impact={p['impact']['detected']}")

GET /v1/model/info

Returns current model version, supported formats, and available channels.

Response
{
  "model_version": "v3.1",
  "encoder": "haptica-physics",
  "checkpoint": "v3.1-prod",
  "signals": {
    "core": ["force_index", "contact", "impact", "rotation"],
    "configured": ["bind_jam", "human_risk"]
  },
  "auroc": { "contact": 0.78, "impact": 0.72, "rotation": 0.71 },
  "window_frames": 16,
  "canonical_fps": 10.0,
  "supported_formats": ["mp4", "mov", "avi", "webm"]
}

POST /v1/stream

Coming soon

Real-time streaming analysis. Send video frames via WebSocket, receive physics signals as they are computed. Available on Scale and Enterprise tiers.

POST /v1/context

Coming soon

Create or update a context profile. Context profiles activate configured channels (bind_jam, human_risk) and improve prediction accuracy for specific task domains.

Response schema

Windowing

The model resamples every video to a 10 Hz canonical grid regardless of source frame rate. Windows are 16 frames (1600 ms) with a stride of 8 frames (800 ms), giving 50% overlap between consecutive windows.

This means window 0 covers 0–1600 ms, window 1 covers 800–2400 ms, window 2 covers 1600–3200 ms, and so on. The overlap is part of the contract — if you depend on it for temporal smoothing or interpolation, it is guaranteed to remain stable.

Window fields

Every Window object in the response contains these fields.

ParameterTypeDescription
indexintWindow index (0-based)
timing.start_msintWindow start time in milliseconds
timing.end_msintWindow end time in milliseconds
timing.canonical_fpsfloatCanonical frame rate (10 Hz). Windows are 1600 ms with 800 ms stride (50% overlap).
physics.force_indexfloat [0, 1]Continuous force intensity. Monotonic with measured Newtons.
physics.contact{ detected, confidence }Physical contact detection + confidence [0, 1]
physics.impact{ detected, confidence }Sudden force onset: collision, strike, drop
physics.rotation{ detected, confidence }Rotation under load: screw, turn, twist
physics.bind_jamobject | nullMechanical binding/jamming. Null without context.
physics.human_riskfloat | nullContext-aware safety risk [0, 1]. Null without context.
evidence.dominant_primitivestring | nullHighest-confidence evidence channel. Null when activity_regime is not "clear".
evidence.dominant_candidatestringHighest-scoring channel (always present, for debugging)
evidence.activity_regimestring"clear" | "low_activity" | "ambiguous" — confidence regime classification
evidence.dominant_marginfloatGap between top two evidence channels [0, 1]
evidence.stability_scorefloatPrediction confidence/decisiveness [0, 1]
evidence.tokensobject{ contact, impact, rotation } -- per-channel evidence [0, 1]

Null semantics

Core signals (force_index, contact, impact, rotation, evidence) are always present and never null.

Configured signals (bind_jam, human_risk) return null unless activated by context. Check the top-level availability map for reason codes: no_context, unsupported_domain, calibration_required.

Null means unsupported for this request, not missing data. Do not retry on null.

Errors & rate limits

Error codes

CodeMeaningDetails
400Bad requestInvalid video format, missing required fields, unsupported content type, or invalid URL
401UnauthorizedMissing or invalid API key, or key has been revoked
413Payload too largeVideo exceeds 100 MB size limit or 60s duration limit (video_too_long)
429Rate limit exceededCheck Retry-After header. Back off exponentially.
500Internal errorRetry with exponential backoff. If persistent, contact support.

Rate limits per tier

TierRateQuota
Standard3 concurrent60s max duration
Trusted3 concurrent5 min max duration
EnterpriseCustomCustom

When rate-limited (429), the response includes a Retry-After header in seconds. Use exponential backoff with jitter.

Recipes

Robot safety monitoring

Detect dangerous force events and trigger safe stops.

Python
import haptica

client = haptica.Client("hp_live_...")
result = client.analyze(video="robot_arm.mp4")

for w in result.windows:
    p = w.physics
    if p.force_index > 0.7 and p.contact.detected:
        print(f"[{w.timing.start_ms}ms] HIGH FORCE CONTACT -- force={p.force_index:.2f}")
    if p.human_risk and p.human_risk > 0.8:
        print(f"[{w.timing.start_ms}ms] SAFETY ALERT -- risk={p.human_risk:.2f}")
        robot.trigger_safe_stop()

Warehouse anomaly detection

Flag unusual force patterns relative to baseline.

Python
# Flag anomalous force patterns in warehouse footage
result = client.analyze(video=feed_url)

baseline = sum(w.physics.force_index for w in result.windows) / len(result.windows)
anomalies = [w for w in result.windows if w.physics.force_index > baseline * 2.5]

for w in anomalies:
    alert(f"Anomaly at {w.timing.start_ms}ms: force {w.physics.force_index:.2f} (baseline {baseline:.2f})")

Evidence-based thresholding

Use per-channel evidence scores for fine-grained decision making.

Python
# Use evidence scores for fine-grained decision making
result = client.analyze(video="assembly.mp4")

for w in result.windows:
    tokens = w.evidence.tokens
    # High contact evidence but low impact = sustained press (normal)
    if tokens["contact"] > 0.8 and tokens["impact"] < 0.2:
        log("Sustained contact -- normal assembly pressure")

    # High impact evidence = unexpected collision
    if tokens["impact"] > 0.7:
        log(f"Impact at {w.timing.start_ms}ms (evidence: {tokens['impact']:.2f})")
        queue_review(w)

Agent integration

Drop this tool schema into your agent framework (OpenAI function-calling format).

Tool schema JSON
{
  "type": "function",
  "function": {
    "name": "haptica_analyze",
    "description": "Analyze video for physical interactions. Returns force, contact, impact, rotation, and evidence scores per 1.6s window.",
    "parameters": {
      "type": "object",
      "properties": {
        "video": {
          "type": "string",
          "description": "URL or base64-encoded video clip"
        },
        "context": {
          "type": "string",
          "description": "Task context string (e.g. 'manufacturing_assembly')"
        }
      },
      "required": ["video"]
    }
  }
}

Machine-readable resources

For automated tooling and LLM integration.

haptica.io