mmDial API

Reference · as of October 2026 · Deutsch · back to the main page

General

The mmDial API connects external software to an mmDial account: find and download call recordings, export data, maintain the do-not-call list, and read, create and change leads.

Addresshttps://login.mmdial.de/api/index.php
CallThe action is always given as action in the query string, for example ?action=dnccheck&number=024192789880.
MethodWhich values are expected as GET and which as POST is stated with each action. Where it says GET or POST, either works.
ResponseJSON, encoded as UTF-8. Two exceptions: dncget answers in plain text, and a file request returns the file itself.
AuthenticationWith every call. Without a valid token the API answers 401 Unauthorized – see Token access.

Not every mmDial interface is listed here. If you need another one, please contact our support – a good deal exists and is simply not written up yet.

About the error responses. These actions are of different ages and therefore do not answer uniformly: depending on the action, the status values are ok, found, exists or notfound, and the error text appears in msg, message or reason. What an action sends is stated with that action. When in doubt, rely on the HTTP status and on status.

Token access

Every call identifies itself with a token. You create the token yourself in the customer administration, under API tokens.

The token in a call

Preferably in the Authorization header:

curl -H "Authorization: Bearer <TOKEN>" \
     "https://login.mmdial.de/api/index.php?action=dncget"

Where that is not possible, HTTP basic authentication works as well – user name xmlrpc_user, password is the token:

curl -u "xmlrpc_user:<TOKEN>" \
     "https://login.mmdial.de/api/index.php?action=dncget"

You may append your dialer id to the user name, separated by - or _, for example xmlrpc_user-1098. This changes nothing about the check, but the id ends up in the web server's access log and helps us with troubleshooting. If it does not match the token, the call is rejected.

Whether the token works

The API answers 401 Unauthorized when the token is unknown, switched off, or not allowed for this action. On a 401, check both: the token itself and its action restriction.

The old access method is deprecated. The API used to authenticate with a user account that had admin rights. That method is no longer documented and should no longer be used: a token can be switched off individually and restricted to actions, a user account cannot. Please migrate existing integrations.

authtestGET

The probe action: it answers only when the authentication is valid. No parameters.

curl -H "Authorization: Bearer <TOKEN>" \
     "https://login.mmdial.de/api/index.php?action=authtest"

{"status":"ok","login":"token","customer":1098,"time":"2026-10-26 11:04:12"}
FieldMeaning
statusalways ok – the fact that anything answers here is the information
loginhow you are authenticated: token
customerthe customer number the token belongs to
dialeridonly if you appended the id to the user name. Its presence means it arrived and was checked.
timethe server's time

A restricted token may do this too. authtest is exempt from the action restriction – otherwise you would get a 401 precisely for those tokens where checking matters most, and would take a valid token for a broken one. For monitoring, the HTTP status is enough: 200 means the credentials work.

Fetching filesGET

Recordings and export files are fetched with action=getfile. The ready-made address is part of the response of whichever action created or found the file – in the url field. Take it from there instead of assembling it yourself.

Parameters

NameRequiredMeaning
typeyesvoices for a recording, temp for an export file
fileyesfor voices the voiceid from the recording search, for temp the file_id from the export

Response

The file itself, not JSON. Authentication is required here as well: the address alone does not hand anything out.

curl -H "Authorization: Bearer <TOKEN>" -o recording.mp3 \
  "https://login.mmdial.de/api/index.php?action=getfile&type=voices&file=9912837"

Export files are meant to be fetched, not stored – please collect them promptly.

Field names

Three actions work with lead fields: exportbystatus, addlead and editlead. They use the same names.

NameMeaning
titleform of address or title
phonephone number. In responses always with the country code in front.
alt_phonesecond phone number
first_namefirst name
last_namelast name
company_namecompany name
streetstreet
streetnrhouse number
addraddaddress addition. In responses the same field is called streetadd.
plzpostal code
ortcity
countrycountry code, for example DE
noticesnotes, the comment field
leadid_externalyour own lead number
statusthe lead's status (only editlead and responses)
rotationyes = the lead is available for dialling again (only editlead and responses)
xtra_…your own extra fields, as far as they are set up for the account

