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

# Integrate the hosted service point picker into your checkout

The **service point picker** is a Sendcloud-hosted interface that lets customers choose a service point during checkout.
You add it to your checkout page with a small JavaScript snippet, and it opens as an overlay showing nearby service points on a map and in a list.

The picker handles the service point search and selection interface for you. It finds and displays available service points, then returns the customer's selection to your checkout through a JavaScript callback.

This guide is for custom-built checkouts that integrate directly with Sendcloud. If you use one of our plug-and-play integrations, service point selection is already part of the integration.

<Frame>
  <img src="https://mintcdn.com/sendcloud/DdDKRJriEqG9cvye/images/docs/marketplaces/sendcloud-service-point-picker.webp?fit=max&auto=format&n=DdDKRJriEqG9cvye&q=85&s=49ff8b4bbb9dc2df779ceeb241434c10" alt="Service point picker widget" height={607} width={800} noZoom data-path="images/docs/marketplaces/sendcloud-service-point-picker.webp" />
</Frame>

You can try the picker and its configuration options in our [interactive example](https://sendcloud-public.gitlab.io/spp-integration-example/).
The example is a single HTML page, so you can view its source and use it as a starting point.

<Info>
  If you need more control over your service point integration, [build it around Service Points API
  v3](/docs/service-points/find-service-points-with-the-api) instead.
</Info>

## Before you start

The picker uses the carriers enabled for service point delivery in your integration settings. Enable service point delivery and the carriers you want to offer before you start:

1. In the Sendcloud platform, go to your [integration settings](https://app.sendcloud.com/v2/settings/integrations/manage)
2. Find your API integration and click **Configure**
3. Enable service point delivery
4. Enable the carriers you want to use for service point delivery and **save your changes**

<img src="https://mintcdn.com/sendcloud/bH_7gFwWAF2dSsyu/images/docs/service-points/enable-service-points-in-integration-settings.png?fit=max&auto=format&n=bH_7gFwWAF2dSsyu&q=85&s=29c6265e69eda263758ca13d99070dee" alt="Screenshot showing how to enable service points in the integration settings" width="914" height="1232" data-path="images/docs/service-points/enable-service-points-in-integration-settings.png" />

You also need the **public key** of the same integration. You can find it on the integration settings page. See [How to create your API keys](/docs/getting-started/how-to-create-your-api-keys).

<Warning>
  The picker authenticates with the integration public key, which is safe to expose in client-side code. Keep the
  integration secret key private.
</Warning>

## Add the picker script

Add the picker script to your checkout page:

```html Example: loading the picker script theme={null}
<script src="https://embed.sendcloud.sc/spp/1.0.0/api.min.js"></script>
```

Once loaded, the script makes `sendcloud.servicePoints` available to your page. The next section explains how to use this object to display the picker and control its behavior.

<Note>
  If your checkout enforces a Content Security Policy, allow `https://embed.sendcloud.sc` in both `script-src`, for the
  picker script, and `frame-src`, for the picker overlay itself, which is an iframe served from that origin.
</Note>

## Display the picker

Use `sendcloud.servicePoints.open()` to display the picker. It takes three arguments:

```js open() method signature theme={null}
sendcloud.servicePoints.open(config, onSuccess, onFailure)
```

| Argument    | Type       | Description                                                                                                                          |
| ----------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| `config`    | `object`   | Controls which service points are shown and where the picker initially searches. See [Configuration options](#configuration-options) |
| `onSuccess` | `function` | Called with the customer's selection when they choose a service point. See [Handle the selection](#handle-the-selection)             |
| `onFailure` | `function` | Called with an array of messages when opening fails or the customer closes the picker. See [Handle failures](#handle-failures)       |

### Configuration options

| Option           | Type     | Required | Description                                                                                                                                                                        |
| ---------------- | -------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `apiKey`         | `string` | Yes      | Public key of your API integration                                                                                                                                                 |
| `country`        | `string` | Yes      | Country to show service points for, as an ISO 3166-1 alpha-2 code such as `NL` or `FR`                                                                                             |
| `language`       | `string` | No       | Language of the picker interface. One of `de-de`, `en-gb`, `en-us`, `es-es`, `fr-fr`, `it-it`, or `nl-nl`. Defaults to `en-us`                                                     |
| `postalCode`     | `string` | No       | Postal code to center the initial search on                                                                                                                                        |
| `city`           | `string` | No       | City to center the initial search on                                                                                                                                               |
| `address1`       | `string` | No       | Street, optionally with a house number, to center the initial search on                                                                                                            |
| `carriers`       | `string` | No       | Comma-separated carrier codes to show service points for, such as `postnl,dhl`. If omitted, all carriers enabled for service point delivery in your integration settings are shown |
| `shopType`       | `string` | No       | Carrier-specific shop type to filter on, such as `parcelShop`, `packStation`, or `punto_poste`. The supported values depend on the carrier                                         |
| `servicePointId` | `number` | No       | Sendcloud `id` of a service point to center the picker on. The picker opens centered on that service point                                                                         |

<Note>
  The `carriers` option only filters the carriers enabled for service point delivery in your integration settings.
</Note>

If you already have an address to center the initial search on, pass it using `postalCode`, `city`, and `address1`.
The picker then opens near that address instead of requiring the customer to search for it again.

## Handle the selection

When the customer selects a service point, the picker checks that it is still available before completing the selection. If the service point is available, the picker closes and calls your success callback with two arguments:

| Argument       | Type     | Description                                                                                                                        |
| -------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `servicePoint` | `object` | The selected service point. See [Service point fields](#service-point-fields)                                                      |
| `postNumber`   | `string` | Post number entered by the customer when the selected location requires one, such as a DHL PackStation. Otherwise, an empty string |

### Service point fields

The `servicePoint` argument contains the selected service point details:

```json Example: selected service point theme={null}
{
  "id": 1000001,
  "code": "NL-00001",
  "name": "Stadhuisplein Parcel Shop",
  "carrier": "postnl",
  "street": "Stadhuisplein",
  "house_number": "1",
  "postal_code": "5611EM",
  "city": "Eindhoven",
  "country": "NL",
  "latitude": "51.438022",
  "longitude": "5.478543",
  "shop_type": "parcelShop",
  "general_shop_type": "servicepoint",
  "formatted_opening_times": {
    "0": ["10:00 - 20:00"],
    <...>
    "6": []
  },
  "open_tomorrow": true,
  "open_upcoming_week": true,
  "distance": 85
}
```

| Field                     | Type                                                   | Description                                                                                                                                                                                                   |
| ------------------------- | ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`                      | `number`                                               | The Sendcloud `id` of the service point. You need it to create the shipment                                                                                                                                   |
| `code`                    | `string`                                               | The carrier's own identifier for the service point                                                                                                                                                            |
| `name`                    | `string`                                               | The name of the location, suitable for showing back to the customer                                                                                                                                           |
| `carrier`                 | `string`                                               | The code of the carrier operating the service point, such as `postnl`                                                                                                                                         |
| `street`                  | `string`                                               | The street name of the service point address                                                                                                                                                                  |
| `house_number`            | `string`                                               | The house number of the service point address                                                                                                                                                                 |
| `postal_code`             | `string`                                               | The postal code of the service point address                                                                                                                                                                  |
| `city`                    | `string`                                               | The city the service point is located in                                                                                                                                                                      |
| `country`                 | `string`                                               | The country the service point is located in, as an ISO 3166-1 alpha-2 code                                                                                                                                    |
| `latitude`                | `string`                                               | The geographic latitude of the service point, returned as a string                                                                                                                                            |
| `longitude`               | `string`                                               | The geographic longitude of the service point, returned as a string                                                                                                                                           |
| `shop_type`               | `string` or `null`                                     | The carrier-specific classification of the location, such as `packStation`. `null` if the carrier does not provide one                                                                                        |
| `general_shop_type`       | `string` or `null`                                     | The normalized classification of the location. Carrier-specific shop types are mapped onto a fixed set of values: `servicepoint`, `locker`, `post_office`, or `carrier_depot`                                 |
| `formatted_opening_times` | `object` of `string` arrays, keyed `"0"` through `"6"` | The opening hours for the current week, keyed by day number where `0` is Monday and `6` is Sunday. Each day holds an array of time range strings, and an empty array means the location is closed on that day |
| `open_tomorrow`           | `boolean`                                              | Whether the location is open tomorrow                                                                                                                                                                         |
| `open_upcoming_week`      | `boolean`                                              | Whether the location is open at least once in the next seven days                                                                                                                                             |
| `distance`                | `number`                                               | Distance in meters between the location and the point the picker searched around                                                                                                                              |

<Note>
  The service point object returned in the callback uses a different structure than [Service Points API
  v3](/api/v3/service-points/retrieve-a-list-of-service-points) response.
</Note>

Store the selected service point's Sendcloud `id` with the order. If the picker returns a post number, store that as well.
You'll need these values when you create the shipment.

## Handle failures

The failure callback receives a single argument, `errors`, which is an array of strings. Configuration problems can be reported together, so the array may contain more than one value.

The failure callback can return values such as:

| Value              | When the picker returns it                                                                                  |
| ------------------ | ----------------------------------------------------------------------------------------------------------- |
| `Closed`           | The customer closed the picker without selecting a service point. See [Close the picker](#close-the-picker) |
| `Missing API key.` | `apiKey` was an empty string. The picker doesn't open                                                       |
| `No country set.`  | `country` was an empty string. The picker doesn't open                                                      |

`Closed` is the only value you should handle as a separate case. It represents normal customer behavior rather than an error. Treat other values as errors to log or report without assuming the list above is exhaustive.

Errors handled inside the picker are not passed to your failure callback.
For example, if the selected service point is no longer available, a search fails, or a required post number is missing, the picker handles the problem in its own interface and remains open.

## Close the picker

The customer can close the picker with its close button or by pressing **Esc**. Both call your failure callback with `['Closed']`. See [Handle failures](#handle-failures) for how to handle this case.

You can also close the picker from your code, for example when the customer returns to an earlier checkout step:

```js Example: closing the picker from your code theme={null}
sendcloud.servicePoints.close()
```

Calling `close()` from your code does not trigger the success or failure callback.

## Example integration

The following example puts the pieces together. Replace the public key with the one from your integration settings.

```html Example: minimal service point picker integration theme={null}
<script src="https://embed.sendcloud.sc/spp/1.0.0/api.min.js"></script>

<button
  type="button"
  id="chooseServicePoint"
>
  Choose a service point
</button>

<input
  type="hidden"
  id="servicePointId"
  name="servicePointId"
/>
<input
  type="hidden"
  id="servicePointPostNumber"
  name="servicePointPostNumber"
/>

<p id="servicePointSummary"></p>

<script>
  function onServicePointSelected(servicePoint, postNumber) {
    const { id, name, street, house_number, city } = servicePoint
    const summary = `${name}, ${street} ${house_number}, ${city}`

    document.getElementById('servicePointId').value = id
    document.getElementById('servicePointPostNumber').value = postNumber
    document.getElementById('servicePointSummary').textContent = `Selected service point: ${id}: ${summary}`
  }

  function onServicePointPickerFailure(errors) {
    if (errors.includes('Closed')) {
      return
    }
    console.error('Service point picker error:', errors.join(', '))
  }

  document.getElementById('chooseServicePoint').addEventListener('click', () => {
    sendcloud.servicePoints.open(
      {
        apiKey: 'your-integration-public-key',
        country: 'NL',
        language: 'en-gb',
        postalCode: '5611 EM',
        city: 'Eindhoven',
      },
      onServicePointSelected,
      onServicePointPickerFailure,
    )
  })
</script>
```

## Next step

Once you have stored the selected service point `id` and any post number returned by the picker, continue with creating the shipment.

<Card title="Create a shipment with service point delivery" href="/docs/service-points/create-a-shipment-with-service-point-delivery" icon="truck-fast" horizontal>
  Use the selected service point to find a compatible shipping option, then create and announce the shipment.
</Card>
