Start a workflow from your own system or a form
Every workflow that starts with When a form or app posts to a URL gets its own secret web address. Anything that can send an HTTP POST to it (a website form, an online shop, a payment provider, Zapier, a script) starts the workflow, with no API key and no code on MsGine's side.
This guide uses the dashboard. Developers can manage the same URLs over the API; see Workflow URLs in the Workflows API reference.
Set it up
- Create a workflow (see Building workflows) and set the trigger's Starts when to When a form or app posts to a URL.
- Fill in the trigger's settings (below), add the steps that should run, and connect them.
- Publish the workflow. Posts only start it while it is Active.
- In the trigger's panel, find the Workflow URL box and click Create URL.
- Copy the URL straight away. For your security MsGine keeps only a hash of it, so it is shown once and cannot be shown again.
The URL looks like this:
https://api.msgine.net/api/v1/hooks/wfh_Qm9yZGVyLWZvcm0tZXhhbXBsZS10b2tlbi0wMDAxMjMThe long part is the secret. Anyone who has the whole URL can start your workflow, so keep it out of public places you cannot afford to leak it from.
What can be posted
The body of the post is either a JSON object or ordinary form fields. Each field becomes available to the workflow as trigger.<field name>:
{ "phone": "0701234567", "name": "Amina", "plan": "gold" }becomes trigger.phone, trigger.name and trigger.plan. Nested JSON is reachable too, for example trigger.customer.phone. Use plain field names made of letters, digits and underscores.
Form fields always arrive as text, even when they look like numbers. If you need to compare numbers, post JSON.
The body can be at most 64 KB.
Contact options
On the trigger step, three boxes decide who the run is about:
| Setting | What it does |
|---|---|
| Contact's phone | Where to find the phone number in what was posted, for example trigger.phone. Type the expression with no {{ }} braces. |
| Contact's name | Where to find the name, for example trigger.name. Used only when a new contact is created. |
| Add new phone numbers as contacts | Tick to save the phone as a new contact when you do not have it yet. |
The phone is matched to your contacts however it was typed: 0701234567, 256701234567 and +256701234567 are the same person. When a contact is found or created, the run is about that contact, so {{ contact.name }} works in your messages and your workflow settings (Can a contact go through again?, Never enter if in, goals) apply.
Good to know:
- Only Ugandan mobile numbers (
+2567XXXXXXXX) are added as new contacts. - You must set Contact's phone to use the other two settings.
- If there is no phone in the post, the phone is not a valid number, or no contact has it and you left Add new phone numbers as contacts off, the workflow still starts, but without a contact. Steps that need a contact, such as Update contact or Add to group, then fail, and
{{ contact.phone }}is empty. Send to the posted number directly with{{ trigger.phone }}in that case.
Only when
Only when limits which posts start the workflow. It is one expression with no braces, evaluated on the posted fields:
trigger.form == "signup"A post that does not pass starts nothing (the caller still gets a normal reply; see Testing). This is how you serve several forms from one workflow, or ignore events such as status == "pending" from a provider that posts for every change.
Example: a website form
You run a gym and want to text new sign-ups a welcome message.
The workflow
- Trigger: When a form or app posts to a URL
- Contact's phone:
trigger.phone - Contact's name:
trigger.name - Tick Add new phone numbers as contacts
- Only when:
trigger.form == "signup"
- Contact's phone:
- Step: Send SMS
- To:
{{ contact.phone }} - Message:
Welcome to the gym, {{ contact.name }}! Your first session is on us.
- To:
- Connect the trigger to Send SMS, then Publish and create the URL.
The form on your website
<form method="POST" action="https://api.msgine.net/api/v1/hooks/wfh_YOUR_TOKEN">
<input type="hidden" name="form" value="signup">
<input type="text" name="name" placeholder="Your name" required>
<input type="tel" name="phone" placeholder="0701234567" required>
<button type="submit">Join</button>
</form>Things to know about forms:
- When a visitor submits a plain HTML form, their browser shows MsGine's short reply (
{"accepted":true,...}) as a new page. To keep visitors on your own page, post from your own server, or submit the form in the background (for example into a hidden iframe). - Calls made by JavaScript running on your website go through the browser's cross-origin rules, and MsGine does not allow arbitrary websites. Use a plain form like the one above, or post from your server.
- Anyone can read the URL in your page's source, and each post can send a charged message. The URL is limited to 120 posts a minute, but for anything valuable post from your server instead, and if the URL is ever abused, replace it.
Example: a shop or payment callback
Online shops and payment providers can call a URL when something happens. Suppose your provider posts this when an order is paid (your provider's field names will differ; use whatever it actually sends):
{
"event": "order.paid",
"status": "paid",
"orderId": "A-1042",
"amount": 85000,
"customer": { "name": "Amina", "phone": "0701234567" }
}The workflow
- Trigger: When a form or app posts to a URL
- Contact's phone:
trigger.customer.phone - Contact's name:
trigger.customer.name - Tick Add new phone numbers as contacts
- Only when:
trigger.status == "paid"
- Contact's phone:
- Step: Send SMS
- To:
{{ trigger.customer.phone }} - Message:
Thanks {{ trigger.customer.name }}, we received UGX {{ trigger.amount }} for order {{ trigger.orderId }}.
- To:
- In Workflow settings, set Message type to Transactional, so the receipt is never held back by quiet hours or a daily limit.
Paste the Workflow URL into the provider's "webhook" or "callback URL" setting.
Stop duplicates with Idempotency-Key
Providers resend callbacks when they do not get a quick reply, and a double post would send a double SMS. Add an Idempotency-Key header holding something that identifies the event, such as the order id:
Idempotency-Key: order-A-1042-paidPosting the same key again starts nothing new: MsGine replies with the original run. Keys are remembered per workflow. Keep them under 95 characters.
Many providers cannot add custom headers. In that case have a small piece of your own code receive the callback and forward it to the Workflow URL with the header set. If you post from your own code anyway, always set the header.
Test it with curl
Posts are always live
A post to a Workflow URL always runs for real: it sends real messages and charges your balance. There is no sandbox mode on this route. While testing, use your own phone number.
curl -X POST "https://api.msgine.net/api/v1/hooks/wfh_YOUR_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: test-001" \
-d '{ "form": "signup", "name": "Amina", "phone": "0701234567" }'A form-style post works too:
curl -X POST "https://api.msgine.net/api/v1/hooks/wfh_YOUR_TOKEN" \
-d "form=signup" -d "name=Amina" -d "phone=0701234567"The reply is always status 202. When a run started:
{ "accepted": true, "runId": "c9a3f5de-2b7f-4f60-9a58-0b0c2f2c6a31" }When the post was understood but started nothing:
{ "accepted": false, "reason": "filtered" }reason | Why |
|---|---|
filtered | Only when was not true for this post |
suppressed | The contact is in a Never enter if in group |
already_active | The contact is already going through this workflow |
already_entered | They have been through it, and Can a contact go through again? is Only once |
reentry_window | They went through it too recently to go through again |
Other replies:
| Status | Meaning |
|---|---|
400 | The body is not a JSON object or form fields |
404 | The URL is wrong or was replaced, or the workflow is not Active (published and not paused) |
409 | The live version of the workflow no longer starts from a URL |
413 | The post is over 64 KB |
429 | More than 120 posts in a minute to this workflow |
After a successful post, open the workflow's Runs tab to see the run and its Run timeline.
Replace the URL
If the URL leaks, or you simply want a new one, open the trigger's panel and click Make a new URL, then confirm. The old URL stops working immediately and the new one is shown once, so update every form and provider that used the old one. Pausing the workflow also stops it responding, with a 404, until you resume.
Your own top-ups: payment.completed
You do not need a Workflow URL to react to money arriving in your MsGine balance. Choose the trigger When something happens in MsGine, set Event to Payment completed and, in Only when, trigger.type == 'credit'. The event provides amount, currency, phone (the number on the account's payment, which can be empty), name, email, reference and transactionId, so a Send SMS step can use {{ trigger.phone }}, {{ trigger.amount }} and {{ trigger.reference }}. Events about payments are not about a contact, so use the trigger fields rather than contact.
Next steps
- Build the workflow: Building workflows
- Every field and limit: Workflows API