Skip to main content
Pretend you’re standing at the back of a small site office in Bodija, Ibadan. It’s Tuesday morning. Engr. Adekunle Ogundimu has his laptop open at the desk; his foreman is calling from a site in Mokola; the generator is running outside. He needs five bricklayers for a three-day patch job starting Thursday. Last time, two of the men his foreman brought didn’t show up after day one and he paid for ghosts. He doesn’t want to do that again. This is what happens when he opens guild.com.ng.

1. He posts the job (and the money moves)

1

He opens the dashboard

guild.com.ng/overview. He signed up last week, linked his Access Bank account through a direct-debit mandate, sent the ₦50 confirmation transfer OPay asked for, got the Mandate ready notification three minutes later. His bank is now a payment rail he can tap, once, with one finger.
2

He fills the form

Five bricklayers. Bodija. Three days starting Thursday. ₦4,000 a day. Yoruba preferred. Total budget ₦60,000. Submit.
3

The escrow funds, immediately

The moment he hits submit, ₦60,000 is debited from his Access Bank account via OPay direct debit. It lands in an escrow balance tied to this exact job. A ₦500 posting fee is added on top. The money is committed before any worker even sees the job.This is the part most platforms skip 👀. We don’t wait until the job is done to find out the employer can’t pay. The money is on our side before the first WhatsApp ping fires.
4

The job goes live

Posted at 9:02 AM. Available across voice, WhatsApp, SMS, and the marketplace at guild.com.ng/jobs.

2. Our matching model ranks the candidates

The moment Adekunle’s job posts, our matching model runs over every Job Seeker who could plausibly do it. Four factors weigh in:

Skill

Bricklayer matches bricklayer. The skill tags on a Job Seeker’s profile are exact; the trade category is a fallback. A tiler can apply, but they rank lower.

Location

Bodija is the centre of the search. We expand outward by area, by city, by state, with distance decay. Modakeke is forty minutes by danfo. Still in range.

Language

Adekunle asked for Yoruba. Musa speaks Yoruba and Pidgin. He’s a fit. A Hausa-only speaker drops down the list.

Economic context

Standing tier. On-time rate. Repayment streak. Employer feedback. Recent activity. A Job Seeker who shows up and finishes ranks above one who doesn’t.
Musa lands at the top of the list. Eight other names follow. The whole call takes under a hundred milliseconds.

3. Musa hears about it on WhatsApp

His phone vibrates at 9:04 AM. WhatsApp message:
Adekunle dey hire 5 bricklayers for Bodija. ₦4,000/day, 3 days. Reply YES to apply.
He replies YES. The intent engine recognises the affirmative, looks at the conversation state, posts the application. Done in under a second.
A Job Seeker who isn’t on WhatsApp would hear about the same job by SMS. Tola can also place an outbound voice call to a high-fit candidate (“You get one bricklayer job for Bodija, ₦4,000 daily, you want apply?”) — or the Job Seeker can dial Tola themselves and ask: “Wetin work dey for Bodija?” Same matching model. Different rails.Whether it arrives as a typed YES, a Pidgin voice note, or a spoken reply on a call, Google Gemini does the understanding underneath — one brain behind every rail.

4. Adekunle approves

His dashboard shows a notification: Musa Bello (bricklayer, Modakeke) applied. He taps the row, sees Musa’s profile — standing tier Emerging, twelve completed jobs in the last sixty days, average review 4.7. He taps Approve. Approval writes to the audit ledger. The matching model gets a positive signal. The next time Adekunle posts, candidates similar to Musa rank a notch higher.

5. The work happens, releases fire automatically

