$ok,'data_mode'=>$mode, 'licence'=>'Open data licence, attribution required', 'citation'=>'Districthive Research Labs · The Skerðingsstaðir Experiment', 'data'=>$data]); exit; } $key=$_GET['key']??''; $kh=hash('sha256',$key); $row=$key?db()->prepare('SELECT id FROM api_keys WHERE key_hash=? AND active=1'):null; if($row){$row->execute([$kh]);$row=$row->fetch();} if(!$row){ http_response_code(401); out(false,['error'=>'valid key required; request one via the About page']); } db()->prepare('UPDATE api_keys SET last_used_at=NOW() WHERE key_hash=?')->execute([$kh]); log_activity('api',$_GET['action']??'?', substr(($_GET['stream']??''),0,40)); $action=$_GET['action']??'streams'; if($action==='streams'){ $q=db()->query("SELECT s.code,s.label,s.unit,s.mode,s.visibility,i.product,i.cadence_min FROM streams s JOIN instruments i ON i.id=s.instrument_id WHERE s.visibility IN ('public','keyed')"); out(true,$q->fetchAll()); } if($action==='readings'){ $s=stream_by_code(preg_replace('/[^a-z0-9_]/','',$_GET['stream']??'')); if(!$s||$s['visibility']==='hidden') out(false,['error'=>'unknown or restricted stream']); $from=($_GET['from']??date('Y-m-d',strtotime('-7 days'))).' 00:00:00'; $to=($_GET['to']??date('Y-m-d')).' 23:59:59'; out(true,array_map(fn($r)=>[$r['ts'],(float)$r['value']],series($s,$from,$to,2000)),$s['mode']); } if($action==='events'){ $cls=preg_replace('/[^a-z]/','',$_GET['class']??''); $sql="SELECT ts,class,detail FROM events WHERE is_public=1".($cls?" AND class=".db()->quote($cls):"")." ORDER BY ts DESC LIMIT 500"; out(true,db()->query($sql)->fetchAll()); } if($action==='checksums'){ $p=$_GET['path']??''; $q=db()->prepare('SELECT path,sha256,bytes,pulled_at FROM files_raw WHERE path=?'); $q->execute([$p]); out(true,$q->fetch()?:['error'=>'not found']); } out(false,['error'=>'unknown action']);