thinair-co Learning API

The Learning API from thinair-co — 2 operation(s) for learning.

Operations 2

POST /v1/feedback Submit map feedback into the learning loop #
POST /geo/feedback Submit feedback or a map correction (learning) #

Specifications

Schemas & Data

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/thinair-co:thinair-co-learning-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

thinair-co-learning-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: ThinAir Geo Learning API
  version: 1.0.0
  description: '## Overview


    Geocoding, autocomplete, structured search, place IDs, intersections, routing, distance matrix, isochrones, map matching, traffic, weather, and POI search — one API. REST and MCP consume the same ThinAir Geo service layer; this spec describes the REST surface.


    ## Base URL & authentication


    All endpoints live under `https://geo.thinair.co`. Authenticate with a bearer API key:


    ```bash

    curl "https://geo.thinair.co/v1/geocode?text=Pike Place Market Seattle" \

    -H "Authorization: Bearer ta_geo_…"

    ```


    ## Observability


    Every REST response carries a correlation pair (`X-Request-Id` / `X-Trace-Id`), a cache status (`X-Cache: HIT | HIT-EDGE | STALE | MISS | BYPASS`), and a per-stage timing family (`X-Auth-Ms`, `X-Quota-Ms`, `X-Upstream-Ms`, `X-Worker-Ms`, `X-Edge-Ms`, `X-Total-Ms`) — see components.headers for the full surface. Edge-cached lookups answer in single-digit milliseconds at the edge (verifiable via `X-Edge-Ms`); cold geocoding runs through the regional engine.


    ## Quota


    The daily-quota debit is write-behind on all API-key plans, so `X-Quota-Used` / `X-Quota-Remaining` are eventually consistent (typically within ~30 seconds); `GET /v1/quota` is the authoritative synchronous count.


    ## Enterprise access


    `https://geo.thinair.co` is the canonical public API and MCP surface. Azure API Management (APIM) is available as an enterprise access layer — private deployments, custom quota/SLA, VNET/private-link connectivity, subscription keys, and customer-side governance. APIM is an enterprise access layer. It does not own product behavior. All product behavior lives in the shared ThinAir Geo service layer consumed by REST, MCP, and APIM. APIM calls the same service layer (no separate business logic), preserves request/trace ids and ThinAir response shapes, and may add enterprise auth, quota, IP policy, logging, and private networking. Public documentation keeps `https://geo.thinair.co` as the canonical base URL; enterprise base URLs are issued per customer.'
