---
title: "Attraction developer hub"
description: "Start here to bring Attraction product data into your tools and agents through our API or PromoStandards."
locale: "en-ca"
canonical: "https://www.attraction.com/en-ca/developers/"
markdown: "https://www.attraction.com/en-ca/developers.md"
last_updated: "2026-09-11"
---

# Attraction developer hub

Start here to bring Attraction product data into your tools and agents through our API or PromoStandards.

<a id="start-here"></a>

## Integrations and access

<a id="authentication"></a>

- **[Attraction API](/en-ca/api/) (REST/JSON).** Public product data needs no key. Account net pricing requires an API key. See the [API reference](/en-ca/api/), its [authentication instructions](/en-ca/api/#authentication) and the [OpenAPI description](https://api.attraction.com/openapi.json).

- **[PromoStandards](/en-ca/promo/promostandards/) (SOAP/XML, promotional).** Connect compatible software to product, inventory, media and pricing services. PromoStandards credentials are separate from REST keys.

<a id="errors"></a>

## Errors and recovery

<a id="rest-errors"></a>

### Attraction API (REST/JSON)

REST errors follow [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457) and are served as `application/problem+json`. The code identifies the cause; the guidance below explains how to correct a request or when to retry.

Each `code` keeps its `type` URI: `https://www.attraction.com/developers/#error-<code>`.

```json
{
  "type": "https://www.attraction.com/developers/#error-product_not_found",
  "title": "Product not found",
  "status": 404,
  "detail": "No product matches SKU NOPE-NOT-A-SKU.",
  "instance": "/v1/products/nope-not-a-sku",
  "code": "product_not_found"
}
```

<a id="error-route_not_found"></a>

#### route_not_found (HTTP 404)

No route matches the request path.

**Action.** Check the path in the [API reference](/en-ca/api/). Correct the URL before retrying.

<a id="error-method_not_allowed"></a>

#### method_not_allowed (HTTP 405)

The route exists but not for that HTTP method. The response carries `Allow: GET, HEAD, OPTIONS`.

**Action.** Use a method listed in `Allow`. Correct the request before retrying.

<a id="error-invalid_request"></a>

#### invalid_request (HTTP 400)

The request does not match what the route expects, for example a malformed query parameter.

**Action.** Correct the parameter identified in `detail` using the [API reference](/en-ca/api/).

<a id="error-unsupported_locale"></a>

#### unsupported_locale (HTTP 400)

`locale` must be `en-CA`, `en-US`, or `fr-CA`.

**Action.** Use one of the three accepted canonical values: `en-CA`, `en-US`, or `fr-CA`.

<a id="error-invalid_sku"></a>

#### invalid_sku (HTTP 400)

The `sku` path parameter is not a valid SKU.

**Action.** Check the SKU in the [product list](/en-ca/api/#list-products), then correct the path parameter.

<a id="error-unauthorized"></a>

#### unauthorized (HTTP 401)

Reserved for the private `/v1/sync/*` routes; the public product endpoints never return this.

**Action.** This code concerns a private integration. Ask its owner to check its permissions.

<a id="error-key_required"></a>

#### key_required (HTTP 401)

`GET /v1/products/{sku}/pricing` or `GET /v1/products/pricing` was called with no credentials. That route prices one account, so it has no public fallback. The product endpoints answer anonymously with MSRP. The response carries `WWW-Authenticate: Bearer realm="api.attraction.com"` with no `error` parameter: nothing was presented to reject.

**Action.** Add an account key following the [authentication instructions](/en-ca/api/#authentication), then retry.

<a id="error-invalid_key"></a>

#### invalid_key (HTTP 401)

The `Authorization: Bearer` header carries a key the API cannot recognise. `detail` says which: **not recognised** (often copied incompletely), or **malformed**, meaning it lacks the shape `attr_sk_<16 hex characters>_<43 characters>`. Either way, create a new one on the [API keys page](/en-ca/api/keys/). The response carries `WWW-Authenticate: Bearer realm="api.attraction.com", error="invalid_token"`.

**Action.** Check that you copied the complete key. Replace it if needed before retrying; do not remove authentication to bypass the error.

<a id="error-key_revoked"></a>

#### key_revoked (HTTP 401)

The API key is no longer active: it was revoked, or the account behind it no longer holds distributor pricing (closed, deactivated, or off its price tier). The key and account can be checked on the [API keys page](/en-ca/api/keys/). A tier change never causes this. A key follows its account's live tier.

**Action.** Check the account's distributor access and create a new key if the old one was revoked. Repeating the same request does not reactivate a key.

<a id="error-product_not_found"></a>

#### product_not_found (HTTP 404)

No product matches the given SKU.

**Action.** Read the [product list](/en-ca/api/#list-products) and select an existing SKU before retrying.

<a id="error-rate_limited"></a>

#### rate_limited (HTTP 429)

The client is over the [rate-limit policy](#rate-limits). The response carries `Retry-After` and the `RateLimit`/`RateLimit-Policy` headers.

**Action.** Wait for the `Retry-After` interval, then reduce the request frequency.

<a id="error-upstream_unavailable"></a>

#### upstream_unavailable (HTTP 503)

The public Product API cannot reach its catalogue source or verify API keys. The response carries `Retry-After: 30`.

**Action.** Wait for the interval specified by `Retry-After` before retrying. Contact support if the error persists.

<a id="error-internal_error"></a>

#### internal_error (HTTP 500)

An unexpected server error, with no stack trace or internal detail in the response.

**Action.** Check the [API status](https://api.attraction.com/v1/health). If the error persists, send support the operation and the time of the failure.

<a id="promostandards-errors"></a>

### PromoStandards (SOAP/XML)

Check the HTTP status first: a temporary rejection can return `429` or `503` without a SOAP response. PromoStandards application errors arrive in XML with HTTP 200. Check the response body even when transport succeeds. Invalid envelopes and unknown operations produce SOAP Faults. The [PromoStandards reference](/en-ca/promo/promostandards/) describes the requests and schemas.

<a id="promostandards-common-errors"></a>

#### PromoStandards access and requests

All four services can return these codes in an XML response with HTTP `200`. Check the response body before treating the request as successful. PromoStandards credentials are separate from REST API keys.

<a id="promostandards-error-common-104"></a>

##### 104

Inactive PromoStandards account.

**Action.** Contact Attraction to restore access before resuming requests.

<a id="promostandards-error-common-105"></a>

##### 105

Authentication failed.

**Action.** Check the `id` and `password` pair issued for your PromoStandards access. Correct the credentials before retrying.

<a id="promostandards-error-common-110"></a>

##### 110

Missing password.

**Action.** Include `password` in the SOAP request body.

<a id="promostandards-error-common-115"></a>

##### 115

Unrecognized service version.

**Action.** Match `wsVersion` to the endpoint’s service version and use that version’s WSDL.

<a id="promostandards-error-common-120"></a>

##### 120

Missing required field, or an invalid `changeTimeStamp` in a date-modified request.

**Action.** Supply the fields listed in `description`. For `changeTimeStamp`, provide a valid XML `dateTime` value.

<a id="promostandards-error-common-999"></a>

##### 999

General service error.

**Action.** Contact Attraction with the service, operation, request time and returned code. Remove the password from any request example you share.

<a id="promostandards-product-data-errors"></a>

#### Product Data 2.0.0

Errors appear in `ServiceMessageArray.ServiceMessage`, with `code`, `description` and `severity: Error`. An empty product list, including a response to `GetProductCloseOutRequest`, can be valid.

<a id="promostandards-error-product-data-125"></a>

##### 125

Unsupported country or language.

**Action.** Use `localizationCountry: CA` or `US`, with `localizationLanguage: en`.

<a id="promostandards-error-product-data-130"></a>

##### 130

Product not found, no longer sellable or unavailable in the requested market.

**Action.** Check `productId` against the requested market’s sellable products using `GetProductSellableRequest`.

<a id="promostandards-error-product-data-140"></a>

##### 140

The product has no matching `partId`.

**Action.** Retrieve the product without the `partId` filter, then use a returned part identifier.

<a id="promostandards-error-product-data-145"></a>

##### 145

No part matches the requested colour after applying the optional `partId` filter.

**Action.** Check `colorName` and its combination with `partId` against an unfiltered product response.

<a id="promostandards-error-product-data-150"></a>

##### 150

No part matches the requested sizes after the other filters have been applied.

**Action.** Use the product’s `labelSize` values and check the combination of part, colour and size filters.

<a id="promostandards-inventory-errors"></a>

#### Inventory 2.0.0

Errors appear in `ServiceMessageArray.ServiceMessage`, with `code`, `description` and `severity: Error`. A filter with no matching parts returns an empty list without error `600`.

<a id="promostandards-error-inventory-600"></a>

##### 600

Product not found or no longer sellable.

**Action.** Verify `productId` through Product Data before resuming inventory synchronization.

<a id="promostandards-media-content-errors"></a>

#### Media Content 1.1.0

Errors appear in the single `errorMessage` element, with `code` and `description`. This service does not return a `ServiceMessageArray` or a `severity` field. Filters with no matching media can produce a valid empty response.

<a id="promostandards-error-media-content-125"></a>

##### 125

Unsupported culture or media type.

**Action.** Use `cultureName: en-CA` or `en-US`. Supported `mediaType` values are `Image`, `Video`, `Audio` and `Document`.

<a id="promostandards-error-media-content-130"></a>

##### 130

Product not found or no longer sellable, or the product has no matching `partId`.

**Action.** Check `productId` and, when supplied, `partId` against Product Data responses.

<a id="promostandards-ppc-errors"></a>

#### Product Pricing and Configuration 1.0.0

Errors appear in the single `ErrorMessage` element, with `code` and `description`, without `severity`. Decoration location, charge and decoration colour operations return valid empty responses for a recognized product.

<a id="promostandards-error-ppc-400"></a>

##### 400

Product not found or no longer sellable, or the product has no matching `partId`.

**Action.** Check `productId` and, when supplied, `partId` against Product Data responses.

<a id="promostandards-error-ppc-401"></a>

##### 401

No published pricing for this product in the requested currency.

**Action.** Use a currency returned by `GetFobPointsRequest` for this product.

<a id="promostandards-error-ppc-402"></a>

##### 402

Unsupported price type, or no published net price grid for the requested product.

**Action.** Use `priceType: List` for public prices or `Net` when a standard net grid is published. `Customer` is not supported. A `List` price is not a replacement for a missing `Net` price.

<a id="promostandards-error-ppc-403"></a>

##### 403

Unrecognized `fobId` shipping point.

**Action.** Use the `fobId` returned by `GetFobPointsRequest` for this product.

<a id="promostandards-error-ppc-404"></a>

##### 404

Unsupported country.

**Action.** Use `localizationCountry: CA` or `US`. This XML code is not an HTTP 404 status.

<a id="promostandards-error-ppc-405"></a>

##### 405

Unsupported language.

**Action.** Use `localizationLanguage: en`.

<a id="promostandards-error-ppc-406"></a>

##### 406

Unsupported configuration.

**Action.** Use `configurationType: Blank`. This service does not publish decoration pricing.

<a id="promostandards-transport-errors"></a>

#### Authentication limits and availability

Access checks can stop a request before it is processed. These HTTP responses use `text/plain`, without an XML error code or SOAP `Fault`. Check the HTTP status and content type before parsing XML.

<a id="promostandards-error-transport-429"></a>

##### HTTP 429

A temporary credential-verification limit was reached. The body reads `Temporarily rate limited`.

**Action.** Wait for the interval in `Retry-After` before resuming and reduce request frequency. Switching SOAP services does not reset these limits.

<a id="promostandards-error-transport-503"></a>

##### HTTP 503

Access verification is temporarily unavailable. The body reads `Authentication temporarily unavailable`.

**Action.** Retry later and contact Attraction if the problem persists. This response does not mean your credentials are invalid and does not provide a `Retry-After` interval.

<a id="promostandards-soap-faults"></a>

#### SOAP envelope and operation faults

An unreadable envelope or unknown operation returns HTTP `500` with a SOAP `Fault` element and `faultcode: soapenv:Client`. Correct the request before sending it again.

<a id="promostandards-error-soap-envelope"></a>

##### soapenv:Client

Empty body, malformed XML, missing `Envelope` or `Body`, or multiple operations inside `Body`.

**Action.** Send a valid SOAP 1.1 envelope with `Content-Type: text/xml` and exactly one operation in `Body`. Read `faultstring` for the specific cause.

<a id="promostandards-error-soap-operation"></a>

##### soapenv:Client

The request element does not match an operation on the selected service.

**Action.** Check the request element name, its case and the endpoint URL against the matching WSDL.

<a id="rate-limits"></a>

## Request limits

### Attraction API (REST/JSON)

The `/v1/products` list, even with a key, and anonymous requests use `default`: 600 requests per minute per client IP. Detail and pricing requests with a verified key use `keyed`: 1200 requests per minute per key. First key verification, or verification after its cache expires, also requires IP admission. Headers report `keyed` after successful verification and `default` otherwise. These advisory counts are tracked per instance and are not a capacity guarantee. Exceeding these application quotas returns `429` and `Retry-After`; wait for that interval before resuming. Headers follow [draft-ietf-httpapi-ratelimit-headers](https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/). Infrastructure also enforces a global backstop of 100 requests per second, with a burst of 200; rejections at that level do not guarantee the same headers.

- `RateLimit-Policy: "default";q=600;w=60`
- `RateLimit-Policy: "keyed";q=1200;w=60`
- `RateLimit: "default";r=<remaining>;t=<seconds>`

### PromoStandards (SOAP/XML)

PromoStandards services share a ceiling of 20 requests per second, with a burst of 40; this is not a capacity guarantee per integration. Credential verification also applies protective limits; repeated failures can limit requests from the same IP. A verification limit returns HTTP `429` with `Retry-After`: wait for that interval and reduce the request frequency. Infrastructure limits can reject a request without the same headers. Include the services and expected request frequency in your access request when planning a SOAP synchronisation.

<a id="versioning-and-deprecation"></a>

## Versioning and deprecation

### Attraction API (REST/JSON)

The REST API is versioned in the URL: current endpoints are under `/v1`. Breaking changes are published under `/v2`; adding fields or optional parameters does not change the version.

When a REST version is deprecated, we announce it at least three months ahead. Responses carry the `Deprecation` ([RFC 9745](https://www.rfc-editor.org/rfc/rfc9745)) and `Sunset` ([RFC 8594](https://www.rfc-editor.org/rfc/rfc8594)) headers indicating deprecation and the retirement date.

### PromoStandards (SOAP/XML)

Each PromoStandards service uses its WSDL version. Check the [available services and versions](/en-ca/promo/promostandards/#services). The REST notice above applies to the REST API; it is not a SOAP version retirement policy.

<a id="status-and-support"></a>

## Status and support

[`/v1/health`](https://api.attraction.com/v1/health) reports REST API status. For the API or PromoStandards, contact [promo@attraction.com](mailto:promo@attraction.com) with the service, operation, error code and time of the failure. Do not include API keys or passwords.

<a id="agent-resources"></a>

[Public resource index](/llms.txt)

<a id="changelog"></a>

## Changelog

Public interface changes and actions to plan for your integrations. The dates below refer to the corresponding releases.

- **2026-09-11 — PromoStandards**. PPC 1.0.0 now accepts `priceType=Net` for standard A3 net prices when the product has a published net grid. `List` continues to return MSRP; `Customer` is not supported. Product Data 2.0.0 adds `ColorArray` to each part. Media Content no longer publishes high-resolution image archives or their `High`/`2001` classification. See the [PromoStandards pricing scope](/en-ca/promo/promostandards/#data-scope).

- **2026-08-31 — REST API**. Net pricing through the API: an account API key, created and revoked on the [API keys page](/en-ca/api/keys/), adds your account's net prices to `/v1/products/{sku}` and to two new pricing-only endpoints, `/v1/products/{sku}/pricing` (one product) and `/v1/products/pricing` (the whole catalog). Keys are bearer tokens that follow the account's live price tier, and bring the [`invalid_key`](#error-invalid_key) and [`key_revoked`](#error-key_revoked) error codes plus the `keyed` rate-limit policy. Per-colour materials: product detail colours now carry `material` (the `composition`, a locale-formatted `weight` label, the numeric `gsm`, and, on Jameo products, the fabric `name`). The former top-level `materials` array and the per-colour `weight` string are removed.

- **2026-08-25 — REST API**. Product freshness: every product now reports `updatedAt`, set only when its product content actually changes (inventory movements never affect it), and the product list reports `catalogUpdatedAt` when a product is added or removed.

- **2026-08-24 — REST API**. Published this developer hub. Error responses moved to RFC 9457 `application/problem+json`; added rate-limit headers and a versioning and deprecation policy.

- **2026-06-26 — REST API**. Official launch: the read-only public Product API at api.attraction.com (product list and detail under `/v1`, no key required) with its OpenAPI description and interactive documentation.

## Sitemap

- [Full XML sitemap](https://www.attraction.com/sitemap.xml)
- [Page index for agents](https://www.attraction.com/llms.txt)
