Install

Reserve a Doctolib appointment slot for the logged-in user (UNTESTED draft).

UNTESTED until recorded logged in. Selects an exact slot (from doctolib.de/get-slots) in Doctolib's booking funnel for the user's own logged-in account, after an explicit Allow. Returns the practice's notices, which the user must read, and the next booking page to finish in the browser. It does not accept practice notices or confirm the appointment on its own.

No reports yetAsks before it sends, your login
Site
Doctolib, Germany
Version
v1
Runs, last 7 days
No reports yet
sha256
f26b3e5d5082…

Requests

sent from your browser, in order
  1. 1POST/online_booking/api/slot_selection_funnel/v1/select_slotOBSERVED anonymously only (spikes/doctolib.md). Logged out, Doctolib answers with redirection to /auth/patient_de, which is reported as login_required. Logged in, the response and the following funnel calls are unknown: record them with tools/har2recipe before shipping.writes, asks firstjson body

Before it writes, the extension shows you UNTESTED recipe. Reserve the Doctolib slot {{params.start_date}} (visit type {{params.visit_motive_id}}, practice {{params.practice_id}}, {{params.insurance_sector}} insurance) for your logged-in Doctolib account. You finish the booking yourself in Doctolib. and waits for Allow.

Parameters

from your agent
agenda_idsinteger[]required
insurance_sectorenumrequired "public" | "private"
practice_idintegerrequired
profile_idintegerrequiredFrom search-practitioners
start_datestringrequiredExact slot timestamp from get-slots, e.g. 2026-11-09T15:45:00.000+01:00
visit_motive_idintegerrequired

Returns

to your agent
continue_urlstringDoctolib page to finish the booking
practice_noticesstring[]Practice notices (HTML) the user must read and accept in Doctolib before the booking is final
statusany

Where it can send

  • www.doctolib.de

Anything else is blocked by the extension.

Reads from your session

  • csrf from meta

Used only in requests to the addresses on the left. Never sent to wield.run or your agent.

Checks

a run passes when
  • output.status == 'slot_selected_unconfirmed'

Raw recipe

Served as canonical JSON from /api/v1/recipes/doctolib.de/book-slot, so its sha256 matches the ETag and the index.

