API reference

Server-to-server endpoints for listing, collecting, sharing, and downloading consent evidence.

On this page

Authentication

Generate an API key in the dashboard (Organization → API Keys). The secret is shown only once — if lost, generate a new key.

Send it as X-API-Key in the format <keyId>.<secret>:

bash
X-API-Key: <keyId>.<secret>

Base URL

bash
export EC_API_KEY="<keyId>.<secret>"

# Production:
export EC_API_BASE_URL="https://api-next.expressconsent.com"

# Local emulator:
# export EC_API_BASE_URL="http://127.0.0.1:5001/demo-expressconsent/us-central1/api"

All curl examples below use $EC_API_BASE_URL so they work in any environment.

Response format

All responses are JSON with a request ID for debugging.

Success

json
{
  "ok": true,
  "data": { ... },
  "requestId": "2e9f4a2d-..."
}

Error

json
{
  "ok": false,
  "error": {
    "code": "UNAUTHENTICATED",
    "message": "API key required",
    "requestId": "2e9f4a2d-..."
  }
}

Error codes:

  • UNAUTHENTICATED — missing, malformed, or invalid API key
  • FORBIDDEN — authenticated but not authorized
  • INVALID_ARGUMENT — bad query/path input
  • NOT_FOUND — resource doesn’t exist or isn’t accessible
  • CONFLICT — conflicting state (e.g. duplicates)

Endpoints

Read endpoints

GET /v1/domains

List all domains for your organization.

bash
curl -sS \
  -H "X-API-Key: $EC_API_KEY" \
  "$EC_API_BASE_URL/v1/domains"

GET /v1/domains/:domainId/cdrs

List CDRs for a domain, with pagination and optional metadata filtering.

  • pageSize: 1–100 (default 20)
  • order: asc | desc (default desc)
  • pageToken: CDR ID to start after
  • metadataKey + metadataValue: filter by custom metadata (both required together)
bash
curl -sS \
  -H "X-API-Key: $EC_API_KEY" \
  "$EC_API_BASE_URL/v1/domains/example.com/cdrs?pageSize=20&order=desc"
bash
curl -sS \
  -H "X-API-Key: $EC_API_KEY" \
  "$EC_API_BASE_URL/v1/domains/example.com/cdrs?metadataKey=leadId&metadataValue=123"

Example response

json
{
  "ok": true,
  "data": {
    "cdrs": [
      {
        "cdrId": "abc_123",
        "domain": "example.com",
        "createdAt": 1738600000000,
        "collected": true,
        "downloadUrl": "https://storage.googleapis.com/... (short-lived)",
        "customMetadata": { "leadId": "123" },
        "sessionId": "session_abc",
        "subGroupIds": ["step-1"]
      }
    ],
    "nextPageToken": "abc_122"
  }
}

GET /v1/cdrs/:cdrId

Fetch a single CDR with full detail, including signer telemetry (IP, User-Agent, geo).

bash
curl -sS \
  -H "X-API-Key: $EC_API_KEY" \
  "$EC_API_BASE_URL/v1/cdrs/abc_123"

Example response

json
{
  "ok": true,
  "data": {
    "cdr": {
      "cdrId": "abc_123",
      "domain": "example.com",
      "organizationName": "Acme Corp",
      "createdAt": 1738600000000,
      "collected": true,
      "downloadUrl": "https://storage.googleapis.com/...",
      "pageUrl": "https://example.com/consent",
      "signerTelemetry": {
        "ip": "203.0.113.1",
        "userAgent": "Mozilla/5.0 ...",
        "geo": { "country": "US", "region": "CA" }
      },
      "customMetadata": { "leadId": "123" }
    }
  }
}

Write endpoints

POST /v1/cdrs/:cdrId/collect

Mark a CDR as Collected (billing attribution). Idempotent — calling twice returns alreadyCollected: true.

bash
curl -sS -X POST \
  -H "X-API-Key: $EC_API_KEY" \
  "$EC_API_BASE_URL/v1/cdrs/abc_123/collect"

Example response

json
{
  "ok": true,
  "data": {
    "cdrId": "abc_123",
    "collected": true,
    "alreadyCollected": false
  }
}

POST /v1/cdrs/:cdrId/share

Generate a share token for a CDR. The returned shareUrl can be given to a business partner (e.g. a lead buyer) so they can claim the evidence.

bash
curl -sS -X POST \
  -H "X-API-Key: $EC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"expiresInMs":3600000}' \
  "$EC_API_BASE_URL/v1/cdrs/abc_123/share"

Example response

json
{
  "ok": true,
  "data": {
    "token": "share_token_xyz",
    "shareUrl": "/v1/shares/share_token_xyz",
    "expiresAt": 1739200000000
  }
}

POST /v1/shares/:token

Claim a shared CDR into your organization. Once claimed, the evidence appears under your account and you can download it. Once any party has collected a CDR, other parties with access do not need to pay again.

When using autoShare, the SDK returns a full absolute shareUrl — the lead buyer POSTs to that URL with their API key. When using this endpoint to create shares server-side, prepend your API base URL to the returned path. Legacy /v1/shares/:token/claim remains supported for backward compatibility.

bash
curl -sS -X POST \
  -H "X-API-Key: $EC_API_KEY" \
  "$EC_API_BASE_URL/v1/shares/share_token_xyz"

Example response

json
{
  "ok": true,
  "data": {
    "claimed": true,
    "alreadyClaimed": false,
    "cdrId": "abc_123",
    "domainId": "example.com"
  }
}

Collected vs Pending

A CDR can exist in two states. Pending means evidence is saved but billing attribution hasn’t been recorded. Collected means billing attribution exists.

  • downloadUrl is only returned when collected === true.
  • Download URLs are short-lived signed URLs (~5 min). Store cdrId, not the URL.

Related docs