{"info":{"_postman_id":"3b6f9a52-6d1e-4c1f-9d47-0f4d8c1a7e25","name":"Manage²Hero API: webhooks and reconciliation","description":"Requests for the webhooks and the reconciliation of the Manage²Hero API. All values live in variables: enter `token` under **Variables** (API token with scope `webhooks:manage` and the read scopes of the objects) and adjust `base_url` and `receiver_url`. Your token must never end up in a request or an export: keep `token` empty in the exported collection.\n\nFlow: 1. create a webhook (sets the variable `webhook_id`), 2. send a test event, 3. look at the delivery log, 4. reconcile per resource, 5. try the error cases.\n\n**Idempotency-Key:** every writing request gets a key automatically. It is kept per request: sending the same request again repeats the operation without a second effect. For a new operation set the variable `idempotency_renew` to `true` (applies to the next request).\n\nThe description of all calls: https://api.manage2hero.com/docs/en","schema":"https://schema.getpostman.com/json/collection/v2.1.0/collection.json"},"auth":{"type":"bearer","bearer":[{"key":"token","value":"{{token}}","type":"string"}]},"event":[{"listen":"prerequest","script":{"type":"text/javascript","exec":["// Idempotency-Key: one key per request, kept until idempotency_renew is \"true\" (then a new one for ONE request)","if (pm.request.headers.has(\"Idempotency-Key\")) {","  const holder = \"idempotency_key_\" + pm.info.requestId;","  let key = pm.collectionVariables.get(holder);","  if (!key || pm.collectionVariables.get(\"idempotency_renew\") === \"true\") {","    key = pm.variables.replaceIn(\"{{$guid}}\");","    pm.collectionVariables.set(holder, key);","    pm.collectionVariables.set(\"idempotency_renew\", \"false\");","  }","  pm.variables.set(\"idempotency_key\", key);","}"]}},{"listen":"test","script":{"type":"text/javascript","exec":["// Name the request id of every error, support asks for it","if (pm.response.code >= 400) {","  let antwort = {};","  try { antwort = pm.response.json(); } catch (e) { /* not JSON */ }","  console.info(\"HTTP \" + pm.response.code, antwort.error && antwort.error.code, antwort.request_id);","}"]}}],"variable":[{"key":"base_url","value":"https://api-stg.manage2hero.com/v1","type":"string","description":"Base URL including /v1"},{"key":"token","value":"","type":"secret","description":"Your API token (do not export)"},{"key":"receiver_url","value":"https://webhooks.example.com/hooks/manage2hero","type":"string","description":"Public https address of your receiver (port 443)"},{"key":"webhook_id","value":"00000000-0000-4000-8000-000000000000","type":"string"},{"key":"delivery_id","value":"00000000-0000-4000-8000-000000000000","type":"string"},{"key":"object_id","value":"00000000-0000-4000-8000-000000000000","type":"string","description":"Id from data of a message"},{"key":"from_day","value":"2026-01-01","type":"string"},{"key":"to_day","value":"2026-10-12","type":"string"},{"key":"page_cursor","value":"","type":"string"},{"key":"changes_cursor_bookings","value":"","type":"string"},{"key":"pending_cursor_bookings","value":"","type":"string"},{"key":"ids_bookings","value":"00000000-0000-4000-8000-000000000000","type":"string"},{"key":"changes_cursor_payments","value":"","type":"string"},{"key":"pending_cursor_payments","value":"","type":"string"},{"key":"ids_payments","value":"00000000-0000-4000-8000-000000000000","type":"string"},{"key":"changes_cursor_invoices","value":"","type":"string"},{"key":"pending_cursor_invoices","value":"","type":"string"},{"key":"ids_invoices","value":"00000000-0000-4000-8000-000000000000","type":"string"},{"key":"changes_cursor_dunning_notices","value":"","type":"string"},{"key":"pending_cursor_dunning_notices","value":"","type":"string"},{"key":"ids_dunning_notices","value":"00000000-0000-4000-8000-000000000000","type":"string"},{"key":"changes_cursor_documents","value":"","type":"string"},{"key":"pending_cursor_documents","value":"","type":"string"},{"key":"ids_documents","value":"00000000-0000-4000-8000-000000000000","type":"string"},{"key":"changes_cursor_emails","value":"","type":"string"},{"key":"pending_cursor_emails","value":"","type":"string"},{"key":"ids_emails","value":"00000000-0000-4000-8000-000000000000","type":"string"},{"key":"changes_cursor_contracts","value":"","type":"string"},{"key":"pending_cursor_contracts","value":"","type":"string"},{"key":"ids_contracts","value":"00000000-0000-4000-8000-000000000000","type":"string"},{"key":"changes_cursor_damages","value":"","type":"string"},{"key":"pending_cursor_damages","value":"","type":"string"},{"key":"ids_damages","value":"00000000-0000-4000-8000-000000000000","type":"string"},{"key":"demo_key","value":"postman-demo-key-1","type":"string"},{"key":"demo_webhook_id","value":"00000000-0000-4000-8000-000000000000","type":"string"},{"key":"sandbox_token","value":"","type":"secret","description":"Sandbox test token (m2h_test_…, do not export)"},{"key":"sandbox_webhook_id","value":"00000000-0000-4000-8000-000000000000","type":"string"},{"key":"sandbox_webhook_key","value":"postman-sandbox-webhook-1","type":"string"},{"key":"idempotency_renew","value":"false","type":"string"}],"item":[{"name":"1. Manage webhooks","description":"Scope `webhooks:manage`; the token creator needs the right \"API access\" with full access in the management app.","item":[{"name":"Create a webhook","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200 oder 201', function () {","  pm.expect(pm.response.code).to.be.oneOf([200, 201]);","});","if (pm.response.code === 201 || pm.response.code === 200) {","  pm.collectionVariables.set(\"webhook_id\", pm.response.json().data.id);","}"]}}],"request":{"method":"POST","header":[{"key":"Idempotency-Key","value":"{{idempotency_key}}"},{"key":"Content-Type","value":"application/json"}],"url":{"raw":"{{base_url}}/webhooks","host":["{{base_url}}"],"path":["webhooks"]},"description":"The response contains the secret `secret` (`whsec_…`) **once**: copy it into your receiver configuration at once. Sending the same request again returns 200 without the secret (same Idempotency-Key).","body":{"mode":"raw","raw":"{\n  \"url\": \"{{receiver_url}}\",\n  \"events\": [\n    \"payment.received\",\n    \"invoice.created\"\n  ],\n  \"description\": \"Postman\"\n}","options":{"raw":{"language":"json"}}}},"response":[]},{"name":"List all webhooks","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/webhooks","host":["{{base_url}}"],"path":["webhooks"]},"description":"Never contains a secret."},"response":[]},{"name":"One webhook","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/webhooks/{{webhook_id}}","host":["{{base_url}}"],"path":["webhooks","{{webhook_id}}"]}},"response":[]},{"name":"Switch a webhook on again","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});"]}}],"request":{"method":"PATCH","header":[{"key":"Content-Type","value":"application/json"}],"url":{"raw":"{{base_url}}/webhooks/{{webhook_id}}","host":["{{base_url}}"],"path":["webhooks","{{webhook_id}}"]},"description":"After a switch-off (`delivery_failed`). The calling token becomes the creator token.","body":{"mode":"raw","raw":"{\n  \"active\": true\n}","options":{"raw":{"language":"json"}}}},"response":[]},{"name":"Switch a webhook off","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});"]}}],"request":{"method":"PATCH","header":[{"key":"Content-Type","value":"application/json"}],"url":{"raw":"{{base_url}}/webhooks/{{webhook_id}}","host":["{{base_url}}"],"path":["webhooks","{{webhook_id}}"]},"body":{"mode":"raw","raw":"{\n  \"active\": false\n}","options":{"raw":{"language":"json"}}}},"response":[]},{"name":"Delete a webhook","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});"]}}],"request":{"method":"DELETE","header":[],"url":{"raw":"{{base_url}}/webhooks/{{webhook_id}}","host":["{{base_url}}"],"path":["webhooks","{{webhook_id}}"]},"description":"Deletes the webhook with its delivery log."},"response":[]},{"name":"Send a test event","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200 oder 201 oder 202', function () {","  pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);","});"]}}],"request":{"method":"POST","header":[{"key":"Idempotency-Key","value":"{{idempotency_key}}"}],"url":{"raw":"{{base_url}}/webhooks/{{webhook_id}}/test","host":["{{base_url}}"],"path":["webhooks","{{webhook_id}}","test"]},"description":"Queues `webhook.test`: one attempt, a failure does not switch the webhook off. The server sends within about a minute; the result is in the delivery log."},"response":[]},{"name":"Sandbox: simulate an event","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200 oder 404', function () {","  pm.expect(pm.response.code).to.be.oneOf([200, 404]);","});"]}}],"request":{"method":"POST","header":[{"key":"Idempotency-Key","value":"{{idempotency_key}}"},{"key":"Content-Type","value":"application/json"}],"url":{"raw":"{{base_url}}/sandbox/events","host":["{{base_url}}"],"path":["sandbox","events"]},"description":"Only with a sandbox token (m2h_test_…): queues an event for a sample object of the sandbox and sends it to your active webhooks (livemode false). With a real token: 404.","body":{"mode":"raw","raw":"{\n  \"type\": \"payment.received\"\n}","options":{"raw":{"language":"json"}}}},"response":[]},{"name":"Rotate the secret","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200 oder 201', function () {","  pm.expect(pm.response.code).to.be.oneOf([200, 201]);","});"]}}],"request":{"method":"POST","header":[{"key":"Idempotency-Key","value":"{{idempotency_key}}"}],"url":{"raw":"{{base_url}}/webhooks/{{webhook_id}}/rotate-secret","host":["{{base_url}}"],"path":["webhooks","{{webhook_id}}","rotate-secret"]},"description":"Returns a new `secret` once. The previous one stays valid for 24 hours as a second `v1` in the signature header."},"response":[]},{"name":"Delivery log","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});","const items = pm.response.json().data.items || [];","if (items.length > 0) { pm.collectionVariables.set(\"delivery_id\", items[0].id); }"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/webhooks/{{webhook_id}}/deliveries?limit=50","host":["{{base_url}}"],"path":["webhooks","{{webhook_id}}","deliveries"],"query":[{"key":"limit","value":"50"}]},"description":"Newest first, kept for 30 days. Sets `delivery_id` to the first delivery."},"response":[]},{"name":"Failed deliveries only","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/webhooks/{{webhook_id}}/deliveries?status=failed","host":["{{base_url}}"],"path":["webhooks","{{webhook_id}}","deliveries"],"query":[{"key":"status","value":"failed"}]}},"response":[]},{"name":"Send one delivery again (replay)","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200 oder 409', function () {","  pm.expect(pm.response.code).to.be.oneOf([200, 409]);","});"]}}],"request":{"method":"POST","header":[{"key":"Idempotency-Key","value":"{{idempotency_key}}"}],"url":{"raw":"{{base_url}}/webhooks/{{webhook_id}}/deliveries/{{delivery_id}}/retry","host":["{{base_url}}"],"path":["webhooks","{{webhook_id}}","deliveries","{{delivery_id}}","retry"]},"description":"Only for `failed` and `abandoned` (otherwise 409 `delivery_not_replayable`). Same event id, new timestamp and new signature."},"response":[]},{"name":"Send failed deliveries again (bulk replay)","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});"]}}],"request":{"method":"POST","header":[{"key":"Idempotency-Key","value":"{{idempotency_key}}"},{"key":"Content-Type","value":"application/json"}],"url":{"raw":"{{base_url}}/webhooks/{{webhook_id}}/deliveries/retry-failed","host":["{{base_url}}"],"path":["webhooks","{{webhook_id}}","deliveries","retry-failed"]},"description":"Oldest first, at most 100 per call. `remaining` > 0: call again with a **new** key (`idempotency_renew` = `true`).","body":{"mode":"raw","raw":"{\n  \"status\": \"abandoned\",\n  \"period\": \"last_7_days\"\n}","options":{"raw":{"language":"json"}}}},"response":[]}]},{"name":"2. Load the object of an event","description":"`object_id` is the id from `data` of the message (e.g. `payment_id`). The event is only a hint: load the **current** state. 404 means: the object is no longer visible to this token.","item":[{"name":"payment.received (data.payment_id)","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200 oder 404', function () {","  pm.expect(pm.response.code).to.be.oneOf([200, 404]);","});"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/payments/by-ids?ids={{object_id}}","host":["{{base_url}}"],"path":["payments","by-ids"],"query":[{"key":"ids","value":"{{object_id}}"}]}},"response":[]},{"name":"dunning.sent (data.dunning_notice_id)","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200 oder 404', function () {","  pm.expect(pm.response.code).to.be.oneOf([200, 404]);","});"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/dunning/notices/by-ids?ids={{object_id}}","host":["{{base_url}}"],"path":["dunning","notices","by-ids"],"query":[{"key":"ids","value":"{{object_id}}"}]}},"response":[]},{"name":"contract.signed (data.lease_id)","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200 oder 404', function () {","  pm.expect(pm.response.code).to.be.oneOf([200, 404]);","});"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/contracts/by-ids?ids={{object_id}}","host":["{{base_url}}"],"path":["contracts","by-ids"],"query":[{"key":"ids","value":"{{object_id}}"}]}},"response":[]},{"name":"invoice.created (data.invoice_id)","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200 oder 404', function () {","  pm.expect(pm.response.code).to.be.oneOf([200, 404]);","});"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/invoices/by-ids?ids={{object_id}}","host":["{{base_url}}"],"path":["invoices","by-ids"],"query":[{"key":"ids","value":"{{object_id}}"}]}},"response":[]},{"name":"document.created (data.document_id)","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200 oder 404', function () {","  pm.expect(pm.response.code).to.be.oneOf([200, 404]);","});"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/documents/{{object_id}}","host":["{{base_url}}"],"path":["documents","{{object_id}}"]}},"response":[]},{"name":"email.sent (data.email_id)","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200 oder 404', function () {","  pm.expect(pm.response.code).to.be.oneOf([200, 404]);","});"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/emails/{{object_id}}","host":["{{base_url}}"],"path":["emails","{{object_id}}"]}},"response":[]},{"name":"damage.created (data.damage_id)","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200 oder 404', function () {","  pm.expect(pm.response.code).to.be.oneOf([200, 404]);","});"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/damages/by-ids?ids={{object_id}}","host":["{{base_url}}"],"path":["damages","by-ids"],"query":[{"key":"ids","value":"{{object_id}}"}]}},"response":[]},{"name":"contract.terminated (data.lease_id)","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200 oder 404', function () {","  pm.expect(pm.response.code).to.be.oneOf([200, 404]);","});"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/contracts/by-ids?ids={{object_id}}","host":["{{base_url}}"],"path":["contracts","by-ids"],"query":[{"key":"ids","value":"{{object_id}}"}]}},"response":[]},{"name":"invoice.cancelled (data.invoice_id)","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200 oder 404', function () {","  pm.expect(pm.response.code).to.be.oneOf([200, 404]);","});"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/invoices/by-ids?ids={{object_id}}","host":["{{base_url}}"],"path":["invoices","by-ids"],"query":[{"key":"ids","value":"{{object_id}}"}]}},"response":[]},{"name":"damage.updated (data.damage_id)","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200 oder 404', function () {","  pm.expect(pm.response.code).to.be.oneOf([200, 404]);","});"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/damages/by-ids?ids={{object_id}}","host":["{{base_url}}"],"path":["damages","by-ids"],"query":[{"key":"ids","value":"{{object_id}}"}]}},"response":[]},{"name":"Invoice with line items","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200 oder 404', function () {","  pm.expect(pm.response.code).to.be.oneOf([200, 404]);","});"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/invoices/{{object_id}}","host":["{{base_url}}"],"path":["invoices","{{object_id}}"]}},"response":[]},{"name":"Dunning notice with items","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200 oder 404', function () {","  pm.expect(pm.response.code).to.be.oneOf([200, 404]);","});"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/dunning/notices/{{object_id}}","host":["{{base_url}}"],"path":["dunning","notices","{{object_id}}"]}},"response":[]}]},{"name":"3. Reconciliation","description":"Webhooks are a hint, not gap-free delivery: reconcile regularly. A cursor only works for its own resource (otherwise 400 `invalid_cursor`), so every resource has its own variable.","item":[{"name":"Bookings","description":"Order: (1) starting cursor **first**, (2) full fetch, (3) changes since the cursor, (4) reload the ids; keep the new cursor only after successful processing.","item":[{"name":"(1) Starting cursor","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});","pm.collectionVariables.set(\"changes_cursor_bookings\", pm.response.json().data.cursor);"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/bookings/changes/cursor","host":["{{base_url}}"],"path":["bookings","changes","cursor"]}},"response":[]},{"name":"(2) Full fetch in a period","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/bookings?from={{from_day}}&to={{to_day}}&limit=200","host":["{{base_url}}"],"path":["bookings"],"query":[{"key":"from","value":"{{from_day}}"},{"key":"to","value":"{{to_day}}"},{"key":"limit","value":"200"}]},"description":"`from` up to and including `to`; each call is limited to the maximum span of the endpoint (`range_too_large`). Continue with `next_cursor` (see folder Paging)."},"response":[]},{"name":"(3) Changes since the cursor","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});","const daten = pm.response.json().data;","pm.collectionVariables.set(\"pending_cursor_bookings\", daten.next_cursor || daten.resume_cursor || \"\");","const ids = daten.items.map(function (e) { return e.id; }).filter(function (id, i, alle) { return alle.indexOf(id) === i; });","pm.collectionVariables.set(\"ids_bookings\", ids.join(\",\"));","// nothing changed: there is nothing to reload, so the cursor can move on right away","if (ids.length === 0) {","  pm.collectionVariables.set(\"changes_cursor_bookings\", pm.collectionVariables.get(\"pending_cursor_bookings\"));","  pm.collectionVariables.set(\"pending_cursor_bookings\", \"\");","}"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/bookings/changes?cursor={{changes_cursor_bookings}}&limit=100","host":["{{base_url}}"],"path":["bookings","changes"],"query":[{"key":"cursor","value":"{{changes_cursor_bookings}}"},{"key":"limit","value":"100"}]},"description":"Ids only, at most 100 per page (exactly what the next call reloads). The follow-up cursor (`next_cursor`, at the end `resume_cursor`) is only taken over by \"(4) Reload the ids\" once reloading succeeded; on an error simply send (3) and (4) again."},"response":[]},{"name":"(4) Reload the ids","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});","// the page is processed: now (and only now) move the cursor forward","if (pm.response.code === 200 && pm.collectionVariables.get(\"pending_cursor_bookings\")) {","  pm.collectionVariables.set(\"changes_cursor_bookings\", pm.collectionVariables.get(\"pending_cursor_bookings\"));","  pm.collectionVariables.set(\"pending_cursor_bookings\", \"\");","}"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/bookings/by-ids?ids={{ids_bookings}}","host":["{{base_url}}"],"path":["bookings","by-ids"],"query":[{"key":"ids","value":"{{ids_bookings}}"}]},"description":"Current state of the ids from (3) of this resource (at most 100). An id that is missing is no longer visible: remove it locally. If (3) returned no id this call is not needed (the cursor has already moved on)."},"response":[]}]},{"name":"Incoming payments","description":"Order: (1) starting cursor **first**, (2) full fetch, (3) changes since the cursor, (4) reload the ids; keep the new cursor only after successful processing.","item":[{"name":"(1) Starting cursor","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});","pm.collectionVariables.set(\"changes_cursor_payments\", pm.response.json().data.cursor);"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/payments/changes/cursor","host":["{{base_url}}"],"path":["payments","changes","cursor"]}},"response":[]},{"name":"(2) Full fetch in a period","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/payments?from={{from_day}}&to={{to_day}}&limit=200","host":["{{base_url}}"],"path":["payments"],"query":[{"key":"from","value":"{{from_day}}"},{"key":"to","value":"{{to_day}}"},{"key":"limit","value":"200"}]},"description":"`from` up to and including `to`; each call is limited to the maximum span of the endpoint (`range_too_large`). Continue with `next_cursor` (see folder Paging)."},"response":[]},{"name":"(3) Changes since the cursor","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});","const daten = pm.response.json().data;","pm.collectionVariables.set(\"pending_cursor_payments\", daten.next_cursor || daten.resume_cursor || \"\");","const ids = daten.items.map(function (e) { return e.id; }).filter(function (id, i, alle) { return alle.indexOf(id) === i; });","pm.collectionVariables.set(\"ids_payments\", ids.join(\",\"));","// nothing changed: there is nothing to reload, so the cursor can move on right away","if (ids.length === 0) {","  pm.collectionVariables.set(\"changes_cursor_payments\", pm.collectionVariables.get(\"pending_cursor_payments\"));","  pm.collectionVariables.set(\"pending_cursor_payments\", \"\");","}"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/payments/changes?cursor={{changes_cursor_payments}}&limit=100","host":["{{base_url}}"],"path":["payments","changes"],"query":[{"key":"cursor","value":"{{changes_cursor_payments}}"},{"key":"limit","value":"100"}]},"description":"Ids only, at most 100 per page (exactly what the next call reloads). The follow-up cursor (`next_cursor`, at the end `resume_cursor`) is only taken over by \"(4) Reload the ids\" once reloading succeeded; on an error simply send (3) and (4) again."},"response":[]},{"name":"(4) Reload the ids","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});","// the page is processed: now (and only now) move the cursor forward","if (pm.response.code === 200 && pm.collectionVariables.get(\"pending_cursor_payments\")) {","  pm.collectionVariables.set(\"changes_cursor_payments\", pm.collectionVariables.get(\"pending_cursor_payments\"));","  pm.collectionVariables.set(\"pending_cursor_payments\", \"\");","}"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/payments/by-ids?ids={{ids_payments}}","host":["{{base_url}}"],"path":["payments","by-ids"],"query":[{"key":"ids","value":"{{ids_payments}}"}]},"description":"Current state of the ids from (3) of this resource (at most 100). An id that is missing is no longer visible: remove it locally. If (3) returned no id this call is not needed (the cursor has already moved on)."},"response":[]}]},{"name":"Invoices","description":"Order: (1) starting cursor **first**, (2) full fetch, (3) changes since the cursor, (4) reload the ids; keep the new cursor only after successful processing.","item":[{"name":"(1) Starting cursor","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});","pm.collectionVariables.set(\"changes_cursor_invoices\", pm.response.json().data.cursor);"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/invoices/changes/cursor","host":["{{base_url}}"],"path":["invoices","changes","cursor"]}},"response":[]},{"name":"(2) Full fetch in a period","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/invoices?from={{from_day}}&to={{to_day}}&limit=200","host":["{{base_url}}"],"path":["invoices"],"query":[{"key":"from","value":"{{from_day}}"},{"key":"to","value":"{{to_day}}"},{"key":"limit","value":"200"}]},"description":"`from` up to and including `to`; each call is limited to the maximum span of the endpoint (`range_too_large`). Continue with `next_cursor` (see folder Paging)."},"response":[]},{"name":"(3) Changes since the cursor","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});","const daten = pm.response.json().data;","pm.collectionVariables.set(\"pending_cursor_invoices\", daten.next_cursor || daten.resume_cursor || \"\");","const ids = daten.items.map(function (e) { return e.id; }).filter(function (id, i, alle) { return alle.indexOf(id) === i; });","pm.collectionVariables.set(\"ids_invoices\", ids.join(\",\"));","// nothing changed: there is nothing to reload, so the cursor can move on right away","if (ids.length === 0) {","  pm.collectionVariables.set(\"changes_cursor_invoices\", pm.collectionVariables.get(\"pending_cursor_invoices\"));","  pm.collectionVariables.set(\"pending_cursor_invoices\", \"\");","}"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/invoices/changes?cursor={{changes_cursor_invoices}}&limit=100","host":["{{base_url}}"],"path":["invoices","changes"],"query":[{"key":"cursor","value":"{{changes_cursor_invoices}}"},{"key":"limit","value":"100"}]},"description":"Ids only, at most 100 per page (exactly what the next call reloads). The follow-up cursor (`next_cursor`, at the end `resume_cursor`) is only taken over by \"(4) Reload the ids\" once reloading succeeded; on an error simply send (3) and (4) again."},"response":[]},{"name":"(4) Reload the ids","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});","// the page is processed: now (and only now) move the cursor forward","if (pm.response.code === 200 && pm.collectionVariables.get(\"pending_cursor_invoices\")) {","  pm.collectionVariables.set(\"changes_cursor_invoices\", pm.collectionVariables.get(\"pending_cursor_invoices\"));","  pm.collectionVariables.set(\"pending_cursor_invoices\", \"\");","}"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/invoices/by-ids?ids={{ids_invoices}}","host":["{{base_url}}"],"path":["invoices","by-ids"],"query":[{"key":"ids","value":"{{ids_invoices}}"}]},"description":"Current state of the ids from (3) of this resource (at most 100). An id that is missing is no longer visible: remove it locally. If (3) returned no id this call is not needed (the cursor has already moved on)."},"response":[]}]},{"name":"Dunning notices","description":"Order: (1) starting cursor **first**, (2) full fetch, (3) changes since the cursor, (4) reload the ids; keep the new cursor only after successful processing.","item":[{"name":"(1) Starting cursor","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});","pm.collectionVariables.set(\"changes_cursor_dunning_notices\", pm.response.json().data.cursor);"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/dunning/notices/changes/cursor","host":["{{base_url}}"],"path":["dunning","notices","changes","cursor"]}},"response":[]},{"name":"(2) Full fetch in a period","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/dunning/notices?from={{from_day}}&to={{to_day}}&limit=200","host":["{{base_url}}"],"path":["dunning","notices"],"query":[{"key":"from","value":"{{from_day}}"},{"key":"to","value":"{{to_day}}"},{"key":"limit","value":"200"}]},"description":"`from` up to and including `to`; each call is limited to the maximum span of the endpoint (`range_too_large`). Continue with `next_cursor` (see folder Paging)."},"response":[]},{"name":"(3) Changes since the cursor","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});","const daten = pm.response.json().data;","pm.collectionVariables.set(\"pending_cursor_dunning_notices\", daten.next_cursor || daten.resume_cursor || \"\");","const ids = daten.items.map(function (e) { return e.id; }).filter(function (id, i, alle) { return alle.indexOf(id) === i; });","pm.collectionVariables.set(\"ids_dunning_notices\", ids.join(\",\"));","// nothing changed: there is nothing to reload, so the cursor can move on right away","if (ids.length === 0) {","  pm.collectionVariables.set(\"changes_cursor_dunning_notices\", pm.collectionVariables.get(\"pending_cursor_dunning_notices\"));","  pm.collectionVariables.set(\"pending_cursor_dunning_notices\", \"\");","}"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/dunning/notices/changes?cursor={{changes_cursor_dunning_notices}}&limit=100","host":["{{base_url}}"],"path":["dunning","notices","changes"],"query":[{"key":"cursor","value":"{{changes_cursor_dunning_notices}}"},{"key":"limit","value":"100"}]},"description":"Ids only, at most 100 per page (exactly what the next call reloads). The follow-up cursor (`next_cursor`, at the end `resume_cursor`) is only taken over by \"(4) Reload the ids\" once reloading succeeded; on an error simply send (3) and (4) again."},"response":[]},{"name":"(4) Reload the ids","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});","// the page is processed: now (and only now) move the cursor forward","if (pm.response.code === 200 && pm.collectionVariables.get(\"pending_cursor_dunning_notices\")) {","  pm.collectionVariables.set(\"changes_cursor_dunning_notices\", pm.collectionVariables.get(\"pending_cursor_dunning_notices\"));","  pm.collectionVariables.set(\"pending_cursor_dunning_notices\", \"\");","}"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/dunning/notices/by-ids?ids={{ids_dunning_notices}}","host":["{{base_url}}"],"path":["dunning","notices","by-ids"],"query":[{"key":"ids","value":"{{ids_dunning_notices}}"}]},"description":"Current state of the ids from (3) of this resource (at most 100). An id that is missing is no longer visible: remove it locally. If (3) returned no id this call is not needed (the cursor has already moved on)."},"response":[]}]},{"name":"Documents","description":"Order: (1) starting cursor **first**, (2) full fetch, (3) changes since the cursor, (4) reload the ids; keep the new cursor only after successful processing.","item":[{"name":"(1) Starting cursor","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});","pm.collectionVariables.set(\"changes_cursor_documents\", pm.response.json().data.cursor);"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/documents/changes/cursor","host":["{{base_url}}"],"path":["documents","changes","cursor"]}},"response":[]},{"name":"(2) Full fetch","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/documents?period=all&limit=200","host":["{{base_url}}"],"path":["documents"],"query":[{"key":"period","value":"all"},{"key":"limit","value":"200"}]},"description":"`period=all`; page on with `next_cursor`."},"response":[]},{"name":"(3) Changes since the cursor","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});","const daten = pm.response.json().data;","pm.collectionVariables.set(\"pending_cursor_documents\", daten.next_cursor || daten.resume_cursor || \"\");","const ids = daten.items.map(function (e) { return e.id; }).filter(function (id, i, alle) { return alle.indexOf(id) === i; });","pm.collectionVariables.set(\"ids_documents\", ids.join(\",\"));","// nothing changed: there is nothing to reload, so the cursor can move on right away","if (ids.length === 0) {","  pm.collectionVariables.set(\"changes_cursor_documents\", pm.collectionVariables.get(\"pending_cursor_documents\"));","  pm.collectionVariables.set(\"pending_cursor_documents\", \"\");","}"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/documents/changes?cursor={{changes_cursor_documents}}&limit=100","host":["{{base_url}}"],"path":["documents","changes"],"query":[{"key":"cursor","value":"{{changes_cursor_documents}}"},{"key":"limit","value":"100"}]},"description":"Ids only, at most 100 per page (exactly what the next call reloads). The follow-up cursor (`next_cursor`, at the end `resume_cursor`) is only taken over by \"(4) Reload the ids\" once reloading succeeded; on an error simply send (3) and (4) again."},"response":[]},{"name":"(4) Reload the ids","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});","// the page is processed: now (and only now) move the cursor forward","if (pm.response.code === 200 && pm.collectionVariables.get(\"pending_cursor_documents\")) {","  pm.collectionVariables.set(\"changes_cursor_documents\", pm.collectionVariables.get(\"pending_cursor_documents\"));","  pm.collectionVariables.set(\"pending_cursor_documents\", \"\");","}"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/documents/by-ids?ids={{ids_documents}}","host":["{{base_url}}"],"path":["documents","by-ids"],"query":[{"key":"ids","value":"{{ids_documents}}"}]},"description":"Current state of the ids from (3) of this resource (at most 100). An id that is missing is no longer visible: remove it locally. If (3) returned no id this call is not needed (the cursor has already moved on)."},"response":[]}]},{"name":"Emails","description":"Order: (1) starting cursor **first**, (2) full fetch, (3) changes since the cursor, (4) reload the ids; keep the new cursor only after successful processing.","item":[{"name":"(1) Starting cursor","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});","pm.collectionVariables.set(\"changes_cursor_emails\", pm.response.json().data.cursor);"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/emails/changes/cursor","host":["{{base_url}}"],"path":["emails","changes","cursor"]}},"response":[]},{"name":"(2) Full fetch","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/emails?period=all&limit=200","host":["{{base_url}}"],"path":["emails"],"query":[{"key":"period","value":"all"},{"key":"limit","value":"200"}]},"description":"`period=all`; page on with `next_cursor`."},"response":[]},{"name":"(3) Changes since the cursor","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});","const daten = pm.response.json().data;","pm.collectionVariables.set(\"pending_cursor_emails\", daten.next_cursor || daten.resume_cursor || \"\");","const ids = daten.items.map(function (e) { return e.id; }).filter(function (id, i, alle) { return alle.indexOf(id) === i; });","pm.collectionVariables.set(\"ids_emails\", ids.join(\",\"));","// nothing changed: there is nothing to reload, so the cursor can move on right away","if (ids.length === 0) {","  pm.collectionVariables.set(\"changes_cursor_emails\", pm.collectionVariables.get(\"pending_cursor_emails\"));","  pm.collectionVariables.set(\"pending_cursor_emails\", \"\");","}"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/emails/changes?cursor={{changes_cursor_emails}}&limit=100","host":["{{base_url}}"],"path":["emails","changes"],"query":[{"key":"cursor","value":"{{changes_cursor_emails}}"},{"key":"limit","value":"100"}]},"description":"Ids only, at most 100 per page (exactly what the next call reloads). The follow-up cursor (`next_cursor`, at the end `resume_cursor`) is only taken over by \"(4) Reload the ids\" once reloading succeeded; on an error simply send (3) and (4) again."},"response":[]},{"name":"(4) Reload the ids","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});","// the page is processed: now (and only now) move the cursor forward","if (pm.response.code === 200 && pm.collectionVariables.get(\"pending_cursor_emails\")) {","  pm.collectionVariables.set(\"changes_cursor_emails\", pm.collectionVariables.get(\"pending_cursor_emails\"));","  pm.collectionVariables.set(\"pending_cursor_emails\", \"\");","}"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/emails/by-ids?ids={{ids_emails}}","host":["{{base_url}}"],"path":["emails","by-ids"],"query":[{"key":"ids","value":"{{ids_emails}}"}]},"description":"Current state of the ids from (3) of this resource (at most 100). An id that is missing is no longer visible: remove it locally. If (3) returned no id this call is not needed (the cursor has already moved on)."},"response":[]}]},{"name":"Contracts","description":"Order: (1) starting cursor **first**, (2) full fetch, (3) changes since the cursor, (4) reload the ids; keep the new cursor only after successful processing.","item":[{"name":"(1) Starting cursor","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});","pm.collectionVariables.set(\"changes_cursor_contracts\", pm.response.json().data.cursor);"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/contracts/changes/cursor","host":["{{base_url}}"],"path":["contracts","changes","cursor"]}},"response":[]},{"name":"(2) Full fetch","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/contracts?period=all&limit=200","host":["{{base_url}}"],"path":["contracts"],"query":[{"key":"period","value":"all"},{"key":"limit","value":"200"}]},"description":"`period=all`; page on with `next_cursor`."},"response":[]},{"name":"(3) Changes since the cursor","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});","const daten = pm.response.json().data;","pm.collectionVariables.set(\"pending_cursor_contracts\", daten.next_cursor || daten.resume_cursor || \"\");","const ids = daten.items.map(function (e) { return e.id; }).filter(function (id, i, alle) { return alle.indexOf(id) === i; });","pm.collectionVariables.set(\"ids_contracts\", ids.join(\",\"));","// nothing changed: there is nothing to reload, so the cursor can move on right away","if (ids.length === 0) {","  pm.collectionVariables.set(\"changes_cursor_contracts\", pm.collectionVariables.get(\"pending_cursor_contracts\"));","  pm.collectionVariables.set(\"pending_cursor_contracts\", \"\");","}"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/contracts/changes?cursor={{changes_cursor_contracts}}&limit=100","host":["{{base_url}}"],"path":["contracts","changes"],"query":[{"key":"cursor","value":"{{changes_cursor_contracts}}"},{"key":"limit","value":"100"}]},"description":"Ids only, at most 100 per page (exactly what the next call reloads). The follow-up cursor (`next_cursor`, at the end `resume_cursor`) is only taken over by \"(4) Reload the ids\" once reloading succeeded; on an error simply send (3) and (4) again."},"response":[]},{"name":"(4) Reload the ids","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});","// the page is processed: now (and only now) move the cursor forward","if (pm.response.code === 200 && pm.collectionVariables.get(\"pending_cursor_contracts\")) {","  pm.collectionVariables.set(\"changes_cursor_contracts\", pm.collectionVariables.get(\"pending_cursor_contracts\"));","  pm.collectionVariables.set(\"pending_cursor_contracts\", \"\");","}"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/contracts/by-ids?ids={{ids_contracts}}","host":["{{base_url}}"],"path":["contracts","by-ids"],"query":[{"key":"ids","value":"{{ids_contracts}}"}]},"description":"Current state of the ids from (3) of this resource (at most 100). An id that is missing is no longer visible: remove it locally. If (3) returned no id this call is not needed (the cursor has already moved on)."},"response":[]}]},{"name":"Damages","description":"Order: (1) starting cursor **first**, (2) full fetch, (3) changes since the cursor, (4) reload the ids; keep the new cursor only after successful processing.","item":[{"name":"(1) Starting cursor","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});","pm.collectionVariables.set(\"changes_cursor_damages\", pm.response.json().data.cursor);"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/damages/changes/cursor","host":["{{base_url}}"],"path":["damages","changes","cursor"]}},"response":[]},{"name":"(2) Full fetch","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/damages?period=all&limit=200","host":["{{base_url}}"],"path":["damages"],"query":[{"key":"period","value":"all"},{"key":"limit","value":"200"}]},"description":"`period=all`; page on with `next_cursor`."},"response":[]},{"name":"(3) Changes since the cursor","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});","const daten = pm.response.json().data;","pm.collectionVariables.set(\"pending_cursor_damages\", daten.next_cursor || daten.resume_cursor || \"\");","const ids = daten.items.map(function (e) { return e.id; }).filter(function (id, i, alle) { return alle.indexOf(id) === i; });","pm.collectionVariables.set(\"ids_damages\", ids.join(\",\"));","// nothing changed: there is nothing to reload, so the cursor can move on right away","if (ids.length === 0) {","  pm.collectionVariables.set(\"changes_cursor_damages\", pm.collectionVariables.get(\"pending_cursor_damages\"));","  pm.collectionVariables.set(\"pending_cursor_damages\", \"\");","}"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/damages/changes?cursor={{changes_cursor_damages}}&limit=100","host":["{{base_url}}"],"path":["damages","changes"],"query":[{"key":"cursor","value":"{{changes_cursor_damages}}"},{"key":"limit","value":"100"}]},"description":"Ids only, at most 100 per page (exactly what the next call reloads). The follow-up cursor (`next_cursor`, at the end `resume_cursor`) is only taken over by \"(4) Reload the ids\" once reloading succeeded; on an error simply send (3) and (4) again."},"response":[]},{"name":"(4) Reload the ids","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});","// the page is processed: now (and only now) move the cursor forward","if (pm.response.code === 200 && pm.collectionVariables.get(\"pending_cursor_damages\")) {","  pm.collectionVariables.set(\"changes_cursor_damages\", pm.collectionVariables.get(\"pending_cursor_damages\"));","  pm.collectionVariables.set(\"pending_cursor_damages\", \"\");","}"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/damages/by-ids?ids={{ids_damages}}","host":["{{base_url}}"],"path":["damages","by-ids"],"query":[{"key":"ids","value":"{{ids_damages}}"}]},"description":"Current state of the ids from (3) of this resource (at most 100). An id that is missing is no longer visible: remove it locally. If (3) returned no id this call is not needed (the cursor has already moved on)."},"response":[]},{"name":"One damage with documents","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200 oder 404', function () {","  pm.expect(pm.response.code).to.be.oneOf([200, 404]);","});"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/damages/{{object_id}}","host":["{{base_url}}"],"path":["damages","{{object_id}}"]}},"response":[]}]}]},{"name":"4. Paging","description":"Every list returns `items` and `next_cursor`. Send \"Next page\" until `next_cursor` is `null`. The cursor only works with the same filters as the first page.","item":[{"name":"First page (2 entries)","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});","pm.collectionVariables.set(\"page_cursor\", pm.response.json().data.next_cursor || \"\");"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/documents?period=all&limit=2","host":["{{base_url}}"],"path":["documents"],"query":[{"key":"period","value":"all"},{"key":"limit","value":"2"}]}},"response":[]},{"name":"Next page","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});","pm.collectionVariables.set(\"page_cursor\", pm.response.json().data.next_cursor || \"\");","pm.test(\"next_cursor ist vorhanden (null = letzte Seite)\", function () {","  pm.expect(pm.response.json().data).to.have.property(\"next_cursor\");","});"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/documents?period=all&limit=2&cursor={{page_cursor}}","host":["{{base_url}}"],"path":["documents"],"query":[{"key":"period","value":"all"},{"key":"limit","value":"2"},{"key":"cursor","value":"{{page_cursor}}"}]}},"response":[]}]},{"name":"5. Error cases","description":"Every request triggers an error on purpose; the test checks status and `error.code`. Every error response carries a `request_id`: quote it to support.","item":[{"name":"No token (401)","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 401', function () {","  pm.expect(pm.response.code).to.be.oneOf([401]);","});","pm.test('error.code ist missing_token', function () {","  pm.expect(pm.response.json().error.code).to.eql('missing_token');","});"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/webhooks","host":["{{base_url}}"],"path":["webhooks"]},"auth":{"type":"noauth"}},"response":[]},{"name":"Invalid token (401)","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 401', function () {","  pm.expect(pm.response.code).to.be.oneOf([401]);","});"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/webhooks","host":["{{base_url}}"],"path":["webhooks"]},"auth":{"type":"bearer","bearer":[{"key":"token","value":"kein-gueltiges-token","type":"string"}]}},"response":[]},{"name":"Unknown parameter (400)","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 400', function () {","  pm.expect(pm.response.code).to.be.oneOf([400]);","});","pm.test('error.code ist validation_error', function () {","  pm.expect(pm.response.json().error.code).to.eql('validation_error');","});"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/payments?from={{from_day}}&to={{to_day}}&gibt_es_nicht=1","host":["{{base_url}}"],"path":["payments"],"query":[{"key":"from","value":"{{from_day}}"},{"key":"to","value":"{{to_day}}"},{"key":"gibt_es_nicht","value":"1"}]}},"response":[]},{"name":"Invalid id in the path (400)","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 400', function () {","  pm.expect(pm.response.code).to.be.oneOf([400]);","});","pm.test('error.code ist validation_error', function () {","  pm.expect(pm.response.json().error.code).to.eql('validation_error');","});"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/invoices/keine-uuid","host":["{{base_url}}"],"path":["invoices","keine-uuid"]}},"response":[]},{"name":"Unknown id (404)","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 404', function () {","  pm.expect(pm.response.code).to.be.oneOf([404]);","});","pm.test('error.code ist not_found', function () {","  pm.expect(pm.response.json().error.code).to.eql('not_found');","});"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/invoices/00000000-0000-4000-8000-000000000000","host":["{{base_url}}"],"path":["invoices","00000000-0000-4000-8000-000000000000"]}},"response":[]},{"name":"Range too large (400)","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 400', function () {","  pm.expect(pm.response.code).to.be.oneOf([400]);","});","pm.test('error.code ist range_too_large', function () {","  pm.expect(pm.response.json().error.code).to.eql('range_too_large');","});"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/payments?from=2020-01-01&to=2026-10-12","host":["{{base_url}}"],"path":["payments"],"query":[{"key":"from","value":"2020-01-01"},{"key":"to","value":"2026-10-12"}]}},"response":[]},{"name":"Reversed range (400)","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 400', function () {","  pm.expect(pm.response.code).to.be.oneOf([400]);","});","pm.test('error.code ist range_invalid', function () {","  pm.expect(pm.response.json().error.code).to.eql('range_invalid');","});"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/payments?from=2026-10-12&to=2026-01-01","host":["{{base_url}}"],"path":["payments"],"query":[{"key":"from","value":"2026-10-12"},{"key":"to","value":"2026-01-01"}]}},"response":[]},{"name":"Invalid cursor (400)","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 400', function () {","  pm.expect(pm.response.code).to.be.oneOf([400]);","});","pm.test('error.code ist invalid_cursor', function () {","  pm.expect(pm.response.json().error.code).to.eql('invalid_cursor');","});"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/payments/changes?cursor=kein-cursor","host":["{{base_url}}"],"path":["payments","changes"],"query":[{"key":"cursor","value":"kein-cursor"}]}},"response":[]},{"name":"Unknown address (404)","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 404', function () {","  pm.expect(pm.response.code).to.be.oneOf([404]);","});","pm.test('error.code ist route_not_found', function () {","  pm.expect(pm.response.json().error.code).to.eql('route_not_found');","});"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/does-not-exist","host":["{{base_url}}"],"path":["does-not-exist"]}},"response":[]},{"name":"Writing call without Idempotency-Key (400)","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 400', function () {","  pm.expect(pm.response.code).to.be.oneOf([400]);","});","pm.test('error.code ist idempotency_key_required', function () {","  pm.expect(pm.response.json().error.code).to.eql('idempotency_key_required');","});"]}}],"request":{"method":"POST","header":[],"url":{"raw":"{{base_url}}/webhooks/00000000-0000-4000-8000-000000000000/test","host":["{{base_url}}"],"path":["webhooks","00000000-0000-4000-8000-000000000000","test"]}},"response":[]}]},{"name":"6. Idempotency-Key","description":"Same key and same content: the same success without a second effect. Same key and different content: 409 `idempotency_conflict`. The two requests use the fixed key `demo_key`. **The first one creates a real webhook** (delete it afterwards with the third request of this folder; it deletes only this demo webhook, not the one from folder 1).","item":[{"name":"Create a webhook (content A)","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200 oder 201', function () {","  pm.expect(pm.response.code).to.be.oneOf([200, 201]);","});","if (pm.response.code === 200 || pm.response.code === 201) {","  pm.collectionVariables.set(\"demo_webhook_id\", pm.response.json().data.id);","}"]}}],"request":{"method":"POST","header":[{"key":"Idempotency-Key","value":"{{demo_key}}"},{"key":"Content-Type","value":"application/json"}],"url":{"raw":"{{base_url}}/webhooks","host":["{{base_url}}"],"path":["webhooks"]},"description":"Sent again: 200 without the secret, no second webhook.","body":{"mode":"raw","raw":"{\n  \"url\": \"{{receiver_url}}\",\n  \"events\": [\n    \"payment.received\"\n  ],\n  \"description\": \"Postman idempotency demo\"\n}","options":{"raw":{"language":"json"}}}},"response":[]},{"name":"Same key, different content (409)","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 409', function () {","  pm.expect(pm.response.code).to.be.oneOf([409]);","});"]}}],"request":{"method":"POST","header":[{"key":"Idempotency-Key","value":"{{demo_key}}"},{"key":"Content-Type","value":"application/json"}],"url":{"raw":"{{base_url}}/webhooks","host":["{{base_url}}"],"path":["webhooks"]},"description":"Expects 409 `idempotency_conflict`: the same key was used with different content.","body":{"mode":"raw","raw":"{\n  \"url\": \"{{receiver_url}}\",\n  \"events\": [\n    \"invoice.created\"\n  ],\n  \"description\": \"Postman idempotency demo\"\n}","options":{"raw":{"language":"json"}}}},"response":[]},{"name":"Delete the demo webhook","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200 oder 404', function () {","  pm.expect(pm.response.code).to.be.oneOf([200, 404]);","});"]}}],"request":{"method":"DELETE","header":[],"url":{"raw":"{{base_url}}/webhooks/{{demo_webhook_id}}","host":["{{base_url}}"],"path":["webhooks","{{demo_webhook_id}}"]},"description":"Deletes the webhook of the first request in this folder (variable `demo_webhook_id`), never the one from folder 1."},"response":[]}]},{"name":"7. Sandbox (test mode)","description":"For trying things out without real data. Enter a **test token** (`m2h_test_…`, Administration → API access → Sandbox) as `sandbox_token` under **Variables**; the requests in this folder never use the real `token`. The sandbox needs active API access (otherwise 403 `sandbox_unavailable`). Delivery to your receiver only happens from production; messages carry `livemode: false`.","item":[{"name":"Read locations (sample data)","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});","pm.test(\"Antwortkopf X-M2H-Sandbox ist true\", function () {","  pm.expect(pm.response.headers.get(\"X-M2H-Sandbox\")).to.eql(\"true\");","});"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/locations","host":["{{base_url}}"],"path":["locations"]},"description":"Every response to a test token carries the header `X-M2H-Sandbox: true`.","auth":{"type":"bearer","bearer":[{"key":"token","value":"{{sandbox_token}}","type":"string"}]}},"response":[]},{"name":"Create a webhook for the sandbox","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200 oder 201', function () {","  pm.expect(pm.response.code).to.be.oneOf([200, 201]);","});","if (pm.response.code === 201 || pm.response.code === 200) {","  pm.collectionVariables.set(\"sandbox_webhook_id\", pm.response.json().data.id);","}"]}}],"request":{"method":"POST","header":[{"key":"Idempotency-Key","value":"{{sandbox_webhook_key}}"},{"key":"Content-Type","value":"application/json"}],"url":{"raw":"{{base_url}}/webhooks","host":["{{base_url}}"],"path":["webhooks"]},"description":"The test token needs the scope `webhooks:manage`; at most 3 webhooks per sandbox. The response contains the secret once.","auth":{"type":"bearer","bearer":[{"key":"token","value":"{{sandbox_token}}","type":"string"}]},"body":{"mode":"raw","raw":"{\n  \"url\": \"{{receiver_url}}\",\n  \"events\": [\n    \"payment.received\",\n    \"invoice.created\",\n    \"dunning.sent\"\n  ],\n  \"description\": \"Postman Sandbox\"\n}","options":{"raw":{"language":"json"}}}},"response":[]},{"name":"Simulate an event: payment received","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});","pm.test(\"Antwortkopf X-M2H-Sandbox ist true\", function () {","  pm.expect(pm.response.headers.get(\"X-M2H-Sandbox\")).to.eql(\"true\");","});"]}}],"request":{"method":"POST","header":[{"key":"Idempotency-Key","value":"{{idempotency_key}}"},{"key":"Content-Type","value":"application/json"}],"url":{"raw":"{{base_url}}/sandbox/events","host":["{{base_url}}"],"path":["sandbox","events"]},"description":"Queues `payment.received` for a sample object of the sandbox without any real booking. The server sends from production only (`delivery` in the response); the history is under `/webhooks/{id}/deliveries`. Quotas: 100 waiting and 500 per 24 hours.","auth":{"type":"bearer","bearer":[{"key":"token","value":"{{sandbox_token}}","type":"string"}]},"body":{"mode":"raw","raw":"{\n  \"type\": \"payment.received\"\n}","options":{"raw":{"language":"json"}}}},"response":[]},{"name":"Simulate an event: invoice created","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});","pm.test(\"Antwortkopf X-M2H-Sandbox ist true\", function () {","  pm.expect(pm.response.headers.get(\"X-M2H-Sandbox\")).to.eql(\"true\");","});"]}}],"request":{"method":"POST","header":[{"key":"Idempotency-Key","value":"{{idempotency_key}}"},{"key":"Content-Type","value":"application/json"}],"url":{"raw":"{{base_url}}/sandbox/events","host":["{{base_url}}"],"path":["sandbox","events"]},"description":"Queues `invoice.created` for a sample object of the sandbox without any real booking. The server sends from production only (`delivery` in the response); the history is under `/webhooks/{id}/deliveries`. Quotas: 100 waiting and 500 per 24 hours.","auth":{"type":"bearer","bearer":[{"key":"token","value":"{{sandbox_token}}","type":"string"}]},"body":{"mode":"raw","raw":"{\n  \"type\": \"invoice.created\"\n}","options":{"raw":{"language":"json"}}}},"response":[]},{"name":"Simulate an event: dunning notice","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});","pm.test(\"Antwortkopf X-M2H-Sandbox ist true\", function () {","  pm.expect(pm.response.headers.get(\"X-M2H-Sandbox\")).to.eql(\"true\");","});"]}}],"request":{"method":"POST","header":[{"key":"Idempotency-Key","value":"{{idempotency_key}}"},{"key":"Content-Type","value":"application/json"}],"url":{"raw":"{{base_url}}/sandbox/events","host":["{{base_url}}"],"path":["sandbox","events"]},"description":"Queues `dunning.sent` for a sample object of the sandbox without any real booking. The server sends from production only (`delivery` in the response); the history is under `/webhooks/{id}/deliveries`. Quotas: 100 waiting and 500 per 24 hours.","auth":{"type":"bearer","bearer":[{"key":"token","value":"{{sandbox_token}}","type":"string"}]},"body":{"mode":"raw","raw":"{\n  \"type\": \"dunning.sent\"\n}","options":{"raw":{"language":"json"}}}},"response":[]},{"name":"Delivery log of the sandbox","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});"]}}],"request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/webhooks/{{sandbox_webhook_id}}/deliveries?limit=50","host":["{{base_url}}"],"path":["webhooks","{{sandbox_webhook_id}}","deliveries"],"query":[{"key":"limit","value":"50"}]},"auth":{"type":"bearer","bearer":[{"key":"token","value":"{{sandbox_token}}","type":"string"}]}},"response":[]},{"name":"Delete the sandbox webhook","event":[{"listen":"test","script":{"type":"text/javascript","exec":["pm.test('Status ist 200', function () {","  pm.expect(pm.response.code).to.be.oneOf([200]);","});"]}}],"request":{"method":"DELETE","header":[],"url":{"raw":"{{base_url}}/webhooks/{{sandbox_webhook_id}}","host":["{{base_url}}"],"path":["webhooks","{{sandbox_webhook_id}}"]},"auth":{"type":"bearer","bearer":[{"key":"token","value":"{{sandbox_token}}","type":"string"}]}},"response":[]}]}]}