Payment connections
Send each completed payment from Paystack, a till, Mobile Money or another system to Agoo Reviews, so every paying customer is invited to review and their review shows Paid visit.
This is a published preview. Names and fields may still change before general availability; changes will be listed in the changelog.
A business on Reviews Business (or Reviews Enterprise) can connect a payment source to a branch. Every completed payment it reports invites that customer to review the branch, after a delay the business chooses (0 to 48 hours), and the review they write shows Paid visit beside its label: a transaction the business's own payment system reported, which Agoo checked was signed.
Every payment, or none
A connection invites every customer who pays. Nothing in a connection can choose who: the business can only pause the whole connection. The rules every invitation keeps still apply: nobody who asked not to be asked, nobody your business asked in the last 90 days, and your level's monthly allowance. Never offer anything for a review.
Connect a source
In the business area on agoo.reviews, open Payments and select Connect a payment source: choose the branch, a name ("Main till") and the delay, then one of:
- Paystack: paste your Paystack secret key (
sk_live_…; ansk_test_…key makes a test connection whose payments are checked and counted but never invited). Agoo seals it at once and never shows it again; only its last four characters are kept in the clear. Then, in your Paystack dashboard, set the connection's address as your Webhook URL. - Another system: Agoo makes a signing secret (
whsec_…), shown once. Your till, Mobile Money integration or point of sale signs each payment with it, as below.
Each connection has its own address:
POST https://api.agoohq.com/webhooks/reviews-payments/{address}The address alone lets nothing through: every delivery must be signed. Up to 5 connections a page. Pause stops invitations at once; Disconnect deletes the connection and its secret, and its address is refused from then on.
Paystack
Agoo takes charge.success events with data.status success, signed in x-paystack-signature (HMAC-SHA512 of the raw body with your secret key), exactly as Paystack sends them. It reads the payment's data.reference and the customer's name, email and phone from data.customer. Every other event is acknowledged and ignored.
If your Paystack account already sends its webhooks to your own server, forward each charge.success body unchanged, with its x-paystack-signature header, to the connection's address.
Another system
Send one POST per completed payment, with a JSON body:
{
"reference": "TILL-2026-10-29-0042",
"status": "paid",
"customer": { "name": "Ama Owusu", "email": "ama@coastline.example", "phone": "+233241234567" }
}reference(required, up to 120 characters) is your own payment's ID. A payment is counted once: a repeat with the same reference answersduplicate.statusispaid(the default),successorcompleted. Anything else, such as a refund, is acknowledged and ignored.customerneeds an email address or a Ghanaian mobile number. A payment without one is counted, never invited.
Sign it with Standard Webhooks, as Agoo signs its own webhooks (verify signatures shows the same scheme the other way):
| Header | Value |
|---|---|
webhook-id | A unique ID for this message |
webhook-timestamp | Unix seconds now. Messages more than 5 minutes off are refused |
webhook-signature | v1, then the base64 HMAC-SHA256 of {webhook-id}.{webhook-timestamp}.{body}, keyed with the secret after whsec_ (base64-decoded) |
import { createHmac, randomUUID } from "node:crypto"
const secret = process.env.AGOO_PAYMENTS_SECRET! // whsec_…
const key = Buffer.from(secret.replace(/^whsec_/, ""), "base64")
export async function reportPayment(address: string, payment: object) {
const body = JSON.stringify(payment)
const id = randomUUID()
const timestamp = Math.floor(Date.now() / 1000).toString()
const signature = createHmac("sha256", key).update(`${id}.${timestamp}.${body}`).digest("base64")
return fetch(`https://api.agoohq.com/webhooks/reviews-payments/${address}`, {
method: "POST",
headers: { "Content-Type": "application/json", "webhook-id": id, "webhook-timestamp": timestamp, "webhook-signature": `v1,${signature}` },
body,
})
}What Agoo answers
A signed delivery answers 200 with what became of the payment:
{ "received": true, "outcome": "invited" }outcome | Means |
|---|---|
invited | The customer is invited, after the connection's delay |
duplicate | This reference was counted already |
ignored | Not a completed payment (another Paystack event, a refund) |
paused | The connection, or invitations, are paused |
test | A test connection (a Paystack test key): counted, never invited |
no_contact | No email address or Ghanaian mobile number to invite |
stopped | The customer asked not to be invited |
asked_recently | Your business invited them in the last 90 days |
quota | This month's invitations are used up |
not_open | The page or branch isn't open on Agoo Reviews |
kind | A kind of place where invitations aren't sent (the message could say where someone was treated) |
plan | The branch's level doesn't include payment connections |
rate_limited | Over 120 payments a minute, or 5,000 a day, for this connection |
An unsigned or wrongly signed delivery answers 401; an unknown address 404; a body without a reference, or larger than 64 KB, 400. Retry a 503 later with the same reference.
What the business sees
The business area shows each connection's payments of the last 30 days by outcome, never a customer's contact. Contacts are sealed as they arrive, used only for the invitation and its one reminder, and deleted 30 days after the link ends, as for every invitation. Which invitation became which review is never shown.
Related
- Agoo Reviews quick start
- Connect a payment source in the help centre
- What review labels mean