Map Generation

This document describes how to submit a map generation job, monitor its progress, and cancel jobs using raw HTTP requests against the Supabase backend.

All requests go through Supabase and require the project URL and anon key, referred to as SUPABASE_URL and SUPABASE_ANON_KEY throughout this document. Quota enforcement is handled server-side — the submit endpoint rejects requests that exceed the caller's annual km² allowance.

1

Authenticate

POST /auth/v1/token?grant_type=password

Exchange an email and password for a session containing an access token.

Headers:

Header
Value

apikey

SUPABASE_ANON_KEY

Content-Type

application/json

Body:

{
  "email": "[email protected]",
  "password": "hunter2"
}

Example:

POST <SUPABASE_URL>/auth/v1/token?grant_type=password
apikey: <SUPABASE_ANON_KEY>
Content-Type: application/json

{
  "email": "[email protected]",
  "password": "hunter2"
}

Response 200:

{
  "access_token": "eyJhbGciOiJIUzI1NiIs...",
  "token_type": "bearer",
  "expires_in": 3600,
  "expires_at": 1711324800,
  "refresh_token": "v1.MjQ3...",
  "user": {
    "id": "d0d8c19e-1b2a-4c3d-8e4f-5a6b7c8d9e0f",
    "email": "[email protected]",
    "role": "authenticated"
  }
}

Save the access_token — every subsequent request uses it as a Bearer token.

2

Submit Map Generation Job

circle-exclamation

POST /functions/v1/submit-map-job

Submit a map generation job. The server validates the caller's quota before accepting the job. If the requested area would exceed the annual km² allowance, the request is rejected with a 403 and a descriptive error. On success, the server records the area and quota year automatically — no separate quota recording step is needed.

Headers:

Header
Value

apikey

SUPABASE_ANON_KEY

Authorization

Bearer <access_token>

Content-Type

application/json

Body:

Field
Type
Required
Description

area_name

string

Yes

3–50 chars: lowercase letters, numbers, underscores

geometry

Polygon

Yes

GeoJSON polygon of the map area

org_id

string

No

Organization ID if generating under an org's quota

Example:

POST <SUPABASE_URL>/functions/v1/submit-map-job
apikey: <SUPABASE_ANON_KEY>
Authorization: Bearer <access_token>
Content-Type: application/json

{
  "area_name": "downtown_austin",
  "geometry": {
    "type": "Polygon",
    "coordinates": [[
      [-97.75, 30.26],
      [-97.73, 30.26],
      [-97.73, 30.28],
      [-97.75, 30.28],
      [-97.75, 30.26]
    ]]
  }
}

Response 200 (job accepted):

{
  "workflow_id": "wf-abc-123",
  "request_id": 42,
  "status": "queued",
  "message": "Map generation job submitted successfully",
  "area_name": "downtown_austin",
  "area_km2": 1.25,
  "quota_info": {
    "total_quota_km2": 500,
    "used_km2": 120.5,
    "remaining_km2": 378.25,
    "requested_km2": 1.25,
    "after_request_km2": 121.75
  }
}

Save the workflow_id — it is used for status polling, cancellation, and download.

Response 403 (quota exceeded):

{
  "error": "Quota exceeded. You have 0.2 km² remaining, but requested 1.3 km².",
  "quota_info": {
    "total_quota_km2": 500,
    "used_km2": 499.8,
    "remaining_km2": 0.2,
    "requested_km2": 1.3,
    "after_request_km2": 501.1
  }
}

Response 403 (no license):

{
  "error": "No active license found. Please purchase a license at https://dashboard.theseus.us",
  "quota_info": null
}

Key fields:

Field
Description

workflow_id

Unique identifier for this generation job

area_km2

Calculated area of the submitted polygon in km²

quota_info.remaining_km2

Remaining quota after this submission

quota_info.total_quota_km2

0 means unlimited — no quota limit is enforced

3

Poll Job Status

POST /functions/v1/map-workflow-status

Poll for real-time progress on a generation job. Returns the current state and percent complete.

Headers:

Header
Value

apikey

SUPABASE_ANON_KEY

Authorization

Bearer <access_token>

Content-Type

application/json

Body:

Field
Type
Required
Description

workflow_id

string

Yes

The workflow_id from the submit step

Example:

POST <SUPABASE_URL>/functions/v1/map-workflow-status
apikey: <SUPABASE_ANON_KEY>
Authorization: Bearer <access_token>
Content-Type: application/json

{
  "workflow_id": "wf-abc-123"
}

Response 200 (in progress):

{
  "state": "processing",
  "status": "Generating tiles (batch 3/8)",
  "percent_complete": 42,
  "area_name": "downtown_austin",
  "task_id": "wf-abc-123"
}

Response 200 (completed):

{
  "state": "completed",
  "status": "Map generation complete",
  "percent_complete": 100,
  "area_name": "downtown_austin",
  "task_id": "wf-abc-123"
}

Response 200 (failed):

{
  "state": "failed",
  "error": "Satellite imagery unavailable for the requested area",
  "area_name": "downtown_austin",
  "task_id": "wf-abc-123"
}

Key state values:

State
Meaning

queued

Job accepted, waiting for a worker

started

Worker picked up the job

processing

Actively generating tiles

completed

Generation finished, download available

failed

Generation failed — check error for details

cancelled

Job was cancelled by the user

Recommended polling interval: 5 seconds. Continue polling until state is completed, failed, or cancelled.

4

Cancel a Job (Optional)

POST /functions/v1/cancel-map-workflow

Cancel a running or queued map generation job.

Headers:

Header
Value

apikey

SUPABASE_ANON_KEY

Authorization

Bearer <access_token>

Content-Type

application/json

Body:

Field
Type
Required
Description

workflow_id

string

Yes

The workflow_id to cancel

Example:

POST <SUPABASE_URL>/functions/v1/cancel-map-workflow
apikey: <SUPABASE_ANON_KEY>
Authorization: Bearer <access_token>
Content-Type: application/json

{
  "workflow_id": "wf-abc-123"
}

Response 200:

{
  "workflow_id": "wf-abc-123",
  "status": "cancelled",
  "message": "Workflow cancelled successfully",
  "area_name": "downtown_austin"
}
5

Confirm Completion via Supabase

Once the status endpoint reports completed, the map result will also appear in the Supabase map_requests table with a populated map_results join. This is the same query described in Map Download — List Maps.

Poll the Supabase table or filter by workflow_id to confirm the result is available:

Headers:

Header
Value

apikey

SUPABASE_ANON_KEY

Authorization

Bearer <access_token>

Accept

application/vnd.pgrst.object+json

Example:

GET <SUPABASE_URL>/rest/v1/map_requests?select=*,map_results(*)&workflow_id=eq.wf-abc-123&deleted_at=is.null
apikey: <SUPABASE_ANON_KEY>
Authorization: Bearer <access_token>
Accept: application/vnd.pgrst.object+json

When map_results is no longer null and map_results.download_url is present, the map is ready to download. Follow the Map Download flow from there.

Complete Flow Summary

Geometry Format

The geometry field must be a valid GeoJSON Polygonarrow-up-right. Coordinates are [longitude, latitude] pairs (GeoJSON order). The ring must be closed — the first and last coordinate must be identical.

Minimum 4 coordinates (3 unique vertices + closing point). The server calculates the polygon area in km² using a spherical trapezoidal approximation.

Area Name Requirements

Rule
Constraint

Length

3–50 characters

Characters

Lowercase letters, numbers, underscores

Uniqueness

Must not match an existing map name

Sanitization

Hyphens are converted to underscores

Last updated