Skip to content
XICBOT

Settings

Deutsch
Documentation · API reference

API: account, security, billing and privacy

Endpoints for profile, account switching, password, two-factor authentication, security keys, sessions, billing, data export, retention and account deletion.

In plain language

This page describes the endpoints for your own account. They cover profile, password and the second step of sign-in. Security keys and sessions belong here too. You can see when someone signed in. Other endpoints deal with billing and privacy. For these endpoints you need the token from the sign-in. A key for your own systems is not enough.

Last updated

All documentation topics

This page describes the endpoints for your own account: sign-out, profile, account switching, confirmation mail, password, two-factor authentication, security keys, sessions and sign-in history, plus billing and privacy. All paths start with /api/v1/ and require the session token from sign-in, not an API key. In the application you find the same functions under Account, Billing and Legal and data.

Requirements

Without a valid session token, every endpoint on this page responds with 401. How to obtain a token is described in API authentication. After that, these checks apply depending on the endpoint:

CheckApplies toResponse on failure
Account activeevery endpoint on this page except POST /api/v1/tenant/switch and POST /api/v1/logout403 no_tenant or tenant_paused, tenant_suspended, tenant_deleted with the German text „Das Konto ist derzeit nicht aktiv.“ (the account is currently not active) in message
Email address confirmedall paths under /api/v1/billing and /api/v1/privacy/403 email_unverified
Rolewhere stated for the endpoint403 role_too_low, with the required role in required
No takeoverwhere stated for the endpoint403 in_impersonation

The roles build on one another: Read, Edit, Administration, Owner. If an endpoint requires a role, that role or a higher one is sufficient. How the roles differ in the application is described in Team and roles.

If the operator takes over your account to help you, that session appears in the session list with kind support, in the application as Takeover by the operator. From a takeover, the password, two-factor authentication and security keys cannot be changed, all other sessions cannot be ended in one go and the account cannot be switched.

Rate limits

Some endpoints count requests per person and minute. Endpoints with the same limit share one counter: five password attempts within a minute also use up the attempts for turning off two-factor authentication. What happens when a limit is exceeded is described in API limits.

LimitEndpointsRequests per minute
tenant-switchPOST /api/v1/tenant/switch20
confirmationPOST /api/v1/confirmation/resend3
password-changePUT /api/v1/password, DELETE /api/v1/totp, DELETE /api/v1/webauthn/{id}5, one shared counter
privacyGET /api/v1/privacy/export, POST /api/v1/privacy/subprocessors/object, PUT /api/v1/privacy/retention, POST /api/v1/privacy/deletion5, one shared counter
dpaPOST /api/v1/privacy/dpa10, counted per account and person

Account and profile

POST /api/v1/logout

Ends the session that makes the request: the token is deleted and is no longer valid afterwards. Other sessions remain. This also works when the account is no longer active. Called with the token of an impersonation, the request ends the impersonation like POST /api/v1/impersonation/stop; the log then shows impersonation.end. The response is {"logged_out": true}.

Authentication
Session token, any role

GET /api/v1/me

Returns the signed-in person in user, the account they are currently working in in tenant and every account they belong to in tenants. During a takeover, impersonation holds the address of the person who took over (operator) and the end of the takeover (expires_at), otherwise null.

Authentication
Session token, any role
Field in userContent
id, email, nameID, address and name of the person
rolerole in the current account: viewer, editor, admin or owner
localede, en or empty; every successful sign-in that sends de or en as locale sets it, and so does PUT /api/v1/locale with de or en, which the language button of the application calls (403 during a takeover). It sets the language of the confirmation email, of the email after a password change and of the invitations the person sends, German if empty
totp_activetrue if two-factor authentication by code is set up and confirmed
webauthn_keysnumber of registered security keys
email_verifiedtrue if the address is confirmed
operatortrue only for the operator's own logins, false for customer accounts
available, available_atwhether the person is currently accepting handovers, and since when
FieldContent
tenantamong others id, name, slug, status, the plan in plan and plan_name and its features in features
tenantsper account id, name, slug, your own role in role, status, an identifying colour in color and in active whether it is the current account. Deleted accounts are left out; paused and suspended ones are listed with their status.

POST /api/v1/tenant/switch

Switches to another account you belong to, in the application via Switch account. The tenant field holds the ID of the target account (required, at most 64 characters). Afterwards you work with the role you have in that account. Switching also works if the current account is not active; the target has to be active. The response contains user, tenant and tenants as with GET /api/v1/me.

