---
id: public-api.quickstart
title: Your First API Request
summary: Configure issued workspace identifiers, authenticate a read and choose an ingestion or evaluation workflow.
kind: quickstart
product_area: public_api
status: stable
updated: 2026-10-31
canonical: /docs/public-api/quickstart
---

# Your First API Request

## Prerequisites

Use an existing workspace and Project, a key with Project read access injected as `TEAMMATELY_API_KEY`, and curl. Copy the organization key and issued Project ID from Teammately; replace the placeholders below.

## Configure the destination

```sh
export TEAMMATELY_ORGANIZATION='<organization-key>'
export TEAMMATELY_PROJECT='<issued-project-id>'
PROJECT_URL="https://api.teammately.ai/v1/organizations/${TEAMMATELY_ORGANIZATION}"
PROJECT_URL="${PROJECT_URL}/projects/${TEAMMATELY_PROJECT}"
export PROJECT_URL
```

Only nonsecret identifiers are configured here. Keep the API key out of URLs, source and shell history.

## Send a read request

### Example: Retrieve a Case page

```sh
curl --fail-with-body \
  --header "Authorization: Bearer ${TEAMMATELY_API_KEY}" \
  "${PROJECT_URL}/cases?limit=1&offset=0"
```

```python
import os
from urllib.parse import quote, urlencode
from urllib.request import HTTPRedirectHandler, Request, build_opener

class NoRedirect(HTTPRedirectHandler):
    def redirect_request(self, req, fp, code, msg, headers, newurl):
        return None

opener = build_opener(NoRedirect())
api_key = os.environ["TEAMMATELY_API_KEY"]

url = os.environ["PROJECT_URL"] + "/cases"
url += "?" + urlencode({"limit": "1", "offset": "0"})
headers = {"Authorization": "Bearer " + api_key}
request = Request(url, headers=headers, method="GET")
with opener.open(request) as response:
    print(response.read().decode("utf-8"))
```

```typescript
const apiKey = process.env.TEAMMATELY_API_KEY!;

{
  const url = new URL(process.env.PROJECT_URL! + "/cases");
  url.searchParams.set("limit", "1");
  url.searchParams.set("offset", "0");
  const response = await fetch(url, {
    method: "GET",
    redirect: "error",
    headers: {
      Authorization: `Bearer ${apiKey}`,
    },
  });
  if (!response.ok) throw new Error(`HTTP ${response.status}`);
  console.log(await response.text());
}
```

```go
package main

import (
    "context"
    "fmt"
    "io"
    "log"
    "net/http"
    "net/url"
    "os"
)

func main() {
    if err := run(context.Background()); err != nil { log.Fatal(err) }
}

func run(ctx context.Context) error {
    client := &http.Client{
        CheckRedirect: func(req *http.Request, via []*http.Request) error {
            return http.ErrUseLastResponse
        },
    }
    {
        target := os.Getenv("PROJECT_URL") + "/cases"
        query := url.Values{}
        query.Set("limit", "1")
        query.Set("offset", "0")
        target += "?" + query.Encode()
        request, err := http.NewRequestWithContext(ctx, "GET", target, nil)
        if err != nil { return err }
        request.Header.Set("Authorization", "Bearer " + os.Getenv("TEAMMATELY_API_KEY"))
        response, err := client.Do(request)
        if err != nil { return err }
        payloadBytes, readErr := io.ReadAll(response.Body)
        response.Body.Close()
        if readErr != nil { return readErr }
        fmt.Println(string(payloadBytes))
        if response.StatusCode < 200 || response.StatusCode >= 300 { return fmt.Errorf("HTTP %d", response.StatusCode) }
    }
    return nil
}
```

The response has `message` and `data.columns`/`data.rows`. Empty `rows` can be a valid empty Project. Read a returned `case_id` through `/cases/{caseId}`; that detail response uses `result`.

## Choose the next workflow

| Goal | Guide |
| --- | --- |
| Capture application behavior | [Fieldloop](/docs/public-api/fieldloop) or a [language SDK](/docs/sdks) |
| Import Cases | [Case imports](/docs/public-api/case-imports) |
| Evaluate application outputs | [External outputs](/docs/public-api/evaluation-outputs) |
| Execute a managed Harness | [Managed execution](/docs/public-api/managed-execution) |

Benchmark workflows also need the exact Benchmark and immutable Version:

```sh
export TEAMMATELY_BENCHMARK='<issued-benchmark-id>'
export TEAMMATELY_BENCHMARK_VERSION='<issued-benchmark-version-id>'
BENCHMARK_URL="${PROJECT_URL}/benchmarks/${TEAMMATELY_BENCHMARK}"
BENCHMARK_URL="${BENCHMARK_URL}/versions/${TEAMMATELY_BENCHMARK_VERSION}"
export BENCHMARK_URL
```

## Success and common failures

This read changes no Case. Confirm the intended Project and parse its envelope. A Fieldloop-only key does not authorize a general Case read. For `401`, inspect credential validity; for `403`, inspect capability and restrictions; for `404`, check resource scope.

## Related reference pages

{% related-card-grid %}
- [Authentication](/docs/public-api/authentication)
- [Conventions](/docs/public-api/conventions)
- [Permissions troubleshooting](/docs/troubleshooting/permissions)
{% /related-card-grid %}
