Foyer API · Recipe
Auto-approve callers from my CRM
Your clients should not have to explain themselves to a screener. This script reads your CRM's contact export and approves each number, so those callers ring straight through.
You need: Concierge or Chief of Staff, a key with contacts:read and contacts:write, and a CSV export from your CRM with a name and a phone number column. Most CRMs can export contacts as CSV; you can also read from your CRM's own API instead of the file.
How it works
- Check that your plan allows changes:
GET /v1/mereturnsaccess.writes_allowed. - Read the numbers Foyer already treats as contacts:
GET /v1/contacts, page by page. - For each new number in the export, call
POST /v1/contacts/approvewith the number and name. It is the same as choosing Through on a contact in the app.
Approving a number also clears a block on it. Review the export first so you do not let through someone you blocked on purpose.
The script
import csv
import os
import sys
import time
import requests
API = "https://api.hifoyer.com/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['FOYER_API_KEY']}"}
CSV_PATH = sys.argv[1] if len(sys.argv) > 1 else "crm-export.csv"
def call(method, path, **kwargs):
while True:
resp = requests.request(method, f"{API}{path}", headers=HEADERS, timeout=30, **kwargs)
if resp.status_code == 429:
time.sleep(int(resp.headers.get("Retry-After", "5")))
continue
resp.raise_for_status()
return resp.json()
if not call("GET", "/me")["data"]["access"]["writes_allowed"]:
sys.exit("Approving callers needs Concierge or Chief of Staff.")
known, cursor = set(), None
while True:
page = call("GET", "/contacts", params={"limit": 100, **({"cursor": cursor} if cursor else {})})
known.update(c["number"] for c in page["data"])
cursor = page["next_cursor"]
if not cursor:
break
with open(CSV_PATH, newline="") as f:
for row in csv.DictReader(f):
number, name = row.get("Phone", "").strip(), row.get("Name", "").strip()
if not number or number in known:
continue
call("POST", "/contacts/approve", json={"number": number, "name": name} if name else {"number": number})
known.add(number)
print("Approved", name or number)
time.sleep(1.1) # stay under 60 requests a minuteChange "Phone" and "Name" to your export's column names. US numbers may leave out +1. Approving a number that is already approved is safe, but a name you send replaces the name Foyer has saved for that number.
Run it once, or nightly to pick up new clients. It only adds approvals; it never removes one.
Related
- Screen someone again:
POST /v1/contacts/unapprove. - Screen a contact like a stranger for a while:
POST /v1/contacts/appear-unknown. - Decide from a call instead:
POST /v1/calls/{id}/refilewiththrough,screened,review,voicemailorblock.
All are in the endpoint reference.