The Opportunity
If you run a marketplace where customers find tradespeople, you have a trust problem you didn't build and a payments problem you don't want to own.
Customers ask: Is this worker reliable? Will they show up? Can I trust them with my home?
Workers ask: Will I actually get paid? Can a customer dispute work I've already done?
Verity solves both — and we can attach directly to your platform without you changing your product or owning any payment risk.
What Verity Is
Verity is a trust and payments layer for informal tradespeople, built on:
- An append-only financial ledger — every quote, payment and dispute is permanently recorded and cannot be altered
- A trust score built from real job history — not identity documents
- A WhatsApp-native interface — workers manage everything from WhatsApp, no app download required
- A cryptographic evidence chain — every financial event is hashed and anchored publicly
We currently operate in South Africa (ZAR), with workers communicating in English and Afrikaans.
What You Get
| Your marketplace gets | Workers get | Customers get |
|---|---|---|
| A verified trust badge on worker profiles | Inbound quote requests via WhatsApp | A trusted, independently-verified score |
| Automated job lead delivery to workers | A permanent record of their work history | Evidence-backed payment protection |
| Payment tracking without owning payment rails | Access to more customers | Dispute resolution through Verity |
| A worker vetting signal you didn't have to build | No app download required | Transparent, explainable transaction history |
Flow 1 — Trust Scores on Worker Profiles
When a customer browses your platform and views a worker's profile, display their Verity trust badge alongside your own data.
// Request GET /api/marketplace/workers/+27821234567/trust X-Marketplace-Key: your-partner-key // Response { "verified": true, "trust_tier": "gold", "trust_score": 112, "badge": "✅ Verity Verified — Gold", "completed_jobs": 34, "dispute_rate_pct": 0, "summary": "Gold tier · 34 jobs · 0% dispute rate", "id_verified": true, "business_verified": false, "can_accept_large_jobs": true, "member_days": 142 }
Score range: 0–200 (identity score 0–100 + behaviour score 0–100). Phone verification is required before behaviour points count.
Trust Tiers
| Tier | Score | What it signals |
|---|---|---|
| trusted_pro | 150+ | 10+ verified jobs, excellent payment record, very low dispute rate |
| gold | 100–149 | 5+ verified jobs, strong payment record |
| silver | 50–99 | Some identity + behaviour history, phone confirmed |
| bronze | 10–49 | Phone verified, early history |
unregistered |
— | Worker not yet registered — returns trust_tier: "unregistered", trust_score: 0, badge: "Not yet on Verity" |
silver and above. For unregistered workers, show a "Not yet verified" prompt that links to Verity registration.Flow 2 — Push Quote Requests to Workers
When a customer selects a worker and requests a quote, push that lead to Verity. The worker gets a WhatsApp notification immediately — whether or not they're currently registered on Verity.
// Request POST /api/marketplace/lead X-Marketplace-Key: your-partner-key Content-Type: application/json { "worker_phone": "+27821234567", "customer_name": "Sipho Dlamini", "customer_phone": "+27798765432", "job_title": "Fix leaking geyser", "job_description": "Kitchen geyser dripping — needs washer replacement", "marketplace_job_url": "https://yourplatform.co.za/jobs/abc123", "external_ref": "abc123" } // Response { "job_id": "uuid...", "worker_notified": true, "message": "Lead created. Worker has been notified via WhatsApp." }
WhatsApp Message Sent to Worker
📋 New Quote Request via [Your Platform] Sipho Dlamini is looking for a handyman: 🔧 Fix leaking geyser "Kitchen geyser dripping — needs washer replacement" 🔗 View full request: https://yourplatform.co.za/jobs/abc123 Reply QUOTE to send them a quote through Verity. Not registered yet? Reply START — takes 30 seconds.
Important Behaviour
- If the worker is not registered, the message still delivers. The
STARTprompt recruits them automatically — your leads become a registration funnel. - If the worker replies QUOTE, they enter the Verity quoting wizard with customer phone and job title pre-filled.
- If your platform has a
marketplace_job_url, the worker sees it as a tap-through link. - Duplicate prevention is automatic — Verity rejects a second lead with the same
external_reffrom the same partner.
Flow 3 — Daily Job Digest
Push a curated list of available jobs to workers matching a location or trade. Verity delivers a WhatsApp digest (up to 5 jobs) the worker can act on immediately.
// Request POST /api/marketplace/digest X-Marketplace-Key: your-partner-key Content-Type: application/json { "worker_phone": "+27821234567", "jobs": [ { "title": "Fix leaking tap", "location": "Claremont", "estimated_value_zar": 350, "customer_name": "Thabo N.", "marketplace_job_url": "https://yourplatform.co.za/jobs/j1" }, { "title": "Paint bedroom ceiling", "location": "Rondebosch", "estimated_value_zar": 1200, "customer_name": "Priya K.", "marketplace_job_url": "https://yourplatform.co.za/jobs/j2" } ] }
WhatsApp Digest Sent to Worker
🌅 2 Jobs Near You — [Your Platform] 1️⃣ Fix leaking tap – Claremont – ~R350 Customer: Thabo N. 2️⃣ Paint bedroom ceiling – Rondebosch – ~R1,200 Customer: Priya K. Tap a link to request contact details, or reply QUOTE to send a quote for any job. Reply LEADS anytime to see fresh opportunities.
Outbound Webhooks
When a job progresses, Verity fires an event to your registered webhook URL so your platform stays in sync without polling.
Events
| Event | Triggered when |
|---|---|
job.lead_notified | Worker WhatsApp sent (immediately after POST /lead) |
job.accepted | Customer accepts the worker's Verity quote |
job.completed | Payment confirmed by both parties — job done and paid |
payment.confirmed | Payment confirmed and applied to ledger |
job.completed and payment.confirmed fire together. They are separate event types so your platform can handle them with different business logic.Payload Format
POST https://yourplatform.co.za/webhooks/verity Content-Type: application/json X-Verity-Event: payment.confirmed X-Verity-Signature: sha256=<hmac-hex> { "event": "payment.confirmed", "job_id": "uuid...", "partner": "your-slug", "timestamp": "2026-03-28T14:23:00.000Z", "external_ref": "abc123" }
Per-Event Extra Fields
| Event | Extra fields |
|---|---|
job.lead_notified | worker_phone, worker_notified (bool) |
job.accepted | none beyond envelope |
job.completed | payment_method — "cash" or "eft" |
payment.confirmed | payment_method — "cash" or "eft" |
Signature Verification
Every webhook is signed with HMAC-SHA256 using your webhook secret. Always verify before processing.
import crypto from 'crypto'; function verifyVerityWebhook(rawBody, signatureHeader, webhookSecret) { const expected = 'sha256=' + crypto.createHmac('sha256', webhookSecret) .update(rawBody) // raw bytes — do NOT parse JSON first .digest('hex'); return crypto.timingSafeEqual( Buffer.from(signatureHeader), Buffer.from(expected) ); } // Express app.post('/webhooks/verity', express.raw({ type: 'application/json' }), (req, res) => { const sig = req.headers['x-verity-signature']; if (!verifyVerityWebhook(req.body, sig, process.env.VERITY_WEBHOOK_SECRET)) { return res.status(401).send('Invalid signature'); } const event = JSON.parse(req.body); // handle event... res.sendStatus(200); });
job_id + event if you need replay.How the Trust Score Is Built
Unlike identity-only verification (ID document, selfie), the Verity trust score is built from real transaction history. A worker earns score by doing jobs and getting paid — not by uploading documents.
Two Components — 100 Points Each (Total 0–200)
Identity component (0–100): Phone verification, ID document, business registration, and account age. Unlocks the behaviour component — behaviour points don't count until a phone is verified.
Behaviour component (0–100): Earned from real job history:
| Behaviour signal | Points | What it measures |
|---|---|---|
| Completion Reliability | 40 | Jobs completed vs started |
| Payment Integrity | 25 | Payments confirmed without dispute |
| Consistency & Volume | 20 | Regularity of work activity |
| Dispute Behaviour | 15 | Dispute rate across all payments |
Authentication
All API calls use a per-partner API key in the X-Marketplace-Key header. Keys are stored as SHA-256 hashes — the raw key is shown once at registration and never again. To rotate a key, contact the Verity team.
Rate Limits
All endpoints are limited to 100 requests per minute per partner key. Exceeding this returns 429 Too Many Requests with a Retry-After header.
| Response header | Meaning |
|---|---|
X-RateLimit-Limit | Maximum requests allowed in the window |
X-RateLimit-Remaining | Requests remaining in the current window |
X-RateLimit-Reset | Unix timestamp when the window resets |
{
"error": "rate_limit_exceeded",
"message": "Too many requests. Limit: 100 per 1m",
"statusCode": 429
}
Phone Number Format
All phone numbers must be in E.164 format with the + prefix. Numbers without + are rejected. South African numbers use +27 — drop the leading 0:
// Incorrect 082 123 4567 or 0821234567 // Correct +27821234567
Error Responses
| HTTP | error value | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid X-Marketplace-Key |
400 | validation_error | Request body failed schema validation — see details field |
409 | duplicate_external_ref | A lead with this external_ref already exists for your account |
404 | — | Not used for trust score. Unknown phone returns 200 with trust_tier: "unregistered" |
429 | rate_limit_exceeded | Too many requests — see Retry-After header |
Base URLs & Testing
Production: https://handyman-ledger.fly.dev Pilot: https://handyman-ledger-pilot.fly.dev
Verity will issue a separate test API key pointing to the pilot environment. Note that test leads send real WhatsApp messages — use a phone number you control.
Verify Your Key
GET /api/marketplace/partner X-Marketplace-Key: your-test-key // Expected response { "partner": { "id": "uuid...", "name": "Your Platform Name", "slug": "your-slug", "webhook_configured": true } }
Endpoints
| Method | Path | Purpose |
|---|---|---|
| GET | /api/marketplace/partner |
Verify your key — returns your partner identity |
| GET | /api/marketplace/workers/{phone}/trust |
Worker trust score and badge |
| POST | /api/marketplace/lead |
Push a quote request to a worker |
| POST | /api/marketplace/digest |
Send a job digest to a worker |
Partner Portal
Once approved, log in to the partner portal to monitor your integration. The dashboard shows:
- Total leads sent and worker notification rate
- Jobs accepted and completed
- Webhook delivery success rate
- A feed of your 20 most recent leads
- Your API key prefix and webhook configuration status
Your API key prefix (first 8 characters) is visible so you can identify which key is active. The full key is never displayed again after initial provisioning.
What You Don't Have to Build or Own
| Concern | Verity owns it | You own it |
|---|---|---|
| Payment processing | ✅ | |
| Dispute resolution | ✅ | |
| Worker identity verification | ✅ | |
| Evidence and audit trail | ✅ | |
| WhatsApp communication with workers | ✅ | |
| Trust score calculation | ✅ | |
| Customer experience on your platform | → | |
| Worker discovery and matching | → | |
| Job categories and geographic coverage | → |
Getting Started
Complete the application at verityledger.co.za/marketplace/signup
You receive your API key and webhook secret by email within 1 business day.
GET /api/marketplace/partner should return your partner name.
Test lead delivery, trust badge display, and webhook delivery end-to-end.
Tune timing and job selection criteria based on quote conversion rates.
Typical time from application to first live lead: 1–3 days. All integration work is on your side — Verity is ready now.
FAQ
Does the worker need to be on Verity before we send a lead?
No. Verity delivers the WhatsApp regardless. If they're not registered, the message includes a START prompt. Your leads become a natural registration funnel.
What happens if the worker ignores the lead?
The job stays in lead status. You receive the job.lead_notified webhook immediately. If there's no further activity, close it on your side after your own timeout. Verity doesn't chase the worker — that's your product decision.
Can we send leads to multiple workers for the same job?
Yes — call POST /api/marketplace/lead once per worker with the same job_title but a different worker_phone. Use your own external_ref format to distinguish them (e.g. job-abc123-worker-1, job-abc123-worker-2).
Do customers interact with Verity directly?
Only when confirming payment. When a worker records a payment through Verity, the customer receives a confirmation link handled entirely by Verity. Everything else — browsing, booking, reviewing — stays on your platform.
Is the trust score real-time?
Yes. GET /api/marketplace/workers/:phone/trust queries the live ledger every time. There is no cache to invalidate.
What if a worker disputes their trust score?
The score is derived from an immutable ledger. Every component is explainable: "you have 3 disputed payments out of 30 — that gives you a 10% dispute rate." There is no hidden logic.
Ready to integrate?
Apply for access and get your API key within 1 business day.