Authentication
Session token, not from a takeover
Rate limit
20 per minute
StatusErrorMeaning
403in_impersonationrequest from a takeover
404not_foundyou do not belong to this account, or it does not exist
403tenant_paused, tenant_suspended, tenant_deletedthe target account is not active; message gives the reason

PUT /api/v1/tenant/name

Changes the account name, the company or project name from sign-up; in the application under Account in the Account name card. The name field holds the new name (required, at most 160 characters, surrounding spaces are removed). The account's identifier (slug) stays unchanged. If the name changes, the Audit log records the old and the new name. The response contains tenant with id and name.

Authentication
Session token, Owner role, confirmed email address, not from a takeover
StatusErrorMeaning
403role_too_lowthe role is not Owner; required is owner
403in_impersonationrequest from a takeover
403email_unverifiedthe email address is not confirmed yet
422validationname is missing, empty or longer than 160 characters

POST /api/v1/confirmation/resend

Sends the confirmation link for the email address again, in the language from locale; in the application this is Send the message again. The endpoint does not require a confirmed address, otherwise unconfirmed accounts could not reach it. If the address is already confirmed, nothing is sent and the response is {"confirmed": true, "sent": false}. Otherwise earlier links that have not been used become invalid, the new one is valid for 48 hours, and the response is {"confirmed": false, "sent": true}.

Authentication
Session token, any role
Rate limit
3 per minute

Password and two-factor authentication

PUT /api/v1/password

Changes the password, in the application under Account with Change password. Changing it ends every other sign-in session of the person; the session the request comes from and a running takeover by the operator remain. API keys are not sessions and stay valid. Afterwards an email goes to the account address stating the time and the number of ended sessions.

Authentication
Session token, not from a takeover
Rate limit
5 per minute, shared with turning off two-factor authentication and removing keys
FieldRule
current_passwordrequired, at most 200 characters; in the application Current password
passwordrequired, at least 12 characters, including letters and digits, different from the current one; in the application New password
password_confirmationrequired, equal to password; in the application Repeat password
StatusResponseMeaning
200{"ok": true, "sessions_ended": 2}changed; sessions_ended counts the ended sessions
403in_impersonationrequest from a takeover
422bad_credentialsthe current password is wrong

Two-factor authentication by code

Two-factor authentication by code is called Two-factor authentication in the application and is switched on in two steps: Set up creates a secret, Confirm activates it with the first code from the authenticator app. As long as the confirmation is missing, two-factor authentication does not apply. How the code is requested at sign-in is described in API authentication.

POST /api/v1/totp

Creates a new secret from 20 random bytes and returns it Base32-encoded in secret and as an otpauth:// address in url for the authenticator app: method according to RFC 6238, issuer XICBOT, SHA1, six digits, 30 seconds per code. In the application the value is shown under Secret. Calling the endpoint again replaces a secret that has not been confirmed yet. If two-factor authentication is already active, the endpoint responds with 409 totp_already_active.

Authentication
Session token, not from a takeover

POST /api/v1/totp/confirm

Confirms the secret with a code in the totp field (required, at most 10 characters; in the application Six-digit code). Spaces are removed; exactly six digits must remain. The code of the current 30-second step is accepted, as are those of the previous and the following step. The response is {"is_active": true}. Without a log entry two-factor authentication is not turned on, and the response is 500 with not_logged.

Authentication
Session token, not from a takeover

DELETE /api/v1/totp

Turns off two-factor authentication (Turn off) and requires the password in the password field of the request body. The secret and its confirmation are deleted. The response is {"is_active": false}. Without a log entry two-factor authentication stays on, and the response is 500 with not_logged.

Authentication
Session token, not from a takeover
Rate limit
5 per minute, shared with the password change and removing keys
StatusErrorMeaning
403in_impersonationrequest from a takeover
409totp_already_activeset up although two-factor authentication is already active
409no_secretconfirm without setting up first
422bad_totpthe code is wrong
422bad_credentialswhen turning off: the password is wrong
500not_loggedthe change could not be logged and was therefore not saved; operator logins without an account of their own are exempt, for them the change takes effect even without a log entry

Security keys

