> ## Documentation Index
> Fetch the complete documentation index at: https://docs.yasmina.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Motor Insurance

> Seamless insurance for the cars you're selling and the drivers that are buying from you.

<div className="ai-note">
  <Icon icon="sparkles" iconType="solid" color="#2563EB" size={18} />

  <p><strong>Build it with AI</strong> — an AI coding assistant can scaffold this entire integration for you straight from these docs. See <a href="/build-with-ai/motor">Build with AI</a> to get started.</p>
</div>

## Introduction

This guide introduces Yasmina’s **Motor Insurance Price Comparison APIs**, covering both comprehensive and TPL cover (for the single-provider versions, see [Comprehensive](/single-provider-integrations/car) and [TPL](/single-provider-integrations/cartpl)). These APIs enable you to retrieve quotes from several insurance companies before issuing a policy to your customer. The guide covers all key operations, including requesting quotes, issuing and managing policies, generating payment links, and handling claims.
Our APIs are built on RESTful principles and follow consistent input and output structures, making them simple to integrate, test, and maintain within your systems

## What you will learn

* Request OTPs
* Requesting and managing quotes
* Uploading vehicle photos
* Issuing and managing policies

## Prerequisites

1. **Account in Yasmina** - See the <a href="/introduction#onboarding" target="_blank">Onboarding section</a> for details. You need "Motor Insurance Comprehensive (Price Comparison)", "Motor Insurance TPL (Price Comparison)", or both in the products field, depending on the cover you want quoted.
2. **Authenticated Token** - You can follow the <a href="/authentication" target="_blank">Authentication guide</a> or head straight to the <a href="/auth-api-reference/oauth-20/generate-token" target="_blank">Generate Token API</a>.
3. **Backend server** - Required to securely call Yasmina APIs.

## Quotes

Quotes represent the different premiums, benefits, and deductibles offered by insurance providers. Before issuing a motor insurance policy, you need to provide the car details to retrieve quotes from various insurance providers. A single quote request returns both comprehensive and TPL offers, so the same flow covers either cover type. These quotes are then used when issuing the policy.

### OTP for quotations

Before requesting quotations, we need to verify the Phone number of the customer through an OTP. You can do that using the <a href="/car-api-reference/otps/request-otp-for-quote-verification" target="_blank">Quote OTP API</a>

You need to provide the following properties for the Quote OTP API:

| Field      | Example Value         | Description                                                                                                                           |
| ---------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `owner_id` | `2234567890`          | The owner’s national ID (starts with `1` for Saudi nationals) or Iqama ID (starts with `2` for residents). Must be exactly 10 digits. |
| `email`    | `someone@example.com` | The owner’s email. Must be unique and belong to the one customer (Do not use the same email for multiple customers).                  |
| `phone`    | `05XXXXXXXX`          | Saudi mobile number. Must start with `05` and be exactly 10 digits.                                                                   |

Example Payload

```
POST /api/v1/car-comp/quote-otp HTTP/1.1
Host: sandbox.yasmina.ai
Accept: application/json
Authorization: Bearer token
Content-Type: application/json
Content-Length: 93

{
    "email": "someone@example.com",
    "phone": "0512345678",
    "owner_id": "1234567890"
}
```

The customer should then receive an OTP. The API returns `204 No Content`.
This quote OTP remains valid for 8 hours and can be reused for multiple quote
requests during that period. You do not need to request a new quote OTP before
every quotation.

The response includes:

* `X-OTP-Expires-In`: Remaining validity in seconds
* `X-OTP-Expires-At`: Exact expiry time in ISO 8601 format

<Note>
  Requesting a new quote OTP invalidates the previously issued quote OTP. After
  8 hours, request a new OTP before submitting another quote request.
</Note>

Afterwards you will be ready to Request Quotations.

### Request Quotes

In order to provide quotes for your customer you need to execute the <a href="/car-api-reference/quotes/request-quotes" target="_blank">Request Quotes API</a>. This API provides an array response from different insurance providers. Each item in this array, represents the name of the company, the logo, the different premiums and deductibles, and also the list of benefits (both free and paid).

<Note>
  The Request Quotes API may take longer to respond because it retrieves results
  from multiple insurance providers. Be sure to increase your timeout to at
  least 2 minutes before making the request.
</Note>

You need to provider the following properties for the Request Quotes API:

