surfingdog-ai Reports API

How a business's doors went, as agents say: private to the business.

Operations 2

POST /v1/door-reports Say how a business's door went #
GET /v1/door-reports/me Your own reporting credit, and what you read with #

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/surfingdog-ai:surfingdog-ai-reports-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

surfingdog-ai-reports-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Surfing Dog Search Reports API
  version: '1'
  license:
    name: ODbL-1.0 (the directory data; town names and centres © GeoNames, CC BY 4.0)
    url: https://opendatacommons.org/licenses/odbl/1-0/
  summary: A public directory of businesses an AI can ask, book or buy from, through their own inboxes and other agent doors.
  description: 'Everything here is a public read, no sign-in, the same answer for everyone (a free directory key only lets a list page deeper than 200 places), except two calls about door reports: POST /v1/door-reports, where an agent says how a business''s door went, and GET /v1/door-reports/me, signed, which answers the signer''s own reporting credit. Signed reads may count against a contributor''s own allowance; the answers are the same. The directory''s order is published at GET /v1/ranking and cannot be bought; every query parameter only leaves businesses out. This API takes no orders or payments and books nothing itself; each result lists the business''s own doors (a listing''s doors, or a member''s protocols). A business this network found on its own website is marked as found, with the date it was checked; only facts it published itself are shown, never a phone or an email. Errors are RFC 9457 problem documents. The protocol behind this API, with its JSON Schemas and test vectors, is public; the MCP server at /mcp offers the same reads as tools, and can carry a person''s request to a business''s own inbox when the business allows it.'
servers:
- url: https://network.surfingdog.ai
tags:
- name: Reports
  description: 'How a business''s doors went, as agents say: private to the business.'