The date of birth. When writing (addlead, editlead) the field is called birthdate. The old name bithdate – a typo from earlier years – stays valid; if you send both, the value of bithdate is used. In the export the field is called birthday. The expected format is DD.MM.YYYY.

The export additionally accepts these names, which do not exist when writing: agentid (agent of the last call), imported_date (created on), last_edit (last changed), last_phone (last call). Any other column of the lead table can also be exported under its own name.

searchvoicebyleadidGET

Finds the recordings belonging to a lead.

Parameters

NameRequiredMeaning
leadidyesthe lead number

Response

FieldMeaning
statusok or error
msgonly with error, for example no lead found
voiceslist of recordings, most recent first
  recidnumber of the recording
  agentidagent who handled the call
  timestampstart of the recording
  availableyes if the file can be fetched, otherwise no
  voiceidnumber of the file (only with yes)
  urladdress to fetch the file (only with yes)
  lengthlength in seconds (only with yes)
  sizesize in bytes (only with yes)
{
  "status": "ok",
  "voices": [
    {
      "recid": "4815162",
      "agentid": "1098-204",
      "timestamp": "2026-10-20 11:32:07",
      "available": "yes",
      "voiceid": "9912837",
      "url": "https://login.mmdial.de/api/index.php?action=getfile&type=voices&file=9912837",
      "length": "184",
      "size": "1472000"
    }
  ]
}

About the address. It points at the same host you just called the API on, and it uses https. Send the same authentication when fetching the file as with the call itself – the address alone does not hand out a file. See Fetching files.

If available is no, the recording has not finished transferring yet or was deleted after the retention period. The other values are still there.

searchvoicebyphonenumberGET

Finds recordings by the customer's phone number.

Parameters

NameRequiredMeaning
phoneyesthe number as it was dialled (national form, with the leading zero)
datenoonly recordings of that day, YYYY-MM-DD
timestampnoexactly this recording, YYYY-MM-DD HH:MM:SS

Response

As with searchvoicebyleadid, and every entry additionally carries leadid – the same number can appear in several leads.

At most 1000 recordings per call, most recent first. Narrow the range with date if you expect more.

searchvoicebyagentGET

Finds recordings by agent.

Parameters

NameRequiredMeaning
agentidyesthe agent id as it appears in the administration
datenoonly recordings of that day, YYYY-MM-DD
timestampnoexactly this recording, YYYY-MM-DD HH:MM:SS

Response

As with searchvoicebyphonenumber, likewise at most 1000 recordings per call. For a full day of one agent that is usually not enough – query day by day in that case.

getfieldsbycampaignGET

Lists the order form fields of a campaign. This tells you the names that exportbystatus and editlead expect.

Parameters

NameRequiredMeaning
campaign_idyesthe campaign number
allfieldsnoyes also lists the fields for which data has already been stored in this campaign – including fields of forms that have since been replaced.

Response

{
  "fields": [
    { "name": "Kundennummer", "GUID": "41" },
    { "name": "Tarif",        "GUID": "41" }
  ]
}

GUID is the number of the form. A field of the same name can appear in several forms of one campaign; only name and GUID together identify it. Entries coming from allfields=yes have no GUID.

getfieldsbyguidGET

The same for a single form, by its number. Useful when a campaign has several forms and you only need the fields of one.

Parameters

NameRequiredMeaning
GUIDyesthe number of the form – spelled in capitals
allfieldsnoyes also lists the fields for which data has already been stored under this number

Response

As with getfieldsbycampaign: a list fields with name and GUID.

exportbystatusGETPOST

Creates a CSV file with the leads of a campaign and returns the address to fetch it from. You choose the fields yourself.

Parameters

NameRequiredMeaning
campaign_idyesthe campaign number
selectedfieldsyesThe fields of the file, separated by commas, in column order. Lead fields with the prefix customerfield_, order form fields with webformfield_<GUID>_. GET or POST.
list_idnoonly this one list. Without it, all lists of the campaign.
statusnoonly these statuses – repeat the parameter as an array: status[]=NEW&status[]=SALE. Without it, all of them.
datetypenowhat the time range refers to: last_phone (last call, the default), last_edit (last change) or imported_date (created on)
fromdate, fromtimenostart of the range, DD.MM.YYYY and HH:MM:SS. Both together, otherwise neither takes effect.
todate, totimenoend of the range, likewise
encodingnocharacter encoding of the file: ISO-8859-1 (the default), Windows-1252 or UTF-8

