🏆 We won the Shopify Build Award Read more →

Developer reference

Custom endpoint

Custom endpoints let you offer pickup points from any source not covered by our built-in carrier integrations. This feature requires Shopify Plus and a developer to implement the endpoint.

How it works

In Shopify Admin → Atlas Pickup Points, open the pickup point configuration, select Custom as the carrier, and paste your endpoint URL. Each time pickup points are displayed, Atlas makes a GET request to your endpoint with the following query parameters:

ParameterNameDescription
latLatitudeLatitude of the buyer’s shipping address or their position on the map
lngLongitudeLongitude of the buyer’s shipping address or their position on the map
country_codeCountry codeCountry code (ISO 3166-1 alpha-2) of the buyer’s shipping address. Does not change if the buyer moves the map to a different country.
qSearch queryOptional: search query from the list view. Search can be enabled in the custom endpoint settings.

If your endpoint requires additional options, you can pass them as query parameters and they will be merged with the parameters above.

Authentication

If your endpoint requires authentication, you can add a secret in the custom endpoint settings. Atlas will send it as the x-atlas-pickup-points-secret header with every request, allowing your endpoint to verify that the request is coming from Atlas.

Your endpoint must respond with JSON in the following format:

{
  "locations": [
    {
      "code": "019889",
      "address": {
        "address1": "19 BOULEVARD GALLIENI",
        "address2": null,
        "city": "NEUILLY PLAISANCE",
        "zip": "93360",
        "country_code": "FR",
        "latitude": 48.8532417,
        "longitude": 2.514444
      },
      "details": {
        "name": "NEW HIGH TECH GSM",
        "description": null,
        "business_hours": [
          {
            "day": "MONDAY",
            "opening_time": "08:00",
            "closing_time": "21:00"
          },
          {
            "day": "TUESDAY",
            "opening_time": "08:00",
            "closing_time": "21:00"
          },
          {
            "day": "WEDNESDAY",
            "opening_time": "08:00",
            "closing_time": "21:00"
          },
          {
            "day": "THURSDAY",
            "opening_time": "08:00",
            "closing_time": "21:00"
          },
          {
            "day": "FRIDAY",
            "opening_time": "08:00",
            "closing_time": "21:00"
          },
          {
            "day": "SATURDAY",
            "opening_time": "08:00",
            "closing_time": "21:00"
          },
          {
            "day": "SUNDAY",
            "opening_time": "09:00",
            "closing_time": "20:00"
          }
        ],
        "open_24_hours": false
      },
      "attributes": [
        {
          "key": "type",
          "value": "PUDO"
        }
      ]
    },
    {
      "code": "014514",
      "address": {
        "address1": "32 RUE ROGER-SALENGRO",
        "address2": null,
        "city": "FONTENAY SOUS BOIS",
        "zip": "94120",
        "country_code": "FR",
        "latitude": 48.855606,
        "longitude": 2.474787
      },
      "details": {
        "name": "LOCKER 24/7 INTERMARCH ROGER SA",
        "description": null,
        "business_hours": [],
        "open_24_hours": true
      },
      "attributes": [
        {
          "key": "type",
          "value": "LOCKER"
        }
      ]
    }
  ]
}

Response

Response object

KeyRequiredTypeDescription
locationstrueLocation[]List of available pickup points for the requested coordinates
error_messagefalseStringError message visible in the network response (not shown in the UI)

Location object

KeyRequiredTypeDescription
codetrueStringUnique identifier of the pickup point
addresstrueAddressPickup point address
detailstrueDetailsPickup point details
attributesfalseAttributes[]Additional attributes that will be passed to the order
icon_urlfalseStringURL of the map pin icon. Should be a PNG hosted on Shopify CDN.

Address object

KeyRequiredTypeDescription
address1trueStringFirst line of the address (street and number)
address2falseStringSecond line of the address (not visible to the buyer)
citytrueStringCity
ziptrueStringPostal code
country_codetrueStringCountry code ISO 3166-1 alpha-2
latitudetrueFloatLatitude
longitudetrueFloatLongitude

Details object

KeyRequiredTypeDescription
nametrueStringLocation name, displayed to the buyer
descriptionfalseStringDescription of the location, displayed to the buyer
business_hoursfalseBusinessHour[]List of opening hours. If unknown or 24/7, send empty array.
open_24_hoursfalseBooleanIs the location open 24/7? If unknown, send false.

BusinessHour object

KeyRequiredTypeDescription
daytrueEnum: MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY SUNDAYDay of the week
opening_timetrueStringTime in 24h format, for example: 01
or 23
closing_timetrueStringTime in 24h format, for example: 01
or 23

Attributes object

KeyRequiredTypeDescription
keytrueStringKey of the attribute
valuetrueString / Boolean / NumberValue of the attribute

TypeScript type

type CustomIntegrationResponse = {
  error_message?: string | null;
  locations: {
    code: string;
    address: {
      address1: string;
      address2?: string | null;
      city: string;
      zip: string;
      longitude: number;
      latitude: number;
      country_code: string;
    };
    details: {
      name: string;
      description?: string | null;
      business_hours: {
        day: "MONDAY" | "TUESDAY" | "WEDNESDAY" | "THURSDAY" | "FRIDAY" | "SATURDAY" | "SUNDAY";
        opening_time: string;
        closing_time: string;
      }[];
      open_24_hours: boolean;
    };
    attributes: {
      key: string;
      value: string | number | boolean;
    }[];
    icon_url?: string | null;
  }[];
};

Implementation tips

Hosting options

We recommend Heroku, AWS Lambda, or Cloudflare Workers. For the best performance and lowest latency, deploy in the EU region, preferably AWS eu-west-1 (Ireland), where our infrastructure is located.

For static locations (up to 50):

  1. Create a JSON file with your locations
  2. Upload it in Shopify Admin → Content → Files
  3. Use the CDN URL as your endpoint

Troubleshooting

If you receive a CUSTOM_INTEGRATION_INVALID_RESPONSE error:

  1. Open your browser’s Developer Tools
  2. Go to the Network tab
  3. Find the request to the /locations endpoint
  4. Inspect the response to see detailed error information

While we don’t assist with implementation, our support team is happy to help with debugging issues.