Summary

The DoorBird D31TDH is a Video Door Station supporting LAN-based HTTP, RTSP, SIP, and UDP broadcast control. This spec covers the LAN-2-LAN API: HTTP CGI endpoints for door/light relay control, live image/video, audio, history, favorites/schedule management, SIP call control, RTSP streaming, and encrypted UDP event broadcasts.

Transport

protocols:
  - http
  - udp
  - rtsp
  - sip
addressing:
  base_url: "http://<device-ip>/bha-api/"  # also https://<device-ip>/bha-api/ on port 443 (self-signed cert)
  port: 80  # HTTP unencrypted; 443 for HTTPS
http_ports:
  - 80   # HTTP (unencrypted, LAN)
  - 443  # HTTPS (self-signed cert, LAN)
udp:
  broadcast_ports:
    - 6524
    - 35344
  note: "Event monitoring UDP broadcasts sent on ports 6524 and 35344; keep-alive packets every 7 seconds"
rtsp:
  ports:
    - 554    # RTSP
    - 8557   # RTSP-over-HTTP
sip:
  port: 5060  # P2P SIP (device version 000099+)
auth:
  type: basic_or_digest  # RFC 2617 Basic or Digest auth required per request; same credentials as DoorBird App
  alternative: "Plaintext HTTP params http-user and http-password supported (insecure)"
  rate_limit: "Max 1 concurrent connection per second; 1 minute IP/user block on excessive wrong credentials (HTTP 423)"

Traits

# - queryable  # inferred from info.cgi, sip status, monitor.cgi, favorites/schedule list queries
traits:
  - queryable

Actions

# --- Session management ---
- id: get_session
  label: Get Session ID
  kind: query
  command: "GET /bha-api/getsession.cgi"
  params: []
  notes: "Returns JSON with SESSIONID (valid 10 min) and NOTIFICATION_ENCRYPTION_KEY. Session used for HTTPS-less video/audio streaming."

- id: invalidate_session
  label: Invalidate Session ID
  kind: action
  command: "GET /bha-api/getsession.cgi?invalidate={old_session_id}"
  params:
    - name: old_session_id
      type: string
      description: The session-id to invalidate/destroy
  notes: "Returns JSON with empty SESSIONID on success."

# --- Live video / image (HTTP) ---
- id: live_video_http
  label: Live Video Request (HTTP MJPG)
  kind: query
  command: "GET /bha-api/video.cgi"
  params: []
  notes: "Returns multipart/x-mixed-replace MJPG stream (up to 8 fps). Permission: valid user, watch-always or ring event in past 5 min. 204 if no permission. For HTTPS-less streaming append ?sessionid=<id>."

- id: live_image
  label: Live Image Request
  kind: query
  command: "GET /bha-api/image.cgi"
  params: []
  notes: "Returns JPEG image. Permission: valid user, watch-always or ring event in past 1 min. 204 if no permission."

# --- Relay control ---
- id: open_door
  label: Open Door (Relay)
  kind: action
  command: "GET /bha-api/open-door.cgi?r={relay}"
  params:
    - name: relay
      type: string
      description: "Relay to trigger, e.g. physical relay number '1'/'2' or '<doorcontrollerID>@<relay>' for paired IP I/O DoorController. Omit to trigger physical relay 1."
      required: false
  notes: "Energizes door opener/alarm output relay. Returns JSON. Permission: valid user, watch-always or ring event in past 5 min. 204 if no permission."

- id: light_on
  label: Light On (Relay)
  kind: action
  command: "GET /bha-api/light-on.cgi"
  params: []
  notes: "Energizes light relay. Returns JSON. Permission: valid user, watch-always or ring event in past 5 min. 204 if no permission."

