Skip to main content

Autka Backend API: Cloudflare Workers, D1, and R2

Reference for Autka's Cloudflare backend API. Endpoints for health, offers, sources, ingestion, images, and import services. Built on Workers, D1 SQL, and R2 object storage.
5 min read

Autka's backend runs on Cloudflare Workers with a D1 SQL database and R2 object storage. It aggregates authorized car listing feeds and exposes a clean REST API for the Android app. This page documents the available endpoints, request parameters, and the CarOffer data model.

Base URL#

  • Production: configured in the Android release build (BACKEND_BASE_URL build config field)
  • Local development: http://10.0.2.2:8787/ (emulator loopback to host running wrangler dev)

Endpoints#

GET /health#

Returns a simple liveness check for the Worker.

Response:

GET /offers#

Search and list offers. Query parameters mirror the app's SearchFilter fields.

Query parameters:

ParameterTypeDescription
querystringFree-text search
makestringVehicle manufacturer filter
modelstringVehicle model filter
minPricenumberRequested minimum price; currently applied client-side after currency conversion
maxPricenumberRequested maximum price; currently applied client-side after currency conversion
minYearnumberMinimum model year
maxYearnumberMaximum model year
maxMileageKmnumberMaximum odometer reading in kilometres
fuelTypesstringComma-separated fuel types
transmissionsstringComma-separated transmission types
regionsstringComma-separated regions
sourcesstringComma-separated source identifiers
sortstringNEWEST, PRICE_ASC, PRICE_DESC, MILEAGE_ASC, or YEAR_DESC; price sorts are currently applied client-side
dedupbooleanSet false to disable backend de-duplication
completebooleanReturn the full matching set without pagination
limitnumberPage size (ignored when complete=true)
offsetnumberPage offset (ignored when complete=true)

Response (regular mode):

Response (complete=true): Returns the full matching set from one SQL statement, ignoring limit and offset. This prevents page shifts during ingestion. Complete responses are capped at 5,000 rows. If the result exceeds this limit, the API returns HTTP 422 instead of silently truncating.

Warning

Server-side price filtering and sorting are disabled until a normalized-price column is added. Android requests complete=true and performs these operations locally after currency conversion.

GET /offers/:id#

Returns a single offer by its namespaced CarOffer.id, for example otomoto:12345. The backend looks up the same offers.id value returned in list responses.

Response: CarOffer object.

Note

The current Android client reads offer details directly from the Room cache rather than through this endpoint, so the UI stays consistent with the cached catalogue.

GET /sources#

Returns the list of configured sources with public-safe health metadata.

Response fields per source:

FieldTypeDescription
idstringSource identifier
enabledbooleanWhether the source is active
offerCountnumber | nullNumber of offers from this source
lastCompletedAtEpochMsnumber | nullTimestamp of last completed ingest
lastCompletedOkboolean | nullWhether the last completed ingest succeeded
lastOffersUpsertednumber | nullHow many offers were upserted in the last run

If D1 health lookup fails, the static source list and enabled flags are still returned with health fields set to null. Raw ingestion errors remain server-side.

POST /admin/ingest#

Manually triggers ingestion. Requires a bearer token in the Authorization header.

Headers:

Behavior: Runs all enabled ingestion adapters. Concurrent scheduled or manual runs for the same source are skipped; different sources still run in parallel.

GET /images/:key#

Streams a cached offer image from R2.

Features:

  • Supports ETag and HTTP 304 caching
  • Never fetches arbitrary URLs on demand
  • Returns the original URL if the image was not cached in R2

GET /import-services#

Returns a directory of import and logistics companies, optionally filtered by region.

Query parameters:

ParameterTypeDescription
regionstringOptional region filter

CarOffer model#

The CarOffer shape in backend/src/lib/types.ts mirrors Android's com.autka.core.model.CarOffer. Keep them in sync when making changes.

Core fields:

FieldTypeDescription
sourceIdstringSource identifier
idstringStable namespaced offer ID (source:native-id)
titlestringListing title
makestringVehicle manufacturer
modelstringVehicle model
pricenumberListed price
currencystringPrice currency: PLN, EUR, or USD
fuelstringFuel type
transmissionstringTransmission type
regionstringGeographic region
originalUrlstringLink to original marketplace listing
yearnumber | nullModel year (optional)
mileagenumber | nullOdometer reading (optional)
powernumber | nullEngine power (optional)
locationstring | nullLocation description (optional)
latitudenumber | nullLatitude for map view (optional)
longitudenumber | nullLongitude for map view (optional)
imagesstring[]Image URLs (may be empty)
thumbnailstring | nullThumbnail URL (optional)
updatedAtstring | nullISO 8601 timestamp (optional)
expiresAtstring | nullISO 8601 expiry timestamp (optional)

Local development#

Install dependencies

Apply local migrations

Start the development server

Run tests and type checking

The Android debug build points at http://10.0.2.2:8787/ automatically.

Deploy to production#

Migration is required to create the offer schema, de-duplication columns, coordinate support, ingest leases, and to remove mock rows left by older deployments.

Tip

Set ENABLE_MOCK_SOURCE=true locally for demo data. Production keeps this disabled.

Next steps#