Response

FieldMeaning
statusok or error
messageonly with error, e.g. Keine Kampagne angegeben (no campaign given) or Nichts zu exportieren (nothing to export)
file_idid of the generated file
sizesize in bytes
urladdress to fetch it from
broken_data_countnumber of rows that could not be converted into the chosen encoding. Greater than 0 means the file contains a note instead of the data at those places. With encoding=UTF-8 this does not happen.
curl -H "Authorization: Bearer <TOKEN>" \
  "https://login.mmdial.de/api/index.php?action=exportbystatus\
&campaign_id=3000&status[]=SALE&datetype=last_edit\
&fromdate=01.10.2026&fromtime=00:00:00\
&selectedfields=customerfield_leadid_external,customerfield_company_name,customerfield_phone,webformfield_41_Tarif\
&encoding=UTF-8"

{"status":"ok","file_id":"6f1c0b9e4a2d8d31b7a05c9e3d8f7a21",
 "size":182344,
 "url":"https://login.mmdial.de/api/index.php?action=getfile&type=temp&file=6f1c0b9e4a2d8d31b7a05c9e3d8f7a21",
 "broken_data_count":0}

Fetch the file from that address afterwards – again with your token, and over https:

curl -H "Authorization: Bearer <TOKEN>" -o export.csv \
  "https://login.mmdial.de/api/index.php?action=getfile&type=temp&file=<file_id>"

About the file

getcampaignsGET

Lists all campaigns of the account. No parameters.

Response

{
  "campaigns": [
    { "id": "3000", "name": "Vertrieb Nord", "callerid": "4924194580649",
      "active": "Y", "ki_enabled": "Y" },
    { "id": "3500", "name": "Verkauf", "callerid": "4924194580649",
      "active": "N", "ki_enabled": "N" }
  ]
}
FieldMeaning
idthe campaign number you use for all other calls
namethe name from the administration
calleridthe campaign's outbound number
activeY or N
ki_enabledY if the campaign is dialled by the AI

getcampaignGET

The settings of one campaign.

Parameters

NameRequiredMeaning
campaignidyesthe campaign number. Spelled in lower case here – other actions spell it campaignID.

Response

{
  "status": "ok",
  "campaign": {
    "name": "Vertrieb Nord",
    "callerid": "4924194580649",
    "active": "Y",
    "ki_enabled": "Y",
    "dial_timeout": "30"
  }
}

If the campaign does not exist, the answer is {"status":"notfound"}. dial_timeout is the time in seconds the dialer lets a call ring.

This action knows further parameters for integrating AI telephony. They belong to the dialer side and are not described here – please ask support if you work on that.

editcampaignGETPOST

Changes a campaign. Only what you send is written.

Parameters

NameMethodMeaning
campaignidGET, requiredthe campaign number
nameGET or POSTnew name
calleridGET or POSTnew outbound number
activeGET or POSTyes switches the campaign on, anything else switches it off
dial_levelGET or POSTthe dial level. It also sets the upper limit for the adaptive level – both receive the same value.

Response

{ "status": "ok" }
{ "status": "notfound" }

This takes effect on live operation immediately. Switching a campaign on means calls are placed, and the dial level determines how many calls run per agent at the same time. Check your values before you send them.

getcampaignlivedataGET

The live figures of a campaign – meant for your own display next to the user interface.

Parameters

NameRequiredMeaning
campaignidyesthe campaign number
campaign_idnothe same number once more. Only this parameter fills the campaign field of the response; without it the field stays empty.

Response