Besides the code, a WebAuthn security key can be registered as a second factor, in the application under Security keys with Add key. If a key is registered, sign-in lists it in methods as webauthn; the flow is described in API authentication. Registering takes two steps: POST /api/v1/webauthn/options fetches the challenge, the browser has the key sign it with navigator.credentials.create, and POST /api/v1/webauthn submits the result. Binary values are base64url-encoded without padding in both directions.

GET /api/v1/webauthn

Lists the registered keys of the signed-in person in keys, oldest first.

Authentication
Session token, any role
FieldContent
idID of the key, used for removing it
namethe name you gave it when registering
algorithmsignature algorithm: ES256, EdDSA or RS256
user_verifiedtrue if the key verified the person when it was registered, for example by PIN or fingerprint
created, last_used_atregistration and last use at a sign-in

POST /api/v1/webauthn/options

Creates a challenge from 32 random bytes and stores it for the signed-in person; only the most recently fetched one is valid per person. The response contains what the browser needs for navigator.credentials.create.

Authentication
Session token, not from a takeover
FieldContent
challengethe challenge
rp_id, rp_namerelying party ID and display name of the service, XICBOT unless configured otherwise
userid (your ID, encoded), name (your address) and display_name (your name, or the address if there is no name)
excludeIDs of keys already registered, so the same key is not registered twice
algorithmspermitted algorithms as numbers: -7, -8, -257
timeoutvalidity of the challenge in seconds, at least 30, 120 unless configured otherwise

POST /api/v1/webauthn

Submits the result of navigator.credentials.create. The server checks the challenge, the origin of the page and the signature itself. After a successful check the challenge is used up; fetch a new one for another attempt. The response (201) contains the new key in key and the whole list in keys. Without a log entry the key is not stored, and the response is 500 with not_logged.

Authentication
Session token, not from a takeover
FieldRule
namerequired, at most 80 characters; in the application Name of the key
client_data_jsonrequired, at most 8000 characters, base64url
attestation_objectrequired, at most 20000 characters, base64url

DELETE /api/v1/webauthn/{id}

Removes a key (Remove) and requires the password in the password field of the request body, like turning off the code factor. The response contains the remaining keys in keys. Without a log entry the key remains, and the response is 500 with not_logged.

Authentication
Session token, not from a takeover
Rate limit
5 per minute, shared with the password change and turning off two-factor authentication
StatusErrorMeaning
403in_impersonationrequest from a takeover
404not_foundwhen removing: this person has no key with this ID
409webauthn_limitthe maximum number of keys has been reached, 10 per person unless configured otherwise
409webauthn_knownthis key is already registered
422challenge_expiredno valid challenge, for example because it has expired
422bad_attestationthe check failed; reason names the point of failure
422bad_credentialswhen removing: the password is wrong
500not_loggedthe change could not be logged and was therefore not saved; operator logins without an account of their own are exempt, for them the change takes effect even without a log entry
503webauthn_unconfiguredsecurity keys are not set up for this service

Sessions and sign-in history

Each sign-in receives its own session token, valid for 30 days. Its name is the identification the browser gives of itself, cut to 190 characters, or sitzung if there is none. API keys are not sessions and do not appear here; you manage them under API keys and webhooks.

GET /api/v1/sessions

Lists in sessions the still valid sessions of the signed-in person, in the application Signed-in devices, at most 50, most recently used first. Expired sessions are left out.

Authentication
Session token, any role
FieldContent
idID of the session, used for ending it
namebrowser identification of the sign-in
last, created, expires_atlast use, sign-in and expiry
currenttrue for the session the request comes from; in the application this device
kindlogin for your own sign-in, support for a takeover by the operator

DELETE /api/v1/sessions

Ends all other sessions of the signed-in person (End all others). The session the request comes from and takeovers by the operator remain, and so do API keys. The response gives the number of ended sessions in ended and the number of those left in kept: support for takeovers still running (expired ones are not counted), api_keys for the valid API keys of the account. The audit log entry account.sessions_ended gives the same numbers in count, kept_support and kept_api_keys.

Authentication
Session token, not from a takeover

DELETE /api/v1/sessions/{id}

Ends a single session of your own (End). An ID that does not belong to a current session of the signed-in person returns 404 not_found, including that of a session that has already expired. From a takeover by the operator, only the takeover itself can be ended; any other session returns 403 in_impersonation. The response is {"ended": true}.

Authentication
Session token, any role

GET /api/v1/logins

