{
 "openapi": "3.1.0",
 "info": {
  "title": "DreamWidget API",
  "version": "1.0.0",
  "description": "Embeddable Logo Showcase and Video Showcase widgets for any website. Build a widget, set its design, add logos or video sources, publish it to the CDN and read its counts. A plan term is bought with x402 at POST /api/v1/plan; everything else needs the API key that purchase (or the account page) gives you.",
  "x-guidance": "To buy a plan: POST /api/v1/plan with {\"plan\":\"pro\",\"term\":\"month\",\"email\":\"you@example.com\"}. The answer is 402 with the price in USDC on Base, USDC on Solana or XRP; pay and repeat the request with the PAYMENT-SIGNATURE header. A new email gets an account and its API key in the 200 answer. Then, with Authorization: Bearer dw_live_\u2026, POST /api/v1/widgets to make a widget (type logo or video), PATCH it with settings and logos, POST /api/v1/widgets/{id}/logos to add a logo from a URL, POST /api/v1/widgets/{id}/sources to add a YouTube channel or playlist, POST /api/v1/widgets/{id}/publish to put it on the CDN, and use the embed snippet returned. Prices: Single $6/month or $59/year (one widget of one kind), Basic $11 or $99, Pro $20 or $169 (five widgets of each kind), Studio $37 or $289. A term does not renew on its own. Full guide: https://dreamwidget.com/guides/api.html and https://dreamwidget.com/guides/x402.html",
  "contact": {
   "name": "DreamWidget",
   "email": "hello@dreamwidget.com",
   "url": "https://dreamwidget.com"
  },
  "termsOfService": "https://dreamwidget.com/terms.html"
 },
 "servers": [
  {
   "url": "https://dreamwidget.com"
  }
 ],
 "components": {
  "securitySchemes": {
   "apiKey": {
    "type": "http",
    "scheme": "bearer",
    "description": "An API key, dw_live_\u2026, from the x402 purchase or the account page."
   }
  }
 },
 "paths": {
  "/api/v1/plan": {
   "post": {
    "operationId": "buyPlan",
    "summary": "Buy a plan term with x402",
    "description": "Answers 402 with the price in USDC on Base, USDC on Solana or XRP. Repeat with the signed payment in PAYMENT-SIGNATURE. With an API key the plan goes on that account; without one, put an email in the body and a new email gets an account and its API key in the answer.",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "granted": {
           "type": "boolean"
          },
          "plan": {
           "type": "string"
          },
          "term": {
           "type": "string"
          },
          "until": {
           "type": "string",
           "format": "date-time"
          },
          "account": {
           "type": "string"
          },
          "apiKey": {
           "type": "string",
           "description": "Only when a new account was made: shown once, opens the API."
          },
          "paid": {
           "type": "object",
           "properties": {
            "network": {
             "type": "string"
            },
            "asset": {
             "type": "string"
            },
            "amount": {
             "type": "string"
            },
            "transaction": {
             "type": "string"
            },
            "payer": {
             "type": "string"
            }
           }
          },
          "note": {
           "type": "string"
          }
         },
         "required": [
          "granted",
          "plan",
          "term"
         ]
        }
       }
      }
     },
     "402": {
      "description": "Payment Required: x402 v2, PAYMENT-REQUIRED header with the price in USDC on Base (eip155:8453), USDC on Solana (solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp) and XRP (xrpl:0)."
     },
     "201": {
      "description": "Granted (same body as 200)"
     }
    },
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "plan": {
          "type": "string",
          "enum": [
           "single",
           "basic",
           "pro",
           "studio"
          ],
          "description": "The plan to buy. Single $6, Basic $11, Pro $20, Studio $37 a month; a year is $59, $99, $169, $289."
         },
         "term": {
          "type": "string",
          "enum": [
           "month",
           "year"
          ],
          "default": "month",
          "description": "How long the plan runs. It does not renew on its own; buy another before it ends and it continues."
         },
         "email": {
          "type": "string",
          "format": "email",
          "description": "Needed when paying without an API key: the account the plan goes on. A new email gets a new account and an API key in the answer; an existing account gets the plan and makes a key after signing in."
         }
        },
        "required": [
         "plan"
        ]
       }
      }
     }
    },
    "x-payment-info": {
     "price": {
      "mode": "dynamic",
      "currency": "USD",
      "min": "6.00",
      "max": "289.00"
     },
     "protocols": [
      {
       "x402": {}
      }
     ]
    }
   }
  },
  "/api/v1/me": {
   "get": {
    "operationId": "me",
    "summary": "The account, its plan and limits",
    "description": "Plan, limits (widgets per type, logos per widget, sources per tab) and when a prepaid term ends.",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "uid": {
           "type": "string"
          },
          "email": {
           "type": "string"
          },
          "plan": {
           "type": "string"
          },
          "limits": {
           "type": "object"
          },
          "widgets": {
           "type": "object"
          },
          "term": {
           "type": "object"
          }
         }
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/api/v1/widgets": {
   "get": {
    "operationId": "listWidgets",
    "summary": "List the account's widgets",
    "description": "",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "widgets": {
           "type": "array",
           "items": {
            "type": "object",
            "properties": {
             "id": {
              "type": "string"
             },
             "type": {
              "type": "string",
              "enum": [
               "logo",
               "video"
              ]
             },
             "name": {
              "type": "string"
             },
             "plan": {
              "type": "string"
             },
             "embed": {
              "type": "string",
              "description": "The iframe snippet to put on a web page."
             },
             "settings": {
              "type": "object"
             },
             "logos": {
              "type": "array",
              "items": {
               "type": "object"
              }
             },
             "groups": {
              "type": "array",
              "items": {
               "type": "object"
              }
             }
            }
           }
          }
         }
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   },
   "post": {
    "operationId": "createWidget",
    "summary": "Make a widget",
    "description": "A Logo Showcase (type logo) or a Video Showcase (type video) from the standard design, with the embed snippet in the answer.",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "widget": {
           "type": "object",
           "properties": {
            "id": {
             "type": "string"
            },
            "type": {
             "type": "string",
             "enum": [
              "logo",
              "video"
             ]
            },
            "name": {
             "type": "string"
            },
            "plan": {
             "type": "string"
            },
            "embed": {
             "type": "string",
             "description": "The iframe snippet to put on a web page."
            },
            "settings": {
             "type": "object"
            },
            "logos": {
             "type": "array",
             "items": {
              "type": "object"
             }
            },
            "groups": {
             "type": "array",
             "items": {
              "type": "object"
             }
            }
           }
          }
         }
        }
       }
      }
     }
    },
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "type": {
          "type": "string",
          "enum": [
           "logo",
           "video"
          ]
         },
         "name": {
          "type": "string"
         },
         "settings": {
          "type": "object"
         }
        },
        "required": [
         "type"
        ]
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/api/v1/widgets/{id}": {
   "get": {
    "operationId": "getWidget",
    "summary": "Read a widget",
    "description": "",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "widget": {
           "type": "object",
           "properties": {
            "id": {
             "type": "string"
            },
            "type": {
             "type": "string",
             "enum": [
              "logo",
              "video"
             ]
            },
            "name": {
             "type": "string"
            },
            "plan": {
             "type": "string"
            },
            "embed": {
             "type": "string",
             "description": "The iframe snippet to put on a web page."
            },
            "settings": {
             "type": "object"
            },
            "logos": {
             "type": "array",
             "items": {
              "type": "object"
             }
            },
            "groups": {
             "type": "array",
             "items": {
              "type": "object"
             }
            }
           }
          }
         }
        }
       }
      }
     }
    },
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The widget id"
     }
    ],
    "security": [
     {
      "apiKey": []
     }
    ]
   },
   "patch": {
    "operationId": "updateWidget",
    "summary": "Change a widget",
    "description": "Rename, merge settings, replace the logo list or the video tabs.",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "widget": {
           "type": "object",
           "properties": {
            "id": {
             "type": "string"
            },
            "type": {
             "type": "string",
             "enum": [
              "logo",
              "video"
             ]
            },
            "name": {
             "type": "string"
            },
            "plan": {
             "type": "string"
            },
            "embed": {
             "type": "string",
             "description": "The iframe snippet to put on a web page."
            },
            "settings": {
             "type": "object"
            },
            "logos": {
             "type": "array",
             "items": {
              "type": "object"
             }
            },
            "groups": {
             "type": "array",
             "items": {
              "type": "object"
             }
            }
           }
          }
         }
        }
       }
      }
     }
    },
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "name": {
          "type": "string"
         },
         "settings": {
          "type": "object"
         },
         "logos": {
          "type": "array",
          "items": {
           "type": "object"
          }
         },
         "groups": {
          "type": "array",
          "items": {
           "type": "object"
          }
         }
        }
       }
      }
     }
    },
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The widget id"
     }
    ],
    "security": [
     {
      "apiKey": []
     }
    ]
   },
   "delete": {
    "operationId": "deleteWidget",
    "summary": "Delete a widget",
    "description": "Takes it off the CDN too.",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "deleted": {
           "type": "boolean"
          }
         }
        }
       }
      }
     }
    },
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The widget id"
     }
    ],
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/api/v1/widgets/{id}/logos": {
   "post": {
    "operationId": "addLogo",
    "summary": "Add a logo from a URL",
    "description": "The image is fetched, stored on the CDN and added to the widget's list.",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "logo": {
           "type": "object"
          }
         }
        }
       }
      }
     }
    },
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "url": {
          "type": "string",
          "format": "uri"
         },
         "name": {
          "type": "string"
         },
         "link": {
          "type": "string",
          "format": "uri"
         }
        },
        "required": [
         "url"
        ]
       }
      }
     }
    },
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The widget id"
     }
    ],
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/api/v1/widgets/{id}/sources": {
   "post": {
    "operationId": "addSource",
    "summary": "Add a video source into a tab",
    "description": "A YouTube playlist id, a link with list=, a channel link or an @handle; or another provider's reference.",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "tab": {
           "type": "string"
          },
          "added": {
           "type": "integer"
          },
          "videos": {
           "type": "array",
           "items": {
            "type": "string"
           }
          }
         }
        }
       }
      }
     }
    },
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "provider": {
          "type": "string",
          "default": "youtube"
         },
         "ref": {
          "type": "string"
         },
         "tab": {
          "type": "string"
         }
        },
        "required": [
         "ref"
        ]
       }
      }
     }
    },
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The widget id"
     }
    ],
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/api/v1/widgets/{id}/publish": {
   "post": {
    "operationId": "publishWidget",
    "summary": "Publish the widget to the CDN",
    "description": "",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "published": {
           "type": "boolean"
          },
          "config": {
           "type": "string"
          },
          "embed": {
           "type": "string"
          }
         }
        }
       }
      }
     }
    },
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The widget id"
     }
    ],
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/api/v1/widgets/{id}/stats": {
   "get": {
    "operationId": "widgetStats",
    "summary": "Views, clicks and plays",
    "description": "",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "totals": {
           "type": "object"
          }
         }
        }
       }
      }
     }
    },
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The widget id"
     },
     {
      "name": "days",
      "in": "query",
      "schema": {
       "type": "integer",
       "default": 30,
       "maximum": 90
      }
     }
    ],
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  }
 }
}