Thursday morning, Musa shows up at the Bodija site at 7:30 AM. The foreman opens his dashboard and marks him present. Two more bricklayers show, two more, one more. All five present. Work starts. That evening, our scheduler reads the day’s attendance against the escrowed budget. For every Job Seeker marked present, one day’s wage releases from escrow to their wallet. Five releases of ₦4,000 each. Five SMS notifications. Five wallets crediting inside a few seconds of each other. Friday: same thing. Saturday: same thing. Each attendance entry is its own audit row. Each release is its own audit row. The foreman cannot retroactively edit attendance once it’s marked — the triggers reject every UPDATE and DELETE on the audit tables. The history is structurally immutable. By Saturday evening, Musa has ₦12,000 in his Guild wallet without Adekunle ever tapping a Pay button. The money was committed when the job posted; the releases flowed as the work happened.

6. The reconcile path (security in the background)

You might wonder: how do we know the OPay debit from step 1 actually settled? How do we know the per-shift releases are safe to fire? Hold on — this is the part most platforms skip 👀.
1

The initial escrow debit triggers a OPay webhook

OPay fires charge_successful to our webhook receiver. Our middleware verifies the HMAC-SHA512 signature against the raw body. crypto.timingSafeEqual for the comparison. We accept three signature schemes OPay uses; the right one is detected per request.
2

The reconcile guard runs against OPay's authoritative endpoint

Before we mark the escrow as funded, we re-verify the transaction directly against OPay. Status must match success. Amount must match the webhook body to the kobo. Anything off, the escrow stays unfunded — and no shift releases can fire because there’s nothing in escrow to release from.
3

Per-shift release writes to the ledger atomically

The release is an internal ledger move (escrow row debited, Job Seeker wallet credited) with a ULID idempotency key. Postgres-durable + Redis fast-path replay protection. A replayed release is a no-op.
4

Notification fires through OPay SMS

“₦4,000 added by Adekunle Ogundimu. Balance: ₦4,000.” Sub-second delivery.

7. Musa withdraws to his bank

Saturday night, Musa taps the SMS link. WhatsApp opens. He sends withdraw. The intent engine routes him to the withdrawal flow. ₦10,000, Access Bank, the account he linked last month. Confirms. OPay’s payout API fires. Beneficiary name pre-validated by OPay’s name-enquiry service before the transfer goes out. OPay responds with approval and a NIP reference in the same call — we mark the payout SUCCESS synchronously, no need to wait for a follow-up webhook. Seven seconds end to end. His phone buzzes: “₦10,000 sent to Access Bank ••••3911.”

8. The standing score updates

That evening Musa opens guild.com.ng/overview. His standing tier sits at Emerging, but the chart shows the tick upward — completed jobs +1, on-time rate held at 100%, employer review pending. Sunday morning Adekunle leaves a 5-star review. The standing model recomputes. Musa moves from Emerging to Trusted. This is the moment the work compounds. Three months of jobs like this, and Musa has a transaction history a lender can verify. Not a vouching letter. Not a foreman’s word. OPay-backed receipts in an immutable ledger.

9. A lender reads the signal

Months later — let’s say Musa needs ₦25,000 for a new wheelbarrow. He applies through a partner lender who’s integrated with our Partner API. The lender asks Musa to grant consent in his Guild dashboard. He taps yes. Consent record written. The lender hits GET /partner/v1/users/usr_01HMFB.../snapshot. We return a signed JSON document:
The lender verifies the signature, runs their underwriting, approves the loan. Disbursement runs over OPay payout. Repayments run over OPay direct debit on the schedule Musa accepted. That’s the loop.

The three roles, one ledger

Job Seekers

Sign up by voice, WhatsApp, or web. Find work in their language. Get paid same-day. Build a standing score that compounds.

Traders

Open a OPay virtual account. Take customer transfers. Sales velocity unlocks inventory advance offers.

Employers

Link a bank by direct debit. Post jobs. See attendance proof, day by day. Pay per-shift without middlemen.
Same ledger. Same standing model. Different doors.

Read the architecture

Eight services, sixteen shared packages, one Postgres cluster, one Redis. Built for a national footprint, in service of one informal job seeker at a time.