Organization Onboarding Guide¶
This guide is for account managers setting up a new organization on AstraPBX. It covers the full onboarding process from creating the org to enabling outbound calling, with the Why, How, and What for each step.
Use GrandEstancia as the reference implementation.
Prerequisites¶
Before starting, ensure you have:
- SSH access to the cloud server (
147.93.168.216) - API access to
https://devpbx.astradial.com/docs(Swagger UI) - Customer's DID number(s) from the SIP trunk provider
- List of users with their names, extensions, and roles
- Department/queue structure (who answers which calls, in what order)
Step 1: Create the Organization¶
Why: Every customer is an isolated tenant. The organization defines the boundary for users, DIDs, routes, queues, and dialplan contexts. All Asterisk configuration is generated per-org.
What: An org gets a unique ID, API key, and context prefix that scopes all its Asterisk resources.
How:
curl -X POST 'https://devpbx.astradial.com/api/v1/orgs' \
-H 'Content-Type: application/json' \
-d '{
"name": "CustomerName",
"plan": "business"
}'
Save the response — you'll need these values for every subsequent step:
| Field | Example | Used For |
|---|---|---|
id | ba50c665-... | All API calls referencing the org |
api_key | org_1938b72... | X-API-Key header for authentication |
context_prefix | org_mnd5khym_ | Asterisk dialplan/PJSIP naming |
Step 2: Create Users¶
Why: Each user gets a PJSIP endpoint (SIP phone registration), an extension number, and optionally an external phone number for call forwarding.
What: Users are the people who answer calls. Each user has:
- Extension — internal number (e.g., 1001)
- Role —
admin,supervisor,agent, oruser - Asterisk endpoint — auto-generated PJSIP config; this name is the SIP username the phone registers with
- Phone number (optional) — external number for forwarding
- Ring target —
ext(SIP phone) orphone(external number)
From the dashboard (recommended)¶
In the editor, Users → Add User now asks for Full Name + Extension only:
- The extension is auto-suggested (lowest free ≥ 1001); edit it if you want. A duplicate shows an error toast.
- The SIP username and password are generated automatically — you don't type them.
- Right after creating, the generated SIP credentials are shown (username + password + QR). You can reopen them any time from the user row's SIP Creds button, and rotate the password there with Regenerate password.
Short, ONT-friendly SIP credentials
New users get a short (< 12 character), alphanumeric SIP username of the form e<ext><random> (e.g. e1001x7k2) and a 10-char alphanumeric password — no hyphens. This is required for some ONT/FXS devices, whose username/password fields reject long values or special characters.
The SIP username is the Asterisk endpoint name (PJSIP matches the REGISTER URI to the AOR). It's globally unique, and the per-org call routing comes from the org's context (<context_prefix>_internal), not from the endpoint name — so the short name is fully multi-tenant-safe.
Existing users keep their original long endpoints (org_<orgid>_<ext>); only users created after this change get short ones. Editing a user's extension no longer rewrites the endpoint — it's a stable SIP identity.
How (API):
Only extension is required. username, email, and password are optional — omit them and the backend auto-generates the short SIP identity (the old behaviour of passing them still works for existing integrations).
curl -X POST 'https://devpbx.astradial.com/api/v1/users' \
-H 'X-API-Key: org_XXXX' \
-H 'Content-Type: application/json' \
-d '{
"extension": "1001",
"full_name": "Hari Kumar",
"role": "admin",
"phone_number": "7400464659"
}'
The response includes the generated sip_password and asterisk_endpoint (the SIP username) — give these to the user for Zoiper/softphone setup.
Helper endpoints:
GET /api/v1/users/next-extension→{ "extension": "1003", "available": true }— the next free extension.GET /api/v1/users/{id}/sip-credentials→{ sip_password, endpoint, extension }— view creds later.POST /api/v1/users/{id}/sip-password/rotate(optional body{ "password": "<1–11 alnum>" }) → regenerates (or sets) the SIP password and redeploys. Returns the new credentials.
Assign Phone Number and Ring Target¶
To route calls to an external phone number instead of the SIP extension:
curl -X PUT 'https://devpbx.astradial.com/api/v1/users/{userId}' \
-H 'X-API-Key: org_XXXX' \
-H 'Content-Type: application/json' \
-d '{
"phone_number": "7400464659",
"ring_target": "phone"
}'
ring_target | Behavior |
|---|---|
ext (default) | Rings the user's SIP endpoint (Zoiper/softphone) |
phone | Dials the external phone_number via the outbound trunk |
Ring Target Requires Outbound Route
ring_target: "phone" uses the org's outbound route to reach the external number. Make sure Step 5 (outbound route) is completed first.
Step 3: Create a SIP Trunk¶
Why: The trunk connects AstraPBX to the PSTN. For Tata NNI trunks, the NUC gateway receives calls on the physical SIP interface and forwards them to the cloud via WireGuard.
What: A trunk defines the PJSIP peer that Asterisk uses to send/receive calls to/from the SIP provider.
How:
curl -X POST 'https://devpbx.astradial.com/api/v1/trunks' \
-H 'X-API-Key: org_XXXX' \
-H 'Content-Type: application/json' \
-d '{
"name": "Tata SIP Trunk",
"host": "10.10.10.2",
"port": 5060,
"transport": "udp",
"trunk_type": "peer2peer",
"max_channels": 10
}'
Tata Trunk via NUC
For Tata NNI trunks, the host is always 10.10.10.2 (NUC WireGuard IP). The NUC handles the physical SIP connection to Tata's SBC and forwards via the tunnel.
Step 4: Assign DID Numbers¶
Why: DID (Direct Inward Dialing) numbers are the public phone numbers customers call. Each DID is routed to a specific destination — an extension, queue (department), or IVR.
What: A DID maps an incoming phone number to a routing destination inside the org.
How:
curl -X POST 'https://devpbx.astradial.com/api/v1/dids' \
-H 'X-API-Key: org_XXXX' \
-H 'Content-Type: application/json' \
-d '{
"number": "08065978002",
"trunk_id": "{trunk_id}",
"description": "Main reception line",
"routing_type": "queue",
"routing_destination": "5001",
"recording_enabled": true
}'
routing_type | routing_destination | Description |
|---|---|---|
extension | 1001 | Direct to a user's extension |
queue | 5001 | Route to a department queue |
ivr | {ivr_id} | Route to an IVR menu |
Step 5: Create Departments (Queues)¶
Why: Departments distribute incoming calls across a team. When a caller reaches the reception queue, it rings team members in sequence until someone answers.
What: A queue defines ring strategy, timeout, and member priority.
How:
curl -X POST 'https://devpbx.astradial.com/api/v1/queues' \
-H 'X-API-Key: org_XXXX' \
-H 'Content-Type: application/json' \
-d '{
"name": "reception",
"number": "5001",
"strategy": "linear",
"timeout": 15,
"retry": 3,
"max_wait_time": 120,
"recording_enabled": true
}'
Add Members to Queue¶
curl -X POST 'https://devpbx.astradial.com/api/v1/queues/{queueId}/members' \
-H 'X-API-Key: org_XXXX' \
-H 'Content-Type: application/json' \
-d '{
"user_id": "{userId}",
"penalty": 0
}'
| Strategy | Behavior |
|---|---|
linear | Rings members in penalty order (0 first, then 1, etc.) |
ringall | Rings all members simultaneously |
roundrobin | Rotates through members |
leastrecent | Rings the member who has been idle longest |
fewestcalls | Rings the member with fewest completed calls |
Penalty = Ring Priority
Lower penalty = rings first. Set penalty 0 for primary agent, 1 for backup, etc.
Step 6: Configure Outbound Route¶
Why: Outbound routes allow users to make external calls from their softphones and enable ring_target: "phone" forwarding. Without an outbound route, no calls can leave the system.
What: An outbound route maps dialed number patterns to a trunk and sets the caller ID for outgoing calls.
How:
curl -X POST 'https://devpbx.astradial.com/api/v1/outbound-routes' \
-H 'X-API-Key: org_XXXX' \
-H 'Content-Type: application/json' \
-d '{
"name": "Tata Outbound",
"trunk_id": "{trunk_id}",
"dial_pattern": "_X.",
"caller_id_override": "08065978002",
"caller_id_name_override": "CustomerName",
"recording_enabled": true,
"priority": 1
}'
Caller ID is Required
caller_id_override must be set to the org's DID number. Without it, the Tata trunk sends anonymous caller ID and returns 403 Forbidden. See Troubleshooting: Tata 403 on Outbound.
Number Format for Tata Trunk¶
| What User Dials | What Reaches NUC | NUC Transforms To | Sent to Tata |
|---|---|---|---|
7400464659 | 7400464659 | 07400464659 | National format |
+917400464659 | 917400464659 | 0917400464659 | Stripped +, prepend 0 |
The cloud outbound context strips + prefix. The NUC prepends 0 for national dialing format and converts caller ID to E.164 (+918065978002).
Step 7: Deploy Configuration¶
Why: All the API changes update the database. To take effect in Asterisk, the configuration must be deployed (generates .conf files) and reloaded.
How:
curl -X POST 'https://devpbx.astradial.com/api/v1/config/deploy' \
-H 'X-API-Key: org_XXXX' \
-H 'Content-Type: application/json' \
-d '{"reload": true}'
This generates three files and reloads Asterisk:
| File | Contains |
|---|---|
pjsip_{orgname}.conf | User endpoints, trunk endpoint, AOR, identify |
ext_{orgname}.conf | Dialplan: internal, incoming, outbound, queue contexts |
queues_{orgname}.conf | Queue definitions and static members |
No Downtime
"reload": true uses core reload which applies changes without dropping active calls.
Step 8: Verify Setup¶
Checklist¶
- Users registered — Check in Zoiper or via API:
GET /api/v1/users - Inbound calls work — Call the DID from an external phone, verify it reaches the queue
- Queue rings correctly — Verify ring order matches penalty assignments
- Outbound calls work — Dial an external number from Zoiper
- Phone forwarding works — Set
ring_target: "phone"and call the user's extension - Recording works — Check
/var/spool/asterisk/monitor/for.wavfiles after a call
Useful API Endpoints¶
# List all users
GET /api/v1/users
# List queues and members
GET /api/v1/queues
# List DIDs
GET /api/v1/dids
# List outbound routes
GET /api/v1/outbound-routes
# Check active calls
GET /api/v1/calls/active
# View call history
GET /api/v1/call-records
Complete Call Flow¶
graph TD
A[External Caller] -->|Dials DID 08065978002| B[Tata PSTN]
B --> C[NUC Gateway<br/>10.54.225.90 NNI]
C -->|WireGuard Tunnel| D[Cloud Asterisk<br/>10.10.10.1]
D --> E{DID Routing}
E -->|routing_type: queue| F[Queue 5001<br/>Reception]
E -->|routing_type: extension| G[Direct to Extension]
E -->|routing_type: ivr| H[IVR Menu]
F --> I{ring_target?}
I -->|ext| J[Ring PJSIP Endpoint<br/>Zoiper/Softphone]
I -->|phone| K[Ring External Phone<br/>via Outbound Route]
K --> L[Cloud Outbound Context]
L -->|CALLERID = DID| M[NUC Gateway]
M -->|0 + number, +91 CID| N[Tata PSTN → Phone] GrandEstancia Reference¶
GrandEstancia was the first org onboarded. Use it as a reference:
| Resource | Value |
|---|---|
| Org ID | ba50c665-7ab4-4f04-a301-eccc395dc42b |
| API Key | <GE_API_KEY> |
| DID | 08065978002 |
| Reception Queue | 5001 (linear, Hari → Surya) |
| AI Bot | ext 1003, AudioSocket + Pipecat |
| Swagger UI | https://devpbx.astradial.com/docs |
See GrandEstancia Setup for the full implementation details.