| Field                   | Example Value         | Is Required       | Description                                                                                                                                                                     |
| ----------------------- | --------------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `otp`                   | `1234`                | Yes               | The four-digit OTP received by the customer from the Request OTP API.                                                                                                           |
| `owner_id`              | `2234567890`          | Yes               | The owner’s national ID (starts with `1` for Saudi nationals) or Iqama ID (starts with `2` for residents). Must be exactly 10 digits.                                           |
| `email`                 | `someone@example.com` | Yes               | The owner’s email. Must be unique and belong to the one customer (Do not use the same email for multiple customers).                                                            |
| `birthdate`             | `1988-04-20`          | Yes               | Date of birth of the owner in `YYYY-MM-DD` format. For a Saudi national ID (starts with `1`) give a Hijri date; for an Iqama ID (starts with `2`) give a Gregorian date.        |
| `phone`                 | `05XXXXXXXX`          | Yes               | Saudi mobile number. Must start with `05` and be exactly 10 digits.                                                                                                             |
| `car_sequence_number`   | `52423810`            | Conditional       | The car’s sequence number (8-9 digits). Required when `custom_number` is not provided. Do not send both vehicle identifiers.                                                    |
| `custom_number`         | `1234567890`          | Conditional       | Customs card number for an imported vehicle (6-10 digits). Required when `car_sequence_number` is not provided. Also requires `maker_code`, `model_code`, and `body_type_code`. |
| `maker_code`            | `101`                 | With customs card | Vehicle maker code returned by the Vehicle Makers API.                                                                                                                          |
| `model_code`            | `1001`                | With customs card | Vehicle model code returned by the Vehicle Models API for the selected `maker_code`.                                                                                            |
| `body_type_code`        | `3`                   | With customs card | Vehicle body-type code returned by the Vehicle Body Types API.                                                                                                                  |
| `is_ownership_transfer` | `false`               | No                | Boolean flag. `true` if the car is being transferred to a new owner, otherwise `false`. Defaults to `false` when omitted.                                                       |
| `current_car_owner_id`  | `1234567890`          | Yes (if transfer) | The current owner’s national ID (starts with `1`) or Iqama ID (starts with `2`). **Only required if** `is_ownership_transfer = true`.                                           |
| `car_estimated_cost`    | `45000`               | Yes               | Estimated market cost of the car in SAR.                                                                                                                                        |
| `car_model_year`        | `2026`                | No                | Year of manufacture of the car. Must be between 1950 and the next year. If omitted, Yasmina uses the current year.                                                              |
| `start_date`            | `2026-07-28`          | No                | Start date of the policy in `YYYY-MM-DD` format. It must be after today and before the date 28 days from today.                                                                 |
| `drivers`               | See below             | No                | An array of driver objects. When provided, the sum of all `driving_percentage` values must equal 100, and the owner must be included among the drivers.                         |

### Customs card vehicle lookup

If your customer identifies vehicles only by customs card number, collect the
provider-compatible maker, model, and body-type codes before requesting a
quote. Do not send codes from your own vehicle catalogue.

All three lookup endpoints support an optional `q` query parameter. It searches
English and Arabic names without case sensitivity. A complete numeric value
searches by exact code. The maximum search length is 100 characters.

#### 1. Search vehicle makers

```bash theme={null}
curl --request GET \
  --url 'https://sandbox.yasmina.ai/api/v1/car-comp/vehicle-makers?q=Toyota' \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer <token>'
```

Only makers with at least one available model are returned.

#### 2. Search models for the selected maker

`maker_code` is required. The returned model codes belong only to that maker.

```bash theme={null}
curl --request GET \
  --url 'https://sandbox.yasmina.ai/api/v1/car-comp/vehicle-models?maker_code=101&q=Corolla' \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer <token>'
```

#### 3. Search vehicle body types

```bash theme={null}
curl --request GET \
  --url 'https://sandbox.yasmina.ai/api/v1/car-comp/vehicle-body-types?q=SUV' \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer <token>'
```

Each lookup endpoint returns an array with the same structure:

```json theme={null}
[
  {
    "code": 101,
    "name_en": "Toyota",
    "name_ar": "تويوتا"
  }
]
```

<Note>
  For a customs card quote, send `custom_number`, `maker_code`, `model_code`,
  and `body_type_code`. Omit `car_sequence_number`. Yasmina registers the
  imported vehicle with the insurance platform before requesting quotations.
  If the vehicle is already registered, the quotation continues normally.
</Note>

#### Drivers Array

When providing drivers, each driver object must include the following fields:

| Field                | Example Value | Is Required | Description                                                                                                                          |
| -------------------- | ------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| `owner_id`           | `2234567890`  | Yes         | Driver's national ID (starts with `1` for Saudi nationals) or Iqama ID (starts with `2` for residents). Must be exactly 10 digits.   |
| `birthdate`          | `1988-04-20`  | Yes         | Driver's date of birth in `YYYY-MM-DD` format.                                                                                       |
| `driving_percentage` | `50`          | Yes         | Percentage of driving for this driver. Valid values: `25`, `50`, `75`, or `100`. The sum of all drivers' percentages must equal 100. |

<Note>
  When drivers are provided, the vehicle owner must be included among the
  drivers.
