Ghidul e disponibil deocamdată doar în engleză, ca documentația API.
Getting started
Voice is telephony through an API for sales and support teams, a 2Lines product. The agent clicks the customer’s number in the CRM: the platform rings the agent’s mobile, then the customer, from the company’s landline number. Inbound calls reach the right agent. Your CRM hears about every step through signed webhooks and gets the recording at the end.
This guide takes you from the first key to the first call, then to production. You integrate on staging first, which only calls your test numbers; then you move to production with new keys.
The full reference, with every endpoint, field, error code and event, is the API documentation: staging and production.
How the platform is organised
| Level | Key | What it holds |
|---|---|---|
| Partner (you, if you run a CRM with several customers) | psk_live_… / psk_test_… |
your tenants, their API keys, webhooks and route endpoints (/v1/tenants/…) |
| Tenant (a company: one of your customers) | sk_live_… / sk_test_… |
its agents, lines (phone numbers), queues, webhook, calls and recordings, kept apart from the other companies |
| Agent | none | a person who makes and takes calls: the platform rings the agent’s mobile first, then connects the customer |
Every request carries Authorization: Bearer <key>. Keys are per environment and shown only once, when created:
store them as secrets.
Environments
| Environment | Base URL | Keys |
|---|---|---|
| Staging (sandbox) | https://voice-api-staging.2l.ro |
*_test_* |
| Production | https://voice-api.2l.ro |
*_live_* |
Integrate against staging first. It places real calls, but only to phone numbers on an allowlist kept by us
(send us your test numbers). Each environment serves these docs at /v1/docs and
the schema at /v1/openapi.json. The examples below use staging.
Step 1. Get your partner key
We create your partner organisation and hands over the partner key through a secure channel (never by plain
email). A key can be restricted to a list of client IPs (ask us); without a list it is accepted from any IP, and a
request from an IP outside the list gets 403 IP_NOT_ALLOWED.
Step 2. Check the partner key
curl https://voice-api-staging.2l.ro/v1/tenants -H "Authorization: Bearer $PARTNER_KEY"
# → {"data": [...], "next_cursor": null} your tenants
Step 3. Create a tenant
curl -X POST https://voice-api-staging.2l.ro/v1/tenants \
-H "Authorization: Bearer $PARTNER_KEY" -H "Content-Type: application/json" \
-d '{"name": "Dealer One", "slug": "dealer-one"}'
# → {"tenant_id": "tn_…", …}
The slug is unique on the platform and is sent as tenant in every webhook. We allocate the tenant’s phone
numbers (lines): tell us which tenant needs which numbers.
Step 4. Create the tenant’s API key
curl -X POST https://voice-api-staging.2l.ro/v1/tenants/tn_…/api-keys \
-H "Authorization: Bearer $PARTNER_KEY" -H "Content-Type: application/json" \
-d '{"name": "crm"}'
# → {"key_id": "…", "api_key": "sk_test_…", …} shown only once
A tenant can have two active keys at a time, so you can rotate without downtime: create the new key, deploy it, then
revoke the old one (DELETE /v1/tenants/{tenant_id}/api-keys/{key_id}).
Step 5. Check the tenant key and its configuration
curl https://voice-api-staging.2l.ro/v1/ping -H "Authorization: Bearer $TENANT_KEY" # which tenant
curl https://voice-api-staging.2l.ro/v1/lines -H "Authorization: Bearer $TENANT_KEY" # its phone numbers
curl https://voice-api-staging.2l.ro/v1/queues -H "Authorization: Bearer $TENANT_KEY" # queues for inbound calls
Step 6. Configure the webhook
With the tenant key, or with the partner key on PUT /v1/tenants/{tenant_id}/webhook:
curl -X PUT https://voice-api-staging.2l.ro/v1/webhook \
-H "Authorization: Bearer $TENANT_KEY" -H "Content-Type: application/json" \
-d '{"url": "https://crm.example.com/telephony/events"}'
# → {"secret": "whs_…", …} shown only once
Verify every delivery with the secret (X-Signature, X-Timestamp; see Webhooks in the API documentation). Webhooks come from
several IP addresses that can change: rely on the signature, not on an IP allowlist. Delivery is at least once, so
deduplicate by event_id. Every attempt is listed by GET /v1/webhook-deliveries.
Step 7. Create the agents
curl -X POST https://voice-api-staging.2l.ro/v1/agents \
-H "Authorization: Bearer $TENANT_KEY" -H "Content-Type: application/json" \
-d '{"name": "Andrei Ionescu", "mobile": "+40722123456", "external_ref": "41",
"default_line_id": "ln_…", "queues": ["q_…"], "status": "AVAILABLE"}'
# → {"agent_id": "ag_…", …}
external_ref: your own user id; it comes back in every call and event.mobile: the agent’s Romanian mobile number, rung first (on staging it must be on the allowlist).default_line_id: the number customers see when the agent calls them.queues: the queues whose inbound calls the agent takes.
Change availability with PUT /v1/agents/{agent_id}/status.
Step 8. Make the first call
Always send an Idempotency-Key: a retry after a timeout then never places a second call.
curl -X POST https://voice-api-staging.2l.ro/v1/calls \
-H "Authorization: Bearer $TENANT_KEY" -H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"agent_id": "ag_…", "to": "+40700987654", "external_ref": {"lead_id": 612}}'
# → 201 {"call_id": "c_…", "status": "INITIATED"}
The platform calls the agent’s mobile; when the agent answers (and, if the tenant requires it, confirms with key 1),
it calls the customer on the agent’s line and connects them. You receive call.created, call.agent_answered,
call.answered and call.ended; GET /v1/calls/{call_id} returns the same state at any time, and
GET /v1/calls/{call_id}/timeline shows every event with its delivery attempts.
Step 9. Download the recording
Calls with record (the tenant default) are recorded. After call.recording_ready:
curl -o call.mp3 https://voice-api-staging.2l.ro/v1/calls/c_…/recording -H "Authorization: Bearer $TENANT_KEY"
Keep your own copy: the platform deletes it after the tenant’s retention period (7 days by default). If the
recording cannot be produced you receive call.recording_failed instead (see Recordings in the API documentation).
Step 10. Inbound calls (optional)
When a customer calls one of the tenant’s lines, the platform can ask your endpoint which agent should take the call
(tenant key, or the partner key on PUT /v1/tenants/{tenant_id}/route-config):
curl -X PUT https://voice-api-staging.2l.ro/v1/route-config \
-H "Authorization: Bearer $TENANT_KEY" -H "Content-Type: application/json" \
-d '{"url": "https://crm.example.com/telephony/route"}'
The request comes from 63.189.116.235, is signed with the webhook secret and must be answered within 1.5 s (see Inbound calls in the API documentation). Without it the platform still routes inbound calls: to the last agent who talked to the
caller, then to the queue. Working hours, menus and queues are set up by us: send us, per tenant, the schedule,
the menu options and which agents take which queue.
Step 11. Go live
When the integration works on staging, we hand over the production partner key (psk_live_…) and allocate
the production numbers. Repeat steps 3 to 7 on https://voice-api.2l.ro with your production webhook and route URLs.
When you contact us about a request, quote its X-Request-Id response header.