# Place order

The place order endpoint /api/placeorder/<ordering-url-id>/ allows you place an order without using the built-in Iteras ordering UI, e.g. if you have a highly customized UI that you want to plug in.

You still define an ordering form inside Iteras and post against it, reusing the ordering flow logic. For instance, you can inside Iteras decide to a make a field mandatory, or decide whether manual approval of new orders is required or not. If you unfamiliar with this, try setting up a form and place an order using the built-in UI.

Of course, since this bypasses the UI, some things won't work without some extra work: Payment agreements that require interaction with a payment gateway require the customer to fill in information - but you can get back a URL and redirect the customer yourself to the gateway UI. Same for the automatic email duplicate checking/logging in in the UI - but you can pass in a customer ID.

Before we start, note that there are lot of interesting edge cases in ordering. If all you're after is a different look, we strongly suggest you start with the built-in forms and see what you can do with some CSS and Javascript.

# Parameters

The endpoint uses POST.

Supported POST parameters depends on the ordering form setup - it's the same as those found in the form itself. If you're in doubt, you can try placing an order manually and check the POST'ed parameters in the browser development tool. Note that a few of those are optional and only used by the GUI, e.g. "accept_terms" and "products". It's also recommended that the users client IP address is supplied.

For a simple name + email ordering form with a custom field named "Receive newsletter", you might send the following request:

POST /api/placeorder/a72fb21d/ HTTP/1.1

name=John Doe
email=johndoe@example.com
:Receive newsletter=on
clientip=77.243.49.236

This works as long as the form only allows choosing one product. If there are several choices, you need to specify what to order by taking the campaign ID/product external ID and prefixing it with campaignid-<ID> or productid-<ID>. For instance, if you have a campaign with the campaign ID "3months" and a product with the external ID "foo", you might send

POST /api/placeorder/a72fb21d/ HTTP/1.1

campaignid-3months=1
productid-foo=2
name=John Doe
email=johndoe@example.com
:Receive newsletter=on
clientip=77.243.49.236

to get one subscription on "3months" and two "foo"s.

This is a bit different from the way the UI currently works.

You can place an order for a specific customer by adding a customer parameter with the customer ID:

POST /api/placeorder/a72fb21d/ HTTP/1.1

customer=123321
name=John Doe
email=johndoe@example.com
:Receive newsletter=on
clientip=77.243.49.236

Note that even if the customer already exists, you still have to pass in all the fields expected for the form - the UI does it in the same manner. If you don't want to do that, configure the form to not use those fields.

The customer parameter can also be used to set the customer ID for new customers, in case you are creating customers that already have an ID in another system. The ID must be numeric.

# Return value

The data returned is an object like { "placed": true }. In case the ordering form is setup to automatically approve the order and this is possible (not say pending a payment gateway interaction), the result also includes the customer ID of the resulting customer and the IDs of any subscriptions created:

{
  "placed": true,
  "customer_id": "321415",
  "subscription_ids": ["12314232"]
}

In case of a validation error, an error object with fields and arrays of error messages is returned:

{
  "placed": false,
  "errors": {
    "name": ["This field is required."],
    "email": ["Please enter a valid email address."]
  }
}

Append ?language=<code> to the URL to change the language of the error messages.

# Redirects and payment gateway URLs

If a payment gateway has been configured and the ordering form set up to pay through an automatic payment agreement, the customer is not created immediately. Instead they need to go through a payment gateway flow. There are a couple of extra GET parameters to control this:

  • "iframe" - whether to use UI designed to be run in an iframe, e.g. iframe=1

  • "return_url" - where to redirect the customer after successful payment agreement creation, e.g. return_url=https://example.com/ordering/done/

  • "cancel_url" - where to redirect the customer in case the payment agreement process is cancelled, e.g. cancel_url=https://example.com/ordering/failed/

  • "test" - whether to accept transactions from test cards, e.g. test=1

For instance, you might POST this

POST /api/placeorder/a72fb21d/?iframe=1&return_url=https://example.com/ordering/done/&cancel_url=https://example.com/ordering/cancelled/ HTTP/1.1

name=John Doe
email=johndoe@example.com
:Receive newsletter=on

and get back a placed, but unconfirmed order

{
  "placed": true,
  "redirect_to": "https://payments.examplegateway.com/?key=dx123js32..."
}

You then redirect the customer to https://payments.examplegateway.com/?key=dx123js32..., and they either enter their details at the payment gateway, in which case the order is confirmed, or quit, in which case the order does not progress any further.

If you need to save information about the customer across the calls, you can use a cookie or put GET parameters in the continue and cancel URLs, e.g. return_url=https://example.com/ordering/done/?sessionid=XYZ. If it's important data, just remember to make it tamper-proof, either by signing it (e.g. using something like Javascript Web Tokens) or pointing to things you store in your database, to prevent someone from succesfully fiddling with it.