Skip to content

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 ​

  1. Create a workflow (see Building workflows) and set the trigger's Starts when to When a form or app posts to a URL.
  2. Fill in the trigger's settings (below), add the steps that should run, and connect them.
  3. Publish the workflow. Posts only start it while it is Active.
  4. In the trigger's panel, find the Workflow URL box and click Create URL.
  5. 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_Qm9yZGVyLWZvcm0tZXhhbXBsZS10b2tlbi0wMDAxMjM

The 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>:

json
{ "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:

SettingWhat it does
Contact's phoneWhere to find the phone number in what was posted, for example trigger.phone. Type the expression with no {{ }} braces.
Contact's nameWhere to find the name, for example trigger.name. Used only when a new contact is created.
Add new phone numbers as contactsTick 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"
  • Step: Send SMS
    • To: {{ contact.phone }}
    • Message: Welcome to the gym, {{ contact.name }}! Your first session is on us.
  • Connect the trigger to Send SMS, then Publish and create the URL.

The form on your website

html
<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):

json
{
  "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"
  • Step: Send SMS
    • To: {{ trigger.customer.phone }}
    • Message: Thanks {{ trigger.customer.name }}, we received UGX {{ trigger.amount }} for order {{ trigger.orderId }}.
  • 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-paid

Posting 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.

bash
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:

bash
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:

json
{ "accepted": true, "runId": "c9a3f5de-2b7f-4f60-9a58-0b0c2f2c6a31" }

When the post was understood but started nothing:

json
{ "accepted": false, "reason": "filtered" }
reasonWhy
filteredOnly when was not true for this post
suppressedThe contact is in a Never enter if in group
already_activeThe contact is already going through this workflow
already_enteredThey have been through it, and Can a contact go through again? is Only once
reentry_windowThey went through it too recently to go through again

Other replies:

StatusMeaning
400The body is not a JSON object or form fields
404The URL is wrong or was replaced, or the workflow is not Active (published and not paused)
409The live version of the workflow no longer starts from a URL
413The post is over 64 KB
429More 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 ​

Released under the MIT License.