{
  "status": "ok",
  "data": {
    "dial_level": 2.5,
    "available_leads": "18342",
    "calls_today": "4211",
    "average_agents": "12",
    "drops": "38",
    "dropcount": "0.90",
    "dropcount_answers": 3.21,
    "campaign": "3000",
    "extrastats": {
      "calls_hour": "612", "answers_hour": "131",
      "drops_hour": "4", "drops_hour_pct": "0.65",
      "calls_halfhour": "...", "calls_fivemin": "...", "calls_onemin": "..."
    }
  }
}
FieldMeaning
dial_levelthe configured dial level
available_leadshow many leads are currently dialable
calls_todaycalls today
average_agentsagents on average over the last minute
dropsdropped calls today
dropcounttheir share in percent, as the dialer computes it
dropcount_answerstheir share of the answered calls, in percent
extrastatsthe same figures for the last hour, half hour, five minutes and minute

If there are no figures for the campaign yet today, the answer is {"status":"notfound"}. The values come from the dialer's live statistics and are updated once a minute – please do not poll more often.

getcampaignstatsGET

Two evaluations over a time range: the agents' average wait time and the time spent per status.

Parameters

NameRequiredMeaning
typeyesWAITtimeAVG for the average wait time per agent, STATUStime for the total per status. Spelled exactly like that.
campaign_idyesthe campaign number. With an underscore here.
fromdate, todatenothe time range, as a date or a date with time. Without them: since midnight today.
agentchosennoonly these agents, several separated by commas
only_bigger_zeronoyes leaves times of 0 out of the calculation

Response

{ "waittimes": [ { "user": "1098-204", "length_in_sec": "18" },
                 { "user": "1098-207", "length_in_sec": "24" } ] }

{ "statustimes": [ { "Status": "PAUSE", "length_in_sec": "3120" },
                   { "Status": "READY", "length_in_sec": "8400" } ] }

Times are in seconds, sorted ascending.

If the start lies further back than yesterday, at most one day from that start is evaluated – the end is moved forward accordingly. For longer ranges, query day by day.

dncaddGET

Adds one or more numbers to the account's do-not-call list.

Parameters

NameRequiredMeaning
numberyesthe phone number. Several separated by commas.
reasonnoreason for the block. It is recorded with the number and can be seen in the administration later – highly recommended.

Response

FieldMeaning
statusok, doublet (the number was already listed) or error
messageonly with error
numbersthe result per number: a list of number (in the spelling the number was stored in) and status
{
  "status": "ok",
  "numbers": [
    { "number": "24192789880",   "status": "ok" },
    { "number": "4924192789880", "status": "doublet" },
    { "number": "17012345678",   "status": "ok" }
  ]
}

The outer status summarises: ok as soon as at least one number was newly added, doublet when all of them were already listed, and error when a real error occurred. On an error, processing stops at that point; message names the position of the number (counting from 0), and numbers shows what was stored up to then. An already listed number is not an error and does not stop the list.

How the number is stored

Before being stored, the number is reduced to its digits, and leading zeros are dropped: 0241 / 92789880 becomes 24192789880, while 0049 241 92789880 becomes 4924192789880. These are therefore different entries.

So always send numbers in the same form in which your leads are stored – otherwise the number sits in the list without the block taking effect when dialling. dnccheck applies the same conversion and shows you what arrived.

dncdelGET

Removes one or more numbers from the do-not-call list.

Parameters

NameRequiredMeaning
numberyesthe phone number. Several separated by commas.
reasonnoreason for the release, recorded with the number

Response

status is ok or error, with message in the error case. ok means the request was carried out – including when the number was not in the list at all. Use dnccheck to find out whether a number is blocked.

dncgetGET

Returns the whole do-not-call list of the account. No parameters.

Response

Plain text, one number per line, line ending CRLF. Not JSON. The numbers appear as they were stored – see how the number is stored, under dncadd.

24192789880
4924192789880
17012345678
...

dnccheckGET

Looks up a number in the do-not-call list.

Parameters

NameRequiredMeaning
numberyesthe phone number
fuzzynoyes also searches for partial numbers

Response

Without fuzzy:

{ "status": "exists" }      // the number is blocked
{ "status": "notfound" }    // it is not

With fuzzy=yes the action answers without status and lists every match. It searches for the number itself and every shorter form of it down to six digits – that way you also find a blocked area code or a blocked number range:

{ "results": [ "241927", "24192789880" ] }

