> For the complete documentation index, see [llms.txt](https://help.pixfizz.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://help.pixfizz.com/orders-and-fulfillment/sample-json-fulfillment-template.md).

# Sample JSON Fulfillment Template

A complete, production-ready JSON fulfillment template using Liquid. This template can be used as a starting point for HTTP fulfillment destinations.

***

### Template

```liquid
{
	"schema": "pixfizz.fulfillment.default.v1",

	"order": {
		"order_id": "{{ order.code | escape_json }}",
		"external_order_id": "{{ order.id }}",
		"source": "pixfizz",
		"status": "confirmed",
		"ordered_at": "{{ order.confirmed_at }}",

		"customer": {
			"name": "{{ order.first_name | escape_json }} {{ order.last_name | escape_json }}",
			"email": "{{ order.email | escape_json }}",
			"phone": "{{ order.telephone | escape_json }}"
		},

		"totals": {
			"subtotal": {{ order.orderlines_total }},
			"shipping": {{ order.shipping }},
			"tax": {{ order.tax }},
			"discount": {{ order.discount }},
			"total": {{ order.total }},
			"currency": "{{ website.currency_code | escape_json }}"
		},

		"notes": "{{ order.notes | escape_json }}"
	},

	"shipping": {
		"method": "{{ order.shipping_method | escape_json }}",
		"ship_to": {
			"name": "{{ order.address.first_name | default: order.first_name | escape_json }} {{ order.address.last_name | default: order.last_name | escape_json }}",
			"address_1": "{{ order.address.street | escape_json }}",
			"address_2": "{{ order.address.street2 | escape_json }}",
			"city": "{{ order.address.city | escape_json }}",
			"region": "{{ order.address.region | escape_json }}",
			"postal_code": "{{ order.address.postcode | escape_json }}",
			"country_code": "{{ order.address.country.code | escape_json }}",
			"email": "{{ order.email | escape_json }}",
			"phone": "{{ order.address.telephone | default: order.telephone | escape_json }}"
		}
	},

	"jobs": [
		{%- for line in orderlines -%}
		{
			"job_id": "{{ order.code | escape_json }}-{{ forloop.index }}",
			"external_line_item_id": "{{ line.id }}",

			"product": {
				"name": "{{ line.product.name | escape_json }}",
				"code": "{{ line.product.code | escape_json }}",
				"category": "{{ line.product.category | escape_json }}"
			},

			"quantity": {% if line.is_cut_print %}{{ line.cut_print_quantity }}{% else %}{{ line.quantity }}{% endif %},
			"print_quantity": {% if line.is_cut_print %}{{ line.cut_print_quantity }}{% else %}{{ line.quantity }}{% endif %},

			"options": [
				{%- assign opt_first = true -%}

				{%- comment %} Template options {%- endcomment -%}
				{%- for opt in line.chosen_template_options -%}
					{%- if opt.template_option.type == "image_upload" or opt.template_option.type == "file_upload" or opt.value == blank -%}
					{%- else -%}
						{%- unless opt_first -%},{%- endunless -%}
						{ "key": "{{ opt.template_option.code | default: opt.template_option.name | escape_json }}", "value": "{{ opt.template_option_value.code | default: opt.value | escape_json }}" }
						{%- assign opt_first = false -%}
					{%- endif -%}
				{%- endfor -%}

				{%- comment %} Product variants {%- endcomment -%}
				{%- for v in line.chosen_variants -%}
					{%- if v.variant.type == "image_upload" or v.variant.type == "file_upload" or v.variant_value.name == blank -%}
					{%- else -%}
						{%- unless opt_first -%},{%- endunless -%}
						{ "key": "{{ v.variant.code | default: v.variant.name | escape_json }}", "value": "{{ v.variant_value.code | default: v.variant_value.name | escape_json }}" }
						{%- assign opt_first = false -%}
					{%- endif -%}
				{%- endfor -%}
			],

			"assets": [
				{%- for file in line.generated_files -%}
				{
					"type": "{{ file.type | escape_json }}",
					"url": "{{ file.url | escape_json }}",
					"filename": "{{ file.filename | escape_json }}",
					"pages": {% if file.type == 'cover' %}1{% elsif line.project and line.project.page_count %}{{ line.project.page_count }}{% else %}1{% endif %}
				}{% unless forloop.last %},{% endunless %}
				{%- endfor -%}
			]
		}{% unless forloop.last %},{% endunless %}
		{%- endfor -%}
	]
}
```

***

### Key patterns in this template

* **`escape_json`** — always use this filter for string values to prevent JSON-breaking characters
* **Cut print detection** — uses `line.is_cut_print` to switch between `cut_print_quantity` and `quantity`
* **Comma handling** — uses an `opt_first` flag to avoid leading commas in the options array
* **Image/file upload filtering** — skips `image_upload` and `file_upload` option types (these are not relevant to fulfillment options)
* **Fallback chains** — uses `| default:` for addresses and option codes to handle missing data gracefully
* **Generated files** — iterates `line.generated_files` which is only available in the fulfillment rendering context

***

### Available Liquid variables

This template uses the fulfillment rendering context, which provides:

* `order` — the order being fulfilled
* `orderlines` — the orderlines being fulfilled by the current fulfillment setting
* `user` — the user who created the order
* `website` — the website on which the order was created
