Skip to content

GrandEstancia Setup

This guide documents the GrandEstancia organization setup on AstraPBX, including reception department configuration, DID assignment, and call routing.


Organization Details

Field Value
Org ID ba50c665-7ab4-4f04-a301-eccc395dc42b
Name GrandEstancia
Context Prefix org_mnd5khym_
API Key <GE_API_KEY>

Users

Username Extension Asterisk Endpoint User ID
Hari 1001 org_mnd5khym_1001 <USER_ID>
Surya 1002 org_mnd5khym_1002 bc49cda3-d858-49b8-a2ef-06af2a45c303

Reception Department (Queue)

The reception "department" is implemented as an Asterisk queue with linear ring strategy.

Field Value
Queue ID 4552f60b-cc18-4c47-8bee-2d95b94512d2
Name reception
Number 5001
Strategy linear (rings members in order by penalty)
Timeout 15 seconds per member
Retry 3 seconds between retries
Recording Enabled

Ring Order

With linear strategy and penalty-based ordering:

  1. Hari (ext 1001, penalty 0) — rings first for 15 seconds
  2. Surya (ext 1002, penalty 1) — rings next if Hari doesn't answer

DID Assignment

Field Value
DID Number 08065978002
DID ID 8d7d7db4-9183-4499-a15f-9722fce0e3d0
Trunk Tata SIP Trunk (peer2peer, via NUC WireGuard)
Trunk ID f0182848-d091-4717-bc95-056d0c3c452c
Routing Type queue
Routing Destination 5001 (reception queue)
Recording Enabled

Inbound Call Flow

graph TD
    A[Caller dials 08065978002] --> B[Tata PSTN]
    B --> C[NUC Gateway - SIP over NNI]
    C --> D[WireGuard Tunnel 10.10.10.2 → 10.10.10.1]
    D --> E[Cloud Asterisk]
    E --> F[Match DID in org_mnd5khym__incoming context]
    F --> G[Route to org_mnd5khym__queue context, ext 5001]
    G --> H[Queue: reception - linear strategy]
    H --> I[Ring Hari ext 1001 - 15s timeout]
    I -->|No answer| J[Ring Surya ext 1002 - 15s timeout]
    I -->|Answer| K[Call connected to Hari]
    J -->|Answer| L[Call connected to Surya]
    J -->|No answer| M[Queue timeout - play unavailable message]

API Usage

Authentication

All API calls use the org API key:

-H 'x-api-key: <GE_API_KEY>'

Or use a JWT Bearer token obtained from /api/v1/auth/login.

1. Click-to-Call to Reception Department

Originate a call that rings the from extension first, then connects to the reception queue.

curl -X POST 'https://devpbx.astradial.com/api/v1/calls/click-to-call' \
  -H 'x-api-key: <GE_API_KEY>' \
  -H 'Content-Type: application/json' \
  -d '{
    "from": "1001",
    "to": "5001",
    "to_type": "queue",
    "caller_id": "1001",
    "timeout": 30
  }'

Parameters:

Field Description
from Extension to ring first (the agent initiating)
from_type "extension" (default) or "external"
to Queue number (5001 for reception)
to_type Must be "queue" for department routing
caller_id Caller ID shown to the queue members
timeout Seconds to wait for from to answer

2. Click-to-Call External Number and Connect to Reception

Call an external phone number and when they answer, connect them to the reception queue:

curl -X POST 'https://devpbx.astradial.com/api/v1/calls/click-to-call' \
  -H 'x-api-key: <GE_API_KEY>' \
  -H 'Content-Type: application/json' \
  -d '{
    "from": "+919944421125",
    "from_type": "external",
    "to": "5001",
    "to_type": "queue",
    "caller_id": "08065978002",
    "timeout": 30
  }'

This will:

  1. Dial +919944421125 via the Tata outbound trunk
  2. When they answer, connect them to the reception queue (5001)
  3. Queue rings Hari first (15s), then Surya (15s)

Outbound Calls Working

Outbound calls via the Tata trunk are operational. The caller ID is set to 08065978002 (the org DID) and the NUC converts to E.164 format for Tata.