An empty results list means nothing is blocked.

camp_dncadd, camp_dncdel, camp_dncget, camp_dnccheckGET

Besides the do-not-call list of the whole account there is one per campaign. These four actions work exactly like dncadd, dncdel, dncget and dnccheck – same number, same reason, same fuzzy, same responses. One parameter is added:

NameRequiredMeaning
campaignIDyesthe campaign whose list is meant. Capital ID.
curl -H "Authorization: Bearer <TOKEN>" \
  "https://login.mmdial.de/api/index.php?action=camp_dncadd\
&campaignID=3000&number=024192789880&reason=objection+by+email"

The list only takes effect if the campaign uses it. Whether the campaign's own do-not-call list is checked is a setting of the campaign itself; without it you can add numbers without anything changing when dialling. The account-wide list (dncadd) is independent of that setting.

camp_dncadd does not report the result per number – the numbers field only exists on dncadd. If you send several numbers here, processing stops at one that is already listed.

getleadbyidGET

Reads a lead by its lead number.

Parameters

NameRequiredMeaning
leadidyesthe lead number
getxtratables_fieldsnofields from your extra tables, repeated as an array: getxtratables_fields[]=xtra_table_<table>__<field>. Support can tell you the names.

Response

FieldMeaning
statusfound or notfound
is_archivedtrue if the lead only exists in the archive. Absent otherwise.
lead_datathe lead's data, see below
formdatathe lead's order forms: per form (GUID) the most recently stored state
xtra_tables_dataonly with getxtratables_fields: the requested values, keyed by the requested name

lead_data contains the field names and in addition:

lead_idthe lead number
listidlist the lead belongs to
agentidagent of the last call, empty for a call without an agent
last_contactlast call, in your time zone
called_countnumber of call attempts
{
  "status": "found",
  "lead_data": {
    "lead_id": "45611659",
    "title": "Frau",
    "phone": "4924192789880",
    "alt_phone": "",
    "first_name": "Erika",
    "last_name": "Mustermann",
    "street": "Theaterstr.",
    "streetnr": "70-74",
    "streetadd": "",
    "plz": "52062",
    "ort": "Aachen",
    "country": "DE",
    "notices": "",
    "company_name": "Musterfirma GmbH",
    "rotation": "no",
    "status": "SALE",
    "agentid": "1098-204",
    "listid": "202610181",
    "last_contact": "2026-10-20 11:32:07",
    "called_count": "2",
    "leadid_external": "A-55912"
  },
  "formdata": {
    "41": { "Kundennummer": "A-55912", "Tarif": "Komfort" },
    "42": { "Zaehlernummer": "12345" }
  }
}

Fields that are not set come back as an empty string, not as null. Your own extra fields appear as xtra_<name> inside lead_data.

If the lead is not found in the live database, the action continues in the archive by itself and then sets is_archived.

About formdata. The key is the number of the form (GUID) as getfieldsbycampaign reports it. Per form, only the latest stored state appears there; older states remain in the history and are not included. If the lead has no form, formdata is empty.

getleadbyphonenumberGET

Reads leads by phone number. The same number can appear in several leads, which is why lead_data is a list here.

Parameters

NameRequiredMeaning
numberyesthe phone number. The spelling is converted automatically.
archivenoyes also searches the archive

Response

{
  "status": "found",
  "lead_data": [
    { "lead_id": "45611659", "phone": "4924192789880", "...": "..." },
    { "lead_id": "39811204", "phone": "4924192789880", "...": "...",
      "archived": true }
  ],
  "formdata": [
    { "41": { "Kundennummer": "A-55912", "Tarif": "Komfort" } }
  ]
}

The fields of each entry are the same as with getleadbyid, without called_count. Entries from the archive carry archived: true. If nothing is found, the answer is {"status":"notfound"}.

The form data appears twice. Once with each lead itself, as formdata inside its entry in lead_data – only there can you see which state belongs to which lead. And once, as it always has, as a flat list formdata next to lead_data. If you find several leads, use the value attached to the lead.

getleadbyexternalidGET

Reads leads by your own lead number (leadid_external).