Returns in logins the 50 most recent sign-in attempts for the signed-in person, in the application Recent sign-ins, failed ones included. Each entry has time, result and in device the browser identification, cut to 240 characters. The IP address is only stored as a hash and is not returned.

Authentication
Session token, any role
resultMeaning
successsigned in
bad_passwordwrong password
unknownthere is no login for the address entered
bad_totpwrong two-factor code
bad_webauthnsecurity key rejected
lockedcredentials correct, but the account is not active

Billing

GET /api/v1/billing

Returns usage and line items of the current month for the current account, in the application under Billing on the Usage and billing page. Amounts are in cents, net. Plan prices are listed under Pricing, the quotas under Plans and quotas.

Authentication
Session token, any role
FieldContent
periodfrom and to as dates, month as the month
tenantid, name, billing email address in billing_email, VAT ID in vat_id
packagekey, name and scope of the plan; known is false if the plan key is unknown
limitsthe limits of the plan, in the application Plan limits, for example monthly_token_budget and requests_per_minute; if values are stored for the account itself, those apply, whatever the plan
usageusage of the month, see below
itemsthe line items, in the application Line items
price_basisnetto (net)
total_cents, total_completetotal of the line items (Total); if a line item has no amount, total_cents is null and total_complete is false
payment_providernull: no payment has been triggered
Line item (kind)Content
base_feethe plan as one line item with the monthly amount in unit_cents and total_cents. If the plan has no fixed monthly amount, both are null, measured is false, reason gives the reason as a sentence and reason_code as a fixed code.
overageonly appears if usage exceeds the quota: amount gives the tokens above it, the amounts are null, measured is false, reason and reason_code give the reason
Field in usageContent
month, used, budget, remainingmonth, tokens used (input and output), quota and remainder
messagesnumber of replies in the month
warn_at, sharewarning threshold in tokens and share used, truncated to four decimal places
warning, exhausted, levelwarning level reached, quota used up; level combines both as ok, warning or exhausted
throttled, reply_tokens, tool_roundsfrom the warning threshold on, replies are shorter; the two numbers give the reply length in tokens and the number of tool rounds that then apply
warningsone entry per metric (token, messages) with used, limit, warn_share, warn_at, share, state (ok, warning, exhausted), measured, reason and reason_code

The warning starts at a fixed share of the quota, warn_share, currently 0.8. There is no monthly quota for replies: the messages entry in warnings counts them in used but has measured set to false, and limit, warn_share, warn_at, share and state stay empty. There, measured refers to the warning, not to the counting.

GET /api/v1/billing/history

Returns in months the usage per month, in the application History, at most 24 months, most recent first. Each entry has month, tokens_in, tokens_out, the sum of both in token and the number of replies in messages.

Authentication
Session token, any role

In the application these endpoints are found under Legal and data. All of them require a confirmed email address; reading is allowed for every role, changes are reserved for Administration or the Owner depending on the endpoint. What the data means is described in Privacy and legal.

Overview of stored data

GET /api/v1/privacy/overview

Returns the overview the application shows under Stored data and in the sections below it.

Authentication
Session token, any role
FieldContent
categoriesnumber of stored entries per category
categories_unmeasuredfor each category that could not be counted, the reason; its number in categories is then null, in the application Not measured
catalogcheck status of the data catalogue that export and deletion work from: complete is true if every table holding account data is in the catalogue and the order is correct; if this could not be checked, complete is null and measured is false
retentionperiods in days for conversations (general), test conversations (test), conversations via the API (api) and logs (logs)
retention_objectsall object types with their period, as with PUT /api/v1/privacy/retention
dpastatus of the data processing agreement, as with GET /api/v1/privacy/dpa
deletion_wordthe word used to confirm an account deletion
versionscurrent versions of the terms of use (terms), the privacy policy (privacy) and the data processing agreement (dpa)

GET /api/v1/privacy/legal

Returns the annex Technical and organisational measures in tom, with its version in version, the contract version in contract_version and the groups in groups; each group has key, title and items with key, title, text and state. accessibility holds the accessibility statement.

Authentication
Session token, any role

Data export

GET /api/v1/privacy/export

Returns the account data as a JSON file, in the application under Data export with Export data. The export contains conversations in plain text and is therefore reserved for the owner. The file is named xicbot-ausfuhr-<account-id>-<date>.json. If the export cannot be logged, no file is delivered and the response is 500 with not_logged.

