Zoho Creator — Payment Status Console

A single console in Zoho Creator to track invoice status and trigger one-click actions (SMS, WhatsApp, payment link) that speed up collections.

Zoho Creator — Payment Status Console

What this console does

A finance agent opens one place in Zoho Creator to see unpaid invoices and click one of three row actions: SEND SMS (via Twilio), SEND WHATSAPP (via Superchat/BSP), and Send Tabby Payment Link. The app generates a secure payment link, sends it through the selected channel, tracks attempts, and updates status automatically when the customer pays.

How it works (end-to-end)

  1. Agent clicks a row action. Creator runs a server function (Deluge) so keys/tokens never touch the browser.
  2. For Tabby, the function calls the Payments API to create a one-time link (amount, currency, invoice ref, customer info). The link & expiry are saved on the record.
  3. The same function sends the link by SMS (Twilio) or WhatsApp(Superchat/BSP) using Creator Connections (secure auth).
  4. When the customer pays, a webhook from the PSP hits a Creator endpoint, which flips the status to Completed, stamps the time, and logs a receipt.
  5. A post-payment routine writes back to Zoho Books (record payment against the invoice) and updates Zoho CRM (contact’s last_payment fields, notes).

Data model (key fields)

Integrations (Creator Connections + APIs)

Deluge Function

1) Create a Tabby link, store it, and send by SMS

// Assume this runs in a Creator workflow or page action
inv_no = input.Invoice_Number;
amount = input.Amount;
currency = input.Currency;
customer_phone = input.Phone;
customer_name = input.Name;

// 1) Create payment link (Tabby)
payload = {
  "amount": amount,
  "currency": currency,
  "buyer": {"phone": customer_phone, "name": customer_name},
  "order": {"reference_id": inv_no}
};
tabby_resp = invokeurl
[
  url: "<TABBY_BASE>/payments/links"   // configured in your Connection
  type: POST
  content-type: "application/json"
  body: payload.toString()
  connection: "tabby_conn"
];
link = tabby_resp.get("url");
expiry = tabby_resp.get("expires_at");

// Persist on the record
input.Payment_Link = link;
input.Expires_At = expiry;
input.Payment_Status = "Sent";
input.Attempts = ifnull(input.Attempts,0) + 1;
input.Channel = "SMS";

// 2) Send SMS (Twilio)

// === Twilio creds & message (replace with your values or app variables) ===
account_sid = "ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
api_key     = "SKxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";   // API Key SID (recommended)
api_secret  = "your_api_key_secret";                  // API Key Secret
from_num    = "+1XXXXXXXXXX";                         // your Twilio number (or use MessagingServiceSid)
to_num      = "+9715XXXXXXXX";
body_text   = "Your invoice INV-0004 is ready. Pay: https://example.com/pay/INV-0004";

// === Endpoint (same as cURL) ===
url_str = "https://api.twilio.com/2010-04-01/Accounts/" + account_sid + "/Messages.json";

// === Form fields (urlencoded) ===
params = Map();
params.put("To",   to_num);
params.put("From", from_num);                         // OR: params.put("MessagingServiceSid","MGxxxxxxxxxxxxxxxxxxxx");
params.put("Body", body_text);

// === Basic Auth header: "Basic base64(api_key:api_secret)" ===
auth_header = "Basic " + base64Encode(api_key + ":" + api_secret);

resp = invokeurl
[
    url       : url_str
    type      : POST
    parameters: params                            // sends as application/x-www-form-urlencoded
    headers   : {"Authorization": auth_header}
];

// Twilio returns JSON with fields like sid, status, error_code, error_message
sid = resp.get("sid");
if(sid != null)
{
    info "SMS queued. SID: " + sid;
}
else
{
    info "Twilio error: " + resp;
}

2) Send the same link via WhatsApp (Superchat/BSP)

header = {"X-API-KEY": "auth_12394ru02wdoncn3d034"};

params = {
  "to": [
    {
      "identifier": "hello@superchat.de"
    }
  ],
  "from": {
    "channel_id": "mc_12394ru02wdoncn3d034",
    "name": "Jane Smith"
  },
  "content": {
    "type": "text",
    "body": "Hi " + customer_name + ", pay invoice " + inv_no + " here: " + link"
  },
  "in_reply_to": "string"
}
wa_resp = invokeurl
[
  url: "https://api.superchat.com/v1.0/messages"
  type: POST
  parameters: params.toString()
  headers: header
];

3) Function to mark as Completed in Books/CRM

// Expose this as a Creator API endpoint; verify signature from provider!
status = param("status");
inv_ref = param("order_reference") ?: "";
rec = Payment_Status[Invoice_Number == inv_ref];

if(rec != null)
{
  if(status == "PAID")
  {
    rec.Payment_Status = "Completed";
    rec.Paid_At = zoho.currenttime;

    // Zoho Books: record payment
    books_resp = invokeurl
    [
      url: "https://books.zoho.com/api/v3/customerpayments"
      type: POST
      parameters: {"customer_id": rec.Customer_ID, "amount": rec.Amount, "invoices":[{"invoice_id": rec.Invoice_ID,"amount_applied": rec.Amount}]}.toString()
      connection: "zohobooks_conn"
    ];

    // Zoho CRM: update contact payment info
    data = {"Last_Payment_Status":"Completed","Last_Payment_At":rec.Paid_At};
    crm_resp = zoho.crm.updateRecord("Contacts", data, "zohocrm_conn");
  }
}

Operational niceties

User flow (what I demo)

  1. Filter by status = Generated, pick an invoice, click Send Tabby Payment Link.
  2. Link is created, saved, and sent by WhatsApp or SMS; status flips to Sent.
  3. Payment completes; webhook marks Completed, Books gets a Customer Payment, CRM is updated.