Busy landlords need more than a buyer — They need a team that delivers
Property118 Busy landlords need more than a buyer — They need a team that delivers A busy landlord in Kent had already accepted two offers through other estate agents. Both sales fell through when the buyers could not secure mortgages. Months of waiting had brought her no closer to selling. Pulled in several directions, she did not have the time or energy to untangle the problems herself. She needed more than another offer. She needed someone to take responsibility for getting the sale done. That is why she turned to Landlord Sales Agency. We agreed a minimum of £105,000 for her, plus 90% of anything achieved above our estimated £120,000 value. That guaranteed amount represented 87.5% of our estimated vacant possession value. The difference gave us room to fund the work, cover costs and solve the problems needed to deliver a faster, more reliable sale. For this landlord, using some of her equity meant having an experienced team take the job off her hands – with an agreed amount protected for her. Two failed sales gave us a head start on the problems We began by finding out why the previous buyers had struggled. One lender had declined because the property was a basement flat. Another had requested information the freeholder could not supply. Those were lessons we could use to prepare the next sale properly. We secured a buyer and took their deposit in just over four weeks. When the lender then valued the flat below the agreed purchase price, we challenged the valuation with comparable sales and worked with the buyer and seller to find a way forward. The lender valued the property at £115,000. The buyer agreed to pay £117,000 with vacant possession. Our margin reduced. The seller’s agreed £105,000 did not. Rather than leaving her to choose between taking another financial hit or starting again, we made the figures work within our own margin. We protected the rental income while securing the next step The buyer needed vacant possession, but moving the tenant before the mortgage position was clear could have left the seller with another failed sale – this time with an empty flat and no rent. We obtained written confirmation from the lender that the mortgage could proceed before telling the tenant they would need to relocate. As soon as we had that, we spoke directly to the tenant, offered practical and financial support funded from our margin, and stayed involved until her move was complete. We confirmed she had vacated and coordinated access for the buyer. The seller did not have to manage the tenant’s move or fund that support separately. We took care of it as part of delivering the sale. We kept the sale moving when the paperwork didn’t Questions about ground rent, planned works, fire safety and building management all had the potential to hold things up. We tracked down the answers, gathered the information, followed communication to make sure nothing was lost or misplaced and chased progress to ensure the sale would complete as fast as possible. When a concern arose about the property’s condition, we established the cause and made sure it was rectified to everyone’s satisfaction. These are the gaps where sales can stall or collapse while everyone waits for someone else to find the root of the problem before taking responsibility. We made it our business to close them. After completion, the seller wrote: “After trying with multiple estate agents, we finally tried Landlord Sales Agency! They sold the property first time and were helpful and professional throughout the sale. They were on top of it at all times and left me feeling in good hands with less stress! Would definitely recommend them to anyone wanting a straight forward sale of their property” This is what your equity pays for Busy landlords do not need another list of people to chase. They need a team with the contacts, experience and time to make things happen. At Landlord Sales Agency, we reach buyers through our network of more than 30,000 investors and buyers, alongside local and nationwide agents. We arrange access, photographs and video tours, and work directly with tenants to make sales possible with them in situ or support a move where needed. We secure buyers’ commitment with a non-refundable deposit, then manage the sale through to completion. We coordinate solicitors, lenders and surveyors, challenge delays and find practical solutions when problems threaten the deal. Our service is funded from the agreed margin within the sale price, with no separate seller’s fee or commission. That margin pays for the work that helps turn an accepted offer into money in the bank. You make the decision to sell. We take responsibility for making the sale work. Complete the form below and tell us a little about your property. We can explain what you could receive, what work we expect to handle and how much of your equity our service would need to deliver a faster, more reliable sale. Name * Email * Phone * Please give us details of how we can help and the properties in question * Privacy Policy * I have read and accept Property118’s Privacy Policy (function(){var el=document.getElementById("ts-607776b5-3f7b-431c-b5cc-fc304603fee3");if(!el)return;var b=document.body,h=document.documentElement;var dark=b.classList.contains("dark-mode")||b.classList.contains("dark")||b.classList.contains("night-mode")||h.classList.contains("dark");if(!dark){var bg=window.getComputedStyle(b).backgroundColor,m=bg.match(/\d+/g);if(m)dark=(m[0]*0.299+m[1]*0.587+m[2]*0.114) Submit (function(){ var uid = "crm-form-ba09a29b"; var form = document.getElementById(uid + '-form'); var wrap = document.getElementById(uid); var msg = wrap.querySelector('.crm-message'); var totalPages = 1; var curPage = 0; // ── Name casing ────────────────────────────────────────────────────── // Tidy a name box as the visitor leaves it, so they are not staring at // "JOHN SMITH" in their own form. Deliberately cosmetic: the API runs // the same normalisation on submit and is the authority on what gets // stored, so a disagreement here is harmless. Kept in step with // packages/shared/src/names.ts. var NAME_PARTICLES = ' van von de del della der den di da dal du la le el bin ibn al dos das do ter ten '; var NAME_MACS = ' macdonald macintyre macleod macarthur macgregor macneil macpherson macrae mackinnon macqueen '; function nameUp(s){ return s.replace(/[a-z]/i, function(c){ return c.toUpperCase(); }); } function isParticle(w){ return NAME_PARTICLES.indexOf(' ' + w.toLowerCase() + ' ') >= 0; } function nameRecase(atom){ if (!/[a-z]/i.test(atom)) return atom; var dot = atom.charAt(atom.length - 1) === '.' ? '.' : ''; var core = dot ? atom.slice(0, -1) : atom; var lower = core.toLowerCase(); if (/^(?:II|III|IV|VI|VII|VIII|IX|XI|XII)$/.test(core.toUpperCase())) return core.toUpperCase() + dot; if (lower === 'jr' || lower === 'sr') return nameUp(lower) + dot; if (core.length === 1) return core.toUpperCase() + dot; var mc = /^mc([a-z]{2,})$/.exec(lower); if (mc) return 'Mc' + nameUp(mc[1]) + dot; if (NAME_MACS.indexOf(' ' + lower + ' ') >= 0) return 'Mac' + nameUp(lower.slice(3)) + dot; return nameUp(lower) + dot; } function nameWellFormed(atom){ // "Mccoll" has its leading capital but still wants McColl. Safe only // because "Mc" is unambiguous — "Mac" deliberately has no such rule. if (/^Mc[a-z]{2,}$/.test(atom)) return false; return /^(?:[A-Z][a-z]*|[A-Z][a-z]+[A-Z][A-Za-z]*|O[A-Z][a-z]+|[A-Z]{1,3}|[IVX]+)$/.test(atom); } function tidyName(value){ var v = (value || '').replace(/\s+/g, ' ').replace(/^ | $/g, ''); if (!v) return value; if (/[@\d,]|&[a-z]+;|&#|https?:|www\./i.test(v)) return value; // not a name var words = v.split(' '); var deliberate = words.every(function(w){ // A lone particle is not a particle — it is someone's name (Di, Al). if (words.length > 1 && isParticle(w)) return true; return w.split(/[-'\u2019.]/).filter(function(seg){ return /[a-z]/i.test(seg); }) .every(function(seg){ return nameWellFormed(seg); }); }); if (deliberate) return v; return words.map(function(w, i){ if (i > 0 && isParticle(w)) return w.toLowerCase(); return w.split(/([-'\u2019.])/).map(function(seg){ return /^[-'\u2019.]$/.test(seg) ? seg : nameRecase(seg); }).join(''); }).join(' '); } // ── Thousand separators ────────────────────────────────────────────── // Opt-in per field (data-thousands). Mirrors formatThousands() and the // caret helpers in the CRM's packages/shared/src/numbers.ts. The CRM // strips the separators again on submit, so storage is unaffected. function groupThousands(value){ var raw = String(value == null ? '' : value).replace(/,/g, ''); if (!raw) return ''; var neg = raw.charAt(0) === '-'; var body = neg ? raw.slice(1) : raw; var dot = body.indexOf('.'); var digits = function(x){ return x.replace(/[^0-9]/g, ''); }; var whole = digits(dot === -1 ? body : body.slice(0, dot)); var frac = dot === -1 ? null : digits(body.slice(dot + 1)); if (!whole && frac === null) return neg ? '-' : ''; var grouped = whole.replace(/\B(?=(\d{3})+(?!\d))/g, ','); return (neg ? '-' : '') + grouped + (frac === null ? '' : '.' + frac); } // Reposition by digit count, not character index: commas appear and // vanish to the left of the caret, and counting characters would throw // it to the end of the field on every keystroke. function caretAfterGrouping(formatted, digitsBefore){ if (digitsBefore parseFloat(cmp); case 'lessthan': return parseFloat(val) [ ][ ]', so the prefix arm above // collects EVERY rendered row. Demanding all of them be filled means one blank // extra row - added by mistake, or rendered by settings.minRows - blocks Next and // Submit with a generic message on the wrapper. Only the first row is required. var firstRow = form.querySelector('[data-field-id="' + fld.id + '"] .crm-repeater-row'); if (firstRow) { reqEls = Array.prototype.filter.call(reqEls, function (el) { return firstRow.contains(el); }); } var toTest = reqEls.length ? reqEls : [els[0]]; return Array.prototype.every.call(toTest, function (el) { return (el.value || '').trim() !== ''; }); } function crmFirstInvalid(pageIdx) { for (var i = 0; i [ ][ ]". // Group those flat keys into an array of row objects under the repeater // id. Plain fields, checkbox "[]" arrays and single-bracket composites // (name[first], address[city]) don't match the double-bracket pattern, so // ordinary submissions are unchanged. var _repRe = /^(.+?)\[(\d+)\]\[(.+)\]$/; var _repIds = {}; Object.keys( data ).forEach( function ( key ) { var m = key.match( _repRe ); if ( ! m ) { return; } var rid = m[1], row = parseInt( m[2], 10 ), sub = m[3]; _repIds[ rid ] = true; if ( ! Array.isArray( data[ rid ] ) ) { data[ rid ] = []; } if ( ! data[ rid ][ row ] || typeof data[ rid ][ row ] !== 'object' ) { data[ rid ][ row ] = {}; } data[ rid ][ row ][ sub ] = data[ key ]; delete data[ key ]; } ); Object.keys( _repIds ).forEach( function ( rid ) { if ( Array.isArray( data[ rid ] ) ) { data[ rid ] = data[ rid ].filter( function ( r ) { return r && typeof r === 'object'; } ); } } ); // GF auto-substituted {user_agent} / {referer} on hidden fields // at render time. We do the equivalent right before submit so // fields whose default value carries these placeholders // resolve to the browser's actual values rather than being // stored as literal "{user_agent}" / "{referer}" strings. // The last ARTICLE the visitor read (set client-side on post views by // P118_Article_Views). Used to attribute the enquiry to the article // even after navigating away or with a stripped/absent referer. var lastPost = ''; try { var lpm = document.cookie.match(/(?:^|;\s*)p118_last_post=([^;]+)/); if (lpm) lastPost = decodeURIComponent(lpm[1]); } catch (e) {} var subs = { '{user_agent}': navigator.userAgent || '', // Prefer the last article read; fall back to the (lossy) HTTP referer. '{referer}': lastPost || document.referrer || '', '{last_post}': lastPost || '', '{embed_url}': window.location.href || '', }; for (var name in data) { if (!data.hasOwnProperty(name)) continue; var v = data[name]; if (typeof v !== 'string') continue; for (var tag in subs) { if (v.indexOf(tag) !== -1) v = v.split(tag).join(subs[tag]); } data[name] = v; } // Agent/BDM attribution — read LIVE so it works even on a fully cached // page (the browser always sees the real URL + cookie). URL ?ataid=/?cid= // first, then the 30-day agent_id/cid cookies set by atat-tracking.php. var _qp = new URLSearchParams(window.location.search); var _ataid = _qp.get('ataid') || (document.cookie.match(/(?:^|;\s*)agent_id=([^;]+)/) || [])[1] || ''; var _cid = _qp.get('cid') || (document.cookie.match(/(?:^|;\s*)cid=([^;]+)/) || [])[1] || ''; if (_ataid) data.agent_id = decodeURIComponent(_ataid); if (_cid) data.bdm_id = decodeURIComponent(_cid); // Which page the form was actually on. Read live for the same reason // as the attribution above: on a cached page the server has no idea // which URL it is being served as, but the browser always does. data._sourceUrl = window.location.href; // …and what sent them to it. Read live for the same reason: a cached // page cannot know either, but the browser does. Blank when they // typed the address, used a bookmark, or came from an email client — // which is the honest answer, not a gap to be filled in server-side. data._referrerUrl = document.referrer || ''; // This browser's progress through a multi-page form is now sent. if (typeof progVisit !== 'undefined' && progVisit) data._visitId = progVisit; return data; } function uploadFiles(data) { var fileInputs = form.querySelectorAll('input[type=file][data-crm-file-field]'); var uploads = []; fileInputs.forEach(function(el) { if (!el.files || !el.files[0]) return; var fd = new FormData(); fd.append('file', el.files[0]); var fieldName = el.name; uploads.push( fetch(crmApiUrl + '/public/forms/' + "08ceeaae-4809-444e-ba0f-88da5836c463" + '/upload', { method: 'POST', body: fd }) .then(function(r) { if (!r.ok) throw new Error('File upload failed (' + r.status + ')'); return r.json(); }) .then(function(res) { if (res.path) data[fieldName] = res.path; else throw new Error(res.error || 'File upload failed'); }) ); }); return Promise.all(uploads).then(function() { return data; }); } function submitFormData(data) { var body = new FormData(); body.append('action', 'p118_crm_submit'); body.append('form_id', "08ceeaae-4809-444e-ba0f-88da5836c463"); body.append('data', JSON.stringify(data)); // Embed-page context for GF-style merge tags ({embed_url}, // {embed_post:post_title}, {embed_post:ID}). Captured PHP-side // at render time, then echoed to JS so the submit fetch can // forward to V2 as request headers. body.append('embed_url', ""); body.append('embed_post_id', "0"); body.append('embed_post_title', ""); return fetch("https:\/\/www.property118.com\/wp-admin\/admin-ajax.php", { method: 'POST', body: body, credentials: 'same-origin' }) .then(function(r){ return r.json(); }) .then(function(res){ var p = res.data || res; if (p && p.success) { if (typeof progDone === 'function') progDone(); if (p.confirmationType === 'form' && p.nextFormId) { return swapInNextForm(p.nextFormId, p.prefill || {}); } if (p.confirmationType === 'redirect' && p.confirmationRedirectUrl) { window.location.href = p.confirmationRedirectUrl; } else { form.style.display = 'none'; msg.className = 'crm-message success'; // Sent: the progress line says so, not "Step 6 of 6". var doneText = wrap.querySelector('.crm-progress-text'); if (doneText) doneText.textContent = 'Completed'; var doneFill = wrap.querySelector('.crm-progress-fill'); if (doneFill) doneFill.style.width = '100%'; msg.innerHTML = p.confirmationMessage || 'Thank you for your submission.'; // Carry the calculator's own results across. A calculator form // renders its figures into [data-iht-results] as the visitor // types; hiding the form hid those too, so the completion // screen went blank and the visitor lost what they had just // worked out. Nothing happens on forms without that element. var resultsEl = form.querySelector('[data-iht-results]'); if (resultsEl && resultsEl.innerHTML.trim()) { var carried = document.createElement('div'); carried.className = 'crm-message-results'; carried.innerHTML = resultsEl.innerHTML; msg.appendChild(carried); } // Download link for a generated report, present only when the // API filed the PDF before responding. Built through the DOM // rather than concatenated into innerHTML so the URL cannot // inject markup. if (p.reportDownloadUrl) { var dlWrap = document.createElement('p'); dlWrap.className = 'crm-report-download'; var dl = document.createElement('a'); dl.className = 'crm-report-button'; // Building through the DOM stops markup injection but not a // javascript: URL, which would run in this origin the moment // the submitter clicks the button. dl.href = /^https?:\/\//i.test(String(p.reportDownloadUrl)) ? p.reportDownloadUrl : '#'; dl.target = '_blank'; dl.rel = 'noopener noreferrer'; dl.textContent = 'Download your report (PDF)'; dlWrap.appendChild(dl); msg.appendChild(dlWrap); } msg.style.display = 'block'; if (msg.scrollIntoView) { msg.scrollIntoView({ behavior: 'smooth', block: 'start' }); } } } else { throw new Error((p && p.error) || 'Submission failed.'); } }); } // Replace this whole form widget with another form, rendered server-side // with the carried-over values seeded in. Inline injected via // innerHTML won't run, so we re-create each script node to execute it // (this is what wires up the new form's submit / conditional logic). function swapInNextForm(nextFormId, prefill) { var rbody = new FormData(); rbody.append('action', 'p118_crm_render_form'); rbody.append('form_id', nextFormId); rbody.append('prefill', JSON.stringify(prefill || {})); return fetch("https:\/\/www.property118.com\/wp-admin\/admin-ajax.php", { method: 'POST', body: rbody, credentials: 'same-origin' }) .then(function(r){ return r.json(); }) .then(function(res2){ var pd = res2.data || res2; if (!pd || !pd.html) { throw new Error((pd && pd.error) || 'Could not load the next form.'); } var frag = document.createElement('div'); frag.innerHTML = pd.html; var parent = wrap.parentNode; var nodes = []; while (frag.firstChild) { var node = frag.firstChild; parent.insertBefore(node, wrap); nodes.push(node); } parent.removeChild(wrap); function reexec(old) { var s = document.createElement('script'); for (var a = 0; a The post Busy landlords need more than a buyer — They need a team that delivers appeared first on Property118 .
Originally published by
Property118