Authentication
Session token, role Owner
Rate limit
5 per minute, shared with the other privacy endpoints that make changes
FieldContent
generated, tenanttime of the export and ID of the account
sectionsper section ok, on success the data in data, otherwise null and the reason in reason; a failed section does not empty the others. Also withheld with the deliberately omitted fields as table.field and truncated with the shortened tables, each with table, exported, stored, measured and reason
failed_sectionsnames of the failed sections
unexported_tablestables of the data catalogue not covered by any section
catalogcheck status of the data catalogue as in the overview
completetrue if no section failed, every catalogue table is covered, catalog.complete is true and no section is shortened
files_completetrue only without files attached by visitors; the files are not part of the export
filesvisitor_attachments with count, bytes, measured, reason and the download request for the ZIP archive

The headers x-sections, x-failed, x-unexported and x-truncated give the number of sections, of failed sections, of tables not covered and of shortened tables, and x-files-not-included the number of files attached by visitors that are not in the file. The account section contains the people of the account with role, language, two-factor status and the name, registration and last use of their security keys, but not their credential_id, credential_hash and public_key. Columns marked as secret or as derived in the catalogue and the account ID per row are left out; if a secret sits in a JSON column, the file shows __set__ there if a value is set and an empty value otherwise. Some sections are limited in their number of rows, oldest entries first: activities to 5000, logins to 2000 and the sections taken from single tables to 20000 rows. If activities, logins or a section taken from a single table contains fewer entries than are stored for the account, its truncated names the table with exported and stored, and complete is false. If the stored number cannot be counted, stored is null and measured is false; the section then still counts as shortened.

GET /api/v1/privacy/export/attachments

Returns the files visitors attached as a ZIP archive: each file as <conversation>/<id>.<extension> plus manifest.json with ID, conversation, enquiry, name, type, size and checksum, a missing file with missing: true. The headers x-files and x-files-missing give the numbers. If the request cannot be logged, nothing is delivered and the response is 500 with not_logged.

Authentication
Session token, role Owner
Rate limit
5 per minute, shared with the other privacy endpoints that make changes

Retention periods

PUT /api/v1/privacy/retention

Sets the periods per object type in days, in the application under Retention periods with Save. Every field is optional: a missing field leaves the period unchanged, null sets it to "nothing is deleted". Whole numbers from 1 to 3650 are allowed; 0 is not permitted because it means something different from null. The response contains the new state in retention_objects. Without a log entry the previous periods stay in place, and the response is 500 with not_logged. What the periods do is described in Retention and deletion.

Authentication
Session token, role Administration or higher
Rate limit
5 per minute, shared with the other privacy endpoints that make changes
FieldObject type
conversationsconversations
conversations_testtest conversations; without a value of its own, the period of conversations applies
conversations_apiconversations via the API; without a value of its own, the period of conversations applies
leadsenquiries; the period also applies to appointments and cart_handoffs
attachmentsuploaded files
visitor_attachmentsvisitor attachments
logslogs; the period also applies to login_events (sign-in events)
Field per entry in retention_objectsContent
key, daysobject type and its own period in days, null without its own period
follows, effective_daysobject type whose period applies without a value of its own, and the resulting effective period
deletesfalse if no period applies
settable, nullablewhether the period can be set through this endpoint and set to null
table, column, date_column, filter, cascadewhat the period is attached to: table, column holding the period, relevant date and selection
StatusErrorMeaning
422validation error per fieldvalue outside 1 to 3650 or not a whole number; in the application "Permitted values are 1 to 3650 days."
500not_loggedthe change could not be logged and was therefore not saved
500no_settable_retentionno object type can be set

Data processing agreement and sub-processors

GET /api/v1/privacy/dpa

Returns the status of the Data processing agreement: the current contract version in contract_version, the contract text in contract, the acceptance in accepted_at, accepted_version and accepted_by (name of the person who accepted; accepted_by_gone is true if that person can no longer be found) and in contract_pending whether acceptance of the current version is outstanding. subprocessors holds the current list version (version), the confirmed version (confirmed_version), whether a confirmation is outstanding (change_pending) and the directory (directory).

Authentication
Session token, any role

POST /api/v1/privacy/dpa