paths:
  /v1/door-reports:
    post:
      operationId: reportDoors
      tags:
      - Reports
      summary: Say how a business's door went
      description: 'After an agent uses a business''s door (its inbox, MCP, A2A or API), done or not, it says how it went: ok, refused (an honest no), invalid (the caller''s own fault), fail, or info (the door needs a person), with a class for every result but ok. A report goes privately to the business as counts by day; a report that the door could not be reached makes this network read the door itself, at most twice a day per door for reports no proof binds. On its own a report changes nothing public. Each report is taken or ignored on its own, with the first reason that applies: unknown_door, unknown_op, bad_class, bad_time, superseded (a later report in the call is the same attempt), over_limit. The body is strict JSON with closed objects: a member not named here (in any letter case), a member named twice, or a value of the wrong type or outside its pattern is refused whole with 400 malformed, and a report never carries a pass, a key, a person, an email, a name, a phone, an address, a message, an item id, a free-text reason or a trace; more than 100 reports, more than 128 KB or a token over 1 KB is 413 too_large. Unsigned calls are welcome; sdi-agent/1 with a self-held key, or Web Bot Auth with a platform''s key directory, says more about where reports come from, never who. A signature that does not verify makes the call unsigned, and Sdi-Signature says why. The same call is the MCP tool report_door. A guide: /report.md.'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - v
              - reports
              additionalProperties: false
              properties:
                v:
                  type: integer
                  const: 1
                reports:
                  type: array
                  minItems: 1
                  maxItems: 100
                  items:
                    type: object
                    required:
                    - domain
                    - door
                    - op
                    - at
                    - intent
                    - result
                    additionalProperties: false
                    properties:
                      domain:
                        type: string
                        pattern: ^[a-z0-9.-]{1,253}$
                        description: The business's domain, as the directory lists it.
                      door:
                        type: object
                        required:
                        - type
                        - url
                        additionalProperties: false
                        description: 'The door used, its type and URL exactly as the directory shows them: for a member''s inbox, type inbox at the card''s inbox.url, inbox.mcp or inbox.rest; else one of a listing''s doors. A door the directory does not show for that domain, or a URL with a query or a fragment, is ignored (unknown_door).'
                        properties:
                          type:
                            type: string
                            pattern: ^[a-z0-9:_-]{1,48}$
                            description: inbox, mcp, a2a, openapi, api, ucp, acp, nlweb, or platform:<slug>.
                          url:
                            type: string
                            minLength: 1
                            maxLength: 2048
                      op:
                        type: string
                        pattern: ^[a-z][a-z0-9_]{0,31}$
                        description: What was tried, from the capability vocabulary (GET /v1/score-rules); another is ignored (unknown_op).
                        examples:
                        - find
                        - catalogue
                        - availability
                        - message
                        - negotiate
                        - book
                        - order
                        - signup
                        - pay
                        - change
                        - cancel
                        - track
                        - return
                        - receipt
                        - feedback
                        - subscription
                        - vouchers
                        - waitlist
                        - support
                        - policies
                      tool:
                        type: string
                        pattern: ^[a-z0-9_.-]{1,64}$
                      at:
                        type: integer
                        minimum: 0
                        description: 'When the door was used, in Unix seconds, kept to the minute: within the last 7 days, and no later than a minute after the call (else bad_time).'
                      ms:
                        type: integer
                        minimum: 0
                        maximum: 600000
                        description: How long the door took, in milliseconds. Private to the business.
                      intent:
                        type: string
                        pattern: ^[A-Za-z0-9_-]{8,32}$
                        description: 'One per attempt, the same for its retries: a retried attempt counts once, and its last result wins.'
                      result:
                        type: string
                        enum:
                        - ok
                        - refused
                        - invalid
                        - fail
                        - info
                      class:
                        type: string
                        pattern: ^[a-z0-9_.]{1,64}$
                        examples:
                        - dns.name_not_resolved
                        - dns.failed
                        - tcp.timed_out
                        - tcp.refused
                        - tcp.reset
                        - tls.cert.invalid
                        - tls.failed
                        - http.error
                        - http.response.invalid
                        - abandoned
                        - timeout
                        - operation.timeout
                        - protocol.internal
                        - protocol.advertised_missing
                        - protocol.version
                        - protocol.invalid_answer
                        - operation.tool_error
                        - operation.failed
                        - operation.internal
                        - payment_failed
                        - slot_taken
                        - out_of_stock
                        - item_unavailable
                        - outside_limits
                        - wrong_state
                        - customer_side
                        - escalation
                        - auth
                        - person
                        - client.invalid_params
                        - client.parse_error
                        - client.invalid_request
                        - client.mcp_headers
                        - client.mcp_refused
                        - client.http
                        - client.rate_limited
                        description: For every result but ok, what happened, a class of that result (vocab/door-report-classes.json, /report.md); none with ok. Else bad_class.
                      token:
                        type: string
                        maxLength: 1024
                        pattern: ^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$
                        description: The door's signed outcome token for this answer, when it gave one, as it came.
      responses:
        '202':
          description: 'Every report accepted (what proved it, what it was kept as: both private) or ignored (why), by its place in reports.'
          content:
            application/json:
              schema:
                type: object
                required:
                - accepted
                - ignored
                - next
                properties:
                  accepted:
                    type: array
                    items:
                      type: object
                      required:
                      - i
                      - proof
                      - counts
                      properties:
                        i:
                          type: integer
                          minimum: 0
                        proof:
                          type: string
                          enum:
                          - none
                          - signature
                          - token
                          description: token, a door token that verified; signature, a signature that verified; else none.
                        counts:
                          type: string
                          enum:
                          - counter
                          - row
                          description: 'What the report was kept as: a per-door daily counter, or a row (a platform''s signed report); both private.'
                  ignored:
                    type: array
                    items:
                      type: object
                      required:
                      - i
                      - why
                      properties:
                        i:
                          type: integer
                          minimum: 0
                        why:
                          type: string
                          enum:
                          - unknown_door
                          - unknown_op
                          - bad_class
                          - bad_time
                          - superseded
                          - over_limit
                  next:
                    type: string
        '400':
          $ref: '#/components/responses/Problem'
        '413':
          $ref: '#/components/responses/Problem'
        '429':
          $ref: '#/components/responses/Problem'
  /v1/door-reports/me:
    get:
      operationId: getReporter
      tags:
      - Reports
      summary: Your own reporting credit, and what you read with
      description: 'Signed sdi-agent/1 with your own key, or Web Bot Auth as your platform, it answers the signer''s credit over the last 30 days and whether that makes it a contributor. A signed report earns its signer 1 point for its business, once a day, when the signer''s own signed reads returned that business today or yesterday (UTC), whatever the report said, and at most 10 points a day; a platform earns none at a business on its own registrable domain. A contributor has 30 points in the last 30 days, on at least 7 different days, and reads /mcp, /a2a, /v1/businesses and /v1/businesses/{domain} on an allowance of its own: 1,800 a minute for a key, 6,000 for a platform, on top of the 600 a minute every address has. Nothing else changes for it: the same answers and the same order. The signature is checked before anything is looked up, so there is no way to ask about anyone else. Unsigned: 401 signature_required. A guide: /report.md.'
      responses:
        '200':
          description: The signer's credit and allowance.
          content:
            application/json:
              schema:
                type: object
                required:
                - reporter
                - credit
                - contributor
                - threshold
                - reads
                - contributor_reads
                - guide
                - as_of
                properties:
                  reporter:
                    type: object
                    required:
                    - type
                    properties:
                      type:
                        type: string
                        enum:
                        - key
                        - platform
                      keyid:
                        type: string
                        description: A key's RFC 7638 thumbprint.
                      origin:
                        type: string
                        description: A platform's origin, as its Signature-Agent named it.
                      platform:
                        type: string
                        description: 'The platform''s registrable domain: every origin of it is one reporter.'
                  credit:
                    type: object
                    description: 'Over the window: the points, and the days that earned any.'
                    required:
                    - points
                    - days
                    properties:
                      points:
                        type: integer
                        minimum: 0
                      days:
                        type: integer
                        minimum: 0
                  contributor:
                    type: boolean
                  threshold:
                    type: object
                    description: 'The rule, as packages/spec''s REPORTER_CREDIT_RULE gives it: a contributor has min_points points on min_days days in the last window_days, each day counting at most per_day_at_most.'
                    required:
                    - window_days
                    - min_days
                    - min_points
                    - per_day_at_most
                    properties:
                      window_days:
                        type: integer
                      min_days:
                        type: integer
                      min_points:
                        type: integer
                      per_day_at_most:
                        type: integer
                  reads:
                    $ref: '#/components/schemas/ReadAllowance'
                  contributor_reads:
                    $ref: '#/components/schemas/ReadAllowance'
                  guide:
                    type: string
                    format: uri
                    description: This network's guide for agents, /report.md, which publishes the rule.
                  as_of:
                    type: string
                    format: date-time
        '401':
          description: signature_required (the call is not signed), or why its signature was not used (bad_signature, expired, replayed_signature), also in Sdi-Signature.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          description: 'rate_limited: over 60 calls a minute from one address or its network. Try again after Retry-After seconds.'
          headers:
            Retry-After:
              schema:
                type: integer
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
components:
  schemas:
    Problem:
      type: object
      required:
      - type
      - title
      - status
      properties:
        type:
          type: string
        title:
          type: string
        status:
          type: integer
        code:
          type: string
          description: 'What to do differently, when a status alone does not say: cursor_expired, not_found, too_large, rate_limited, category_unresolved, page_too_deep.'
        detail:
          type: string
        instance:
          type: string
        candidates:
          type: array
          items:
            type: string
          description: 'category_unresolved: up to 5 categories to try.'
    ReadAllowance:
      type: object
      required:
      - per_minute
      - burst
      - per
      properties:
        per_minute:
          type: integer
        burst:
          type: integer
        per:
          type: string
          enum:
          - address
          - key
          - platform
          description: What it is counted per.
        per_address:
          type: integer
          description: 'A contributor''s: the most of its kind''s reads from one address.'
  responses:
    Problem:
      description: An RFC 9457 problem document.
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
externalDocs:
  description: The network protocol
  url: https://github.com/surfingdogai/inbox/blob/main/docs/protocol/network.md