# Hipcall — All Content > Full text of every published article on Hipcall (English). For the list of product pages, see /llms.txt. --- ## Call Centre Service Level: ISO 18295, BDDK, and EPDK URL: https://www.hipcall.com/blog/call-centre-service-level-calculation/ Date: 2026-08-11 Categories: call-center Tags: call-center, customer-service, product-update One month of calls, 3 legitimate service level percentages. Here's what ISO 18295, BDDK, and EPDK each put in the total, when the clock starts, and why. The same month of calls can produce service levels 17 points apart without anyone getting the arithmetic wrong. "The percentage of calls answered within X seconds" sounds like one number, but it hides 2 decisions that nobody writes down: which calls belong in the total, and when the stopwatch starts. That's why our customers ask us how the service level in their call centre software can differ from the figure their regulator expects. It usually isn't a bug. It's a definition. This post walks through both decisions, shows what ISO 18295-1, BDDK, and EPDK each decide, and works a single month of calls through all of them. - [ISO 18295-1](https://www.iso.org/standard/64739.html) - [BDDK](https://www.resmigazete.gov.tr/eskiler/2020/05/20200520-9.htm) - [EPDK](https://www.epdk.gov.tr/Detay/DownloadDocument?id=H9xqfigpDgc=) ## The service level formula everyone agrees on Every published standard defines service level the same way: > Calls answered by an agent within the threshold, divided by calls offered. The disagreements are entirely about the words *offered* and *within*. Get those 2 right and the arithmetic takes care of itself. ## Decision 1: which calls go in the total There are 3 defensible populations, and they produce very different denominators. | Population | What it includes | Who uses it | |---|---|---| | **All inbound calls** | Every call that reached your number, including ones handled entirely in the IVR and ones that hung up in the menu | ISO 18295-1 | | **Calls that entered an agent queue** | Only calls where the caller asked for a person and joined the queue | BDDK, EPDK | | **Only calls an agent answered** | Calls that were picked up | No standard | That third row is the one to watch. It's a common default in call centre reporting, and it flatters the number badly, because a call nobody picked up disappears from the total entirely. Miss every call in a bad hour and your service level for that hour is undefined rather than 0%. It was the old Hipcall default too, which is exactly why we replaced it. ## Decision 2: when the clock starts The threshold is a stopwatch, and the standards disagree about when you press start. - **On arrival**—the moment the call hits the platform. Greeting, menu, and hold music all count against you. - **On queue entry**—after the caller has finished with the [IVR](/feature/interactive-voice-response-ivr/) and joined the queue for a person. Menu navigation doesn't count. - **On platform answer**—when the system picks up, before any human is involved. This isn't a caller-experience measure at all, and no standard uses it. BDDK and EPDK both start at queue entry, and both exclude greeting and IVR time, on the reasoning that a caller browsing a self-service menu isn't waiting for anyone. ISO 18295-1 doesn't fix the clock at all and leaves it to the agreement between the contact centre and its client. In Hipcall, a queue is a **team**, so "entered an agent queue" means the call was placed in a team's queue. ## What each standard actually says | | ISO 18295-1 | BDDK | EPDK | |---|---|---|---| | Applies to | Any customer contact centre | Bank call centres in Türkiye | Electricity distribution and supply companies in Türkiye | | Formula reference | Annex A, metric 4 | MADDE 8(2), `%HS = E / C x 100` | MADDE 6(1)(b), `%SS = F / E x 100` | | Denominator | All interactions offered | Calls transferred to the agent queue | Calls entering the operator queue | | Clock starts | Not fixed by the standard | Queue entry | Queue entry, stated explicitly | | Threshold | Client-defined | 30 seconds, or 20 seconds for lost, stolen, and suspicious transactions | 20 seconds | | Target | Client-defined | At least 80% monthly, at least 90% monthly on the lost or stolen line | Not set by the regulation; contractual | | Reporting period | Agreed intervals, from 15 minutes to annually | Daily, monthly, annually | 15-minute, daily, monthly, annually | Sources: ISO 18295-1:2017 Annex A · BDDK regulation on bank call centre service level and quality, Resmî Gazete 20 May 2020, issue 31132 · EPDK principles for electricity distribution and supply call centre service quality, in force since 1 January 2021. Check the current text of the regulation that applies to you before you report against it. 3 things are worth knowing beyond the headline formula. **Service level is not the only number either regulator wants.** BDDK also requires an answer rate (MADDE 8(1), at least 95% monthly) and an accessibility level measuring line capacity (MADDE 5(2), at least 95% annually), plus a monthly quality score of at least 70 out of 100 built from a random sample of recorded calls. EPDK requires accessibility, service level, answer rate, and a satisfaction rate collected by calling customers back within 2 days of their original call. **BDDK excludes statistical outlier days.** Under MADDE 8(5), any day whose total call volume exceeds the trailing 180-day mean plus 2 standard deviations is dropped from the monthly average. A single viral incident doesn't sink your month. **EPDK requires certification, not just numbers.** MADDE 5(1)(k) obliges electricity companies to document that the call centre operates in line with TS EN ISO 18295-1 and -2, TS EN ISO 9001, TS ISO 10002, and TS EN ISO/IEC 27001, certified by a TÜRKAK-accredited body, with the audited report submitted to EPDK by the end of March each year. ## The same month, 4 different answers Here's a support number with 1,000 inbound calls in a month. - 120 never reached an agent queue—self-served in the IVR, called out of hours, or hung up in the menu. - 880 entered the agent queue. - 800 were answered by an agent. - 80 abandoned while queuing, 35 of them within 5 seconds. Of the 800 answered calls: 660 were picked up within 20 seconds of joining the queue, 720 within 30 seconds, and 700 within 60 seconds of the call first arriving. Same calls, 4 definitions: | Definition | Answered in time | Total | Service level | |---|---|---|---| | ISO 18295-1, 60 s from arrival, all inbound | 700 | 1,000 | **70.0%** | | EPDK, 20 s from queue entry, queued calls | 660 | 880 | **75.0%** | | BDDK, 30 s from queue entry, queued calls | 720 | 880 | **81.8%** | | Old default, 60 s from arrival, answered calls only | 700 | 800 | **87.5%** | Look at the first and last rows. Identical numerator, 17.5 points apart, purely because one keeps the calls nobody answered in the total and the other doesn't. ## The exclusion trap At some point someone will suggest removing short abandons—the caller who joins the queue and hangs up 4 seconds later, before any agent could realistically have reached them. It feels fair. It's also a common way a reported service level quietly stops matching its standard. ISO 18295-1 rules it out in the definition itself: > No exclusions to be factored in such as abandoned contacts under threshold. Neither BDDK nor EPDK defines an exclusion either. In the worked example above, dropping the 35 short abandons moves the ISO figure from 70.0% to 72.5%—small enough to look harmless, large enough to matter when your target is 80%. There are legitimate reasons to do it anyway: a client contract may specifically call for it. Just know that the moment you do, the number you're publishing is your own metric, not an ISO 18295-1, BDDK, or EPDK one. Classifying short abandons is a different thing from excluding them, and it's worth doing. In Hipcall the short abandoned threshold (8 seconds by default) gives those calls their own column in the reports, so you can see how many there were, without touching the denominator. ## Which standard applies to you - **A bank in Türkiye**—BDDK. It isn't a choice. - **An electricity distribution or supply company in Türkiye**—EPDK, along with the certification requirement. - **A BPO or outsourced contact centre**—whatever your client's SLA specifies. ISO 18295-1 is the usual reference frame, and part 2 puts the obligation on the client to agree the service level with the contact centre, taking customer wait tolerance into account. - **Everyone else**—ISO 18295-1, then set your own threshold and target. There's nothing sacred about 20 seconds, 30 seconds, or 80%. What matters is that the definition is written down and stays fixed long enough to mean something. ## How this works in Hipcall Service level is configurable rather than hard-coded, under **Settings → Communication → Phone → General → Call metrics**. Pick a preset—ISO 18295, BDDK, EPDK, or Custom—and it writes the population, the clock, and the threshold together. Choosing BDDK sets calls-that-entered-a-queue, the queue clock, and 30 seconds in one step, so the 3 axes can't drift out of alignment with each other. Custom exposes the same axes individually, with the warnings attached where they belong. Tick "short abandoned calls" under **Remove from the total** and the form tells you ISO 18295 forbids it before you save. 5 details matter for anyone who reports these numbers to a regulator or a client: - **Presets store resolved values, not a label.** Your account keeps the actual axes. If we later refine a preset definition, your historical figures don't move—the page shows you the difference and lets you apply it deliberately. - **Changing the setting never rewrites history.** We record when the definition changed, and a report spanning that date says so. An auditor asking "what was March?" gets the number March was reported with. - **"Within 30 seconds" means a 30-second wait counts.** The threshold you enter is the number your contract or regulator states, and the form shows you the exact comparison it will run. - **Missing data shows as an em dash, never 0%.** If you measure on the queue clock over a range with no queue data, the report says so rather than rendering a catastrophic-looking zero. - **Nothing moved when we shipped this.** Existing accounts were migrated to Custom carrying their previous definition exactly, so no reported figure changed on deploy. New accounts start on ISO 18295. The number report in our [call centre software](/call-center-software/) also splits inbound calls into agent answered, system answered, and never answered—a partition that sums to the total—with the reason each unanswered call was lost. In a typical account, a large share of inbound calls are resolved in the IVR without ever reaching an agent, and that used to look identical to a missed call. Now it doesn't. If you're measuring on queued calls, the report adds a queue answer rate card next to the service level: answered divided by queued, which is what BDDK calls %KO and EPDK calls %CO. Same ratio, 2 names, and both regulators want it alongside the service level. ## 3 rules that survive every standard Whichever definition you land on: 1. **Keep unanswered calls in the total.** A denominator of answered calls can't drag your figure down no matter how badly the day goes, which is precisely the problem. 2. **Don't start the clock when the agent's phone rings.** Measure what the caller experienced, from arrival or from queue entry. 3. **Don't delete the short abandons.** All 3 standards keep them, and the gain from removing them is exactly the amount by which your number stops being comparable. Then write down which definition you use and the date you last changed it. Most service level arguments turn out to be arguments about an undocumented definition, and they end the moment somebody produces the definition. If you're setting this up for the first time, start on the call metrics page, pick the standard that applies to you, and check the preview before you commit—it shows what the last 30 days would have reported under each standard. And if you're still deciding whether you need queue-level measurement at all, [call centre software vs a business phone system](/blog/call-centre-software-vs-business-phone-system/) is the better place to begin. --- ## Agent Status Timeline: every agent's day, at a glance URL: https://www.hipcall.com/blog/agent-status-timeline/ Date: 2026-08-10 Categories: call-center Tags: call-center, product-update, customer-service, productivity The Agent Status Timeline turns raw status logs into a visual chart, so supervisors can see who was on break, busy, or available at any given moment. The agent report already tells you how much time each person spent available, busy, on break, or away, but it can't tell you the shape of that time. Three separate one-hour breaks and a single three-hour break add up to the same total, but they're not the same shift, and if 4 agents were all on break at once during the afternoon rush, a total won't show you that either. **The Agent Status Timeline is a new report that turns those same status logs into a visual timeline you can easily read, move through, and drill into.** Shift disputes, coverage gaps, and QA reviews all turn on the same underlying question, and this report is built to answer it: who was doing what, at a given moment? ## What a total hides An agent's day is really a sequence of blocks: available from 9:00 to 11:30, busy on a call, back to available, away for lunch, and so on. The [call centre software](/call-center-software/) already records every one of those transitions. The Agent Status Timeline's only job is to turn the raw sequence into something you can look at. Two things a total can never show: - **How the time was split.** A break total of 3 hours could be one long block or 6 separate ones—and only one of those is worth a conversation. - **Who overlapped with whom.** 4 agents on break between 14:00 and 14:15 is a coverage gap; the same 4 minutes spread across the day is not. The Agent Status Timeline shows both, because every block on the chart is a real, individual segment of time, not a sum. ## A timeline you can move through, not just read The core of the report is a horizontal chart: one row per agent, coloured blocks for available, busy, break, and away. You can zoom from a full week down to 15-minute detail, drag to pan across the day, and scroll with Ctrl (or ⌘) held down to zoom in on the exact moment you're looking at. A cursor readout tells you, second by second, what everyone's status was at the point you're hovering over. A marker for the current moment separates what has happened from what hasn't. That's useful on a day that's still in progress: a block still running is marked ongoing rather than looking finished. {/* RESIM1 — screenshot of the Agent Status Timeline: one row per agent, coloured status blocks, the scale control and the summary cards visible above it. Source: NOT IN CATALOG — needs a real product screenshot Target path: assets/blog/agent-status-timeline/timeline-overview.webp Suggested alt: "The Agent Status Timeline showing coloured status blocks for each agent" */} ## 5 numbers above the chart Above the timeline, 5 cards summarise the range you're looking at: | Card | What it tells you | |---|---| | **Available now / at cursor** | How many agents are available, out of the whole team | | **Simultaneous break peak** | The most agents on break at the same time, and when | | **Longest single break** | The longest uninterrupted break in the range | | **Longest single busy block** | The longest uninterrupted stretch on a call or task | | **Never available** | Agents who had zero available time in the range | Every card reads from the same segments as the chart. So filtering the timeline down to just "break" and "away" doesn't change what the cards say; deselecting "available" doesn't make it look like nobody was ever available. ## Facts, not verdicts The Agent Status Timeline deliberately doesn't tell you anyone was late. There's no per-agent shift schedule in the product to measure against, so a "late start" flag would have no real threshold behind it. It would just brand whoever happened to log in after some arbitrary time, every single day. "Never available" is a fact; "missed their shift" is a judgement call the report leaves to the supervisor who knows whether that person was on leave that day. The same logic applies to short breaks: there's no minimum-duration filter that quietly drops anything under a few minutes. A 4-minute break can be exactly why a call went unanswered, and hiding it would trade honesty for tidiness. Sort the table by duration instead, and the short ones sort right alongside the long ones. ## Where to find it In the product menu it's currently labelled **Shift View**; that's the name to look for at **Portal → Reports → Shift View**, at `/portal/reports/shift-view/`. You can export the full range to CSV from the same "•••" menu the other reports use. The chart itself is capped at a 7-day view to stay readable, but the export always covers everything you asked for. Times follow your account's own timezone throughout, so "today" and your date filters behave the way you'd expect, whichever timezone your team runs on. If your team is already weighing a phone system against a full [call centre setup](/blog/call-centre-software-vs-business-phone-system/), the Agent Status Timeline offers one more proof the two aren't the same thing: a phone line doesn't know what state an agent was in 5 minutes ago. A [customer service team](/customer-service-software/) running tickets alongside calls gets the same status history either way, since it comes from the same agent status log. Open **Portal → Reports → Shift View** and pick a day your team already talked about (a busy afternoon, a reported gap) and see what the timeline says. --- ## Agent reports now show both call and ticket CSAT scores URL: https://www.hipcall.com/blog/call-and-ticket-csat-in-agent-reports/ Date: 2026-08-10 Categories: call-center, customer-experience Tags: call-center, customer-service, product-update Call CSAT and ticket CSAT now sit beside every other agent metric in your report and CSV export, weighted correctly whether you look at an hour or a month. The agent report already told you how much work each person did. Calls answered, calls missed, talk time, occupancy rate, conversations, messages sent 31 columns of activity. What it never told you is whether the customer on the other end was happy. Your customers were answering that question all along. Callers rate the agent on their keypad after a call ends. Ticket contacts rate the resolution through a link in the closing email. Those scores were sitting on individual call records and individual tickets, one at a time, where no manager was ever going to add them up. **The agent report now has a CSAT column group: rated calls, call CSAT, rated tickets, and ticket CSAT.** ## What the 4 new columns show | Column | What it tells you | |---|---| | **Rated calls** | How many of this agent's calls the caller actually scored | | **Call CSAT** | Average score of those calls, on a 1 to 5 scale | | **Rated tickets** | How many of this agent's tickets the customer scored | | **Ticket CSAT** | Average score of those tickets, on a 1 to 5 scale | The 2 count columns matter as much as the 2 averages. A 5.00 built on 1 rating and a 4.10 built on 90 ratings are not the same fact, and a report that showed only the average would let you mistake one for the other. Read the count first, then the score. When nobody rated anything in the period, the average cell reads `-`, not `0.0`. A zero on a 1 to 5 scale means "the customer thought this was terrible," which is the opposite of "we have no data." The CSV leaves the same cell blank for the same reason. ## Where the 2 scores come from Both numbers come from surveys you switch on yourself. Neither appears until you do. ### Call CSAT: the post-call survey After the conversation ends, the caller is asked to rate it on their keypad, 1 to 5. You configure it per team, under **Settings → Communication → Phone → Teams → CSAT**, and you decide who gets asked: every answered call automatically, or only callers who pressed an activation key while they were waiting in the queue. The survey asks 2 questions one about your company, one about the agent who handled the call. The report's call CSAT column is the agent question. That's deliberate: this is an agent report, and how a caller rates your pricing or your opening hours isn't something the agent who answered can act on. It's also not the same number as the quality score on the call detail record. Quality score is what your supervisor gave the call out of 100 after listening to it. Call CSAT is what the customer gave the agent out of 5. Both are useful, and they don't always agree which is usually the interesting part. ### Ticket CSAT: the link in the closing email When a ticket group has CSAT enabled, the email that closes the ticket carries a rating link. The customer picks 1 to 5, and can add written feedback, which lands on the ticket itself. You configure this under **Settings → Customer Service → Tickets → Groups → CSAT**. The score is credited to the agent the ticket was assigned to, so it lines up with the rest of that agent's row. ## Why the CSAT average survives being zoomed out The report runs at 4 granularities: hourly, daily, weekly, and monthly. CSAT averages are correct at all of them, because the underlying rows store the sum of the scores and the number of ratings, not a pre-computed average. Zooming out adds the sums and adds the counts, then divides once. That distinction shows up the moment 2 hours in the same day have very different volume: | Period | Rated calls | Call CSAT | |---|---|---| | 09:00 | 1 | 5.00 | | 14:00 | 20 | 3.40 | | **The day** | **21** | **3.48** | Averaging the 2 hourly averages would have produced 4.20 and told you the day went well. It didn't. The 20 callers at 14:00 outnumber the 1 caller at 09:00 by 20 to 1, and the daily row says so. ## Ticket ratings land in the hour the customer replied One timing detail worth knowing before you reconcile anything. Ticket CSAT is counted in the hour the customer submitted the score not the hour the ticket closed. The rating link goes out with the closing email and stays valid for 30 days, so a ticket closed on Monday morning and rated on Thursday night appears in Thursday night's row. This is the only bucketing that works. Hourly rows are written once, shortly after the hour ends, and never revisited. Attributing a rating to the ticket's close time would mean writing into a row that was finalised days earlier, and almost every response would be dropped. The practical consequence: in any single row, rated tickets won't match tickets closed. Over a week or a month the gap closes and the number reads normally. ## How to read the CSAT columns together The point of putting CSAT in the agent report rather than on its own page is that it sits on the same row as the rest of the story. - **Read the count before the score.** 3 ratings out of 200 calls is a sample, not a verdict. If rated calls stays low across the whole team, the survey configuration is the thing to look at first, not the agents. - **Check the row, not just the cell.** A dip in call CSAT next to a spike in occupancy rate and longer talk times is more likely a staffing problem than an agent problem. - **Use daily or weekly for coaching, hourly for diagnosis.** Individual hours are noisy at typical rating volumes. Hourly is what you use once you already know something went wrong and want to find the shift it happened on. - **Compare an agent's 2 CSAT columns.** If someone scores well on tickets and poorly on calls, the gap points at live conversation skills rather than at product knowledge. ## Turning the surveys on If the CSAT columns are showing 0 rated calls and 0 rated tickets everywhere, the surveys aren't collecting yet: 1. Enable the post-call survey on each team you want scored, and write both survey questions. 2. Enable ticket CSAT on each ticket group, and write the question customers will see. 3. Give it a few days. Callers respond immediately; ticket customers respond on their own schedule. If the CSAT tab isn't there at all, your plan doesn't include the surveys yet. The [pricing page](/pricing/) shows what each plan carries. CSAT is part of the same set of tools as the queues and agent management in [call centre software](/call-center-software/), and the ticket side belongs to [customer service software](/customer-service-software/). If you're mapping out what else can be measured or automated around a call, the [full feature list](/feature/) is the place to start. ## Availability The 4 CSAT columns are live now in **Reports → Agent**, on per-agent rows and on the **TOTAL** row, at every granularity. The CSV export carries them too, as 4 extra columns and its header row is no longer locked to English, so it follows the interface language of whoever ran the export. One caveat about history: the columns are populated going forward. Hours that were already summarised before this release keep 0 rated calls and 0 rated tickets, so your CSAT trend starts from today rather than from the day you first switched a survey on. --- **Add CSAT to your report →** Settings → Communication → Phone → Teams → CSAT *Not sure which of your teams and ticket groups should be surveyed? Get in touch with our support team and we'll help you work out where the scores will actually be useful.* --- ## API update: stricter validation and clearer 422 errors URL: https://www.hipcall.com/blog/api-stricter-input-validation/ Date: 2026-08-06 Categories: developers Tags: api, hipcall-api, integrations, product-update The Hipcall API now validates every request against its OpenAPI spec. Unknown fields, bad enums and malformed filters return 422 instead of being ignored. If you integrate with the Hipcall API, one thing is changing and it's worth 10 minutes of your attention: **the API now validates every request against its published OpenAPI specification.** Input the server can't process returns `422` instead of being quietly dropped. Most well-formed integrations won't notice. But if your code has been sending a field name with a typo in it, or a filter value the API never understood, you've been getting `200` responses that didn't do what you assumed. Those requests now fail loudly. This post is a map of what changed, so you can check your integration before your users do. ## The problem this fixes Here's the case that prompted the work. Ask for dispositions with a mistyped filter value: ```bash # "success" misspelled as "succes" curl -H "Authorization: Bearer $TOKEN" \ "https://api.hipcall.com/api/v3/dispositions?outcome=succes" ``` The old behaviour: `200 OK`, and **the complete unfiltered list**. The filter wasn't understood, so it wasn't applied, and the response looked exactly like a successful filtered query. If you then counted those rows, or synced them, or showed them to a user, you were working with wrong data and had no way to know. That's worse than an error. An error you handle; a plausible wrong answer you propagate. The same request now returns `422`: ```json { "errors": { "outcome": ["Invalid value for enum"] } } ``` Same error shape you already parse. ## The rule, in one sentence **If the API understood your request but can't process it, you get a `422` naming the field.** It no longer guesses, defaults, or ignores. 6 things follow from that: 1. Unknown fields are rejected rather than skipped. 2. No silent type coercion—except one that's now explicitly documented (see `external_id`). 3. Enum values are validated, never defaulted. 4. A filter that can't be applied fails the request instead of returning everything. 5. Validation happens before any write, so there are no half-applied payloads. 6. Errors name the offending field. ## What now returns 422 ### Unknown query parameters Previously ignored. This is the change with the widest reach, because a typo in a parameter name used to be invisible. ```bash # Was: 200 with every contact. Now: 422. curl -H "Authorization: Bearer $TOKEN" \ "https://api.hipcall.com/api/v3/contacts?life_cycle_i=3" ``` ### Unknown body fields Same rule for writes. A misspelled key used to return `200` having changed nothing at all: ```bash curl -X PATCH \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"first_nam": "Jane"}' \ "https://api.hipcall.com/api/v3/contacts/123" ``` ```json { "errors": { "first_nam": ["Unexpected field: first_nam"] } } ``` A `PATCH` whose body contains **only** unrecognised keys is now a `422` too. "I did nothing" was never a success. ### Pagination on endpoints that never paginated A few endpoints return a small fixed collection and accept no `limit` or `offset`—dispositions, call cards, the contact-centre vocabularies, your profile. They used to accept those parameters and ignore them, which quietly implied you were paging through results you were in fact receiving whole. They now say so with a `422`. ### Filter operators Bracket-notation filters validate their operators against the documented set: ```bash # Valid—unchanged "?started_at[gte]=2026-01-01T00:00:00Z" # Unknown operator: was a silently dropped rule, now 422 "?started_at[invalid]=2026-01-01T00:00:00Z" ``` The wire format hasn't changed. If your filters work today, they keep working. ## Field-level changes worth checking ### `external_id` If you use `external_id` to keep your CRM in lockstep with Hipcall—the pattern in [syncing CRM companies with external_id](/developers/sync-crm-companies-with-external-id/)—read this one carefully. | You send | Before | Now | |---|---|---| | `"CRM-4821"` | stored | stored (unchanged) | | `4821` (integer) | stored as `"4821"` | stored as `"4821"` (unchanged, now documented) | | `null` | clears the field | clears the field (unchanged) | | `""` | silently became `null` | **422** | | `" "` | silently became `null` | **422** | | `["a"]`, `{"k":"v"}`, `true` | silently became `null` | **422** | The integer coercion stays, and is now declared in the schema as `oneOf: [string, integer]`—so `4821` and `"4821"` are the same value. What changed is that meaningless values are rejected instead of turning into `null` behind your back. **To clear the field, send `null`.** An empty string no longer does it. ### `phones` and `emails` on update These were accepted by `POST` and silently discarded by `PATCH`. If you've been sending them in an update expecting them to apply, they never did. ```bash # Now returns 422 naming "phones" curl -X PATCH \ -H "Content-Type: application/json" \ -d '{"first_name":"Jane","phones":[{"number":"+905551112233","country":"TR"}]}' \ "https://api.hipcall.com/api/v3/contacts/123" ``` Use the sub-resources instead: `/contacts/:id/phones` and `/contacts/:id/emails`, and the same pair under `/companies/:id/`. ### Attribution tracking `POST /attribution` used to store `null` for an unrecognised `device` or an unparseable `occurredAt`. Both are now validated—`device` accepts `mobile`, `tablet`, or `desktop`. If your tracker is a fire-and-forget browser beacon that ignores the response, this is the one to check by hand. A beacon won't tell you it started failing. ## Error format The shape is unchanged: an object keyed by field name, exactly what you parse today. ```json { "errors": { "outcome": ["Invalid value for enum"] } } ``` 2 details worth knowing. **Nested fields carry a JSON pointer** in the message, so an array index isn't lost: ```json { "errors": { "phones": ["#/phones/0/number: Missing field: number"] } } ``` **Two endpoints wrap their body in a `data` envelope**—`POST /tasks` and `POST /tasks/:id/comments`. Errors there are keyed under `data`, with the field named in the pointer: ```json { "errors": { "data": ["#/data/name: Missing field: name"] } } ``` If you parse `errors["name"]` on those two endpoints, switch to reading `errors["data"]`. ## Send a JSON content type Write endpoints declare a JSON request body. If your client sends `application/x-www-form-urlencoded` or a multipart body, those requests now return `422`. ``` Content-Type: application/json ``` `application/json; charset=utf-8` is fine. This is the most common reason a previously working integration starts failing, and it's a one-line fix in most HTTP clients. ## What hasn't changed Worth stating plainly, because "stricter validation" makes people nervous about things that are fine: - **Authentication still comes first.** An unauthenticated request returns `401`, not `422`. Validation can't be used to probe which parameters exist. - **Numeric strings still work.** `{"company_id": "123"}` is still accepted where an integer is expected. - **Existing length, format and enum rules are unchanged.** If a 300-character name was rejected before, it's rejected the same way now. - **Valid filter requests are untouched.** Bracket notation, comma-separated `in` lists, pagination—all identical. - **No endpoint changed its URL, its method, or its success response body.** ## A 5-minute checklist 1. **Set `Content-Type: application/json`** on every write request. 2. **Grep your integration for field names** and compare them against the spec at `/api/openapi`. Typos are the number one cause of the new `422`s. 3. **Search for `external_id` assignments** that could produce `""` or a whitespace-only string. Send `null` to clear. 4. **Check any `PATCH` that includes `phones` or `emails`** and move it to the sub-resource endpoint. 5. **Log your `422` rate** for a week after you deploy. A step change points straight at the offending call. The OpenAPI specification at `/api/openapi` is the enforced contract now, not documentation that drifted alongside the code. If the spec and the API disagree, that's a bug and we want to hear about it. The rollout is phased across endpoints, so treat the spec as the source of truth for whichever ones you depend on. Full reference and guides live in the [developer hub](/developers/). If something breaks and the reason isn't obvious from the error body, send us the request and the response—we'll tell you exactly which rule it hit. --- ## Call record sync now supports SFTP URL: https://www.hipcall.com/blog/call-record-sync-now-supports-sftp/ Date: 2026-07-29 Categories: call-center Tags: call-records, sync, sftp, security, product-update Send your call records and recordings to your own server over an encrypted connection for IT teams who've already switched off FTP. Your call records don't only live in Hipcall. Finance wants the call detail records in the data warehouse, compliance wants the recordings on a server they control, and your BI team wants a CSV they can load without touching an API. That's what call record sync is for: it copies your call records and audio recordings out of Hipcall and into storage you own. Until now you could send them to S3 compatible storage, an FTP server, or Google Drive. Customers kept asking for one more option the one their IT teams were most likely to sign off on. **SFTP is now available as a sync destination.** ## Why customers asked for SFTP The requests came from teams who already had an FTP destination working and weren't comfortable with it. Plain FTP sends credentials and files over the network unencrypted. For a directory holding customer call recordings, that's a hard conversation to have with a security reviewer. SFTP solves it at the protocol level: the whole session authentication, file transfer, directory listing runs inside an SSH connection. The reasons we heard: - **Their security policy already ruled out FTP.** Many IT teams disabled plain FTP years ago. SFTP was the only file-transfer option left open on the network. - **The server already existed.** Teams with an on-premise archive, a Linux backup host, or a managed SFTP endpoint didn't want to stand up object storage just for call records. - **Data residency.** Some customers need recordings on a server in a specific country, under their own retention rules, on their own disks. - **One less firewall request.** SFTP runs on port 22 alongside SSH. FTP needs a control port plus a range of data ports, which makes network approvals slower. ## What you get Nothing about the sync itself changes—only where the files land. Each run writes to a dated folder on your server: ``` HipcallBackup/2026/07/29/ ├── call_logs_20260729T031500Z.csv ├── 8f14e45f-ea3d-4c1b-9c3b-a1b2c3d4e5f6.mp3 └── 2c1a7b90-3f8d-4e2a-8b71-9f0e1d2c3b4a.mp3 ``` - **A CSV of your call records.** UUID, direction, caller and callee numbers, start, answer and end times, duration, recording URL, missed-call and billing flags, caller and callee type, and who hung up. Timestamps are written in your account's timezone in RFC 3339 format, so they load into a database or a spreadsheet without conversion work. - **The audio recordings** for every call in that batch, written alongside the CSV. - **Dated folders** year, month, day so a retention script or a scheduled import can find yesterday's batch without any guesswork. You choose how often it runs: - **Daily sync** automatic, covering the last 24 hours. Set it once and stop thinking about it. - **One-time sync** pick a start and end date. Useful for backfilling an archive or handing a specific period to an auditor. ## Setting it up Go to **Settings → Communication → Phone → Call sync**, create a sync job, and choose **SFTP Server (SSH)** as the destination. You'll need four things: | Field | Notes | |-------|-------| | Host | Hostname or IP address of your SFTP server | | Username | The account Hipcall connects as | | Password | Stored encrypted—see below | | Port | Optional. Defaults to 22 | Then pick your sync type—daily or one-time—and save. **We test the connection before we save the job.** Hipcall connects to your server, writes a small test file, and deletes it again. If the host is wrong, the credentials are rejected, or the account can't write to its home directory, you find out right then, with the reason—not three days later when you notice the archive is empty. 2 things worth checking on your side: - The SFTP account needs write permission where the files will land. Hipcall creates the `HipcallBackup/YYYY/MM/DD` folder tree itself, but it can't create what the account isn't allowed to create. - If your server sits behind a firewall that filters inbound connections by source, allow Hipcall to reach it on your SFTP port. ## About your credentials Your destination configuration including the SFTP password is encrypted at rest in our database. One current limitation, stated plainly: **SFTP authentication is password-based.** SSH key authentication isn't supported yet. If key-only access is a requirement in your environment, tell us—customer demand is how this feature got built in the first place. ## Availability SFTP is available now in your call sync settings. Existing S3, FTP, and Google Drive sync jobs keep running exactly as before—nothing to migrate, nothing to reconfigure. If you're currently syncing over plain FTP, switching takes about 2 minutes: create a new sync job pointing at the same server over SFTP, confirm the connection test passes, then deactivate the FTP job. --- **Set up your first SFTP sync →** Settings → Communication → Phone → Call sync *Not sure whether your server is ready for it? Get in touch with our support team and we'll help you work through the configuration.* --- ## 10 Books Every Sales Team Should Read URL: https://www.hipcall.com/blog/books-every-sales-team-should-read/ Date: 2026-04-06 Categories: sales Tags: sales, books, prospecting, negotiation A curated reading list to sharpen your pipeline, master objections, and close more deals — from prospecting to enterprise negotiation. I never imagined during my university years that I would build and manage a sales team. My first encounter with sales came through the management trainee program I attended at BBVA Bank. In 2007, I left the banking sector and stepped into entrepreneurship. Undoubtedly, the most challenging aspect of that journey was building and managing a sales team. There are certainly many books worth recommending, but I think limiting the list to 10 is the right call. These are the books that contributed the most to my growth and that I turned to most often while managing my sales team. I hope they contribute to the development of your sales team as well. In selecting the books, I chose both the foundational reads every good salesperson should know and books about team management and the mathematics of sales. I would especially recommend Aaron Ross and Trish Bertuzzi's books to sales leaders interested in building and managing a team. The other books shed light on different aspects of sales and belong on every sales professional's shelf. ## Predictable Revenue The playbook behind Salesforce's $100M ARR growth. Ross introduces the concept of specialized sales roles (SDRs, AEs, CSMs) and outbound prospecting systems that generate consistent, forecastable pipeline. A must-read for any team trying to build a scalable revenue machine. * **Author**: Aaron Ross & Marylou Tyler * **Category**: Sales Operations * **Link**: goodreads.com ## From Impossible to Inevitable Ross's follow-up explores what separates hyper-growth companies from the rest. The niche-down principle, nail-a-niche strategy, and the concept of "predictable revenue" are explored at a strategic level — ideal for sales leaders thinking beyond individual quota. * **Author**: Aaron Ross, Jason Lemkin * **Category**: Hypergrowth Strategy * **Link**: goodreads.com ## The Challenger Customer The sequel to *The Challenger Sale* shifts focus to the buyer side. In complex enterprise deals, you're rarely selling to one person — and most buying groups are dysfunctional. This book teaches your team how to identify and mobilize the internal champion who can actually get deals done. * **Author**: Brent Adamson, Matthew Dixon et al. * **Category**: Enterprise Sales * **Link**: goodreads.com ## Never Split the Difference An FBI hostage negotiator teaches you everything wrong with classical negotiation — and what actually works. Tactical empathy, mirroring, and calibrated questions will change how your team handles pricing conversations, pushback, and late-stage deal pressure. * **Author**: Chris Voss * **Category**: Negotiation * **Link**: goodreads.com ## HBR's 10 Must Reads on Sales Includes foundational HBR essays on topics like the science of selling, managing a sales force, and aligning sales with marketing. Dense, research-backed, and ideal for sales managers who want to lead with data rather than gut feeling. Great for structured team book clubs. * **Author**: Harvard Business Review * **Category**: Foundational Thinking * **Link**: goodreads.com ## Fanatical Prospecting The brutal truth about why most salespeople fail is simple: they don't prospect enough. Blount's no-nonsense guide covers phone, email, social, and cold outreach — and makes the case that a full pipeline is the only protection against quota-missing anxiety. Required reading before anything else on this list. * **Author**: Jeb Blount * **Category**: Pipeline Building * **Link**: goodreads.com ## Objections Every sales conversation hits friction. This book is a systematic guide to expecting, welcoming, and dismantling objections at every stage of the funnel — from first contact to contract close. Read it alongside *Fanatical Prospecting* for a complete Blount curriculum. * **Author**: Jeb Blount * **Category**: Handling Resistance * **Link**: goodreads.com ## Virtual Selling Written for a world where Zoom is the new boardroom, this book covers video presence, digital body language, asynchronous communication, and how to build rapport through a screen. Even if your team sells in person, the communication principles apply universally. * **Author**: Jeb Blount * **Category**: Remote Sales * **Link**: goodreads.com ## The Challenger Sale Research on 6,000+ salespeople revealed that the best performers don't just build relationships — they teach, tailor, and take control of the conversation. This book will reframe how your team approaches discovery and value delivery, especially in complex B2B deals. * **Author**: Matthew Dixon & Brent Adamson * **Category**: Sales Methodology * **Link**: goodreads.com ## The Sales Development Playbook If you run or are building an inside sales team, this is the operating manual. Bertuzzi covers hiring profiles, sequencing, messaging, metrics, and team structure with a precision that most books at this level lack. Particularly valuable for sales managers scaling a team. * **Author**: Trish Bertuzzi * **Category**: SDR Leadership * **Link**: goodreads.com ## Bonus — Influence Not a sales book per se, but the single most impactful book on human persuasion ever written. Reciprocity, scarcity, social proof, authority, liking, and commitment — these six principles underpin every sales conversation. A timeless bonus read that belongs on every team's shelf. * **Author**: Robert B. Cialdini * **Category**: Persuasion Science * **Link**: goodreads.com Every book on this list shares one insight: the best salespeople are learners first. They study human psychology, build systems around prospecting, and treat objections as invitations rather than walls. If your team reads just three of these this year — start with *Fanatical Prospecting*, *The Challenger Sale*, and *Never Split the Difference*. The pipeline results will follow. --- ## Call Centre Software vs Business Phone System URL: https://www.hipcall.com/blog/call-centre-software-vs-business-phone-system/ Date: 2026-02-25 Categories: tech Tags: call-center, voip Call centre software manages agents and queues. A business phone system connects calls. Learn the key differences and which one your team actually needs. Both call centre software and business phone systems handle voice calls, but they solve fundamentally different problems. A business phone system is the infrastructure — it connects calls, routes them, and manages your numbers. Call centre software is the operational layer — it manages the people who spend their day on those calls. The distinction matters because buying the wrong one means either overpaying for features you won't use or scrambling to bolt on capabilities you desperately need. ## What a Business Phone System Does A [business phone system](/business-phone-system/) replaces the old PBX box in the server room with cloud VoIP. Its core job is straightforward: make and receive calls over the internet, route them to the right person, and handle the basics that every business needs. The feature set centres on connectivity: - **Extensions and ring groups** — assign internal numbers to people and teams so calls reach the right desk. - **IVR menus** — the "press 1 for sales, press 2 for support" flows that direct callers before a human picks up. - **Call forwarding and voicemail** — route unanswered calls to mobiles, other extensions, or voicemail boxes with custom greetings. - **Conference calling** — bring multiple parties into a single call without third-party meeting software. - **Local numbers in 50+ countries** — present a local presence to customers regardless of where your team actually sits. - **Call recording** — capture conversations for compliance, training, or dispute resolution. Who needs one? Any business that makes or receives phone calls. Whether you're a five-person consultancy or a 200-person company, the phone system is the foundation. It doesn't care how many agents you have or how you measure their performance — it just connects calls. ## What Call Centre Software Does [Call centre software](/call-center-software/) assumes you already have a way to make calls. Its job is managing the teams who handle high volumes of them — tracking agent performance, distributing calls efficiently, and giving managers the visibility to keep service levels on target. The feature set centres on workforce management: - **ACD routing** — automatic call distribution sends incoming calls to available agents using rules like skills-based routing, longest-idle, round-robin, or priority queues. - **Call queues** — hold callers in line with estimated wait times, position announcements, and overflow rules when volume spikes. - **Live dashboards and wallboards** — real-time views of queue depth, wait times, agent status, and service levels displayed on screens across the floor. - **Call coaching** — managers can listen to live calls silently, whisper guidance that only the agent hears, or barge into the conversation when needed. - **Disposition codes** — agents tag every call with an outcome (resolved, escalated, callback required) so managers can analyse what's actually happening. - **CSAT surveys** — post-call surveys measure customer satisfaction immediately after each interaction, tied directly to the agent and queue. - **SLA tracking** — measure whether your team is meeting response time and resolution targets, with alerts before you breach. Who needs it? Teams with five or more agents handling significant inbound call volume — support desks, sales floors, booking lines, collections teams. If you have queues to manage and agents to coach, this is the tool that makes that possible. ## Key Differences at a Glance | | Business Phone System | Call Centre Software | |---|---|---| | **Primary focus** | Connecting calls | Managing the people who take calls | | **Routing** | IVR menus, ring groups, time-based rules | ACD queues with skills-based routing | | **Monitoring** | Call logs, CDRs, voicemail | Live dashboards, real-time coaching | | **Key metrics** | Call volume, duration, missed calls | Agent utilisation, CSAT, SLA compliance | | **Typical user** | Any business with a phone | Contact centre teams with 5+ agents | | **Complexity** | Set it and forget it | Actively managed day to day | ## Where They Overlap The line between them isn't always sharp. Both use VoIP infrastructure under the hood. Both can record calls. Both route inbound calls to the right destination. Many phone systems include basic queue functionality, and most call centre platforms include the underlying phone features. The overlap is exactly why the two get confused. A small team of three support agents might get by with a phone system's ring groups and call forwarding for months. The pain only shows up when the team grows — suddenly you need to know why hold times spiked on Tuesday, which agents are handling the most calls, and whether your new hire needs coaching on a specific call type. In practice, teams tend to follow a predictable path: start with a business phone system because you need phones, then add call centre features when queue management and agent performance become real problems. ## Which One Do You Need? The decision comes down to what you're managing: **You need a business phone system if** your team makes and receives calls but you don't have dedicated agents sitting in queues. You want professional call handling — IVR, voicemail, forwarding, local numbers — without the operational overhead of queue management and performance dashboards. **You need call centre software if** you have a team of agents whose primary job is handling call volume. You care about queue wait times, agent utilisation, service levels, and coaching. You need real-time visibility into what's happening on the floor. **You need both if** your business has outgrown basic phone features but you also need the infrastructure they provide. This is the most common scenario for growing teams — you can't run a call centre without a phone system underneath it, and at a certain scale a phone system alone isn't enough. Some platforms treat these as separate products you bolt together. Others, like [Hipcall](/), build both into the same system — the phone infrastructure and the call centre layer share the same backend, the same contact records, and the same reporting. Whether you start with just the phone system or deploy the full call centre from day one, it's one platform and one bill. ## The Bottom Line Start with what you need today. A business phone system handles your calls. Call centre software handles the people who take them. When your team grows past the point where ring groups and voicemail are enough, the call centre layer is what turns a collection of agents into a managed operation. The best time to think about which one you need is before you've signed a contract for the wrong one. --- ## What Is Hipcall? The 7-in-1 Communication Platform URL: https://www.hipcall.com/blog/what-is-hipcall/ Date: 2023-01-13 Categories: tech Tags: hipcall What is Hipcall? It unifies business phone, call centre, SMS, WhatsApp, live chat, CRM, and helpdesk into one platform for sales and support teams. ## What Is Hipcall? So, what is Hipcall? [Hipcall](/) is a cloud communication platform that bundles seven products into a single workspace: business phone system, call centre, SMS, WhatsApp, live chat, sales management, and customer service. One login, one bill, one place where every customer conversation lives. The pitch is simple: most sales and support teams run their operations across half a dozen disconnected tools. A VoIP provider for calls, a separate helpdesk for tickets, a standalone CRM for deals, maybe Slack or WhatsApp for messaging, and a live chat widget bolted on top. Each tool has its own login, its own billing cycle, and its own version of the customer record. When a customer calls about a ticket they raised over chat last week, nobody has the full picture. Hipcall exists to collapse that stack into one platform. Every channel feeds into the same contact record. An agent handling a phone call can see the customer's open tickets, recent chat messages, WhatsApp history, and deal status — all without switching tabs. The company is headquartered in London with an engineering office in Denizli, Turkey. It serves over 3,200 companies across 50+ countries, with local phone numbers available in all of them. ## The Seven Products Now that we've covered what is Hipcall at a high level, let's look at the seven products. They aren't separate tools sharing a logo — they're built on the same backend, share the same contact database, and pass context between each other automatically. ### Business Phone System The [business phone system](/business-phone-system/) is the foundation. It's cloud VoIP — no desk phones or PBX hardware required, though you can connect SIP devices if you want them. Calls run through a WebRTC softphone in the browser or through mobile apps on iOS and Android. The system includes IVR menus (the "press 1 for billing" flows), intelligent call routing, call recording, voicemail with custom greetings, conference calling, ring groups, and business hours rules. You can get local numbers in over 50 countries, so a team in London can present a Berlin number to German customers while a colleague in Istanbul handles calls on a local Turkish line. What separates this from a basic VoIP provider is the routing intelligence. Calls can be routed based on the caller's contact record, their previous interactions, time of day, agent availability, or custom rules you define. A returning customer with an open support ticket can skip the menu entirely and land on the agent already handling their case. ### Call Centre Software The [call centre software](/call-center-software/) adds the operational layer that teams with more than a handful of agents need. Call queues with configurable distribution strategies — round-robin, skills-based, longest-idle, priority-based. Real-time dashboards showing queue depth, wait times, and agent status. A wallboard view for TV screens in the office. For managers, there's call coaching: listen to a live call silently, whisper advice that only the agent hears, or barge in and join the conversation. Quality assurance scorecards let you rate calls against criteria you define. Post-call surveys measure customer satisfaction immediately after each interaction. Outbound teams get a power dialer for campaigns — upload a list, let the system dial, and connect agents only when someone answers. After-call work timers give agents a defined window to wrap up notes before the next call drops in. ### Business SMS The [SMS module](/sms/) handles two-way business texting. Send and receive text messages from your business number, use templates for common replies, and automate messages through workflows. SMS conversations appear in the same inbox as calls and chat, so agents see the full thread regardless of which channel the customer used. ### WhatsApp Business [WhatsApp Business](/whatsapp-business/) integration gives your team a shared inbox for WhatsApp messages. Instead of one person managing the company WhatsApp from their personal phone, conversations are distributed to agents just like calls or chat. You can send text, images, documents, audio, and video. Message templates handle the common responses, and insight cards show customer context alongside every conversation. ### Live Chat The [live chat widget](/live-chat-software/) sits on your website and routes conversations to available agents in real time. Smart routing sends chats to the right team based on the page the visitor is on, their language, or rules you configure. Canned responses speed up replies for frequent questions. Like every other channel in Hipcall, chat conversations become part of the customer's unified history. An agent who picks up a phone call from a customer who chatted yesterday can see exactly what was discussed. ### Sales Management [Sales management](/sales-management-software/) provides pipeline tracking with Kanban boards, deal management with values and stages, and task assignment linked to contacts and deals. Agent performance reports show who's closing and where deals stall. The difference from a standalone CRM is context. When a sales rep opens a deal, they see every call recording, every chat transcript, every SMS, every ticket — not just the notes someone remembered to type into a contact field. The communication history is automatic because it all happens inside the same platform. ### Customer Service The [customer service module](/customer-service-software/) is a ticketing system. Calls, emails, chats, and messages become tickets that can be assigned, prioritised, and tracked against SLAs. A built-in knowledge base lets you create self-service articles so customers can find answers without contacting support. SLA tracking measures response times and resolution times against the targets you set, with escalation rules that trigger when a ticket is about to breach. ## Who Hipcall Is Built For Hipcall is designed for sales and support teams — specifically, businesses where customer conversations happen across multiple channels and nobody wants to manage six different subscriptions to handle them. The sweet spot is teams of 5 to 200 agents. Small enough that an enterprise-grade Avaya or Genesys deployment would be overkill, but large enough that duct-taping together Twilio, Zendesk, HubSpot, and a WhatsApp integration creates real pain. The platform serves 26 industry sectors, from finance and insurance to e-commerce, healthcare, logistics, and education. The common thread isn't the industry — it's the operational pattern: teams that handle significant call volume alongside chat, messaging, and ticket workflows, and want all of it in one place. If your team spends more time switching between tabs than talking to customers, that's exactly what is Hipcall designed to fix. ## What Makes It Different The communication platform market isn't short of options. The question is always: why consolidate into one platform instead of picking the best tool for each job? **Shared context across channels.** When a customer calls, the agent sees their WhatsApp messages, chat history, open tickets, and deal stage. There's no "can you give me your reference number again?" because the system already knows who's calling and what they've been dealing with. This context travels automatically — no integration middleware, no Zapier workflows, no syncing delays. **One set of reports.** Instead of exporting CSVs from five different dashboards and trying to reconcile them in a spreadsheet, Hipcall gives you unified analytics. Call volumes, chat response times, ticket resolution rates, sales pipeline velocity — all in the same reporting suite, all using the same contact records. **Simpler administration.** One user directory. One permission system. One billing invoice. When you onboard a new agent, you create one account and they have access to phone, chat, tickets, and CRM. No per-tool seat management, no SSO configuration across five different SaaS apps. **Lower total cost.** A mid-size support team paying separately for VoIP, helpdesk, live chat, CRM, and WhatsApp tools typically spends more per agent than Hipcall's all-in-one price — before accounting for the integration and admin overhead. The trade-off is specialisation. A dedicated CRM like Salesforce will have deeper customisation. A dedicated helpdesk like Zendesk will have more ticket automation rules. Hipcall isn't trying to out-feature any single category leader. It's betting that for most teams, having everything connected and working together matters more than having the deepest feature set in any one area. ## How Pricing Works Hipcall offers two plans: **Essentials** starts at $29 per user per month. It covers the core phone system — IVR, call routing, recording, voicemail, extensions — plus the communication channels (SMS, WhatsApp, live chat) and basic CRM and ticketing. For teams that need reliable multi-channel communication without the advanced call centre features, this is the entry point. **Professional** is $49 per user per month and adds the operational tools: smart IVR with advanced routing, call coaching (listen, whisper, barge), real-time dashboards and wallboards, quality assurance scorecards, SLA measurement, power dialer campaigns, and the full API with webhooks and integration marketplace. Both plans require a minimum of three users. Annual billing is available. There are no setup fees, no hidden charges, and no per-minute call bundling tricks. The 14-day free trial gives you the full Professional feature set with no credit card required. You can port your existing numbers or start with new ones, invite your team, and run real workflows before committing. For current pricing in your currency, check the [pricing page](/pricing/). ## Getting Started Setting up Hipcall takes about 15 minutes. No hardware to install, no IT department required. 1. **Sign up** for the free trial. No credit card needed. 2. **Choose your numbers.** Pick local numbers in any of the 50+ supported countries, or port your existing numbers. 3. **Invite your team.** Add agents, assign roles and permissions, organise into teams. 4. **Configure your call flow.** Build your IVR menus and routing rules using the visual call flow designer. Set business hours, holiday schedules, and overflow rules. 5. **Turn on your channels.** Enable SMS, connect WhatsApp Business, drop the live chat widget onto your website. 6. **Start taking calls.** Agents can use the browser-based softphone, the desktop app, or the mobile apps for iOS and Android. The learning curve is gentle. If you've used any modern SaaS tool, the interface will feel familiar. For teams migrating from another platform, number porting typically takes a few business days depending on the carrier. ## When Hipcall Isn't the Right Fit No platform is right for everyone. Hipcall probably isn't for you if: **You only need email marketing or marketing automation.** Hipcall handles communication after someone becomes a lead or customer. It's not a Mailchimp or HubSpot Marketing Hub replacement. **You need a CRM with deep customisation.** If your sales process requires hundreds of custom fields, complex workflow automation, or integrations with dozens of vertical-specific tools, a dedicated CRM like Salesforce or HubSpot CRM will serve you better. Hipcall's sales module covers the fundamentals — pipelines, deals, tasks, contact history — but it's built for communication-first teams, not CRM-first organisations. **You're running a 1,000+ seat contact centre that needs on-premise deployment.** Hipcall is cloud-native. It scales well for teams up to a few hundred agents, but if you need on-premise infrastructure, carrier-grade redundancy certifications, or heavily customised integrations with legacy systems, enterprise platforms like Genesys or Avaya are built for that. **You don't handle voice calls.** If your customer communication is entirely email and social media with no phone component, you're paying for a phone system you won't use. A dedicated helpdesk would be more focused. Being honest about where Hipcall fits — and where it doesn't — saves everyone time. In short, what is Hipcall? It's a single place for every customer conversation, with shared context and unified reporting. If that's the problem you're solving, it's worth the 14-day trial to see if it fits. --- ## Sync your CRM companies to Hipcall using external_id URL: https://www.hipcall.com/developers/sync-crm-companies-with-external-id/ Date: 2026-05-09 Tags: api, external-id, crm, companies, sync, integration Use the Hipcall REST API and the external_id field to create, look up, and update companies in lockstep with your own CRM — no mapping table required. ## Overview Most businesses already keep their canonical company records in a CRM or ERP. Pushing those records into Hipcall means your agents, dialers, and reports work against the same data your sales and finance teams trust — without anyone copying rows by hand. This guide shows how to use the Hipcall REST API and the `external_id` field to keep companies in sync. You stamp each Hipcall company with **your** primary key on creation, look it up later by that same key, and update it without ever caching the Hipcall numeric ID. ## How It Works `external_id` is a string field (up to 255 characters) on every company and contact. It belongs to you — Hipcall never generates or interprets it. Three rules to keep in mind: - It must be **unique within your Hipcall account**. Two companies in the same account cannot share an `external_id`. - It is **independent across resources**. The same string can identify a company *and* a contact in the same account. - It is **isolated across accounts**. Different Hipcall accounts can each use the value `"123"` without conflict. With those properties in place, syncing reduces to one repeating decision per record: *does Hipcall already have this `external_id`?* If yes, update. If no, create. > [!WARNING] > We strongly recommend storing Hipcall's numeric ID in your CRM alongside your own key. The `by-external-id` lookup adds a round-trip on every operation. If you cache the Hipcall ID after the first create or lookup, subsequent updates go directly to `PATCH /companies/:id` — faster, simpler, and less load on both sides. Treat `external_id` as a safety net for bootstrapping or recovery, not as your primary handle in a hot path. ### Sync Flow ```mermaid flowchart TD A[Company changed in your CRM] --> B[GET /companies/by-external-id/:crm_id] B --> C{Found?} C -- 404 No --> D[POST /companies with external_id] C -- 200 Yes --> E[PATCH /companies/:hipcall_id] D --> F[Synced] E --> F ``` ## Step 1: Get a Hipcall API Token Sign in to Hipcall and navigate to **Account > Integrations > REST API**. Generate a personal access token and copy it — Hipcall shows it only once. Send the token as a Bearer credential on every request: ```http Authorization: Bearer YOUR_API_TOKEN ``` All endpoints below live under `/api/v3`. ## Step 2: Create a Company With external_id When a new company appears in your CRM, create the matching Hipcall record and stamp it with your CRM's primary key. **Endpoint:** ```http POST /api/v3/companies Authorization: Bearer YOUR_API_TOKEN Content-Type: application/json ``` **Request body:** ```json { "name": "Acme Corp", "external_id": "ERP-9876", "website_url": "https://acme.example.com", "custom_url": "https://crm.yourcompany.com/companies/9876", "emails": [ { "email": "info@acme.example.com", "order": 0 } ], "phones": [ { "country": "GB", "number": "+442045205757", "order": 0 } ] } ``` **Response (201 Created):** ```json { "data": { "id": 42, "name": "Acme Corp", "external_id": "ERP-9876", "website_url": "https://acme.example.com", "custom_url": "https://crm.yourcompany.com/companies/9876", "emails": [ { "email": "info@acme.example.com", "order": 0 } ], "phones": [ { "country": "GB", "number": "+442045205757", "order": 0 } ] } } ``` A few notes on how Hipcall normalizes `external_id`: - Leading and trailing whitespace are trimmed. - An empty string is stored as `null`. - A JSON integer (e.g. `9876`) is coerced to the string `"9876"`. Send whatever shape your CRM emits — Hipcall handles the conversion. ## Step 3: Retrieve a Company by external_id This is the endpoint that makes the whole pattern work. Instead of remembering the Hipcall numeric ID Hipcall returned at creation time, look up the company using *your* identifier. **Endpoint:** ```http GET /api/v3/companies/by-external-id/ERP-9876 Authorization: Bearer YOUR_API_TOKEN ``` **Response (200 OK):** ```json { "data": { "id": 42, "name": "Acme Corp", "external_id": "ERP-9876", "website_url": "https://acme.example.com", "custom_url": "https://crm.yourcompany.com/companies/9876", "emails": [...], "phones": [...] } } ``` **Response (404 Not Found)** — no company in your account matches that `external_id`: ```json { "errors": { "detail": "Not Found" } } ``` In a sync workflow that 404 is *not* an error — it's the signal to create. See **Putting it together** below. ## Step 4: Update a Company Once you've found the company in Step 3, update it by its Hipcall numeric ID. PATCH only the fields you want to change. ```http PATCH /api/v3/companies/42 Authorization: Bearer YOUR_API_TOKEN Content-Type: application/json ``` ```json { "website_url": "https://new.acme.example.com" } ``` You can also change the `external_id` itself — for example when the upstream CRM re-keys a record: ```json { "external_id": "ERP-9999" } ``` Or clear it entirely by sending `null`: ```json { "external_id": null } ``` ## Putting It Together: An Idempotent Sync Loop Here is the loop a sync job runs for every changed company in your CRM: ```text for each company in your_crm: response = GET /api/v3/companies/by-external-id/{crm_id} if response.status == 404: POST /api/v3/companies { external_id: crm_id, ...fields } else if response.status == 200: PATCH /api/v3/companies/{response.data.id} { ...changed_fields } ``` **Race-condition fallback (422 Unprocessable Entity).** If two sync jobs run at the same moment, both can see 404 for the same `external_id` and both can call POST. The second POST returns: ```json { "errors": { "external_id": ["has already been taken"] } } ``` Treat any 422 with an `external_id` error as a signal to retry the lookup-then-PATCH path. The combined flow — lookup, create-or-update, fall back to update on duplicate — is fully idempotent. You can replay the sync any number of times safely. ## A Note About Contacts The same pattern works for contacts. `POST /api/v3/contacts` accepts `external_id`, and `GET /api/v3/contacts/by-external-id/:external_id` returns the contact. The company and contact `external_id` namespaces are independent within an account, so the same string can identify both a company and a contact without conflict. ## Tools Used | Tool | Purpose | |---|---| | **REST API** | All requests use the v3 REST API with a Bearer token | | **`external_id` field** | Carries your CRM's primary key on the Hipcall company record | | **Lookup-by-external-id endpoint** | `GET /api/v3/companies/by-external-id/:external_id` removes the need for a side mapping table | ## Next Steps - [REST API documentation](https://use.hipcall.com/api-docs/) — full schema for companies, contacts, and all available endpoints - [Webhooks](#) — subscribe to company change events for the reverse direction (Hipcall → your CRM) --- ## Authenticate Callers with PIN Verification URL: https://www.hipcall.com/developers/pin-authentication-with-external-management/ Date: 2026-04-03 Tags: external-management, ivr, authentication, security Learn how to authenticate callers by phone number and PIN, then route them to different extensions based on the result. ## Overview Some calls need more than just routing — they need identity verification. A caller's phone number alone isn't always enough: the same SIM card may be used by multiple people, or you need to confirm the caller is who they claim to be. This guide shows how to use **External Management** to build a PIN-based authentication IVR. When a call arrives, Hipcall prompts the caller to enter a personal PIN. Your server verifies it against the caller's phone number and tells Hipcall where to route the call — to the customer support team on success, or to sales if the PIN does not match. ## How It Works Hipcall sends each step of the call to your server as a JSON sequence. On the first request (no PIN entered yet), your server responds with a `gather` action to collect digits. On the second request (PIN provided), your server validates it and responds with `play` and `connect` actions. ### Architecture ```mermaid flowchart TD A[Caller dials in] --> B[External Management POSTs to your server] B --> C[Server returns gather action] C --> D[Caller enters 1-4 digit PIN] D --> E[External Management POSTs again with PIN] E --> F{Phone found AND PIN correct?} F -- Yes --> G[Play success audio\nConnect to ext 1091] F -- No --> H[Play failure audio\nConnect to ext 1092] ``` ## Step 1: Configure External Management in Hipcall 1. Go to **Settings > Developer > External Managements** in your Hipcall dashboard. 2. Create a new External Management entry with: | Field | Value | |---|---| | **Name** | PIN Authentication | | **Target URL** | `https://your-server.example.com/api/external/hipcall-ingress` | 3. Attach this External Management to the desired IVR step or call flow in your Hipcall account. > **Local development:** Use [ngrok](https://ngrok.com/) to expose your local server. Run `ngrok http 5000` and use the generated URL as the Target URL. ## Step 2: Handle the Initial Request When a call first hits your External Management endpoint, Hipcall sends a POST with the caller's phone number but no PIN yet: ```json { "caller": "+905060508169", "data": {} } ``` Respond with a `gather` action to prompt the caller for their PIN: ```python @app.route('/api/external/hipcall-ingress', methods=['POST']) def hipcall_ingress(): data = request.json caller = data.get('caller') gather_data = data.get('data', {}) if 'pin_code' not in gather_data: return jsonify({ "version": "1", "seq": [ { "action": "gather", "args": { "min_digits": 1, "max_digits": 4, "ask": "https://your-server.example.com/static/audio/pin_prompt.mp3", "variable_name": "pin_code" } } ] }) ``` The `ask` field is an MP3 URL played to the caller (e.g. *"Please enter your PIN."*). Hipcall collects between `min_digits` and `max_digits` key presses and stores them under `variable_name`. ## Step 3: Verify the PIN and Route the Call After the caller enters their PIN, Hipcall sends a second POST with the collected digits: ```json { "caller": "+905060508169", "data": { "pin_code": "1234" } } ``` Look up the caller in your database and compare PINs. Normalize the phone number before querying — Hipcall may send it with a country prefix: ```python def normalize_phone(phone): if not phone: return phone phone = phone.strip() if phone.startswith('+90'): phone = phone[3:] elif phone.startswith('90') and len(phone) == 12: phone = phone[2:] elif phone.startswith('0') and len(phone) == 11: phone = phone[1:] return phone ``` Then verify the PIN and respond with the appropriate routing: ```python # Continuing hipcall_ingress() from Step 2 ... normalized_caller = normalize_phone(caller) user = db.execute( 'SELECT * FROM users WHERE phone = ?', (normalized_caller,) ).fetchone() entered_pin = gather_data.get('pin_code') if user and entered_pin == user['pin_code']: return jsonify({ "version": "1", "seq": [ { "action": "play", "args": { "url": "https://your-server.example.com/static/audio/success.mp3" } }, { "action": "connect", "args": {"destination": "1091"} } ] }) else: return jsonify({ "version": "1", "seq": [ { "action": "play", "args": { "url": "https://your-server.example.com/static/audio/failure.mp3" } }, { "action": "connect", "args": {"destination": "1092"} } ] }) ``` **On success:** Hipcall plays the success audio and connects the caller to extension `1091` (customer support). **On failure:** Hipcall plays the failure audio and connects the caller to extension `1092` (sales team), where an agent can assist further. ## Step 4: Log Requests for Debugging During development, log every incoming request and outgoing response so you can trace PIN verification in real time: ```python @app.after_request def log_request_response(response): if request.path == '/api/external/hipcall-ingress': req_body = request.get_data(as_text=True) res_body = response.get_data(as_text=True) db.execute( "INSERT INTO logs (method, path, request_body, response_body) VALUES (?, ?, ?, ?)", (request.method, request.path, req_body, res_body) ) db.commit() return response ``` ## Tools Used | Tool | Purpose | |---|---| | **External Management** | Drives the two-step IVR sequence — collect PIN, then route the call | ## Next Steps - [External Management documentation](#) — Learn the full action sequence reference (`gather`, `play`, `connect`, `hangup`) - [Webhooks documentation](#) — Combine with `call_hangup` events to audit authentication attempts - [REST API authentication](#) — Secure your endpoint with Basic Auth or API key verification --- ## Place Calls by Order Number Without Seeing the Customer's Phone Number URL: https://www.hipcall.com/developers/call-via-order-number/ Date: 2026-04-02 Tags: speed-dial, privacy, crm Learn how to let couriers call customers using only an order code, without ever accessing their phone number. ## Overview In delivery and logistics, a courier often needs to call a customer — but sharing customer phone numbers with field staff raises privacy and data protection concerns. The customer's number should never leave your system. This guide shows how to use **Speed Dial** with a webservice lookup to bridge calls using only an order number. The courier dials a short extension, enters the order code, and Hipcall connects them to the customer automatically — without the courier ever seeing the phone number. ## How It Works The courier dials a Speed Dial extension and enters the order number when prompted. Hipcall sends the digits to your server, which looks up the customer's phone number and returns it. Hipcall places the call on behalf of the courier — the number stays hidden end to end. ### Architecture ```mermaid flowchart TD A[Courier dials Speed Dial ext. 72] --> B[Hipcall prompts for order number] B --> C[Courier enters digits e.g. 1234] C --> D[Hipcall POSTs digits to your server] D --> E{Order found?} E -- Yes --> F[Return customer phone number] E -- No --> G[Return error] F --> H[Hipcall bridges the call\ncourier ↔ customer] ``` ## Step 1: Configure Speed Dial in Hipcall 1. Go to **Account > Integrations > Speed Dial** in your Hipcall dashboard. 2. Create a new Speed Dial entry with the following settings: | Field | Value | |---|---| | **Extension** | `72` (or any free extension) | | **Announcement** | "Please enter the order number." | | **Webservice URL** | `https://your-server.example.com/lookup` | > **Local development:** Use [ngrok](https://ngrok.com/) to expose your local server. Run `ngrok http 5010` and use the generated URL. ## Step 2: Receive the Lookup Request When the courier finishes entering digits, Hipcall POSTs the following payload to your endpoint: ```json { "number": "1234", "user_id": 3508, "uuid": "06787f4b-4873-433b-a000-8fd99ff24ccf", "speed_dial_id": 5, "timestamp": 1774611216 } ``` The `number` field contains the DTMF digits the courier entered — this is your order code. The other fields (`user_id`, `speed_dial_id`) identify which agent and Speed Dial rule triggered the request. ## Step 3: Look Up the Order and Return the Destination Query your database using the order code. If found, respond with the customer's phone number in the `destination` field. Hipcall immediately bridges the call to that number. ```python @app.route('/lookup', methods=['POST']) def lookup(): data = request.get_json() code = str(data.get('number', '')).strip() row = db.execute( 'SELECT phone FROM orders WHERE order_code = ?', (code,) ).fetchone() if row: return jsonify({"destination": row['phone']}), 200 else: return jsonify({"error": "Order not found"}), 404 ``` **Successful response:** ```json { "destination": "905060508169" } ``` Return the phone number in E.164 format (digits only, no `+` prefix). Hipcall dials this number and connects it to the courier's active call. **Not found response:** ```json { "error": "Order not found" } ``` If the order code does not exist, Hipcall plays an error message to the courier. ## Tools Used | Tool | Purpose | |---|---| | **Speed Dial** | Prompts the courier for digits and calls your lookup endpoint | ## Next Steps - [Speed Dial documentation](#) — Configure extensions, announcements, and webservice integration - [REST API authentication](#) — Secure your lookup endpoint with API keys or Basic Auth - [Webhooks documentation](#) — Combine with `call_hangup` events to log which orders were called --- ## Route Incoming Calls Automatically Based on CRM Data URL: https://www.hipcall.com/developers/route-calls-with-smart-ivrs/ Date: 2026-04-02 Tags: smart-ivrs, crm, ivr, webhooks Learn how to look up callers in your CRM and route them to the right team automatically, before the call is even answered. ## Overview Not every caller deserves the same experience. Registered customers should reach your support team immediately; unknown numbers should go to a general queue. Manually maintaining routing rules in the phone system does not scale — and it breaks the moment your CRM data changes. This guide shows how to use **Web Service-Based Smart IVRs** to query your CRM in real time and return a routing decision before the call is even answered. ## How It Works When a call arrives, Hipcall's Smart IVRs feature calls your HTTP endpoint with the caller's phone number. Your server looks up the number in your CRM and responds with an extension number. Hipcall routes the call accordingly — all in milliseconds, before the caller hears a single ring. ### Architecture ```mermaid flowchart TD A[Incoming call] --> B[Hipcall Smart IVRs fires] B --> C[POST to your endpoint\nwith caller number] C --> D{Found in CRM?} D -- Yes --> E[Return VIP extension\ne.g. 1093] D -- No --> F[Return general extension\ne.g. 1094] E --> G[Call routed to VIP queue] F --> H[Call routed to general queue] ``` ## Step 1: Configure Smart IVRs in Hipcall 1. Go to **Settings > Phone System > Smart IVRs** in your Hipcall dashboard. 2. Click **New** and choose **Webservice** as the route type. 3. Enter your endpoint URL (e.g. `https://your-server.example.com/api/smart-ivr`). 4. Save the rule and assign it to the phone number or IVR menu you want to control. > **Local development:** Use [ngrok](https://ngrok.com/) to expose your local server. Run `ngrok http 5008` and use the generated URL as your endpoint. ## Step 2: Receive the Webhook Hipcall sends a `POST` request to your endpoint with the caller's phone number as soon as the call arrives. **Example request from Hipcall:** ```json { "caller": "+442045205757" } ``` The `caller` field contains the caller's phone number in E.164 format. Your endpoint must respond within the timeout window — keep the CRM lookup fast. ## Step 3: Look Up the Caller Normalize the phone number to match your database format, then query your CRM. **Example normalization (Python):** ```python def normalize_phone(phone): # Strip non-numeric characters phone = ''.join(filter(str.isdigit, phone)) # Handle Turkish local formats if phone.startswith('0') and len(phone) == 11: phone = '9' + phone elif len(phone) == 10: phone = '90' + phone return phone ``` Query your database using the normalized number: ```python caller = data.get('caller') normalized = normalize_phone(caller) customer = db.execute( 'SELECT id FROM customers WHERE phone = ?', (normalized,) ).fetchone() ``` ## Step 4: Return the Routing Decision Respond with a JSON object containing the `extension` to route the call to. Use one extension for known customers, another for unknown callers. **Registered customer:** ```json { "extension": "1093" } ``` **Unknown caller:** ```json { "extension": "1094" } ``` Hipcall reads the `extension` value and transfers the call to that extension immediately. The caller never experiences a delay. ## Tools Used | Tool | Purpose | |---|---| | **Web Service-Based Smart IVRs** | Triggers your endpoint on incoming calls and routes based on the response | ## Next Steps - [Smart IVRs documentation](#) — Configure route types, timeouts, and fallback behavior - [REST API authentication](#) — Secure your endpoint with API keys or Basic Auth - [Webhooks documentation](#) — Combine with call events for post-call logging and analytics --- ## Show Caller Name, Company, and Balance on the Insight Card URL: https://www.hipcall.com/developers/show-caller-info-on-insight-card/ Date: 2026-04-02 Tags: insight-card, webhooks, crm, erp Display caller name, company, and balance on the agent's screen the moment a call connects, using Webhooks and the Insight Card API. ## Overview When an agent answers a call, every second counts. Instead of searching through a CRM to find out who is calling, the agent should see the caller's name, company, and account balance automatically — before they even say hello. This guide shows how to combine **Webhooks** and the **Insight Card API** to display real-time caller data on the agent screen the moment a call connects. ## How It Works The integration uses two Hipcall developer tools: 1. **Webhooks** — Hipcall sends a `call_init` event to your server when a call starts. 2. **Insight Card API** — Your server looks up the caller and pushes a card to Hipcall, which displays it on the agent's screen. ### Architecture ```mermaid flowchart TD A[Incoming call] --> B[Hipcall sends call_init webhook] B --> C[Your server receives event] C --> D{Match found\nin CRM/ERP?} D -- Yes --> E[POST to Insight Card API] D -- No --> F[Skip] E --> G[Agent sees caller info on screen] ``` ## Step 1: Receive the Webhook Subscribe to the `call_init` event in **Account > Integrations > Webhooks**. Hipcall will POST a JSON payload to your endpoint when every call starts — both inbound and outbound. **Example webhook payload:** ```json { "event": "call_init", "data": { "uuid": "call_abc123", "direction": "inbound", "caller_number": "+442045205757", "callee_number": "+441234567890", "callee_extension_id": 1042 } } ``` Extract `data.uuid` (the call ID) and the customer's phone number: - **Inbound call** → customer is `data.caller_number` - **Outbound call** → customer is `data.callee_number` ## Step 2: Look Up Caller Data in Your CRM or ERP Use the customer's phone number to query your data source — a database, CRM API, or ERP system. **Example response from your CRM:** ```json { "full_name": "Jane Smith", "company": "Acme Corp", "balance": "4250.00" } ``` If no match is found, you can skip the Insight Card call entirely or push a minimal fallback card. ## Step 3: Push the Card to the Insight Card API Call the Insight Card API with the `call_id` from the webhook to associate the card with the right call. **Endpoint:** ```http POST /api/v3/calls/{call_id}/cards Authorization: Bearer YOUR_API_TOKEN Content-Type: application/json ``` **Request body:** ```json { "card": [ { "type": "title", "text": "Hipcall Insight", "link": "https://www.hipcall.com" }, { "type": "shortText", "label": "Name", "text": "Jane Smith" }, { "type": "shortText", "label": "Company", "text": "Acme Corp" }, { "type": "shortText", "label": "Balance", "text": "$4,250.00" } ] } ``` The card appears on the agent's Webphone within milliseconds of the call starting. ## Tools Used | Tool | Purpose | |---|---| | **Webhooks** | Receive `call_init` event when a call starts | | **Insight Card API** | Push caller data card to the agent's screen | ## Next Steps - [Webhooks documentation](#) — Subscribe to events, configure retry logic, verify signatures - [Insight Card API reference](#) — Full list of card types, formatting options, and limits - [REST API authentication](#) — Set up API keys or OAuth 2.0 for your server --- ## Store Call Records and Recordings in Your Own System Using Webhooks URL: https://www.hipcall.com/developers/store-call-records-with-webhooks/ Date: 2026-04-02 Tags: webhooks, cdr, call-recording Learn how to store call records and automatically download recordings into your own system the moment a call ends. ## Overview Hipcall keeps call detail records accessible through the dashboard and REST API, but many teams need to push that data into their own systems — a data warehouse, compliance archive, CRM, or custom analytics dashboard. Doing it in real time, the moment a call ends, is exactly what the `call_hangup` webhook is designed for. This guide shows how to receive the `call_hangup` event, store the call record in your own database, and automatically download the call recording before the pre-signed URL expires. ## How It Works When a call ends, Hipcall sends a `call_hangup` webhook to your endpoint. Your server parses the payload, inserts the call record into a database, and — if a recording URL is present — downloads the audio file in the background before the pre-signed URL expires. ### Architecture ```mermaid flowchart TD A[Call ends] --> B[Hipcall fires call_hangup webhook] B --> C[Your server receives payload] C --> D[Store CDR in database] D --> E{record_url\npresent?} E -- Yes --> F[Download recording\nin background] E -- No --> G[Done] F --> H[Save MP3 locally\nupdate record path] ``` ## Step 1: Create the Webhook in Hipcall 1. Go to **Account > Integrations** in your Hipcall dashboard. 2. Click **Create New Integration** and choose **Webhook**. 3. Configure the webhook: | Field | Value | |---|---| | **Target URL** | `https://your-server.example.com/webhook/hipcall-cdr` | | **Events** | `Call Hangup` (`call_hangup`) | | **Method** | `POST` | > **Local development:** Use [ngrok](https://ngrok.com/) to expose your local server. Run `ngrok http 5007` and use the generated URL as your target. ## Step 2: Receive the Webhook Hipcall POSTs a JSON payload to your endpoint every time a call ends. **Example payload:** ```json { "event": "call_hangup", "data": { "uuid": "call_abc123", "caller_number": "+442045205757", "callee_number": "+441234567890", "direction": "inbound", "call_duration": 45, "started_at": "2026-04-02T10:00:00Z", "ended_at": "2026-04-02T10:00:45Z", "record_url": "https://storage.example.com/recordings/call_abc123.mp3?token=...", "hangup_by": "callee" } } ``` Key fields: | Field | Description | |---|---| | `uuid` | Unique call identifier — use this to deduplicate | | `caller_number` / `callee_number` | Parties on the call | | `direction` | `inbound` or `outbound` | | `call_duration` | Duration in seconds | | `record_url` | Pre-signed URL to the MP3 recording — expires after a short time | | `hangup_by` | Who ended the call (`caller`, `callee`, or `system`) | Respond with `HTTP 200` quickly — move any heavy processing to the background. ## Step 3: Store the CDR Always filter on `event === "call_hangup"` — your endpoint may receive other events in the future. Use `uuid` as the primary key to prevent duplicate records if the webhook is retried. ```python @app.route('/webhook/hipcall-cdr', methods=['POST']) def receive_cdr(): payload = request.json if payload.get('event') != 'call_hangup': return jsonify({"status": "ignored"}), 200 data = payload.get('data', {}) uuid = data.get('uuid') # Deduplicate — Hipcall may retry on timeout if db.execute('SELECT 1 FROM cdrs WHERE uuid = ?', (uuid,)).fetchone(): return jsonify({"status": "exists"}), 200 db.execute(''' INSERT INTO cdrs (uuid, caller_number, callee_number, direction, duration, started_at, ended_at, record_url, hangup_by) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) ''', ( uuid, data.get('caller_number'), data.get('callee_number'), data.get('direction'), data.get('call_duration'), data.get('started_at'), data.get('ended_at'), data.get('record_url'), data.get('hangup_by'), )) db.commit() return jsonify({"status": "success"}), 201 ``` ## Step 4: Download the Recording The `record_url` is a pre-signed URL — it expires shortly after the call ends. Download the file in a background thread so your webhook endpoint returns immediately. Wait a few seconds before downloading: the recording is finalized and uploaded to storage right after hangup, and a small delay ensures the file is ready. ```python def download_recording(record_url, uuid): time.sleep(10) # Wait for the file to be ready on storage response = requests.get(record_url, stream=True, timeout=30) if response.status_code == 200: path = f"./data/records/{uuid}.mp3" with open(path, 'wb') as f: for chunk in response.iter_content(chunk_size=8192): f.write(chunk) db.execute( 'UPDATE cdrs SET local_record_path = ? WHERE uuid = ?', (f"/api/records/{uuid}.mp3", uuid) ) db.commit() # Trigger in the webhook handler after inserting the CDR record_url = data.get('record_url') if record_url: threading.Thread( target=download_recording, args=(record_url, uuid), daemon=True ).start() ``` ## Tools Used | Tool | Purpose | |---|---| | **Webhooks** | Receive `call_hangup` event when a call ends | ## Next Steps - [Webhooks documentation](#) — Subscribe to events, configure retry logic, verify signatures - [REST API authentication](#) — Secure your endpoint with API keys or Basic Auth - [REST API — CDR endpoints](#) — Pull historical call records on demand via the REST API --- ## Other languages - Deutsch: [llms.txt](https://www.hipcall.com/de/llms.txt) · [llms-full.txt](https://www.hipcall.com/de/llms-full.txt) - English (current): [llms.txt](https://www.hipcall.com/llms.txt) · [llms-full.txt](https://www.hipcall.com/llms-full.txt) - Español: [llms.txt](https://www.hipcall.com/es/llms.txt) · [llms-full.txt](https://www.hipcall.com/es/llms-full.txt) - Français: [llms.txt](https://www.hipcall.com/fr/llms.txt) · [llms-full.txt](https://www.hipcall.com/fr/llms-full.txt) - Italiano: [llms.txt](https://www.hipcall.com/it/llms.txt) · [llms-full.txt](https://www.hipcall.com/it/llms-full.txt) - Nederlands: [llms.txt](https://www.hipcall.com/nl/llms.txt) · [llms-full.txt](https://www.hipcall.com/nl/llms-full.txt) - Türkçe: [llms.txt](https://www.hipcall.com/tr/llms.txt) · [llms-full.txt](https://www.hipcall.com/tr/llms-full.txt)