Docs
Integrations

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.

Preview· P9For developers at businesses on Agoo Reviews

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_…; an sk_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 answers duplicate.
  • status is paid (the default), success or completed. Anything else, such as a refund, is acknowledged and ignored.
  • customer needs 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):

HeaderValue
webhook-idA unique ID for this message
webhook-timestampUnix seconds now. Messages more than 5 minutes off are refused
webhook-signaturev1, then the base64 HMAC-SHA256 of {webhook-id}.{webhook-timestamp}.{body}, keyed with the secret after whsec_ (base64-decoded)
sign.ts
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" }
outcomeMeans
invitedThe customer is invited, after the connection's delay
duplicateThis reference was counted already
ignoredNot a completed payment (another Paystack event, a refund)
pausedThe connection, or invitations, are paused
testA test connection (a Paystack test key): counted, never invited
no_contactNo email address or Ghanaian mobile number to invite
stoppedThe customer asked not to be invited
asked_recentlyYour business invited them in the last 90 days
quotaThis month's invitations are used up
not_openThe page or branch isn't open on Agoo Reviews
kindA kind of place where invitations aren't sent (the message could say where someone was treated)
planThe branch's level doesn't include payment connections
rate_limitedOver 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.

On this page