{
  "openapi": "3.1.0",
  "info": {
    "title": "Otomi public store API",
    "version": "1",
    "description": "For sites and apps that are not WooCommerce. Send the whole record every time it changes; Otomi compares it with what it had and works out what happened. Test keys (`osk_test_…`) check everything and store nothing. Guide: docs/api/v1.md."
  },
  "servers": [
    {
      "url": "https://my.otomi.app/api"
    }
  ],
  "security": [
    {
      "apiKey": []
    }
  ],
  "paths": {
    "/v1/ping": {
      "get": {
        "summary": "Is the key right?",
        "responses": {
          "200": {
            "description": "The store the key belongs to.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "const": true
                    },
                    "mode": {
                      "enum": ["test", "live"]
                    },
                    "store": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "currency": {
                          "enum": ["IRT", "IRR"]
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Wrong or revoked key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orders": {
      "post": {
        "summary": "An order as it is now",
        "description": "Created or changed (paid, shipped, cancelled, refunded): send all of it.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Order"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Received.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WriteResult"
                }
              }
            }
          },
          "400": {
            "description": "Fix the data; do not resend as is.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Wrong or revoked key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Sent from a browser: keys belong on your server.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Over 20 requests a second: retry after `Retry-After`."
          }
        }
      }
    },
    "/v1/customers": {
      "post": {
        "summary": "A customer as they are now",
        "description": "On sign-up and sign-in. A later `lastLoginAt` starts \"signed in\" automations.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Customer"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Received.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WriteResult"
                }
              }
            }
          },
          "400": {
            "description": "Fix the data; do not resend as is.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Wrong or revoked key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Sent from a browser: keys belong on your server.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Over 20 requests a second: retry after `Retry-After`."
          }
        }
      }
    },
    "/v1/products": {
      "post": {
        "summary": "A product as it is now",
        "description": "Created or changed (price, stock, categories). Addresses must be on your own site.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Product"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Received.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WriteResult"
                }
              }
            }
          },
          "400": {
            "description": "Fix the data; do not resend as is.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Wrong or revoked key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Sent from a browser: keys belong on your server.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Over 20 requests a second: retry after `Retry-After`."
          }
        }
      }
    },
    "/v1/products/{id}": {
      "delete": {
        "summary": "A product removed from the site",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Removed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WriteResult"
                }
              }
            }
          },
          "400": {
            "description": "Fix the data; do not resend as is.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Wrong or revoked key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Sent from a browser: keys belong on your server.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Over 20 requests a second: retry after `Retry-After`."
          }
        }
      }
    },
    "/v1/reviews": {
      "post": {
        "summary": "A published review",
        "description": "Once it shows on the site. One younger than a day starts \"review posted\" automations.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Review"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Received.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WriteResult"
                }
              }
            }
          },
          "400": {
            "description": "Fix the data; do not resend as is.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Wrong or revoked key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Sent from a browser: keys belong on your server.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Over 20 requests a second: retry after `Retry-After`."
          }
        }
      }
    },
    "/v1/subscriptions": {
      "post": {
        "summary": "A subscription as it is now",
        "description": "Bought, renewed, payment failed, cancelled or expired: send all of it.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Subscription"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Received.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WriteResult"
                }
              }
            }
          },
          "400": {
            "description": "Fix the data; do not resend as is.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Wrong or revoked key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Sent from a browser: keys belong on your server.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Over 20 requests a second: retry after `Retry-After`."
          }
        }
      }
    },
    "/v1/import": {
      "post": {
        "summary": "Old records, history only",
        "description": "Up to 500 records of any kinds; stored as history, no message goes out. Not needed when the site registers its address: Otomi then copies everything by itself.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Import"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Stored (all or nothing).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "const": true
                    },
                    "mode": {
                      "enum": ["test", "live"]
                    },
                    "imported": {
                      "type": "object",
                      "properties": {
                        "customers": {
                          "type": "integer"
                        },
                        "products": {
                          "type": "integer"
                        },
                        "orders": {
                          "type": "integer"
                        },
                        "subscriptions": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Fix the data; do not resend as is.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Wrong or revoked key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Sent from a browser: keys belong on your server.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Over 20 requests a second: retry after `Retry-After`."
          }
        }
      }
    },
    "/v1/hook": {
      "put": {
        "summary": "The site's address",
        "description": "Register once with a live key. Otomi tries it at once (signed `health`, then `changes`) and saves it only when it answers right; then it copies all your data by itself (history, no message) and every hour what changed. With `coupons` the address also makes discount codes.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SiteHook"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Saved (a test key checks and saves nothing).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "const": true
                    },
                    "mode": {
                      "enum": ["test", "live"]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Fix the data; do not resend as is.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Wrong or revoked key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Sent from a browser: keys belong on your server.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Over 20 requests a second: retry after `Retry-After`."
          }
        }
      }
    }
  },
  "webhooks": {
    "changes": {
      "post": {
        "summary": "Command `changes`",
        "description": "Records of `kind` changed at or after `since`, oldest first, at most `limit`, in the same shapes as the writes (each with `updatedAt`); `hasMore` when more are waiting.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["command", "params"],
                "properties": {
                  "command": {
                    "const": "changes"
                  },
                  "params": {
                    "type": "object",
                    "required": ["kind", "since", "limit"],
                    "properties": {
                      "kind": {
                        "enum": ["customers", "products", "orders", "subscriptions"]
                      },
                      "since": {
                        "type": "string",
                        "format": "date-time"
                      },
                      "limit": {
                        "type": "integer",
                        "maximum": 100
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Signed answer.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "title": "customers",
                      "type": "object",
                      "properties": {
                        "items": {
                          "maxItems": 100,
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "string",
                                "pattern": "^[A-Za-z0-9][A-Za-z0-9_.-]{0,63}$"
                              },
                              "mobile": {
                                "type": "string",
                                "maxLength": 40
                              },
                              "email": {
                                "type": "string",
                                "maxLength": 254
                              },
                              "firstName": {
                                "type": "string",
                                "maxLength": 100
                              },
                              "lastName": {
                                "type": "string",
                                "maxLength": 100
                              },
                              "city": {
                                "type": "string",
                                "maxLength": 100
                              },
                              "province": {
                                "type": "string",
                                "maxLength": 40
                              },
                              "registeredAt": {
                                "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)))$"
                              },
                              "lastLoginAt": {
                                "anyOf": [
                                  {
                                    "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)))$"
                                  },
                                  {
                                    "type": "null"
                                  }
                                ]
                              },
                              "loginCount": {
                                "type": "integer",
                                "minimum": 0,
                                "maximum": 1000000000
                              },
                              "source": {
                                "type": "string",
                                "maxLength": 100
                              },
                              "updatedAt": {
                                "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": ["id"],
                            "additionalProperties": false
                          }
                        },
                        "hasMore": {
                          "type": "boolean"
                        }
                      },
                      "required": ["items", "hasMore"],
                      "additionalProperties": false
                    },
                    {
                      "title": "products",
                      "type": "object",
                      "properties": {
                        "items": {
                          "maxItems": 100,
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "string",
                                "pattern": "^[A-Za-z0-9][A-Za-z0-9_.-]{0,63}$"
                              },
                              "name": {
                                "type": "string",
                                "maxLength": 300
                              },
                              "url": {
                                "type": "string",
                                "maxLength": 2048,
                                "format": "uri"
                              },
                              "price": {
                                "anyOf": [
                                  {
                                    "anyOf": [
                                      {
                                        "type": "string",
                                        "pattern": "^\\d{1,15}(\\.\\d{1,6})?$"
                                      },
                                      {
                                        "type": "number",
                                        "minimum": 0,
                                        "maximum": 999999999999999
                                      }
                                    ]
                                  },
                                  {
                                    "type": "null"
                                  }
                                ]
                              },
                              "salePrice": {
                                "anyOf": [
                                  {
                                    "anyOf": [
                                      {
                                        "type": "string",
                                        "pattern": "^\\d{1,15}(\\.\\d{1,6})?$"
                                      },
                                      {
                                        "type": "number",
                                        "minimum": 0,
                                        "maximum": 999999999999999
                                      }
                                    ]
                                  },
                                  {
                                    "type": "null"
                                  }
                                ]
                              },
                              "stock": {
                                "anyOf": [
                                  {
                                    "type": "integer",
                                    "minimum": -1000000000,
                                    "maximum": 1000000000
                                  },
                                  {
                                    "type": "null"
                                  }
                                ]
                              },
                              "active": {
                                "type": "boolean"
                              },
                              "categories": {
                                "maxItems": 50,
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "id": {
                                      "type": "string",
                                      "pattern": "^[A-Za-z0-9][A-Za-z0-9_.-]{0,63}$"
                                    },
                                    "name": {
                                      "type": "string",
                                      "maxLength": 200
                                    },
                                    "url": {
                                      "type": "string",
                                      "maxLength": 2048,
                                      "format": "uri"
                                    }
                                  },
                                  "required": ["id", "name"],
                                  "additionalProperties": false
                                }
                              },
                              "attributes": {
                                "maxItems": 200,
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "name": {
                                      "type": "string",
                                      "maxLength": 100
                                    },
                                    "value": {
                                      "type": "string",
                                      "maxLength": 100
                                    }
                                  },
                                  "required": ["name", "value"],
                                  "additionalProperties": false
                                }
                              },
                              "updatedAt": {
                                "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": ["id", "name"],
                            "additionalProperties": false
                          }
                        },
                        "hasMore": {
                          "type": "boolean"
                        }
                      },
                      "required": ["items", "hasMore"],
                      "additionalProperties": false
                    },
                    {
                      "title": "orders",
                      "type": "object",
                      "properties": {
                        "items": {
                          "maxItems": 100,
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "string",
                                "pattern": "^[A-Za-z0-9][A-Za-z0-9_.-]{0,63}$"
                              },
                              "status": {
                                "type": "string",
                                "enum": [
                                  "pending_payment",
                                  "paid",
                                  "processing",
                                  "shipped",
                                  "delivered",
                                  "completed",
                                  "cancelled",
                                  "refunded"
                                ]
                              },
                              "paid": {
                                "type": "boolean"
                              },
                              "total": {
                                "anyOf": [
                                  {
                                    "type": "string",
                                    "pattern": "^\\d{1,15}(\\.\\d{1,6})?$"
                                  },
                                  {
                                    "type": "number",
                                    "minimum": 0,
                                    "maximum": 999999999999999
                                  }
                                ]
                              },
                              "currency": {
                                "type": "string",
                                "enum": ["IRT", "IRR"]
                              },
                              "refunded": {
                                "anyOf": [
                                  {
                                    "type": "string",
                                    "pattern": "^\\d{1,15}(\\.\\d{1,6})?$"
                                  },
                                  {
                                    "type": "number",
                                    "minimum": 0,
                                    "maximum": 999999999999999
                                  }
                                ]
                              },
                              "discountTotal": {
                                "anyOf": [
                                  {
                                    "type": "string",
                                    "pattern": "^\\d{1,15}(\\.\\d{1,6})?$"
                                  },
                                  {
                                    "type": "number",
                                    "minimum": 0,
                                    "maximum": 999999999999999
                                  }
                                ]
                              },
                              "customer": {
                                "type": "object",
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "pattern": "^[A-Za-z0-9][A-Za-z0-9_.-]{0,63}$"
                                  },
                                  "mobile": {
                                    "type": "string",
                                    "maxLength": 40
                                  },
                                  "email": {
                                    "type": "string",
                                    "maxLength": 254
                                  },
                                  "firstName": {
                                    "type": "string",
                                    "maxLength": 100
                                  },
                                  "lastName": {
                                    "type": "string",
                                    "maxLength": 100
                                  },
                                  "city": {
                                    "type": "string",
                                    "maxLength": 100
                                  },
                                  "province": {
                                    "type": "string",
                                    "maxLength": 40
                                  }
                                },
                                "additionalProperties": false
                              },
                              "items": {
                                "maxItems": 500,
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "productId": {
                                      "type": "string",
                                      "pattern": "^[A-Za-z0-9][A-Za-z0-9_.-]{0,63}$"
                                    },
                                    "quantity": {
                                      "default": 1,
                                      "type": "integer",
                                      "minimum": 1,
                                      "maximum": 1000000
                                    }
                                  },
                                  "required": ["productId"],
                                  "additionalProperties": false
                                }
                              },
                              "coupons": {
                                "maxItems": 50,
                                "type": "array",
                                "items": {
                                  "type": "string",
                                  "maxLength": 100
                                }
                              },
                              "paymentMethod": {
                                "type": "string",
                                "pattern": "^[\\p{L}\\p{N}_.:%-]{1,100}$"
                              },
                              "shippingMethod": {
                                "type": "string",
                                "pattern": "^[\\p{L}\\p{N}_.:%-]{1,100}$"
                              },
                              "source": {
                                "type": "string",
                                "maxLength": 100
                              },
                              "createdAt": {
                                "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)))$"
                              },
                              "paidAt": {
                                "anyOf": [
                                  {
                                    "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)))$"
                                  },
                                  {
                                    "type": "null"
                                  }
                                ]
                              },
                              "updatedAt": {
                                "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)))$"
                              },
                              "subscription": {
                                "type": "object",
                                "properties": {
                                  "plan": {
                                    "type": "string",
                                    "maxLength": 100
                                  },
                                  "periodEnd": {
                                    "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": ["plan", "periodEnd"],
                                "additionalProperties": false
                              }
                            },
                            "required": ["id", "status", "total", "customer"],
                            "additionalProperties": false
                          }
                        },
                        "hasMore": {
                          "type": "boolean"
                        }
                      },
                      "required": ["items", "hasMore"],
                      "additionalProperties": false
                    },
                    {
                      "title": "subscriptions",
                      "type": "object",
                      "properties": {
                        "items": {
                          "maxItems": 100,
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "string",
                                "pattern": "^[A-Za-z0-9][A-Za-z0-9_.-]{0,63}$"
                              },
                              "customer": {
                                "type": "object",
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "pattern": "^[A-Za-z0-9][A-Za-z0-9_.-]{0,63}$"
                                  },
                                  "mobile": {
                                    "type": "string",
                                    "maxLength": 40
                                  },
                                  "email": {
                                    "type": "string",
                                    "maxLength": 254
                                  },
                                  "firstName": {
                                    "type": "string",
                                    "maxLength": 100
                                  },
                                  "lastName": {
                                    "type": "string",
                                    "maxLength": 100
                                  },
                                  "city": {
                                    "type": "string",
                                    "maxLength": 100
                                  },
                                  "province": {
                                    "type": "string",
                                    "maxLength": 40
                                  }
                                },
                                "additionalProperties": false
                              },
                              "plan": {
                                "type": "string",
                                "maxLength": 100
                              },
                              "status": {
                                "type": "string",
                                "enum": ["trialing", "active", "past_due", "cancelled", "expired"]
                              },
                              "currentPeriodEnd": {
                                "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)))$"
                              },
                              "startedAt": {
                                "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)))$"
                              },
                              "autoRenew": {
                                "type": "boolean"
                              },
                              "price": {
                                "anyOf": [
                                  {
                                    "type": "string",
                                    "pattern": "^\\d{1,15}(\\.\\d{1,6})?$"
                                  },
                                  {
                                    "type": "number",
                                    "minimum": 0,
                                    "maximum": 999999999999999
                                  }
                                ]
                              },
                              "currency": {
                                "type": "string",
                                "enum": ["IRT", "IRR"]
                              },
                              "updatedAt": {
                                "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": ["id", "customer", "plan", "status", "currentPeriodEnd"],
                            "additionalProperties": false
                          }
                        },
                        "hasMore": {
                          "type": "boolean"
                        }
                      },
                      "required": ["items", "hasMore"],
                      "additionalProperties": false
                    }
                  ]
                }
              }
            }
          }
        }
      }
    },
    "health": {
      "post": {
        "summary": "Command `health`",
        "description": "Any small JSON object.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["command", "params"],
                "properties": {
                  "command": {
                    "const": "health"
                  },
                  "params": {
                    "type": "object"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Signed answer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "`osk_test_…` or `osk_live_…`, from the store page in the Otomi app."
      }
    },
    "schemas": {
      "Order": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^[A-Za-z0-9][A-Za-z0-9_.-]{0,63}$"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending_payment",
              "paid",
              "processing",
              "shipped",
              "delivered",
              "completed",
              "cancelled",
              "refunded"
            ]
          },
          "paid": {
            "type": "boolean"
          },
          "total": {
            "anyOf": [
              {
                "type": "string",
                "pattern": "^\\d{1,15}(\\.\\d{1,6})?$"
              },
              {
                "type": "number",
                "minimum": 0,
                "maximum": 999999999999999
              }
            ]
          },
          "currency": {
            "type": "string",
            "enum": ["IRT", "IRR"]
          },
          "refunded": {
            "anyOf": [
              {
                "type": "string",
                "pattern": "^\\d{1,15}(\\.\\d{1,6})?$"
              },
              {
                "type": "number",
                "minimum": 0,
                "maximum": 999999999999999
              }
            ]
          },
          "discountTotal": {
            "anyOf": [
              {
                "type": "string",
                "pattern": "^\\d{1,15}(\\.\\d{1,6})?$"
              },
              {
                "type": "number",
                "minimum": 0,
                "maximum": 999999999999999
              }
            ]
          },
          "customer": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "pattern": "^[A-Za-z0-9][A-Za-z0-9_.-]{0,63}$"
              },
              "mobile": {
                "type": "string",
                "maxLength": 40
              },
              "email": {
                "type": "string",
                "maxLength": 254
              },
              "firstName": {
                "type": "string",
                "maxLength": 100
              },
              "lastName": {
                "type": "string",
                "maxLength": 100
              },
              "city": {
                "type": "string",
                "maxLength": 100
              },
              "province": {
                "type": "string",
                "maxLength": 40
              }
            },
            "additionalProperties": false
          },
          "items": {
            "maxItems": 500,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "productId": {
                  "type": "string",
                  "pattern": "^[A-Za-z0-9][A-Za-z0-9_.-]{0,63}$"
                },
                "quantity": {
                  "default": 1,
                  "type": "integer",
                  "minimum": 1,
                  "maximum": 1000000
                }
              },
              "required": ["productId"],
              "additionalProperties": false
            }
          },
          "coupons": {
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 100
            }
          },
          "paymentMethod": {
            "type": "string",
            "pattern": "^[\\p{L}\\p{N}_.:%-]{1,100}$"
          },
          "shippingMethod": {
            "type": "string",
            "pattern": "^[\\p{L}\\p{N}_.:%-]{1,100}$"
          },
          "source": {
            "type": "string",
            "maxLength": 100
          },
          "createdAt": {
            "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)))$"
          },
          "paidAt": {
            "anyOf": [
              {
                "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)))$"
              },
              {
                "type": "null"
              }
            ]
          },
          "updatedAt": {
            "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)))$"
          },
          "subscription": {
            "type": "object",
            "properties": {
              "plan": {
                "type": "string",
                "maxLength": 100
              },
              "periodEnd": {
                "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": ["plan", "periodEnd"],
            "additionalProperties": false
          }
        },
        "required": ["id", "status", "total", "customer"],
        "additionalProperties": false
      },
      "Customer": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^[A-Za-z0-9][A-Za-z0-9_.-]{0,63}$"
          },
          "mobile": {
            "type": "string",
            "maxLength": 40
          },
          "email": {
            "type": "string",
            "maxLength": 254
          },
          "firstName": {
            "type": "string",
            "maxLength": 100
          },
          "lastName": {
            "type": "string",
            "maxLength": 100
          },
          "city": {
            "type": "string",
            "maxLength": 100
          },
          "province": {
            "type": "string",
            "maxLength": 40
          },
          "registeredAt": {
            "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)))$"
          },
          "lastLoginAt": {
            "anyOf": [
              {
                "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)))$"
              },
              {
                "type": "null"
              }
            ]
          },
          "loginCount": {
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "source": {
            "type": "string",
            "maxLength": 100
          },
          "updatedAt": {
            "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": ["id"],
        "additionalProperties": false
      },
      "Product": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^[A-Za-z0-9][A-Za-z0-9_.-]{0,63}$"
          },
          "name": {
            "type": "string",
            "maxLength": 300
          },
          "url": {
            "type": "string",
            "maxLength": 2048,
            "format": "uri"
          },
          "price": {
            "anyOf": [
              {
                "anyOf": [
                  {
                    "type": "string",
                    "pattern": "^\\d{1,15}(\\.\\d{1,6})?$"
                  },
                  {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 999999999999999
                  }
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "salePrice": {
            "anyOf": [
              {
                "anyOf": [
                  {
                    "type": "string",
                    "pattern": "^\\d{1,15}(\\.\\d{1,6})?$"
                  },
                  {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 999999999999999
                  }
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "stock": {
            "anyOf": [
              {
                "type": "integer",
                "minimum": -1000000000,
                "maximum": 1000000000
              },
              {
                "type": "null"
              }
            ]
          },
          "active": {
            "type": "boolean"
          },
          "categories": {
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string",
                  "pattern": "^[A-Za-z0-9][A-Za-z0-9_.-]{0,63}$"
                },
                "name": {
                  "type": "string",
                  "maxLength": 200
                },
                "url": {
                  "type": "string",
                  "maxLength": 2048,
                  "format": "uri"
                }
              },
              "required": ["id", "name"],
              "additionalProperties": false
            }
          },
          "attributes": {
            "maxItems": 200,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string",
                  "maxLength": 100
                },
                "value": {
                  "type": "string",
                  "maxLength": 100
                }
              },
              "required": ["name", "value"],
              "additionalProperties": false
            }
          },
          "updatedAt": {
            "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": ["id", "name"],
        "additionalProperties": false
      },
      "Review": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^[A-Za-z0-9][A-Za-z0-9_.-]{0,63}$"
          },
          "productId": {
            "type": "string",
            "pattern": "^[A-Za-z0-9][A-Za-z0-9_.-]{0,63}$"
          },
          "rating": {
            "anyOf": [
              {
                "type": "integer",
                "minimum": 1,
                "maximum": 5
              },
              {
                "type": "null"
              }
            ]
          },
          "customer": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "pattern": "^[A-Za-z0-9][A-Za-z0-9_.-]{0,63}$"
              },
              "mobile": {
                "type": "string",
                "maxLength": 40
              },
              "email": {
                "type": "string",
                "maxLength": 254
              }
            },
            "additionalProperties": false
          },
          "createdAt": {
            "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": ["id", "productId", "customer"],
        "additionalProperties": false
      },
      "Subscription": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^[A-Za-z0-9][A-Za-z0-9_.-]{0,63}$"
          },
          "customer": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "pattern": "^[A-Za-z0-9][A-Za-z0-9_.-]{0,63}$"
              },
              "mobile": {
                "type": "string",
                "maxLength": 40
              },
              "email": {
                "type": "string",
                "maxLength": 254
              },
              "firstName": {
                "type": "string",
                "maxLength": 100
              },
              "lastName": {
                "type": "string",
                "maxLength": 100
              },
              "city": {
                "type": "string",
                "maxLength": 100
              },
              "province": {
                "type": "string",
                "maxLength": 40
              }
            },
            "additionalProperties": false
          },
          "plan": {
            "type": "string",
            "maxLength": 100
          },
          "status": {
            "type": "string",
            "enum": ["trialing", "active", "past_due", "cancelled", "expired"]
          },
          "currentPeriodEnd": {
            "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)))$"
          },
          "startedAt": {
            "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)))$"
          },
          "autoRenew": {
            "type": "boolean"
          },
          "price": {
            "anyOf": [
              {
                "type": "string",
                "pattern": "^\\d{1,15}(\\.\\d{1,6})?$"
              },
              {
                "type": "number",
                "minimum": 0,
                "maximum": 999999999999999
              }
            ]
          },
          "currency": {
            "type": "string",
            "enum": ["IRT", "IRR"]
          },
          "updatedAt": {
            "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": ["id", "customer", "plan", "status", "currentPeriodEnd"],
        "additionalProperties": false
      },
      "Import": {
        "type": "object",
        "properties": {
          "customers": {
            "maxItems": 500,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string",
                  "pattern": "^[A-Za-z0-9][A-Za-z0-9_.-]{0,63}$"
                },
                "mobile": {
                  "type": "string",
                  "maxLength": 40
                },
                "email": {
                  "type": "string",
                  "maxLength": 254
                },
                "firstName": {
                  "type": "string",
                  "maxLength": 100
                },
                "lastName": {
                  "type": "string",
                  "maxLength": 100
                },
                "city": {
                  "type": "string",
                  "maxLength": 100
                },
                "province": {
                  "type": "string",
                  "maxLength": 40
                },
                "registeredAt": {
                  "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)))$"
                },
                "lastLoginAt": {
                  "anyOf": [
                    {
                      "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)))$"
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "loginCount": {
                  "type": "integer",
                  "minimum": 0,
                  "maximum": 1000000000
                },
                "source": {
                  "type": "string",
                  "maxLength": 100
                },
                "updatedAt": {
                  "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": ["id"],
              "additionalProperties": false
            }
          },
          "products": {
            "maxItems": 500,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string",
                  "pattern": "^[A-Za-z0-9][A-Za-z0-9_.-]{0,63}$"
                },
                "name": {
                  "type": "string",
                  "maxLength": 300
                },
                "url": {
                  "type": "string",
                  "maxLength": 2048,
                  "format": "uri"
                },
                "price": {
                  "anyOf": [
                    {
                      "anyOf": [
                        {
                          "type": "string",
                          "pattern": "^\\d{1,15}(\\.\\d{1,6})?$"
                        },
                        {
                          "type": "number",
                          "minimum": 0,
                          "maximum": 999999999999999
                        }
                      ]
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "salePrice": {
                  "anyOf": [
                    {
                      "anyOf": [
                        {
                          "type": "string",
                          "pattern": "^\\d{1,15}(\\.\\d{1,6})?$"
                        },
                        {
                          "type": "number",
                          "minimum": 0,
                          "maximum": 999999999999999
                        }
                      ]
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "stock": {
                  "anyOf": [
                    {
                      "type": "integer",
                      "minimum": -1000000000,
                      "maximum": 1000000000
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "active": {
                  "type": "boolean"
                },
                "categories": {
                  "maxItems": 50,
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string",
                        "pattern": "^[A-Za-z0-9][A-Za-z0-9_.-]{0,63}$"
                      },
                      "name": {
                        "type": "string",
                        "maxLength": 200
                      },
                      "url": {
                        "type": "string",
                        "maxLength": 2048,
                        "format": "uri"
                      }
                    },
                    "required": ["id", "name"],
                    "additionalProperties": false
                  }
                },
                "attributes": {
                  "maxItems": 200,
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "name": {
                        "type": "string",
                        "maxLength": 100
                      },
                      "value": {
                        "type": "string",
                        "maxLength": 100
                      }
                    },
                    "required": ["name", "value"],
                    "additionalProperties": false
                  }
                },
                "updatedAt": {
                  "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": ["id", "name"],
              "additionalProperties": false
            }
          },
          "orders": {
            "maxItems": 500,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string",
                  "pattern": "^[A-Za-z0-9][A-Za-z0-9_.-]{0,63}$"
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "pending_payment",
                    "paid",
                    "processing",
                    "shipped",
                    "delivered",
                    "completed",
                    "cancelled",
                    "refunded"
                  ]
                },
                "paid": {
                  "type": "boolean"
                },
                "total": {
                  "anyOf": [
                    {
                      "type": "string",
                      "pattern": "^\\d{1,15}(\\.\\d{1,6})?$"
                    },
                    {
                      "type": "number",
                      "minimum": 0,
                      "maximum": 999999999999999
                    }
                  ]
                },
                "currency": {
                  "type": "string",
                  "enum": ["IRT", "IRR"]
                },
                "refunded": {
                  "anyOf": [
                    {
                      "type": "string",
                      "pattern": "^\\d{1,15}(\\.\\d{1,6})?$"
                    },
                    {
                      "type": "number",
                      "minimum": 0,
                      "maximum": 999999999999999
                    }
                  ]
                },
                "discountTotal": {
                  "anyOf": [
                    {
                      "type": "string",
                      "pattern": "^\\d{1,15}(\\.\\d{1,6})?$"
                    },
                    {
                      "type": "number",
                      "minimum": 0,
                      "maximum": 999999999999999
                    }
                  ]
                },
                "customer": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "pattern": "^[A-Za-z0-9][A-Za-z0-9_.-]{0,63}$"
                    },
                    "mobile": {
                      "type": "string",
                      "maxLength": 40
                    },
                    "email": {
                      "type": "string",
                      "maxLength": 254
                    },
                    "firstName": {
                      "type": "string",
                      "maxLength": 100
                    },
                    "lastName": {
                      "type": "string",
                      "maxLength": 100
                    },
                    "city": {
                      "type": "string",
                      "maxLength": 100
                    },
                    "province": {
                      "type": "string",
                      "maxLength": 40
                    }
                  },
                  "additionalProperties": false
                },
                "items": {
                  "maxItems": 500,
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "productId": {
                        "type": "string",
                        "pattern": "^[A-Za-z0-9][A-Za-z0-9_.-]{0,63}$"
                      },
                      "quantity": {
                        "default": 1,
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 1000000
                      }
                    },
                    "required": ["productId"],
                    "additionalProperties": false
                  }
                },
                "coupons": {
                  "maxItems": 50,
                  "type": "array",
                  "items": {
                    "type": "string",
                    "maxLength": 100
                  }
                },
                "paymentMethod": {
                  "type": "string",
                  "pattern": "^[\\p{L}\\p{N}_.:%-]{1,100}$"
                },
                "shippingMethod": {
                  "type": "string",
                  "pattern": "^[\\p{L}\\p{N}_.:%-]{1,100}$"
                },
                "source": {
                  "type": "string",
                  "maxLength": 100
                },
                "createdAt": {
                  "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)))$"
                },
                "paidAt": {
                  "anyOf": [
                    {
                      "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)))$"
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "updatedAt": {
                  "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)))$"
                },
                "subscription": {
                  "type": "object",
                  "properties": {
                    "plan": {
                      "type": "string",
                      "maxLength": 100
                    },
                    "periodEnd": {
                      "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": ["plan", "periodEnd"],
                  "additionalProperties": false
                }
              },
              "required": ["id", "status", "total", "customer"],
              "additionalProperties": false
            }
          },
          "subscriptions": {
            "maxItems": 500,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string",
                  "pattern": "^[A-Za-z0-9][A-Za-z0-9_.-]{0,63}$"
                },
                "customer": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "pattern": "^[A-Za-z0-9][A-Za-z0-9_.-]{0,63}$"
                    },
                    "mobile": {
                      "type": "string",
                      "maxLength": 40
                    },
                    "email": {
                      "type": "string",
                      "maxLength": 254
                    },
                    "firstName": {
                      "type": "string",
                      "maxLength": 100
                    },
                    "lastName": {
                      "type": "string",
                      "maxLength": 100
                    },
                    "city": {
                      "type": "string",
                      "maxLength": 100
                    },
                    "province": {
                      "type": "string",
                      "maxLength": 40
                    }
                  },
                  "additionalProperties": false
                },
                "plan": {
                  "type": "string",
                  "maxLength": 100
                },
                "status": {
                  "type": "string",
                  "enum": ["trialing", "active", "past_due", "cancelled", "expired"]
                },
                "currentPeriodEnd": {
                  "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)))$"
                },
                "startedAt": {
                  "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)))$"
                },
                "autoRenew": {
                  "type": "boolean"
                },
                "price": {
                  "anyOf": [
                    {
                      "type": "string",
                      "pattern": "^\\d{1,15}(\\.\\d{1,6})?$"
                    },
                    {
                      "type": "number",
                      "minimum": 0,
                      "maximum": 999999999999999
                    }
                  ]
                },
                "currency": {
                  "type": "string",
                  "enum": ["IRT", "IRR"]
                },
                "updatedAt": {
                  "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": ["id", "customer", "plan", "status", "currentPeriodEnd"],
              "additionalProperties": false
            }
          }
        },
        "additionalProperties": false
      },
      "SiteHook": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "maxLength": 2048,
            "format": "uri"
          },
          "keyId": {
            "type": "string",
            "pattern": "^ok_[A-Za-z0-9_-]{22}$"
          },
          "secret": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{43}$"
          },
          "coupons": {
            "type": "object",
            "properties": {
              "hourlyLimit": {
                "type": "integer",
                "minimum": 1,
                "maximum": 20000
              },
              "percentCap": {
                "type": "boolean"
              }
            },
            "required": ["hourlyLimit", "percentCap"],
            "additionalProperties": false
          }
        },
        "required": ["url", "keyId", "secret"],
        "additionalProperties": false
      },
      "WriteResult": {
        "type": "object",
        "required": ["ok", "mode", "events"],
        "properties": {
          "ok": {
            "const": true
          },
          "mode": {
            "enum": ["test", "live"]
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "What the record caused, e.g. [\"order.created\"]; [] = nothing new."
          }
        }
      },
      "Error": {
        "type": "object",
        "required": ["code", "message"],
        "properties": {
          "code": {
            "type": "string",
            "examples": ["validation", "unauthorized", "rate_limited"]
          },
          "message": {
            "type": "string"
          },
          "requestId": {
            "type": "string"
          },
          "issues": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "path": {
                  "type": "array",
                  "items": {
                    "type": ["string", "integer"]
                  }
                },
                "code": {
                  "type": "string",
                  "examples": ["mobile_or_email_required", "url_not_on_site"]
                }
              }
            }
          }
        }
      }
    }
  }
}
