lydoh
Start free trial

Quickstart

Two ways in.

A business publishes one signed JSON file and is done. A platform teaches its agent one sentence, a few digits, and a signed HTTPS exchange. Everything below is copied from the specification.

01 For a business02 For a platform03 The full spec

For a business

Publish a card in ten minutes.

Conformance Level 0 is one signed JSON document at a fixed path. It is useful to a caller even when a person answers your phone, and it does not change how you answer it.

01

Write the card

Only eleven fields are required: atep, party, numbers, endpoint, keys, intents, disclosure, contact, issued, expires, and sig. Everything else, including hours, services, languages, and policies, is optional and makes you easier to deal with.

card.json

{
  "atep": "1.0",
  "party": {
    "id": "urn:atep:party:<uuid you generate once and keep>",
    "name": "<Your business, as you would say it out loud>",
    "kind": "business",
    "website": "https://<your-domain>"
  },
  "numbers": ["+1<your number, E.164, no spaces>"],
  "endpoint": "https://<your-domain>/atep/v1/sessions",
  "keys": [
    {
      "kid": "2026-09",
      "kty": "OKP",
      "crv": "Ed25519",
      "x": "<base64url of your Ed25519 public key>",
      "use": "sig"
    }
  ],
  "intents": ["message", "handoff"],
  "disclosure": "This is <Your business>'s AI assistant.",
  "contact": {
    "technical": "it@<your-domain>",
    "abuse": "abuse@<your-domain>"
  },
  "issued": "2026-09-23T00:00:00Z",
  "expires": "2027-09-23T00:00:00Z",
  "sig": "<the signing step writes this>"
}

disclosure is the exact sentence your phone answers with. It must name you and must contain AI, artificial, automated, or virtual, together with assistant or agent. expires must be no more than 400 days after issued, and an expired card is treated as absent. Set healthcare to true and the healthcare profile applies to every session with you.

02

Put it at the well-known path

https://<your-domain>/.well-known/atep.json

Served with Content-Type: application/json, over TLS, with a cache lifetime of at least one hour. The path is frozen and will never move.

If a platform answers your phone for you, it publishes its own card at the well-known path on its own domain and may host yours at any HTTPS URL on that domain, signed with its key, naming you as the party. Either way, a number must resolve to exactly one card.

03

Sign it

Coming with the CLI

npx atep sign card.json --key key.jwk

Coming The atep CLI is not published yet. The command shape above is what it will be.

By hand until then: sig is a detached JWS (RFC 7515, compact serialization) over the JCS form (RFC 8785) of the card with its sig field removed, algorithm EdDSA with an Ed25519 key. The JWS header carries kid naming a key in the card, and must not carry jku: keys come only from cards. A caller verifies the signature before trusting any other field.

04

Get the number listed

The reference registry

POST https://atep.io/v1/numbers
Content-Type: application/json

{
  "number": "+1<your number>",
  "card": "https://<your-domain>/.well-known/atep.json"
}

→ 202 { "verification_id": "v_01J8…", "status": "pending" }

GET https://atep.io/v1/verifications/v_01J8…
→ 200 { "status": "verified" }

The registry fetches your card, checks that numbers includes the number, calls the number, and expects the ATEP handshake and a completed binding against your endpoint. It re-verifies at least every 90 days, and removes a number whose card expired or whose verification fails twice.

Coming The reference registry at atep.io is not live yet. Anyone may run a registry; a caller is configured with one or more base URLs.

For a platform

One sentence, a few digits, one signed exchange.

What a voice-AI platform needs to answer ATEP, and what a personal-assistant platform needs to call with it. Both sides fall back to plain voice when the other side turns out to be a person.

The hello

Say it first, every time

An ATEP agent's first utterance is its hello, spoken within 10 seconds of the call connecting. The templates are frozen. Braces mark substitutions, and an agent must re-assert that it is an AI whenever asked, in any phrasing, on any leg, at any time.

Templates, normative in English

Caller:    This is an AI assistant calling for {principal}. Callback {number}. ATEP.
Answerer:  {disclosure} ATEP.

Recording insert:        This call is recorded.          (immediately before "ATEP.")
Synthetic-voice insert:  using a synthetic voice         (before "ATEP.")
Redial insert:           ATEP session {id}.              (rebinding a released session)

{principal} is the display name from the delegation. {number}is a callback number read as digits, at which a human can reach the caller's principal or platform. It must not be a dialer-only number.

The frame

Then the digits

Immediately after speaking the word ATEP, the agent sends a DTMF frame. The 1 is the major version.

DTMF frames

Caller:    # 1 #
Answerer:  # 1 <pointer> #

<pointer> is optional, and is one of:
  14632513583   the answerer's own E.164 digits without "+": resolve me by this number
  042           "0" then a registry platform code, here 42: resolve my platform, then
                ask it for the card for the number you dialed

A # followed by an unexpected digit sequence is not a frame. Phone trees commonly swallow # sequences that match no menu option, so an agent must tolerate a lost frame and fall back to voice.

Binding

Tie the session to this call

