Projects Api V1
Djass Projects API (v1)
Base URL: https://djass.dev/api/v1
Coverage: create, list, get, status, and download endpoints for project generation.
1) What this API does
This API lets an agent: 1. inspect the current generator option catalog, 2. create a new Djass project generation job, 3. list the caller's projects, 4. fetch one project by id, 5. poll status until generation is complete, 6. download the generated project ZIP artifact.
All data access is owner-scoped: keys can only see projects for their own profile.
2) Authentication and key scoping
Project mutation and project history endpoints require an API key. The generator option catalog is public.
Accepted auth formats (in lookup order)
X-API-Key: <key>Authorization: Bearer <key>(also acceptsApi-Key,apikey,tokenschemes)- Query fallback:
?api_key=<key>(legacy compatibility)
Key types
- Legacy profile key: full access to
projects:create+projects:read - Scoped API key (
ProjectAPIKey): only granted scopes
Required scopes
POST /projectsrequiresprojects:createGET /projects,GET /projects/{id},GET /projects/{id}/status, andGET /projects/{id}/downloadrequireprojects:readGET /project-optionsdoes not require authentication
If scope is missing: 403 with error.code = "insufficient_scope".
3) Error contract (all non-2xx)
{
"error": {
"code": "machine_readable_code",
"category": "validation|auth|quota|retryable|internal",
"message": "Human readable summary",
"retryable": false,
"details": {}
}
}
Common codes used by this API
auth_requiredinsufficient_scopeinvalid_project_slugquota_exceededproject_not_foundartifact_not_readyretryable_errorinternal_error
Retry guidance may appear in error.details.retry_guidance.
4) Endpoint reference
4.1 Project options
Method/Path: GET /project-options
Purpose: return the current generator option catalog grouped for UI/API clients.
Success response (200)
{
"defaults": {
"project_name": "My Awesome Project",
"project_slug": "{{ cookiecutter.project_name.lower()|replace(' ', '_')|replace('-', '_')|replace('.', '_')|trim() }}",
"caprover_app_name": "{{ cookiecutter.project_slug|replace('_', '-') }}",
"repo_url": "https://github.com/cookiecutter/cookiecutter",
"use_posthog": "y",
"use_chatwoot": "n",
"use_apprise": "n",
"use_mcp": "n",
"use_digitalocean": "n"
},
"groups": [
{
"key": "monitoring",
"label": "Monitoring",
"options": [
{
"key": "use_posthog",
"label": "Use PostHog",
"default": "y",
"category": "monitoring"
}
]
}
]
}
Notes:
- defaults mirrors the typed generator option catalog used by Djass.
- groups contains feature flags only; identity/metadata fields stay in the create payload.
- create requests use the same flat option keys shown in groups[].options[].
4.2 Create project
Method/Path: POST /projects
Purpose: queue project generation from template settings.
Request body
{
"project_name": "Acme CRM",
"project_slug": "acme_crm",
"caprover_app_name": "acme-crm",
"project_description": "Internal CRM for support and sales",
"repo_url": "https://github.com/acme/acme-crm",
"author_name": "Acme Bot",
"author_email": "[email protected]",
"author_url": "https://acme.test",
"project_main_color": "green",
"use_posthog": "y",
"use_chatwoot": "n",
"use_s3": "y",
"use_stripe": "y",
"use_sentry": "y",
"generate_blog": "y",
"generate_docs": "y",
"use_mjml": "y",
"use_ai": "y",
"use_logfire": "y",
"use_healthchecks": "y",
"use_apprise": "n",
"use_mcp": "n",
"use_ci": "y",
"use_digitalocean": "n"
}
Notes:
- all feature flags are "y"|"n"
- use GET /project-options to discover the current supported generator flags
- project_slug is normalized (slugify, then - -> _)
- if author_email is empty, backend fills it from profile email
Success response (201)
{
"project": {
"id": 123,
"name": "Acme CRM",
"slug": "acme_crm",
"status": "queued",
"error_message": "",
"created_at": "2026-03-11T12:00:00Z",
"updated_at": "2026-03-11T12:00:00Z",
"started_at": null,
"finished_at": null,
"artifact_ready": false,
"input_payload": {
"project_name": "Acme CRM",
"project_slug": "acme_crm",
"caprover_app_name": "acme-crm",
"project_description": "Internal CRM for support and sales",
"repo_url": "https://github.com/acme/acme-crm",
"author_name": "Acme Bot",
"author_email": "[email protected]",
"author_url": "https://acme.test",
"project_main_color": "green",
"use_posthog": "y",
"use_chatwoot": "n",
"use_s3": "y",
"use_stripe": "y",
"use_sentry": "y",
"generate_blog": "y",
"generate_docs": "y",
"use_mjml": "y",
"use_ai": "y",
"use_logfire": "y",
"use_healthchecks": "y",
"use_apprise": "n",
"use_mcp": "n",
"use_ci": "y",
"use_digitalocean": "n"
}
}
}
Error statuses
400invalid payload / invalid slug401missing or invalid key403insufficient scope429project quota exceeded503temporary queueing failure (retryable)500internal error
4.3 List projects
Method/Path: GET /projects
Purpose: list caller-owned projects with pagination and optional status filter.
Query params
limit(default20, min1, max100)offset(default0, min0)status(queued|generating|ready|failed)
Success response (200)
{
"projects": [
{
"id": 123,
"name": "Acme CRM",
"slug": "acme_crm",
"status": "ready",
"error_message": "",
"created_at": "2026-03-11T12:00:00Z",
"updated_at": "2026-03-11T12:02:40Z",
"started_at": "2026-03-11T12:00:05Z",
"finished_at": "2026-03-11T12:02:39Z",
"artifact_ready": true,
"input_payload": {
"project_name": "Acme CRM",
"project_slug": "acme_crm"
}
}
],
"total": 1,
"limit": 20,
"offset": 0,
"has_next": false,
"filters": {
"status": "ready"
}
}
Error statuses
401missing or invalid key403insufficient scope422invalid query params (limit/offset/status)500internal error
4.4 Get project
Method/Path: GET /projects/{project_id}
Purpose: fetch one full project object.
Success response (200)
Returns full Project object (same shape as project in create response).
Error statuses
401missing/invalid key403insufficient scope404project not found500internal error
4.5 Get project status
Method/Path: GET /projects/{project_id}/status
Purpose: lightweight polling endpoint.
Success response (200)
{
"id": 123,
"status": "generating",
"error_message": "",
"artifact_ready": false,
"started_at": "2026-03-11T12:00:05Z",
"finished_at": null,
"updated_at": "2026-03-11T12:00:20Z"
}
Error statuses
401missing/invalid key403insufficient scope404project not found500internal error
4.6 Download project artifact
Method/Path: GET /projects/{project_id}/download
Purpose: download the generated repository ZIP after project generation is ready.
Success response (200)
Returns a binary ZIP stream with:
Content-Type: application/zipContent-Disposition: attachment; filename="<project_slug>-YYYYMMDD.zip"
Error statuses
401missing/invalid key403insufficient scope404project not found409artifact is not ready yet500internal error
When the artifact is not ready, poll GET /projects/{project_id}/status until
artifact_ready is true.
5) Agent quickstart (copy-paste)
# 0) Set runtime values
export DJASS_BASE_URL="https://djass.dev/api/v1"
export DJASS_API_KEY="replace-with-key"
# 1) Create project
curl -sS -X POST "$DJASS_BASE_URL/projects" \
-H "Content-Type: application/json" \
-H "X-API-Key: $DJASS_API_KEY" \
--data '{
"project_name": "Acme CRM",
"project_slug": "acme_crm",
"caprover_app_name": "acme-crm",
"project_description": "Internal CRM for support and sales",
"repo_url": "https://github.com/acme/acme-crm",
"author_name": "Acme Bot",
"author_email": "[email protected]",
"author_url": "https://acme.test",
"project_main_color": "green",
"use_posthog": "y",
"use_chatwoot": "n",
"use_s3": "y",
"use_stripe": "y",
"use_sentry": "y",
"generate_blog": "y",
"generate_docs": "y",
"use_mjml": "y",
"use_ai": "y",
"use_logfire": "y",
"use_healthchecks": "y",
"use_apprise": "n",
"use_mcp": "n",
"use_ci": "y",
"use_digitalocean": "n"
}'
# 2) Get latest project (or parse ID from create response)
curl -sS "$DJASS_BASE_URL/projects?limit=1&offset=0" \
-H "X-API-Key: $DJASS_API_KEY"
# 3) Poll status until ready/failed
PROJECT_ID="123"
curl -sS "$DJASS_BASE_URL/projects/$PROJECT_ID/status" \
-H "X-API-Key: $DJASS_API_KEY"
# 4) Fetch full project object
curl -sS "$DJASS_BASE_URL/projects/$PROJECT_ID" \
-H "X-API-Key: $DJASS_API_KEY"
# 5) Download generated repo ZIP when ready
curl -L "$DJASS_BASE_URL/projects/$PROJECT_ID/download" \
-H "X-API-Key: $DJASS_API_KEY" \
-o "acme_crm.zip"
Polling recommendation:
- start at 2s interval
- back off to max 15s
- stop on status in {"ready", "failed"}
6) Common failure cases (with real payload shapes)
Missing/invalid auth (401)
{
"error": {
"code": "auth_required",
"category": "auth",
"message": "Authentication required.",
"retryable": false,
"details": {}
}
}
Missing scope (403)
{
"error": {
"code": "insufficient_scope",
"category": "auth",
"message": "API key is missing required scope: projects:create",
"retryable": false,
"details": {
"required_scope": "projects:create"
}
}
}
Invalid slug (400)
{
"error": {
"code": "invalid_project_slug",
"category": "validation",
"message": "project_slug must contain letters or numbers.",
"retryable": false,
"details": {
"field": "project_slug"
}
}
}
Quota exceeded (429)
{
"error": {
"code": "quota_exceeded",
"category": "quota",
"message": "Project quota exceeded for this API identity.",
"retryable": false,
"details": {
"quota": 200,
"retry_guidance": "Delete old projects or request limit bump."
}
}
}
Temporary queue failure (503, retryable)
{
"error": {
"code": "retryable_error",
"category": "retryable",
"message": "Temporary failure while queueing project generation.",
"retryable": true,
"details": {
"retry_guidance": "Retry with exponential backoff."
}
}
}
Not found (404)
{
"error": {
"code": "project_not_found",
"category": "validation",
"message": "Project not found.",
"retryable": false,
"details": {
"project_id": 999999
}
}
}
Artifact not ready (409, retryable)
{
"error": {
"code": "artifact_not_ready",
"category": "retryable",
"message": "Project artifact is not ready yet.",
"retryable": true,
"details": {
"project_id": 123,
"status": "generating",
"retry_guidance": "Poll the status endpoint until artifact_ready is true."
}
}
}
7) Implementation references
This API reference is aligned with backend implementation and tests:
- endpoint logic: apps/api/views.py
- schema definitions: apps/api/schemas.py
- auth parsing/scoping: apps/api/auth.py, apps/api/utils.py
- API tests: apps/api/test_spec_001_contract.py
Local execution note:
- running API tests in this environment requires PostgreSQL with pgvector migration support (CREATE EXTENSION vector)
- sqlite fallback test run fails by design on that migration
8) Known limitations / TODO
- No idempotency key on create: repeated
POST /projectscan create duplicates. - No callback/webhook for completion: clients must poll
/status. - Legacy query-string auth remains enabled for compatibility; should eventually be deprecated for security hygiene.
- No server-provided request ID in response body for cross-system tracing.