Graveinfo.Kobler gravere og infrastruktureiere

Kodeeksempler

Kopier og tilpass eksemplene under. Alle eksempler forutsetter at API-nøkkelen er lagret i miljøvariabelen GRAVEINFO_API_KEY.

Organisasjonssøk

Søk etter infrastruktureiere og entreprenører. Se full referanse →

curl

bash
# Søk etter infrastruktureiere med navn
curl "https://graveinfo.no/api/v1/organizations/search?q=Elvia&type=owner" \
  -H "Authorization: Bearer $GRAVEINFO_API_KEY"

# Oppslag på organisasjonsnummer
curl "https://graveinfo.no/api/v1/organizations/search?orgnr=920197106" \
  -H "Authorization: Bearer $GRAVEINFO_API_KEY"

# Filtrer på kommune (0301 = Oslo)
curl "https://graveinfo.no/api/v1/organizations/search?q=vann&municipality=0301&limit=10" \
  -H "Authorization: Bearer $GRAVEINFO_API_KEY"

# Paginering - side 2 med 20 resultater per side
curl "https://graveinfo.no/api/v1/organizations/search?q=nett&limit=20&offset=20" \
  -H "Authorization: Bearer $GRAVEINFO_API_KEY"

JavaScript / TypeScript

Fungerer i Node.js (18+), Deno og i nettleseren. Ingen eksterne avhengigheter.

typescript
const GRAVEINFO_API_KEY = process.env.GRAVEINFO_API_KEY;
const BASE_URL = 'https://graveinfo.no/api/v1';

async function searchOrganizations(query: string, options?: {
  type?: 'owner' | 'contractor' | 'all';
  municipality?: string;
  limit?: number;
  offset?: number;
}) {
  const params = new URLSearchParams({ q: query });
  if (options?.type) params.set('type', options.type);
  if (options?.municipality) params.set('municipality', options.municipality);
  if (options?.limit) params.set('limit', String(options.limit));
  if (options?.offset) params.set('offset', String(options.offset));

  const response = await fetch(`${BASE_URL}/organizations/search?${params}`, {
    headers: {
      'Authorization': `Bearer ${GRAVEINFO_API_KEY}`,
    },
  });

  if (!response.ok) {
    const error = await response.json();
    throw new Error(`API error ${response.status}: ${error.error?.message}`);
  }

  return response.json();
}

// Eksempel: søk etter alle infrastruktureiere i Oslo
const result = await searchOrganizations('vann', {
  type: 'owner',
  municipality: '0301',
});

console.log(`Fant ${result.meta.total} resultater`);
result.data.forEach((org) => {
  console.log(`${org.name} (${org.orgnr}) - gravemottak: ${org.gravemottak}`);
});

Paginering

Bruk en async generator for å hente alle sider automatisk:

typescript
async function* paginateOrganizations(query: string, pageSize = 20) {
  let offset = 0;
  let total = Infinity;

  while (offset < total) {
    const result = await searchOrganizations(query, { limit: pageSize, offset });
    total = result.meta.total;
    yield* result.data;
    offset += pageSize;
  }
}

// Hent alle treff for "nett"
for await (const org of paginateOrganizations('nett')) {
  console.log(org.name);
}

Python

Krever requests (pip install requests).

python
import os
import requests

GRAVEINFO_API_KEY = os.environ["GRAVEINFO_API_KEY"]
BASE_URL = "https://graveinfo.no/api/v1"

def search_organizations(query: str, **kwargs) -> dict:
    """Søk etter organisasjoner i Graveinfo."""
    params = {"q": query, **kwargs}
    response = requests.get(
        f"{BASE_URL}/organizations/search",
        params=params,
        headers={"Authorization": f"Bearer {GRAVEINFO_API_KEY}"},
        timeout=10,
    )
    response.raise_for_status()
    return response.json()


# Eksempel: søk etter infrastruktureiere i Bergen (1201)
result = search_organizations("vann", type="owner", municipality="1201", limit=10)

print(f"Fant {result['meta']['total']} resultater")
for org in result["data"]:
    print(f"  {org['name']} ({org['orgnr']}) - {org['gravemottak']}")

Paginering

python
def paginate_organizations(query: str, page_size: int = 20):
    """Generator som henter alle sider for et søk."""
    offset = 0
    while True:
        result = search_organizations(query, limit=page_size, offset=offset)
        yield from result["data"]
        offset += page_size
        if offset >= result["meta"]["total"]:
            break

# Hent alle "nett"-organisasjoner
for org in paginate_organizations("nett"):
    print(org["name"])

Feilhåndtering

python
import requests

try:
    result = search_organizations("elvia")
except requests.exceptions.HTTPError as e:
    if e.response.status_code == 429:
        print("Rate limit nådd - vent ett minutt")
    elif e.response.status_code == 401:
        print("Ugyldig API-nøkkel")
    else:
        error = e.response.json()
        print(f"API-feil: {error['error']['message']}")