3. Transfer Active Call to Reception Department

Transfer a live call to the reception queue using the channel ID.

curl -X POST 'https://devpbx.astradial.com/api/v1/calls/{channelId}/transfer' \
  -H 'x-api-key: <GE_API_KEY>' \
  -H 'Content-Type: application/json' \
  -d '{
    "destination": "5001",
    "destination_type": "queue"
  }'

Parameters:

Field Description
destination Queue number (5001 for reception)
destination_type "queue", "extension", or "external"

Getting the Channel ID

To transfer a call, you need the active channel ID. You can get active channels from the call events webhook or by querying active calls.

4. Click-to-Call to Specific Extension

Call a specific user directly (bypassing the queue):

curl -X POST 'https://devpbx.astradial.com/api/v1/calls/click-to-call' \
  -H 'x-api-key: <GE_API_KEY>' \
  -H 'Content-Type: application/json' \
  -d '{
    "from": "1001",
    "to": "1002",
    "to_type": "extension",
    "caller_id": "1001"
  }'

Outbound Calling

Outbound calls from Zoiper and phone number forwarding both route through the Tata trunk via the NUC gateway.

Field Value
Outbound Route Tata Outbound (_X. pattern, priority 1)
Route ID 75a7da13-92d6-40d6-95c0-74ba959162ac
Caller ID 08065978002 (DID number)
Trunk org_mnd5khym_trunk1774876586092 → NUC 10.10.10.2

Outbound Call Flow

graph TD
    A[User dials number<br/>from Zoiper] --> B[Cloud Asterisk<br/>outbound context]
    B --> C[Set CALLERID = 08065978002]
    C --> D[PJSIP Dial via trunk<br/>to NUC 10.10.10.2]
    D --> E[NUC from-cloud context]
    E --> F[Strip leading 0 from CID<br/>Add +91 prefix]
    F --> G[Prepend 0 to dialed number<br/>for national format]
    G --> H[Dial via Tata endpoint<br/>to 10.79.215.102]
    H --> I[Tata PSTN<br/>Call connected]

Number Transformation

Stage Caller ID Dialed Number
User dials 1002 (extension) 7400464659
Cloud outbound 08065978002 (DID override) 7400464659
NUC from-cloud +918065978002 (E.164) 07400464659 (national)

Phone Number Forwarding

Users can have calls forwarded to an external phone number instead of ringing their SIP endpoint.

User Extension Phone Number Ring Target
Hari 1001 7400464659 phone or ext

Configure via API

# Set ring target to phone
curl -X PUT 'https://devpbx.astradial.com/api/v1/users/<USER_ID>' \
  -H 'X-API-Key: <GE_API_KEY>' \
  -H 'Content-Type: application/json' \
  -d '{"ring_target": "phone", "phone_number": "7400464659"}'

# Redeploy config
curl -X POST 'https://devpbx.astradial.com/api/v1/config/deploy' \
  -H 'X-API-Key: <GE_API_KEY>' \
  -H 'Content-Type: application/json' \
  -d '{"reload": true}'

Set ring target back to SIP extension

curl -X PUT 'https://devpbx.astradial.com/api/v1/users/<USER_ID>' \
  -H 'X-API-Key: <GE_API_KEY>' \
  -H 'Content-Type: application/json' \
  -d '{"ring_target": "ext"}'

Bugs Fixed During Setup

DID Queue Routing Not Working (dialplanGenerator.js)

When a DID's routing_type was "queue" and routing_destination was set to the queue number (e.g., "5001"), the dialplan generator only searched by queue ID, causing a mismatch. The generated dialplan would play "number-not-in-service" instead of routing to the queue.

Fix: Updated dialplanGenerator.js to match queues by both ID and number:

// Before
const queue = org.queues.find(q => q.id === did.routing_destination);

// After
const queue = org.queues.find(q => q.id === did.routing_destination || q.number === did.routing_destination);

Same fix applied for IVR routing.

DID E.164 Number Format Mismatch

Tata sends inbound calls with E.164 format (+918065978002) but the DID was stored as 08065978002. The dialplan generator only created patterns for the stored number and + prefix of the stored number — it didn't generate E.164 variants.