</Note>

Example request

```
POST /api/v1/car-comp/quote-requests HTTP/1.1
Accept: application/json
Content-Type: application/json
Authorization: ••••••
Content-Length: 226

{
    "otp": "1234",
    "owner_id": "2234567890",
    "email": "someone@example.com",
    "phone": "05XXXXXXXX",
    "birthdate": "1982-04-20",
    "custom_number": "1234567890",
    "maker_code": 101,
    "model_code": 1001,
    "body_type_code": 3,
    "is_ownership_transfer": false,
    "car_estimated_cost": 45000,
    "car_model_year": 2024,
    "drivers": [
        {
            "owner_id": "2234567890",
            "birthdate": "1982-04-20",
            "driving_percentage": 50
        },
        {
            "owner_id": "1234567891",
            "birthdate": "1990-06-15",
            "driving_percentage": 50
        }
    ]
}
```

Once you execute this you will get a response that includes pricing and benefits
from multiple insurance providers. This is an example of a response, trimmed to a
single provider quote:

```json theme={null}
{
  "owner_id": "1234567890",
  "email": "someone@example.com",
  "phone": "0555555555",
  "birthdate": "1990-01-01",
  "car_sequence_number": 1111111111,
  "is_ownership_transfer": true,
  "current_car_owner_id": "1000000000",
  "car_estimated_cost": 45000,
  "car_model_year": 2024,
  "start_date": "2026-07-28",
  "drivers": [
    {
      "owner_id": "1234567890",
      "birthdate": "1990-01-01",
      "driving_percentage": 50
    },
    {
      "owner_id": "2345678901",
      "birthdate": "1985-06-20",
      "driving_percentage": 50
    }
  ],
  "quotes": [
    {
      "type": "Comprehensive",
      "insurance_type_display": "Comprehensive",
      "insurance_type_display_ar": "شامل",
      "fix_type": "workshop",
      "vehicle_estimated_value": 45000,
      "company_name": "Al Rajhi Takaful",
      "company_name_ar": "تكافل الراجحي",
      "company_logo": "/images/company-logos/art.png",
      "company_logo_url": "https://cdn.yasmina.ai/company-logos/art.png",
      "square_company_logo_url": "https://cdn.yasmina.ai/insurance-logos/alrajhi.png",
      "quote_expiry_date": "2026-10-09T22:03:56+00:00",
      "quote_reference_id": "6c7c18a7-ee89-49fe-9f7e-dde72ad809ce",
      "prices": [
        {
          "quote_price_id": "f5d52340-3661-48af-b81a-028f251ef6a9",
          "deductible": 500,
          "subtotal": 5232.12,
          "vat_percentage": 15,
          "vat": 784.82,
          "total": 6016.94
        },
        {
          "quote_price_id": "40fe40ec-e7d0-f011-972d-005056a9891a",
          "deductible": 1000,
          "subtotal": 5145.03,
          "vat_percentage": 15,
          "vat": 771.75,
          "total": 5916.78
        }
      ],
      "benefits": [
        {
          "quote_benefit_id": "f72846cb-98ed-4b78-b3b5-bb0d587f8da5",
          "id": "1296",
          "name": "Natural Disasters",
          "name_ar": "كوارث طبيعية",
          "amount": 0,
          "vat": 0,
          "url": null
        },
        {
          "quote_benefit_id": "67fe40ec-e7d0-f011-972d-005056a9891a",
          "id": "600100",
          "name": "Roadside assistance service",
          "name_ar": "خدمة المساعدة على الطريق",
          "amount": 10,
          "vat": 1.5,
          "url": null
        }
      ]
    }
  ],
  "attachments": null,
  "client_id": "9f757acd-1ab4-466f-8cb2-d65ddedb2374",
  "updated_at": "2026-10-06T22:03:56.000000Z",
  "created_at": "2026-10-06T22:03:56.000000Z",
  "id": 25
}
```

### Explaining the Quotes Request response

The response has two halves.

The first is an **echo of what you sent** — `owner_id`, `email`, `phone`,
`birthdate`, the vehicle identifier, `drivers`, `start_date`. Nothing new, but it
means a stored response is enough to re-render the customer's page later without
keeping your own copy of the request.

The second is **the offers**: the top-level `id`, and the `quotes` array with one
entry per offer the insurance providers returned.

<Note>
  The same insurance company can appear several times in `quotes`. Each entry is a
  distinct offer — a cover type (`type`) combined with a repair type (`fix_type`).
  Al Rajhi Takaful, for instance, commonly returns a Comprehensive/Agency offer, a
  Comprehensive/Workshop offer and a TPL offer: three entries, each with its own
  `quote_reference_id`, its own prices and its own benefits. Group by
  `company_name` if you want one card per company in your UI.
</Note>

#### The shape at a glance