servers:
- url: https://geo.thinair.co
security:
- bearerAuth: []
tags:
- name: Learning
paths:
  /v1/feedback:
    post:
      summary: Submit map feedback into the learning loop
      description: 'Learning surface — report a wrong/right/moved verdict on a geocoding answer. Seeds an evidence bundle and a pending entry in the validation-gated promotion queue; a human adjudicates before anything can change an answer. Authenticated; never metered (X-Quota-Cost: 0); limited to 20 submissions per day per key. `note` is retained for human review only and never reaches analytics.'
      tags:
      - Learning
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/FeedbackV1Request'
            example:
              query: Santo Domingo & San Martin, Santiago
              verdict: wrong
              suggested:
                lat: -33.4335
                lon: -70.6535
              note: Resolved to the wrong corner; should be one block west.
      responses:
        '202':
          description: Feedback recorded into the promotion queue.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FeedbackV1Response'
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
            X-Trace-Id:
              $ref: '#/components/headers/X-Trace-Id'
            X-Cache:
              $ref: '#/components/headers/X-Cache'
            X-Cache-Hit:
              $ref: '#/components/headers/X-Cache-Hit'
            X-Cache-Tier:
              $ref: '#/components/headers/X-Cache-Tier'
            X-Edge-Ms:
              $ref: '#/components/headers/X-Edge-Ms'
            X-Upstream-Ms:
              $ref: '#/components/headers/X-Upstream-Ms'
            X-Worker-Ms:
              $ref: '#/components/headers/X-Worker-Ms'
            X-Total-Ms:
              $ref: '#/components/headers/X-Total-Ms'
            X-Auth-Ms:
              $ref: '#/components/headers/X-Auth-Ms'
            X-Quota-Ms:
              $ref: '#/components/headers/X-Quota-Ms'
            X-Quota-Cost:
              $ref: '#/components/headers/X-Quota-Cost'
            X-Quota-Used:
              $ref: '#/components/headers/X-Quota-Used'
            X-Quota-Remaining:
              $ref: '#/components/headers/X-Quota-Remaining'
            X-Quota-Reset:
              $ref: '#/components/headers/X-Quota-Reset'
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-Session-Id:
              $ref: '#/components/headers/X-Session-Id'
            X-Edge-Location:
              $ref: '#/components/headers/X-Edge-Location'
            X-Data-Age-S:
              $ref: '#/components/headers/X-Data-Age-S'
        '400':
          description: Invalid body (bad verdict, note > 280 chars, neither query nor place_id, …).
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
        '429':
          description: Feedback daily limit (20/day per key) or plan quota exhausted.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
      operationId: postV1Feedback
      x-operation-id-source: derived
  /geo/feedback:
    post:
      summary: Submit feedback or a map correction (learning)
      description: 'Learning surface — submit a verdict or a correction on a prior result. This is NOT a normal geocoding query: it feeds ThinAir Geo''s validation-gated promotion/learning pipeline. Authenticated (401 for anonymous — unattributed feedback is unusable), and never metered (no quota debit). `correction.note` is retained for human review and is never emitted to analytics.'
      tags:
      - Learning
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/FeedbackRequest'
      responses:
        '202':
          description: Feedback recorded (200 with deduped:true on a repeat).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FeedbackResponse'
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
            X-Trace-Id:
              $ref: '#/components/headers/X-Trace-Id'
            X-Cache:
              $ref: '#/components/headers/X-Cache'
            X-Cache-Hit:
              $ref: '#/components/headers/X-Cache-Hit'
            X-Cache-Tier:
              $ref: '#/components/headers/X-Cache-Tier'
            X-Edge-Ms:
              $ref: '#/components/headers/X-Edge-Ms'
            X-Upstream-Ms:
              $ref: '#/components/headers/X-Upstream-Ms'
            X-Worker-Ms:
              $ref: '#/components/headers/X-Worker-Ms'
            X-Total-Ms:
              $ref: '#/components/headers/X-Total-Ms'
            X-Auth-Ms:
              $ref: '#/components/headers/X-Auth-Ms'
            X-Quota-Ms:
              $ref: '#/components/headers/X-Quota-Ms'
            X-Quota-Cost:
              $ref: '#/components/headers/X-Quota-Cost'
            X-Quota-Used:
              $ref: '#/components/headers/X-Quota-Used'
            X-Quota-Remaining:
              $ref: '#/components/headers/X-Quota-Remaining'
            X-Quota-Reset:
              $ref: '#/components/headers/X-Quota-Reset'
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-Session-Id:
              $ref: '#/components/headers/X-Session-Id'
            X-Edge-Location:
              $ref: '#/components/headers/X-Edge-Location'
            X-Data-Age-S:
              $ref: '#/components/headers/X-Data-Age-S'
        '400':
          description: Invalid feedback.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
        '401':
          description: Authentication required — anonymous feedback is not accepted.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
      operationId: postGeoFeedback
      x-operation-id-source: derived