In the old documentation this action was called getleadbypexternalid, with one p too many. The correct name is getleadbyexternalid.

Parameters

NameRequiredMeaning
leadidyesyour own lead number
archivenoyes also searches the archive

Response

As with getleadbyphonenumber: lead_data is a list, because your number can appear in several leads – the API does not require it to be unique.

getleadbyextrafieldGET

Reads leads by one of your extra fields.

Parameters

NameRequiredMeaning
fieldnameyesthe name of the extra field – without the xtra_ prefix
fieldvalueyesthe value to look for. Matching is exact, not partial.
archivenoyes also searches the archive

Response

As with getleadbyphonenumber: status and lead_data as a list.

getleadbycustomdataGET

The search with several criteria at once. Everything you send must match.

Parameters

NameRequiredMeaning
extleadidat least one criterionyour own lead number
numberthe phone number; the spelling is converted automatically
extra_fieldname and extra_fieldvalueone extra field and its value, the name without xtra_
listidone list, or several as an array: listid[]=202610181&listid[]=202610182. Several count as "any one of these".
campaignIDall lists of this campaign
archiveyes also searches the archive

Response

As with getleadbyphonenumber. If you send no criterion at all, the answer is {"status":"noarguments"} – so the action does not accidentally hand out every lead.

curl -H "Authorization: Bearer <TOKEN>" \
  "https://login.mmdial.de/api/index.php?action=getleadbycustomdata\
&campaignID=3000&extra_fieldname=Vertragsnummer&extra_fieldvalue=V-4711"

addlistGET

Creates a new list in a campaign.

Parameters

NameRequiredMeaning
campaignIDyesthe campaign number. Mind the spelling with capital ID.
descriptionyesname of the list

Response

FieldMeaning
statusok or error
listidnumber of the new list (only with ok)
reasonreason for the error (only with error)
{ "status": "ok", "listid": "202610261" }

The new list is switched off. It is created inactive so that dialling does not start while you are still adding leads. You can switch it on in the administration or with editlist. The list number is made up of the date and a counter.

getlistsGET

Lists the lists – all of them, or those of one campaign.

Parameters

NameRequiredMeaning
campaignIDnoonly the lists of this campaign. Without it, all lists of the account.

Response

{
  "lists": [
    { "listid": "202610261", "name": "Import 26.10.",
      "campaignID": "3000", "status": "inactive" }
  ]
}

status is active or inactive: a switched-off list is not dialled.

editlistGETPOST

Changes a list – and switches it on. This is the step after addlist: a newly created list is switched off.

Parameters

NameMethodMeaning
listidGET, requiredthe list number
descriptionGET or POSTnew name of the list
campaignIDGET or POSTmoves the list into another campaign
activeGET or POSTyes switches the list on, anything else switches it off

Response

{ "status": "ok" }
{ "status": "notfound" }
curl -H "Authorization: Bearer <TOKEN>" \
  "https://login.mmdial.de/api/index.php?action=editlist\
&listid=202610261&active=yes"

addleadPOST

Creates a lead – one per call. You switch the checks for duplicates and invalid numbers on yourself.

Parameters

NameRequiredMeaning
campaign_idyesthe campaign number
list_idyesthe list the lead goes into
country_phone_codeyescountry code of the phone number, for example 49. 00 means the number brings its own country code.
leaddatayesthe lead's data as an array: leaddata[first_name], leaddata[phone] and so on. Allowed are the field names without status and rotation, plus your xtra_ fields.
invalidchecknoyes rejects numbers that have been found invalid elsewhere
doubletcheck_globalnoyes rejects the lead if the number already exists anywhere in the account
doubletcheck_campaignnoyes checks within this campaign only. Takes effect only when doubletcheck_global is not yes.
doubletcheck_search_archivednono leaves the archive out of the duplicate check. The default is to include it.
importstatusnostatus of the new lead. Default NEW.
importfilternonumber of an import filter set up in the administration, applied to the lead

Response

