{
  "openapi": "3.1.0",
  "info": {
    "title": "EDIBridge Transform API",
    "version": "0.1.0",
    "description": "Any-to-any EDI/data transform plus a free Walmart 850 pre-flight compliance check. Also reachable via MCP at /mcp (tools: transform_document, validate_edi) — same engine, no separate logic. Currently a free preview across every route; launch prices will be $0.05/document for transform and $0.25/file for validate (10 free validations/day/IP).",
    "contact": {
      "url": "https://transform.edibridge.com"
    }
  },
  "servers": [
    {
      "url": "https://transform.edibridge.com",
      "description": "Production (canonical host)"
    },
    {
      "url": "https://edibridge-edge-api.alpaughscott.workers.dev",
      "description": "Workers.dev (dev/staging)"
    }
  ],
  "x-supported-directions": [
    "x12->json",
    "json->x12",
    "csv->json",
    "json->csv",
    "csv->x12"
  ],
  "paths": {
    "/v1/transform": {
      "post": {
        "summary": "Transform a document between formats",
        "description": "Bytes in, bytes out. `from`/`to` select the direction; only directions listed in `x-supported-directions` (top-level) are live — this list is generated from the same `SUPPORTED_DIRECTIONS` constant the Worker enforces at runtime, so it can never drift from `GET /v1/health`.",
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "x12",
                "json",
                "csv"
              ]
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "x12",
                "json",
                "csv"
              ]
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "The source document. Raw X12 text for from=x12, a canonical PurchaseOrder JSON object for from=json (see #/components/schemas/CanonicalPurchaseOrder), or CSV text conforming to #/components/schemas/CsvV1PurchaseOrderRow for from=csv.",
          "content": {
            "text/plain": {
              "schema": {
                "type": "string"
              }
            },
            "application/json": {
              "schema": {
                "type": "string"
              }
            },
            "text/csv": {
              "schema": {
                "type": "string"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Transformed document in the target format (unwrapped — the raw document, not a JSON envelope).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "string"
                }
              },
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              },
              "text/csv": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "MISSING_DIRECTION, UNSUPPORTED_DIRECTION, EMPTY_BODY, JSON_READ_ERROR, or CSV_READ_ERROR (non-conforming CSV — see #/components/schemas/CsvV1PurchaseOrderRow).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED — POST only.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "413": {
            "description": "BODY_TOO_LARGE — 1 MB cap.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "422": {
            "description": "PARSE_FAILED or GENERATION_ERROR (e.g. Target 856 missing SSCC-18).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED — 60 requests/60s per IP."
          }
        }
      }
    },
    "/v1/validate": {
      "post": {
        "summary": "Validate a raw X12 850 Purchase Order for structural compliance",
        "description": "The \"will Walmart reject this file?\" anxiety-relief product. Always returns 200 with a ValidationResult — an invalid document is a normal, expected answer (`valid: false` + `fatal` findings), not an HTTP error. Free tier: 10 validations/day/IP.",
        "parameters": [
          {
            "name": "profile",
            "in": "query",
            "required": false,
            "description": "Optional retailer ruleset applied on top of baseline structural checks.",
            "schema": {
              "type": "string",
              "enum": [
                "walmart"
              ]
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "text/plain": {
              "schema": {
                "type": "string",
                "description": "Raw X12 850 EDI text."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Validation result (always 200 — see description).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationResult"
                }
              }
            }
          },
          "400": {
            "description": "EMPTY_BODY or UNSUPPORTED_PROFILE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "405": {
            "description": "METHOD_NOT_ALLOWED — POST only."
          },
          "413": {
            "description": "BODY_TOO_LARGE — 1 MB cap."
          },
          "429": {
            "description": "RATE_LIMITED — free tier is 10/day/IP."
          }
        }
      }
    },
    "/v1/openapi.json": {
      "get": {
        "summary": "This OpenAPI document",
        "responses": {
          "200": {
            "description": "This spec.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/v1/health": {
      "get": {
        "summary": "Health check + live-supported-directions truth source",
        "description": "The single source of truth for what's actually shipped — never trust a marketing page or this spec over this endpoint's `supported_directions` array.",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "engine": {
                      "type": "string",
                      "description": "Canonical model version, e.g. \"cm.v1\"."
                    },
                    "supported_directions": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  },
                  "required": [
                    "ok",
                    "engine",
                    "supported_directions"
                  ]
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "ErrorEnvelope": {
        "type": "object",
        "description": "Every error response across every route shares this shape.",
        "properties": {
          "code": {
            "type": "string",
            "description": "Machine-readable error code.",
            "enum": [
              "MISSING_DIRECTION",
              "UNSUPPORTED_DIRECTION",
              "EMPTY_BODY",
              "BODY_TOO_LARGE",
              "METHOD_NOT_ALLOWED",
              "NOT_FOUND",
              "NOT_IMPLEMENTED",
              "PARSE_FAILED",
              "GENERATION_ERROR",
              "JSON_READ_ERROR",
              "CSV_READ_ERROR",
              "UNSUPPORTED_PROFILE",
              "RATE_LIMITED"
            ]
          },
          "message": {
            "type": "string"
          },
          "docs_url": {
            "type": "string"
          }
        },
        "required": [
          "code",
          "message",
          "docs_url"
        ]
      },
      "CsvV1PurchaseOrderRow": {
        "type": "object",
        "description": "v1 public CSV header contract (Andy-decided 2026-07-08, HANDOFF_BUILD_PLAN Task 5). ALL 12 columns must appear in the header row, in this exact order — the stateless anonymous lane does not accept a caller-supplied column mapping. Non-conforming CSV gets a 400 CSV_READ_ERROR that links here. Weird/unknown headers are not auto-mapped by this route; use /v1/map (AI mapping, not yet live) or the EDIBridge SaaS FieldMap builder for arbitrary schemas. One row = one line item; PO/ship-to columns repeat identically on every row of the same purchase order (one PO per file in v1 — mixed PO_Number values are rejected).",
        "properties": {
          "PO_Number": {
            "type": "string",
            "description": "Required, non-blank, identical on every row."
          },
          "Order_Date": {
            "type": "string",
            "description": "Required. \"YYYY-MM-DD\" or \"YYYYMMDD\"."
          },
          "Ship_To_Name": {
            "type": "string"
          },
          "Ship_To_Address": {
            "type": "string"
          },
          "Ship_To_City": {
            "type": "string"
          },
          "Ship_To_State": {
            "type": "string"
          },
          "Ship_To_Zip": {
            "type": "string"
          },
          "Item_UPC": {
            "type": "string"
          },
          "Item_Description": {
            "type": "string"
          },
          "Quantity": {
            "type": "string",
            "description": "Required. Numeric."
          },
          "Unit_Price": {
            "type": "string",
            "description": "Numeric if present."
          },
          "Unit_Of_Measure": {
            "type": "string",
            "description": "Defaults to \"EA\" if blank."
          }
        },
        "required": [
          "PO_Number",
          "Order_Date",
          "Quantity"
        ]
      },
      "CanonicalPurchaseOrder": {
        "type": "object",
        "description": "cm.v1 canonical Purchase Order — what X12 850s parse into, and what json->x12 (documentType=\"850\")/json->csv expect as input. See packages/transform-engine/src/canonical/purchase-order.ts for the authoritative shape; kept here as a pointer, not duplicated field-by-field, to avoid drift.",
        "properties": {
          "poNumber": {
            "type": "string"
          },
          "poDate": {
            "type": "string"
          },
          "parties": {
            "type": "array"
          },
          "lineItems": {
            "type": "array"
          }
        },
        "required": [
          "poNumber",
          "poDate",
          "parties",
          "lineItems"
        ]
      },
      "ValidationFinding": {
        "type": "object",
        "properties": {
          "severity": {
            "type": "string",
            "enum": [
              "fatal",
              "warning",
              "info"
            ]
          },
          "segment": {
            "type": "string",
            "description": "X12 segment tag, when applicable (e.g. \"BEG\", \"N1\")."
          },
          "element": {
            "type": "string",
            "description": "X12 element reference, when applicable (e.g. \"BEG03\")."
          },
          "code": {
            "type": "string",
            "enum": [
              "EMPTY_INPUT",
              "NOT_X12",
              "MISSING_ISA",
              "MISSING_GS",
              "MISSING_ST",
              "WRONG_TRANSACTION_SET",
              "MISSING_BEG",
              "MISSING_PO_NUMBER",
              "ENVELOPE_NOT_CLOSED",
              "CONTROL_NUMBER_MISMATCH",
              "SEGMENT_COUNT_MISMATCH",
              "NO_LINE_ITEMS",
              "LINE_COUNT_MISMATCH",
              "TEST_DATA",
              "WALMART_MISSING_SHIP_TO",
              "WALMART_MISSING_DEPT_NUMBER",
              "WALMART_MISSING_UPC",
              "WALMART_NOT_DSV_004010"
            ]
          },
          "message": {
            "type": "string"
          }
        },
        "required": [
          "severity",
          "code",
          "message"
        ]
      },
      "ValidationResult": {
        "type": "object",
        "properties": {
          "valid": {
            "type": "boolean",
            "description": "true iff no `fatal` finding is present."
          },
          "transaction_type": {
            "type": "string",
            "description": "ST01 value, e.g. \"850\"."
          },
          "control_numbers": {
            "type": "object",
            "properties": {
              "isa": {
                "type": "string"
              },
              "gs": {
                "type": "string"
              },
              "st": {
                "type": "string"
              }
            }
          },
          "findings": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ValidationFinding"
            }
          },
          "profile_applied": {
            "type": "string",
            "enum": [
              "none",
              "walmart"
            ]
          }
        },
        "required": [
          "valid",
          "transaction_type",
          "control_numbers",
          "findings",
          "profile_applied"
        ]
      }
    }
  }
}