Use a Playwright action to submit a form on a portal that has no API, such as an RMA request, with an approval before it runs
Let the SuperIT agent submit a form on a vendor's website for you, such as a hardware return (RMA) request, a fault report to a connectivity provider, or a new user in a line-of-business portal, when the vendor has no API. A Playwright workflow action signs in, fills in the fields, submits and returns the reference number. For MSPs and IT teams who retype the same details into vendor portals every week.
| Runs in | Cloud sandbox (Playwright) |
| Uses | API key credential (portal username and password stored as custom headers) |
| Suggested approval | Require approval from a lead (for example superit:service-leads) |
| Category | Browser automation |
Test it with SuperIT before you rely on it
This is an example, not a ready-made action, and it hasn't been tested end to end. The portal address, field labels and confirmation text are placeholders: every portal needs its own. Before you use it, work through it with SuperIT: ask SuperIT to review the script against your environment and requirements, and adjust it together. Then test it, as in Test it. Test in the action editor isn't a dry run: it runs the script for real.
Why use an action instead of asking SuperIT
SuperIT has no web browser, so it can't sign in to a vendor portal or submit a form there. A Playwright action does it headlessly in the cloud sandbox, with the portal login stored as an encrypted credential, and only after a lead approves the run. It submits the form, such as an RMA request, and returns the case number. To draft the fault description or check what's already on the ticket, just ask SuperIT in chat instead; it reads the ticket and the device natively.
When to use it
- "The PSU in SRV-HV02 has failed. Raise an RMA with the vendor."
- "Log a fault with the line provider for the Leeds office: no sync since 08:00."
- "Request a replacement for this switch, it's under warranty."
The SuperIT agent already has most of the details from the ticket and the device, so the engineer only confirms them.
What the action does
- Checks the inputs and the required confirmation switch.
- Signs in to the portal with the username and password from the linked credential.
- Opens the new RMA form and fills in the serial number, fault, contact and delivery details.
- Submits the form and waits for the confirmation page.
- Reads the RMA number from the page and returns it, so SuperIT can add it to the ticket.
What it doesn't do:
- It doesn't check warranty first. Run Look up device warranty before submitting.
- It doesn't retry a submission. If it fails after clicking Submit, check the portal before running it again, so you don't raise the request twice.
- It doesn't upload photos or attachments.
- It doesn't track the RMA afterwards.
Before you begin
- A portal account that is allowed to raise requests, ideally used only by SuperIT.
- A credential. Under Workflows → Credentials, select New, name it
Vendor Portaland choose Custom HTTP headers (under Advanced). Add rowsusernameandpassword. The script reads them asCREDENTIAL_VENDOR_PORTAL_USERNAMEandCREDENTIAL_VENDOR_PORTAL_PASSWORD. See Credentials. If the portal needs an authenticator code, see the Variations in Download a report from a vendor portal. - An authorization policy, because the action commits you to something with a vendor. Under Workflows → Authorization policies, create one with Requester Specific groups
superit:engineersand Approver Require approval fromsuperit:service-leads. Approvers get an email and can approve in the app or in chat. Approvals expire after 7 days. See Approvals. - Your role. Creating an action in chat needs the Admin role. Engineers can build it by hand under Workflows → Actions. Creating a policy needs the Admin role.
Build it with SuperIT
Create an action called "Raise vendor RMA".
Purpose: sign in to https://portal.vendor.example, open Support > New RMA, fill in the form, submit, and return the RMA number.
Runtime: Playwright/Python in the cloud sandbox.
Inputs: serial (string, required), fault (textarea, required), contact_name (string, required), contact_phone (string, required), delivery_address (textarea, required), confirm (boolean, required: "I confirm these details are correct").
Credential: "Vendor Portal" (custom headers username and password).
Form labels: "Serial number", "Fault description", "Contact name", "Contact phone", "Delivery address"; button "Submit request". Confirmation page shows "RMA number: RMA-123456".
It writes: submits one RMA request. Never print the password.
Authorization policy: engineers request, service leads approve.
SuperIT confirms exactly what the action submits, drafts the script, validates it and creates the action as a draft. You review it, test it and publish it under Workflows → Actions.
Or build it yourself
| Name | Type | Required | Example |
|---|---|---|---|
serial |
string | Yes | 7XK2M93 |
fault |
textarea | Yes | PSU 2 failed. Amber light, server on PSU 1 only. |
contact_name |
string | Yes | Jo Smith |
contact_phone |
string | Yes | +44 113 496 0000 |
delivery_address |
textarea | Yes | Unit 4, Example Park, Leeds LS1 1AA |
confirm |
boolean | Yes | on |
A required boolean must be switched on before the action runs, so it works as an acknowledgement. Set Runtime to Playwright/Python. The script follows the same shape as Download a report from a vendor portal: main first, one small function per step, and output = await main(...) at the bottom.
# Goal: sign in to the vendor portal, submit one RMA request with the given details, and return its RMA number.
import os
import re
PORTAL = "https://portal.vendor.example"
FIELDS = {"serial": "Serial number", "fault": "Fault description",
"contact_name": "Contact name", "contact_phone": "Contact phone",
"delivery_address": "Delivery address"}
async def main(values, confirm):
check_inputs(values, confirm)
username, password = read_credential()
await sign_in(username, password)
await fill_rma_form(values)
rma = await submit_and_read_rma_number()
print(f"=== RMA RAISED ===\nSerial : {values['serial']}\nRMA number : {rma}")
return {"serial": values["serial"], "rma_number": rma}
def check_inputs(values, confirm):
# A boolean input arrives as the string "true" or "false", so compare it explicitly.
if confirm != "true":
raise RuntimeError("The confirmation switch must be on.")
missing = [k for k, v in values.items() if not v]
if missing:
raise RuntimeError(f"Missing inputs: {', '.join(missing)}")
if not re.fullmatch(r"[A-Za-z0-9-]{4,30}", values["serial"]):
raise RuntimeError("Serial number contains unexpected characters.")
def read_credential():
username = os.environ.get("CREDENTIAL_VENDOR_PORTAL_USERNAME")
password = os.environ.get("CREDENTIAL_VENDOR_PORTAL_PASSWORD")
if not username or not password:
raise RuntimeError("The 'Vendor Portal' credential is missing username or password.")
return username, password
async def sign_in(username, password):
await page.goto(f"{PORTAL}/login", wait_until="domcontentloaded")
await page.get_by_label("Email").fill(username)
await page.get_by_label("Password").fill(password)
await page.get_by_role("button", name="Sign in").click()
await page.wait_for_url("**/dashboard**", timeout=30000)
print("Signed in.")
async def fill_rma_form(values):
await page.goto(f"{PORTAL}/support/rma/new", wait_until="domcontentloaded")
for key, label in FIELDS.items():
await page.get_by_label(label).fill(values[key])
print("Form filled. Submitting.")
async def submit_and_read_rma_number():
await page.get_by_role("button", name="Submit request").click()
# .first: the label can appear more than once on the page, which would make a plain locator ambiguous.
await page.get_by_text("RMA number").first.wait_for(timeout=60000)
match = re.search(r"RMA number:\s*([A-Z0-9-]+)", await page.inner_text("body"))
if not match:
raise RuntimeError("Submitted, but no RMA number was found. Check the portal before retrying.")
return match.group(1)
output = await main(
values={key: (input_context.get(key) or "").strip() for key in FIELDS},
confirm=input_context.get("confirm"),
)
The script prints a line before submitting. If a run fails after "Submitting.", the request may have gone through; check the portal before running it again.
Test it
- Ask the vendor whether the portal has a test or sandbox mode. If it doesn't, plan to test with a real request you need anyway, or cancel the test request with the vendor afterwards.
- Save the draft and select Test.
- Test is not a dry run: it skips authorization and approvals, uses the real credential and network access, and submits a real request to the vendor. Test runs aren't billed.
- Check the RMA number in Stdout matches the portal.
- Select Publish.
Use it
- In chat: "The PSU in SRV-HV02 has failed, raise an RMA." SuperIT checks the warranty, gathers the serial, fault and site details from the ticket and device, confirms them with you, and runs the action. The run waits for a service lead's approval, then submits.
- From a ticket: link the run to the ticket so approval, completion and error notes post to the PSA ticket automatically.
- Managed teams: usually the service provider holds the vendor account, so keep this action in the service provider team.
Variations
- Guest Wi-Fi voucher: create a time-limited voucher in a cloud-managed Wi-Fi controller's portal and return the code. An end user who requests a run sees a redacted view of its output (see End users and approvals), so have the code sent to the guest by another route, such as a message to reception.
- Connectivity fault: fill in the provider's fault form with the circuit ID and the outage time from the ticket.
- Line-of-business user: add a new starter to a portal with no SCIM or API, with the role taken from Look up a new starter in your HR system.