# Storefront · Sync

Part of AppEngine API Documentation. Full index: https://appengine.appmint.io/documentation.md
## GET /storefront/sync/partners

**List shopping partners**

`operationId: StorefrontController_getShoppingPartners`

Returns the marketplace and shopping partners available for product sync, with each one's connection state for this org. Use it to build a sync UI rather than hard-coding the partner list.

#### Signature

```http
GET /storefront/sync/partners (configId?: string) -> The available partners and their connection state
```

#### Access

Public — no credentials required.

#### Errors

Plus the standard platform errors: `429`, `500`.

#### See also

- `POST /storefront/sync/{partner}/{productId}`
- `POST /storefront/sync/add-products`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `configId` | query | string | — | Which configured connection to the partner to use. An org can hold several connections to one partner — separate Google Merchant accounts, for instance. Omit to use the connection named `default`. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The available partners and their connection state |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /storefront/sync/{partner}/{productId}

**Sync one product to a partner**

`operationId: StorefrontController_syncProduct`

Pushes a single product to one marketplace, creating or updating its listing. This is the call to make right after a product is edited, so the marketplace copy does not drift.

#### Signature

```http
POST /storefront/sync/{partner}/{productId} (partner: string, productId: string, configId?: string) -> The sync result
```

#### Access

Public — no credentials required.

#### Notes

- Safe to repeat — a product already listed is updated rather than duplicated.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | PRODUCT_NOT_FOUND | Product not found | The product id or SK does not resolve in the org. | Check the identifier with `GET /storefront/products`. |
| `400` | PARTNER_API_ERROR | The partner rejected the request. | The marketplace API returned an error — a policy violation, a missing required attribute, or an expired credential. | The partner's message is passed through. Fix the reported problem, or re-authorise the connection if the credential expired. |

Plus the standard platform errors: `429`, `500`.

#### See also

- `POST /storefront/sync/all/{productId}`
- `DELETE /storefront/sync/{partner}/{productId}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `partner` | path | string | yes | Partner identifier, e.g. `google`, `facebook`, `tiktok`, `amazon`, `shopify`. List the supported values with `GET /storefront/sync/partners`. |
| `productId` | path | string | yes | Product `sk` or id. |
| `configId` | query | string | — | Which configured connection to the partner to use. An org can hold several connections to one partner — separate Google Merchant accounts, for instance. Omit to use the connection named `default`. |

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The sync result |
| `400` | The partner rejected the request. — The marketplace API returned an error — a policy violation, a missing required attribute, or an expired credential. |
| `404` | Product not found — The product id or SK does not resolve in the org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## DELETE /storefront/sync/{partner}/{productId}

**Remove a product from a partner**

`operationId: StorefrontController_deleteProduct`

Delists a single product from one marketplace. The product itself is untouched in your catalog — only the partner's copy is removed.

#### Signature

```http
DELETE /storefront/sync/{partner}/{productId} (partner: string, productId: string, configId?: string) -> The delist result
```

#### Access

Public — no credentials required.

#### Notes

- Deleting a product that is not listed is not treated as an error by most partners.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | PARTNER_NOT_CONFIGURED | Partner integration not found for this organization | The org has no connection to that partner, or none under the given `configId`. | Connect the partner first. `GET /storefront/sync/partners` lists what is configured. |
| `400` | PARTNER_API_ERROR | The partner rejected the request. | The marketplace API returned an error — a policy violation, a missing required attribute, or an expired credential. | The partner's message is passed through. Fix the reported problem, or re-authorise the connection if the credential expired. |

Plus the standard platform errors: `429`, `500`.

#### See also

- `POST /storefront/sync/delete-products`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `partner` | path | string | yes | Partner identifier, e.g. `google`, `facebook`, `tiktok`, `amazon`, `shopify`. List the supported values with `GET /storefront/sync/partners`. |
| `productId` | path | string | yes | Product id as known to the partner, or the local `sk`. |
| `configId` | query | string | — | Which configured connection to the partner to use. An org can hold several connections to one partner — separate Google Merchant accounts, for instance. Omit to use the connection named `default`. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The delist result |
| `400` | The partner rejected the request. — The marketplace API returned an error — a policy violation, a missing required attribute, or an expired credential. |
| `404` | Partner integration not found for this organization — The org has no connection to that partner, or none under the given `configId`. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /storefront/sync/all/{productId}

**Sync one product to every partner**

`operationId: StorefrontController_syncProductToAll`

Pushes a product to every partner the org has configured, in one call. Partners are attempted independently — one marketplace rejecting the product does not stop the others.

#### Signature

```http
POST /storefront/sync/all/{productId} (productId: string) -> One result per configured partner
```

#### Access

Public — no credentials required.

#### Notes

- Check every entry in the response: a `200` here means the request ran, not that every partner accepted the product.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | PRODUCT_NOT_FOUND | Product not found | The product id or SK does not resolve in the org. | Check the identifier with `GET /storefront/products`. |

Plus the standard platform errors: `429`, `500`.

#### See also

- `POST /storefront/sync/{partner}/{productId}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `productId` | path | string | yes | Product `sk` or id. |

### Responses

| Status | Meaning |
| --- | --- |
| `201` | One result per configured partner |
| `404` | Product not found — The product id or SK does not resolve in the org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /storefront/sync/add-products

**Sync several products to a partner**

`operationId: StorefrontController_syncServiceAdd`

Bulk version of the single-product sync: pushes many products to one marketplace in a single call.

Set `alsoPostToSocial` to publish a social post for the same products as part of the operation, configured through `postOptions`. That is a convenience over calling `sync/post-to-social` separately, and it uses the same rendering.

#### Signature

