# Make your first API call

Using a coding assistant? [Set up Docs MCP](https://developers.apideck.com/mcp#docs-mcp) for current Apideck documentation in any language. It needs no API key and does not access customer data. The Apideck MCP server for connected apps is separate.

The interactive workspace also offers **Try this read in Explorer**. It preserves the selected operation and connector and reuses Explorer credentials already saved in the same browser tab. Review the consumer and connection before clicking Run. If temporary credentials have expired, reopen Explorer from the dashboard. This does not prefill API keys in the code examples.

## Authentication and request headers

For Unified API calls, send these headers from your server:

- Authorization: Bearer $API_KEY — your Apideck secret API key, never a downstream connector token.
- x-apideck-app-id: $APP_ID — the Apideck application that owns the key.
- x-apideck-consumer-id: $CONSUMER_ID — the customer whose connection you authorized in Vault.
- x-apideck-service-id: the selected connector ID, such as xero or salesforce. Set it explicitly to avoid selecting the wrong connection.

Keep secrets out of browser code and URLs. A connected Vault consumer is required before reading customer data. These headers apply to Accounting, CRM, HRIS and Ecommerce; select the API-specific endpoint below.


Choose Accounting, CRM, HRIS, or Ecommerce in the workspace. Each API has its own endpoint, prerequisites, and code.

## Accounting: list invoices

Read one page of invoices from a connected company, verify the result, and carry that working connection into your integration.

This example reads one page of up to 10 invoices. It does not create records. The [interactive workspace](https://developers.apideck.com/first-api-call) preserves language and connector choices in its URL. This Markdown mirror contains all language variants. Add ?api=crm, ?api=hris, or ?api=ecommerce to read a different API example; language and connector parameters do not tailor the Markdown.

## Prepare the connection

- Enable the Accounting API and your connector in your Apideck application.
- Use a test company and a consumer mapped to that customer. Authorize the connector through Vault and complete its required settings.
- Confirm that the connector supports listing invoices and that the authorizing user can read them. Selecting a connector here does not verify support.
- Set the environment variables below in your terminal or server. Never use an API key in browser code, a NEXT_PUBLIC variable, or a shared URL.

[Enable your account](https://developers.apideck.com/get-started.md), [connect with Vault](https://developers.apideck.com/guides/vault.md), then [check invoice coverage](https://developers.apideck.com/apis/accounting/coverage?resources=invoices).

Set APIDECK_API_KEY, APIDECK_APP_ID, APIDECK_CONSUMER_ID and APIDECK_SERVICE_ID in your server environment. Use the consumer that owns the authorized connection and its connector ID (for example quickbooks or xero). Never include credentials in shared URLs.

## Choose a language

### TypeScript

Node.js 24 or newer. This example uses native TypeScript execution and @apideck/unify 0.52.2.

Install or check prerequisites:

```sh
npm install @apideck/unify@0.52.2
```

Save as first-read.ts:

```typescript
import { Apideck } from "@apideck/unify";

function required(name: string): string {
  const value = process.env[name];
  if (!value) throw new Error(`Set ${name} in your server environment.`);
  return value;
}

async function main() {
  const serviceId = required("APIDECK_SERVICE_ID");
  const apideck = new Apideck({
    apiKey: required("APIDECK_API_KEY"),
    appId: required("APIDECK_APP_ID"),
    consumerId: required("APIDECK_CONSUMER_ID"),
  });
  const result = await apideck.accounting.invoices.list({ serviceId, limit: 10 });
  const body = result.getInvoicesResponse;
  if (!body || body.service !== serviceId) {
    throw new Error("Unexpected response. Check the request in Logs.");
  }
  console.log(JSON.stringify({
    status: body.status,
    service: body.service,
    records: body.data.length,
    nextCursor: body.meta?.cursors?.next ?? null,
  }, null, 2));
}

main().catch(() => {
  console.error("Read failed. Check environment variables and Apideck Logs.");
  process.exitCode = 1;
});
```

Run:

```sh
node first-read.ts
```

### Python

Python 3.9.2 or newer. Commands use a POSIX shell and apideck-unify 0.47.1.

Install or check prerequisites:

```sh
python3 -m venv .venv
. .venv/bin/activate
python -m pip install apideck-unify==0.47.1
```

Save as first_read.py:

```python
import json
import os
import sys
from apideck_unify import Apideck


def main():
    service_id = os.environ["APIDECK_SERVICE_ID"]
    with Apideck(
        api_key=os.environ["APIDECK_API_KEY"],
        app_id=os.environ["APIDECK_APP_ID"],
        consumer_id=os.environ["APIDECK_CONSUMER_ID"],
    ) as apideck:
        result = apideck.accounting.invoices.list(service_id=service_id, limit=10)
        body = result.get_invoices_response if result else None
        if body is None or body.service != service_id:
            raise RuntimeError("Unexpected response. Check the request in Logs.")
        cursor = body.meta.cursors.next if body.meta and body.meta.cursors else None
        print(json.dumps({
            "status": body.status,
            "service": body.service,
            "records": len(body.data),
            "nextCursor": cursor,
        }, indent=2))


try:
    main()
except Exception:
    print("Read failed. Check environment variables and Apideck Logs.", file=sys.stderr)
    sys.exit(1)
```

Run:

```sh
python first_read.py
```

### cURL

A POSIX shell and cURL 7.76 or newer (--fail-with-body). No SDK installation needed.

Install or check prerequisites:

```sh
curl --version
```

Save as first-read.sh:

```sh
#!/bin/sh
set -eu
: "${APIDECK_API_KEY:?Set APIDECK_API_KEY}"
: "${APIDECK_APP_ID:?Set APIDECK_APP_ID}"
: "${APIDECK_CONSUMER_ID:?Set APIDECK_CONSUMER_ID}"
: "${APIDECK_SERVICE_ID:?Set APIDECK_SERVICE_ID}"

curl --fail-with-body --silent --show-error \
  --url 'https://unify.apideck.com/accounting/invoices?limit=10' \
  --header "Authorization: Bearer $APIDECK_API_KEY" \
  --header "x-apideck-app-id: $APIDECK_APP_ID" \
  --header "x-apideck-consumer-id: $APIDECK_CONSUMER_ID" \
  --header "x-apideck-service-id: $APIDECK_SERVICE_ID" \
  --output response.json \
  --write-out 'HTTP %{http_code}\n'
# Inspect response.json locally. It may contain customer data.
```

Run:

```sh
sh first-read.sh
```

### JavaScript

Node.js 18 or newer. Uses direct HTTP; no SDK installation needed. Reads one page only.

Install or check prerequisites:

```sh
node --version
```

Save as first-read.mjs:

```javascript
function required(name) {
  const value = process.env[name];
  if (!value) throw new Error(`Set ${name} in your server environment.`);
  return value;
}

try {
  const service = required("APIDECK_SERVICE_ID");
  const response = await fetch("https://unify.apideck.com/accounting/invoices?limit=10", {
    headers: {
      Authorization: `Bearer ${required("APIDECK_API_KEY")}`,
      "x-apideck-app-id": required("APIDECK_APP_ID"),
      "x-apideck-consumer-id": required("APIDECK_CONSUMER_ID"),
      "x-apideck-service-id": service,
    },
    signal: AbortSignal.timeout(30000),
    redirect: "error",
  });
  if (!response.ok) throw new Error(`HTTP ${response.status}`);
  const body = await response.json();
  if (body.service !== service || !Array.isArray(body.data)) throw new Error("Unexpected response");
  console.log(JSON.stringify({ status: body.status, service: body.service,
    records: body.data.length, nextCursor: body.meta?.cursors?.next ?? null }, null, 2));
} catch {
  console.error("Read failed. Check environment variables and Apideck Logs.");
  process.exitCode = 1;
}
```

Run:

```sh
node first-read.mjs
```

### PHP

PHP 8 or newer with the cURL extension. Uses direct HTTP; no SDK installation needed. Reads one page only.

Install or check prerequisites:

```sh
php --version
php -m # Requires curl and json
```

Save as first-read.php:

```php
<?php
function required(string $name): string {
    $value = getenv($name);
    if ($value === false || $value === '') throw new RuntimeException("Missing environment variable");
    return $value;
}

try {
    $service = required('APIDECK_SERVICE_ID');
    $request = curl_init('https://unify.apideck.com/accounting/invoices?limit=10');
    curl_setopt_array($request, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => 30,
        CURLOPT_HTTPHEADER => [
            'Authorization: Bearer ' . required('APIDECK_API_KEY'),
            'x-apideck-app-id: ' . required('APIDECK_APP_ID'),
            'x-apideck-consumer-id: ' . required('APIDECK_CONSUMER_ID'),
            'x-apideck-service-id: ' . $service,
        ],
    ]);
    $response = curl_exec($request);
    $status = curl_getinfo($request, CURLINFO_HTTP_CODE);
    if ($response === false || $status < 200 || $status >= 300) throw new RuntimeException('Read failed');
    $body = json_decode($response, true, 512, JSON_THROW_ON_ERROR);
    if (($body['service'] ?? null) !== $service || !is_array($body['data'] ?? null)) {
        throw new RuntimeException('Unexpected response');
    }
    echo json_encode([
        'status' => $body['status'], 'service' => $body['service'],
        'records' => count($body['data']), 'nextCursor' => $body['meta']['cursors']['next'] ?? null,
    ], JSON_PRETTY_PRINT) . PHP_EOL;
} catch (Throwable $error) {
    fwrite(STDERR, "Read failed. Check environment variables and Apideck Logs.\n");
    exit(1);
}
```

Run:

```sh
php first-read.php
```

### Go

Go 1.20 or newer. Uses direct HTTP; no SDK installation needed. Reads one page only.

Install or check prerequisites:

```sh
go version
```

Save as first-read.go:

```go
package main

import (
    "encoding/json"
    "errors"
    "fmt"
    "net/http"
    "os"
    "time"
)

func read() error {
    req, err := http.NewRequest("GET", "https://unify.apideck.com/accounting/invoices?limit=10", nil)
    if err != nil { return err }
    for header, name := range map[string]string{
        "Authorization": "APIDECK_API_KEY",
        "x-apideck-app-id": "APIDECK_APP_ID",
        "x-apideck-consumer-id": "APIDECK_CONSUMER_ID",
        "x-apideck-service-id": "APIDECK_SERVICE_ID",
    } {
        value := os.Getenv(name)
        if value == "" { return errors.New("missing environment variable") }
        if header == "Authorization" { value = "Bearer " + value }
        req.Header.Set(header, value)
    }
    client := &http.Client{Timeout: 30 * time.Second,
        CheckRedirect: func(_ *http.Request, _ []*http.Request) error { return http.ErrUseLastResponse }}
    res, err := client.Do(req)
    if err != nil { return err }
    defer res.Body.Close()
    if res.StatusCode < 200 || res.StatusCode >= 300 { return errors.New("read failed") }
    var body struct {
        Status string `json:"status"`
        Service string `json:"service"`
        Data []json.RawMessage `json:"data"`
        Meta struct { Cursors struct { Next *string `json:"next"` } `json:"cursors"` } `json:"meta"`
    }
    if err := json.NewDecoder(res.Body).Decode(&body); err != nil { return err }
    if body.Service != os.Getenv("APIDECK_SERVICE_ID") || body.Data == nil { return errors.New("unexpected response") }
    return json.NewEncoder(os.Stdout).Encode(map[string]any{
        "status": body.Status, "service": body.Service,
        "records": len(body.Data), "nextCursor": body.Meta.Cursors.Next,
    })
}

func main() {
    if err := read(); err != nil {
        fmt.Fprintln(os.Stderr, "Read failed. Check environment variables and Apideck Logs.")
        os.Exit(1)
    }
}
```

Run:

```sh
go run first-read.go
```

### C# / .NET

.NET 8 or newer. Create the project, then replace Program.cs. Uses direct HTTP; no SDK installation needed. Reads one page only.

Install or check prerequisites:

```sh
dotnet new console -o first-read
cd first-read
```

Save as Program.cs:

```dot-net
using System.Net.Http;
using System.Text.Json;

string Required(string name) => Environment.GetEnvironmentVariable(name) is { Length: > 0 } value
    ? value : throw new InvalidOperationException("Missing environment variable");

try
{
    var service = Required("APIDECK_SERVICE_ID");
    using var client = new HttpClient(new HttpClientHandler { AllowAutoRedirect = false })
        { Timeout = TimeSpan.FromSeconds(30) };
    using var request = new HttpRequestMessage(HttpMethod.Get,
        "https://unify.apideck.com/accounting/invoices?limit=10");
    request.Headers.Add("Authorization", "Bearer " + Required("APIDECK_API_KEY"));
    request.Headers.Add("x-apideck-app-id", Required("APIDECK_APP_ID"));
    request.Headers.Add("x-apideck-consumer-id", Required("APIDECK_CONSUMER_ID"));
    request.Headers.Add("x-apideck-service-id", service);
    using var response = await client.SendAsync(request);
    response.EnsureSuccessStatusCode();
    using var document = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
    var body = document.RootElement;
    if (body.GetProperty("service").GetString() != service)
        throw new InvalidOperationException("Unexpected service");
    string? next = body.TryGetProperty("meta", out var meta) && meta.ValueKind == JsonValueKind.Object
        && meta.TryGetProperty("cursors", out var cursors) && cursors.ValueKind == JsonValueKind.Object
        && cursors.TryGetProperty("next", out var cursor) ? cursor.GetString() : null;
    Console.WriteLine(JsonSerializer.Serialize(new {
        status = body.GetProperty("status").GetString(), service,
        records = body.GetProperty("data").GetArrayLength(), nextCursor = next
    }));
}
catch
{
    Console.Error.WriteLine("Read failed. Check environment variables and Apideck Logs.");
    Environment.ExitCode = 1;
}
```

Run:

```sh
dotnet run
```

### Java

Java 11 or newer. Uses direct HTTP; no SDK installation needed. Reads one page only.

Install or check prerequisites:

```sh
java --version
```

Save as FirstRead.java:

```java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;

class FirstRead {
    static String required(String name) {
        String value = System.getenv(name);
        if (value == null || value.isEmpty()) throw new IllegalStateException("Missing environment variable");
        return value;
    }

    public static void main(String[] args) {
        try {
            HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://unify.apideck.com/accounting/invoices?limit=10"))
                .timeout(Duration.ofSeconds(30))
                .header("Authorization", "Bearer " + required("APIDECK_API_KEY"))
                .header("x-apideck-app-id", required("APIDECK_APP_ID"))
                .header("x-apideck-consumer-id", required("APIDECK_CONSUMER_ID"))
                .header("x-apideck-service-id", required("APIDECK_SERVICE_ID"))
                .GET().build();
            HttpClient client = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(30)).build();
            HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
            System.out.println("HTTP " + response.statusCode());
            if (response.statusCode() < 200 || response.statusCode() >= 300)
                throw new IllegalStateException("Read failed");
            Files.writeString(Path.of("response.json"), response.body());
            // Inspect service, data and meta.cursors.next locally. Keep customer data out of version control.
            System.out.println("Saved response.json. Verify the service and records before continuing.");
        } catch (Exception error) {
            System.err.println("Read failed. Check environment variables and Apideck Logs.");
            System.exit(1);
        }
    }
}
```

Run:

```sh
java FirstRead.java
```


## Verify the result

TypeScript, Python, JavaScript, PHP, Go and C# print status, service, record count and next cursor. cURL and Java print the HTTP status and saves the full response in response.json; inspect it locally and keep it out of version control. No example fetches subsequent pages.

- Confirm a successful HTTP response and that the response service matches the connector you authorized.
- Inspect the request in Logs and confirm the consumer and company match your intended test connection. HTTP success alone does not establish the correct company.
- An empty data array can be valid. Compare with the source company and permissions before treating it as a complete dataset.
- This example reads only the first page. A next cursor means more records exist; use the pagination guide before building a complete sync.

[Request logs](https://developers.apideck.com/logs.md) · [Pagination and sync](https://developers.apideck.com/guides/syncing-accounting-data-at-scale.md) · [List invoices](https://developers.apideck.com/apis/accounting/reference/invoices/invoicesAll.md)

### Record what you verified

Record your own checks, then copy a review brief for a teammate or coding agent. This workspace does not execute or inspect your request. Choices stay in this page session and reset when you change language or connector, or reload.

- **I have not run the request:** Run the read above, then compare the response with your intended connection.
- **The request failed:** Inspect the request in Logs, then use the troubleshooting guidance for authentication, configuration, coverage or downstream errors.
- **The request succeeded with no invoices:** An empty page can be valid. Compare the company and user permissions with the source application before treating it as a complete dataset.
- **The request succeeded with invoices:** Verify the service, company and first page before planning a complete sync. Check the next cursor even when the first page looks correct.

After a successful response, record only checks you have completed:

- [ ] Successful response and expected service
- [ ] Correct consumer and company confirmed in Logs
- [ ] Records or empty result compared with the source
- [ ] Next cursor checked; first-page limit understood

The interactive workspace creates a copyable review brief with your selected connector, language, reported result, completed checks and source links. Unchecked items remain open; the brief asks for missing evidence and distinguishes a first page from a complete sync. These are developer-reported observations, not an automated verification. The workspace URL saves language and connector only, not checklist results. Keep credentials and customer payloads out of the brief.

## Build on this first read

Keep the same consumer and connector as your successful request. Keep credentials and customer identifiers in your local environment, not documentation URLs.

1. **Build one workflow:** follow [accounts receivable](https://developers.apideck.com/guides/accounts-receivable-automation.md), or your selected [use case](https://developers.apideck.com/use-cases.md). Resolve related records and verify the result with a read-back.
2. **Handle more records and failures:** add [pagination and recovery](https://developers.apideck.com/guides/syncing-accounting-data-at-scale.md). Finish when every page is processed and uncertain writes can be reconciled without duplication.
3. **React to changes:** add [webhooks](https://developers.apideck.com/guides/webhooks.md) when ongoing updates are needed. Verify signatures and test duplicate delivery.
4. **Extend connector behavior:** inspect coverage and downstream logs before adding [field mapping](https://developers.apideck.com/guides/field-mapping.md) or Proxy calls. Verify each extension with a test request.

## Troubleshoot

### Authentication or access denied

Check the App ID and server API key, the consumer that owns the connection, and the connector permissions. Reauthorize through Vault when needed.

[Read more](https://developers.apideck.com/guides/vault)

### Missing configuration or unsupported operation

Check the selected company, required connection settings, and invoice-list coverage for this connector. A unified endpoint is not a guarantee of provider support.

[Read more](https://developers.apideck.com/apis/accounting/coverage?resources=invoices)

### Empty or unexpected invoices

Compare the connected company and user permissions with the source application. Read the downstream response in Logs; do not create a test invoice until you have agreed to that write.

[Read more](https://developers.apideck.com/logs)

### Rate limits or downstream failures

Inspect the status, error details and retry guidance in Logs. Use bounded retries for transient reads and avoid adding a second retry loop around SDK retries.

[Read more](https://developers.apideck.com/errors)

## Next steps

[Plan the integration](https://developers.apideck.com/integration-plan.md) or [choose a workflow](https://developers.apideck.com/use-cases.md).


## First read with MCP

Select MCP in the workspace for a contextual agent prompt and client configuration. The Apideck MCP server (https://mcp.apideck.dev/mcp) accesses connected apps. Configure credentials locally, connect the intended consumer through Vault, check connector coverage, and approve a read of at most 10 records. Inspect the tool schema before execution. Verify the response service, source account and next cursor in Logs. Never paste keys or customer records into shared prompts.

[Client setup](https://developers.apideck.com/mcp#install). The separate [Documentation MCP](https://developers.apideck.com/mcp#docs-mcp), at https://developers.apideck.com/mcp, searches and reads docs without an API key; it does not execute requests against connected apps.

## First reads for CRM, HRIS, and Ecommerce

The workspace also selects these APIs. API, language, workflow, and connector choices are shareable; credentials and consumer IDs are not. Switching API resets incompatible connector/workflow choices. Without an API selection, all variants follow. Add ?api=crm, ?api=hris, or ?api=ecommerce for the corresponding API example. These are executable examples, not evidence of a successful live integration.

### CRM: list contacts

Read one page of contacts from your connected CRM workspace, verify the result, and continue with the same connector.

- Enable the CRM API and your connector in your Apideck application.
- Use a test CRM workspace and a consumer mapped to that customer. Authorize the connector in Vault and complete the required connection settings.
- Check list-contacts coverage and the source user’s record visibility. Selecting a connector does not establish support.
- Confirm which contacts the authorized CRM user can see; a successful request may still return a permission-limited subset.

Set APIDECK_API_KEY, APIDECK_APP_ID, APIDECK_CONSUMER_ID, and APIDECK_SERVICE_ID in your server environment or local POSIX shell. Choose the consumer owning the authorized connection. Never put these credentials in browser code, shared URLs, or agent briefs.

#### TypeScript

Node.js 24 or newer. This example uses native TypeScript execution and @apideck/unify 0.52.2.

```sh
npm install @apideck/unify@0.52.2
```

Save as first-read.ts:

```typescript
import { Apideck } from "@apideck/unify";

function required(name: string): string {
  const value = process.env[name];
  if (!value) throw new Error(`Set ${name} in your server environment.`);
  return value;
}

async function main() {
  const serviceId = required("APIDECK_SERVICE_ID");
  const apideck = new Apideck({
    apiKey: required("APIDECK_API_KEY"),
    appId: required("APIDECK_APP_ID"),
    consumerId: required("APIDECK_CONSUMER_ID"),
  });
  const result = await apideck.crm.contacts.list({ serviceId, limit: 10 });
  const body = result.getContactsResponse;
  if (!body || body.service !== serviceId) {
    throw new Error("Unexpected response. Check the request in Logs.");
  }
  console.log(JSON.stringify({
    status: body.status,
    service: body.service,
    records: body.data.length,
    nextCursor: body.meta?.cursors?.next ?? null,
  }, null, 2));
}

main().catch(() => {
  console.error("Read failed. Check environment variables and Apideck Logs.");
  process.exitCode = 1;
});
```

Run:

```sh
node first-read.ts
```

#### Python

Python 3.9.2 or newer. Commands use a POSIX shell and apideck-unify 0.47.1.

```sh
python3 -m venv .venv
. .venv/bin/activate
python -m pip install apideck-unify==0.47.1
```

Save as first_read.py:

```python
import json
import os
import sys
from apideck_unify import Apideck


def main():
    service_id = os.environ["APIDECK_SERVICE_ID"]
    with Apideck(
        api_key=os.environ["APIDECK_API_KEY"],
        app_id=os.environ["APIDECK_APP_ID"],
        consumer_id=os.environ["APIDECK_CONSUMER_ID"],
    ) as apideck:
        result = apideck.crm.contacts.list(service_id=service_id, limit=10)
        body = result.get_contacts_response if result else None
        if body is None or body.service != service_id:
            raise RuntimeError("Unexpected response. Check the request in Logs.")
        cursor = body.meta.cursors.next if body.meta and body.meta.cursors else None
        print(json.dumps({
            "status": body.status,
            "service": body.service,
            "records": len(body.data),
            "nextCursor": cursor,
        }, indent=2))


try:
    main()
except Exception:
    print("Read failed. Check environment variables and Apideck Logs.", file=sys.stderr)
    sys.exit(1)
```

Run:

```sh
python first_read.py
```

#### cURL

A POSIX shell and cURL 7.76 or newer (--fail-with-body). No SDK installation needed.

```sh
curl --version
```

Save as first-read.sh:

```sh
#!/bin/sh
set -eu
: "${APIDECK_API_KEY:?Set APIDECK_API_KEY}"
: "${APIDECK_APP_ID:?Set APIDECK_APP_ID}"
: "${APIDECK_CONSUMER_ID:?Set APIDECK_CONSUMER_ID}"
: "${APIDECK_SERVICE_ID:?Set APIDECK_SERVICE_ID}"

curl --fail-with-body --silent --show-error \
  --url 'https://unify.apideck.com/crm/contacts?limit=10' \
  --header "Authorization: Bearer $APIDECK_API_KEY" \
  --header "x-apideck-app-id: $APIDECK_APP_ID" \
  --header "x-apideck-consumer-id: $APIDECK_CONSUMER_ID" \
  --header "x-apideck-service-id: $APIDECK_SERVICE_ID" \
  --output response.json \
  --write-out 'HTTP %{http_code}\n'
# Inspect response.json locally. It may contain customer data.
```

Run:

```sh
sh first-read.sh
```

#### JavaScript

Node.js 18 or newer. Uses direct HTTP; no SDK installation needed. Reads one page only.

```sh
node --version
```

Save as first-read.mjs:

```javascript
function required(name) {
  const value = process.env[name];
  if (!value) throw new Error(`Set ${name} in your server environment.`);
  return value;
}

try {
  const service = required("APIDECK_SERVICE_ID");
  const response = await fetch("https://unify.apideck.com/crm/contacts?limit=10", {
    headers: {
      Authorization: `Bearer ${required("APIDECK_API_KEY")}`,
      "x-apideck-app-id": required("APIDECK_APP_ID"),
      "x-apideck-consumer-id": required("APIDECK_CONSUMER_ID"),
      "x-apideck-service-id": service,
    },
    signal: AbortSignal.timeout(30000),
    redirect: "error",
  });
  if (!response.ok) throw new Error(`HTTP ${response.status}`);
  const body = await response.json();
  if (body.service !== service || !Array.isArray(body.data)) throw new Error("Unexpected response");
  console.log(JSON.stringify({ status: body.status, service: body.service,
    records: body.data.length, nextCursor: body.meta?.cursors?.next ?? null }, null, 2));
} catch {
  console.error("Read failed. Check environment variables and Apideck Logs.");
  process.exitCode = 1;
}
```

Run:

```sh
node first-read.mjs
```

#### PHP

PHP 8 or newer with the cURL extension. Uses direct HTTP; no SDK installation needed. Reads one page only.

```sh
php --version
php -m # Requires curl and json
```

Save as first-read.php:

```php
<?php
function required(string $name): string {
    $value = getenv($name);
    if ($value === false || $value === '') throw new RuntimeException("Missing environment variable");
    return $value;
}

try {
    $service = required('APIDECK_SERVICE_ID');
    $request = curl_init('https://unify.apideck.com/crm/contacts?limit=10');
    curl_setopt_array($request, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => 30,
        CURLOPT_HTTPHEADER => [
            'Authorization: Bearer ' . required('APIDECK_API_KEY'),
            'x-apideck-app-id: ' . required('APIDECK_APP_ID'),
            'x-apideck-consumer-id: ' . required('APIDECK_CONSUMER_ID'),
            'x-apideck-service-id: ' . $service,
        ],
    ]);
    $response = curl_exec($request);
    $status = curl_getinfo($request, CURLINFO_HTTP_CODE);
    if ($response === false || $status < 200 || $status >= 300) throw new RuntimeException('Read failed');
    $body = json_decode($response, true, 512, JSON_THROW_ON_ERROR);
    if (($body['service'] ?? null) !== $service || !is_array($body['data'] ?? null)) {
        throw new RuntimeException('Unexpected response');
    }
    echo json_encode([
        'status' => $body['status'], 'service' => $body['service'],
        'records' => count($body['data']), 'nextCursor' => $body['meta']['cursors']['next'] ?? null,
    ], JSON_PRETTY_PRINT) . PHP_EOL;
} catch (Throwable $error) {
    fwrite(STDERR, "Read failed. Check environment variables and Apideck Logs.\n");
    exit(1);
}
```

Run:

```sh
php first-read.php
```

#### Go

Go 1.20 or newer. Uses direct HTTP; no SDK installation needed. Reads one page only.

```sh
go version
```

Save as first-read.go:

```go
package main

import (
    "encoding/json"
    "errors"
    "fmt"
    "net/http"
    "os"
    "time"
)

func read() error {
    req, err := http.NewRequest("GET", "https://unify.apideck.com/crm/contacts?limit=10", nil)
    if err != nil { return err }
    for header, name := range map[string]string{
        "Authorization": "APIDECK_API_KEY",
        "x-apideck-app-id": "APIDECK_APP_ID",
        "x-apideck-consumer-id": "APIDECK_CONSUMER_ID",
        "x-apideck-service-id": "APIDECK_SERVICE_ID",
    } {
        value := os.Getenv(name)
        if value == "" { return errors.New("missing environment variable") }
        if header == "Authorization" { value = "Bearer " + value }
        req.Header.Set(header, value)
    }
    client := &http.Client{Timeout: 30 * time.Second,
        CheckRedirect: func(_ *http.Request, _ []*http.Request) error { return http.ErrUseLastResponse }}
    res, err := client.Do(req)
    if err != nil { return err }
    defer res.Body.Close()
    if res.StatusCode < 200 || res.StatusCode >= 300 { return errors.New("read failed") }
    var body struct {
        Status string `json:"status"`
        Service string `json:"service"`
        Data []json.RawMessage `json:"data"`
        Meta struct { Cursors struct { Next *string `json:"next"` } `json:"cursors"` } `json:"meta"`
    }
    if err := json.NewDecoder(res.Body).Decode(&body); err != nil { return err }
    if body.Service != os.Getenv("APIDECK_SERVICE_ID") || body.Data == nil { return errors.New("unexpected response") }
    return json.NewEncoder(os.Stdout).Encode(map[string]any{
        "status": body.Status, "service": body.Service,
        "records": len(body.Data), "nextCursor": body.Meta.Cursors.Next,
    })
}

func main() {
    if err := read(); err != nil {
        fmt.Fprintln(os.Stderr, "Read failed. Check environment variables and Apideck Logs.")
        os.Exit(1)
    }
}
```

Run:

```sh
go run first-read.go
```

#### C# / .NET

.NET 8 or newer. Create the project, then replace Program.cs. Uses direct HTTP; no SDK installation needed. Reads one page only.

```sh
dotnet new console -o first-read
cd first-read
```

Save as Program.cs:

```dot-net
using System.Net.Http;
using System.Text.Json;

string Required(string name) => Environment.GetEnvironmentVariable(name) is { Length: > 0 } value
    ? value : throw new InvalidOperationException("Missing environment variable");

try
{
    var service = Required("APIDECK_SERVICE_ID");
    using var client = new HttpClient(new HttpClientHandler { AllowAutoRedirect = false })
        { Timeout = TimeSpan.FromSeconds(30) };
    using var request = new HttpRequestMessage(HttpMethod.Get,
        "https://unify.apideck.com/crm/contacts?limit=10");
    request.Headers.Add("Authorization", "Bearer " + Required("APIDECK_API_KEY"));
    request.Headers.Add("x-apideck-app-id", Required("APIDECK_APP_ID"));
    request.Headers.Add("x-apideck-consumer-id", Required("APIDECK_CONSUMER_ID"));
    request.Headers.Add("x-apideck-service-id", service);
    using var response = await client.SendAsync(request);
    response.EnsureSuccessStatusCode();
    using var document = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
    var body = document.RootElement;
    if (body.GetProperty("service").GetString() != service)
        throw new InvalidOperationException("Unexpected service");
    string? next = body.TryGetProperty("meta", out var meta) && meta.ValueKind == JsonValueKind.Object
        && meta.TryGetProperty("cursors", out var cursors) && cursors.ValueKind == JsonValueKind.Object
        && cursors.TryGetProperty("next", out var cursor) ? cursor.GetString() : null;
    Console.WriteLine(JsonSerializer.Serialize(new {
        status = body.GetProperty("status").GetString(), service,
        records = body.GetProperty("data").GetArrayLength(), nextCursor = next
    }));
}
catch
{
    Console.Error.WriteLine("Read failed. Check environment variables and Apideck Logs.");
    Environment.ExitCode = 1;
}
```

Run:

```sh
dotnet run
```

#### Java

Java 11 or newer. Uses direct HTTP; no SDK installation needed. Reads one page only.

```sh
java --version
```

Save as FirstRead.java:

```java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;

class FirstRead {
    static String required(String name) {
        String value = System.getenv(name);
        if (value == null || value.isEmpty()) throw new IllegalStateException("Missing environment variable");
        return value;
    }

    public static void main(String[] args) {
        try {
            HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://unify.apideck.com/crm/contacts?limit=10"))
                .timeout(Duration.ofSeconds(30))
                .header("Authorization", "Bearer " + required("APIDECK_API_KEY"))
                .header("x-apideck-app-id", required("APIDECK_APP_ID"))
                .header("x-apideck-consumer-id", required("APIDECK_CONSUMER_ID"))
                .header("x-apideck-service-id", required("APIDECK_SERVICE_ID"))
                .GET().build();
            HttpClient client = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(30)).build();
            HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
            System.out.println("HTTP " + response.statusCode());
            if (response.statusCode() < 200 || response.statusCode() >= 300)
                throw new IllegalStateException("Read failed");
            Files.writeString(Path.of("response.json"), response.body());
            // Inspect service, data and meta.cursors.next locally. Keep customer data out of version control.
            System.out.println("Saved response.json. Verify the service and records before continuing.");
        } catch (Exception error) {
            System.err.println("Read failed. Check environment variables and Apideck Logs.");
            System.exit(1);
        }
    }
}
```

Run:

```sh
java FirstRead.java
```


#### Verify, recover, and continue

Confirm successful status, response service, and the intended consumer and CRM workspace in Logs. Compare source record visibility before interpreting empty results. TypeScript, Python, JavaScript, PHP, Go and C# print counts, not customer records; cURL and Java save response.json locally and that file must stay out of version control. These examples read one page only. Persist the consumer, connector, and source record ID together. Follow the next cursor before treating the import as complete.

For authentication/permission errors, check the application credentials, consumer ownership, and source permissions; reauthorize only when necessary. For missing configuration or unsupported operations, check connector setup and coverage. For validation errors, fix inputs. For throttling or transient reads, use bounded retries without stacking another retry loop around the SDK.

The optional workspace review records developer observations, not automated verification. Check expected service, intended consumer/account, source records or empty results, and next cursor. It resets on reload or selection changes. Never include secrets or customer payloads in a copied review brief.

- [Workspace](https://developers.apideck.com/first-api-call?api=crm&useCase=customer-sync)
- [Operation source](https://developers.apideck.com/apis/crm/reference/contacts/contactsAll.md)
- [Coverage](https://developers.apideck.com/apis/crm/coverage?resources=contacts)
- [Vault setup](https://developers.apideck.com/guides/vault.md)
- [Explorer](https://developers.apideck.com/apis/crm/api-explorer?operation=contactsAll&useCase=customer-sync)
- [Guided simulation](https://developers.apideck.com/playground?api=crm)

### HRIS: list employees

Read one page of employees from your connected employee directory, verify the result, and continue with the same connector.

- Enable the HRIS API and your connector in your Apideck application.
- Use a test employee directory and a consumer mapped to that customer. Authorize the connector in Vault and complete the required connection settings.
- Check list-employees coverage and the source user’s record visibility. Selecting a connector does not establish support.
- Confirm directory permissions. Keep employee data out of logs and copied briefs; only request fields your integration needs.

Set APIDECK_API_KEY, APIDECK_APP_ID, APIDECK_CONSUMER_ID, and APIDECK_SERVICE_ID in your server environment or local POSIX shell. Choose the consumer owning the authorized connection. Never put these credentials in browser code, shared URLs, or agent briefs.

#### TypeScript

Node.js 24 or newer. This example uses native TypeScript execution and @apideck/unify 0.52.2.

```sh
npm install @apideck/unify@0.52.2
```

Save as first-read.ts:

```typescript
import { Apideck } from "@apideck/unify";

function required(name: string): string {
  const value = process.env[name];
  if (!value) throw new Error(`Set ${name} in your server environment.`);
  return value;
}

async function main() {
  const serviceId = required("APIDECK_SERVICE_ID");
  const apideck = new Apideck({
    apiKey: required("APIDECK_API_KEY"),
    appId: required("APIDECK_APP_ID"),
    consumerId: required("APIDECK_CONSUMER_ID"),
  });
  const result = await apideck.hris.employees.list({ serviceId, limit: 10 });
  const body = result.getEmployeesResponse;
  if (!body || body.service !== serviceId) {
    throw new Error("Unexpected response. Check the request in Logs.");
  }
  console.log(JSON.stringify({
    status: body.status,
    service: body.service,
    records: body.data.length,
    nextCursor: body.meta?.cursors?.next ?? null,
  }, null, 2));
}

main().catch(() => {
  console.error("Read failed. Check environment variables and Apideck Logs.");
  process.exitCode = 1;
});
```

Run:

```sh
node first-read.ts
```

#### Python

Python 3.9.2 or newer. Commands use a POSIX shell and apideck-unify 0.47.1.

```sh
python3 -m venv .venv
. .venv/bin/activate
python -m pip install apideck-unify==0.47.1
```

Save as first_read.py:

```python
import json
import os
import sys
from apideck_unify import Apideck


def main():
    service_id = os.environ["APIDECK_SERVICE_ID"]
    with Apideck(
        api_key=os.environ["APIDECK_API_KEY"],
        app_id=os.environ["APIDECK_APP_ID"],
        consumer_id=os.environ["APIDECK_CONSUMER_ID"],
    ) as apideck:
        result = apideck.hris.employees.list(service_id=service_id, limit=10)
        body = result.get_employees_response if result else None
        if body is None or body.service != service_id:
            raise RuntimeError("Unexpected response. Check the request in Logs.")
        cursor = body.meta.cursors.next if body.meta and body.meta.cursors else None
        print(json.dumps({
            "status": body.status,
            "service": body.service,
            "records": len(body.data),
            "nextCursor": cursor,
        }, indent=2))


try:
    main()
except Exception:
    print("Read failed. Check environment variables and Apideck Logs.", file=sys.stderr)
    sys.exit(1)
```

Run:

```sh
python first_read.py
```

#### cURL

A POSIX shell and cURL 7.76 or newer (--fail-with-body). No SDK installation needed.

```sh
curl --version
```

Save as first-read.sh:

```sh
#!/bin/sh
set -eu
: "${APIDECK_API_KEY:?Set APIDECK_API_KEY}"
: "${APIDECK_APP_ID:?Set APIDECK_APP_ID}"
: "${APIDECK_CONSUMER_ID:?Set APIDECK_CONSUMER_ID}"
: "${APIDECK_SERVICE_ID:?Set APIDECK_SERVICE_ID}"

curl --fail-with-body --silent --show-error \
  --url 'https://unify.apideck.com/hris/employees?limit=10' \
  --header "Authorization: Bearer $APIDECK_API_KEY" \
  --header "x-apideck-app-id: $APIDECK_APP_ID" \
  --header "x-apideck-consumer-id: $APIDECK_CONSUMER_ID" \
  --header "x-apideck-service-id: $APIDECK_SERVICE_ID" \
  --output response.json \
  --write-out 'HTTP %{http_code}\n'
# Inspect response.json locally. It may contain customer data.
```

Run:

```sh
sh first-read.sh
```

#### JavaScript

Node.js 18 or newer. Uses direct HTTP; no SDK installation needed. Reads one page only.

```sh
node --version
```

Save as first-read.mjs:

```javascript
function required(name) {
  const value = process.env[name];
  if (!value) throw new Error(`Set ${name} in your server environment.`);
  return value;
}

try {
  const service = required("APIDECK_SERVICE_ID");
  const response = await fetch("https://unify.apideck.com/hris/employees?limit=10", {
    headers: {
      Authorization: `Bearer ${required("APIDECK_API_KEY")}`,
      "x-apideck-app-id": required("APIDECK_APP_ID"),
      "x-apideck-consumer-id": required("APIDECK_CONSUMER_ID"),
      "x-apideck-service-id": service,
    },
    signal: AbortSignal.timeout(30000),
    redirect: "error",
  });
  if (!response.ok) throw new Error(`HTTP ${response.status}`);
  const body = await response.json();
  if (body.service !== service || !Array.isArray(body.data)) throw new Error("Unexpected response");
  console.log(JSON.stringify({ status: body.status, service: body.service,
    records: body.data.length, nextCursor: body.meta?.cursors?.next ?? null }, null, 2));
} catch {
  console.error("Read failed. Check environment variables and Apideck Logs.");
  process.exitCode = 1;
}
```

Run:

```sh
node first-read.mjs
```

#### PHP

PHP 8 or newer with the cURL extension. Uses direct HTTP; no SDK installation needed. Reads one page only.

```sh
php --version
php -m # Requires curl and json
```

Save as first-read.php:

```php
<?php
function required(string $name): string {
    $value = getenv($name);
    if ($value === false || $value === '') throw new RuntimeException("Missing environment variable");
    return $value;
}

try {
    $service = required('APIDECK_SERVICE_ID');
    $request = curl_init('https://unify.apideck.com/hris/employees?limit=10');
    curl_setopt_array($request, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => 30,
        CURLOPT_HTTPHEADER => [
            'Authorization: Bearer ' . required('APIDECK_API_KEY'),
            'x-apideck-app-id: ' . required('APIDECK_APP_ID'),
            'x-apideck-consumer-id: ' . required('APIDECK_CONSUMER_ID'),
            'x-apideck-service-id: ' . $service,
        ],
    ]);
    $response = curl_exec($request);
    $status = curl_getinfo($request, CURLINFO_HTTP_CODE);
    if ($response === false || $status < 200 || $status >= 300) throw new RuntimeException('Read failed');
    $body = json_decode($response, true, 512, JSON_THROW_ON_ERROR);
    if (($body['service'] ?? null) !== $service || !is_array($body['data'] ?? null)) {
        throw new RuntimeException('Unexpected response');
    }
    echo json_encode([
        'status' => $body['status'], 'service' => $body['service'],
        'records' => count($body['data']), 'nextCursor' => $body['meta']['cursors']['next'] ?? null,
    ], JSON_PRETTY_PRINT) . PHP_EOL;
} catch (Throwable $error) {
    fwrite(STDERR, "Read failed. Check environment variables and Apideck Logs.\n");
    exit(1);
}
```

Run:

```sh
php first-read.php
```

#### Go

Go 1.20 or newer. Uses direct HTTP; no SDK installation needed. Reads one page only.

```sh
go version
```

Save as first-read.go:

```go
package main

import (
    "encoding/json"
    "errors"
    "fmt"
    "net/http"
    "os"
    "time"
)

func read() error {
    req, err := http.NewRequest("GET", "https://unify.apideck.com/hris/employees?limit=10", nil)
    if err != nil { return err }
    for header, name := range map[string]string{
        "Authorization": "APIDECK_API_KEY",
        "x-apideck-app-id": "APIDECK_APP_ID",
        "x-apideck-consumer-id": "APIDECK_CONSUMER_ID",
        "x-apideck-service-id": "APIDECK_SERVICE_ID",
    } {
        value := os.Getenv(name)
        if value == "" { return errors.New("missing environment variable") }
        if header == "Authorization" { value = "Bearer " + value }
        req.Header.Set(header, value)
    }
    client := &http.Client{Timeout: 30 * time.Second,
        CheckRedirect: func(_ *http.Request, _ []*http.Request) error { return http.ErrUseLastResponse }}
    res, err := client.Do(req)
    if err != nil { return err }
    defer res.Body.Close()
    if res.StatusCode < 200 || res.StatusCode >= 300 { return errors.New("read failed") }
    var body struct {
        Status string `json:"status"`
        Service string `json:"service"`
        Data []json.RawMessage `json:"data"`
        Meta struct { Cursors struct { Next *string `json:"next"` } `json:"cursors"` } `json:"meta"`
    }
    if err := json.NewDecoder(res.Body).Decode(&body); err != nil { return err }
    if body.Service != os.Getenv("APIDECK_SERVICE_ID") || body.Data == nil { return errors.New("unexpected response") }
    return json.NewEncoder(os.Stdout).Encode(map[string]any{
        "status": body.Status, "service": body.Service,
        "records": len(body.Data), "nextCursor": body.Meta.Cursors.Next,
    })
}

func main() {
    if err := read(); err != nil {
        fmt.Fprintln(os.Stderr, "Read failed. Check environment variables and Apideck Logs.")
        os.Exit(1)
    }
}
```

Run:

```sh
go run first-read.go
```

#### C# / .NET

.NET 8 or newer. Create the project, then replace Program.cs. Uses direct HTTP; no SDK installation needed. Reads one page only.

```sh
dotnet new console -o first-read
cd first-read
```

Save as Program.cs:

```dot-net
using System.Net.Http;
using System.Text.Json;

string Required(string name) => Environment.GetEnvironmentVariable(name) is { Length: > 0 } value
    ? value : throw new InvalidOperationException("Missing environment variable");

try
{
    var service = Required("APIDECK_SERVICE_ID");
    using var client = new HttpClient(new HttpClientHandler { AllowAutoRedirect = false })
        { Timeout = TimeSpan.FromSeconds(30) };
    using var request = new HttpRequestMessage(HttpMethod.Get,
        "https://unify.apideck.com/hris/employees?limit=10");
    request.Headers.Add("Authorization", "Bearer " + Required("APIDECK_API_KEY"));
    request.Headers.Add("x-apideck-app-id", Required("APIDECK_APP_ID"));
    request.Headers.Add("x-apideck-consumer-id", Required("APIDECK_CONSUMER_ID"));
    request.Headers.Add("x-apideck-service-id", service);
    using var response = await client.SendAsync(request);
    response.EnsureSuccessStatusCode();
    using var document = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
    var body = document.RootElement;
    if (body.GetProperty("service").GetString() != service)
        throw new InvalidOperationException("Unexpected service");
    string? next = body.TryGetProperty("meta", out var meta) && meta.ValueKind == JsonValueKind.Object
        && meta.TryGetProperty("cursors", out var cursors) && cursors.ValueKind == JsonValueKind.Object
        && cursors.TryGetProperty("next", out var cursor) ? cursor.GetString() : null;
    Console.WriteLine(JsonSerializer.Serialize(new {
        status = body.GetProperty("status").GetString(), service,
        records = body.GetProperty("data").GetArrayLength(), nextCursor = next
    }));
}
catch
{
    Console.Error.WriteLine("Read failed. Check environment variables and Apideck Logs.");
    Environment.ExitCode = 1;
}
```

Run:

```sh
dotnet run
```

#### Java

Java 11 or newer. Uses direct HTTP; no SDK installation needed. Reads one page only.

```sh
java --version
```

Save as FirstRead.java:

```java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;

class FirstRead {
    static String required(String name) {
        String value = System.getenv(name);
        if (value == null || value.isEmpty()) throw new IllegalStateException("Missing environment variable");
        return value;
    }

    public static void main(String[] args) {
        try {
            HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://unify.apideck.com/hris/employees?limit=10"))
                .timeout(Duration.ofSeconds(30))
                .header("Authorization", "Bearer " + required("APIDECK_API_KEY"))
                .header("x-apideck-app-id", required("APIDECK_APP_ID"))
                .header("x-apideck-consumer-id", required("APIDECK_CONSUMER_ID"))
                .header("x-apideck-service-id", required("APIDECK_SERVICE_ID"))
                .GET().build();
            HttpClient client = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(30)).build();
            HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
            System.out.println("HTTP " + response.statusCode());
            if (response.statusCode() < 200 || response.statusCode() >= 300)
                throw new IllegalStateException("Read failed");
            Files.writeString(Path.of("response.json"), response.body());
            // Inspect service, data and meta.cursors.next locally. Keep customer data out of version control.
            System.out.println("Saved response.json. Verify the service and records before continuing.");
        } catch (Exception error) {
            System.err.println("Read failed. Check environment variables and Apideck Logs.");
            System.exit(1);
        }
    }
}
```

Run:

```sh
java FirstRead.java
```


#### Verify, recover, and continue

Confirm successful status, response service, and the intended consumer and employee directory in Logs. Compare source record visibility before interpreting empty results. TypeScript, Python, JavaScript, PHP, Go and C# print counts, not customer records; cURL and Java save response.json locally and that file must stay out of version control. These examples read one page only. Request only the permissions and fields your directory needs. Handle pagination and employee lifecycle changes before a production sync.

For authentication/permission errors, check the application credentials, consumer ownership, and source permissions; reauthorize only when necessary. For missing configuration or unsupported operations, check connector setup and coverage. For validation errors, fix inputs. For throttling or transient reads, use bounded retries without stacking another retry loop around the SDK.

The optional workspace review records developer observations, not automated verification. Check expected service, intended consumer/account, source records or empty results, and next cursor. It resets on reload or selection changes. Never include secrets or customer payloads in a copied review brief.

- [Workspace](https://developers.apideck.com/first-api-call?api=hris&useCase=directory)
- [Operation source](https://developers.apideck.com/apis/hris/reference/employees/employeesAll.md)
- [Coverage](https://developers.apideck.com/apis/hris/coverage?resources=employees)
- [Vault setup](https://developers.apideck.com/guides/vault.md)
- [Explorer](https://developers.apideck.com/apis/hris/api-explorer?operation=employeesAll&useCase=directory)
- [Guided simulation](https://developers.apideck.com/playground?api=hris)

### Ecommerce: list orders

Read one page of orders from your connected store, verify the result, and continue with the same connector.

- Enable the Ecommerce API and your connector in your Apideck application.
- Use a test store and a consumer mapped to that customer. Authorize the connector in Vault and complete the required connection settings.
- Check list-orders coverage and the source user’s record visibility. Selecting a connector does not establish support.
- Confirm the selected store, order access, and any connector-specific history restrictions before interpreting an empty page.

Set APIDECK_API_KEY, APIDECK_APP_ID, APIDECK_CONSUMER_ID, and APIDECK_SERVICE_ID in your server environment or local POSIX shell. Choose the consumer owning the authorized connection. Never put these credentials in browser code, shared URLs, or agent briefs.

#### TypeScript

Node.js 24 or newer. This example uses native TypeScript execution and @apideck/unify 0.52.2.

```sh
npm install @apideck/unify@0.52.2
```

Save as first-read.ts:

```typescript
import { Apideck } from "@apideck/unify";

function required(name: string): string {
  const value = process.env[name];
  if (!value) throw new Error(`Set ${name} in your server environment.`);
  return value;
}

async function main() {
  const serviceId = required("APIDECK_SERVICE_ID");
  const apideck = new Apideck({
    apiKey: required("APIDECK_API_KEY"),
    appId: required("APIDECK_APP_ID"),
    consumerId: required("APIDECK_CONSUMER_ID"),
  });
  const result = await apideck.ecommerce.orders.list({ serviceId, limit: 10 });
  const body = result.getEcommerceOrdersResponse;
  if (!body || body.service !== serviceId) {
    throw new Error("Unexpected response. Check the request in Logs.");
  }
  console.log(JSON.stringify({
    status: body.status,
    service: body.service,
    records: body.data.length,
    nextCursor: body.meta?.cursors?.next ?? null,
  }, null, 2));
}

main().catch(() => {
  console.error("Read failed. Check environment variables and Apideck Logs.");
  process.exitCode = 1;
});
```

Run:

```sh
node first-read.ts
```

#### Python

Python 3.9.2 or newer. Commands use a POSIX shell and apideck-unify 0.47.1.

```sh
python3 -m venv .venv
. .venv/bin/activate
python -m pip install apideck-unify==0.47.1
```

Save as first_read.py:

```python
import json
import os
import sys
from apideck_unify import Apideck


def main():
    service_id = os.environ["APIDECK_SERVICE_ID"]
    with Apideck(
        api_key=os.environ["APIDECK_API_KEY"],
        app_id=os.environ["APIDECK_APP_ID"],
        consumer_id=os.environ["APIDECK_CONSUMER_ID"],
    ) as apideck:
        result = apideck.ecommerce.orders.list(service_id=service_id, limit=10)
        body = result.get_ecommerce_orders_response if result else None
        if body is None or body.service != service_id:
            raise RuntimeError("Unexpected response. Check the request in Logs.")
        cursor = body.meta.cursors.next if body.meta and body.meta.cursors else None
        print(json.dumps({
            "status": body.status,
            "service": body.service,
            "records": len(body.data),
            "nextCursor": cursor,
        }, indent=2))


try:
    main()
except Exception:
    print("Read failed. Check environment variables and Apideck Logs.", file=sys.stderr)
    sys.exit(1)
```

Run:

```sh
python first_read.py
```

#### cURL

A POSIX shell and cURL 7.76 or newer (--fail-with-body). No SDK installation needed.

```sh
curl --version
```

Save as first-read.sh:

```sh
#!/bin/sh
set -eu
: "${APIDECK_API_KEY:?Set APIDECK_API_KEY}"
: "${APIDECK_APP_ID:?Set APIDECK_APP_ID}"
: "${APIDECK_CONSUMER_ID:?Set APIDECK_CONSUMER_ID}"
: "${APIDECK_SERVICE_ID:?Set APIDECK_SERVICE_ID}"

curl --fail-with-body --silent --show-error \
  --url 'https://unify.apideck.com/ecommerce/orders?limit=10' \
  --header "Authorization: Bearer $APIDECK_API_KEY" \
  --header "x-apideck-app-id: $APIDECK_APP_ID" \
  --header "x-apideck-consumer-id: $APIDECK_CONSUMER_ID" \
  --header "x-apideck-service-id: $APIDECK_SERVICE_ID" \
  --output response.json \
  --write-out 'HTTP %{http_code}\n'
# Inspect response.json locally. It may contain customer data.
```

Run:

```sh
sh first-read.sh
```

#### JavaScript

Node.js 18 or newer. Uses direct HTTP; no SDK installation needed. Reads one page only.

```sh
node --version
```

Save as first-read.mjs:

```javascript
function required(name) {
  const value = process.env[name];
  if (!value) throw new Error(`Set ${name} in your server environment.`);
  return value;
}

try {
  const service = required("APIDECK_SERVICE_ID");
  const response = await fetch("https://unify.apideck.com/ecommerce/orders?limit=10", {
    headers: {
      Authorization: `Bearer ${required("APIDECK_API_KEY")}`,
      "x-apideck-app-id": required("APIDECK_APP_ID"),
      "x-apideck-consumer-id": required("APIDECK_CONSUMER_ID"),
      "x-apideck-service-id": service,
    },
    signal: AbortSignal.timeout(30000),
    redirect: "error",
  });
  if (!response.ok) throw new Error(`HTTP ${response.status}`);
  const body = await response.json();
  if (body.service !== service || !Array.isArray(body.data)) throw new Error("Unexpected response");
  console.log(JSON.stringify({ status: body.status, service: body.service,
    records: body.data.length, nextCursor: body.meta?.cursors?.next ?? null }, null, 2));
} catch {
  console.error("Read failed. Check environment variables and Apideck Logs.");
  process.exitCode = 1;
}
```

Run:

```sh
node first-read.mjs
```

#### PHP

PHP 8 or newer with the cURL extension. Uses direct HTTP; no SDK installation needed. Reads one page only.

```sh
php --version
php -m # Requires curl and json
```

Save as first-read.php:

```php
<?php
function required(string $name): string {
    $value = getenv($name);
    if ($value === false || $value === '') throw new RuntimeException("Missing environment variable");
    return $value;
}

try {
    $service = required('APIDECK_SERVICE_ID');
    $request = curl_init('https://unify.apideck.com/ecommerce/orders?limit=10');
    curl_setopt_array($request, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => 30,
        CURLOPT_HTTPHEADER => [
            'Authorization: Bearer ' . required('APIDECK_API_KEY'),
            'x-apideck-app-id: ' . required('APIDECK_APP_ID'),
            'x-apideck-consumer-id: ' . required('APIDECK_CONSUMER_ID'),
            'x-apideck-service-id: ' . $service,
        ],
    ]);
    $response = curl_exec($request);
    $status = curl_getinfo($request, CURLINFO_HTTP_CODE);
    if ($response === false || $status < 200 || $status >= 300) throw new RuntimeException('Read failed');
    $body = json_decode($response, true, 512, JSON_THROW_ON_ERROR);
    if (($body['service'] ?? null) !== $service || !is_array($body['data'] ?? null)) {
        throw new RuntimeException('Unexpected response');
    }
    echo json_encode([
        'status' => $body['status'], 'service' => $body['service'],
        'records' => count($body['data']), 'nextCursor' => $body['meta']['cursors']['next'] ?? null,
    ], JSON_PRETTY_PRINT) . PHP_EOL;
} catch (Throwable $error) {
    fwrite(STDERR, "Read failed. Check environment variables and Apideck Logs.\n");
    exit(1);
}
```

Run:

```sh
php first-read.php
```

#### Go

Go 1.20 or newer. Uses direct HTTP; no SDK installation needed. Reads one page only.

```sh
go version
```

Save as first-read.go:

```go
package main

import (
    "encoding/json"
    "errors"
    "fmt"
    "net/http"
    "os"
    "time"
)

func read() error {
    req, err := http.NewRequest("GET", "https://unify.apideck.com/ecommerce/orders?limit=10", nil)
    if err != nil { return err }
    for header, name := range map[string]string{
        "Authorization": "APIDECK_API_KEY",
        "x-apideck-app-id": "APIDECK_APP_ID",
        "x-apideck-consumer-id": "APIDECK_CONSUMER_ID",
        "x-apideck-service-id": "APIDECK_SERVICE_ID",
    } {
        value := os.Getenv(name)
        if value == "" { return errors.New("missing environment variable") }
        if header == "Authorization" { value = "Bearer " + value }
        req.Header.Set(header, value)
    }
    client := &http.Client{Timeout: 30 * time.Second,
        CheckRedirect: func(_ *http.Request, _ []*http.Request) error { return http.ErrUseLastResponse }}
    res, err := client.Do(req)
    if err != nil { return err }
    defer res.Body.Close()
    if res.StatusCode < 200 || res.StatusCode >= 300 { return errors.New("read failed") }
    var body struct {
        Status string `json:"status"`
        Service string `json:"service"`
        Data []json.RawMessage `json:"data"`
        Meta struct { Cursors struct { Next *string `json:"next"` } `json:"cursors"` } `json:"meta"`
    }
    if err := json.NewDecoder(res.Body).Decode(&body); err != nil { return err }
    if body.Service != os.Getenv("APIDECK_SERVICE_ID") || body.Data == nil { return errors.New("unexpected response") }
    return json.NewEncoder(os.Stdout).Encode(map[string]any{
        "status": body.Status, "service": body.Service,
        "records": len(body.Data), "nextCursor": body.Meta.Cursors.Next,
    })
}

func main() {
    if err := read(); err != nil {
        fmt.Fprintln(os.Stderr, "Read failed. Check environment variables and Apideck Logs.")
        os.Exit(1)
    }
}
```

Run:

```sh
go run first-read.go
```

#### C# / .NET

.NET 8 or newer. Create the project, then replace Program.cs. Uses direct HTTP; no SDK installation needed. Reads one page only.

```sh
dotnet new console -o first-read
cd first-read
```

Save as Program.cs:

```dot-net
using System.Net.Http;
using System.Text.Json;

string Required(string name) => Environment.GetEnvironmentVariable(name) is { Length: > 0 } value
    ? value : throw new InvalidOperationException("Missing environment variable");

try
{
    var service = Required("APIDECK_SERVICE_ID");
    using var client = new HttpClient(new HttpClientHandler { AllowAutoRedirect = false })
        { Timeout = TimeSpan.FromSeconds(30) };
    using var request = new HttpRequestMessage(HttpMethod.Get,
        "https://unify.apideck.com/ecommerce/orders?limit=10");
    request.Headers.Add("Authorization", "Bearer " + Required("APIDECK_API_KEY"));
    request.Headers.Add("x-apideck-app-id", Required("APIDECK_APP_ID"));
    request.Headers.Add("x-apideck-consumer-id", Required("APIDECK_CONSUMER_ID"));
    request.Headers.Add("x-apideck-service-id", service);
    using var response = await client.SendAsync(request);
    response.EnsureSuccessStatusCode();
    using var document = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
    var body = document.RootElement;
    if (body.GetProperty("service").GetString() != service)
        throw new InvalidOperationException("Unexpected service");
    string? next = body.TryGetProperty("meta", out var meta) && meta.ValueKind == JsonValueKind.Object
        && meta.TryGetProperty("cursors", out var cursors) && cursors.ValueKind == JsonValueKind.Object
        && cursors.TryGetProperty("next", out var cursor) ? cursor.GetString() : null;
    Console.WriteLine(JsonSerializer.Serialize(new {
        status = body.GetProperty("status").GetString(), service,
        records = body.GetProperty("data").GetArrayLength(), nextCursor = next
    }));
}
catch
{
    Console.Error.WriteLine("Read failed. Check environment variables and Apideck Logs.");
    Environment.ExitCode = 1;
}
```

Run:

```sh
dotnet run
```

#### Java

Java 11 or newer. Uses direct HTTP; no SDK installation needed. Reads one page only.

```sh
java --version
```

Save as FirstRead.java:

```java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;

class FirstRead {
    static String required(String name) {
        String value = System.getenv(name);
        if (value == null || value.isEmpty()) throw new IllegalStateException("Missing environment variable");
        return value;
    }

    public static void main(String[] args) {
        try {
            HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://unify.apideck.com/ecommerce/orders?limit=10"))
                .timeout(Duration.ofSeconds(30))
                .header("Authorization", "Bearer " + required("APIDECK_API_KEY"))
                .header("x-apideck-app-id", required("APIDECK_APP_ID"))
                .header("x-apideck-consumer-id", required("APIDECK_CONSUMER_ID"))
                .header("x-apideck-service-id", required("APIDECK_SERVICE_ID"))
                .GET().build();
            HttpClient client = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(30)).build();
            HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
            System.out.println("HTTP " + response.statusCode());
            if (response.statusCode() < 200 || response.statusCode() >= 300)
                throw new IllegalStateException("Read failed");
            Files.writeString(Path.of("response.json"), response.body());
            // Inspect service, data and meta.cursors.next locally. Keep customer data out of version control.
            System.out.println("Saved response.json. Verify the service and records before continuing.");
        } catch (Exception error) {
            System.err.println("Read failed. Check environment variables and Apideck Logs.");
            System.exit(1);
        }
    }
}
```

Run:

```sh
java FirstRead.java
```


#### Verify, recover, and continue

Confirm successful status, response service, and the intended consumer and store in Logs. Compare source record visibility before interpreting empty results. TypeScript, Python, JavaScript, PHP, Go and C# print counts, not customer records; cURL and Java save response.json locally and that file must stay out of version control. These examples read one page only. Preserve the store and source order ID. Treat money fields as decimals, follow pagination, and reconcile later changes and refunds.

For authentication/permission errors, check the application credentials, consumer ownership, and source permissions; reauthorize only when necessary. For missing configuration or unsupported operations, check connector setup and coverage. For validation errors, fix inputs. For throttling or transient reads, use bounded retries without stacking another retry loop around the SDK.

The optional workspace review records developer observations, not automated verification. Check expected service, intended consumer/account, source records or empty results, and next cursor. It resets on reload or selection changes. Never include secrets or customer payloads in a copied review brief.

- [Workspace](https://developers.apideck.com/first-api-call?api=ecommerce&useCase=orders)
- [Operation source](https://developers.apideck.com/apis/ecommerce/reference/orders/ordersAll.md)
- [Coverage](https://developers.apideck.com/apis/ecommerce/coverage?resources=orders)
- [Vault setup](https://developers.apideck.com/guides/vault.md)
- [Explorer](https://developers.apideck.com/apis/ecommerce/api-explorer?operation=ordersAll&useCase=orders)
- [Guided simulation](https://developers.apideck.com/playground?api=ecommerce)