```text theme={null}
id .......................... the quote request itself → send as quote_request_id
quotes[] .................... one entry per provider offer
├── company_name ............ who is offering
├── type / fix_type ......... what cover, and where it is repaired
├── quote_expiry_date ....... how long the offer stands
├── quote_reference_id ...... identifies this offer → send when issuing
├── prices[] ................ one entry per deductible
│   ├── quote_price_id ...... identifies the chosen deductible → send when issuing
│   └── deductible, subtotal, vat, total
└── benefits[] .............. add-ons attached to this offer
    ├── amount .............. 0 = already included, > 0 = optional extra
    └── quote_benefit_id .... send only for the paid extras the customer picked
```

#### The identifiers you carry into issuance

Policy issuance never re-sends the car or the customer details — it points back at
one exact selection inside this response. Four values do that:

| What the customer chose              | Field you read from this response      | Field you send to the Issue APIs |
| ------------------------------------ | -------------------------------------- | -------------------------------- |
| This quote request                   | `id` (top level)                       | `quote_request_id`               |
| The provider and cover they picked   | `quotes[].quote_reference_id`          | `quote_reference_id`             |
| The deductible and price they picked | `quotes[].prices[].quote_price_id`     | `quote_price_id`                 |
| Each paid add-on they ticked         | `quotes[].benefits[].quote_benefit_id` | `benefits[]`                     |

<Warning>
  All four must describe one consistent selection: the price must belong to the
  same `quotes[]` entry as the reference, and the benefits must belong to that
  same entry too. A `quote_price_id` from one provider sent with another
  provider's `quote_reference_id` is rejected.
</Warning>

The <a href="/car-api-reference/otps/request-otp-for-quote-verification" target="_blank">Issue Policy OTP API</a>
takes the first three; the <a href="/car-api-reference/policies/issue-policy" target="_blank">Issue Policy API</a>
takes all four. Keep the customer's selection around between the two calls.

#### Top-level fields

<ResponseField name="id" type="integer">
  Yasmina's identifier for this quote request. Send it as `quote_request_id` when
  issuing, and use it to fetch the request again with the
  <a href="/car-api-reference/quotes/show-quote" target="_blank">Show Quote Request API</a>.
</ResponseField>

<ResponseField name="quotes" type="object[]">
  The offers returned by the insurance providers. Empty if no provider priced
  this vehicle and driver combination. Each entry is described under **Each
  offer (`quotes[]`)** below.
</ResponseField>

<ResponseField name="attachments" type="object | null">
  The five vehicle photos once they have been uploaded, keyed by position
  (`front`, `back`, `right`, `left`, `chassis`). `null` until you call the
  <a href="/car-api-reference/quotes/upload-vehicle-photos" target="_blank">Upload Vehicle Photos API</a>.
</ResponseField>

<ResponseField name="client_id" type="string (uuid)">
  Your client identifier. Same value on every quote request you create.
</ResponseField>

<ResponseField name="created_at" type="string (date-time)">
  When the quote request was made. Useful together with `quote_expiry_date` when
  deciding whether to re-quote.
</ResponseField>

<ResponseField name="updated_at" type="string (date-time)">
  When the record last changed — for example after vehicle photos were uploaded.
</ResponseField>

Alongside those, the request values come back unchanged: `owner_id`, `email`,
`phone`, `birthdate`, `is_ownership_transfer`, `current_car_owner_id`,
`car_estimated_cost`, `car_model_year`, `start_date` and `drivers`, plus the
vehicle identifier you used. Two details are worth knowing:

* `current_car_owner_id` is filled with `owner_id` when `is_ownership_transfer` is `false`.
* The customs-card fields (`custom_number`, `maker_code`, `model_code`, `body_type_code`) appear only for imported vehicles; `car_sequence_number` appears only for locally registered ones.

<Note>
  Anything not listed here or below is internal bookkeeping. Do not build against
  fields this page does not document — they can change without notice.
</Note>

#### Each offer (`quotes[]`)

<ResponseField name="quote_reference_id" type="string (uuid)">
  The provider's identifier for this offer. Send it as `quote_reference_id` when
  issuing. It is unique per offer, not per company: a company returning three
  cover types returns three different reference IDs.
</ResponseField>

<ResponseField name="company_name" type="string">
  English name of the insurance company, e.g. `Al Rajhi Takaful`.
</ResponseField>

<ResponseField name="company_name_ar" type="string">
  Arabic name of the same company. Falls back to the English name if a company is
  not yet mapped.
</ResponseField>

<ResponseField name="company_logo_url" type="string (uri)">
  Absolute CDN URL of the company's wide logo — the one to put on a quote card.
  Empty string if the company has no logo on file. The CDN host differs between
  sandbox and production, so always render the URL as returned rather than
  rebuilding it.
