# POST /api/v1/credit/shopify-pull

> Pull a merchant's Shopify underwriting data with a salted ephemeral token

- **Tag:** credit
- **Operation ID:** `pull_credit_merchant_shopify`

## Description

For partners that hold the merchant's Shopify Admin API token in their own vault and pass it encrypted (`PBKDF2-HMAC-SHA256` with a per-request random `salt` + `AES-256-GCM` bound to `shop_domain` + salted SHA-256 `token_hash`). DayZero decrypts the token only in memory, queries Shopify for orders, daily sales and refund summaries, disputes, and Shopify Capital balance transactions onto the merchant's DayZero business, and discards the plaintext token. Only the irreversible salted SHA-256 fingerprint (`sha256:{salt}:{hash}`) is stored in the database.

## Authentication

Bearer token in `Authorization` header.
Required header: `x-business-id: <business uuid>`.

## Request body

Schema: `ShopifyPullRequest`

- `program_id` (string) — Your lending program id. Required without `credit_line_id`; with it, must match the line's program if sent.
- `external_merchant_id` (string) — Your id for the merchant, as sent on `POST /credit/lines` and `POST /credit/bank-feeds`. Required without `credit_line_id`.
- `credit_line_id` (string) — The merchant's open credit line id, when one already exists.
- `merchant_legal_name` (string) — Names the merchant's DayZero business when this call creates it. Ignored when the business already exists.
- `merchant_business_id` (string) — The merchant's existing DayZero business id, when already created by a bank feed or bank connection.
- `shop_domain` (string · required) — The merchant's Shopify store domain (`*.myshopify.com`).
- `encrypted_token` (string · required) — Base64 AES-256-GCM ciphertext of the Shopify Admin API access token, encrypted with the per-request `salt` and `iv` and bound to the normalized `shop_domain` as additional authenticated data.
- `salt` (string · required) — Per-request random hex salt (16–32 bytes) used for PBKDF2-HMAC-SHA256 key derivation and the salted `token_hash`.
- `iv` (string · required) — Hex initialization vector (12–16 bytes) for AES-256-GCM.
- `auth_tag` (string · required) — 16-byte hex authentication tag produced by AES-256-GCM.
- `token_hash` (string · required) — Salted SHA-256 hex digest of `{salt}:{shop_domain}:{access_token}` verifying token integrity after transport decryption.

## Responses

### 201 — Successful Response

Schema: `SuccessEnvelope_ShopifyPullResponse_`

- `success` (boolean)
- `message` (string)
- `code` (string)
- `data` (ShopifyPullResponse)

### 400 — Bad Request - Invalid input

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

### 401 — Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

### 403 — Forbidden - Insufficient permissions

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

### 404 — Not Found - Resource does not exist

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

### 422 — Validation Error

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

## Code samples

### cURL

```bash
curl -X POST 'https://api.ondayzero.com/api/v1/credit/shopify-pull' \
  -H 'Authorization: Bearer dz_your_token' \
  -H 'x-business-id: YOUR_BUSINESS_ID' \
  -H 'Content-Type: application/json' \
  -d '{
  "shop_domain": "string",
  "encrypted_token": "string",
  "salt": "string",
  "iv": "string",
  "auth_tag": "string",
  "token_hash": "string"
}'
```

### JavaScript

```javascript
const response = await fetch('https://api.ondayzero.com/api/v1/credit/shopify-pull', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer dz_your_token',
    'x-business-id': 'YOUR_BUSINESS_ID',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
  "shop_domain": "string",
  "encrypted_token": "string",
  "salt": "string",
  "iv": "string",
  "auth_tag": "string",
  "token_hash": "string"
}),
});
const data = await response.json();
```

### Python

```python
import httpx

headers = {
    "Authorization": "Bearer dz_your_token",
    "x-business-id": "YOUR_BUSINESS_ID",
}

payload = {'shop_domain': 'string',
 'encrypted_token': 'string',
 'salt': 'string',
 'iv': 'string',
 'auth_tag': 'string',
 'token_hash': 'string'}

response = httpx.post("https://api.ondayzero.com/api/v1/credit/shopify-pull", headers=headers, json=payload)
data = response.json()
```

## See also

- HTML version: https://www.ondayzero.com/docs/reference/credit/pull-credit-merchant-shopify
- OpenAPI slice: https://www.ondayzero.com/docs/reference/credit/pull-credit-merchant-shopify/openapi.json
- Other endpoints in **credit**: https://www.ondayzero.com/docs/reference/credit (markdown bundle: https://www.ondayzero.com/docs/reference/credit.md, OpenAPI: https://www.ondayzero.com/docs/reference/credit/openapi.json)
- Endpoint catalog: https://www.ondayzero.com/docs/reference/index.md