Infrastrukturdekning per kommune

Finn alle infrastruktureiere registrert i en kommune. Se full referanse →

curl

bash
# Finn alle infrastruktureiere i Oslo (0301)
curl "https://graveinfo.no/api/v1/coverage?municipality=0301" \
  -H "Authorization: Bearer $GRAVEINFO_API_KEY"

# Filtrer på infrastrukturtype
curl "https://graveinfo.no/api/v1/coverage?municipality=0301&type=vann_avlop" \
  -H "Authorization: Bearer $GRAVEINFO_API_KEY"

JavaScript / TypeScript

typescript
async function getCoverage(municipalityNumber: string, type?: string) {
  const params = new URLSearchParams({ municipality: municipalityNumber });
  if (type) params.set('type', type);

  const response = await fetch(
    `${BASE_URL}/coverage?${params}`,
    { headers: { 'Authorization': `Bearer ${GRAVEINFO_API_KEY}` } },
  );

  if (!response.ok) {
    const error = await response.json();
    throw new Error(`API error ${response.status}: ${error.error?.message}`);
  }

  return response.json();
}

// Vis alle eiere i en kommune
const coverage = await getCoverage('0301');
console.log(`${coverage.municipality.name}: ${coverage.total} infrastruktureiere`);

for (const owner of coverage.owners) {
  const types = owner.infrastructureTypes.join(', ');
  console.log(`  ${owner.name} - ${types} (${owner.gravemottak})`);
}

Python

python
def get_coverage(municipality_number: str, infra_type: str | None = None) -> dict:
    """Hent infrastruktureiere for en gitt kommune."""
    params: dict = {"municipality": municipality_number}
    if infra_type:
        params["type"] = infra_type
    response = requests.get(
        f"{BASE_URL}/coverage",
        params=params,
        headers={"Authorization": f"Bearer {GRAVEINFO_API_KEY}"},
        timeout=10,
    )
    response.raise_for_status()
    return response.json()


# Bygg en oversikt over alle kommuner
municipalities = ["0301", "4601", "1201"]  # Oslo, Bergen, Stavanger

for mun_num in municipalities:
    coverage = get_coverage(mun_num)
    mun_name = coverage["municipality"]["name"]
    count = coverage["total"]
    print(f"{mun_name} ({mun_num}): {count} infrastruktureiere")

Send gravemelding

Opprett og send en gravemelding til infrastruktureiere i arbeidsområdet. Se steg-for-steg-guide →

Polygon-koordinater: Koordinater MÅ bruke EPSG:25833 (UTM sone 33N) - ikke WGS84/bredde-/lengdegrad. Eksemplene under bruker koordinater i nærheten av Oslo sentrum.

curl

bash
curl -X POST "https://graveinfo.no/api/v1/gravemeldinger" \
  -H "Authorization: Bearer $GRAVEINFO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Graving Storgata 12",
    "description": "Legging av fiberkabel langs Storgata 12-18",
    "work_types": ["telekommunikasjon", "grunnarbeid"],
    "polygon": {
      "type": "Polygon",
      "coordinates": [[
        [258000, 6648000],
        [258100, 6648000],
        [258100, 6648100],
        [258000, 6648100],
        [258000, 6648000]
      ]]
    },
    "planned_start": "2026-06-01",
    "planned_end": "2026-06-14",
    "contact_person": "Ola Nordmann",
    "contact_phone": "91234567",
    "adresse": "Storgata 12, Oslo"
  }'

JavaScript / TypeScript

typescript
interface GravemeldingInput {
  title: string;
  description?: string;
  work_types: string[];
  polygon: { type: 'Polygon'; coordinates: number[][][] };
  planned_start: string;
  planned_end: string;
  contact_person: string;
  contact_phone: string;
  adresse?: string;
}

async function sendGravemelding(input: GravemeldingInput) {
  const response = await fetch(`${BASE_URL}/gravemeldinger`, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${GRAVEINFO_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(input),
  });

  if (!response.ok) {
    const error = await response.json();
    throw new Error(`API error ${response.status}: ${error.error?.message}`);
  }

  return response.json();
}

// Polygon i EPSG:25833 (UTM sone 33N)
const result = await sendGravemelding({
  title: 'Graving Storgata 12',
  description: 'Legging av fiberkabel langs Storgata 12-18',
  work_types: ['telekommunikasjon', 'grunnarbeid'],
  polygon: {
    type: 'Polygon',
    coordinates: [[
      [258000, 6648000],
      [258100, 6648000],
      [258100, 6648100],
      [258000, 6648100],
      [258000, 6648000],
    ]],
  },
  planned_start: '2026-06-01',
  planned_end: '2026-06-14',
  contact_person: 'Ola Nordmann',
  contact_phone: '91234567',
  adresse: 'Storgata 12, Oslo',
});