Symptom: Cloud Asterisk log showed:

Call (UDP:10.10.10.2:5060) to extension '+918065978002' rejected because extension not found in context 'org_mnd5khym__incoming'

Fix: Updated dialplanGenerator.js generateDidRouting() to also generate E.164 patterns for Indian numbers starting with 0:

// For Indian numbers starting with 0, also match +91 version
// e.g., 08065978002 -> also match +918065978002 and 918065978002
if (cleanNumber.startsWith('0')) {
  const e164Number = `91${cleanNumber.substring(1)}`;
  // Add patterns for e164Number and +e164Number
}

Outbound + Prefix Not Matching Dialplan

Click-to-call with from: "+919944421125" failed because the outbound dialplan pattern _X. only matches digits, not +.

Symptom: Asterisk log showed:

No such extension/context +919944421125@org_mnd5khym__outbound while calling Local channel

Fix: Added a + prefix handler in dialplanGenerator.js generateOutboundContext():

; Strip + prefix and route normally
exten => _+X.,1,Goto(${CONTEXT},${EXTEN:1},1)

Tata Trunk Returns 403 on Outbound Calls (FIXED)

Outbound calls via the Tata trunk returned 403 Forbidden - 6034 from Tata's SBC.

Root cause: Two issues:

  1. No caller ID on outbound routecaller_id_override was null, so Asterisk sent anonymous or the internal extension number. Tata rejects anonymous calls.
  2. NUC double-prefixed caller ID — The NUC's from-cloud context did Set(CALLERID(num)=+91${CALLERID(num)}), turning 08065978002 into +9108065978002 (invalid).

Fix:

  1. Set caller_id_override: "08065978002" on the outbound route via API
  2. Fixed NUC /etc/asterisk/extensions.conf: Set(CALLERID(num)=+91${CALLERID(num):1}) — strips the leading 0 before adding +91

Status: Fixed and working. Outbound calls and phone forwarding both operational.

Codec Translation Error: ulaw to opus (FIXED)

Internal calls and phone forwarding failed with Unable to find a codec translation path: (ulaw) -> (opus).

Root cause: User PJSIP endpoints allowed opus but Asterisk only had res_format_attr_opus.so (format description), not codec_opus.so (actual transcoder). Local channels for outbound routing couldn't bridge opus↔ulaw.

Fix: Removed opus from user endpoint allow list in userProvisioningService.js:

// Before
config += `allow=ulaw,alaw,g722,opus\n`;
// After
config += `allow=ulaw,alaw,g722\n`;
Users must re-register softphones after this change.

Queue Members Showing "Invalid" State (queueService.js)

After fixing DID routing, inbound calls reached the queue but failed with "Unable to join queue" because all members showed (Invalid) status.

Root cause: Two issues in queueService.js:

  1. Wrong member format — Static queue members in queues.conf use the format interface,penalty,membername,state_interface (4 fields). The generator was producing 5 fields with a paused value: PJSIP/endpoint,penalty,paused,"Name",PJSIP/endpoint. Asterisk parsed 0 (paused) as the member name and rejected the rest.

  2. Invalid keyword monitor-join — The queue config included monitor-join=yes which is not a valid Asterisk queue keyword, producing warnings during reload.

Fix:

// Before (wrong - 5 fields with paused)
return `PJSIP/${endpoint},${penalty},${paused},"${memberName}",PJSIP/${endpoint}`;

// After (correct - 4 fields, no paused)
return `PJSIP/${endpoint},${penalty},"${memberName}",PJSIP/${endpoint}`;

Removed monitor-join=yes from recording section (only monitor-format and monitor-type are valid).

Missing linear Queue Strategy in Database

The Queue model defined linear as a valid strategy, but the database ENUM didn't include it. Fixed by altering the column:

ALTER TABLE queues MODIFY COLUMN strategy
  ENUM('ringall','roundrobin','leastrecent','fewestcalls','random','rrmemory','linear')
  NOT NULL DEFAULT 'ringall';

Date

Setup completed: 2026-03-30 Outbound calling & phone forwarding fixed: 2026-03-31