# --- History ---
- id: history_image
  label: History Image Request
  kind: query
  command: "GET /bha-api/history.cgi?index={index}&event={event}"
  params:
    - name: index
      type: integer
      description: "Index of history image, 1..50, where 1 is latest"
    - name: event
      type: string
      description: "Event type: doorbell or motionsensor (optional; default ring history for DoorBird)"
      required: false
  notes: "Returns JPEG from cloud history. Permission: valid user + history permission (+motion permission for motion events). 204 if no permission."

# --- Monitor (state stream) ---
- id: monitor
  label: Monitor Request (State Stream)
  kind: query
  command: "GET /bha-api/monitor.cgi?ring={ring}"
  params:
    - name: ring
      type: string
      description: "Event type(s) to monitor, comma-separated: doorbell, motionsensor. rfid/keypad coming soon."
  notes: "Returns continuous multipart stream of motionsensor/doorbell state (H=high/L=low). Max 8 concurrent streams; 509 if all busy. Permission: valid user."

# --- Audio ---
- id: audio_receive
  label: Live Audio Receive
  kind: query
  command: "GET /bha-api/audio-receive.cgi"
  params: []
  notes: "Returns real-time G.711 μ-law audio (8000 Hz). Permission: valid user, watch-always or ring event in past 5 min. For HTTPS-less streaming append ?sessionid=<id>."

- id: audio_transmit
  label: Live Audio Transmit
  kind: action
  command: "POST /bha-api/audio-transmit.cgi"
  params:
    - name: audio_data
      type: binary
      description: "G.711 μ-law audio data, Content-Type: audio/basic, Content-Length: 9999999, Connection: Keep-Alive, Cache-Control: no-cache"
  notes: "POST singlepart G.711 μ-law audio. Only one consumer can transmit at a time. Permission: valid user, watch-always or ring event in past 5 min."

# --- Device info ---
- id: info
  label: Info Request
  kind: query
  command: "GET /bha-api/info.cgi"
  params: []
  notes: "Returns JSON: RETURNCODE, VERSION array (FIRMWARE, BUILD_NUMBER, PRIMARY_MAC_ADDR, RELAYS, DEVICE-TYPE). Relays config included from firmware 000108. Permission: valid user."

# --- Favorites management ---
- id: list_favorites
  label: List Favorites
  kind: query
  command: "GET /bha-api/favorites.cgi"
  params: []
  notes: "Returns JSON of sip/http favorites. Requires API-Operator permission. Firmware 000110+."

- id: save_favorite
  label: Add or Change Favorite
  kind: action
  command: "POST /bha-api/favorites.cgi?action=save&type={type}&title={title}&value={value}&id={id}"
  params:
    - name: type
      type: string
      description: "Type of favorite: sip or http (cannot switch type on existing favorite)"
    - name: title
      type: string
      description: Name/short description of favorite
    - name: value
      type: string
      description: "URL/address of favorite (HTTP(S) URL or SIP target, including credentials if needed)"
    - name: id
      type: integer
      description: "ID of favorite to change; omit when saving new favorite"
      required: false
  notes: "New favorite id returned in response header 'favoriteid'. Status: 200 OK, 400 param missing, 401 auth, 500 internal, 507 size limit. Requires API-Operator permission. Firmware 000110+."

- id: remove_favorite
  label: Delete Favorite
  kind: action
  command: "POST /bha-api/favorites.cgi?action=remove&type={type}&id={id}"
  params:
    - name: type
      type: string
      description: "Type of favorite: sip or http"
    - name: id
      type: integer
      description: ID of the favorite to delete
  notes: "If favorite is used in a schedule, that schedule entry is also removed. Status: 200 OK, 400 param missing, 401 auth, 500 internal. Requires API-Operator permission."

# --- Schedule management ---
- id: list_schedules
  label: List Schedules
  kind: query
  command: "GET /bha-api/schedule.cgi"
  params: []
  notes: "Returns JSON array of schedule entries (input/param/output). 204 if no data for requested input. Requires API-Operator permission. Firmware 000110+."