{
  "lead_stats": {
    "success": 1,
    "error": 0,
    "sqlerror": 0,
    "formaterror": 0,
    "doubleterror": 0,
    "invaliderror": 0,
    "formaterror_types": []
  },
  "the_new_leadid": "45611660"
}
FieldMeaning
success1 if the lead was created
error1 if it was not. The counters below say why.
sqlerrorwriting to the database failed
formaterrora value has the wrong format; formaterror_types names the field or the kind of error
doubleterrorduplicate, according to the check you selected
invaliderrorthe number is known to be invalid
filtererror, filteredonly with importfilter: the filter did not run, or it rejected the lead
the_new_leadidlead number of the new lead, or false
curl -H "Authorization: Bearer <TOKEN>" \
  -d "campaign_id=3000" -d "list_id=202610261" \
  -d "country_phone_code=49" \
  -d "doubletcheck_campaign=yes" \
  -d "leaddata[company_name]=Musterfirma GmbH" \
  -d "leaddata[first_name]=Erika" \
  -d "leaddata[last_name]=Mustermann" \
  -d "leaddata[phone]=024192789880" \
  -d "leaddata[plz]=52062" \
  -d "leaddata[ort]=Aachen" \
  -d "leaddata[leadid_external]=A-55912" \
  "https://login.mmdial.de/api/index.php?action=addlead"

addlead cannot write order form fields. Create the lead and send the form fields afterwards with editlead.

editleadGETPOST

Changes an existing lead. Only what you send is written; everything else stays as it is.

Parameters

NameMethodMeaning
leadidGET, requiredthe lead number
campaign_idGET, requiredthe campaign number
leaddataPOSTthe fields to change, here including status and rotation. Extra fields as leaddata[extrafields][<name>].
formfieldsPOSTorder form fields, named as formfields[webform_<GUID>_<fieldname>]. The names come from getfieldsbycampaign.
GUIDGETthe form the new state is stored under – required as soon as you send formfields

Either leaddata or formfields must be present, otherwise the action answers with an error.

Response

{ "status": "ok" }
{ "status": "error", "reason": "Fehlende Felder" }

What to keep in mind

curl -H "Authorization: Bearer <TOKEN>" \
  -d "leaddata[status]=SALE" \
  -d "leaddata[notices]=Contract received" \
  -d "formfields[webform_41_Tarif]=Komfort" \
  -d "formfields[webform_41_Kundennummer]=A-55912" \
  "https://login.mmdial.de/api/index.php?action=editlead\
&leadid=45611659&campaign_id=3000&GUID=41"

getcallbacksbyleadidGET

Lists the callbacks of a lead.

Parameters

NameRequiredMeaning
leadidyesthe lead number

Response

{
  "callbacks": [
    {
      "id": "88312",
      "user": "1098-204",
      "global_callback": false,
      "status": "aktiv",
      "created": "2026-10-20 11:35:02",
      "set_time": "2026-10-27 09:00:00",
      "campaign_id": "3000",
      "comments": "Better call in the morning"
    }
  ]
}
FieldMeaning
idnumber of the callback
userthe agent who arranged it
global_callbackfalse if only this agent receives the callback, otherwise true
statusaktiv (active), bearbeitet (handled), tot (dead) or unknown – these values are in German
createdwhen it was arranged
set_timewhen the call is due
commentsthe agent's note

If there is none, callbacks is empty. This action has no status field of its own.

addcallbackGETPOST

Arranges a callback for a lead.

Parameters

NameMethodMeaning
lead_idGET, requiredthe lead number. With an underscore here.
callbackPOST, requiredwhen the call is due: YYYY-MM-DD HH:MM:SS
userPOSTthe agent the callback belongs to
recipientPOSTuser: only the named agent receives the callback. ANYONE: every agent of the campaign. The former value USERONLY still works and means the same as user.
hinweisePOSTthe note for the callback
statusPOSTthe status the lead should get at the time of the callback. Without it, CALLBK.

Response

{ "status": "ok" }
{ "status": "error" }

What happens

curl -H "Authorization: Bearer <TOKEN>" \
  -d "callback=2026-10-27 09:00:00" \
  -d "user=1098-204" \
  -d "recipient=user" \
  -d "hinweise=Better call in the morning" \
  "https://login.mmdial.de/api/index.php?action=addcallback&lead_id=45611659"