components:
  headers:
    X-Quota-Cost:
      description: Capability units this call debited.
      schema:
        type: string
    X-Worker-Ms:
      description: 'Worker-side overhead: total minus upstream (ms). Decomposes into X-Auth-Ms + X-Quota-Ms + unattributed residue (serialization, telemetry, routing).'
      schema:
        type: string
    X-Edge-Location:
      description: Edge location (IATA airport code) that served the request. Omitted when unavailable.
      schema:
        type: string
    X-RateLimit-Limit:
      description: Plan cap proxy (-1 = unlimited).
      schema:
        type: string
    X-Session-Id:
      description: Session correlation id grouping requests issued under one client session.
      schema:
        type: string
    X-Quota-Reset:
      description: ISO-8601 instant the daily counter rolls over.
      schema:
        type: string
    X-Cache-Hit:
      description: Legacy boolean cache signal (true|false). Prefer X-Cache.
      schema:
        type: string
    X-Trace-Id:
      description: Alias of X-Request-Id for tracing tooling that auto-detects the Trace-Id spelling.
      schema:
        type: string
    X-Data-Age-S:
      description: Age in seconds of the underlying data snapshot backing the response (e.g. a traffic observation). Only present on endpoints where data age is meaningful.
      schema:
        type: string
    X-Total-Ms:
      description: Equal to X-Edge-Ms; kept distinct per spec §6.
      schema:
        type: string
    X-Quota-Remaining:
      description: Daily limit minus used (-1 = unlimited). Eventually consistent (see X-Quota-Used); GET /v1/quota is authoritative.
      schema:
        type: string
    X-Quota-Ms:
      description: Synchronous quota work on the request path (ms). All API-key plans use a write-behind debit, so this reflects only the fast synchronous exhausted-flag check. The demo (Try-It) identity keeps the synchronous pre-flight peek + post-success debit (QuotaCounter round-trips).
      schema:
        type: string
    X-Edge-Ms:
      description: Total wall time the worker held the request (ms).
      schema:
        type: string
    X-Quota-Used:
      description: 'Units consumed in the current daily period. The debit is write-behind on all API-key plans: this value is eventually consistent (typically within ~30 seconds); GET /v1/quota is the authoritative synchronous count.'
      schema:
        type: string
    X-Auth-Ms:
      description: API-key validation time (ms). Present only on the ta_* api-key and demo-token paths; OAuth-JWT validation happens inside the auth library and is not measurable.
      schema:
        type: string
    X-RateLimit-Remaining:
      description: Remaining headroom (-1 = unlimited).
      schema:
        type: string
    X-Request-Id:
      description: Edge-generated request correlation id (req_*).
      schema:
        type: string
    X-Cache:
      description: 'Cache status: HIT (served from the cache without an upstream call), HIT-EDGE (served from the edge tier, no durable-store round-trip), STALE (served past its soft TTL while a background refresh runs), MISS (cacheable, went upstream), BYPASS (endpoint has no cache).'
      schema:
        type: string
        enum:
        - HIT
        - HIT-EDGE
        - STALE
        - MISS
        - BYPASS
    X-Cache-Tier:
      description: 'Serving cache tier, when reported: edge (edge tier), l0 (in-region cache), or kv (durable edge store).'
      schema:
        type: string
        enum:
        - edge
        - l0
        - kv
    X-Upstream-Ms:
      description: Wall time spent in engine round-trips (ms). Omitted on cache hits (no upstream call).
      schema:
        type: string
  schemas:
    FeedbackV1Response:
      type: object
      properties:
        bundle_id:
          type: string
          example: eb_01J0000000000000000000000A
        queue_id:
          type: string
          example: pq_01J0000000000000000000000B
          description: Promotion-queue reference. Absent when the queue write soft-failed (see warnings) — never a dangling id.
        class_key:
          type: string
          enum:
          - feedback_contradiction
          - feedback_confirmation
        status:
          type: string
          enum:
          - recorded
        warnings:
          type: array
          items:
            type: string
          description: Soft-failure notices (e.g. evidence store unavailable). The feedback is still accepted.
      required:
      - bundle_id
      - class_key
      - status
    ProblemDetails:
      type: object
      properties:
        type:
          type: string
          format: uri
        title:
          type: string
        status:
          type: integer
        detail:
          type: string
        code:
          type: string
          description: Stable internal_code; see /docs/errors
        request_id:
          type: string
        instance:
          type: string
        retry_after_ms:
          type: integer
        upgrade_url:
          type: string
          description: Present on 429 (quota exceeded) and on 401 TRIAL_EXPIRED. Preselects the recommended plan and, when the caller's tenant is known, carries a short-lived token that upgrades the API key you are already using — no key swap and no config change after payment.
        suggested_upgrade:
          type:
          - string
          - 'null'
          description: Recommended next plan, or null on the top self-serve tier. 429 only.
        upgrade_cta:
          type: string
          description: One-line upgrade prompt. 429 only.
        upgrade_plans:
          type: array
          items:
            $ref: '#/components/schemas/UpgradePlan'
          description: Full self-serve plan menu. 429 only.
        next_step:
          type: string
          description: Prose instruction naming the same URL as upgrade_url. 429 only.
        usage:
          type: object
          properties:
            plan:
              type: string
            used:
              type: number
            limit:
              type: number
            period:
              type: string
            reset:
              type: string
              description: ISO 8601 instant the counter rolls over.
          required:
          - plan
          description: Where the cap stands. 429 only; counters are omitted when the denial has none.
        expired_at:
          type: string
          description: ISO 8601 instant the key stopped authenticating. TRIAL_EXPIRED only.
        plan:
          type: string
          description: Plan the expired key carried. TRIAL_EXPIRED only.
        quota:
          type: object
          properties:
            daily:
              type: number
            period:
              type: string
          required:
          - daily
          - period
          description: Daily allowance the expired key had; -1 = unlimited. TRIAL_EXPIRED only.
      required:
      - type
      - title
      - status
      - detail
      - code
      - request_id
      - instance
      description: RFC 7807 problem-details with ThinAir extensions (code, request_id, retry_after_ms). A 429 additionally carries upgrade_url, suggested_upgrade, upgrade_cta, upgrade_plans, next_step and usage; a 401 TRIAL_EXPIRED carries upgrade_url, expired_at, plan and quota.
    UpgradePlan:
      type: object
      properties:
        name:
          type: string
        price:
          type: string
          description: Display price, e.g. "$29/mo" or "custom".
        quota:
          type: string
          description: Display allowance, e.g. "10,000/day".
        note:
          type: string
        upgrade_url:
          type: string
          description: Checkout link for this specific plan. Carries the same plan preselect, in-place upgrade token and src attribution as the top-level upgrade_url.
      required:
      - name
      - price
      - quota
      - upgrade_url
      description: One self-serve plan offered on a 429.
    FeedbackV1Request:
      type: object
      properties:
        query:
          type: string
          minLength: 1
          maxLength: 2000
          description: The original query text this feedback is about.
          example: Santo Domingo & San Martin, Santiago
        place_id:
          type: string
          pattern: ^ta_(place|intersection)_[0-9a-f]{7,32}$
          description: Stable ThinAir place id the feedback is about.
          example: ta_place_8f3a2c9e61c04d58
        verdict:
          type: string
          enum:
          - wrong
          - right
          - moved
          description: '''wrong'' — the answer is incorrect; ''right'' — confirms the answer; ''moved'' — the place exists but sits at different coordinates (pair with `suggested`).'
        suggested:
          type: object
          properties:
            lat:
              type: number
              minimum: -90
              maximum: 90
              example: 29.7604
              description: Latitude in decimal degrees, WGS84.
            lon:
              type: number
              minimum: -180
              maximum: 180
              example: -95.3698
              description: Longitude in decimal degrees, WGS84.
          required:
          - lat
          - lon
          description: Suggested correct coordinates (WGS84).
        note:
          type: string
          maxLength: 280
          description: Free-text context for human review (≤280 chars). Stored in the evidence bundle only — never emitted to analytics.
      required:
      - verdict
    FeedbackResponse:
      type: object
      properties:
        feedback_id:
          type: string
        status:
          type: string
        deduped:
          type: boolean
      required:
      - feedback_id
    FeedbackRequest:
      type: object
      properties:
        verdict:
          type: string
          enum:
          - accepted
          - rejected
          - corrected
          description: Your judgement of the subject result.
        subject_event_id:
          type: string
          description: Event id of the result you're commenting on (or provide tool + query_text).
        tool:
          type: string
        query_text:
          type: string
        subject_entity_id:
          type: string
          description: Stable id the feedback is about.
          example: ta_place_8f3a2c9e61c04d58
        correction:
          type: object
          properties:
            entity_id:
              type: string
            label:
              type: string
              maxLength: 120
            lat:
              type: number
            lon:
              type: number
            note:
              type: string
              maxLength: 500
              description: Free-text note for human review — never sent to analytics.
          description: Required when verdict is 'corrected' (entity_id, label, or lat+lon).
        feedback_source:
          type: string
          enum:
          - user
          - agent
          - automated_validator
          - support
      required:
      - verdict
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer