Opportunities webhook
Target audience: Developers who are integrating with the Gensen salary sacrifice system and need to receive opportunities (including employee, vehicle and quote information) through a webhook API.
Event triggers
The opportunities webhook is triggered when an employee applies for a car within the salary sacrifice platform.
Payload
The webhook will send a POST request to an agreed endpoint URL with a JSON body described by OpportunityRequest, which is a container type for SalsacQuote.
Security
The webhook can be secured using an agreed shared secret (token) that will be
sent in the authorization header of the request:
authorization: Bearer <shared secret>Retry policy
At present there are no retries. If the webhook fails, we store the data within our system and can resend it manually.
We hope to implement retries in the future.
Update policy
The webhook will be updated to preserve forward compatibility whenever possible. We may add new fields to the request object, but any new response fields will be optional.
We may be required to make breaking changes in response to UK government policy changes and we will endeavour to document changes as soon as possible.
Sample request/response
Request
POST /opportunity/create HTTP/1.1
host: example.com
content-type: application/json
authorization: Bearer <shared secret>
{
"data": {
"client_vehicle_id": "abc123",
"rate_source": "ratebook",
"cap_id": 92358,
"model_year": "2022.25",
"cap_option_ids": [
"156105",
"147970"
],
"cap_vehicle_type": "C",
"make": "Ford",
"model": "Cortina",
"derivative": "1.5L LX",
"p11d_value": 76483.01,
"co2_emissions": 0,
"client_rate_id": "xyz123",
"term_months": 36,
"mileage_yearly": 10000,
"initial_payments": 1,
"payment_profile": "S",
"rental": 234.56,
"maintenance": 75.31,
"effective_rental": 735.12,
"effective_maintenance": 205.12,
"one_up_front_effective_rental": 735.12,
"one_up_front_effective_maintenance": 205.12,
"contingency_fee": 48.12,
"insurance_premium": 180.21,
"salary_sacrifice_gross": 23134,
"salary_sacrifice_net": 18765,
"nic_saving_shared_with_employee": 1234,
"salary_sacrifice_gross_pre_nic_sharing": 23134,
"employer_nic_savings_shared": 0,
"employer_nic_savings_shared_fraction": 0,
"employee": [
{
"year": "2021/22",
"income_tax_saving": -123.45,
"salary_sacrifice_net": 123.45,
"salary_sacrifice_gross": 123.45,
"bik_tax": 123.45,
"nic_saving": -123.45,
"salary_sacrifice_gross_pre_nic_sharing": 123.45,
"nic_saving_shared_with_employee": 0,
"tax_saving": -123.45,
"hscl_saving": 0
},
{
"year": "2022/23",
"income_tax_saving": -123.45,
"salary_sacrifice_net": 123.45,
"salary_sacrifice_gross": 123.45,
"bik_tax": 123.45,
"nic_saving": -123.45,
"salary_sacrifice_gross_pre_nic_sharing": 123.45,
"nic_saving_shared_with_employee": 0,
"tax_saving": -123.45,
"hscl_saving": 0
},
{
"year": "2023/24",
"income_tax_saving": -123.45,
"salary_sacrifice_net": 123.45,
"salary_sacrifice_gross": 123.45,
"bik_tax": 123.45,
"nic_saving": -123.45,
"salary_sacrifice_gross_pre_nic_sharing": 123.45,
"nic_saving_shared_with_employee": 0,
"tax_saving": -123.45,
"hscl_saving": 0
}
],
"employer": [
{
"year": "2021/22",
"nic_saving": 123.45,
"class_1_nic_saving": 123.45,
"class_1_nic_saving_original": 123.45,
"class_1a_nic": 123.45,
"nic_savings_shared": 0,
"hscl_saving": 0,
"hscl": 0
},
{
"year": "2022/23",
"nic_saving": 123.45,
"class_1_nic_saving": 123.45,
"class_1_nic_saving_original": 123.45,
"class_1a_nic": 123.45,
"nic_savings_shared": 0,
"hscl_saving": 0,
"hscl": 0
},
{
"year": "2023/24",
"nic_saving": 123.45,
"class_1_nic_saving": 123.45,
"class_1_nic_saving_original": 123.45,
"class_1a_nic": 123.45,
"nic_savings_shared": 0,
"hscl_saving": 0,
"hscl": 0
}
],
"pch": 518.88,
"vat_partial_exemption_fraction": 0.95,
"early_termination_contingency_amount": null,
"early_termination_contingency_fraction": 0.04,
"early_termination_insurance_premium": 0,
"early_termination_insurance_fraction": 0.087654,
"early_termination_protection_monthly": 0,
"effective_early_termination_protection_monthly": 0,
"customer_id": 91533,
"user_id": 75643,
"name": "Lavern Bauch",
"given_name": "Lavern",
"family_name": "Bauch",
"contact_number": null,
"email": null,
"marketing_email_consent": null,
"marketing_sms_consent": null,
"residence": "Scotland",
"income_tax_rate_first_year": 0.21,
"postcode": "AB12 1AB",
"address": null,
"motor_insurance_type": "Default",
"motor_insurance_provider": "LloydLatchford",
"insurer_quote_id": "XYZ12345",
"insurance_quote_datetime": "2021-05-18T09:12:34.56Z",
"driver_1_dob": "1980-06-05",
"driver_2_dob": "1981-03-01",
"driver_3_dob": null,
"driver_1_name": "Sade",
"driver_2_name": "El Greco",
"driver_3_name": null,
"personal_contract_hire_yn": "N",
"maintenance_yn": "Y",
"gensen_quote_id": "00012345"
}
}Success response
{
"data": {
"opportunity_id": "12345"
}
}Error response
{
"errors": [
{
"code": "12345",
"message": "An message we can log for later debugging"
}
]
}An appropriate HTTP status error code (4xx or 5xx) is expected for an error response.
Testing
At the moment we do not have a specific test environment for the webhook, though we suggest adapting the sample request above to test your implementation.
Schema
Scalar Types
| Name | Definition | Description |
|---|---|---|
Yes | "Y" | |
No | "N" | |
TerminalPause | "P" | |
SpreadRental | "S" | |
Residence | "UK" | "Scotland" | "Wales" | |
Car | "C" | |
Lcv | "L" | |
Decimal | number | |
Decimal2Dps | Decimal | |
Decimal1Dp | Decimal | |
Integer | number | |
ExVatAmount | number | |
VatIncAmount | number | |
Amount | number | |
RateSource | "ratebook" | "lex" | |
MotorInsuranceType | "Default" | "EmployerProvided" | |
Iso8601Date | '${number}-${number}-${number}' | |
Iso8601DateTime | '${Iso8601Date}${"T" | " "}${number}:${number}:${number}${string}' |
Object Types
SalsacQuote
The quote sent to a CRM as an opportunity or as a final quote recalculation.
| Field | Type | Description |
|---|---|---|
address | PostalAddress | null | The address where the vehicle will be parked overnight. Not provided for employer-supplied or private insurance. |
cap_id | number | null | The cap ID of the car, where available. |
cap_option_ids | string[] | null | null indicates no selection was made, whereas an empty array indicates no options were selected. CAP IDs as provided by CAP’s SOAP option bundle endpoint See https://soap.cap.co.uk/nvd/capnvd.asmx?op=GetCapOptionsBundle IDs may include options that have inclusive pricing from “IN” and “IO” rules and should be removed from P11D and rental pricing. Where more than one item in an IO rule is selected, the most expensive is offered for free. At time of writing, users are not blocked from enquiries on invalid option combinations and merely indicate a preference. |
cap_vehicle_type | "C" | For salsac, this is always “C” for car. |
client_rate_id | string | null | Rate ID as provided on import, where available. Treat this as the canonical, source-specific rate identifier. For Lex rates, this will indicate the product code only, there is no unique rate identifier. |
client_vehicle_id | string | null | Vehicle ID as provided on import, where available. Treat this as the canonical, source-specific vehicle identifier. For Lex vehicles, this carries the raw identifier returned by Lex. |
co2_emissions | number | |
contact_number | string | null | Employee’s phone number |
contingency_fee | number | Any contingency fee added to the quote, ex VAT |
customer_id | string | number | null | Identifier for the employer as provided, where available. A string will be returned (unless previously agreed to send as an integer) |
derivative | string | |
driver_1_dob | '${number}-${number}-${number}' | Driver 1 date of birth Example: "1983-01-29" |
driver_1_name | string | Driver 1 name (may be different from employee name in some cases) Example: "Jane Smith" |
driver_2_dob | '${number}-${number}-${number}' | null | Driver 2 date of birth Example: "1983-01-29" |
driver_2_name | string | null | Driver 2 name Example: "John Smith" |
driver_3_dob | '${number}-${number}-${number}' | null | Driver 3 date of birth Example: "1983-01-29" |
driver_3_name | string | null | Driver 3 name Example: "Jake Smith" |
early_termination_contingency_amount | number | null | Amount of contingency fee, ex VAT |
early_termination_contingency_fraction | number | null | Contingency fee as a fraction of the ex VAT total rental |
early_termination_insurance_fraction | number | null | The amount of early termination insurance that is applied, as a fraction of the ex VAT rental + maintenance. |
early_termination_insurance_premium | number | Monthly insurance premium for early termination |
early_termination_protection_monthly | number | null | The amount of early termination protection that is applied as part of the overall rental cost (ex VAT). Will report as zero for recalculations where the original rental should include the ETP amount. |
effective_early_termination_protection_monthly | number | null | The amount of early termination protection that is applied as part of the overall rental cost. Takes account of any VAT recovery or blockage. Will report as zero for recalculations where the original rental should include the ETP amount. |
effective_maintenance | number | Represents a periodic business lease maintenance, taking account of VAT recovery and the Lease Rental Restriction. Any upfront maintenance will be applied, rather than converted to a 1-0-x payment profile. |
effective_rental | number | Represents a periodic business lease rental, taking account of VAT recovery and the Lease Rental Restriction. Early termination protection is not included, except when included in the original rental. Any upfront rental will be applied, rather than converted to a 1-0-x payment profile. |
email | string | null | Employee’s email address |
employee | SalsacQuoteEmployee[] | Breakdown of employee costs and savings by year |
employer | SalsacQuoteEmployer[] | Breakdown of employer costs and savings by year |
employer_nic_savings_shared | number | The average monthly class 1 NIC savings shared by employer with employee over the full term |
employer_nic_savings_shared_fraction | number | The fraction of the employer NIC savings shared with the employee. 1 represents 100% of the employer NIC savings shared with the employee, 0 represents 0% of the employer NIC |
family_name | string | null | Employee’s family name |
gensen_quote_id | string | Identifier for the quote in the Gensen system. |
given_name | string | null | Employee’s given name |
income_tax_rate_first_year | number | Employee’s tax rate for the first year of the lease. |
initial_payments | 1 | All salsac quotes are based on 1 in advance, so this will always be 1. |
insurance_premium | number | Annual motor insurance premium quoted |
insurance_quote_datetime | '${number}-${number}-${number} ${number}:${number}:${number}${string}' | '${number}-${number}-${number}T${number}:${number}:${number}${string}' | Date stamp for motor insurance quote. |
insurer_quote_id | string | Motor insurer’s quote ID. |
maintenance | number | Periodic ex VAT maintenance amount Converted to 1-0-x if necessary. |
maintenance_yn | "Y" | Deprecated: Will be removed in future versions, don’t depend on this. |
make | string | |
marketing_email_consent | boolean | null | Confirmation that the employee has consented to email marketing. |
marketing_sms_consent | boolean | null | Confirmation that the employee has consented to SMS marketing. |
mileage_yearly | number | Lease mileage allowance per year |
model | string | |
model_year | string | Many cap ID or cap codes represent a range of cars over several years, so model year is required to disambiguate. Example: "2024.25" |
motor_insurance_provider | string | null | Motor insurance provider name (if applicable). |
motor_insurance_type | MotorInsuranceType | null | Motor insurance type (if included in the quote). |
name | string | Employee’s full name |
nic_saving_shared_with_employee | number | Average monthly employer class 1 NIC saving shared with employee. |
one_up_front_effective_maintenance | number | The effective_maintenance represents a periodic business lease maintenance and will take account of VAT recovery and the Lease Rental Restriction. Payments converted to 1-0-x if necessary. |
one_up_front_effective_rental | number | Represents a periodic business lease rental so will take account of VAT recovery and the Lease Rental Restriction. Early termination protection is not included, except when included in the original rental. Payments converted to 1-0-x if necessary. |
p11d_value | number | |
payment_profile | "S" | All salsac quotes are based on spread rental, so this will always be “S”. |
pch | number | Includes rental, maintenance, insurance, but not contingency fee. |
personal_contract_hire_yn | "N" | Deprecated: Will be removed in future versions, don’t depend on this. |
postcode | string | null | Postcode where the vehicle will be parked overnight. Not provided for employer-supplied or private insurance. |
rate_source? | RateSource | Identifies the source of the underlying vehicle and rate data. Prefer ratebook for partner-provided ratebooks. Use lex for quotes sourced from Lex’s used car API. |
rental | number | Periodic ex VAT rental amount. Doesn’t include any applicable early termination protection. Converted to 1-0-x if necessary. |
request_type | RequestType | undefined | Indicates whether this was requested as an enquiry or an order. |
residence | Residence | Employee’s residence for tax purposes. |
salary_sacrifice_gross | number | Average monthly gross cost over the full term |
salary_sacrifice_gross_pre_nic_sharing | number | If NIC is shared, represents the gross salary sacrifice amount before NIC is deducted |
salary_sacrifice_net | number | The average monthly net cost over the full term |
term_months | number | Lease term in months |
user_id | string | number | null | Identifier for the employee within Gensen. A string will be returned (unless previously agreed to send as an integer) |
vat_partial_exemption_fraction | number | null | 1 represents 100% VAT recovery by the employer, 0 represents 0% VAT recovery. |
SalsacQuoteEmployee
Represents employee costs over a financial year.
| Field | Type | Description |
|---|---|---|
bik_tax | number | |
hscl_saving | 0 | Deprecated: Will be removed in a future version. |
income_tax_saving | number | |
nic_saving | number | |
nic_saving_shared_with_employee | number | Employer class 1 NIC saving shared with employee. |
salary_sacrifice_gross | number | |
salary_sacrifice_gross_pre_nic_sharing | number | |
salary_sacrifice_net | number | |
tax_saving | number | |
year | string |
SalsacQuoteEmployer
| Field | Type | Description |
|---|---|---|
class_1_nic_saving | number | |
class_1_nic_saving_original | number | This is the employer’s NIC saving prior to sharing with the employee. |
class_1a_nic | number | |
hscl | 0 | Deprecated: Will be removed in a future version. |
hscl_saving | 0 | Deprecated: Will be removed in a future version. |
nic_saving | number | |
nic_savings_shared | number | |
year | string |
SalsacQuoteRequest
| Field | Type | Description |
|---|---|---|
external_ref | string | |
initial_payments | number | If terminal pause (TP), the payments will be converted into spread rental, and if more than 1 in advance, will be converted to 1-0-x. Early termination protection (ETP) is only available on 1 in advance, spread rental, and an error will be returned for invalid payment profiles. |
maintenance | number | |
mileage_yearly | number | |
p11d_value | number | |
payment_profile | "S" | "P" | |
previous_gensen_quote_id | string | |
rental | number | |
term_months | number | Term must match original quote on recalculation, because the motor insurance quote is only valid for the original term. |
OpportunityRequest
| Field | Type | Description |
|---|---|---|
data | SalsacQuote |
OpportunityResponse
The response expected from the 3rd-party CRM after creating an opportunity.
| Field | Type | Description |
|---|---|---|
data? | { opportunity_id: string | number } | |
errors? | readonly { code?: string; message: string }[] | Only required if there is an issue creating the opportunity. Note that this is a machine-to-machine API and so any error messages can only be logged for later debugging. |
status? | number | Deprecated: Legacy field, 0 indicates success, anything else indicates failure. Still used by eFleet (FASS). |
Scalar Types
interface PostalAddress {
line1: string;
line2?: string;
line3?: string;
line4?: string;
line5?: string;
postcode: string;
}Object Types
-
2024-08-14
SalsacQuote:- Added field
addressand related typePostalAddress. - Clarified that postcode may be null for employer-supplied or private insurance.
- Added field
-
2023-07-26
SalsacQuote:- Added fields
effective_early_termination_protection_monthly,one_up_front_effective_rental,one_up_front_effective_maintenance
- Added fields
SalsacQuoteRequest:- Clarified that some payment profiles may be invalid with ETP.
-
2023-07-07
SalsacQuote:- Added fields
salary_sacrifice_gross_pre_nic_sharing,employer_nic_savings_shared,employer_nic_savings_shared_fraction,early_termination_insurance_premium,early_termination_insurance_fraction,early_termination_protection_monthly
- Added fields
SalsacQuoteEmployee:- Added fields
salary_sacrifice_gross_pre_nic_sharing,nic_saving_shared_with_employee
- Added fields
SalsacQuoteEmployer:- Added field
nic_savings_shared,class_1_nic_saving_original
- Added field