Docs

Make your first API call

Create a test key, list your sites, invite a visitor with an idempotent request, read the visit back, and receive a signed test webhook.

Preview· P9

This is a published preview. Names and fields may still change before general availability; changes will be listed in the changelog.

This walkthrough takes you from a new test key to a verified webhook. You'll invite Ama Owusu from Coastline Consult to meet Kwame Mensah at Volta Bank's Ridge HQ, then have Agoo tell your server about it.

Everything happens in test mode: a sandbox copy of your organisation where no SMS, WhatsApp or email reaches anyone and nothing is billed. Test mode works on every plan.

Examples use fetch and httpx

The TypeScript examples use the built-in fetch (Node.js 22.18 or later runs .mts files directly; or use npx tsx), and the Python examples use httpx (pip install httpx). An official TypeScript SDK, @ardent-africa/agoo, is planned; these examples show the raw requests so every header and status is visible.

What you need

  • An Agoo organisation on any plan, and the Owner or Admin role so you can create keys.
  • curl, Node.js 22.18 or later, or Python 3.10 or later.
  • For the webhook steps, a way to expose a local port over HTTPS, such as cloudflared or ngrok (see local testing).

Create a test key

In Console → Developers → API keys, choose Create key and set:

  • Name: "Quickstart"
  • Kind and mode: secret, test
  • Scopes: sites:read, people:read, visits:read, visits:write, webhooks:manage

Copy the key. It's shown only once, and it starts with agoo_sk_test_. Put it in an environment variable in the terminal you'll use:

export AGOO_API_KEY="agoo_sk_test_…"   # paste your full key

Keep secret keys on servers and out of source control. See authentication.

Set up a small client

curl needs nothing more. For TypeScript and Python, save this helper. It adds your key to every request and turns error responses into exceptions that include the problem details and the request ID.

Nothing to set up: each command below reads $AGOO_API_KEY.

List your sites

A visit happens at a site, so start by finding the site's ID with GET/sites.

curl https://api.agoo.ardent.africa/v1/sites \
  -H "Authorization: Bearer $AGOO_API_KEY"
Response (trimmed)
{
  "data": [
    {
      "id": "site_01kjpt3yw0fz0v414608h9x65s",
      "name": "Ridge HQ",
      "time_zone": "Africa/Accra",
      "gates": [
        { "id": "gate_01kjpt5sf0fgyvy00hg9tg68m2", "name": "Main gate" },
        { "id": "gate_01kjpt7m20fpf9vcsaexsxgqr3", "name": "Lobby" }
      ]
    }
  ],
  "next_cursor": null,
  "has_more": false
}

Your IDs will be different. Use the ones from your own response in the steps below.

Find the host

Every invitation has a host: the person the visitor is coming to see. Look them up with GET/people.

curl -G https://api.agoo.ardent.africa/v1/people \
  -H "Authorization: Bearer $AGOO_API_KEY" \
  --data-urlencode "q=Kwame" \
  --data-urlencode "can_host=true"
Output
person_01kjsesxm0e4zbyvkr7bcfxbfg Kwame Mensah kwame.mensah@voltabank.example

Invite a visitor

Create an expected visit with POST/visits. Every POST carries an Idempotency-Key: a UUID you generate once per operation. If the network drops and you retry with the same key, Agoo returns the visit it already created instead of inviting Ama twice. See idempotency.

Use your own site and host IDs, and a time in the next few days.

IDEMPOTENCY_KEY=$(uuidgen)

curl https://api.agoo.ardent.africa/v1/visits \
  -H "Authorization: Bearer $AGOO_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $IDEMPOTENCY_KEY" \
  -d '{
    "site_id": "site_01kjpt3yw0fz0v414608h9x65s",
    "host_id": "person_01kjsesxm0e4zbyvkr7bcfxbfg",
    "type": "meeting",
    "visitor": {
      "name": "Ama Owusu",
      "phone": "+233241234567",
      "email": "ama@coastline.example",
      "company": "Coastline Consult"
    },
    "purpose": "Quarterly treasury review",
    "expected_at": "2026-10-14T09:30:00Z",
    "expected_until": "2026-10-14T11:30:00Z",
    "pass_channels": ["whatsapp", "sms"]
  }'

Agoo responds with 201 Created and the visit:

Response
{
  "id": "visit_01m4k5z4j0fxbte6sn6e8tpgza",
  "status": "expected",
  "type": "meeting",
  "source": "invitation",
  "site_id": "site_01kjpt3yw0fz0v414608h9x65s",
  "gate_id": null,
  "host_id": "person_01kjsesxm0e4zbyvkr7bcfxbfg",
  "visitor": {
    "id": "visitor_01krdtb870fxj8t6ntdtcxwdk5",
    "name": "Ama Owusu",
    "phone": "+233241234567",
    "email": "ama@coastline.example",
    "company": "Coastline Consult"
  },
  "purpose": "Quarterly treasury review",
  "expected_at": "2026-10-14T09:30:00Z",
  "expected_until": "2026-10-14T11:30:00Z",
  "checked_in_at": null,
  "checked_out_at": null,
  "cancelled_at": null,
  "decision": null,
  "booking_id": null,
  "pass": {
    "channels": ["whatsapp"],
    "last_sent_at": "2026-10-10T15:12:44Z"
  },
  "custom_fields": {
    "vehicle_plate": "GR 4521-24",
    "bringing_laptop": true
  },
  "created_at": "2026-10-10T15:12:40Z",
  "updated_at": "2026-10-10T15:12:44Z"
}

What happened:

  • Agoo created or matched a visitor record for Ama by her phone number. Next time, her details are filled in for her.
  • The visit is expected, and visit.created fired.
  • Agoo sent Ama her QR pass on the first channel that worked, WhatsApp, and pass.sent fired. In test mode the message went to the console's test outbox instead of her phone: open it to see exactly what she would receive.

Run the curl command again without changing IDEMPOTENCY_KEY. You get the same visit back, with the same id, and no second pass is sent. Generate a new key and you'd create a second visit.

Read the visit back

Fetch it with GET/visits/{visit_id}, using the id from the last step.

curl https://api.agoo.ardent.africa/v1/visits/visit_01m4k5z4j0fxbte6sn6e8tpgza \
  -H "Authorization: Bearer $AGOO_API_KEY"

The visit stays expected until Ama arrives. Then the kiosk, reception or your own system checks her in and it becomes checked_in.

Register a webhook endpoint

Now have Agoo tell your server when things happen. Start a tunnel to port 3000 on your machine, for example cloudflared tunnel --url http://localhost:3000, and note the HTTPS address it prints. Then register it with POST/webhook-endpoints, replacing YOUR-TUNNEL-ADDRESS:

curl https://api.agoo.ardent.africa/v1/webhook-endpoints \
  -H "Authorization: Bearer $AGOO_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "url": "https://YOUR-TUNNEL-ADDRESS/webhooks/agoo",
    "description": "Quickstart",
    "enabled_events": ["visit.created", "visit.checked_in"]
  }'

The response includes the endpoint's id and its signing secret, which starts with whsec_. The secret is shown only once, so save it:

export AGOO_WEBHOOK_SECRET="whsec_…"   # paste the secret from the response

Run a receiver that verifies signatures

Save the verification function for your language from verify signatures (verify-agoo-webhook.ts or verify_agoo_webhook.py) next to this small server, then start it in the terminal where AGOO_WEBHOOK_SECRET is set:

A receiver has to be a server, so use the TypeScript or Python tab for this step.

Send a test event

Ask Agoo to send your endpoint a signed visit.checked_in with POST/webhook-endpoints/{whep_id}/test, using your endpoint's ID:

curl -X POST https://api.agoo.ardent.africa/v1/webhook-endpoints/whep_01m2jf0cg0ffyrmjbzsk9t0gtc/test \
  -H "Authorization: Bearer $AGOO_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{ "type": "visit.checked_in" }'

The response reports what your server returned:

Response
{
  "endpoint_id": "whep_01m2jf0cg0ffyrmjbzsk9t0gtc",
  "event_id": "evt_01m4wwgwc0f8y8gskxtb18r86q",
  "type": "visit.checked_in",
  "attempted_at": "2026-10-14T09:40:00Z",
  "outcome": "succeeded",
  "status_code": 204,
  "duration_ms": 182,
  "error": null
}

and your receiver prints:

Receiver output
Verified visit.checked_in evt_01m4wwgwc0f8y8gskxtb18r86q

If outcome is failed with status_code 401, the secret in AGOO_WEBHOOK_SECRET doesn't match the endpoint's. Check you copied all of it, then try again.

From now on, every visit you create in test mode sends visit.created to your receiver, and checking one in with POST/visits/{visit_id}/check-in sends visit.checked_in.

Next steps

On this page