</ResponseField>

<ResponseField name="square_company_logo_url" type="string (uri)">
  Absolute CDN URL of the same company's square logo, for avatars, list rows and
  other tight spaces. Empty string if none is on file.
</ResponseField>

<ResponseField name="company_logo" type="string">
  **Deprecated.** A path relative to Yasmina's own web app, not a usable URL from
  your side. Kept for backward compatibility only — use `company_logo_url`.
</ResponseField>

<ResponseField name="type" type="string">
  The normalised cover category, and the field to filter and group on. Always one
  of:

  | Value           | Meaning                                                                                                        |
  | --------------- | -------------------------------------------------------------------------------------------------------------- |
  | `Comprehensive` | Covers damage to the customer's own vehicle as well as third parties.                                          |
  | `TPL`           | Third-party liability only.                                                                                    |
  | `TPL +`         | Any enhanced third-party product. Providers name these differently; they are all normalised to this one value. |
</ResponseField>

<ResponseField name="insurance_type_display" type="string">
  The provider's own wording for the same product, unnormalised — `TPL Plus`,
  `TPL + OD`, `Wafi Smart`, and so on. Show this to the customer; filter on
  `type`.
</ResponseField>

<ResponseField name="insurance_type_display_ar" type="string">
  Arabic translation of `insurance_type_display`. Falls back to the English value
  for provider-specific products that have no translation yet.
</ResponseField>

<ResponseField name="fix_type" type="string">
  Where a claim gets repaired: `Agency` (the manufacturer's authorised dealer,
  more expensive) or `workshop` (an approved independent garage). Empty for TPL
  offers, which carry no own-damage repair. This is the single biggest reason two
  offers from the same company differ in price, so it is worth surfacing in the
  UI.
</ResponseField>

<ResponseField name="vehicle_estimated_value" type="number">
  The vehicle value this offer was priced against, in SAR. Normally the provider's
  own valuation; it falls back to the `car_estimated_cost` you sent when the
  provider does not return one. Worth showing on Comprehensive offers, since it is
  the ceiling of an own-damage payout.
</ResponseField>

<ResponseField name="quote_expiry_date" type="string (date-time)">
  When the provider's offer lapses. Validity varies by provider and by product —
  some offers stand for days, others for months. After this moment the offer can
  no longer be issued, so request fresh quotes rather than replaying a stored
  response.
</ResponseField>

<ResponseField name="prices" type="object[]">
  The price options for this offer, one per deductible. See below.
</ResponseField>

<ResponseField name="benefits" type="object[]">
  The benefits attached to this offer, both included and optional. See below.
</ResponseField>

#### Price options (`quotes[].prices[]`)

One offer carries several prices — the same cover at different deductibles. The
deductible is what the customer pays out of their own pocket on a claim, so a
higher deductible buys a lower premium. A comprehensive offer routinely comes with
ten or more of these; a TPL offer usually has exactly one.

<ResponseField name="quote_price_id" type="string (uuid)">
  Identifies the price the customer picked. Send it as `quote_price_id` when
  issuing, and to the Upload Vehicle Photos API.
</ResponseField>

<ResponseField name="deductible" type="number | null">
  The excess in SAR that the customer bears on each claim. `null` on TPL offers,
  which have no deductible.
</ResponseField>

<ResponseField name="subtotal" type="number">
  The premium for this option in SAR, before VAT.
</ResponseField>

<ResponseField name="vat_percentage" type="number">
  The VAT rate applied, as a percentage. `15` in Saudi Arabia today.
</ResponseField>

<ResponseField name="vat" type="number">
  The VAT amount in SAR for this option.
</ResponseField>

<ResponseField name="total" type="number">
  `subtotal` + `vat` — what the customer pays for the cover itself. It does **not**
  include any optional benefits — see **What the customer actually pays** below.
</ResponseField>

#### Benefits (`quotes[].benefits[]`)

Benefits are the add-ons that come with an offer. `amount` alone tells you which
of the two kinds you are looking at:

| `amount` | Kind     | What you do                                                                                        |
| -------- | -------- | -------------------------------------------------------------------------------------------------- |
| `0`      | Included | Already part of the cover. Display it; do **not** send it when issuing.                            |
| `> 0`    | Optional | An extra the customer may add. Send its `quote_benefit_id` in `benefits[]` when issuing to buy it. |

<ResponseField name="quote_benefit_id" type="string (uuid)">
  Identifies this benefit on this offer. Collect the IDs of the paid benefits the
  customer ticked and send them as the `benefits` array to the Issue Policy API.
  The ID is specific to one offer — a benefit that also appears on another
  provider's offer has a different `quote_benefit_id` there.
</ResponseField>

<ResponseField name="id" type="string">
  The provider's benefit code, e.g. `600100` for roadside assistance. Stable
  across quote requests, so it is the right key if you want to remember a
  customer's preferences or map benefits to your own icons and copy.