console.log(`Sendt! Ref: ${result.reference_number}`);
console.log(`Varslet ${result.recipient_count} mottakere`);
console.log(`Kartfrist: ${result.kart_frist}`);

Python

python
def send_gravemelding(
    title: str,
    work_types: list[str],
    polygon_coords: list[list[list[float]]],
    planned_start: str,
    planned_end: str,
    contact_person: str,
    contact_phone: str,
    description: str | None = None,
    adresse: str | None = None,
) -> dict:
    """Opprett og send en gravemelding.

    polygon_coords: koordinater i EPSG:25833 (UTM sone 33N).
    """
    payload = {
        "title": title,
        "work_types": work_types,
        "polygon": {"type": "Polygon", "coordinates": polygon_coords},
        "planned_start": planned_start,
        "planned_end": planned_end,
        "contact_person": contact_person,
        "contact_phone": contact_phone,
    }
    if description:
        payload["description"] = description
    if adresse:
        payload["adresse"] = adresse

    response = requests.post(
        f"{BASE_URL}/gravemeldinger",
        json=payload,
        headers={"Authorization": f"Bearer {GRAVEINFO_API_KEY}"},
        timeout=30,
    )
    response.raise_for_status()
    return response.json()


# Polygon i EPSG:25833 (UTM sone 33N) - liten firkant nær Oslo
coords = [[
    [258000, 6648000],
    [258100, 6648000],
    [258100, 6648100],
    [258000, 6648100],
    [258000, 6648000],
]]

result = send_gravemelding(
    title="Graving Storgata 12",
    work_types=["telekommunikasjon", "grunnarbeid"],
    polygon_coords=coords,
    planned_start="2026-06-01",
    planned_end="2026-06-14",
    contact_person="Ola Nordmann",
    contact_phone="91234567",
    description="Legging av fiberkabel langs Storgata 12-18",
    adresse="Storgata 12, Oslo",
)

print(f"Sendt! Referanse: {result['reference_number']}")
print(f"Varslet {result['recipient_count']} mottakere")
print(f"Kartfrist: {result['kart_frist']}")

List og hent gravemeldinger

Les gravemeldinger og sjekk mottakerstatus.

curl

bash
# List alle gravemeldinger
curl "https://graveinfo.no/api/v1/gravemeldinger" \
  -H "Authorization: Bearer $GRAVEINFO_API_KEY"

# Filtrer på status
curl "https://graveinfo.no/api/v1/gravemeldinger?status=sent" \
  -H "Authorization: Bearer $GRAVEINFO_API_KEY"

# Hent én gravemelding med mottakerstatus
curl "https://graveinfo.no/api/v1/gravemeldinger/550e8400-e29b-41d4-a716-446655440000" \
  -H "Authorization: Bearer $GRAVEINFO_API_KEY"

JavaScript / TypeScript

typescript
async function listGravemeldinger(options?: {
  status?: 'draft' | 'sent' | 'in_progress' | 'completed';
  from?: string;
  to?: string;
  limit?: number;
  offset?: number;
}) {
  const params = new URLSearchParams();
  if (options?.status) params.set('status', options.status);
  if (options?.from) params.set('from', options.from);
  if (options?.to) params.set('to', options.to);
  if (options?.limit) params.set('limit', String(options.limit));
  if (options?.offset) params.set('offset', String(options.offset));

  const url = `${BASE_URL}/gravemeldinger${params.toString() ? '?' + params : ''}`;
  const response = await fetch(url, {
    headers: { 'Authorization': `Bearer ${GRAVEINFO_API_KEY}` },
  });

  if (!response.ok) {
    const error = await response.json();
    throw new Error(`API error ${response.status}: ${error.error?.message}`);
  }

  return response.json();
}

async function getGravemelding(id: string) {
  const response = await fetch(`${BASE_URL}/gravemeldinger/${id}`, {
    headers: { 'Authorization': `Bearer ${GRAVEINFO_API_KEY}` },
  });

  if (!response.ok) {
    const error = await response.json();
    throw new Error(`API error ${response.status}: ${error.error?.message}`);
  }

  return response.json();
}

// Hent alle som venter på svar, og vis konflikter
const { data } = await listGravemeldinger({ status: 'sent' });
for (const gm of data) {
  if (gm.summary.hasConflicts) {
    const detail = await getGravemelding(gm.id);
    const conflicts = detail.recipients.filter((r) => r.response === 'conflict');
    console.log(`${gm.referenceNumber}: ${conflicts.length} konflikter`);
    conflicts.forEach((r) => console.log(`  - ${r.name}: ${r.responseNote}`));
  }
}

Sett miljøvariabelen

bash / zshexport GRAVEINFO_API_KEY="gv_live_..."
.env-filGRAVEINFO_API_KEY=gv_live_...
Node.js dotenvrequire("dotenv").config()