# Welcome to Goomzo > Know your customers. Reach the right people. Goomzo helps Tanzanian businesses keep customer information in one place and reach the right people. You add your customers, group them into segments, and send SMS and email updates: to one customer, or a whole segment at once. ## Start here ## Explore --- # Get started with Goomzo > From a new account to your first SMS, in five steps. This guide takes you from signing up to sending your first SMS. Most of it takes a few minutes; business verification and your sender ID wait on a review, and you can send in the meantime. ### Create your account Sign up at [app.goomzo.africa](https://app.goomzo.africa/?utm_source=llms&utm_medium=ai) with your name, email, a Tanzanian phone number and a password, or choose **Sign up with Google**. Confirm your email from the link we send you. Goomzo creates your first organization, named **Hobby**. Rename it in **Settings → General**. ### Verify your business In **Settings → General**, under **Compliance**, add your business name and upload its TIN or BRELA certificate. We review it and email you when you're verified. [Learn more](https://docs.goomzo.africa/docs/help/business-verification?utm_source=llms&utm_medium=ai). ### Request a sender ID A sender ID is the name your texts show, such as `DUKA AMINA`. Once you're verified, request one in **Integrations → Sender IDs**. Until it's approved, texts go out under Goomzo's. [Learn more](https://docs.goomzo.africa/docs/help/sender-ids?utm_source=llms&utm_medium=ai). ### Get an SMS bundle Top up your wallet by mobile money or card in **Billing → Overview → Top up**, then pick an SMS bundle in **Engagement → Subscriptions**. [Learn more](https://docs.goomzo.africa/docs/help/sms-bundles?utm_source=llms&utm_medium=ai). ### Add customers and send In **Customers → All customers**, add customers one by one or [import a CSV file](https://docs.goomzo.africa/docs/help/import-customers?utm_source=llms&utm_medium=ai). Then send a [message](https://docs.goomzo.africa/docs/help/messages?utm_source=llms&utm_medium=ai) to one of them, or a [broadcast](https://docs.goomzo.africa/docs/help/broadcasts?utm_source=llms&utm_medium=ai) to everyone. ## Next steps --- # Verify your business > Confirm who you are, so you can send under your own name. Verification tells the mobile networks that your business is real. You need it before you can [request a sender ID](https://docs.goomzo.africa/docs/help/sender-ids?utm_source=llms&utm_medium=ai). The organization's owner and admins can submit it. ## Submit your documents 1. Open **Settings → General** and scroll to **Compliance**. 2. Fill in: - **Registered business name**, exactly as it appears on your document. - **Contact email**, a work email for your business. - **Document type**, a TIN certificate or a BRELA certificate, and its number. A TIN is 9 digits. 3. Upload the certificate as a PDF, up to 5 MB. 4. Select **Submit for verification**. ## After you submit Your status shows under **Compliance**: | Status | What it means | | ------------ | ------------------------------------------------------------------------------------ | | Not verified | Nothing submitted yet. | | In review | Our team is checking it. You can still change it with **Replace submission**. | | Verified | You're done, and can request sender IDs. | | Rejected | Something didn't match. The reason is shown; fix your details and submit again. | We let the owner and admins know, in Goomzo and by email, when your business is verified or if it isn't. Once your business is verified, its details can't be submitted again. --- # Customers > Add, import and find your customers. A customer is anyone you sell to. Each has a name and a way to reach them: a phone number, an email, or both. You find them all in **Customers → All customers**. ## Add a customer 1. In **All customers**, select **New customer → Add a customer**. 2. Enter their name, and a phone number or an email. 3. Optionally, put them in [segments](https://docs.goomzo.africa/docs/help/segments?utm_source=llms&utm_medium=ai), or add details. 4. Save. Phone numbers must be Tanzanian mobile numbers. You can type them as you like, such as `0712 345 678`, and Goomzo keeps them in international form: `+255712345678`. Each phone number and email can belong to only one customer. To add many customers at once, [import a CSV file](https://docs.goomzo.africa/docs/help/import-customers?utm_source=llms&utm_medium=ai). To add them from your own systems, use the [API](https://docs.goomzo.africa/docs/developers?utm_source=llms&utm_medium=ai). ## Add your own details Details are your own facts about a customer, such as a city, a birthday or a loyalty tier. A customer can have up to 50. Search finds customers by their details too. ## Get to know a customer Select a customer to open their sheet. It shows how to reach them, their segments, their details, and their **activity**: things they did, such as a purchase, as your systems record it [through the API](https://docs.goomzo.africa/docs/developers?utm_source=llms&utm_medium=ai), newest first. The sheet stays up to date while it's open. ## Find customers Search by name, phone, email or any detail, and filter by segment. ## Export customers Select **Export** to download the customers you see, with your search, filter and sort, as a CSV file. It has their name, phone, email and segments, and a column for each detail. You can export up to 50,000 at a time. ## Delete customers Open a customer and select **Delete customer**, or select several in the list and choose **Delete**. Their details are removed for good. ## Analytics **Customers → Analytics** shows how many customers you have, how many are new, and how many are active, over the last 7, 30 or 90 days, or 12 months. --- # Import customers > Add or update many customers at once from a CSV file. Importing is the quickest way to bring in the customers you already have, from a spreadsheet or another system. The organization's owner and admins can import, and so can an [API key](https://docs.goomzo.africa/docs/developers/authentication?utm_source=llms&utm_medium=ai) with `customers.write`. ## Prepare your file Save your spreadsheet as a CSV file, separated by commas or semicolons, with the column names in the first row. A file can hold up to 5,000 customers, and up to 5 MB. | Column | Required | What goes in it | | ------------ | -------- | ------------------------------------------------------------------- | | Name | Yes | The customer's name. | | Phone | One of | A Tanzanian mobile number, such as `0712 345 678`. | | Email | these | Their email address. | | Segments | No | Segments to put them in, separated by `;` or `,`. | | Anything else | No | Saved as a [detail](https://docs.goomzo.africa/docs/help/customers?utm_source=llms&utm_medium=ai#add-your-own-details), such as City. | Goomzo recognizes column names in English and Swahili, such as **Jina**, **Simu**, **Barua pepe** and **Makundi**. To start from a blank file, select **Download a template** when you import. ## Import 1. In **All customers**, select **New customer → Import from a file**. 2. Choose your file. Goomzo checks every row first and shows you what will happen. 3. Choose what to do with customers you already have: **Leave their details** or **Update their details**. 4. Select **Import**. ## Customers you already have Goomzo matches each row to an existing customer by phone or email, so nobody is added twice. Whichever you choose, existing customers still join the segments the file names. Importing the same file again changes nothing. ## Rows that can't be imported Goomzo skips a row, and tells you why, when: - it has no name, or neither a phone nor an email; - its phone or email isn't valid, or appears in an earlier row; - its phone and email belong to two different customers. The other rows are imported. Fix the skipped rows and import them again. --- # Segments > Group customers, so you can reach the right ones. A segment is a group of customers, such as **VIP**, **New this month** or **Dar es Salaam**. You pick who is in it by hand, or turn on **Automatic segmentation** and let rules decide. A customer can be in up to 20 segments picked by hand, and you can have up to 500 segments. ## Create a segment In **Customers → Segments**, select **New segment**. Give it a name, a colour, and optionally a description. You can also create one as you go: type a new name in a customer's **Segments**, or in your [import file](https://docs.goomzo.africa/docs/help/import-customers?utm_source=llms&utm_medium=ai). ## Add customers to a segment - **From the list:** in **All customers**, select customers and choose **Add to segment**. - **From the segment:** open it and select **Add customers**. - **From a customer:** edit them and choose their segments. - **By import:** name segments in your file's Segments column. To take customers out, select them in **All customers** and choose **Remove from segment**. ## Automatic segments An automatic segment fills itself. Instead of adding customers, you give it rules, such as "Purchased at least twice in the last 30 days" or "Plan is gold". Customers who match are in it, and they leave when they no longer match. No one is added or removed by hand. 1. In **Customers → Segments**, select **New segment**, and give it a name. 2. Turn on **Automatic segmentation**. 3. Under **Rules**, choose whether customers match **All conditions** or **Any condition**, then select **Add condition** for each one, up to 10. As you add conditions, the form shows how many customers match now, and a few of them. | Condition | Matches customers who | | --- | --- | | **Detail** | Have a detail that is, isn't, contains, is more or less than a value; or has a value or none | | **Activity** | Did something at least a number of times, or didn't do it; optionally in the last so many days, and only where its value is what you give, such as **Link clicked** with **December offer** | | **Activity total** | Have an activity's values adding up to more or less than an amount, such as money spent | | **Any activity** | Did anything, or nothing, in the last so many days | | **Added** | Became your customer in the last so many days | | **Segment** | Are, or aren't, in a segment you pick by hand | | **Engaged** | Are, or aren't, engaged: clicked a link, replied, chose an option or reacted in the last 30 days. Opens don't count, since email apps and read settings make them unreliable | | **Inactive** | Are, or aren't, inactive: none of that in the last 90 days | | **Converted** | Sent, or didn't send, one of your Goomzo tracking events, such as a purchase; optionally in the last so many days | | **Contact** | Have a phone number, or an email | A value such as `25,000` is compared as a number, and **Yes** or **No** as yes or no. Who is in an automatic segment is worked out each time you use it: when you open it, filter customers by it, or send it a [broadcast](https://docs.goomzo.africa/docs/help/broadcasts?utm_source=llms&utm_medium=ai). It shows on each matching customer, next to their other segments. You can have up to 50 automatic segments, and a segment stays automatic, or picked by hand, as it was made. ## Delete a segment Open the segment and select **Delete segment**. Its customers stay; they're only no longer grouped. A segment that an automatic segment's rules use can't be deleted until you change those rules. ## Through the API Send `rules` when you create a segment with `POST /v1/segments`: ```bash curl https://api.goomzo.africa/v1/segments \ -H "Authorization: Bearer $GOOMZO_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "Regular buyers", "rules": { "match": "all", "conditions": [ { "type": "activity", "key": "purchased", "op": "atLeast", "count": 2, "withinDays": 30 }, { "type": "contact", "op": "hasPhone" } ] } }' ``` `match` is `all` or `any`. Each condition has a `type`, and what that type needs: | `type` | Fields | | --- | --- | | `detail` | `key`; `op` is `is`, `isNot` (`value` text, a number or `true`/`false`), `contains` (`value` text), `moreThan`, `lessThan` (`value` a number), `isSet` or `isNotSet` | | `activity` | `key`; `op` is `atLeast` (`count`, 1 if left out) or `none`; `withinDays` and `value` (text, matched ignoring case) optional | | `activityTotal` | `key`; `op` is `moreThan` or `lessThan`; `value` a number; `withinDays` optional | | `anyActivity` | `op` is `some` or `none`; `withinDays` | | `engaged`, `inactive` | `op` is `is` or `isNot`: engaged in the last 30 days, or not in 90 | | `converted` | `op` is `did` or `didNot`; `conversionId` of a tracking event set up in the app; `withinDays` optional | | `added` | `withinDays` | | `segment` | `op` is `in` or `notIn`; `segmentId` of a segment picked by hand | | `contact` | `op` is `hasPhone` or `hasEmail` | `withinDays` is from 1 to 3,650. A problem is named by where it is, such as `rules.conditions[1].value`. - **See who matches first:** send the same `rules` to `POST /v1/segments/preview`. It answers with `count` and the five newest matching `customers`. - **What you get back:** segments have `kind`, `manual` or `rules`, and their `rules`. `customerCount` is who matches now. A customer's `segments` include the automatic ones they match. - **Change the rules** with `PATCH /v1/segments/{id}` and new `rules`. A segment picked by hand can't be given rules. - **No one is added by hand:** adding customers to an automatic segment, or naming it in a customer's `segments` when you add customers, is refused with `segment_fills_itself`. Setting a customer's segments with `PUT /v1/customers/{id}/segments` leaves automatic ones out, so you can send back what you read. ## Next steps --- # Messages > Send an SMS or WhatsApp message to one customer, and reply to what customers send you. A message goes to one customer, by SMS or WhatsApp. To reach many customers with the same message, send a [broadcast](https://docs.goomzo.africa/docs/help/broadcasts?utm_source=llms&utm_medium=ai) instead. SMS need SMS on your account; [buy an SMS bundle](https://docs.goomzo.africa/docs/help/sms-bundles?utm_source=llms&utm_medium=ai) first. WhatsApp needs your own number connected in **Integrations → WhatsApp**; Meta bills your business for it directly. ## Send a message 1. In **Engagement → Messages**, select **Compose**. 2. Choose who it's **To**, and the **Channel**: SMS or WhatsApp. 3. Choose who it's **From**. For SMS, that's one of your [sender IDs](https://docs.goomzo.africa/docs/help/sender-ids?utm_source=llms&utm_medium=ai). For WhatsApp, it's your connected number. 4. Write your message, or start from a saved [template](https://docs.goomzo.africa/docs/help/templates?utm_source=llms&utm_medium=ai). For WhatsApp, choose **Send as** a [template](#whatsapp-templates), or as text to someone who wrote to you in the last 24 hours. 5. Choose **Now**, or **Later** with a day and time, up to a year ahead. WhatsApp text always goes now. 6. Send. ## Track a message Each message shows its status: | Status | What it means | | --------- | -------------------------------------------------------------- | | Scheduled | Waiting for the time you chose. | | Sending | On its way to the network. | | Sent | The network accepted it. | | Delivered | It reached the customer's phone. | | Read | The customer read it. WhatsApp only. | | Failed | It couldn't be sent or delivered. | | Canceled | You canceled it before it went. | To cancel a scheduled message, open it and select **Cancel message**. To send any other message again, now, select **Resend**. ## WhatsApp When a customer messages your WhatsApp number, Goomzo keeps the message and records it as their activity. If they aren't a customer yet, they're added, named as they are on WhatsApp. Everything they send shows: text, photos, voice notes and other audio, videos, documents, stickers, locations and contact cards. Goomzo keeps a copy of each file up to 25 MB; a larger one is listed but not kept. You can reply with text, or with a [template](#whatsapp-templates). Open the customer to see your WhatsApp messages with them, newest at the bottom, and reply from there. To answer one message in particular, select **Reply** under it: your reply quotes it in WhatsApp. When a customer answers one of yours, their message shows the one it answers. WhatsApp lets you write freely only within 24 hours of the customer's last message. After that, Goomzo sends them a short message on your behalf, "Hi Amina, we have replied to the message you sent us on 6 Nov 2026. Tap below to read our reply.", and your reply goes as soon as they tap **Read reply**. Until then it shows as waiting; after 7 days unopened, it fails. To anyone who never wrote, send an approved template instead. WhatsApp text goes straight away; a template can be scheduled. Goomzo makes this reply template on your WhatsApp account when you connect it, in English and Kiswahili (English unless you choose otherwise), and Meta reviews it, usually within minutes. Choose its language in **Integrations → WhatsApp → Reply template**. We let you know, in Goomzo and by email, when your number is connected, when Meta disconnects it and why, and when its health changes: Meta's quality rating, how many conversations you can start a day, or a restriction Meta puts on the account or lifts. ## WhatsApp templates A template is a message Meta approved in advance, with blanks you fill for each customer. It's how you reach a customer outside the 24-hour window, and how WhatsApp [broadcasts](https://docs.goomzo.africa/docs/help/broadcasts?utm_source=llms&utm_medium=ai) go. 1. Make the template in [WhatsApp Manager](https://business.facebook.com/wa/manage/message-templates/). Meta usually reviews it within minutes, sometimes up to a day. 2. In **Integrations → WhatsApp**, see it under **Templates**. Goomzo syncs your templates when Meta reviews them; select **Sync** to read them now. We let you know, in Goomzo and by email, when Meta approves, rejects, pauses or disables a template, or moves it to another category. 3. Once it's approved, send it: with **Compose**, using **Send as** template, or from a conversation in the **Inbox** with the **+** button. 4. Fill each blank with text, or with the customer's details: `{{name}}` for their name, `{{attributes.plan}}` for a detail, and a fallback for anyone without it, as in `{{name|there}}`. Meta charges your business for each template message delivered, by its category: marketing costs more than utility. Goomzo shows roughly what Meta will charge before you send. Templates with a photo, video or document header, and carousels can't be sent from Goomzo yet. ## How SMS are counted One SMS holds 160 characters. A longer text is split into parts of 153 characters, and each part uses one SMS. A text with a character outside the standard SMS alphabet, such as an emoji or `ē`, holds 70 characters, or 67 per part. A few standard characters, such as `€`, `[` and `]`, count as two. A text can be up to 6 parts. As you write, the message box shows how many parts it takes and how many SMS you have left. SMS are only used when the network takes your message. If a message never leaves, its SMS are returned. ## Analytics **Engagement → Analytics** shows how many messages you sent, how many were delivered, and why any failed. --- # Broadcasts > Send one message to a whole segment, or to everyone. A broadcast sends the same message to everyone in a [segment](https://docs.goomzo.africa/docs/help/segments?utm_source=llms&utm_medium=ai), or to all your customers, by SMS or WhatsApp. Each customer gets their own copy. The organization's owner and admins can send broadcasts, and so can an [API key](https://docs.goomzo.africa/docs/developers/authentication?utm_source=llms&utm_medium=ai) with `broadcasts.send`. A broadcast by SMS uses SMS for every customer it reaches. Check you have enough in **Engagement → Subscriptions**, or [buy an SMS bundle](https://docs.goomzo.africa/docs/help/sms-bundles?utm_source=llms&utm_medium=ai). ## Send a broadcast 1. In **Engagement → Broadcasts**, select **New broadcast**. 2. Give it a name you'll recognize, such as **December offer**. 3. Choose who it's **To**: any of your segments and numbers you paste, one per line, or **All customers**. 4. Choose the channel, who it's from, and write your message, as for a [message](https://docs.goomzo.africa/docs/help/messages?utm_source=llms&utm_medium=ai#send-a-message). A WhatsApp broadcast goes as an approved [template](https://docs.goomzo.africa/docs/help/messages?utm_source=llms&utm_medium=ai#whatsapp-templates), its blanks filled for each person. It reaches at most as many people as your number can write to in a day; Goomzo shows the limit. 5. Send it now, or schedule it for later. ## Write to each person Put `{{name}}` in the message and each customer gets their own name in its place. `{{attributes.plan}}` works the same way for any of their details. To say something when someone doesn't have it, add it after `|`: `Hi {{name|there}}` reads "Hi there" for them. Each text is counted as it will be sent, so the estimate shows what everyone's texts use together. ## Send to numbers and several segments A broadcast can go to up to 20 segments and up to 10,000 phone numbers together, here or through the [API](https://docs.goomzo.africa/docs/developers?utm_source=llms&utm_medium=ai#make-your-first-request). Each person gets it once, even when they're in two segments or their number is pasted too. Numbers that belong to your customers show in their history; the others are sent under the number itself, and no customers are added. ## Who receives it Goomzo picks the customers when the broadcast starts sending, so customers added to the segment before then are included. An [automatic segment](https://docs.goomzo.africa/docs/help/segments?utm_source=llms&utm_medium=ai#automatic-segments) reaches whoever matches its rules at that moment. Only customers who can be reached on its channel get it: those with a phone number. A broadcast can reach up to 50,000 customers. ## See who opens your links Turn on **Track link clicks** in **Engagement → Settings**. Every message with a link is then tracked: each customer's activity shows **Link clicked** with the broadcast's name when they open one. ## Track a broadcast The list shows how many customers each broadcast was sent to, how many received it, and its status: Scheduled, Sending, Sent, Failed or Canceled. You can cancel a broadcast until it starts sending. We let you know, in Goomzo and by email, when your broadcast has been sent, with how many were sent, or if it was not sent, and why. --- # Templates > Save messages you send again and again, for SMS and WhatsApp. A template is a message you saved to use again: a welcome text, an order update, a monthly newsletter. When you write a [message](https://docs.goomzo.africa/docs/help/messages?utm_source=llms&utm_medium=ai) or a [broadcast](https://docs.goomzo.africa/docs/help/broadcasts?utm_source=llms&utm_medium=ai), pick a template to fill it in, change anything you like, and send. ## Make a template 1. In **Engagement → Templates**, select **New template**. 2. Name it, and choose its **Channel**: SMS or WhatsApp. 3. Choose its **Category**: what it's for. 4. Write the message. 5. Save. | Category | For | | -------------- | ------------------------------------------------------ | | Marketing | Offers, news and anything promotional. | | Utility | Things a customer needs to know: orders, appointments. | | Authentication | One-time codes. | These are WhatsApp's three categories, used for every channel. A WhatsApp template takes the category Meta gave the template it uses. Fill in each customer's name and details with [placeholders](https://docs.goomzo.africa/docs/help/placeholders?utm_source=llms&utm_medium=ai), such as `{{name|there}}`. ## WhatsApp templates WhatsApp has its own rules: outside the 24-hour window, and for broadcasts, you can only send a template Meta approved. Write it in Goomzo, and Goomzo submits it to Meta for you. 1. In **New template**, choose **Channel** WhatsApp. 2. Choose its **Category** (marketing or utility) and **Language**. 3. Write the message, with placeholders as above, and optionally a header, a footer and up to 3 quick replies. 4. Select **Save**. Goomzo sends it to Meta for review, and it shows **In review** until Meta approves it, usually within minutes, then it's ready. Meta's rules: the message can't start or end with a placeholder, or have two side by side; the header and footer are one line of up to 60 characters, and the footer can't have placeholders. A template you made in WhatsApp Manager can be used too: select it under **Integrations → WhatsApp → Templates**. A WhatsApp template can't be sent while Meta is reviewing or has paused it, or once it's deleted from your WhatsApp account. Templates shows why, and it's ready again once Meta allows it. ## Use a template In **Compose** or **New broadcast**, choose **Template** in the Message section. Only templates for the channel you chose, and ready to send, are listed. Templates can also be managed through the API: `GET`, `POST`, `PATCH` and `DELETE` on `/v1/templates`. The template library, Goomzo's published templates to start from, is `GET /v1/templates/library`, filtered by `channel`, `category`, `industry`, `usecase` and `q`; `POST /v1/templates/library/{id}` with `{ "name" }` saves you your own copy of one. A template the library doesn't have can be asked for from the library page's **Contact us**. --- # Placeholders > Fill each customer's name and details into a message, a broadcast or a template. A placeholder is a word in double braces that Goomzo fills in for each customer when the message goes out. Write `Hi {{name}}` once, and Amina reads "Hi Amina" while Juma reads "Hi Juma". Placeholders work in SMS messages and broadcasts, in [templates](https://docs.goomzo.africa/docs/help/templates?utm_source=llms&utm_medium=ai), and in the blanks of WhatsApp templates. ## What you can fill in | Placeholder | Becomes | | --------------------------- | --------------------------------------------------------------------- | | `{{name}}` | The customer's name. | | `{{attributes.plan}}` | One of your own [details](https://docs.goomzo.africa/docs/help/customers?utm_source=llms&utm_medium=ai#add-your-own-details), here `plan`. | | `{{data.order}}` | A value your system passes when it [sends a template](https://docs.goomzo.africa/docs/developers/messages/templates?utm_source=llms&utm_medium=ai). | | `{{secret.code}}` | The same, kept private: delivered, but kept and shown as `••••••`. | Use a detail by its key, exactly as you named it: `{{attributes.city}}`, `{{attributes.loyalty_tier}}`. A yes or no detail becomes "yes" or "no"; a number is written as it was saved. ## Fallbacks Not every customer has a name or every detail. Add a fallback after a `|`, and it's used for anyone without one: | You write | Amina (plan Gold) reads | A customer with no name or plan reads | | ---------------------------------- | ----------------------- | ------------------------------------- | | `Hi {{name\|there}}` | Hi Amina | Hi there | | `Your {{attributes.plan\|current}} plan` | Your Gold plan | Your current plan | | `Hi {{name}}` | Hi Amina | Hi | Without a fallback, a missing name or detail becomes nothing. That's fine in an SMS, but in a WhatsApp template Meta won't send a blank that's empty: Goomzo stops a broadcast whose blanks come out empty for someone, so give WhatsApp blanks a fallback. ## Check before you send - **Preview.** WhatsApp templates show a preview as a customer named Amina would read it. - **Length.** An SMS is measured once filled in for each person, so a long name can push one person's text into another SMS part. Broadcasts are checked for everyone they reach before they go. - **Mistakes.** A placeholder Goomzo doesn't know, such as `{{email}}`, or a `{{` without its `}}`, is pointed out before anything is sent. ## In WhatsApp templates When you write a WhatsApp template in Goomzo, your placeholders become Meta's numbered blanks: `Hi {{name|there}}, your {{attributes.plan}} plan renews soon` goes to Meta as `Hi {{1}}, your {{2}} plan renews soon`, and Goomzo fills the blanks for each customer when it sends. Meta also asks that the message doesn't start or end with a placeholder, and doesn't have two side by side. --- # Sender IDs > The name your texts show, such as DUKA AMINA. A sender ID is the name customers see as the sender of your texts, instead of a number. It helps them know the text is from you. Until you have one, texts go out under Goomzo's. [Verify your business](https://docs.goomzo.africa/docs/help/business-verification?utm_source=llms&utm_medium=ai) first. The networks need your certificate to approve a sender ID. ## Request a sender ID 1. In **Integrations → Sender IDs**, select **Request sender ID**. 2. Enter the name: 3 to 11 letters, numbers, spaces or hyphens, starting with a letter. Your business name, or a short form of it, works best. 3. Choose what you'll use it for: updates and reminders, orders and payments, offers and promotions, or one-time passwords. 4. Describe what you'll send, in a sentence or two. 5. Submit. ## After you request The mobile networks review each request. While it's **In review**, you can **Withdraw** it. We let you know when it's approved, or, with the reason, when it isn't. ## Which sender ID your texts use You choose it in **From** when you send. When a text doesn't name one, such as one sent [through the API](https://docs.goomzo.africa/docs/developers?utm_source=llms&utm_medium=ai), Goomzo uses a sender ID approved for that kind of message, then any you have approved, then Goomzo's. --- # SMS bundles > Top up your wallet, then choose an SMS bundle. You pay for SMS in two steps: you top up your Goomzo wallet, then buy an SMS bundle with it. Email is free. ## Top up your wallet 1. Open **Billing → Overview** and select **Top up**. 2. Enter an amount, from 500 to 10,000,000 TZS. 3. Choose how to pay: - **Mobile money:** M-Pesa, Airtel Money, Mixx by Yas or Halotel. Approve the payment on your phone. - **Card:** Visa or Mastercard, with your billing details. We let you know when your top-up has been received, or if it was unsuccessful. ## Buy an SMS bundle 1. Open **Engagement → Subscriptions**. 2. Choose a bundle and select **Subscribe**. It's paid from your wallet, and the SMS are added straight away. If your wallet is short, Goomzo tells you how much to top up. ## Check your balance **Engagement → Subscriptions** shows the SMS you have, your wallet balance, and SMS held for texts that are on their way. **Billing → Transactions** lists every top-up and payment. When you run out of SMS, new texts won't send until you buy another bundle. Goomzo tells you how many a text needs and how many you have. --- # About the Goomzo API > Connect your own systems to Goomzo. The Goomzo API lets your own systems, such as your shop, app or point of sale, work with Goomzo. Your system can add customers as they buy, record their activity, and send them SMS and WhatsApp messages, without anyone copying data by hand. ## Base URL ```text https://api.goomzo.africa/v1 ``` Requests and responses are JSON. Every request is made with an [API key](https://docs.goomzo.africa/docs/developers/authentication?utm_source=llms&utm_medium=ai), and can only do what its permissions allow. ## Core capabilities - **Messages:** send a message to one customer, or a saved [template](https://docs.goomzo.africa/docs/developers/messages/templates?utm_source=llms&utm_medium=ai) with your own values, such as a verification code. See [Send messages](https://docs.goomzo.africa/docs/developers/messages/send?utm_source=llms&utm_medium=ai). - **Broadcasts:** send one message to a segment, a list of numbers, or every customer. See [Broadcasts](https://docs.goomzo.africa/docs/developers/messages/broadcasts?utm_source=llms&utm_medium=ai). - **Templates:** create SMS templates, and WhatsApp templates that Meta reviews. See [Templates](https://docs.goomzo.africa/docs/developers/templates?utm_source=llms&utm_medium=ai). - **Customers:** add and update customers, segment them, and record their activity. See [Customers](https://docs.goomzo.africa/docs/developers/customers?utm_source=llms&utm_medium=ai). - **Webhooks:** hear about deliveries, replies and new customers as they happen. See [Webhooks](https://docs.goomzo.africa/docs/developers/webhooks?utm_source=llms&utm_medium=ai). ## Requirements - A Goomzo account, with your business [verified](https://docs.goomzo.africa/docs/help/business-verification?utm_source=llms&utm_medium=ai) to send under your own sender ID. - An [API key](https://docs.goomzo.africa/docs/developers/authentication?utm_source=llms&utm_medium=ai#create-an-api-key) with the permissions your system needs. - SMS on your account to send texts. See [SMS bundles](https://docs.goomzo.africa/docs/help/sms-bundles?utm_source=llms&utm_medium=ai). - For WhatsApp, your number connected in **Integrations → WhatsApp**. ## Phone numbers Send every phone number with its country code, such as `+255712345678`. Spaces and dashes are fine. A local number like `0712345678` is an error that says so. Answers always give numbers in this form. ## Versions Send `Goomzo-Version` with your requests to pin the API version your code is written for. Every answer says which version served it. Changes that would break your code come as a new version, so requests pinned to an older one keep working as they did. Without the header, you get the current version, `2026-11-08`. ## Lists Lists come a page at a time: 50 by default, up to 200 with `limit`. To get the next page, send the `nextCursor` from the last one as `cursor`. It's `null` on the last page. Customers, messages and broadcasts also return a `total`. ```bash curl "https://api.goomzo.africa/v1/customers?limit=200&cursor=$NEXT_CURSOR" \ -H "Authorization: Bearer $GOOMZO_TOKEN" ``` ## SDKs The SDKs send messages, keep customers in step and check webhooks, with types, safe retries and lists that page themselves. - [TypeScript SDK](https://docs.goomzo.africa/docs/developers/ts-sdk?utm_source=llms&utm_medium=ai): `npm install @goomzo/sdk` - [Python SDK](https://docs.goomzo.africa/docs/developers/python-sdk?utm_source=llms&utm_medium=ai): `pip install goomzo` - [PHP SDK](https://docs.goomzo.africa/docs/developers/php-sdk?utm_source=llms&utm_medium=ai): `composer require goomzo/goomzo-php` - [Go SDK](https://docs.goomzo.africa/docs/developers/go-sdk?utm_source=llms&utm_medium=ai): `go get github.com/goomzo/goomzo-go` ```ts title="TypeScript" import { Goomzo } from '@goomzo/sdk' const goomzo = new Goomzo() // reads GOOMZO_API_KEY await goomzo.messages.sendOne({ to: '+255712345678', template: 'auth_1', variables: { code: '482913' } }) ``` ```python title="Python" from goomzo import Goomzo goomzo = Goomzo() # reads GOOMZO_API_KEY goomzo.messages.send_one({'to': '+255712345678', 'template': 'auth_1', 'variables': {'code': '482913'}}) ``` ```php title="PHP" use Goomzo\Goomzo; $goomzo = new Goomzo(); // reads GOOMZO_API_KEY $goomzo->messages->sendOne(['to' => '+255712345678', 'template' => 'auth_1', 'variables' => ['code' => '482913']]); ``` ```go title="Go" client, _ := goomzo.NewClient() // reads GOOMZO_API_KEY client.Messages.SendOne(ctx, goomzo.MessageInput{To: "+255712345678", Template: goomzo.SavedTemplate("auth_1"), Variables: map[string]string{"code": "482913"}}) ``` ## Next steps --- # Authentication > API keys, their secrets and permissions. Every API request is made with an API key: a sign-in for one of your systems, such as your shop, not for a person. You give each key only the permissions it needs. An API key has an ID, which starts with `sva_`, and one or more secrets, which start with `gzk_`. The secret is what proves a request is yours. ## Create an API key 1. Open **Settings → API keys** and select **New API key**. Only the organization's owner and admins can. 2. Name it after the system that will use it, such as **Shop**. 3. Choose its permissions. Start from a bundle (Read only, Customer sync, Messaging or Full access) and adjust. 4. Choose when its first secret expires, and save. The secret is shown once, so copy it straight away. An API key's permissions can't be changed later. To change them, create a new key and switch over. You can have up to 50 API keys, and disable, enable or delete any of them. ## Permissions | Permission | Lets it | | ------------------------------------ | -------------------------------------------------------------------------------------------- | | `customers.read` | List, search, open and export customers | | `customers.write` | Add, import and edit customers, and set their segments | | `customers.delete` | Delete customers | | `activity.read`, `activity.write` | Read and record customer activity | | `segments.read`, `segments.write` | List and manage segments and their members | | `messages.read`, `messages.send` | List and send messages | | `broadcasts.read`, `broadcasts.send` | List and send broadcasts | | `analytics.read` | Read analytics | | `payments.read` | Read your wallet, SMS balance and transactions | | `billing.read` | Read your plan, the plans for sale and plan invoices | | `webhooks.manage` | Add and manage [webhook](https://docs.goomzo.africa/docs/developers/webhooks?utm_source=llms&utm_medium=ai) endpoints, and see and resend deliveries | ## Secrets A new API key comes with its first secret. To add another, open the key and select **Create secret**, name it after where it's used, and choose when it expires: in 30 days, 90 days, a year, or never. An API key can have up to 10 secrets, so you can add a new one, switch your system over, then revoke the old one. Goomzo shows a secret only once, so copy it somewhere safe straight away. Send it with every request as a Bearer token: ```http Authorization: Bearer gzk_... ``` Or use Basic auth, with the key ID as the username and the secret as the password: ```bash curl -u "sva_...:gzk_..." https://api.goomzo.africa/v1/customers ``` Keep secrets out of your code and out of anything a customer's browser can see. If one leaks, select **Revoke** on it in the API key; it stops working right away. ## Key pairs If you'd rather not store a long-lived secret, use a key pair instead. Your system signs a short JWT with its private key and exchanges it for a token that lasts an hour. 1. In the API key, under **Advanced: key pairs**, select **Create key pair** to download a key file, or **Upload public key** to use your own Ed25519 key. Goomzo keeps only the public half. 2. Sign a JWT with the private key: ```text Header: { "alg": "EdDSA", "kid": "" } Claims: { "iss": "sva_...", "aud": "https://api.goomzo.africa/v1/oauth/token", "jti": "", "iat": , "exp": } ``` Each `jti` can be used only once. Add a `scope` claim, with permissions separated by spaces, to get a token with fewer permissions than the account. Use the `token_uri` from your key file as `aud`. Older key files name `https://app.goomzo.africa/v1/oauth/token`, which still works. 3. Exchange it for a token: ```bash curl https://api.goomzo.africa/v1/oauth/token \ -d grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer \ -d assertion=$SIGNED_JWT ``` ```json { "access_token": "gzt_...", "token_type": "Bearer", "expires_in": 3600, "scope": "customers.read" } ``` 4. Send `access_token` as a Bearer token until it expires, then sign a new JWT. An API key can have up to 10 active key pairs. --- # Safe retries > Retry a request without doing it twice. If a request times out or the connection drops, you can't tell whether it was done. Retrying it could add a customer twice or send a message twice. To retry safely, send an `Idempotency-Key` header. ```bash curl https://api.goomzo.africa/v1/messages \ -H "Authorization: Bearer $GOOMZO_TOKEN" \ -H "Idempotency-Key: 6f1c2d3e-order-1042-receipt" \ -H "Content-Type: application/json" \ -d '{"messages": [{"to": "+255712345678", "channel": "sms", "content": {"text": "Your order is ready."}}]}' ``` The key can be any text up to 255 characters without spaces. A request without the header, or with it empty, is done as normal, every time. A UUID, or an ID from your own system such as an order number, works well. ## How it works It works on any `POST`. The first request with a key is done as normal. For the next 24 hours, sending the same request with the same key doesn't do it again: you get the first answer back, with the header `Idempotent-Replayed: true`. | When you send the same key... | You get | | ------------------------------------------ | -------------------------------------------------------- | | With the same request | The first answer again, without doing it twice | | With a different request | `422 idempotency_key_reused`. Use a new key. | | While the first is still being answered | `409 idempotency_key_in_use`. Wait a moment and retry. | | After the first was refused (`4xx`) | The same error again. Fix the request and use a new key. | | After the first failed on our side (`5xx`) | The request is done again, as if new | Idempotency keys belong to each API key, so two systems can't clash by choosing the same one. Use a new one for each new thing you want done. --- # Rate limits > How many requests an API key can make. Each API key can make up to 600 requests a minute. The count starts again at the start of each minute. Every answer says where you stand: | Header | Value | | ----------------------- | ------------------------------------ | | `X-RateLimit-Limit` | Requests allowed each minute: `600` | | `X-RateLimit-Remaining` | Requests left this minute | | `X-RateLimit-Reset` | Seconds until the count starts again | The same is also given in the IETF's standard fields, which some HTTP clients read on their own: ```http RateLimit-Policy: "default";q=600;w=60 RateLimit: "default";r=598;t=42 ``` `r` is what's left and `t` the seconds until the count starts again. Past the limit, a request answers `429` with the code `rate_limited`, and a `Retry-After` header with the number of seconds to wait. Wait that long, then try again. The token endpoint, `POST /v1/oauth/token`, has no API key yet, so it counts by address instead: 60 requests a minute from each. ## Stay under the limit - **Send in bulk.** Use [import](https://docs.goomzo.africa/docs/help/import-customers?utm_source=llms&utm_medium=ai) to add many customers in one request, and a [broadcast](https://docs.goomzo.africa/docs/help/broadcasts?utm_source=llms&utm_medium=ai) to send the same message to up to 10,000 numbers. - **Use webhooks instead of checking.** Rather than asking whether each message was delivered, let [webhooks](https://docs.goomzo.africa/docs/developers/webhooks?utm_source=llms&utm_medium=ai) tell you. - **Ask for bigger pages.** Lists take a `limit` of up to 200. - **One key per system.** Each API key has its own limit, so give each system its own. --- # Errors > What a failed request returns, and how to handle it. A request that fails answers with an HTTP error status and a JSON body that says what went wrong. Use `code` in your own logic: it stays the same, while `message` is written for people and may change. ```json { "status": 400, "code": "invalid", "message": "Some fields are invalid.", "fields": { "phone": { "code": "invalid", "message": "Unsupported mobile number." } }, "requestId": "req_..." } ``` `fields` appears when the request's data wasn't valid, with a message for each field. Every response, failed or not, has the same request ID in its `X-Request-Id` header. Include it when you contact us. ## Common codes | Status | Code | What it means | | ------ | --------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- | | 400 | `invalid` | Some data isn't valid; see `fields`. | | 400 | `invalid_json` | The body isn't one valid JSON object, or has a field the endpoint doesn't take. | | 400 | `invalid_cursor` | The `cursor` isn't one a list gave you. Start from the first page. | | 400 | `invalid_limit` | `limit` isn't a whole number from 1. | | 400 | `invalid_status`, `invalid_channel`, `invalid_period`, `invalid_test` | A filter has a value the list doesn't know. | | 400 | `invalid_api_version` | `Goomzo-Version` isn't a version of the API. | | 400 | `invalid_idempotency_key` | The `Idempotency-Key` is too long or has spaces. | | 401 | `unauthenticated` | No secret was sent. | | 401 | `invalid_token` | The secret is wrong, expired or revoked. | | 403 | `missing_permission` | The API key doesn't have the permission this request needs. | | 403 | `not_for_service_accounts` | This endpoint is only for people signed in to Goomzo. | | 404 | `not_found` | The customer, segment or message doesn't exist. | | 404 | `route_not_found` | There's no such endpoint. Check the path. | | 405 | `method_not_allowed` | The endpoint doesn't take this method. | | 409 | `not_cancellable` | The message or broadcast has already started sending. | | 409 | `name_in_use` | Another segment already has this name. | | 409 | `segment_limit` | You already have 500 segments, or this would take you past them. | | 409 | `segment_fills_itself` | The segment is [automatic](https://docs.goomzo.africa/docs/help/segments?utm_source=llms&utm_medium=ai#automatic-segments): its rules decide who's in it. | | 409 | `segment_in_use` | Another segment's rules use this segment, so it can't be deleted yet. | | 409 | `rule_segment_limit` | You already have 50 automatic segments. | | 409 | `channel_unavailable` | Sending by this channel isn't set up yet. | | 409 | `too_many_endpoints` | You already have 10 [webhook](https://docs.goomzo.africa/docs/developers/webhooks?utm_source=llms&utm_medium=ai) endpoints. | | 409 | `endpoint_disabled` | The webhook endpoint is turned off, so it can't be sent events. | | 409 | `idempotency_key_in_use` | A request with this key is still being answered. Retry shortly. | | 413 | `body_too_large` | The request body is too large. | | 422 | `insufficient_sms` | There aren't enough SMS to send it; `needed` and `available` say how many. [SMS bundles](https://docs.goomzo.africa/docs/help/sms-bundles?utm_source=llms&utm_medium=ai). | | 422 | `too_many_to_export` | More than 50,000 customers match. Search or filter to export fewer. | | 422 | `rules_too_slow` | A segment's rules took too long to work out. Use fewer or simpler conditions. | | 422 | `idempotency_key_reused` | This key was used for a different request. [Use a new key](https://docs.goomzo.africa/docs/developers/idempotency?utm_source=llms&utm_medium=ai). | | 429 | `rate_limited` | Too many requests. Wait `Retry-After` seconds. [Rate limits](https://docs.goomzo.africa/docs/developers/rate-limits?utm_source=llms&utm_medium=ai). | | 500 | `internal` | Something went wrong on our side. Try again later. | ## Token errors The token endpoint, `/v1/oauth/token`, answers in the OAuth format instead, with status 400: ```json { "error": "invalid_grant", "error_description": "..." } ``` `error` is `invalid_request`, `unsupported_grant_type` or `invalid_grant`. --- # Get started > From an API key to your first message, step by step. This guide takes you from nothing to a message on a customer's phone and an event in your own system. It takes about ten minutes. ## Requirements - A Goomzo account. Only the organization's owner and admins can create API keys. - SMS on your account. See [SMS bundles](https://docs.goomzo.africa/docs/help/sms-bundles?utm_source=llms&utm_medium=ai). - A phone you can receive SMS on, to test with. ## Step 1: Create an API key 1. Open **Settings → API keys** and select **New API key**. 2. Name it after your system, such as **Shop**, and choose the **Messaging** bundle of permissions. 3. Save, and copy the secret. Goomzo shows it only once. Keep the secret in an environment variable, never in your code: ```bash export GOOMZO_TOKEN=gzk_... ``` ## Step 2: Add a customer ```bash curl https://api.goomzo.africa/v1/customers \ -H "Authorization: Bearer $GOOMZO_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "ifExists": "update", "customers": [{ "name": "Amina Juma", "phone": "+255712345678" }] }' ``` Use your own phone number, so you receive the message in step 4. ## Step 3: Create a template ```bash curl https://api.goomzo.africa/v1/templates \ -H "Authorization: Bearer $GOOMZO_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "auth_1", "channel": "sms", "category": "authentication", "content": { "text": "Hi {{name|there}}, your code is {{secret.code}}." } }' ``` `{{secret.code}}` is a value you pass when you send. Goomzo delivers it, but keeps it masked as `••••••`. ## Step 4: Send your first message ```bash curl https://api.goomzo.africa/v1/messages \ -H "Authorization: Bearer $GOOMZO_TOKEN" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: first-message-1" \ -d '{ "messages": [{ "to": "+255712345678", "template": "auth_1", "variables": { "code": "482913" } }] }' ``` Your phone receives "Hi Amina, your code is 482913." The answer shows the message with `"status": "sending"`. ## Step 5: Set up a webhook 1. Open **Settings → Webhooks** and select **New endpoint**. 2. Enter your HTTPS URL, and choose `message.delivered` and `message.failed`. 3. Select **Send test event** to check your receiver. Send another message: your URL receives `message.delivered` once it reaches the phone. ## Step 6: Finish You've authenticated, added a customer, created a template, sent a message and received its delivery. These are the building blocks of every Goomzo integration. ## Learn more - [Send messages](https://docs.goomzo.africa/docs/developers/messages/send?utm_source=llms&utm_medium=ai): SMS and WhatsApp, one at a time or up to 100 together. - [Send templates](https://docs.goomzo.africa/docs/developers/messages/templates?utm_source=llms&utm_medium=ai): your own values, and private ones. - [WhatsApp templates](https://docs.goomzo.africa/docs/developers/templates/create?utm_source=llms&utm_medium=ai): write templates for Meta to review. - [Webhooks](https://docs.goomzo.africa/docs/developers/webhooks?utm_source=llms&utm_medium=ai): every event, and how to check signatures. - [Safe retries](https://docs.goomzo.africa/docs/developers/idempotency?utm_source=llms&utm_medium=ai): retry without sending twice. --- # TypeScript SDK > The Goomzo API for TypeScript and JavaScript. `@goomzo/sdk` is the Goomzo API for TypeScript and JavaScript. It types every request and answer, retries safely, and pages through lists for you. It has no dependencies, and runs anywhere with `fetch`. ## Requirements - Node 20 or later, Bun, Deno, Cloudflare Workers or Vercel Edge. - An API key. See [Authentication](https://docs.goomzo.africa/docs/developers/authentication?utm_source=llms&utm_medium=ai). ## Install ```bash npm install @goomzo/sdk ``` ## Make your first request Set your API key's secret as `GOOMZO_API_KEY`, then send a message: ```ts import { Goomzo } from '@goomzo/sdk' const goomzo = new Goomzo() const message = await goomzo.messages.sendOne({ to: '+255712345678', channel: 'sms', content: { text: 'Amina, order #1042 is ready.' }, }) console.log(message.id, message.status) ``` ## What it does for you - **Types:** every request and answer is typed, made from the API's own description. - **A fixed version:** it pins the API version it was written for, so a new version never changes what your code gets. - **Safe retries:** network errors, `429` and `5xx` are tried again, twice by default. Every `POST` carries an `Idempotency-Key`, the same on each try, so nothing is done twice. - **Lists:** await a list for one page, or loop over it with `for await` for every item. - **Errors you can act on:** a `GoomzoError` has the `status`, the `code`, the `fields` that were wrong and the `requestId`. ## Next steps --- # Python SDK > The Goomzo API for Python, sync and asyncio. `goomzo` is the Goomzo API for Python. It types every request and answer, retries safely, and pages through lists for you. It works the same way with or without asyncio. ## Requirements - Python 3.10 or later. - An API key. See [Authentication](https://docs.goomzo.africa/docs/developers/authentication?utm_source=llms&utm_medium=ai). ## Install ```bash pip install goomzo ``` ## Make your first request Set your API key's secret as `GOOMZO_API_KEY`, then send a message: ```python from goomzo import Goomzo goomzo = Goomzo() message = goomzo.messages.send_one({ 'to': '+255712345678', 'channel': 'sms', 'content': {'text': 'Amina, order #1042 is ready.'}, }) print(message['id'], message['status']) ``` With asyncio, use `AsyncGoomzo` and await each call: ```python from goomzo import AsyncGoomzo goomzo = AsyncGoomzo() message = await goomzo.messages.send_one({'to': '+255712345678', 'channel': 'sms', 'content': {'text': 'Hi'}}) ``` ## How it reads - **Requests and answers are dicts,** with the API's own keys, exactly as in its JSON, such as `customerId` and `sendAt`. Each is a typed dict, so your editor completes and checks them. - **Arguments are Python,** such as `limit=200` or `if_exists='update'`. - **Lists of results come back as lists.** Lists that can be long come as a [page](https://docs.goomzo.africa/docs/developers/python-sdk/lists?utm_source=llms&utm_medium=ai) you can loop over. ## What it does for you - **A fixed version:** it pins the API version it was written for, so a new version never changes what your code gets. - **Safe retries:** network errors, `429` and `5xx` are tried again, twice by default. Every `POST` carries an `Idempotency-Key`, the same on each try, so nothing is done twice. - **Errors you can act on:** a `GoomzoError` has the `status`, the `code`, the `fields` that were wrong and the `request_id`. ## Next steps --- # PHP SDK > The Goomzo API for PHP. `goomzo/goomzo-php` is the Goomzo API for PHP. It retries safely, pages through lists for you, and turns errors into exceptions you can act on. It works with Laravel, Symfony or plain PHP. ## Requirements - PHP 8.1 or later, with Composer. - An API key. See [Authentication](https://docs.goomzo.africa/docs/developers/authentication?utm_source=llms&utm_medium=ai). ## Install ```bash composer require goomzo/goomzo-php ``` ## Make your first request Set your API key's secret as `GOOMZO_API_KEY`, then send a message: ```php use Goomzo\Goomzo; $goomzo = new Goomzo(); $message = $goomzo->messages->sendOne([ 'to' => '+255712345678', 'channel' => 'sms', 'content' => ['text' => 'Amina, order #1042 is ready.'], ]); echo $message['id'], ' ', $message['status']; ``` ## How it reads - **Requests and answers are arrays,** with the API's own keys, exactly as in its JSON, such as `customerId` and `sendAt`. They match the requests in these docs one for one. - **Options are named arguments,** such as `idempotencyKey: 'order-1042'`. - **Lists that can be long come as a [page](https://docs.goomzo.africa/docs/developers/php-sdk/lists?utm_source=llms&utm_medium=ai)** you can loop over. ## What it does for you - **A fixed version:** it pins the API version it was written for, so a new version never changes what your code gets. - **Safe retries:** network errors, `429` and `5xx` are tried again, twice by default. Every `POST` carries an `Idempotency-Key`, the same on each try, so nothing is done twice. - **Errors you can act on:** an `ApiException` has the `status`, the `errorCode`, the `fields` that were wrong and the `requestId`. ## Next steps --- # Go SDK > The Goomzo API for Go. `github.com/goomzo/goomzo-go` is the Goomzo API for Go. It types every request and answer, retries safely within your context's deadline, and pages through lists for you. It needs nothing beyond the standard library. ## Requirements - Go 1.24 or later. - An API key. See [Authentication](https://docs.goomzo.africa/docs/developers/authentication?utm_source=llms&utm_medium=ai). ## Install ```bash go get github.com/goomzo/goomzo-go ``` ## Make your first request Set your API key's secret as `GOOMZO_API_KEY`, then send a message: ```go package main import ( "context" "fmt" "log" "github.com/goomzo/goomzo-go" ) func main() { client, err := goomzo.NewClient() if err != nil { log.Fatal(err) } msg, err := client.Messages.SendOne(context.Background(), goomzo.MessageInput{ To: "+255712345678", Channel: goomzo.SMS, Content: &goomzo.Content{Text: "Amina, order #1042 is ready."}, }) if err != nil { log.Fatal(err) } fmt.Println(msg.ID, msg.Status) } ``` ## How it reads - **Every call takes a context.** Cancel it, or give it a deadline, to stop a call and its retries. - **Requests and answers are structs,** with the API's fields. A field that can be empty in an answer is a pointer, such as `Message.Error`. - **Lists are iterators.** Range over one for every item, or ask for one [page](https://docs.goomzo.africa/docs/developers/go-sdk/lists?utm_source=llms&utm_medium=ai). ## What it does for you - **A fixed version:** it pins the API version it was written for, so a new version never changes what your code gets. - **Safe retries:** network errors, `429` and `5xx` are tried again, twice by default. Every `POST` carries an `Idempotency-Key`, the same on each try, so nothing is done twice. - **Errors you can act on:** an `*APIError` has the `Status`, the `Code`, the `Fields` that were wrong and the `RequestID`. ## Next steps --- # Messages > How Goomzo sends SMS and WhatsApp messages, and how you follow them. A message is one SMS or WhatsApp message to one person. Your system sends it, Goomzo queues it and hands it to the network, and its status changes as it goes. To send the same message to many people, use a [broadcast](https://docs.goomzo.africa/docs/developers/messages/broadcasts?utm_source=llms&utm_medium=ai). ## Channels | Channel | Goes from | Paid by | | ---------- | ----------------------------------------------- | ------------------------------------- | | `sms` | Your approved sender ID, or Goomzo's shared one | The SMS on your Goomzo account | | `whatsapp` | Your own connected WhatsApp number | Your WhatsApp account, billed by Meta | ## Ways to send - **Content:** text you write in the request, such as an order update. - **A saved template:** a template's name and the values it needs. See [Send templates](https://docs.goomzo.africa/docs/developers/messages/templates?utm_source=llms&utm_medium=ai). - **A WhatsApp template directly:** a template on your WhatsApp account, by its id. ## Statuses | Status | Meaning | | ----------- | ------------------------------------------------------------------- | | `waiting` | A WhatsApp reply held until the customer opens the chat. See below. | | `scheduled` | Waiting for its `sendAt` time. | | `sending` | Queued, or with the network. | | `sent` | The network took it. | | `delivered` | It reached the phone. | | `read` | The customer read it. WhatsApp only. | | `failed` | It couldn't be sent or delivered. `error` says why. | | `canceled` | You canceled it before it went. | Follow statuses with [webhooks](https://docs.goomzo.africa/docs/developers/webhooks?utm_source=llms&utm_medium=ai) rather than asking again and again. ## WhatsApp customer service windows WhatsApp lets you send free text only within 24 hours of the customer's last message. Outside that window: - **Text you send waits.** Goomzo sends your reply template ("we have replied to the message you sent us on…") and your text goes once the customer opens the chat. It shows as `waiting` until then, and fails after 7 days. - **To write first, or to schedule,** send an approved WhatsApp template instead. **Note:** Someone who has never written to your WhatsApp number can only get a template. ## Private messages A message sent with `{{secret.x}}` values is `private`: the customer gets the values, while Goomzo keeps and shows them as `••••••`, in the dashboard, the API and webhooks. See [Send templates](https://docs.goomzo.africa/docs/developers/messages/templates?utm_source=llms&utm_medium=ai). ## Next steps - [Send messages](https://docs.goomzo.africa/docs/developers/messages/send?utm_source=llms&utm_medium=ai) - [Send templates](https://docs.goomzo.africa/docs/developers/messages/templates?utm_source=llms&utm_medium=ai) - [Broadcasts](https://docs.goomzo.africa/docs/developers/messages/broadcasts?utm_source=llms&utm_medium=ai) --- # Send messages > Send SMS and WhatsApp messages, one to each person, up to 100 at a time. Send one message to each person, by SMS or WhatsApp, now or at a time you choose. Send up to 100 in one request: they're queued all or none. ## Requirements - An API key with the `messages.send` permission. - For SMS, enough SMS on your account. For WhatsApp, your number connected. ## Requests ```text POST /v1/messages ``` ### Request syntax ```json { "messages": [ { "to": "", "customerId": "", "channel": "", "from": "", "content": { "text": "" }, "template": "", "variables": { "": "" }, "sendAt": "