{
  "openapi": "3.1.0",
  "info": {
    "title": "Ulinkly Public API",
    "version": "1.0.0",
    "summary": "Create, resolve, and measure mobile deep links.",
    "description": "The public Ulinkly API for mobile deep-link infrastructure. Public discovery operations require no credentials; link creation and SDK telemetry use a project-scoped X-App-Key. Create keys self-serve in the Ulinkly dashboard. A free plan is available without a credit card.",
    "termsOfService": "https://ulink.ly/terms",
    "contact": {
      "name": "Ulinkly Support",
      "email": "support@ulink.ly",
      "url": "https://ulink.ly/contact"
    },
    "license": {
      "name": "Proprietary API; SDKs and tools have their own licenses",
      "url": "https://ulink.ly/terms"
    }
  },
  "externalDocs": {
    "description": "Ulinkly REST API documentation and integration guides",
    "url": "https://docs.ulink.ly/rest-api/overview"
  },
  "servers": [
    {
      "url": "https://api.ulink.ly",
      "description": "Production API"
    }
  ],
  "tags": [
    {
      "name": "Discovery",
      "description": "Unauthenticated operations for health, plans, and link resolution."
    },
    {
      "name": "Links",
      "description": "Project-scoped operations for creating and reading deep links."
    },
    {
      "name": "Installations",
      "description": "SDK operations for installation and session analytics."
    }
  ],
  "paths": {
    "/health": {
      "get": {
        "operationId": "getApiHealth",
        "summary": "Check API health",
        "description": "Returns the current public API status without authentication. Use this operation to verify connectivity before starting an integration.",
        "tags": ["Discovery"],
        "security": [],
        "responses": {
          "200": {
            "description": "The API is healthy.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthResponse"
                }
              }
            }
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/subscriptions/plans": {
      "get": {
        "operationId": "listSubscriptionPlans",
        "summary": "List available plans",
        "description": "Returns current Ulinkly plans, limits, and features without authentication. Prices are returned for the requested billing period.",
        "tags": ["Discovery"],
        "security": [],
        "parameters": [
          {
            "name": "billingPeriod",
            "in": "query",
            "required": false,
            "description": "Billing period used for returned prices.",
            "schema": {
              "type": "string",
              "enum": ["monthly", "yearly"],
              "default": "monthly"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Available plans and their current limits.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PlansResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/sdk/resolve": {
      "get": {
        "operationId": "resolveDeepLink",
        "summary": "Resolve a deep link",
        "description": "Resolves a full Ulinkly web URL or app-scheme URL to its typed destination and parameters. This public operation also records a click for the owning project.",
        "tags": ["Discovery", "Links"],
        "security": [],
        "parameters": [
          {
            "name": "url",
            "in": "query",
            "required": true,
            "description": "Full HTTPS deep-link URL or custom-scheme URL to resolve.",
            "schema": {
              "type": "string",
              "minLength": 3,
              "examples": ["https://example.shared.ly/welcome"]
            }
          },
          {
            "name": "X-Installation-Token",
            "in": "header",
            "required": false,
            "description": "Optional installation token returned by installation tracking.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Resolved link data and destination parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResolvedLink"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/sdk/links": {
      "post": {
        "operationId": "createDeepLink",
        "summary": "Create a deep link",
        "description": "Creates a unified or dynamic link for the project identified by X-App-Key. Supplying a stable externalId makes repeated requests idempotent and returns the existing link.",
        "tags": ["Links"],
        "security": [
          {
            "AppKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Link routing, fallback, attribution, and preview configuration.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateLinkRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "A new link was created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Link"
                }
              }
            }
          },
          "200": {
            "description": "An existing idempotent link was returned.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Link"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/sdk/links/{slug}": {
      "get": {
        "operationId": "getDeepLinkBySlug",
        "summary": "Get a project link by slug",
        "description": "Returns a link owned by the project associated with X-App-Key. Slugs are scoped to the authenticated project.",
        "tags": ["Links"],
        "security": [
          {
            "AppKey": []
          }
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "description": "Project-scoped link slug.",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 255
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The requested project link.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResolvedLink"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/sdk/installations/track": {
      "post": {
        "operationId": "trackInstallation",
        "summary": "Track an app installation",
        "description": "Creates or refreshes a project installation record and returns an installation token for subsequent SDK calls. Call once per app installation or when the stored token expires.",
        "tags": ["Installations"],
        "security": [
          {
            "AppKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Stable installation identifier plus optional device context.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TrackInstallationRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Installation tracked and token issued.",
            "headers": {
              "X-Installation-Token": {
                "description": "Installation token also included in the response body.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrackInstallationResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/sdk/sessions/start": {
      "post": {
        "operationId": "startInstallationSession",
        "summary": "Start an app session",
        "description": "Starts an analytics session for a previously tracked installation. Send the project X-App-Key and the stable installationId.",
        "tags": ["Installations"],
        "security": [
          {
            "AppKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Installation identifier and optional current device state.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StartSessionRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Session started.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StartSessionResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/sdk/sessions/{sessionId}/end": {
      "post": {
        "operationId": "endInstallationSession",
        "summary": "End an app session",
        "description": "Ends an active installation session and finalizes its duration for analytics.",
        "tags": ["Installations"],
        "security": [
          {
            "AppKey": []
          }
        ],
        "parameters": [
          {
            "name": "sessionId",
            "in": "path",
            "required": true,
            "description": "Session identifier returned by startInstallationSession.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Session ended.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "AppKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-App-Key",
        "description": "Project-scoped API key created under Dashboard → API Keys. Keep it out of public client code when possible."
      }
    },
    "responses": {
      "BadRequest": {
        "description": "The request failed validation.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "X-App-Key is missing or invalid.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "NotFound": {
        "description": "The requested link, installation, session, project, or domain was not found.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "ServiceUnavailable": {
        "description": "The API is temporarily unavailable.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      }
    },
    "schemas": {
      "HealthResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": ["status", "timestamp", "environment"],
        "properties": {
          "status": {
            "type": "string",
            "const": "ok"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          },
          "environment": {
            "type": "string",
            "examples": ["production"]
          }
        }
      },
      "PlansResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": ["plans"],
        "properties": {
          "plans": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Plan"
            }
          }
        }
      },
      "Plan": {
        "type": "object",
        "required": ["name", "priceId", "price", "period", "billingPeriod", "features", "limits", "hasOverage"],
        "properties": {
          "name": { "type": "string" },
          "priceId": { "type": "string" },
          "stripePriceId": { "type": ["string", "null"] },
          "price": { "type": "string", "examples": ["$0"] },
          "period": { "type": "string", "examples": ["/month"] },
          "billingPeriod": { "type": "string", "enum": ["monthly", "yearly"] },
          "yearlyDiscount": { "type": ["string", "null"] },
          "features": { "type": "array", "items": { "type": "string" } },
          "limits": { "type": "object", "additionalProperties": true },
          "hasOverage": { "type": "boolean" },
          "overageRatePer1k": { "type": ["number", "null"] }
        }
      },
      "ResolvedLink": {
        "type": "object",
        "required": ["id", "slug", "type"],
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "slug": { "type": "string" },
          "type": { "type": "string", "enum": ["unified", "dynamic"] },
          "fallbackUrl": { "type": ["string", "null"], "format": "uri" },
          "iosUrl": { "type": ["string", "null"], "format": "uri" },
          "androidUrl": { "type": ["string", "null"], "format": "uri" },
          "iosFallbackUrl": { "type": ["string", "null"], "format": "uri" },
          "androidFallbackUrl": { "type": ["string", "null"], "format": "uri" },
          "parameters": { "type": ["object", "null"], "additionalProperties": true },
          "metadata": { "type": ["object", "null"], "additionalProperties": true },
          "allowQueryPassthrough": { "type": "boolean" }
        }
      },
      "CreateLinkRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": ["type"],
        "properties": {
          "type": { "type": "string", "enum": ["unified", "dynamic"] },
          "slug": { "type": "string", "minLength": 1, "maxLength": 255 },
          "name": { "type": "string", "maxLength": 255 },
          "externalId": { "type": "string", "minLength": 1, "maxLength": 255, "pattern": "^\\S+$" },
          "domain": { "type": "string", "examples": ["example.shared.ly"] },
          "fallbackUrl": { "type": "string", "format": "uri" },
          "iosUrl": { "type": "string", "format": "uri" },
          "androidUrl": { "type": "string", "format": "uri" },
          "iosFallbackUrl": { "type": "string", "format": "uri" },
          "androidFallbackUrl": { "type": "string", "format": "uri" },
          "parameters": { "type": "object", "additionalProperties": true },
          "metadata": { "type": "object", "additionalProperties": true },
          "allowQueryPassthrough": { "type": "boolean", "default": false }
        }
      },
      "Link": {
        "allOf": [
          { "$ref": "#/components/schemas/ResolvedLink" },
          {
            "type": "object",
            "required": ["shortUrl"],
            "properties": {
              "shortUrl": { "type": "string", "format": "uri" },
              "externalId": { "type": ["string", "null"] },
              "createdAt": { "type": "string", "format": "date-time" },
              "updatedAt": { "type": "string", "format": "date-time" }
            }
          }
        ]
      },
      "TrackInstallationRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": ["installationId"],
        "properties": {
          "installationId": { "type": "string", "minLength": 1 },
          "deviceId": { "type": "string" },
          "deviceModel": { "type": "string" },
          "deviceManufacturer": { "type": "string" },
          "osName": { "type": "string" },
          "osVersion": { "type": "string" },
          "appVersion": { "type": "string" },
          "appBuild": { "type": "string" },
          "language": { "type": "string" },
          "timezone": { "type": "string" },
          "networkType": { "type": "string" },
          "deviceOrientation": { "type": "string" },
          "batteryLevel": { "type": "number", "minimum": 0, "maximum": 1 },
          "isCharging": { "type": "boolean" },
          "metadata": { "type": "object", "additionalProperties": true }
        }
      },
      "TrackInstallationResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": ["success", "installationId", "isNew"],
        "properties": {
          "success": { "type": "boolean", "const": true },
          "installationId": { "type": "string", "format": "uuid" },
          "isNew": { "type": "boolean" },
          "installationToken": { "type": "string" }
        }
      },
      "StartSessionRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": ["installationId"],
        "properties": {
          "installationId": { "type": "string", "minLength": 1 },
          "networkType": { "type": "string" },
          "deviceOrientation": { "type": "string" },
          "batteryLevel": { "type": "number", "minimum": 0, "maximum": 1 },
          "isCharging": { "type": "boolean" },
          "metadata": { "type": "object", "additionalProperties": true }
        }
      },
      "StartSessionResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": ["success", "sessionId"],
        "properties": {
          "success": { "type": "boolean", "const": true },
          "sessionId": { "type": "string", "format": "uuid" }
        }
      },
      "SuccessResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": ["success"],
        "properties": {
          "success": { "type": "boolean" }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "required": ["statusCode", "message"],
        "properties": {
          "statusCode": { "type": "integer", "minimum": 400, "maximum": 599 },
          "message": { "type": ["string", "array"], "items": { "type": "string" } },
          "error": { "type": "string" }
        }
      }
    }
  }
}