Check it yourself
curl -s https://wield.run/api/v1/recipes/doctolib.de/book-slot | shasum -a 256
# f26b3e5d5082951dd4ce99b9bcf4505d31bf56916883cda4f61808af6720c96a
doctolib.de/book-slot.json, v1
{
  "auth": {
    "derive": [
      {
        "attr": "content",
        "from": "meta",
        "name": "csrf",
        "selector": "meta[name=\"csrf-token\"]"
      }
    ]
  },
  "confirm": {
    "summary": "UNTESTED recipe. Reserve the Doctolib slot {{params.start_date}} (visit type {{params.visit_motive_id}}, practice {{params.practice_id}}, {{params.insurance_sector}} insurance) for your logged-in Doctolib account. You finish the booking yourself in Doctolib."
  },
  "description": "UNTESTED until recorded logged in. Selects an exact slot (from doctolib.de/get-slots) in Doctolib's booking funnel for the user's own logged-in account, after an explicit Allow. Returns the practice's notices, which the user must read, and the next booking page to finish in the browser. It does not accept practice notices or confirm the appointment on its own.",
  "effect": "write",
  "id": "doctolib.de/book-slot",
  "keywords": [
    "doctolib",
    "termin buchen",
    "arzttermin buchen",
    "book appointment",
    "booking"
  ],
  "output": {
    "schema": {
      "properties": {
        "continue_url": {
          "description": "Doctolib page to finish the booking",
          "type": [
            "string",
            "null"
          ]
        },
        "practice_notices": {
          "description": "Practice notices (HTML) the user must read and accept in Doctolib before the booking is final",
          "items": {
            "type": "string"
          },
          "type": "array"
        },
        "status": {
          "const": "slot_selected_unconfirmed"
        }
      },
      "type": "object"
    },
    "value": "{practice_notices: steps.select_slot.notices, continue_url: steps.select_slot.redirection && (starts_with(steps.select_slot.redirection, 'http') && steps.select_slot.redirection || join('', ['https://www.doctolib.de', steps.select_slot.redirection])) || `null`, status: 'slot_selected_unconfirmed'}"
  },
  "params": {
    "additionalProperties": false,
    "properties": {
      "agenda_ids": {
        "items": {
          "type": "integer"
        },
        "minItems": 1,
        "type": "array"
      },
      "insurance_sector": {
        "enum": [
          "public",
          "private"
        ],
        "type": "string"
      },
      "practice_id": {
        "type": "integer"
      },
      "profile_id": {
        "description": "From search-practitioners",
        "type": "integer"
      },
      "start_date": {
        "description": "Exact slot timestamp from get-slots, e.g. 2026-11-09T15:45:00.000+01:00",
        "pattern": "^\\d{4}-\\d{2}-\\d{2}T",
        "type": "string"
      },
      "visit_motive_id": {
        "type": "integer"
      }
    },
    "required": [
      "profile_id",
      "visit_motive_id",
      "agenda_ids",
      "practice_id",
      "insurance_sector",
      "start_date"
    ],
    "type": "object"
  },
  "provenance": {
    "method": "browser-inspect",
    "notes": "UNTESTED. Only select_slot was seen, anonymously, in the UI (spikes/doctolib.md); the anonymous response carried draft_rules (a practice notice to accept) and redirection to /auth/patient_de. CSRF: the UI sends x-csrf-token from meta[name=csrf-token] (Rails). Unknown until Victor records the logged-in flow (tools/har2recipe): the appointment-creation and confirm calls, whether accepting the notice is its own request, patient selection (self or relative), 2FA, and whether select_slot holds the slot. The final confirm step must be added as another write:true step.",
    "recorded_at": "2026-11-07T12:13:00+01:00",
    "recorded_by": "C4"
  },
  "requires_login": true,
  "schema": "https://wield.run/schema/recipe/v1.json",
  "site": {
    "country": "DE",
    "id": "doctolib.de",
    "language": "de",
    "login_url": "https://www.doctolib.de/auth/patient_de",
    "name": "Doctolib",
    "origin": "https://www.doctolib.de",
    "origins": [
      "https://www.doctolib.de"
    ]
  },
  "steps": [
    {
      "description": "OBSERVED anonymously only (spikes/doctolib.md). Logged out, Doctolib answers with redirection to /auth/patient_de, which is reported as login_required. Logged in, the response and the following funnel calls are unknown: record them with tools/har2recipe before shipping.",
      "expect": {
        "content_type": "json",
        "login_required_if": {
          "assert": "contains(body.redirection || '', '/auth/')",
          "status": [
            401,
            403
          ]
        },
        "status": [
          200,
          201
        ]
      },
      "extract": {
        "json": {
          "notices": "draft_rules[].body || `[]`",
          "redirection": "redirection || `null`",
          "visit_motive_id": "visit_motive_id || `null`"
        }
      },
      "id": "select_slot",
      "request": {
        "body": {
          "type": "json",
          "value": {
            "agenda_ids": "{{params.agenda_ids}}",
            "insurance_sector": "{{params.insurance_sector}}",
            "practice_ids": [
              "{{params.practice_id}}"
            ],
            "profile_id": "{{params.profile_id}}",
            "source_action": "profile",
            "start_date": "{{params.start_date}}",
            "visit_motive_ids": [
              "{{params.visit_motive_id}}"
            ]
          }
        },
        "headers": {
          "Accept": "application/json",
          "Content-Type": "application/json; charset=utf-8",
          "X-CSRF-Token": "{{vars.csrf}}"
        },
        "method": "POST",
        "url": "/online_booking/api/slot_selection_funnel/v1/select_slot"
      },
      "write": true
    }
  ],
  "task": "Reserve a Doctolib appointment slot for the logged-in user (UNTESTED draft)",
  "tos": {
    "notes": "Booking acts on the user's own Doctolib account and only after an explicit Allow per run. Never auto-accept practice notices; the user reads them. One booking per user request, no retries that could double-book.",
    "reviewed": false
  },
  "verify": {
    "checks": [
      "output.status == 'slot_selected_unconfirmed'"
    ],
    "example_params": {
      "agenda_ids": [
        2359956
      ],
      "insurance_sector": "public",
      "practice_id": 723928,
      "profile_id": 1534568,
      "start_date": "2026-11-09T15:45:00.000+01:00",
      "visit_motive_id": 14928354
    }
  },
  "version": 1
}