feat: align integration configuration endpoints with api suite v1.0.0

This commit is contained in:
MOHAN 2026-03-29 18:11:41 +05:30
parent fe524a719d
commit 54565d9b6d
7 changed files with 190 additions and 29 deletions

View File

@ -9,6 +9,8 @@ Source checked: Uber Eats "Integration Configuration Flows" section shared by yo
- Uses merchant token (`authorization_code` / `eats.pos_provisioning`)
- Store activation via POS data:
- `POST /api/v1/uber/stores/{storeId}/pos-data`
- Retrieve integration configuration:
- `GET /api/v1/uber/stores/{storeId}/pos-data`
- Store integration update/deactivation:
- `PATCH /api/v1/uber/stores/{storeId}/pos-data`
- Store de-provision:
@ -26,6 +28,5 @@ Source checked: Uber Eats "Integration Configuration Flows" section shared by yo
## Pending
- Strong store mapping workflow (location-data assisted matching UI flow)
- Typed POS data schema once exact request fields are finalized from endpoint reference
- Strict nested schema validation for deeper webhook config object variants
- Automated post-provisioning follow-up actions (e.g., mandatory menu upload jobs)

View File

@ -0,0 +1,36 @@
# 03 Integration Configuration Suite 1.0.0 Audit
Source checked: "Uber Eats Integration Activation & Configuration API Suite (1.0.0)" shared by you.
## Endpoint Coverage
- Activate Integration:
- `POST /api/v1/uber/stores/{storeId}/pos-data`
- Uses merchant OAuth token (`eats.pos_provisioning`) via `merchantId`
- Update Integration Configuration:
- `PATCH /api/v1/uber/stores/{storeId}/pos-data`
- Uses app token with `eats.store` scope
- Retrieve Integration Configuration:
- `GET /api/v1/uber/stores/{storeId}/pos-data`
- Uses app token with `eats.store` scope
- Remove Integration Configuration:
- `DELETE /api/v1/uber/stores/{storeId}/pos-data`
- Uses app token with `eats.store` scope
## Schema Alignment
- Added typed request schema fields for `pos_data`:
- `allowed_customer_requests`
- `integrator_brand_id`
- `integrator_store_id`
- `is_order_manager`
- `merchant_store_id`
- `require_manual_acceptance`
- `store_configuration_data`
- `webhooks_config`
- `integration_enabled` (PATCH)
## Pending
- Add stricter nested object typing for all `webhooks_config` variants when final examples are shared.

View File