</ResponseField>

<ResponseField name="name" type="string">
  English name of the benefit, e.g. `Roadside assistance service`.
</ResponseField>

<ResponseField name="name_ar" type="string">
  Arabic name of the same benefit.
</ResponseField>

<ResponseField name="amount" type="number">
  Price of the benefit in SAR, excluding VAT. `0` means it is included in the
  cover at no extra cost.
</ResponseField>

<ResponseField name="vat" type="number">
  VAT on `amount`, in SAR. `0` for included benefits.
</ResponseField>

<ResponseField name="url" type="string | null">
  A provider link with the benefit's terms, when the provider supplies one.
  Usually `null` — render the link only when it is present.
</ResponseField>

#### What the customer actually pays

`prices[].total` is the price of the cover on its own. Every paid benefit the
customer adds is charged on top of it, with its own VAT. Taking the example
response above, with the 500 SAR deductible and roadside assistance added:

| Line                           | Amount (SAR) |
| ------------------------------ | ------------ |
| Premium (`subtotal`)           | 5232.12      |
| VAT on the premium (`vat`)     | 784.82       |
| Roadside assistance (`amount`) | 10.00        |
| VAT on roadside assistance     | 1.50         |
| **Total charged**              | **6028.44**  |

You do not have to compute this yourself to charge the customer — the Issue Policy
API returns the final `price` on the policy object and generates a payment link
for exactly that amount. Compute it only to show the customer a breakdown before
they commit.

<Note>
  Included benefits (`amount` = 0) never change the price. Adding them to the
  `benefits` array when issuing is unnecessary.
</Note>

#### Arabic localisation fields

Each quote object includes Arabic counterparts for the fields that typically appear in the UI. Use these when rendering an Arabic experience:

| Field                    | Arabic equivalent           | Notes                                                                                                                                                         |
| ------------------------ | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `company_name`           | `company_name_ar`           | Arabic name of the insurance company                                                                                                                          |
| `insurance_type_display` | `insurance_type_display_ar` | Arabic label for the insurance type as the provider intends it to be shown. Falls back to the English value for provider-specific types without a translation |
| `benefits[].name`        | `benefits[].name_ar`        | Arabic name of each benefit                                                                                                                                   |

`type` is a normalised category value used for filtering and grouping (`TPL`, `TPL +`, `Comprehensive`) and has no Arabic equivalent — use `insurance_type_display_ar` for display purposes.

Both languages are present in every quote, so rendering an Arabic quote card never
takes a second call.

### List Quotes Requests

You can list a paginated list of all the quote requests that your account has generated. In order to do so, you can use the

<a href="/car-api-reference/quotes/list-quotes" target="_blank">
  List quote requests API
</a>

You can filter these by using `owner_id` in the query string. This may be useful in case your customer navigated from one page to another and you need to show the quote requests again (rather than making a new request)

Example:
GET /car-api-reference/quotes/list-quotes?page=2\&per\_page=1\&owner\_id=1234567890

### Delete Quotes Requests

You can delete some of the requests from the system using the <a href="/car-api-reference/quotes/delete-quote" target="_blank">Delete Quotes Requests API</a>.

This is rarely used, but may be helpful if you'd like to reduce the items listed.

## Vehicle photos

If the customer has selected a comprehensive policy, upload the five photos before you
issue the policy — front, back, right, left, and the chassis (VIN) number. Use the
<a href="/car-api-reference/quotes/upload-vehicle-photos" target="_blank">Upload Vehicle Photos API</a>,
against the quote request and the price the customer selected.

<Warning>This step is required for comprehensive cover. If the photos are not uploaded,
the customer cannot continue with the purchase. It must happen before you request the
payment OTP.</Warning>

Example of a request

```
POST /api/v1/car-comp/quote-requests/11/attachments HTTP/1.1
Authorization: Bearer *****
Content-Type: multipart/form-data

quote_price_id=e059d28e-a519-43af-b9d4-e1cc5d97ecb7
front=@front.jpg
back=@back.jpg
right=@right.jpg
left=@left.jpg
chassis=@chassis.jpg
```

Example of a response

```
{
  "attachments": {
      "front": "https://cdn.yasmina.ai/vehicle-photos/abc123.jpg",
      "back": "https://cdn.yasmina.ai/vehicle-photos/def456.jpg",
      "right": "https://cdn.yasmina.ai/vehicle-photos/ghi789.jpg",
      "left": "https://cdn.yasmina.ai/vehicle-photos/jkl012.jpg",
      "chassis": "https://cdn.yasmina.ai/vehicle-photos/mno345.jpg"
  }
}
```

