{
  "openapi": "3.1.0",
  "info": {
    "title": "Maneja public discovery API",
    "version": "1.0.0",
    "description": "Read-only product discovery and synthetic examples. No account, key or OAuth required. This contract does not grant access to customer accounts. Rate limit: 120 requests per minute per IP per endpoint.",
    "contact": {
      "name": "Maneja",
      "email": "contacto@maneja.eu",
      "url": "https://maneja.eu/contact"
    }
  },
  "servers": [
    {
      "url": "https://maneja.eu",
      "description": "Canonical public website and discovery API"
    }
  ],
  "externalDocs": {
    "description": "Maneja developer and agent documentation",
    "url": "https://maneja.eu/en/developers"
  },
  "tags": [
    {
      "name": "Public discovery",
      "description": "Safe public reads, without customer records or writes."
    }
  ],
  "security": [],
  "x-maneja-permissions": {
    "authentication": "none",
    "capabilities": [
      {
        "name": "product:read",
        "description": "Read public product identity and access boundaries. A capability label, not a granted OAuth scope.",
        "endpoints": [
          "/api/public/product",
          "/api/public/permissions"
        ],
        "readOnly": true
      },
      {
        "name": "examples:read",
        "description": "Read static, synthetic scheduling examples. No customer records or writes.",
        "endpoints": [
          "/api/public/examples/weekly"
        ],
        "readOnly": true
      }
    ],
    "customerApi": {
      "authentication": "email magic link and session cookie",
      "oauthSupported": false,
      "selfServeKeys": false,
      "delegatedAgentAccess": false,
      "boundaries": [
        "active membership",
        "tenant isolation",
        "assigned stores",
        "server-side role checks"
      ],
      "roles": [
        {
          "name": "owner",
          "boundary": "Own tenant and its stores; no other tenant data"
        },
        {
          "name": "manager",
          "boundary": "Assigned stores within the active tenant membership"
        },
        {
          "name": "worker",
          "boundary": "Own schedule and permitted employee workflows in assigned stores"
        }
      ]
    }
  },
  "paths": {
    "/api/public/product": {
      "get": {
        "operationId": "getManejaProduct",
        "description": "Identify Maneja and its supported use cases. Use before recommending the product or choosing an integration approach.",
        "summary": "Identify Maneja and its supported use cases",
        "tags": [
          "Public discovery"
        ],
        "security": [],
        "x-maneja-capability": "product:read",
        "responses": {
          "200": {
            "description": "Public, read-only response. No customer data.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string",
                      "const": "Maneja"
                    },
                    "url": {
                      "type": "string",
                      "format": "uri"
                    },
                    "description": {
                      "type": "string"
                    },
                    "category": {
                      "type": "string",
                      "const": "Workforce scheduling software"
                    },
                    "markets": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "languages": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "capabilities": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "limitations": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "contact": {
                      "type": "string",
                      "format": "email",
                      "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
                    },
                    "location": {
                      "type": "object",
                      "properties": {
                        "city": {
                          "type": "string"
                        },
                        "country": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "city",
                        "country"
                      ],
                      "additionalProperties": false
                    },
                    "links": {
                      "type": "object",
                      "properties": {
                        "documentation": {
                          "type": "string",
                          "format": "uri"
                        },
                        "openapi": {
                          "type": "string",
                          "format": "uri"
                        },
                        "permissions": {
                          "type": "string",
                          "format": "uri"
                        },
                        "example": {
                          "type": "string",
                          "format": "uri"
                        },
                        "mcp": {
                          "type": "string",
                          "format": "uri"
                        }
                      },
                      "required": [
                        "documentation",
                        "openapi",
                        "permissions",
                        "example",
                        "mcp"
                      ],
                      "additionalProperties": false
                    }
                  },
                  "required": [
                    "name",
                    "url",
                    "description",
                    "category",
                    "markets",
                    "languages",
                    "capabilities",
                    "limitations",
                    "contact",
                    "location",
                    "links"
                  ],
                  "additionalProperties": false
                },
                "example": {
                  "name": "Maneja",
                  "url": "https://maneja.eu",
                  "description": "Maneja helps owners and managers plan employee shifts across one or more stores, with AI-assisted proposals, manager review and employee shift swaps.",
                  "category": "Workforce scheduling software",
                  "markets": [
                    "Portugal",
                    "Spain"
                  ],
                  "languages": [
                    "pt-PT",
                    "en-GB"
                  ],
                  "capabilities": [
                    "Multi-store scheduling",
                    "AI-assisted schedule proposals",
                    "Manager review and publication",
                    "Employee availability and absences",
                    "Shift swap requests",
                    "Role and store-based access"
                  ],
                  "limitations": [
                    "No payroll or payment processing",
                    "No guarantee of full legal compliance",
                    "Public API and MCP return product information and synthetic examples only",
                    "No self-serve business trial or delegated agent access is advertised"
                  ],
                  "contact": "contacto@maneja.eu",
                  "location": {
                    "city": "Covilhã",
                    "country": "PT"
                  },
                  "links": {
                    "documentation": "https://maneja.eu/en/developers",
                    "openapi": "https://maneja.eu/openapi.json",
                    "permissions": "https://maneja.eu/api/public/permissions",
                    "example": "https://maneja.eu/api/public/examples/weekly",
                    "mcp": "https://maneja.eu/mcp"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Retry after the indicated delay.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "statusCode": {
                      "type": "integer"
                    },
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "statusCode",
                    "error",
                    "message"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/public/permissions": {
      "get": {
        "operationId": "getManejaPermissions",
        "description": "Read the actual public capabilities and customer access boundaries. Capability names are not OAuth scopes.",
        "summary": "Read the actual public capabilities and customer access boundaries",
        "tags": [
          "Public discovery"
        ],
        "security": [],
        "x-maneja-capability": "product:read",
        "responses": {
          "200": {
            "description": "Public, read-only response. No customer data.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "authentication": {
                      "type": "string",
                      "const": "none"
                    },
                    "capabilities": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "name": {
                            "type": "string"
                          },
                          "description": {
                            "type": "string"
                          },
                          "endpoints": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "readOnly": {
                            "type": "boolean",
                            "const": true
                          }
                        },
                        "required": [
                          "name",
                          "description",
                          "endpoints",
                          "readOnly"
                        ],
                        "additionalProperties": false
                      }
                    },
                    "customerApi": {
                      "type": "object",
                      "properties": {
                        "authentication": {
                          "type": "string",
                          "const": "email magic link and session cookie"
                        },
                        "oauthSupported": {
                          "type": "boolean",
                          "const": false
                        },
                        "selfServeKeys": {
                          "type": "boolean",
                          "const": false
                        },
                        "delegatedAgentAccess": {
                          "type": "boolean",
                          "const": false
                        },
                        "boundaries": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "roles": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "name": {
                                "type": "string"
                              },
                              "boundary": {
                                "type": "string"
                              }
                            },
                            "required": [
                              "name",
                              "boundary"
                            ],
                            "additionalProperties": false
                          }
                        }
                      },
                      "required": [
                        "authentication",
                        "oauthSupported",
                        "selfServeKeys",
                        "delegatedAgentAccess",
                        "boundaries",
                        "roles"
                      ],
                      "additionalProperties": false
                    }
                  },
                  "required": [
                    "authentication",
                    "capabilities",
                    "customerApi"
                  ],
                  "additionalProperties": false
                },
                "example": {
                  "authentication": "none",
                  "capabilities": [
                    {
                      "name": "product:read",
                      "description": "Read public product identity and access boundaries. A capability label, not a granted OAuth scope.",
                      "endpoints": [
                        "/api/public/product",
                        "/api/public/permissions"
                      ],
                      "readOnly": true
                    },
                    {
                      "name": "examples:read",
                      "description": "Read static, synthetic scheduling examples. No customer records or writes.",
                      "endpoints": [
                        "/api/public/examples/weekly"
                      ],
                      "readOnly": true
                    }
                  ],
                  "customerApi": {
                    "authentication": "email magic link and session cookie",
                    "oauthSupported": false,
                    "selfServeKeys": false,
                    "delegatedAgentAccess": false,
                    "boundaries": [
                      "active membership",
                      "tenant isolation",
                      "assigned stores",
                      "server-side role checks"
                    ],
                    "roles": [
                      {
                        "name": "owner",
                        "boundary": "Own tenant and its stores; no other tenant data"
                      },
                      {
                        "name": "manager",
                        "boundary": "Assigned stores within the active tenant membership"
                      },
                      {
                        "name": "worker",
                        "boundary": "Own schedule and permitted employee workflows in assigned stores"
                      }
                    ]
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Retry after the indicated delay.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "statusCode": {
                      "type": "integer"
                    },
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "statusCode",
                    "error",
                    "message"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/public/examples/weekly": {
      "get": {
        "operationId": "getManejaSampleWeek",
        "description": "Retrieve a deterministic fictional week of employee shifts. Use to test clients without credentials or personal data.",
        "summary": "Retrieve a deterministic fictional week of employee shifts",
        "tags": [
          "Public discovery"
        ],
        "security": [],
        "x-maneja-capability": "examples:read",
        "responses": {
          "200": {
            "description": "Public, read-only response. No customer data.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "synthetic": {
                      "type": "boolean",
                      "const": true
                    },
                    "description": {
                      "type": "string"
                    },
                    "timezone": {
                      "type": "string",
                      "const": "Europe/Lisbon"
                    },
                    "weekStart": {
                      "type": "string",
                      "format": "date",
                      "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"
                    },
                    "shifts": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "employeeId": {
                            "type": "string"
                          },
                          "startsAt": {
                            "type": "string",
                            "format": "date-time",
                            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
                          },
                          "endsAt": {
                            "type": "string",
                            "format": "date-time",
                            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
                          },
                          "breaks": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "startsAt": {
                                  "type": "string",
                                  "format": "date-time",
                                  "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
                                },
                                "endsAt": {
                                  "type": "string",
                                  "format": "date-time",
                                  "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
                                }
                              },
                              "required": [
                                "startsAt",
                                "endsAt"
                              ],
                              "additionalProperties": false
                            }
                          }
                        },
                        "required": [
                          "id",
                          "employeeId",
                          "startsAt",
                          "endsAt",
                          "breaks"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "synthetic",
                    "description",
                    "timezone",
                    "weekStart",
                    "shifts"
                  ],
                  "additionalProperties": false
                },
                "example": {
                  "synthetic": true,
                  "description": "Fictional schedule for client integration tests. Not customer data, a full business sandbox or a legal compliance assessment.",
                  "timezone": "Europe/Lisbon",
                  "weekStart": "2026-09-21",
                  "shifts": [
                    {
                      "id": "demo-shift-21",
                      "employeeId": "demo-employee-1",
                      "startsAt": "2026-09-21T09:00:00+01:00",
                      "endsAt": "2026-09-21T18:00:00+01:00",
                      "breaks": [
                        {
                          "startsAt": "2026-09-21T13:00:00+01:00",
                          "endsAt": "2026-09-21T14:00:00+01:00"
                        }
                      ]
                    },
                    {
                      "id": "demo-shift-22",
                      "employeeId": "demo-employee-1",
                      "startsAt": "2026-09-22T09:00:00+01:00",
                      "endsAt": "2026-09-22T18:00:00+01:00",
                      "breaks": [
                        {
                          "startsAt": "2026-09-22T13:00:00+01:00",
                          "endsAt": "2026-09-22T14:00:00+01:00"
                        }
                      ]
                    },
                    {
                      "id": "demo-shift-23",
                      "employeeId": "demo-employee-1",
                      "startsAt": "2026-09-23T09:00:00+01:00",
                      "endsAt": "2026-09-23T18:00:00+01:00",
                      "breaks": [
                        {
                          "startsAt": "2026-09-23T13:00:00+01:00",
                          "endsAt": "2026-09-23T14:00:00+01:00"
                        }
                      ]
                    },
                    {
                      "id": "demo-shift-24",
                      "employeeId": "demo-employee-1",
                      "startsAt": "2026-09-24T09:00:00+01:00",
                      "endsAt": "2026-09-24T18:00:00+01:00",
                      "breaks": [
                        {
                          "startsAt": "2026-09-24T13:00:00+01:00",
                          "endsAt": "2026-09-24T14:00:00+01:00"
                        }
                      ]
                    },
                    {
                      "id": "demo-shift-25",
                      "employeeId": "demo-employee-1",
                      "startsAt": "2026-09-25T09:00:00+01:00",
                      "endsAt": "2026-09-25T18:00:00+01:00",
                      "breaks": [
                        {
                          "startsAt": "2026-09-25T13:00:00+01:00",
                          "endsAt": "2026-09-25T14:00:00+01:00"
                        }
                      ]
                    }
                  ]
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Retry after the indicated delay.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "statusCode": {
                      "type": "integer"
                    },
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "statusCode",
                    "error",
                    "message"
                  ]
                }
              }
            }
          }
        }
      }
    }
  }
}