- id: add_update_schedule
  label: Add or Update Schedule Entry
  kind: action
  command: "POST /bha-api/schedule.cgi"
  params:
    - name: schedule_json
      type: object
      description: "JSON object with input (doorbell|motion|rfid|fingerprint), param (doorbell-number/transponder-id), output array (event: notify|sip|relay|http, param, schedule: once|from-to|weekdays). One request per input type."
  notes: "POST JSON. Status: 200 OK, 400 invalid JSON/Content-Length mismatch/too large, 401 auth, 500 internal, 507 size limit. Requires API-Operator permission. Firmware 000110+."

- id: delete_schedule
  label: Delete Schedule Entry
  kind: action
  command: "GET /bha-api/schedule.cgi?action=remove&input={input}&param={param}"
  params:
    - name: input
      type: string
      description: "Input event type: doorbell|motion|rfid"
    - name: param
      type: string
      description: "ID of schedule entry to delete, e.g. doorbell number, RFID transponder id"
  notes: "Status: 200 OK, 401 auth, 500 internal. Requires API-Operator permission."

# --- Restart ---
- id: restart
  label: Restart Device
  kind: action
  command: "GET /bha-api/restart.cgi"
  params: []
  notes: "Restarts device; no diagnostic sound after restart. Status: 200 OK, 401 auth, 503 device busy (e.g. firmware update in progress)."

# --- RTSP video ---
- id: live_video_rtsp
  label: Live Video Request (RTSP H.264)
  kind: query
  command: "rtsp://<device-ip>:554/mpeg/media.amp"
  params: []
  notes: "H.264 RTSP stream (up to 12 fps). RTSP port 554, RTSP-over-HTTP port 8557. Standard RTSP auth (no param auth). Permission: valid user, watch-always or ring event in past 5 min. 204 if no permission."

- id: live_video_rtsp_720p
  label: Live Video Request (RTSP 720p H.264)
  kind: query
  command: "rtsp://<device-ip>:554/mpeg/720p/media.amp"
  params: []
  notes: "720p variant. Supported by D10x/D21x from firmware 000129. UNRESOLVED: D31TDH support not explicitly stated."

- id: live_video_rtsp_1080p
  label: Live Video Request (RTSP 1080p H.264)
  kind: query
  command: "rtsp://<device-ip>:554/mpeg/1080p/media.amp"
  params: []
  notes: "1080p variant. Supported by D11x only. UNRESOLVED: D31TDH support not explicitly stated."

# --- SIP ---
- id: sip_registration
  label: SIP Registration
  kind: action
  command: "GET /bha-api/sip.cgi?action=registration&user={user}&password={password}&url={url}"
  params:
    - name: user
      type: string
      description: Authentication user for the SIP Proxy
    - name: password
      type: string
      description: Authentication password for the SIP Proxy
    - name: url
      type: string
      description: IP/Hostname of the SIP Proxy
  notes: "Register to SIP Proxy (not needed for P2P calls). Status: 200 OK, 401 auth failure or no API-Operator permission. Requires API-Operator permission."

- id: sip_makecall
  label: SIP Make Call
  kind: action
  command: "GET /bha-api/sip.cgi?action=makecall&url={url}"
  params:
    - name: url
      type: string
      description: SIP URL to call (e.g. sip:108@192.168.123.22)
  notes: "Initiate SIP call (P2P or via PBX). Only one simultaneous SIP call. Min 3s between SIP requests. Auto-hangup after 180s. Status: 200 OK, 400 param missing, 401 auth, 503 line busy. Requires API-Operator permission."

- id: sip_hangup
  label: SIP Hangup
  kind: action
  command: "GET /bha-api/sip.cgi?action=hangup"
  params: []
  notes: "Hangup current SIP call. Returns 200 OK even if no ongoing call. Requires API-Operator permission."

