API concepts
Before using the web services there are some API concepts that you should review about how the services are implemented.
We have tried to make the services as RESTful as possible, i.e. working with resources:
- a POST method would create a resource (e.g. an Instruction, Appointment, Report, Quote, Referral).
- a PATCH method would update a resource (e.g. Rebook appointment, Replace report).
- a GET method would return a resource (e.g. an Instruciton or Quote).
- a HEAD method would be used to determine if a resource exists, it is really a GET without returned data (e.g. check a Referral hasn't already been made).
- a PUT method would be used where we operate on a resource, e.g. a supplier would confirm that an appointment took place.
- a DELETE method would be used to remove a resource. It is not used often, e.g. when you "delete" a quote, the quote will be marked as removed but it can still be searched on and retrieved.
The services are split into groups but different groups will access the same *resources", e.g. - the Instruction service will return instructions and the Supplier Operations service can operate on instructions. They both access the Instruction resource.
These web services can be used by Introducer users and Supplier users. In these documents these coloured badges will appear to try and make it clear which services or methods apply to each type of user.
Authentication
For all services in the API you need to provide authentication through a username and password. Two methods of authentication are available:
- Basic authentication
- Bearer token authentication
The web service credentials are used for accessing the API. They are not the same as the interactive portal account credentials that are used to access the interactive portals.
You will create your own web service credentials to use with the API. These are created in the interactive portals.
Each set of web service credentials for the API are linked with an interactive portal account.
Interactive portal accounts
All operations performed via the API must be attributed to an active account in the interactive portals. It is preferred that these operations are in the name of a real person and not that of a shared account. For example, if a note is added to an instruction then it is preferred to be from an individual, e.g. "Fred Smith at XYZ Surveyors".
Shared accounts
We strongly discourage the use of shared accounts to logon to the interactive portals.
They make if difficult to track, audit and provide partial anonymity to those that use them as well as presenting security issues if the credentials are compromised (e.g. when a person leaves your firm).
We recognise that using an individual account is not always possible when working via an API. We provide an approach using an integration service account.
This integration service account can be created on the Integration administration page in the interactive portal. You would then create a web service credential (see below) that is linked to the integration service account.
There are two options to using this integration service account:
The first option is to simply use this credential can be used to create quotes, instructions and other methods in the API. The integration service account has all the same rights as an interactive user - except you cannot logon using this account on the interactive portal.
Limitations for introducers
There are a few limitations for introducers - quotes and instructions created by introducers for new customers would not be associated with an owner. The owner is the person at your firm who first created a case with that customer.
This limitation only affects Introducers who have a team earning commissions from instructions and this is tracked on our portal.
We will be introducing functionality in the API at a later date to allow you to assign an owner to a quote or instruction. If you did want to edit the owner you would need to logon to the portal to do so.
However, since you are using the API to create quotes and referral you would know who owns the eventual instruction on your system.
The second option is to authenticate using the credentials for the integration service account but to perform any operations as a different user. You can either:
- specify the
X-UserCodeheader with the email address of the account you want to perform operations as - or if using Basic authentication change the username portion of header to specify the email address
Example
For example you have three portal users - mary@xyzsurveyors.com, adam@xyzsurveyors.com and arjun@xyzsurveyors.com.
You would not want to create three sets of API credentials for each user - this will be difficult to maintain.
You would create an integration service account as the linked portal account. And on each call you would switch to the individual you want to have the operation performed in the name of (using their email address).
NOTE
- Interactive portal account credentials can only be used with the interactive portal and cannot be used to logon to the API.
- Web service credentials can only be used with the API and cannot be used with the interactive portal.
Web service credentials
You will create your own web service credential for use with the API. These web service credential are created interactively within the TMP portal:
- Logon to the interactive portal.
- Choose the Administration menu option.
- Click on the Integration icon.
INFO
If this option for integration is not present then contact The Moving Portal to have it enabled.
Details about the integration service account will be shown at the top of the page. If it has not been created you should create it. The name will default to the name of your firm and be displayed on items like notes (i.e. "created by My Firm").
A list of Integration authentication users will be shown (initially empty).

Click on Add user. This will open a new window.

The dropdown of users should default to the integration service account. Choose the interactive account that this credential will be used for. Click the New user button.

INFO
When you authenticate to the API using the credentials that are created here, the default person will be used unless you override it. You can override the user by
- specify the
X-UserCodeheader with the email address of the account you want to perform operations as - or if using Basic authentication change the username portion of header to specify the email address
You need to take a copy of the password. This is the only time it will be displayed. Either copy from the text box or use the copy icon. The username will be displayed later.
Once you close the dialog it will display the user, along with a hint about the password (the first few characters).

The key icon will allow you to reset the password. A dialog will appear to confirm that you wish to do this. If an integration is in use with this password then it will stop working if you reset the password.
INFO
Best practice is to create a new set of credentials and swap to them before deleting the old credentials.
To remove the credentials use the dustbin icon. If an integration is in use with this password then it will stop working if you remove the credentials.
If there are repeated failures authenticating with the API using the username/password then the account will lockout. The period of lockout will change depending on the number of failures over time. The lockout date will be in red if the account is locked out. The lockout date will be in gray if the account was locked out and the expiry is over or the account was unlocked. You can either wait until the period expires or click the padlock icon, which will open a dialog to unlock the account. Once you properly authenticate no date will be shown (if a date is shown then this is when the last attempt to authenticate failed).

Lockout policy
The lockout policy may be changed at anytime and will act differently the more lockouts occur, e.g. if you get locked out it will automatically unlock after a few minutes. If you then lockout again then the automatic unlock time will increase.
Initially you should expect to be locked out once you have between 5 and 10 failed attempts.
INFO
Supplier credentials for The Moving Portal and IMyHome are separate.
Basic authentication
Basic authentication requires sending a Basic Authorization header with every HTTP request. , e.g.
Authorization: Basic <credentials>
Where <credentials> is the base64 encoding of the username and password joined by a colon :.
For example:
- username
xyzsuppliersmarysmith283 - password
uh2P%28KSM@##12
This would give credentials of
xyzsuppliersmarysmith283:uh2P%28KSM@##12
This would be encoded as
eHl6c3VwcGxpZXJzbWFyeXNtaXRoMjgzOnVoMlAlMjhLU01AIyMxMg==
and thus the header would be
Authorization: Basic eHl6c3VwcGxpZXJzbWFyeXNtaXRoMjgzOnVoMlAlMjhLU01AIyMxMg==
Example code to generate this would be:
public static HttpClient CreateHttpClient(this IHttpClientFactory httpClientFactory, string username, string password)
{
var httpClient = httpClientFactory.Create();
var bytes = Encoding.UTF8.GetBytes($"{username}:{password}");
httpClient.DefaultRequestHeaders.Add("Authorization", $"Basic {Convert.ToBase64String(bytes)}");
return httpClient;
}
It is also possible to create a header for a specific user within your organisation rather than the default user associated with the credentials. This user would become the effective user for any methods called in the API.
To do this your credentials should be the base64 encoding of the username and email joined by an /, then joined with the password by a colon :.
For example:
- username
xyzsuppliersmarysmith283 - email address
adam@xyzsuppliers.com - password
uh2P%28KSM@##12
This would give credentials of
xyzsuppliersmarysmith283/adam@xyzsuppliers.com:uh2P%28KSM@##12
This would be encoded as
eHl6c3VwcGxpZXJzbWFyeXNtaXRoMjgzL2FkYW1AeHl6c3VwcGxpZXJzLmNvbTp1aDJQJTI4S1NNQCMjMTI=
and thus the header would be
Authorization: Basic eHl6c3VwcGxpZXJzbWFyeXNtaXRoMjgzL2FkYW1AeHl6c3VwcGxpZXJzLmNvbTp1aDJQJTI4S1NNQCMjMTI=
Example code to generate this would be:
public static HttpClient CreateHttpClient(this IHttpClientFactory httpClientFactory, string username, string password)
{
var httpClient = httpClientFactory.CreateClient();
var usernamePortion = string.IsNullOrEmpty(emailAddress) ? username : $"{username}/{emailAddress}";
var bytes = Encoding.UTF8.GetBytes($"{usernamePortion}:{password}");
httpClient.DefaultRequestHeaders.Add("Authorization", $"Basic {Convert.ToBase64String(bytes)}");
return httpClient;
}
An alternative to adding the email address within the credentials is to specify the Http header X-UserCode. It should be set to the email address of the user you wish to perform operations as. It will override any email address within the credentials.
X-UserCode: adam@xyzsuppliers.com
Bearer authentication
The alternative to Basic authentication is to use Bearer authentication where you would send a Bearer Authorization header with every HTTP request. , e.g.
Authorization: Bearer <Bearer-Access-Token>
In this approach you will authenticate once (with your username and password) and receive two tokens - an access token and a refresh token. You would use the access token in subsequent calls to the API in the Authorization header. When the access token expires you can then use the refresh token it to get a new access token - and thus you would not use the username and password again.
Your first authentication would use the method /auth/login. You will receive an accessToken and a refreshToken. The accessToken can be used until it expires (usually after 30 minutes).
To get a new accessToken you would use the method /auth/refresh providing the refreshToken.
The login endpoint /auth/login requires username, password and optionally the email address. The payload for the authentication endpoint is
{
"username": "xyzsuppliersmarysmith283",
"password": "uh2P%28KSM@##12",
"email": "adam@xyzsuppliers.com"
}
Assuming the credentials are valid this will return a token to use for further authentication requests. It will also return a refresh token that can be used to get a new access token.
{
"tokenType": "Bearer",
"accessToken": "....ACCESSTOKEN.....",
"expiresIn": 1800,
"refreshToken": "....REFRESHTOKEN....."
}
The accessToken can then be used in the Http header:
Authorization: Bearer ....ACCESSTOKEN.....
You can also specify the X-UserCode HTTP header to override the user to perform operations as.
Full information can be found in the details for the Authentication service.
HTTP methods
These services make an attempt to act in a RESTful manner and uses the HTTP methods/verbs to indicate the meaning of the calls to the API. In these documents these coloured badges for the methods when they are used.
GET GET
GET is used to access resources. Examples include
- Getting an Instruction
- Performing an Instruction search
- Getting a list of products
A successful request should return 200 OK.
POST POST, PATCH PATCH
POST is used to send data to the API. PATCH is used to replace data stored in the API. Examples include
- Authentication via a POST to the login method.
- An introducer sending us a quote or referral with a POST.
- An introducer sending us a new instruction with a POST.
- A supplier sending us a new document to complete a case with a POST and replacing the document with a PATCH.
Not all places where you can POST allow a PATCH to be done, e.g. you cannot replace a quote, referral or instruction - but you can replace an appointment.
A successful request should return 201 Created.
INFO
The authentication methods for login and refresh are POST methods but will return 200 OK.
PUT PUT
PUT is used to update data on the server by performing an operation. An example would be a supplier accepting or declining a case sent to them.
A successful request should return 200 OK.
HEAD HEAD
HEAD makes a request for a resource and will return a code to indicate that the resource exists. It is used to determine if an instruction exists. A typical use-case is to check the instruction exists before attempting to create it (e.g. has it been imported before).
A successful request should return 200 OK and 404 Not found. A 400 Bad Request may also be returned.
INFO
If you do not have access to a resource (e.g. an instruction) you will also receive a 404 Not found response.
INFO
If a validation problem occurs when a HEAD method is called then a 400 Bad Request may be returned but without any error detail (since this is a HEAD method).
DELETE DELETE
DELETE is used to remove data from the server.
It is not used often. Data is rarely physically removed - e.g. a quote is not deleted, but marked as Archived.
HTTP response codes
HTTP response codes indicate whether a request has been successfully completed. The following are generally used.
200 OK
This response is a generic success response. It should be used for GET and PUT requests.
The POST method to login (for bearer authentication) returns a 200 OK response.
201 Created
This response is used for POST and PATCH requests that have succeeded to tell you that the request has created the item requested.
The POST method to login (for bearer authentication) returns a 200 OK response.
400 Bad Request (validation errors)
The request that you made has errors. These errors should either be resolvable by yourself or a call that should have been made. Examples are:
- A introducer has sent a quote with no customers.
- A supplier has attempted to send details of an appointment for a case which is at the incorrect status.
- A supplier has attempted to send details of an appointment that is a too far in the future.
The document of the individual services details the validation that is performed. See Validation for more information.
INFO
Validation responses are not for display to your end user.
401 Unauthorized
This specifies that either you have not authenticated or the call you are making is not allowed (i.e. a method for an Introducer is being called by a Supplier).
403 Forbidden
This status code is not normally used.
For example, if you to try and access an instruction that you are not allowed to access you will receive a 404 Not found response. By returning this we reduce our security vulnerability footprint.
404 Not found
If you try to access a resource that does not exist then you will receive this response.
This response will also be sent for a request to a resource you do not have access to, e.g. if an introducer requests an instruction that it did not create or a supplier requests an instruction that is not assigned to it they will receive this return.
429 Too many requests
This will be returned when a request to the services is deemed excesive. They are not designed to stop normal operation, but to deal with runaway proceses.
INFO
At the time of writing no rate limiting/throttling is in place - however, this will be added to prevent too many requests being sent.
500 Internal server error
An error has happened that you cannot resolve. These are generally system errors (e.g. a database is unavailable or cannot be updated or a coding error). These are logged internally.
If you receive these and after subsequent retries the problem is not resolved then you should contact us.
We advise creating a retry policy to ensure that an automatic retry is attempted. For example if implementing with .NET use a package like Polly.
Others
There are other codes that we have not programmatically created that may be received are:
- 405 Method not allowed - i.e. using a method not supported such as DELETE on an Instruction resource.
- 408 Request timeout.
- 411 Length required.
- 413 Payload too large.
Payloads and returns
For payloads sent to POST, PATCH and PUT methods we recommend that you use a separate object type for each call, even if the data in those payloads are the same. This is how we have developed most of the code internally. By doing this it is easier to modify when the payload is changed.
For returns from all methods are objects. We have taken the decision to return an object, even if a boolean or string would have sufficed. This provides the ability to extend this in the future if we need to return further data, without it affecting any integrations already in place.
For most operational methods (e.g. for a Supplier to book an appointment or Introducer to update the property address), we would return an object which contains a boolean value indicating success, rather than just returning the boolean value.
For methods returning a reference, e.g. when creating an Instruction, they would normally return a string with the reference of the object created. Again, rather than returning a string we return an object with the string included.
In most of these types of method we have a StandardResponse object. This object contains a boolean value and a string value.
{
"success": true,
"reference": "string"
}
Date formats
We intend to return all dates and dates with times as UTC - whether or not we are in summer time or not. Thus, in summer the time below, 10:07am actually means 11.07am. e.g.
{
"completedTimestamp": "2024-06-07T10:07:50.6129379Z"
}
If we return a date only then the date portion will be correct - this example means 7th June. e.g.
{
"expectedTimestamp": "2024-06-07T00:00:00Z"
}
If you send us a date please ensure that it equates to the correct time. The format used above has a Z at the end specifies with respect to UTC and there is no time zone information. Please see The right JSON Date Format.
INFO
Please be aware of which timestamps are used for a date only or a date with time.
Addresses
The typical payload for an address is:
"address": {
"addressFormatCode": "DEFAULT",
"addressLine1": "32 Crowngate Apartments, 62 Great Hampton Street",
"addressLine2": "Hockley",
"addressLine3": "Birmingham",
"addressLine4": "West Midlands",
"postcode": "B18 6EN",
"countryCode": "GB"
}
Our addresses support
- A type - this should be set to
DEFAULTwhen you have an address andNONEwhen there is none- Internally we might use have address formats depending on the source, but for the API all will be set to
DEFAULT.
- Internally we might use have address formats depending on the source, but for the API all will be set to
- Four lines:
AddressLine1,AddressLine2,AddressLine3,AddressLine4- usually mapped to line 1, line 2, town and county.
- Postcode:
Postcode - Country:
CountryCode
The following validation rules:
AddressLine1: maximum length 100, required.AddressLine2: maximum length 100.AddressLine3: maximum length 100.AddressLine4: maximum length 100.Postcode: maximum length 10, required.CountryCode: needs to be a valid code.
The Data service can be used to return a list of country codes with the key COUNTRYLIST.
Validation
Validation will be performed on every web service method you call. This will include checking whether you can access an instruction using the reference provided. If you cannot a 404 Not found response code is returned.
Other validation will check that the
- The instruction for the reference provided is in the correct state to have the operation performed.
- The data provided is correct, e.g. if a
ReasonCodeis provided it is valid.
If there are validation issues then a 400 Bad Request response code is returned with an object providing details of the validation issues. It is expected that you have either made a mistake (e.g. if the state of an instruction is incorrect) or the data provided is wrong.
INFO
The validation issues returned are not meant for display to your end users. They normally contain information about properties in objects that are wrong.
You should ensure that you log any validation issues and look to resolve them. The team at The Moving Portal should be able to help you and they can escalate issues that there is no obvious reason that you can find.
A sample response with one validation issue is
{
"type": "invalid-request",
"title": "",
"status": 400,
"detail": "CaseStatus: This status does not allow case to be accepted;",
"instance": ""
}
The detail property is a semi-colon separated list of issues, e.g. with more than one issue
{
"type": "invalid-request",
"title": "",
"status": 400,
"detail": "AppointmentDate: Appointments must be within the next six months;AppointmentTimeslotCode: Not recognised;SupplierConfirmedTermsAndConditionsAgreed: Terms and Conditions must be agreed;",
"instance": ""
}
Versioning
It is possible to send with each request a version number. We are hopeful of creating a single version of the API and only using a different version where we create custom functionality. In this case we will inform the integrator of the version number to use otherwise you should not send any specific version details.
There are two methods of sending the version number
- On the query string to the method, specify
api-version. - In the request, specify the header
X-Version.
If you wish to test this, then the Data service can be tested with version 0.0 which will return some dummy data.
