Foyer API pages

Foyer API

Quickstart

You need a Foyer account and a few minutes. Every plan can read. Changing anything needs Concierge or Chief of Staff.

1. Make a key

  1. In the Foyer app or the dashboard, open Settings › Connected apps.
  2. Choose New key and name it after what will use it, for example "Weekly summary".
  3. Tick the permissions it needs. To follow this page, tick See your calls, summaries and voicemails list (calls:read) and Read conversations and voicemail text (transcripts:read). Authentication and permissions lists them all.
  4. Copy the key. It starts with fyr_ and is shown only once: Foyer keeps a fingerprint of it, not the key. A key lasts up to 90 days, and you can revoke it at any time.

Keep the key out of code you share. Put it in an environment variable:

Terminal
export FOYER_API_KEY="fyr_paste_your_key_here"

2. Check what the key can do

GET /v1/me returns the key's permissions, whether your plan allows changes, and your limits. It is a good first call for any agent.

curl
curl https://api.hifoyer.com/v1/me \
  -H "Authorization: Bearer $FOYER_API_KEY"
Response (abridged)
{
  "data": {
    "key": { "name": "Weekly summary", "scopes": ["calls:read", "transcripts:read"], "expires_at": "2027-01-18T15:02:11Z" },
    "access": { "level": "read", "plan": "Doorman", "writes_allowed": false },
    "rate_limits": { "per_minute": 60, "per_day": 10000, "searches_per_minute": 20 }
  }
}

3. List your recent calls

curl
curl "https://api.hifoyer.com/v1/calls?limit=5" \
  -H "Authorization: Bearer $FOYER_API_KEY"
Python (requests)
import os
import requests

API = "https://api.hifoyer.com/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['FOYER_API_KEY']}"}

resp = requests.get(f"{API}/calls", headers=HEADERS, params={"limit": 5}, timeout=30)
resp.raise_for_status()
for call in resp.json()["data"]:
    caller = call["caller"]["name"] or call["caller"]["number"] or "Unknown caller"
    print(call["started_at"], caller, "|", call["outcome_label"], "|", call["summary"])
JavaScript (Node 18 or later)
const API = "https://api.hifoyer.com/v1";
const res = await fetch(`${API}/calls?limit=5`, {
  headers: { Authorization: `Bearer ${process.env.FOYER_API_KEY}` },
});
const body = await res.json();
if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
for (const call of body.data) {
  const caller = call.caller.name ?? call.caller.number ?? "Unknown caller";
  console.log(call.started_at, caller, "|", call.outcome_label, "|", call.summary);
}

Each call has an id, the caller, an outcome (what Foyer did: known, connect, review, voicemail, gate, honeypot or fallback), a plain-words outcome_label, a summary, and voicemail.state. Lists are newest first. When next_cursor is not null, pass it back as cursor for the next page.

Response (abridged, one call)
{
  "data": [
    {
      "id": "example-call-id",
      "started_at": "2026-10-20T14:03:27Z",
      "caller": { "number": "+16175550142", "name": "Rosa", "company": "Dr. Patel's office" },
      "outcome": "voicemail",
      "outcome_label": "Sent to voicemail",
      "summary": "Rosa from Dr. Patel's office is confirming Monday's appointment at 9:00.",
      "read": false,
      "voicemail": { "state": "transcribed", "has_audio": true, "reviewed": false }
    }
  ],
  "next_cursor": "eyJ0IjoiMjAyNi0xMC0yMFQxNDowMzoyNy4wMDBaIiwicyI6ImV4YW1wbGUtY2FsbC1pZCJ9"
}

4. Read one call in full

curl
curl https://api.hifoyer.com/v1/calls/CALL_ID \
  -H "Authorization: Bearer $FOYER_API_KEY"

With transcripts:read, the answer includes screening_conversation (what Foyer and the caller said, in order), voicemail.transcript, and connected_call.transcript when the call was recorded. Without it, those are left out and transcripts_omitted is true. Reading a call through the API never marks it read in your app.

When something goes wrong

Every error has the same shape. code is stable and meant for programs; message is written for people.

Error
{ "error": { "code": "insufficient_scope", "message": "This key does not have audio:read (Listen to recordings). Make a key with it in Settings › Connected apps.", "status": 403, "details": { "required_scope": "audio:read" } } }

Authentication and permissions lists every code. Over a limit, the API answers 429 with a Retry-After header: see Limits.

Next