| Position  | What it shows                      |
| --------- | ---------------------------------- |
| `front`   | The front of the vehicle           |
| `back`    | The rear of the vehicle            |
| `right`   | The right-hand side of the vehicle |
| `left`    | The left-hand side of the vehicle  |
| `chassis` | The chassis (VIN) number           |

### Rules

* **All five together.** A partial upload is rejected with a `422`.
* **JPG or PNG, up to 3 MB each.** Other formats and anything larger are rejected.
* **Once per vehicle.** The insurance provider keeps the first set it accepts. A later
  upload for the same vehicle still returns `200`, with `already_registered: true` in the
  response, but the registered photos do not change. Check the photos before sending them.
* **Comprehensive only.** A `quote_price_id` belonging to a TPL quote is rejected.

## Issuing policies

### Issue Policy OTP

When a customer selects a quotation, they need to go through another OTP check. This time you need to request it through the <a href="/car-api-reference/otps/request-otp-for-quote-verification" target="_blank">Issue OTP API</a>

The Issue Policy OTP requires the following fields:

The three quote identifiers must come from the response returned by the earlier
`POST /quote-requests` call. Use the provider quote and price selected by the
customer from that same response.

| Field                | Example Value                          | Description                                                                                                                                                                                                                                      |
| -------------------- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `quote_request_id`   | `62`                                   | Use the top-level `id` from the quote request response.                                                                                                                                                                                          |
| `quote_reference_id` | `feb9e0ec-d71c-4c60-99d4-22ad9a5c97ec` | Use `quotes[].quote_reference_id` from the insurance provider quote selected by the customer.                                                                                                                                                    |
| `quote_price_id`     | `f0a13788-92c3-f011-972d-005056a9891a` | Use `quotes[].prices[].quote_price_id` from the selected price and deductible inside the same provider quote.                                                                                                                                    |
| `owner_id`           | `2234567890`                           | The owner’s national ID (starts with `1` for Saudi nationals) or Iqama ID (starts with `2` for residents). Must be exactly 10 digits.                                                                                                            |
| `email`              | `someone@example.com`                  | The owner’s email. It must belong to this customer. Do not reuse the same email address for different customers.                                                                                                                                 |
| `phone`              | `0512345678`                           | Saudi mobile number. Must start with `05` and be exactly 10 digits.                                                                                                                                                                              |
| `iban`               | `SA0380000000608010167519`             | The customer's Saudi IBAN (`SA` followed by 22 digits, no spaces). It is sent to the insurance provider with the payment OTP request and used to transfer claim settlements and refunds to the customer; the account is never charged. Required. |

Example request:

```
POST /api/v1/car-comp/issue-otp HTTP/1.1
Host: sandbox.yasmina.ai
Accept: application/json
Authorization: Bearer token
Content-Type: application/json
Content-Length: 249

{
    "email": "someone@example.com",
    "phone": "0512345678",
    "owner_id": "2234567890",
    "quote_request_id": 62,
    "quote_reference_id": "feb9e0ec-d71c-4c60-99d4-22ad9a5c97ec",
    "quote_price_id": "f0a13788-92c3-f011-972d-005056a9891a",
    "iban": "SA0380000000608010167519"
}
```

The customer will receive a separate policy issuance OTP, and the API returns
`204 No Content` on success. This OTP is valid for 15 minutes and must be
supplied to the Issue Policy API within that period. If it expires, request a
new issuance OTP before issuing the policy.

<Warning>
  The 8-hour quote OTP validity does not apply here. The policy issuance OTP
  expires after 15 minutes.
</Warning>

### Issuing a policy

In order to Issue a policy. You can head to the <a href="/car-api-reference/policies/issue-policy" target="_blank">Issue Policy API </a>

Use the same three identifiers previously sent to the Issue Policy OTP API.
They must all come from the earlier `POST /quote-requests` response and represent
one consistent customer selection.

| Field                | Description                                                                                                                                                                                                |
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `quote_request_id`   | Use the top-level `id` returned by the earlier `POST /quote-requests` call.                                                                                                                                |
| `quote_reference_id` | Use `quotes[].quote_reference_id` from the insurance provider quote selected by the customer in that quote response.                                                                                       |
| `quote_price_id`     | Use `quotes[].prices[].quote_price_id` from the selected price and deductible inside the same provider quote.                                                                                              |
| `benefits`           | A list of selected benefit IDs. Only required if the benefit has a cost (`amount > 0`).                                                                                                                    |
| `extra_data`         | Optional JSON object to store additional metadata or custom values that can later be used in <a href="/webhooks/guide" target="_blank">webhooks</a>. Please keep minimal as it can't exceed 255 characters |
| `redirect_url`       | Optional URL that the customer gets redirected to once a successful purchase is made                                                                                                                       |
| `otp`                | The OTP that you got from the issue-otp API                                                                                                                                                                |