- id: sip_settings
  label: SIP Settings
  kind: action
  command: "GET /bha-api/sip.cgi?action=settings&{params}"
  params:
    - name: enable
      type: integer
      description: "0..1; enable/disable SIP registration after reboot (default 0)"
      required: false
    - name: mic_volume
      type: integer
      description: "1..100; microphone volume (default 33)"
      required: false
    - name: spk_volume
      type: integer
      description: "1..100; speaker volume (default 70)"
      required: false
    - name: dtmf
      type: integer
      description: "0..1; enable/disable DTMF support (default 0)"
      required: false
    - name: autocall_doorbell_url
      type: string
      description: "DEPRECATED (use schedule.cgi). SIP URL to auto-call on doorbell, or 'none' (default none)."
      required: false
    - name: relay1_passcode
      type: integer
      description: "0..99999999; pincode for triggering door open relay"
      required: false
    - name: incoming_call_enable
      type: integer
      description: "0..1; enable/disable incoming calls (default 0)"
      required: false
    - name: incoming_call_user
      type: string
      description: "Allowed SIP user authenticated for DoorBird (e.g. sip:10.0.0.1:5060)"
      required: false
    - name: anc
      type: integer
      description: "0..1; enable/disable acoustic noise cancellation (default 1)"
      required: false
    - name: ring_time_limit
      type: integer
      description: "10..300; max ringing time in seconds (default 300)"
      required: false
    - name: call_time_limit
      type: integer
      description: "30..300; max call duration in seconds (default 300)"
      required: false
  notes: "Configure SIP settings. Status: 200 OK, 401 auth failure or no API-Operator permission. Requires API-Operator permission."

- id: sip_status
  label: SIP Status Query
  kind: query
  command: "GET /bha-api/sip.cgi?action=status"
  params: []
  notes: "Returns JSON; LASTERRORCODE '200' = successfully registered, LASTERRORTEXT = most recent SIP error text. Requires API-Operator permission."

- id: sip_reset
  label: SIP Settings Reset
  kind: action
  command: "GET /bha-api/sip.cgi?action=reset"
  params: []
  notes: "Resets all SIP settings except license; hangs up any ongoing call. Returns JSON with LASTERRORCODE. Requires API-Operator permission."

Feedbacks

- id: monitor_state
  type: stream
  description: "Continuous multipart stream from monitor.cgi reporting doorbell and motionsensor state as H (high) / L (low)"

- id: info_response
  type: object
  description: "JSON from info.cgi: RETURNCODE, VERSION array (FIRMWARE, BUILD_NUMBER, PRIMARY_MAC_ADDR, RELAYS, DEVICE-TYPE)"

- id: sip_status_response
  type: object
  description: "JSON from sip.cgi?action=status: LASTERRORCODE (200 = registered), LASTERRORTEXT"

- id: session_response
  type: object
  description: "JSON from getsession.cgi: RETURNCODE, SESSIONID, NOTIFICATION_ENCRYPTION_KEY"

- id: favorites_response
  type: object
  description: "JSON from favorites.cgi: sip{} and http{} favorite entries"

- id: schedule_response
  type: object
  description: "JSON array from schedule.cgi: input/param/output schedule entries"

Variables

- id: sip_mic_volume
  description: "Microphone volume (1..100, default 33) - set via sip.cgi?action=settings&mic_volume="
  type: integer
  range: [1, 100]

- id: sip_spk_volume
  description: "Speaker volume (1..100, default 70) - set via sip.cgi?action=settings&spk_volume="
  type: integer
  range: [1, 100]

- id: sip_ring_time_limit
  description: "Max ringing time in seconds (10..300, default 300) - set via sip.cgi?action=settings&ring_time_limit="
  type: integer
  range: [10, 300]

- id: sip_call_time_limit
  description: "Max call duration in seconds (30..300, default 300) - set via sip.cgi?action=settings&call_time_limit="
  type: integer
  range: [30, 300]

Events