Binding proves that the party controlling the endpoint also controls the leg that sent the matching digits on this call. A stolen card URL is useless without it. Challenges are freshly random per call and never reused.

  1. 01Within 10 seconds of the call connecting

    Each side speaks its hello: the answerer on answer, the caller after the answerer's first sound. The templates are frozen, and a translation must preserve every element.

  2. 02Within 2 seconds of the end of “ATEP.”

    The speaker sends its DTMF frame, each digit 100 ms with 100 ms gaps, as RFC 4733 telephone events where available and in-band tones otherwise. The frame must not be interrupted by speech.

  3. 03Within 8 seconds of the other side's hello

    A well-formed frame heard in that window means the peer is an ATEP agent. No frame means a human or a phone tree: continue in plain voice, send no further frames, and log peer: human.

  4. 04Within 3 seconds of detecting the answerer's frame

    The caller resolves the answerer's card and POSTs hello to its endpoint, carrying call_ref (both numbers, the connect time, a nonce) and a four-digit challenge it chose freshly for this call.

  5. 05Within 2 seconds of that POST

    The answerer replies hello_ack with the session id and a four-digit challenge of its own. Every POST in a session is answered inside two seconds, or with working and a retry_after_ms.

  6. 06Next, on the call

    The answerer's leg sends DTMF # 0 <answerer challenge> #. The caller compares what it heard with the hello_ack, and on a match sends # 0 <caller challenge> # and POSTs bind carrying the digits it heard.

  7. 07Within 10 seconds of the hello POST

    The answerer compares the DTMF it heard with the challenge in the hello, and the bind message with the challenge it sent, then replies bound. Past the deadline either side sends error with binding_failed, nobody hangs up, and both continue in plain voice.

  8. 08After binding

    Neither side speaks on the call. Either side may send release; once both have acknowledged, both hang up and the session continues over HTTPS alone, reaching receipted, declined, or error within 15 minutes.

Release is where the cost goes: a bound session typically needs the call for less than 20 seconds.

Delegation

Say what you are allowed to do

The caller's first message after bound is a delegation. It expires within 24 hours, and the answerer checks revocation_url before any receipt.

delegation

{
  "principal": {
    "id": "urn:atep:principal:c1b6…",
    "name": "Sohel S.",
    "contact": "+17755551234",
    "platform": "https://lydoh.com/.well-known/atep.json"
  },
  "scope": ["availability", "book", "message", "handoff"],
  "caps": {
    "max_spend": { "amount": 200, "currency": "USD" },
    "date_window": { "start": "2026-10-01", "end": "2026-10-31" },
    "max_bookings": 1
  },
  "identity_verification": "none",
  "issued": "2026-09-23T14:29:00-04:00",
  "expires": "2026-09-23T15:29:00-04:00",
  "revocation_url": "https://lydoh.com/atep/v1/delegations/d_01J8…",
  "credential": "<JWS>"
}

credential is a JWS over the delegation body, signed by the platform key, shaped as a W3C Verifiable Credential. identity_verification is fixed at none in v1: a caller never answers a security question, and where a business needs one the answer is a handoff to a person.

Receipt

Finish with something both sides sign

A receipt is produced for every state-changing outcome and for every message and handoff. Each side signs it without the other's signature, both store it, and both must show it to their principal in a human-readable form.

receipt

{
  "session": "s_01J8…",
  "intent": "book",
  "outcome": "booked",
  "outcome_channel": "atep",
  "reference": "4471",
  "summary": "Booked: new patient visit, Tuesday October 6 at 9:00 AM, for Sohel S., reference 4471.",
  "details": { "service": "new-patient", "start": "2026-10-06T09:00:00-04:00", "duration_minutes": 30 },
  "principal": { "id": "urn:atep:principal:c1b6…", "name": "Sohel S.", "platform": "…" },
  "party": { "id": "urn:atep:party:9f2c…", "name": "Cedar Grove Family Medicine", "card": "…" },
  "delegation": "sha256:…",
  "mandate": null,
  "disclosures": {
    "caller": "This is an AI assistant calling for Sohel S. Callback 7 7 5 5 5 5 1 2 3 4. ATEP.",
    "answerer": "This is Cedar Grove Family Medicine's AI assistant. This call is recorded. ATEP."
  },
  "recorded": { "caller": false, "answerer": true },
  "machine_only": true,
  "log_hash": "sha256:…",
  "issued": "2026-09-23T14:30:41-04:00",
  "signatures": { "caller": "<JWS>", "answerer": "<JWS>" }
}

log_hash is SHA-256 over the JCS form of the array of all session messages in order, so the record commits to the log without disclosing it. machine_only is true when every message after binding, from both sides, was marked not human-audible.

Everything else is in the document. The message envelope and the state machine (Section 6), the seven intents and their fields (Section 8), the healthcare profile (Section 9), the behavior rules (Section 10), and the security and privacy considerations (Sections 12 and 13). Read the spec.

Comments are open.

ATEP 1.0 is a draft for public comment. The discovery path, the hello sentences, and the DTMF frames are frozen; message fields may still be added.

Authored by Lydoh. Draft 2, September 2026. Comments to hello@lydoh.com.