Example of a request

```
POST /api/v1/car-comp/policies HTTP/1.1
Authorization: Bearer *****
Content-Type: application/json
Accept: application/json
Content-Length: 212

{
  "otp": "1234",
  "quote_request_id": 11,
  "quote_reference_id": "04486448-3433-43ef-a755-b07799d6580f",
  "quote_price_id": "e059d28e-a519-43af-b9d4-e1cc5d97ecb7",
  "benefits": [],
  "extra_data": {
      "extra_field": 1
  }
}
```

Once you make a request to the Issue Policy API, you will get the Policy object with a `201` HTTP response code. Here is an example of the Policy object.

```
{
    "id": 700,
    "meta_data": {
        "extra_data": null,
        "new_owner_id": "2528297837",
        "quote_price_id": "f5d52340-3661-48af-b81a-028f251ef6a9",
        "quote_request_id": 25,
        "previous_owner_id": "1001364939",
        "car_sequence_number": 723787810
    },
    "provider_policy_id": null,
    "provider_policy": null,
    "created_at": "2025-10-06T23:31:17.000000Z",
    "status": 0,
    "payment_link": "http://localhost:8000/short/wVln4",
    "price": 6016
}
```

This is a summary of the fields returned in the policy object

| Field                | Description                                                                                                                               |
| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `id`                 | Yasmina’s unique identifier for the policy.                                                                                               |
| `meta_data`          | A JSON object that contains information about the fields that were used to generate this policy. `extra_data` will also be returned here. |
| `provider_policy_id` | The policy ID that is returned by the policy provider.                                                                                    |
| `provider_policy`    | A URL that contains the policy in PDF format.                                                                                             |
| `created_at`         | When was the policy issued.                                                                                                               |
| `status`             | 0 = Pending, 1 = Issued.                                                                                                                  |
| \`payment\_link      | A secure payment link generated by Yasmina                                                                                                |
| `price`              | The price of the policy in Saudi Riyal                                                                                                    |

### Payment and Policy activation

When you first make a request to the Issue Policy API. The Policy is not yet activated and the `status` is `0` (which means pending).

Also the `provider_policy` and `provider_policy_id` will both be `null`.

In order for the policy to be activated, the customer needs to make the purchase from the payment link. Once the customer successfully pays. The policy will be activated and the `status` becomes `1`.

<Note>
  Although the payment page is provided by Yasmina, it does not display the
  Yasmina logo or have any mention of Yasmina. <br />

  <br />

  Yasmina does not receive credit card information, instead the payment page
  sends card information directly to the payment vendor.
</Note>

<Tip>
  On Sandbox, you can use a testing card with the following
  information: <br /> Card number: 4111 1111 1111 1111 <br /> Expiry: 02/27{" "}
  <br /> CVV: 123 <br />
  Card owner: Yasmina test
</Tip>

### Redirect URL

You can supply the payload a `redirect_url`. This is used to redirect the customer to any page or deep link you need. You can also include a query string with policyID and it will automatically replace it with the actual `id` of the policy object.

Example for policy `id` 123

```
	{
		...,
		redirect_url: "https://www.example.com?yasmina_policy_id=policyID"
	}
```

Will become on the response

```
	{
		redirect_url: "https://www.example.com?yasmina_policy_id=123"
	}
```

And the customer that purchased the policy will be redirected to
[https://www.example.com?yasmina\_policy\_id=123](https://www.example.com?yasmina_policy_id=123)

### Showing a policy

In order to get a status of a policy, you can use the <a href="/car-api-reference/policies/show-policy" target="_blank">Show Policy API</a>. This API, takes a Yasmina Policy `id` and will return the policy object
This API is ideal when you want to re-fetch a specific policy after the PDF gets generated.

Example of a request

```
GET /api/v1/car-comp/policies/123 HTTP/1.1
Host: production.yasmina.ai
Authorization: Bearer <token>
Content-Type: application/json
Accept: application/json
```

Example a response

```
{
    "id": 659,
    "meta_data": {
        "extra_data": {
        },
        "new_owner_id": "2467701575",
        "quote_price_id": "097116f9-99b1-491f-a2ab-f86b2c535cbe",
        "quote_request_id": 4,
        "previous_owner_id": "2467701575",
        "car_sequence_number": 52423810
    },
    "product_id": 4,
    "provider_policy_id": "53018c24-b246-4bef-866f-4a54c2367196",
    "provider_policy": "policy.pdf",
    "created_at": "2025-09-07T07:53:55.000000Z",
    "status": 1,
    "payment_link": null,
    "price": null
}
```

### Listing policies

You can also use the <a href="/car-api-reference/policies/list-policies" target="_blank">List Policies API</a> to get a list of all policies that were generated from our system. You might use this on your admin interface, or if you just want to check what has been generated.
