Reading this thread with interest.. Curiously enough I asked something similar a while back - got a few replies and at the time decided to stick to pure dialplan - but my application was a general purpose PBX type of thing, and I didn't want to use realtime nor an SQL database... ('embedded' system running from RAM), So I have a "core" of dialplan, some hand-crafted macros, contexts, etc. then everything else is machine generated - I have many PHP programs that write the dialplan for me, based on the plain-text config files I keep (I don't read anything in /etc/asterisk, I generate bits of it). Typically, I'll hand-code a new function, then translate it into a config file representation, then PHP code to write the dialplan. This has worked well for me - and is fast enough to use for test systems with a few 100 extensions (although typicall it's in the 20-60 range) - where I re-write a lot of dialplan, then send an 'extensions reload' to the system (1.2.x) No crashes doing this yet! So maybe I'm creating a hybrid sort of system where PHP is my AEL :) I'll give you an example: Create a "call group" via my GUI - which creates an extension and a list of other extensions in that group which are then called at the same time, but each extension has a do not disturb flag which has to be honoured... The line in my "extensions" config file looks like: 222:100,101,102,103,104,109::CG:House Phones::::::::: Which means extension is 222, members are 100, 101, 102,103,104 and 109, it's a Call Group called House Phones.. This generates (gulp - glad I didn't have to type this in!) ; House Phones exten => 222,1,Noop(Call Group House Phones) exten => 222,n,Set(dialString=) exten => 222,n(cg2220),Set(dnd=${DB(100/doNotDisturb)}) exten => 222,n,GotoIf($["${dnd}" != ""]?cg2221) exten => 222,n,Set(dialString=${dialString}&${ext100}) exten => 222,n(cg2221),Set(dnd=${DB(101/doNotDisturb)}) exten => 222,n,GotoIf($["${dnd}" != ""]?cg2222) exten => 222,n,Set(dialString=${dialString}&${ext101}) exten => 222,n(cg2222),Set(dnd=${DB(102/doNotDisturb)}) exten => 222,n,GotoIf($["${dnd}" != ""]?cg2223) exten => 222,n,Set(dialString=${dialString}&${ext102}) exten => 222,n(cg2223),Set(dnd=${DB(103/doNotDisturb)}) exten => 222,n,GotoIf($["${dnd}" != ""]?cg2224) exten => 222,n,Set(dialString=${dialString}&${ext103}) exten => 222,n(cg2224),Set(dnd=${DB(104/doNotDisturb)}) exten => 222,n,GotoIf($["${dnd}" != ""]?cg2225) exten => 222,n,Set(dialString=${dialString}&${ext104}) exten => 222,n(cg2225),Set(dnd=${DB(109/doNotDisturb)}) exten => 222,n,GotoIf($["${dnd}" != ""]?cg2226) exten => 222,n,Set(dialString=${dialString}&${ext109}) exten => 222,n(cg2226),Noop(Calling ${dialString:1}) -- so the above stuff is generated by a PHP loop, and the stuff below was hand coded by me, but then put into the PHP file for it to write out as part of the process. exten => 222,n,Noop(callGroup - Checking ringTone: Currently set to <${ringTone}>) exten => 222,n,GotoIf($["${ringTone}" = ""]?noEntryRingTone) exten => 222,n,Noop(callGroup - ringTone of ${ringTone} already set.) exten => 222,n,Set(_ringTone=${ringTone}) exten => 222,n,SIPAddHeader(Alert-Info: ${ringTone}) exten => 222,n,Goto(doneRingToneCheck) exten => 222,n(noEntryRingTone),Noop(callGroup - No entry ringTone set - checking internal ringTone) exten => 222,n,GotoIf($["${internalRingTone}" = ""]?doneRingToneCheck) exten => 222,n,Noop(callGroup - Internal ringTone of ${ringTone} set.) exten => 222,n,Set(_ringTone=${internalRingTone}) exten => 222,n,SIPAddHeader(Alert-Info: ${ringTone}) exten => 222,n(doneRingToneCheck),Noop(callGroup - end of ringTone check) exten => 222,n,Dial(${dialString:1},,wton) Maybe the last part should be in a macro, but it's funny how things evolve! Gordon