Accepts the agreement (Accept the agreement) and confirms the list version (Confirm this version). Both fields must be present in the request body: contract as true or false, subprocessor_version as the list version (at most 20 characters) or null. With contract: true the current version is stored with time and person if there is no acceptance yet or a version other than the current one was accepted; the earlier acceptance is then replaced. If the current version has already been accepted, accepting it again leaves that acceptance unchanged. A version in subprocessor_version is only accepted if it matches the current one. The response matches GET /api/v1/privacy/dpa. Without a log entry neither the acceptance nor the list version is stored, and the response is 500 with not_logged.

Authentication
Session token, role Owner
Rate limit
10 per minute per account and person
StatusErrorMeaning
409contract_version_mismatchthe contract text does not match the current version; contract and expected give both
409stale_statethe list has a new version in the meantime; current gives it
500not_loggedthe consent could not be logged and was therefore not saved

POST /api/v1/privacy/subprocessors/object

Objects to the current version of the list of Sub-processors (Object). The reason field holds the reason (required, 5 to 1000 characters; in the application Reason for the objection). The response gives in version the version objected to, carries ingested set to true and in objection the recorded objection with id, version, created_at and answered_at. It is kept as a record of its own, does not expire with the audit log retention and is part of the export (subprocessor_objections); the operator receives a notice with account, version and reason. If the log entry cannot be written, the record is not created either: the response is then 500 with not_logged, and the application shows Not saved: the entry in the audit log could not be written. Please try again. and keeps the reason in the field. Your objection has been recorded. We will get back to you. only appears after a response with ingested set to true.

Authentication
Session token, role Administration or higher
Rate limit
5 per minute, shared with the other privacy endpoints that make changes

Delete account

POST /api/v1/privacy/deletion

Deletes the current account, in the application under Delete account. The confirmation field (required, at most 40 characters) holds the word from deletion_word in the overview, currently LOESCHEN; the application asks for it with Type this word to confirm. Deletion works from the data catalogue and does not start unless catalog.complete is true.

Authentication
Session token, role Owner
Rate limit
5 per minute, shared with the other privacy endpoints that make changes
StatusResponseMeaning
200deleted, log_id, count_before, count_after, unmeasured_before, unmeasured_after, catalogdeleted; the counts per category before and after the deletion, categories that could not be counted with their reason, and the catalogue status
422bad_confirmationthe word is wrong; expected gives the expected one
409already_deletedthe account has been deleted in the meantime, for example by a second request sent at the same time
500catalog_emptythe data catalogue is empty, nothing is deleted
500catalog_incompletecatalog.complete is not true: tables are missing from the catalogue, unknown to it or in the wrong order, or the catalogue could not be checked; missing_tables, unknown_tables and order_violations list the findings, nothing is deleted
500not_loggedthe deletion could not be logged, nothing is deleted

People who also belong to another account that has not been deleted keep their login and move there, preferably to an account they own; their sessions end. The other people are made unrecognisable: name and email address are replaced, the password is replaced by a random value and two-factor authentication is removed. The account receives the status deleted; the billing email address and the VAT ID are removed.

Frequent questions

Why do I get 429 although I have only changed the password twice?

Changing the password, turning off two-factor authentication and removing a security key share one counter of 5 requests per minute and person. Wait for the period given in Retry-After; more under API limits.

Do API keys remain valid if I change the password or end all other sessions?

Yes. API keys are not sessions and remain; DELETE /api/v1/sessions gives their number in kept.api_keys. You revoke a key as described in API keys and webhooks.

Who may export the data or delete the account?

Only the Owner role. Setting periods and objecting to the list of sub-processors is allowed from Administration upwards; every role may read. The roles are described in Team and roles.

Why does a category show Not measured instead of a number?

Counting this category failed. Its number in categories is then null and the reason is in categories_unmeasured. null does not mean that there are no entries.

What is blocked during a takeover by the operator?

Changing the password, setting up, confirming and turning off two-factor authentication, registering and removing security keys, ending all other sessions, ending a single session other than the takeover itself and switching accounts. These endpoints respond with 403 in_impersonation.

Something still unclear?

Tell us which page and which step you mean. We reply personally.

Enquiry in three steps

  1. 1. Topic
  2. 2. Your case
  3. 3. Contact

What is this about?

One click is enough, everything else is optional.

Tell us briefly about your case

Everything in this step is optional. It helps us reply with something concrete straight away instead of asking back.

Enquiries per month, roughly (optional)
When should it start? (optional)
How can we reach you?

Name and email address are enough. We reply personally.

We use your details to handle your enquiry. More on this in the privacy policy.