@ -629,6 +629,27 @@
}
}
},
"get": {
"summary": "Retrieve integration configuration for selected store (GET /pos_data)",
"tags": [
"Uber Provisioning"
],
"parameters": [
{
"in": "path",
"name": "storeId",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Store integration configuration retrieved"
}
}
},
"patch": {
"summary": "Update integration settings for selected store (PATCH /pos_data)",
"tags": [

View File

@ -662,7 +662,7 @@
],
"body": {
"mode": "raw",
"raw": "{\n \"merchantId\": \"{{merchantId}}\",\n \"posData\": {\n \"partner_store_id\": \"POS_STORE_001\",\n \"integration_enabled\": true,\n \"store_configuration_data\": {}\n }\n}"
"raw": "{\n \"merchantId\": \"{{merchantId}}\",\n \"posData\": {\n \"allowed_customer_requests\": {\n \"allow_single_use_items_requests\": false,\n \"allow_special_instruction_requests\": false\n },\n \"integrator_brand_id\": \"app-brand-1jj9th32\",\n \"integrator_store_id\": \"app-store-001\",\n \"is_order_manager\": true,\n \"merchant_store_id\": \"UberStore1\",\n \"require_manual_acceptance\": false,\n \"store_configuration_data\": \"v1-config\",\n \"webhooks_config\": {\n \"webhooks_version\": \"1.0.0\"\n }\n }\n}"
},
"url": {
"raw": "{{baseUrl}}/api/v1/uber/stores/{{storeId}}/pos-data",
@ -680,6 +680,32 @@
}
}
},
{
"name": "Get POS Data",
"request": {
"method": "GET",
"header": [
{
"key": "x-api-key",
"value": "{{apiKey}}"
}
],
"url": {
"raw": "{{baseUrl}}/api/v1/uber/stores/{{storeId}}/pos-data",
"host": [
"{{baseUrl}}"
],
"path": [
"api",
"v1",
"uber",
"stores",
"{{storeId}}",
"pos-data"
]
}
}
},
{
"name": "Patch POS Data (Enable/Disable)",
"request": {
@ -696,7 +722,7 @@
],
"body": {
"mode": "raw",
"raw": "{\n \"merchantId\": \"{{merchantId}}\",\n \"posData\": {\n \"integration_enabled\": false\n }\n}"
"raw": "{\n \"posData\": {\n \"integration_enabled\": false,\n \"require_manual_acceptance\": false\n }\n}"
},
"url": {
"raw": "{{baseUrl}}/api/v1/uber/stores/{{storeId}}/pos-data",
@ -722,16 +748,8 @@
{
"key": "x-api-key",
"value": "{{apiKey}}"
},
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"merchantId\": \"{{merchantId}}\"\n}"
},
"url": {
"raw": "{{baseUrl}}/api/v1/uber/stores/{{storeId}}/pos-data",
"host": [

View File

@ -239,9 +239,37 @@ async function setHolidayHours(req, res) {
}
async function createPosData(req, res) {
const allowedCustomerRequestsSchema = z
.object({
allow_single_use_items_requests: z.boolean().optional(),
allow_special_instruction_requests: z.boolean().optional()
})
.optional();
const webhooksConfigSchema = z
.object({
order_release_webhooks: z.record(z.string(), z.any()).optional(),
schedule_order_webhooks: z.record(z.string(), z.any()).optional(),
delivery_status_webhooks: z.record(z.string(), z.any()).optional(),
webhooks_version: z.string().optional()
})
.optional();
const posDataSchema = z.object({
allowed_customer_requests: allowedCustomerRequestsSchema,
integrator_brand_id: z.string().optional(),
integrator_store_id: z.string().optional(),
is_order_manager: z.boolean().optional(),
merchant_store_id: z.string().optional(),
require_manual_acceptance: z.boolean().optional(),
store_configuration_data: z.string().optional(),
webhooks_config: webhooksConfigSchema,
integration_enabled: z.boolean().optional()
});
const schema = z.object({
merchantId: z.string().min(1),
posData: z.any()
posData: posDataSchema
});
const payload = schema.parse(req.body);
const data = await proxyService.createPosData({
@ -252,14 +280,51 @@ async function createPosData(req, res) {
return res.json({ success: true, data });
}
async function getPosData(req, res) {
const data = await proxyService.getPosData({
storeId: req.params.storeId
});
return res.json({ success: true, data });
}
async function patchPosData(req, res) {
const allowedCustomerRequestsSchema = z
.object({
allow_single_use_items_requests: z.boolean().optional(),
allow_special_instruction_requests: z.boolean().optional()
})
.optional();
const webhooksConfigSchema = z
.object({
order_release_webhooks: z.record(z.string(), z.any()).optional(),
schedule_order_webhooks: z.record(z.string(), z.any()).optional(),
delivery_status_webhooks: z.record(z.string(), z.any()).optional(),
webhooks_version: z.string().optional()
})
.optional();
const posDataSchema = z
.object({
allowed_customer_requests: allowedCustomerRequestsSchema,
integrator_brand_id: z.string().optional(),
integrator_store_id: z.string().optional(),
is_order_manager: z.boolean().optional(),
merchant_store_id: z.string().optional(),
require_manual_acceptance: z.boolean().optional(),
store_configuration_data: z.string().optional(),
webhooks_config: webhooksConfigSchema,
integration_enabled: z.boolean().optional()
})
.refine((value) => Object.keys(value).length > 0, {
message: "posData must include at least one updatable field"
});
const schema = z.object({
merchantId: z.string().min(1),
posData: z.any()
posData: posDataSchema
});
const payload = schema.parse(req.body);
const data = await proxyService.patchPosData({
merchantId: payload.merchantId,
storeId: req.params.storeId,
payload: payload.posData
});
@ -267,12 +332,7 @@ async function patchPosData(req, res) {
}
async function deletePosData(req, res) {
const schema = z.object({
merchantId: z.string().min(1)
});
const payload = schema.parse(req.body);
const data = await proxyService.deletePosData({
merchantId: payload.merchantId,
storeId: req.params.storeId
});
return res.json({ success: true, data });
@ -298,6 +358,7 @@ module.exports = {
getHolidayHours,
setHolidayHours,
createPosData,
getPosData,
patchPosData,
deletePosData
};

View File

@ -354,28 +354,37 @@ async function createPosData({ merchantId, storeId, payload }) {
});
}
async function patchPosData({ merchantId, storeId, payload }) {
async function getPosData({ storeId }) {
const uberPath = interpolatePath(uberEndpoints.stores.posData, { storeId });
return callUberApi({
method: "GET",
uberPath,
wrapperRoute: "/api/v1/uber/stores/:storeId/pos-data",
authMode: "app",
scopes: AUTH_SCOPES.STORE
});
}
async function patchPosData({ storeId, payload }) {
const uberPath = interpolatePath(uberEndpoints.stores.posData, { storeId });
return callUberApi({
merchantId,
method: "PATCH",
uberPath,
body: payload,
wrapperRoute: "/api/v1/uber/stores/:storeId/pos-data",
authMode: "merchant",
scopes: AUTH_SCOPES.POS_PROVISIONING
authMode: "app",
scopes: AUTH_SCOPES.STORE
});
}
async function deletePosData({ merchantId, storeId }) {
async function deletePosData({ storeId }) {
const uberPath = interpolatePath(uberEndpoints.stores.posData, { storeId });
return callUberApi({
merchantId,
method: "DELETE",
uberPath,
wrapperRoute: "/api/v1/uber/stores/:storeId/pos-data",
authMode: "merchant",
scopes: AUTH_SCOPES.POS_PROVISIONING
authMode: "app",
scopes: AUTH_SCOPES.STORE
});
}
@ -399,6 +408,7 @@ module.exports = {
getHolidayHours,
setHolidayHours,
createPosData,
getPosData,
patchPosData,
deletePosData
};

View File

@ -307,6 +307,19 @@ router.put("/uber/stores/hours", asyncHandler(controller.updateHours));
* responses:
* 200:
* description: Store provisioned
* get:
* summary: Retrieve integration configuration for selected store (GET /pos_data)
* tags:
* - Uber Provisioning
* parameters:
* - in: path
* name: storeId
* required: true
* schema:
* type: string
* responses:
* 200:
* description: Store integration configuration retrieved
* patch:
* summary: Update integration settings for selected store (PATCH /pos_data)
* tags:
@ -335,6 +348,7 @@ router.put("/uber/stores/hours", asyncHandler(controller.updateHours));
* description: Store integration removed
*/
router.post("/uber/stores/:storeId/pos-data", asyncHandler(controller.createPosData));
router.get("/uber/stores/:storeId/pos-data", asyncHandler(controller.getPosData));
router.patch("/uber/stores/:storeId/pos-data", asyncHandler(controller.patchPosData));
router.delete("/uber/stores/:storeId/pos-data", asyncHandler(controller.deletePosData));