```http
POST /storefront/sync/add-products (body) -> Per-product sync results, plus the social post result when one was requested
```

#### Access

Public — no credentials required.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | PARTNER_NOT_CONFIGURED | Partner integration not found for this organization | The org has no connection to that partner, or none under the given `configId`. | Connect the partner first. `GET /storefront/sync/partners` lists what is configured. |
| `400` | PARTNER_API_ERROR | The partner rejected the request. | The marketplace API returned an error — a policy violation, a missing required attribute, or an expired credential. | The partner's message is passed through. Fix the reported problem, or re-authorise the connection if the credential expired. |

Plus the standard platform errors: `429`, `500`.

#### See also

- `POST /storefront/sync/delete-products`
- `POST /storefront/sync/post-to-social`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

Which products to push where.

```json
{
  "partner": "google",
  "productIds": [
    "sk_1",
    "sk_2",
    "sk_3"
  ]
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | Per-product sync results, plus the social post result when one was requested |
| `400` | The partner rejected the request. — The marketplace API returned an error — a policy violation, a missing required attribute, or an expired credential. |
| `404` | Partner integration not found for this organization — The org has no connection to that partner, or none under the given `configId`. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /storefront/sync/delete-products

**Remove several products from a partner**

`operationId: StorefrontController_syncServiceDelete`

Bulk delist: removes many products from one marketplace catalog in a single call. Your own catalog is unaffected.

#### Signature

```http
POST /storefront/sync/delete-products (body) -> Per-product delist results
```

#### Access

Public — no credentials required.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | PARTNER_NOT_CONFIGURED | Partner integration not found for this organization | The org has no connection to that partner, or none under the given `configId`. | Connect the partner first. `GET /storefront/sync/partners` lists what is configured. |
| `400` | PARTNER_API_ERROR | The partner rejected the request. | The marketplace API returned an error — a policy violation, a missing required attribute, or an expired credential. | The partner's message is passed through. Fix the reported problem, or re-authorise the connection if the credential expired. |

Plus the standard platform errors: `429`, `500`.

#### See also

- `DELETE /storefront/sync/{partner}/{productId}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

Which products to remove from where.

```json
{
  "partner": "google",
  "productIds": [
    "sk_1",
    "sk_2"
  ]
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | Per-product delist results |
| `400` | The partner rejected the request. — The marketplace API returned an error — a policy violation, a missing required attribute, or an expired credential. |
| `404` | Partner integration not found for this organization — The org has no connection to that partner, or none under the given `configId`. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /storefront/sync/products

**List products across all partners**

`operationId: StorefrontController_listAllProducts`

Returns the products currently listed at every configured partner — what the marketplaces think you are selling, which is the thing to compare against your own catalog when reconciling.

**This endpoint takes no parameters.** It accepts neither paging nor a partner filter, and returns whatever each partner's default page size yields. Use `GET /storefront/sync/products/{partner}` when you need `limit`, `pageToken` or `configId`.

#### Signature

```http
GET /storefront/sync/products () -> Listed products grouped by partner
```

#### Access

Public — no credentials required.

#### Notes

- Unpaged. On a large catalog the result is truncated by each partner's own default page size, with no way to fetch the rest — use the per-partner endpoint for a complete listing.

#### Errors

Plus the standard platform errors: `429`, `500`.

#### See also

- `GET /storefront/sync/products/{partner}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `pageToken` | query | any | — | Page token for pagination |
| `limit` | query | any | — | Maximum number of products to return |
| `configId` | query | any | — | Config ID (optional) |
| `partner` | path | any | — | Partner ID (google, facebook, amazon, shopify, etc.) - optional |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Listed products grouped by partner |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /storefront/sync/products/{partner}

**List products at one partner**

`operationId: StorefrontController_listPartnerProducts`

Returns the products currently listed at a single marketplace, with paging. This is the endpoint to use for reconciliation — it is the only listing that can walk a full catalog.

Paging is the partner's own: pass the `pageToken` from the previous response to fetch the next page, and stop when no token comes back.

#### Signature

```http
GET /storefront/sync/products/{partner} (partner: string, configId?: string, limit?: integer, pageToken?: string) -> A page of listed products, with a token for the next page
```

#### Access

Public — no credentials required.

#### Notes

- The product shape is the partner's, not the platform's — fields differ between Google, Facebook and Shopify.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | PARTNER_NOT_CONFIGURED | Partner integration not found for this organization | The org has no connection to that partner, or none under the given `configId`. | Connect the partner first. `GET /storefront/sync/partners` lists what is configured. |
| `400` | PARTNER_API_ERROR | The partner rejected the request. | The marketplace API returned an error — a policy violation, a missing required attribute, or an expired credential. | The partner's message is passed through. Fix the reported problem, or re-authorise the connection if the credential expired. |

Plus the standard platform errors: `429`, `500`.

#### See also

- `GET /storefront/sync/products`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `partner` | path | string | yes | Partner identifier, e.g. `google`, `facebook`, `tiktok`, `amazon`, `shopify`. List the supported values with `GET /storefront/sync/partners`. |
| `configId` | query | string | — | Which configured connection to the partner to use. An org can hold several connections to one partner — separate Google Merchant accounts, for instance. Omit to use the connection named `default`. |
| `limit` | query | integer | — | Maximum products to return. The partner's own maximum still applies. |
| `pageToken` | query | string | — | Opaque cursor from the previous response. Omit for the first page. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | A page of listed products, with a token for the next page |
| `400` | The partner rejected the request. — The marketplace API returned an error — a policy violation, a missing required attribute, or an expired credential. |
| `404` | Partner integration not found for this organization — The org has no connection to that partner, or none under the given `configId`. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

