PHP
Use PHP's cURL extension to call the Telemetry HTTP API from server-side application code.
Send an event
<?php
$apiKey = getenv("TELEMETRY_API_KEY");
$payload = [
"table" => "api_requests",
"data" => [
"route_template" => "/api/projects/:id",
"method" => "GET",
"status_code" => 200,
"latency_ms" => 184,
],
];
$request = curl_init("https://api.telemetry.sh/log");
curl_setopt_array($request, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: " . $apiKey,
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => json_encode($payload, JSON_THROW_ON_ERROR),
]);
$body = curl_exec($request);
$status = curl_getinfo($request, CURLINFO_HTTP_CODE);
if ($body === false || $status < 200 || $status >= 300) {
throw new RuntimeException("Telemetry log failed with HTTP " . $status);
}
curl_close($request);
Telemetry adds timestamp_utc to every row. Keep the API key in a server-side environment variable and send categorized error context rather than raw request bodies, credentials, or private customer content.
Run a SQL query
Use a read-scoped key when the process only queries data.
<?php
$sql = <<<'SQL'
SELECT
route_template,
COUNT(*) AS requests,
ROUND(AVG(latency_ms), 0) AS avg_latency_ms
FROM api_requests
WHERE timestamp_utc >= now() - INTERVAL '24 hours'
GROUP BY route_template
ORDER BY requests DESC;
SQL;
$request = curl_init("https://api.telemetry.sh/query");
curl_setopt_array($request, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: " . $apiKey,
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => json_encode(["query" => $sql], JSON_THROW_ON_ERROR),
]);
$body = curl_exec($request);
$status = curl_getinfo($request, CURLINFO_HTTP_CODE);
if ($body === false || $status < 200 || $status >= 300) {
throw new RuntimeException("Telemetry query failed with HTTP " . $status);
}
$results = json_decode($body, true, flags: JSON_THROW_ON_ERROR);
curl_close($request);
Production checklist
Set cURL connection and request timeouts, handle non-2xx responses without printing the API key, and retry only transient failures with backoff. Keep event names and field types stable as the table evolves. Exercise success, failure, retry, and timeout branches with synthetic events before creating an operational alert.
See the Log API, Query API, and SQL recipe library for more examples.