---
title: "Discover bounded app Roots and the API-owned build route"
method: POST
path: "/projects/{id}/app-source/detect"
---

# Discover bounded app Roots and the API-owned build route

`POST /projects/{id}/app-source/detect`

## Request

- Base URL: `https://api.eurobase.dev`
- URL: `https://api.eurobase.dev/projects/{id}/app-source/detect`
- Auth: none declared

## Path parameters

- `id` string, required

## Request body

- ProjectAppSourceDetectRequest
  - `repoId` string
  - `repoFullName` string
  - `branch` string
  - `rootDir` string
  - `rootDirectory` string
  - `rootCandidateSetHash` string, nullable
  - `rootChoiceConfirmed` boolean

## Response `200`

Detected app source profile candidate

- ProjectAppSourceResponse
  - `project` ProjectSummary, required
    - `id` string, required
    - `name` string, nullable
    - `organizationId` string, nullable
    - `projectMembershipId` string, nullable
    - `projectRole` 'owner' | 'admin' | 'contributor' | 'null', nullable
    - `projectSlug` string, nullable
    - `projectHostname` string, nullable
    - `primaryHostname` string, nullable: Official address of the project: its active custom domain whose DNS points at Eurobase, the one that went live first when several do, otherwise projectHostname. projectHostname stays reserved and keeps serving.
    - `deploymentMode` 'runtime' | 'static', required
    - `lifecycleState` string, nullable
    - `deleteRequestedAt` string, date-time, nullable
    - `projectRoute` ProjectRoute, required
      - `status` 'healthy' | 'repairing' | 'degraded' | 'broken' | 'unknown', required
      - `reasonCode` 'none' | 'dns_record_missing' | 'dns_propagating' | 'domain_binding_missing' | 'tls_pending' | 'missing_project_upstream' | 'upstream_unreachable' | 'ingress_unreachable' | 'unmanaged_custom_domain' | 'scw_mutation_failed', required
      - `checkedAt` string, date-time, nullable
      - `lastRepairAt` string, date-time, nullable
      - `lastError` string, nullable
      - `managed` boolean, required
      - `convergenceState` 'recovering' | 'exhausted' | 'ready' | 'null', nullable
      - `upstream` ProjectUpstreamState, required
        - `status` 'healthy' | 'broken' | 'unknown', required
        - `reasonCode` 'none' | 'missing_project_upstream' | 'upstream_unreachable', required
        - `checkedAt` string, date-time, nullable
        - `lastError` string, nullable
    - `releaseUsability` ReleaseUsability, required
      - `status` 'reachable' | 'degraded' | 'blocked' | 'unknown', required
      - `reasonCode` 'none' | 'missing_live_release' | 'access_not_allowed' | 'route_repair_in_progress' | 'route_incident' | 'project_suspended', required
      - `lastLiveDeploymentId` string, nullable, required
    - `projectSummaryStatus` ProjectSummaryStatus
      - `label` string, required
      - `tone` 'neutral' | 'problem' | 'error', required
      - `code` 'setup_required' | 'route_issue' | 'deploy_failed' | 'deploy_unhealthy' | 'live_release_blocked' | 'status_check_delayed' | 'deploy_in_progress' | 'rollback_live' | 'healthy' | 'suspended', required
      - `detailTitle` string, nullable, required
      - `detail` string, nullable, required
    - `servingSuspension` ProjectServingSuspension: An operator suspension of the project's public serving (ADR 0080). Operator notes and evidence are never included.
      - `state` 'suspended', required
      - `reasonCategory` 'phishing' | 'malware' | 'shared_domain_abuse' | 'spam' | 'illegal_content' | 'legal_order' | 'other_policy_violation', required
      - `reasonLabel` string, required
      - `since` string, date-time, nullable, required
      - `supportEmail` string, required
      - `policyUrl` string, required
    - `sourceProfile` ProjectSourceProfileSummary, required
      - `framework` 'next' | 'astro' | 'svelte-kit' | 'nuxt' | 'react-router' | 'vite' | 'hono' | 'nestjs' | 'fastify' | 'express' | 'django' | 'fastapi' | 'flask' | 'laravel' | 'rails' | 'node' | 'python' | 'php' | 'ruby' | 'go' | 'java' | 'dotnet' | 'static', required
      - `frameworkLabel` string, required
      - `outputMode` 'runtime' | 'static', required
    - `sourceLock` ProjectSourceLock: ADR 0090: while locked, no caller can change the project repository, branch, root directory or deployment mode.
      - `locked` boolean, required
      - `lockedAt` string, date-time, nullable, required
  - `appRepo` AppRepo
    - `repoId` string, required
    - `repoName` string, nullable
    - `repoFullName` string, required
    - `branch` string, required
    - `rootDir` string, required
    - `runCommand` string, required
    - `healthPath` string, required
    - `containerPort` integer, required
    - `deploymentMode` 'runtime' | 'static', required
  - `appRuntimeTier` AppRuntimeTier
    - `code` 'euro-small' | 'euro-medium' | 'euro-large' | 'euro-xlarge', required
    - `label` string, required
    - `cpu` string
    - `memory` string
    - `limitsKnown` boolean
    - `cpuMillicores` integer, nullable
    - `memoryMb` integer, nullable
    - `minScale` integer, nullable, required
    - `maxScale` integer, nullable, required
    - `burnMultiplier` string, nullable
    - `workloadGuidance` string, nullable
    - `equivalentIncludedRuntimeHours` string, nullable
    - `selectable` boolean
    - `unavailableReason` string, nullable
    - `recoveryAction` string, nullable
    - `configurable` boolean, required
  - `appRuntimeTierOptions` ProjectContainerRuntimeTier[]
    - `code` 'euro-small' | 'euro-medium' | 'euro-large' | 'euro-xlarge' | 'existing-unmanaged', required
    - `label` string, required
    - `limitsKnown` boolean, required
    - `cpuMillicores` integer, nullable, required
    - `memoryMb` integer, nullable, required
    - `minScale` integer, nullable, required
    - `maxScale` integer, nullable, required
    - `burnMultiplier` string, nullable
    - `workloadGuidance` string, nullable
    - `equivalentIncludedRuntimeHours` string, nullable
    - `unavailableReason` string, nullable
    - `recoveryAction` string, nullable
    - `selectable` boolean, required
  - `defaultAppRuntimeTierCode` 'euro-small' | 'euro-medium' | 'euro-large' | 'euro-xlarge' | 'null', nullable
  - `appRuntimeTierPolicyState` object, nullable
    - `status` 'ready' | 'blocked' | 'unavailable', required
    - `reasonCode` string, nullable
    - `recoveryAction` string, nullable
  - `planRuntimeAllowance` object, nullable
    - `smallEquivalentHours` string, required
    - `maxScale` integer, required
  - `appSourceProfile` AppSourceProfile, required
    - `sourceType` 'git_repo', required
    - `repository` object, nullable, required
      - `id` string, nullable
      - `name` string, nullable
      - `fullName` string, nullable
    - `branch` string, required
    - `rootDirectory` string, required
    - `rootCandidates` string[], required
    - `rootCandidateSetHash` string, nullable
    - `rootChoiceRequired` boolean, required
    - `rootChoiceConfirmed` boolean, required
    - `sourceBuildEngine` 'direct-static-v1' | 'paketo-v1' | 'workers-v1', required
    - `directStatic` boolean, required
    - `framework` 'next' | 'astro' | 'svelte-kit' | 'nuxt' | 'react-router' | 'vite' | 'hono' | 'nestjs' | 'fastify' | 'express' | 'django' | 'fastapi' | 'flask' | 'laravel' | 'rails' | 'node' | 'python' | 'php' | 'ruby' | 'go' | 'java' | 'dotnet' | 'static' | 'unknown', required
    - `frameworkLabel` string, required
    - `outputMode` 'runtime' | 'static', required
    - `appRuntimeTierId` 'euro-small' | 'euro-medium' | 'euro-large' | 'euro-xlarge' | 'null', nullable
    - `port` integer, nullable
    - `healthPath` string, nullable
    - `appRuntimeTier` AppRuntimeTier
      - `code` 'euro-small' | 'euro-medium' | 'euro-large' | 'euro-xlarge', required
      - `label` string, required
      - `cpu` string
      - `memory` string
      - `limitsKnown` boolean
      - `cpuMillicores` integer, nullable
      - `memoryMb` integer, nullable
      - `minScale` integer, nullable, required
      - `maxScale` integer, nullable, required
      - `burnMultiplier` string, nullable
      - `workloadGuidance` string, nullable
      - `equivalentIncludedRuntimeHours` string, nullable
      - `selectable` boolean
      - `unavailableReason` string, nullable
      - `recoveryAction` string, nullable
      - `configurable` boolean, required
    - `detection` AppSourceDetection, required
      - `status` 'not_requested' | 'pending' | 'detected' | 'needs_review' | 'failed' | 'unavailable', required
      - `reason` 'none' | 'no_match' | 'ambiguous' | 'cap_exceeded' | 'timeout' | 'rate_limited' | 'repo_access_unavailable' | 'detector_error', required
      - `confidence` 'high' | 'medium' | 'low' | 'unknown', required
      - `detectedAt` string, date-time, nullable
      - `commitSha` string, nullable
      - `treeSha` string, nullable
      - `detectorVersion` string, nullable, required
      - `evidence` AppSourceDetectionEvidence[], required
        - `path` string, required
        - `reason` string, required
      - `warnings` string[], required
    - `overrideState` 'auto' | 'custom_override' | 'detected_but_unconfirmed', required
    - `canDeploy` boolean, required
    - `blockedReason` string, nullable
    - `blockedMessage` string, nullable
    - `sourceRuntime` 'ruby' | 'dotnet' | 'go' | 'python' | 'php' | 'java' | 'node' | 'null', nullable
    - `serviceType` 'web_service' | 'static_site' | 'null', nullable
    - `packageManager` 'npm' | 'yarn' | 'null', nullable
    - `buildCommand` string, nullable
    - `startCommand` string, nullable
    - `publishDirectory` string, nullable
    - `sourceBuild` AppSourceBuildPlan
      - `runtime` string, nullable, required
      - `packageManager` string, nullable, required
      - `blockedReason` string, nullable, required
      - `procfileWeb` string, nullable, required
      - `scripts` string[], required
      - `startRequired` boolean, required
      - `buildAvailable` boolean, required
      - `startLooksLikeDevServer` boolean
      - `defaults` object, required
        - `serviceType` 'web_service' | 'static_site', required
        - `buildCommand` string, nullable, required
        - `startCommand` string, nullable, required
        - `publishDirectory` string, nullable, required
    - `buildHints` object, nullable
      - `runtime` string, nullable
      - `pythonVersion` string, nullable
      - `nodeVersion` string, nullable
      - `nodeLaunchpoint` string, nullable
  - `detectedAppSourceProfile` AppSourceProfile
    - `sourceType` 'git_repo', required
    - `repository` object, nullable, required
      - `id` string, nullable
      - `name` string, nullable
      - `fullName` string, nullable
    - `branch` string, required
    - `rootDirectory` string, required
    - `rootCandidates` string[], required
    - `rootCandidateSetHash` string, nullable
    - `rootChoiceRequired` boolean, required
    - `rootChoiceConfirmed` boolean, required
    - `sourceBuildEngine` 'direct-static-v1' | 'paketo-v1' | 'workers-v1', required
    - `directStatic` boolean, required
    - `framework` 'next' | 'astro' | 'svelte-kit' | 'nuxt' | 'react-router' | 'vite' | 'hono' | 'nestjs' | 'fastify' | 'express' | 'django' | 'fastapi' | 'flask' | 'laravel' | 'rails' | 'node' | 'python' | 'php' | 'ruby' | 'go' | 'java' | 'dotnet' | 'static' | 'unknown', required
    - `frameworkLabel` string, required
    - `outputMode` 'runtime' | 'static', required
    - `appRuntimeTierId` 'euro-small' | 'euro-medium' | 'euro-large' | 'euro-xlarge' | 'null', nullable
    - `port` integer, nullable
    - `healthPath` string, nullable
    - `appRuntimeTier` AppRuntimeTier
      - `code` 'euro-small' | 'euro-medium' | 'euro-large' | 'euro-xlarge', required
      - `label` string, required
      - `cpu` string
      - `memory` string
      - `limitsKnown` boolean
      - `cpuMillicores` integer, nullable
      - `memoryMb` integer, nullable
      - `minScale` integer, nullable, required
      - `maxScale` integer, nullable, required
      - `burnMultiplier` string, nullable
      - `workloadGuidance` string, nullable
      - `equivalentIncludedRuntimeHours` string, nullable
      - `selectable` boolean
      - `unavailableReason` string, nullable
      - `recoveryAction` string, nullable
      - `configurable` boolean, required
    - `detection` AppSourceDetection, required
      - `status` 'not_requested' | 'pending' | 'detected' | 'needs_review' | 'failed' | 'unavailable', required
      - `reason` 'none' | 'no_match' | 'ambiguous' | 'cap_exceeded' | 'timeout' | 'rate_limited' | 'repo_access_unavailable' | 'detector_error', required
      - `confidence` 'high' | 'medium' | 'low' | 'unknown', required
      - `detectedAt` string, date-time, nullable
      - `commitSha` string, nullable
      - `treeSha` string, nullable
      - `detectorVersion` string, nullable, required
      - `evidence` AppSourceDetectionEvidence[], required
        - `path` string, required
        - `reason` string, required
      - `warnings` string[], required
    - `overrideState` 'auto' | 'custom_override' | 'detected_but_unconfirmed', required
    - `canDeploy` boolean, required
    - `blockedReason` string, nullable
    - `blockedMessage` string, nullable
    - `sourceRuntime` 'ruby' | 'dotnet' | 'go' | 'python' | 'php' | 'java' | 'node' | 'null', nullable
    - `serviceType` 'web_service' | 'static_site' | 'null', nullable
    - `packageManager` 'npm' | 'yarn' | 'null', nullable
    - `buildCommand` string, nullable
    - `startCommand` string, nullable
    - `publishDirectory` string, nullable
    - `sourceBuild` AppSourceBuildPlan
      - `runtime` string, nullable, required
      - `packageManager` string, nullable, required
      - `blockedReason` string, nullable, required
      - `procfileWeb` string, nullable, required
      - `scripts` string[], required
      - `startRequired` boolean, required
      - `buildAvailable` boolean, required
      - `startLooksLikeDevServer` boolean
      - `defaults` object, required
        - `serviceType` 'web_service' | 'static_site', required
        - `buildCommand` string, nullable, required
        - `startCommand` string, nullable, required
        - `publishDirectory` string, nullable, required
    - `buildHints` object, nullable
      - `runtime` string, nullable
      - `pythonVersion` string, nullable
      - `nodeVersion` string, nullable
      - `nodeLaunchpoint` string, nullable
  - `sourceConfirmation` ProjectSourceConfirmation
    - `repository` string, required
    - `branch` string, required
    - `rootDirectory` string, required
    - `configurationHash` string, required: API-owned binding of the saved source defaults, excluding detector caches and unrelated project updates.
  - `runtimeSelection` RuntimeSelection: The project runtime plan for one commit. detected: no runtime is stored yet and this commit selects it; confirmed: the commit matches the stored runtime; change-required: the commit needs the detected runtime and deploys only after an explicit sourceBuildEngineChange; stored-engine-blocked: this commit cannot deploy, and blocker carries its reason: either the stored runtime cannot admit it, or a build Job already detected it as a Workers app (detectedEngine workers-v1) that cannot run, which is refused with its fix and never built on Paketo. detectedEngine workers-v1 without a stored runtime is the route: the Workers build Job detects the runtime before any user code runs, then builds on Workers, builds the same deployment on Paketo, or refuses it. Warnings (from the last build Job detection for this commit, and client-written-cookies from the plan read) never block the deploy.
    - `storedEngine` 'direct-static-v1' | 'paketo-v1' | 'workers-v1' | 'null', nullable, required
    - `detectedEngine` 'direct-static-v1' | 'paketo-v1' | 'workers-v1' | 'null', nullable, required
    - `commitSha` string, nullable, required
    - `state` 'detected' | 'confirmed' | 'change-required' | 'changed' | 'stored-engine-blocked', required
    - `detectedBlockedReason` string, nullable
    - `blocker` object
      - `reason` string, required
      - `message` string, required: Owner-facing copy; a command inside it is delimited by backticks.
      - `fixCommand` string, nullable: The one command that fixes a Workers refusal in the repository, when one exists.
      - `evidence` object[], required
        - `path` string
        - `reason` string
    - `warnings` object[]: Warnings for a deployable plan; the deploy proceeds. Workers detection warnings, then one `client-written-cookies` warning per distinct fix for the Root dependencies that write a cookie in the browser for the server to read.
      - `code` 'adapter-compatibility-unverified' | 'client-written-cookies' | 'framework-version-end-of-life' | 'framework-version-vulnerable' | 'package-manager-version-substituted', required
      - `message` string, required: Owner-facing copy; a command or code inside it is delimited by backticks.
      - `fixCommand` string, nullable, required
      - `docsPath` string: Eurobase docs page that explains the warning, as a path on the web app origin.

## Other responses

- `400`: Invalid app source detection request

---

[API](https://skmtc.dev/eurobase/apis/eurobase-api.md) · [All operations](https://skmtc.dev/eurobase/apis/eurobase-api/llms.txt) · [OpenAPI document](https://skmtc.dev/eurobase/apis/eurobase-api/revisions/5266a299d18a?raw)
