{
  "openapi": "3.1.0",
  "info": {
    "title": "Otherwise API",
    "version": "1.0.0",
    "description": "Build and run Shopify Functions as flows. Every operation is also a tool at the app's MCP address. Saving never changes checkout: only publish, pause, delete and adding codes do. A connection can make 120 calls a minute. An answer with status 429 means it made more: wait a minute, then carry on from where you were."
  },
  "servers": [
    {
      "url": "https://functions.otherwise.run/api/v1"
    }
  ],
  "security": [
    {
      "token": []
    }
  ],
  "paths": {
    "/store": {
      "get": {
        "operationId": "get_store",
        "summary": "See which store this is",
        "description": "The one Shopify store this connection works in: its name, address, currency and time zone, the plan it is on, how many functions that plan runs at once and how many are live now. Call it first. Needs a token that may: read.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Done. `ok` is true, with what the operation answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Done"
                }
              }
            }
          },
          "default": {
            "description": "Not done. `ok` is false, with why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotDone"
                }
              }
            }
          }
        }
      }
    },
    "/products/search": {
      "post": {
        "operationId": "find_products",
        "summary": "Find products",
        "description": "Finds products in this store by name, or by an id the merchant gave. Returns each one's id, title, price, tags, type and vendor. Use it for every product a flow or a test cart names: ids from another store or another connector don't exist here. Needs a token that may: read.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "query": {
                    "type": "string",
                    "minLength": 1,
                    "description": "Words from the product's name, or its id"
                  },
                  "limit": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 25
                  }
                },
                "required": [
                  "query"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Done. `ok` is true, with what the operation answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Done"
                }
              }
            }
          },
          "default": {
            "description": "Not done. `ok` is false, with why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotDone"
                }
              }
            }
          }
        }
      }
    },
    "/collections/search": {
      "post": {
        "operationId": "find_collections",
        "summary": "Find collections",
        "description": "Finds collections in this store by name. Returns each one's id, title and handle. Use it for every collection a flow names. Needs a token that may: read.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "query": {
                    "type": "string",
                    "minLength": 1,
                    "description": "Words from the collection's name"
                  },
                  "limit": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 25
                  }
                },
                "required": [
                  "query"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Done. `ok` is true, with what the operation answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Done"
                }
              }
            }
          },
          "default": {
            "description": "Not done. `ok` is false, with why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotDone"
                }
              }
            }
          }
        }
      }
    },
    "/functions": {
      "get": {
        "operationId": "list_functions",
        "summary": "List functions",
        "description": "Lists the store's functions: id, name, type, whether each is active, a draft or paused, and whether it has changes that aren't published. Needs a token that may: read.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Done. `ok` is true, with what the operation answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Done"
                }
              }
            }
          },
          "default": {
            "description": "Not done. `ok` is false, with why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotDone"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "create_function",
        "summary": "Create a function",
        "description": "Creates a new function from a whole flow and saves it as a draft. Nothing runs at checkout until it is published. Needs a token that may: read and draft.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "enum": [
                      "discount",
                      "validation",
                      "delivery",
                      "payment",
                      "cartTransform"
                    ],
                    "description": "discount, validation, delivery, payment or cartTransform"
                  },
                  "flow": {
                    "type": "object",
                    "properties": {
                      "settings": {
                        "type": "object",
                        "propertyNames": {
                          "type": "string"
                        },
                        "additionalProperties": {}
                      },
                      "steps": {
                        "maxItems": 200,
                        "type": "array",
                        "items": {
                          "type": "object",
                          "propertyNames": {
                            "type": "string"
                          },
                          "additionalProperties": {}
                        }
                      }
                    },
                    "required": [
                      "steps"
                    ],
                    "additionalProperties": false,
                    "description": "The whole flow: { settings, steps }. `settings` are the start step's. Each step is { id, type, settings, after, output }. Call list_step_types for the step types, their settings and the rule fields. Product and collection ids come from find_products and find_collections."
                  }
                },
                "required": [
                  "type",
                  "flow"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Done. `ok` is true, with what the operation answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Done"
                }
              }
            }
          },
          "default": {
            "description": "Not done. `ok` is false, with why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotDone"
                }
              }
            }
          }
        }
      }
    },
    "/functions/{id}": {
      "get": {
        "operationId": "get_function",
        "summary": "Read a function",
        "description": "Reads one function: its status and its whole flow, step by step, with any problems that would stop it being published. Needs a token that may: read.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "description": "A function id from list_functions"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Done. `ok` is true, with what the operation answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Done"
                }
              }
            }
          },
          "default": {
            "description": "Not done. `ok` is false, with why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotDone"
                }
              }
            }
          }
        }
      },
      "put": {
        "operationId": "update_function",
        "summary": "Change a function's flow",
        "description": "Replaces a function's flow with a new whole flow and saves it as a new version. Checkout keeps running the published version until publish_function is called. Read the function first and send back the complete flow. Needs a token that may: read and draft.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "description": "A function id from list_functions"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "flow": {
                    "type": "object",
                    "properties": {
                      "settings": {
                        "type": "object",
                        "propertyNames": {
                          "type": "string"
                        },
                        "additionalProperties": {}
                      },
                      "steps": {
                        "maxItems": 200,
                        "type": "array",
                        "items": {
                          "type": "object",
                          "propertyNames": {
                            "type": "string"
                          },
                          "additionalProperties": {}
                        }
                      }
                    },
                    "required": [
                      "steps"
                    ],
                    "additionalProperties": false,
                    "description": "The whole flow: { settings, steps }. `settings` are the start step's. Each step is { id, type, settings, after, output }. Call list_step_types for the step types, their settings and the rule fields. Product and collection ids come from find_products and find_collections."
                  }
                },
                "required": [
                  "flow"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Done. `ok` is true, with what the operation answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Done"
                }
              }
            }
          },
          "default": {
            "description": "Not done. `ok` is false, with why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotDone"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "delete_function",
        "summary": "Delete a function",
        "description": "Deletes a function for good, with its version history. An active one stops applying at checkout at once, and its discount is removed from Shopify. This can't be undone, so only call it when the merchant has asked for that function to be deleted. Needs a token that may: read, draft and publish.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "description": "A function id from list_functions"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Done. `ok` is true, with what the operation answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Done"
                }
              }
            }
          },
          "default": {
            "description": "Not done. `ok` is false, with why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotDone"
                }
              }
            }
          }
        }
      }
    },
    "/step-types/{type}": {
      "get": {
        "operationId": "list_step_types",
        "summary": "List step types",
        "description": "The step types a function of one type can use, each with its settings, plus the fields rules can test. Call this before writing a flow. Needs a token that may: read.",
        "parameters": [
          {
            "name": "type",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "discount",
                "validation",
                "delivery",
                "payment",
                "cartTransform"
              ],
              "description": "discount, validation, delivery, payment or cartTransform"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Done. `ok` is true, with what the operation answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Done"
                }
              }
            }
          },
          "default": {
            "description": "Not done. `ok` is false, with why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotDone"
                }
              }
            }
          }
        }
      }
    },
    "/templates/search": {
      "post": {
        "operationId": "list_templates",
        "summary": "List ready-made flows",
        "description": "The ready-made flows the app ships with, for common requests: buy one get one, free shipping over an amount, a sale on tagged products, a minimum order, and more. Each is known to work. When one is close to what the merchant asked for, read it with get_template and change it, instead of writing a flow from nothing. Needs a token that may: read.",
        "parameters": [],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "enum": [
                      "discount",
                      "validation",
                      "delivery",
                      "payment",
                      "cartTransform"
                    ],
                    "description": "discount, validation, delivery, payment or cartTransform"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Done. `ok` is true, with what the operation answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Done"
                }
              }
            }
          },
          "default": {
            "description": "Not done. `ok` is false, with why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotDone"
                }
              }
            }
          }
        }
      }
    },
    "/templates/{id}": {
      "get": {
        "operationId": "get_template",
        "summary": "Read a ready-made flow",
        "description": "One ready-made flow, written as create_function takes it. Change the amounts, tags and names to what the merchant asked for and pass it to create_function. Needs a token that may: read.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "description": "A template id from list_templates"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Done. `ok` is true, with what the operation answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Done"
                }
              }
            }
          },
          "default": {
            "description": "Not done. `ok` is false, with why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotDone"
                }
              }
            }
          }
        }
      }
    },
    "/functions/{id}/duplicate": {
      "post": {
        "operationId": "duplicate_function",
        "summary": "Duplicate a function",
        "description": "Copies a function as a new draft named \"Copy of …\", with the same flow. A copied code discount starts without a code, because a code can belong to one discount only. Needs a token that may: read and draft.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "description": "A function id from list_functions"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Done. `ok` is true, with what the operation answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Done"
                }
              }
            }
          },
          "default": {
            "description": "Not done. `ok` is false, with why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotDone"
                }
              }
            }
          }
        }
      }
    },
    "/functions/{id}/test": {
      "post": {
        "operationId": "test_function",
        "summary": "Test a function on sample carts",
        "description": "Runs a function's saved flow on carts you describe and says what each cart gets and why: the money off, free shipping, a blocked checkout, hidden options. It is the same engine checkout runs, on this store's real products, and nothing is saved or changed. Send several carts in one call, on both sides of every threshold in the flow (just under, just over), and one that shouldn't qualify at all. Do this before publishing and tell the merchant the results. Needs a token that may: read.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "description": "A function id from list_functions"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "carts": {
                    "minItems": 1,
                    "maxItems": 10,
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "description": "What to call this cart in the answer, such as \"just under $500\"",
                          "type": "string"
                        },
                        "lines": {
                          "maxItems": 50,
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "product": {
                                "type": "string",
                                "description": "A product id from find_products"
                              },
                              "quantity": {
                                "description": "1 when left out",
                                "type": "integer",
                                "minimum": 1,
                                "maximum": 10000
                              },
                              "price": {
                                "description": "One unit's price for this test, in the store's currency, to land on an exact subtotal. The product's own price when left out.",
                                "type": "number",
                                "minimum": 0
                              },
                              "property_value": {
                                "description": "The value of the line item property the flow's rule asks about, when it has one",
                                "type": "string"
                              }
                            },
                            "required": [
                              "product"
                            ],
                            "additionalProperties": false
                          }
                        },
                        "buyer": {
                          "description": "Who is buying. A guest when left out.",
                          "type": "object",
                          "properties": {
                            "signed_in": {
                              "type": "boolean"
                            },
                            "orders": {
                              "description": "How many orders the customer has placed before",
                              "type": "integer",
                              "minimum": 0,
                              "maximum": 9007199254740991
                            },
                            "tags": {
                              "description": "The customer's tags",
                              "maxItems": 100,
                              "type": "array",
                              "items": {
                                "type": "string"
                              }
                            },
                            "b2b": {
                              "type": "boolean"
                            },
                            "country": {
                              "description": "Two-letter country code, such as CA",
                              "type": "string"
                            }
                          },
                          "additionalProperties": false
                        },
                        "codes": {
                          "description": "Discount codes typed at checkout",
                          "maxItems": 100,
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "cart_attribute_value": {
                          "description": "The value of the cart attribute the flow's rule asks about, when it has one",
                          "type": "string"
                        },
                        "in_person": {
                          "description": "The order is rung up in Point of Sale",
                          "type": "boolean"
                        },
                        "outside_schedule": {
                          "description": "Test as if now were outside the flow's time window",
                          "type": "boolean"
                        },
                        "address": {
                          "description": "The shipping address on one line, for rules about it",
                          "type": "string"
                        },
                        "options": {
                          "description": "For delivery and payment functions: the delivery options or payment methods checkout offers, in order",
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "name": {
                                "type": "string"
                              },
                              "cost": {
                                "type": "number",
                                "minimum": 0
                              }
                            },
                            "required": [
                              "name"
                            ],
                            "additionalProperties": false
                          }
                        }
                      },
                      "required": [
                        "lines"
                      ],
                      "additionalProperties": false
                    }
                  }
                },
                "required": [
                  "carts"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Done. `ok` is true, with what the operation answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Done"
                }
              }
            }
          },
          "default": {
            "description": "Not done. `ok` is false, with why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotDone"
                }
              }
            }
          }
        }
      }
    },
    "/functions/{id}/publish": {
      "post": {
        "operationId": "publish_function",
        "summary": "Publish a function",
        "description": "Puts the function's latest saved version live at checkout: activates a draft or paused function, or publishes changes to an active one. Customers are affected at once, so only call it when the merchant has asked for it to go live. Needs a token that may: read, draft and publish.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "description": "A function id from list_functions"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Done. `ok` is true, with what the operation answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Done"
                }
              }
            }
          },
          "default": {
            "description": "Not done. `ok` is false, with why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotDone"
                }
              }
            }
          }
        }
      }
    },
    "/functions/{id}/pause": {
      "post": {
        "operationId": "pause_function",
        "summary": "Pause a function",
        "description": "Stops an active function from running at checkout. Its flow and versions are kept, and publish_function turns it back on. Needs a token that may: read, draft and publish.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "description": "A function id from list_functions"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Done. `ok` is true, with what the operation answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Done"
                }
              }
            }
          },
          "default": {
            "description": "Not done. `ok` is false, with why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotDone"
                }
              }
            }
          }
        }
      }
    },
    "/functions/{id}/codes": {
      "get": {
        "operationId": "list_discount_codes",
        "summary": "See a discount's bulk codes",
        "description": "For a function that is live as a code discount: how many codes the discount has in Shopify, and the bulk imports added through the app with how many codes each one added or couldn't add. Needs a token that may: read.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "description": "A function id from list_functions"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Done. `ok` is true, with what the operation answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Done"
                }
              }
            }
          },
          "default": {
            "description": "Not done. `ok` is false, with why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotDone"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "add_discount_codes",
        "summary": "Add discount codes in bulk",
        "description": "Adds many codes to a function that is live as a code discount, so each one follows the same flow. Give either `codes`, a list of your own, or `generate`, to have random ones made. Up to 10,000 at a time. They are sent to Shopify in the background: call list_discount_codes to follow it. Customers can use the codes as soon as they arrive, so only call it when the merchant has asked for them. Needs a token that may: read, draft and publish.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "description": "A function id from list_functions"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "codes": {
                    "description": "Codes to add as they are. Repeats and codes over 255 characters are left out.",
                    "maxItems": 10000,
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "generate": {
                    "type": "object",
                    "properties": {
                      "count": {
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 10000,
                        "description": "How many codes to make"
                      },
                      "prefix": {
                        "description": "Text every code starts with, such as VIP-",
                        "type": "string",
                        "maxLength": 20
                      },
                      "length": {
                        "description": "Random characters in each code. 8 when left out.",
                        "type": "integer",
                        "minimum": 6,
                        "maximum": 16
                      }
                    },
                    "required": [
                      "count"
                    ],
                    "additionalProperties": false
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Done. `ok` is true, with what the operation answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Done"
                }
              }
            }
          },
          "default": {
            "description": "Not done. `ok` is false, with why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotDone"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "token": {
        "type": "http",
        "scheme": "bearer",
        "description": "A token made on the app's Agents page, in the store's Shopify admin."
      }
    },
    "schemas": {
      "Done": {
        "type": "object",
        "required": [
          "ok"
        ],
        "properties": {
          "ok": {
            "const": true
          }
        },
        "additionalProperties": true
      },
      "NotDone": {
        "type": "object",
        "required": [
          "ok",
          "error"
        ],
        "properties": {
          "ok": {
            "const": false
          },
          "error": {
            "type": "string"
          },
          "problems": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "additionalProperties": true
      }
    }
  }
}