- id: udp_event_broadcast
  description: "Encrypted UDP broadcast on ports 6524 and 35344. v2 packets use ChaCha20-Poly1305 (NONCE 8 bytes + CIPHERTEXT). IDENT bytes 0xDE 0xAD 0xBE, VERSION 0x02. Decrypted payload contains INTERCOM_ID (6 bytes), EVENT (8 bytes, doorbell number or 'motion' padded with spaces), TIMESTAMP (4-byte long Unix). Key obtained once via getsession.cgi (NOTIFICATION_ENCRYPTION_KEY). v1 (0x01, Argon2i) deprecated."
  ports: [6524, 35344]
  encryption: "ChaCha20-Poly1305 (v2)"
  keepalive: "Every 7 seconds (skip these)"

- id: doorbell_ring
  description: "Doorbell ring event delivered via UDP broadcast; EVENT field contains doorbell number padded with spaces"

- id: motion_event
  description: "Motion sensor event delivered via UDP broadcast; EVENT field contains 'motion' padded with spaces"

Macros

# UNRESOLVED: no explicit multi-step sequences documented in source

Safety

confirmation_required_for: []
interlocks: []
safety_notes:
  - "open-door.cgi energizes the door opener relay - physical door access control. Ensure requesting user holds appropriate permission."
  - "SIP calls auto-hangup after 180 seconds for security."
  - "Only one simultaneous SIP call supported; official DoorBird App has precedence and will interrupt LAN API streams/calls."
  - "Rate limit: 1 minute IP/user block (HTTP 423) after excessive wrong credentials."
# UNRESOLVED: no explicit interlock procedures or power-on sequencing requirements stated in source

Notes

  • Official DoorBird App always has precedence over LAN API connections — it can interrupt video/audio/SIP streams at any time.
  • HTTPS uses a self-signed certificate (pre-installed); clients must accept it. Video/audio streaming over HTTPS requires a temporary session ID (obtained via getsession.cgi, valid 10 min) appended as ?sessionid=<id>.
  • AEC/ANR echo & noise cancellation must be implemented client-side for audio transmit; DoorBird's native algorithms are not exposed to third parties.
  • Audio codec: G.711 μ-law, 8000 Hz sampling.
  • "API-Operator" permission required for favorites.cgi, schedule.cgi, and sip.cgi. Users on end-user panels/apps should NOT have this permission.
  • Firmware 000110+ required for favorites and schedules.
  • DTMF support (if enabled) lets the SIP call recipient trigger the door-open relay via pincode.
  • Bonjour (_http._tcp) can be used to discover devices on the LAN.

Provenance

source_domains:
  - doorbird.com
source_urls:
  - "https://www.doorbird.com/downloads/api_lan.pdf?rev=0.36"
  - https://www.doorbird.com/api
retrieved_at: 2026-07-14T07:25:36.225Z
last_checked_at: 2026-07-21T22:27:56.209Z

Verification Summary

verdict: verified
checked_at: 2026-07-21T22:27:56.209Z
matched_actions: 27
action_count: 27
confidence: medium
summary: "All 27 spec actions matched verbatim in source document; comprehensive API coverage with all transport parameters verified. (5 unresolved item(s) noted in Known Gaps.)"

Known Gaps

- "device-specific voltage/power/current specs not in source; firmware version for D31TDH not stated"
- "D31TDH support not explicitly stated.\""
- "no explicit multi-step sequences documented in source"
- "no explicit interlock procedures or power-on sequencing requirements stated in source"
- "firmware version compatibility for D31TDH not stated (source mentions feature-gating versions 000099, 000108, 000110, 000129 for various models/features). RTSP 720p/1080p variants tied to D10x/D21x/D11x; D31TDH resolution support not confirmed. Device voltage/power/current specs absent. Default video resolution/compression config-dependent (not enumerated)."

From the AI4AV catalog (https://ai4av.net) · ODbL-1.0