{
  "openapi": "3.1.0",
  "info": {
    "title": "DOBI API",
    "version": "2.1.0",
    "description": "Agent-native IoT platform: discover devices, read telemetry, chat with devices (LLM, daily quota), run DAMs and pay per use via x402. Public subset for agents; see https://dobi.guru/llms.txt.",
    "contact": {
      "url": "https://dobi.guru"
    }
  },
  "servers": [
    {
      "url": "https://dobi.guru"
    }
  ],
  "components": {
    "securitySchemes": {
      "bearer": {
        "type": "http",
        "scheme": "bearer",
        "description": "Session JWT from wallet login (/api/auth) or the API key from POST /api/agent/login."
      }
    },
    "schemas": {
      "Envelope": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "data": {},
          "error": {
            "type": "string"
          }
        }
      }
    }
  },
  "paths": {
    "/health": {
      "get": {
        "summary": "Health and feature list",
        "responses": {
          "200": {
            "description": "healthy"
          }
        }
      }
    },
    "/api/devices": {
      "get": {
        "summary": "List devices",
        "description": "Devices their owners published, plus the caller's own devices when authenticated. Same set as GET /api/assets.",
        "security": [
          {},
          {
            "bearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit or daily LLM quota exceeded. Retry-After header is set.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/devices/{id}/status": {
      "get": {
        "summary": "Device status and recent metrics",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {},
          {
            "bearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          },
          "404": {
            "description": "Device not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/devices/{id}/chat": {
      "post": {
        "summary": "Natural-language chat with a device (LLM)",
        "description": "Anonymous allowed. Daily quota per IP (20), wallet (200) or verified-human agent (500), plus a platform-wide daily cap.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {},
          {
            "bearer": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "message"
                ],
                "properties": {
                  "message": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit or daily LLM quota exceeded. Retry-After header is set.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/devices/register": {
      "post": {
        "summary": "Device self-registration (provision_key is the credential)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "provision_key"
                ],
                "properties": {
                  "provision_key": {
                    "type": "string"
                  },
                  "id_asset": {
                    "type": "string"
                  },
                  "device_name": {
                    "type": "string"
                  },
                  "device_type": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Already registered",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          },
          "400": {
            "description": "provision_key missing",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          },
          "201": {
            "description": "Registered",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/devices/{id}/heartbeat": {
      "post": {
        "summary": "Device telemetry heartbeat",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "metrics"
                ],
                "properties": {
                  "provision_key": {
                    "type": "string"
                  },
                  "status": {
                    "type": "string"
                  },
                  "metrics": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "value": {
                          "type": "number"
                        },
                        "unit": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/devices/{id}/actions": {
      "get": {
        "summary": "Pending RPC commands for a device (device polls this)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "provision_key",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Device credential"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/dams": {
      "get": {
        "summary": "List DAMs (Decentralized Autonomous Machines)",
        "security": [
          {},
          {
            "bearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/dams/stats": {
      "get": {
        "summary": "Global DAM stats",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/dams/{id}": {
      "get": {
        "summary": "DAM detail",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {},
          {
            "bearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/dams/{id}/devices": {
      "get": {
        "summary": "Devices in a DAM",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {},
          {
            "bearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/dams/{id}/metrics": {
      "get": {
        "summary": "DAM KPIs",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {},
          {
            "bearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/dams/{id}/nl": {
      "post": {
        "summary": "Natural-language command to a DAM (LLM, quota-limited)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {},
          {
            "bearer": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "message"
                ],
                "properties": {
                  "message": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit or daily LLM quota exceeded. Retry-After header is set.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/vend/{id}/chat": {
      "post": {
        "summary": "Customer chat with a vending machine (LLM, quota-limited)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {},
          {
            "bearer": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "message"
                ],
                "properties": {
                  "message": {
                    "type": "string",
                    "maxLength": 1000
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          },
          "413": {
            "description": "message longer than 1000 characters",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit or daily LLM quota exceeded. Retry-After header is set.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/playground": {
      "get": {
        "summary": "List server-side simulated devices",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Spawn a simulated device",
        "description": "Anonymous: max 3 per IP, expire after 24h. Wallet: max 10. Platform-wide cap of 60.",
        "security": [
          {},
          {
            "bearer": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "type"
                ],
                "properties": {
                  "type": {
                    "type": "string",
                    "enum": [
                      "charger",
                      "battery",
                      "smart_display",
                      "smart_locker",
                      "greenhouse",
                      "cold_room"
                    ]
                  },
                  "name": {
                    "type": "string"
                  },
                  "heartbeat_sec": {
                    "type": "integer",
                    "minimum": 2,
                    "maximum": 120
                  },
                  "dam_id": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Spawned",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          },
          "400": {
            "description": "Invalid type",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit or daily LLM quota exceeded. Retry-After header is set.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/llm/quota": {
      "get": {
        "summary": "Caller's LLM quota for today (no LLM call)",
        "security": [
          {},
          {
            "bearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/agent/login": {
      "post": {
        "summary": "Exchange a Notlogin verifiable credential for a DOBI API key",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "vcJson"
                ],
                "properties": {
                  "vcJson": {
                    "type": "object"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          },
          "401": {
            "description": "Invalid credential",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit or daily LLM quota exceeded. Retry-After header is set.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/assets": {
      "get": {
        "summary": "List published assets (same set as GET /api/devices)",
        "security": [
          {},
          {
            "bearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/alarms": {
      "get": {
        "summary": "Active alarms visible to the caller",
        "security": [
          {},
          {
            "bearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/chains": {
      "get": {
        "summary": "Enabled payment chains and token addresses",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/x402/{asset_id}/pay": {
      "post": {
        "summary": "x402 pay-per-use: returns 402 with payment requirements, or executes when a valid payment is attached",
        "parameters": [
          {
            "name": "asset_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Executed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          },
          "402": {
            "description": "Payment Required (x402 payment details)"
          }
        }
      }
    }
  }
}
