{
 "openapi": "3.0.3",
 "info": {
  "title": "xMap Flows API",
  "version": "1.0.0",
  "description": "Run your flows and read their results from your own systems. Sign in with an access key (a personal one from Settings, AI assistants, or an organization key from the Team page) sent as a Bearer token. See https://flows.xmap.ai/api-docs/ for the guide. AI assistants use the MCP server at https://flows.xmap.ai/mcp with the same keys: its tools (flows, runs, AI employees and their budgets, Ask the map, enriching a table, comments and versions) are listed on the guide page.",
  "contact": {
   "email": "sales@xmap.ai",
   "url": "https://flows.xmap.ai/api-docs/"
  }
 },
 "servers": [
  {
   "url": "https://flows.xmap.ai/api"
  }
 ],
 "security": [
  {
   "accessKey": []
  }
 ],
 "components": {
  "securitySchemes": {
   "accessKey": {
    "type": "http",
    "scheme": "bearer",
    "description": "xfk_... access key"
   }
  },
  "schemas": {
   "Error": {
    "type": "object",
    "properties": {
     "error": {
      "type": "string",
      "description": "What went wrong, in words"
     },
     "code": {
      "type": "string",
      "description": "A short code for some errors, such as read_only or unauthorized"
     }
    }
   },
   "Run": {
    "type": "object",
    "properties": {
     "run_id": {
      "type": "string",
      "format": "uuid"
     },
     "status": {
      "type": "string",
      "enum": [
       "passed",
       "failed",
       "waiting",
       "stopped"
      ]
     },
     "waiting_until": {
      "type": "string",
      "format": "date-time"
     },
     "sent_for_real": {
      "type": "boolean"
     },
     "credits_used": {
      "type": "integer"
     },
     "credits_left": {
      "type": "integer"
     },
     "problem": {
      "type": "string",
      "nullable": true
     },
     "steps": {
      "type": "array",
      "items": {
       "type": "object",
       "properties": {
        "block": {
         "type": "string"
        },
        "status": {
         "type": "string"
        },
        "result": {
         "type": "string"
        },
        "credits": {
         "type": "integer"
        }
       }
      }
     },
     "count": {
      "type": "integer",
      "description": "How many items reached the end of the flow"
     },
     "items": {
      "type": "array",
      "items": {
       "type": "object"
      },
      "description": "Those items, up to 500"
     },
     "sample_rows": {
      "type": "array",
      "items": {
       "type": "object"
      }
     },
     "link": {
      "type": "string",
      "format": "uri"
     }
    }
   }
  }
 },
 "paths": {
  "/v1/me": {
   "get": {
    "summary": "Who the key acts as, and its organizations",
    "responses": {
     "200": {
      "description": "The person (or organization key) and its organizations with their credits",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "user": {
           "type": "object",
           "properties": {
            "email": {
             "type": "string"
            },
            "name": {
             "type": "string"
            }
           }
          },
          "organizations": {
           "type": "array",
           "items": {
            "type": "object",
            "properties": {
             "id": {
              "type": "string"
             },
             "name": {
              "type": "string"
             },
             "role": {
              "type": "string"
             },
             "credits": {
              "type": "integer"
             }
            }
           }
          }
         }
        }
       }
      }
     },
     "401": {
      "description": "No key, or the key ended",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "403": {
      "description": "The key may not do this (read-only, or the organization's rules)",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "description": "Not found, or not yours to see",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Too many requests: at most 120 a minute per key",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/v1/flows": {
   "get": {
    "summary": "The flows the key can see",
    "parameters": [
     {
      "name": "organization_id",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string",
       "format": "uuid"
      },
      "description": "Which organization; the first one when left out"
     }
    ],
    "responses": {
     "200": {
      "description": "Flows",
      "content": {
       "application/json": {
        "schema": {
         "type": "array",
         "items": {
          "type": "object",
          "properties": {
           "id": {
            "type": "string"
           },
           "name": {
            "type": "string"
           },
           "status": {
            "type": "string",
            "enum": [
             "draft",
             "live",
             "done"
            ]
           },
           "blocks": {
            "type": "integer"
           },
           "tags": {
            "type": "array",
            "items": {
             "type": "string"
            }
           },
           "archived": {
            "type": "boolean"
           }
          }
         }
        }
       }
      }
     },
     "401": {
      "description": "No key, or the key ended",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "403": {
      "description": "The key may not do this (read-only, or the organization's rules)",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "description": "Not found, or not yours to see",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Too many requests: at most 120 a minute per key",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/v1/flows/{flowId}/run": {
   "post": {
    "summary": "Run a flow",
    "description": "send: true runs it for real (live data, emails and app messages are sent, credits are used, results are remembered); false is a test run that sends nothing. A flow with a Webhook trigger takes input.items.",
    "parameters": [
     {
      "name": "flowId",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string",
       "format": "uuid"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "send": {
          "type": "boolean",
          "default": false
         },
         "input": {
          "type": "object",
          "properties": {
           "items": {
            "type": "array",
            "items": {
             "type": "object"
            }
           }
          }
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "The run",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Run"
        }
       }
      }
     },
     "402": {
      "description": "Not enough credits, or the monthly limit",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "401": {
      "description": "No key, or the key ended",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "403": {
      "description": "The key may not do this (read-only, or the organization's rules)",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "description": "Not found, or not yours to see",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Too many requests: at most 120 a minute per key",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/v1/runs/{runId}": {
   "get": {
    "summary": "A run's status",
    "description": "For runs that wait (Wait, Approval) or carry on in parts. Items are returned by the run call itself; this gives the status, steps and a sample.",
    "parameters": [
     {
      "name": "runId",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string",
       "format": "uuid"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "The run",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Run"
        }
       }
      }
     },
     "401": {
      "description": "No key, or the key ended",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "403": {
      "description": "The key may not do this (read-only, or the organization's rules)",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "description": "Not found, or not yours to see",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Too many requests: at most 120 a minute per key",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/v1/data": {
   "get": {
    "summary": "The data products and the settings each takes",
    "security": [],
    "responses": {
     "200": {
      "description": "Products"
     }
    }
   }
  },
  "/v1/data/{product}": {
   "post": {
    "summary": "Data on demand (sample data for now)",
    "description": "scan (places in an area: area.cities, area.countries, area.point {lat, lng, radius} or area.geojson; limit), or poi, mobility, traffic (for places you send). These answers are sample data while live data is connected to the API, and use no credits; every answer says so (sample: true).",
    "parameters": [
     {
      "name": "product",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string",
       "enum": [
        "scan",
        "poi",
        "mobility",
        "traffic"
       ]
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Places"
     },
     "401": {
      "description": "No key, or the key ended",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "403": {
      "description": "The key may not do this (read-only, or the organization's rules)",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "description": "Not found, or not yours to see",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Too many requests: at most 120 a minute per key",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/v1/tables": {
   "get": {
    "summary": "List the organization's tables in My data",
    "parameters": [
     {
      "name": "organization_id",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "The tables: id, setting (t:<id>), name, columns, rows"
     }
    }
   },
   "post": {
    "summary": "Create a table in My data",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "name",
         "columns",
         "rows"
        ],
        "properties": {
         "organization_id": {
          "type": "string"
         },
         "name": {
          "type": "string"
         },
         "columns": {
          "type": "array",
          "items": {
           "type": "string"
          }
         },
         "rows": {
          "type": "array",
          "items": {}
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "The new table: id, setting, name, rows"
     }
    }
   }
  },
  "/v1/tables/{tableId}/rows": {
   "post": {
    "summary": "Add rows to a table",
    "parameters": [
     {
      "name": "tableId",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "rows"
        ],
        "properties": {
         "columns": {
          "type": "array",
          "items": {
           "type": "string"
          }
         },
         "rows": {
          "type": "array",
          "items": {}
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "How many rows were added, and the flows that started on them"
     }
    }
   }
  },
  "/v1/tables/{tableId}": {
   "delete": {
    "summary": "Delete a table",
    "description": "Deletes a table in My data for good, with its rows. It cannot be undone.",
    "parameters": [
     {
      "name": "tableId",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The table id (or t:<id>)."
     }
    ],
    "responses": {
     "200": {
      "description": "{ \"deleted\": true }"
     }
    }
   }
  }
 }
}