Mechanic is a development and ecommerce automation platform for Shopify. :)
Create a Shopify draft order from the cart submitted with a Mechanic storefront form. Signed-in customers are linked to their verified Shopify customer account. Shopify supplies current variant prices; review the draft before sending an invoice.
Runs . Configuration includes mechanic webhook event topic, form, and email field key.
Create a Shopify draft order from the cart submitted with a Mechanic storefront form. Signed-in customers are linked to their verified Shopify customer account. Shopify supplies current variant prices; review the draft before sending an invoice.
Shopify signs the customer context when rendering the form, and this task verifies it before linking the customer. Form submissions use the ordinary webhook. Guests supply their contact email; entering an email is not verification of a customer account.
The form acknowledges that the request was received. Draft order creation happens asynchronously; the task does not send an invoice or change/clear the cart. Notes include the form answers and uploaded file names, not the file contents. Use the email or Google Sheets/Drive task on the same webhook if you also want those files.
Supports 1–100 ordinary variant lines, quantities, and line item properties. Subscription and bundle items are rejected for separate review. Cart discounts, shipping rates, and displayed prices are not copied. Submitted cart data is visitor input, not proof of a previous purchase. An explicit retry after an uncertain response can create another draft order.
Form signing is configured automatically when you publish. A stale page refreshes its signed customer context through Shopify. If the task cannot verify that context, it stops without creating a draft order; it does not silently switch a signed-in customer to a guest.
Mechanic is designed to benefit everybody: merchants, customers, developers, agencies, Shopifolks, everybody.
That’s why we make it easy to configure automation without code, why we make it easy to tweak the underlying code once tasks are installed, and why we publish it all here for everyone to learn from.
(By the way, have you seen our documentation? Have you joined the Slack community?)
{{ options.mechanic_webhook_event_topic__required }}{% comment %}
{{ options.mechanic_webhook_event_topic__required }}
{{ options.form__storefrontform_required }}
{{ options.email_field_key }}
{% endcomment %}
{% if event.topic != options.mechanic_webhook_event_topic__required %}{% break %}{% endif %}
{% assign payload = event.data %}
{% if payload.body != nil %}{% assign payload = payload.body %}{% endif %}
{% if event.preview %}
{% capture sample %}{"form":{"id":{{ options.form__storefrontform_required | default: "11111111-1111-4111-8111-111111111111" | json }},"revision":"1"},"submission_id":"22222222-2222-4222-8222-222222222222","cart":"{\"items\":[{\"variant_id\":\"1234567890\",\"quantity\":2,\"properties\":{\"Engraving\":\"Welcome\"}}]}","fields":{"name":"Pat Example","email":"pat@example.com","requirements":"Please quote for the items in my cart."}}{% endcapture %}
{% assign payload = sample | parse_json %}
{% endif %}
{% assign customer_id = nil %}
{% assign draft = hash %}
{% assign cart = payload.cart %}
{% unless payload.form %}
{% error "Expected a storefront form submission. Connect a published cart form to this task." %}{% break %}
{% endunless %}
{% if options.form__storefrontform_required == blank and event.preview != true %}
{% error "Choose the published cart form in this task's Form option." %}{% break %}
{% endif %}
{% if options.form__storefrontform_required != blank and options.form__storefrontform_required != payload.form.id %}
{% log "This submission belongs to another form; no draft order was created." %}{% break %}
{% endif %}
{% if event.preview %}
{% assign customer = hash %}
{% assign customer["id"] = "1234567890" %}
{% else %}
{% assign customer = event.storefront_form_customer %}
{% endif %}
{% unless customer %}{% assign invalid = true %}{% error "The form customer context could not be verified. Check that this is a cart form and Mechanic supports customer verification." %}{% break %}{% endunless %}
{% assign customer_id = customer.id %}
{% assign cart_type = cart | json | slice: 0, 1 %}
{% if cart_type != '"' or cart.size > 65536 %}{% assign invalid = true %}{% error "Expected the form's cart JSON, no larger than 64 KB. Enable cart contents in Submission settings." %}{% break %}{% endif %}
{% assign cart = cart | parse_json %}
{% assign fields = payload.fields | default: hash %}
{% assign field_keys = fields | keys %}
{% unless field_keys %}{% assign invalid = true %}{% error "Expected form answers." %}{% break %}{% endunless %}
{% if field_keys.size > 50 %}{% assign invalid = true %}{% error "Too many form answers." %}{% break %}{% endif %}
{% if customer_id == nil and options.email_field_key == blank %}
{% error "Set Email field key so guest cart submissions include a contact email." %}{% break %}
{% endif %}
{% if options.email_field_key != blank %}
{% assign email = fields[options.email_field_key] %}
{% assign email_type = email | json | slice: 0, 1 %}
{% assign valid_email = email | append: "" | match: '\A[^\s@<>,;:]+@[^\s@<>,;:]+\.[^\s@<>,;:]+\z' %}
{% if email != blank %}
{% if email_type != '"' or email.size > 254 or valid_email == nil %}{% assign invalid = true %}{% error "The submitted contact email is invalid." %}{% break %}{% endif %}
{% assign draft["email"] = email %}
{% elsif customer_id == nil %}
{% assign invalid = true %}{% error "A guest cart submission needs a contact email." %}{% break %}
{% endif %}
{% endif %}
{% capture note %}Storefront cart submission
Form: {{ payload.form.id }}
Submission: {{ payload.submission_id }}
{% for field in fields %}{% assign type = field[1] | json | slice: 0, 1 %}{% if type == '"' %}{{ field[0] }}: {{ field[1] }}
{% elsif field[1].content_base64 != nil %}{{ field[0] }}: {{ field[1].name }} (file details only; use the email or Drive task for the file)
{% else %}{{ field[0] }}: {{ field[1] | json }}
{% endif %}{% endfor %}{% endcapture %}
{% if note.size > 10000 %}{% assign invalid = true %}{% error "The cart submission notes exceed 10,000 characters." %}{% break %}{% endif %}
{% assign draft["note"] = note | strip %}
{% assign items_type = cart.items | json | slice: 0, 1 %}
{% if items_type != '[' or cart.items.size == 0 or cart.items.size > 100 %}{% assign invalid = true %}{% error "Expected a cart containing between 1 and 100 line items." %}{% break %}{% endif %}
{% assign line_items = array %}
{% for item in cart.items %}
{% assign variant_id = item.variant_id | append: "" %}
{% assign quantity = item.quantity | append: "" %}
{% assign valid_variant = variant_id | match: '\A[1-9][0-9]{0,19}\z' %}
{% assign valid_quantity = quantity | match: '\A[1-9][0-9]{0,5}\z' %}
{% unless valid_variant and valid_quantity %}{% assign invalid = true %}{% error "A cart item has an invalid variant or quantity." %}{% break %}{% endunless %}
{% if item.selling_plan_id != blank or item.selling_plan_allocation != blank or item.has_components == true or item.item_components != blank or item.parent_relationship != blank or item.requires_components == true %}
{% assign invalid = true %}{% error "This task supports ordinary product variants. Subscription and bundle items need a separate review; no draft order was created." %}{% break %}
{% endif %}
{% assign line = hash %}
{% assign line["variantId"] = "gid://shopify/ProductVariant/" | append: variant_id %}
{% assign line["quantity"] = item.quantity | plus: 0 %}
{% assign attributes = array %}
{% assign properties = item.properties | default: hash %}
{% assign property_keys = properties | keys %}
{% unless property_keys %}{% assign invalid = true %}{% error "Invalid cart line properties." %}{% break %}{% endunless %}
{% if property_keys.size > 50 %}{% assign invalid = true %}{% error "Too many cart line properties." %}{% break %}{% endif %}
{% for property in properties %}
{% assign property_type = property[1] | json | slice: 0, 1 %}
{% if property_type != '"' or property[0].size > 255 or property[1].size > 4000 %}{% assign invalid = true %}{% error "Invalid cart line property." %}{% break %}{% endif %}
{% assign attribute = hash %}
{% assign attribute["key"] = property[0] %}
{% assign attribute["value"] = property[1] %}
{% assign attributes[attributes.size] = attribute %}
{% endfor %}
{% assign line["customAttributes"] = attributes %}
{% assign line_items[line_items.size] = line %}
{% endfor %}
{% if invalid %}{% break %}{% endif %}
{% assign draft["lineItems"] = line_items %}
{% if customer_id != nil %}
{% assign valid_customer = customer_id | append: "" | match: '\A[1-9][0-9]{0,19}\z' %}
{% unless valid_customer %}{% assign invalid = true %}{% error "Invalid customer ID." %}{% break %}{% endunless %}
{% assign draft["purchasingEntity"] = hash %}
{% assign draft["purchasingEntity"]["customerId"] = "gid://shopify/Customer/" | append: customer_id %}
{% endif %}
{% comment %}Shopify supplies current variant prices. Never accept submitted prices, discounts, tax exemptions or payment terms.{% endcomment %}
{% action "shopify" %}
mutation {
draftOrderCreate(input: { {{ draft | graphql_arguments }} }) {
draftOrder { id name }
userErrors { field message }
}
}
{% endaction %}