Integration Process
Abstract
This document describes the core functionality and architecture required to implement a Demand Partner Integration system. The goal is to enable ingestion and management of merchant and offer data, redemption feed processing, and a stub for aggregate reporting within a partner platform. The implementation leverages both SFTP file-based and REST API-based ingestion, enforces strict JSON schema validation, and provides foundational backend structures for further development.
How It Works
The integration is divided into several core components:
-
Merchant Ingestion:
- Supports SFTP-based full-dump JSON file uploads and REST API upsert/delete endpoints.
- All merchant data is validated against a defined schema, supporting statuses like NEW, UPDATED, UPSERT, DELETED, and NO-CHANGE.
- Records are inserted, updated, or deleted in the platform database based on status, always processing the full merchant list.
- File overwrites are allowed; schema validation failures result in rejection.
-
Offer Ingestion:
- Mirrors the merchant ingestion process for partner offers, via both SFTP and REST API.
- Data is validated against an offer schema and supports the same status values and operational logic.
-
Redemption Feed:
- Hourly SFTP download of a redemption feed, containing transaction and partner identifiers and reconciliation details.
- Data is imported to the database for reporting.
-
Aggregate Reporting API (Stub):
- Provides a stubbed REST API endpoint for partners to query aggregate metrics (e.g., purchases, revenue, reach, impressions, activations, customer postcodes, diner segmentation, travel distance).
- The reporting implementation itself is out of scope for MVP.
-
Deliverables:
- Backend: SFTP watchers, REST endpoints, schema validation, database models, stub reporting API, logging, and error handling.
- Documentation: API references and sample payloads.
-
Out of Scope:
- Authentication/authorization, quotas, UI, full reporting, or activation/customer-facing features.
-
Example Directory Structure:
- Provides a sample file/folder organization demonstrating modular separation of schemas, APIs, SFTP watchers, and database models.
-
Example Implementations:
- Includes code snippets for minimal Express.js endpoints (merchant upsert/delete) and an SFTP merchant file watcher using Node.js and chokidar.
-
Schema Extract:
- Partial JSON schema for merchants, detailing required fields and structure.
Overall, this document serves as a blueprint to onboard demand partners through file and API-based integrations, while supporting schema validation, basic CRUD operations, redemption handling, and a foundation for future reporting enhancements.
1. Merchant Ingestion
a. SFTP File Ingestion
- Parse JSON files matching
<Partner_Name>MerchantsCCYYMMDD.json
. - Validate JSON against the Merchant Schema (see below).
- Support all
merchantStatus
values: NEW, UPDATED, UPSERT, DELETED, NO-CHANGE. - Insert, update, or delete merchant records in the platform DB according to status.
- Always process full merchant list (full dump), not deltas.
- Overwrite file if same filename exists.
- Reject file if schema validation fails.
b. REST API Support
- Implement endpoint:
- PUT
/api/v1/partner/merchants/{external_merchant_id}
- Upsert merchant with provided JSON (see schema below).
- Derive
merchantStatus
from HTTP method (PUT → UPSERT).
- DELETE
/api/v1/partner/merchants/{external_merchant_id}
- Remove merchant by ID (status = DELETED).
- PUT
Merchant Schema (Core Fields)
merchantId
,merchantName
,merchantCategoryCode
,merchantSubCategories
paymentChannels
,paymentSubChannels
,merchantUrl
,merchantApps
stores
: Array, each with:storeId
,storeName
,address1
,city
,state
,postalCode
,countryCode
latitude
,longitude
,storePhoneNumbers
,storeEmails
,storeUrl
processorMidChangedFlag
,processorMidRecords
(see detailed schema above)
- See full JSON example in document.
2. Offer Ingestion
a. SFTP File Ingestion
- Parse JSON files matching
<Partner_Name>OffersCCYYMMDD.json
. - Validate JSON against Offer Schema (see below).
- Support all
offerStatus
values: NEW, UPDATED, UPSERT, DELETED, NO-CHANGE. - Insert, update, or delete offer records in the platform DB according to status.
- Always process full offer list.
- Overwrite file if same filename exists.
- Reject file if schema validation fails.
b. REST API Support
- Implement endpoint:
- PUT
/api/v1/partner/merchants/{external_merchant_id}/offers/{external_offer_id}
- Upsert offer (see schema below).
- Derive
offerStatus
from HTTP method (PUT → UPSERT).
- DELETE
/api/v1/partner/merchants/{external_merchant_id}/offers/{external_offer_id}
- Remove offer by ID (status = DELETED).
- PUT
Offer Schema (Core Fields)
offerId
,merchantId
,offerName
assets
:logo
(with eitherurl
orcontent
),largeRectangle
(eitherurl
orcontent
)
- See full JSON example in document.
3. Redemption Feed
- SFTP download of redemption feed (provided by CDLX hourly).
- Parse file with schema:
transaction_id
,cardholder_id
,partner_merchant_id
,partner_offer_id
,partner_store_id
partner_merchant_name
,card_type
,card_last_four
,transaction_amount
,transaction_timestamp
- Import to DB for reporting and reconciliation.
4. Aggregate Reporting API (Stub Only)
- POST
/api/v1/partner/merchants/{external_merchant_id}/reports
- Accepts empty request (all offers) or filter by
offerIds
andtimeRange
. - Returns: purchases, revenue, reach, impressions, activations, list of customer postal codes, new/repeat diners, avg. travel distance.
- Accepts empty request (all offers) or filter by
5. Deliverables
-
Backend
- SFTP watcher for Merchant/Offer files.
- REST endpoints for Merchant/Offer upsert & delete.
- JSON schema validation.
- Database models for merchants, offers, stores, redemptions.
- Simple reporting API stub.
- Logging and error handling.
-
Documentation
- API reference for REST endpoints.
- Sample SFTP and REST payloads.
6. Out of Scope
- Partner authentication & authorization.
- Quota/RPS enforcement.
- UI/dashboard.
- Full reporting implementation.
- Offer activation or customer-facing functionality.
7. Example Directory Structure
/integration-mvp/
/schemas/
merchant.schema.json
offer.schema.json
redemption.schema.json
/api/
merchants.js
offers.js
reporting.js
/sftp/
merchantWatcher.js
offerWatcher.js
redemptionFetcher.js
/db/
models.js
README.md
8. Example: Minimal Merchant Upsert Endpoint (Express/Node.js)
// api/merchants.js
const express = require('express');
const router = express.Router();
const { validateMerchant } = require('../schemas/merchant.schema');
const { upsertMerchant, deleteMerchant } = require('../db/models');
// Upsert
router.put('/api/v1/partner/merchants/:merchantId', async (req, res) => {
const merchant = req.body;
const valid = validateMerchant(merchant);
if (!valid) return res.status(400).json({ error: 'Invalid merchant payload.' });
await upsertMerchant(merchant);
res.json({ message: 'Request accepted for processing', trace_id: `req-${Date.now()}` });
});
// Delete
router.delete('/api/v1/partner/merchants/:merchantId', async (req, res) => {
await deleteMerchant(req.params.merchantId);
res.json({ message: 'Request accepted for processing', trace_id: `req-${Date.now()}` });
});
module.exports = router;
9. Example: Minimal SFTP Merchant File Watcher
// sftp/merchantWatcher.js
const chokidar = require('chokidar');
const fs = require('fs');
const { validateMerchantFile } = require('../schemas/merchant.schema');
const { upsertMerchant, deleteMerchant } = require('../db/models');
chokidar.watch('/mnt/sftp-drop/*.json').on('add', async (path) => {
const raw = fs.readFileSync(path);
const data = JSON.parse(raw);
if (!validateMerchantFile(data)) return; // log error
for (const rec of data.merchantRecords) {
if (rec.merchantStatus === 'DELETED') await deleteMerchant(rec.merchantId);
else await upsertMerchant(rec);
}
});
10. Example: Merchant Schema (JSON Schema extract)
{
"type": "object",
"properties": {
"merchantId": { "type": "string" },
"merchantName": { "type": "string" },
"merchantCategoryCode": { "type": "string" },
"merchantSubCategories": {
"type": "array",
"items": {
"type": "object",
"properties": {
"categoryType": { "type": "string" },
"categoryItems": { "type": "array", "items": { "type": "string" } }
}
}
},
"paymentChannels": { "type": "array", "items": { "type": "string" } },
"stores": {
"type": "array",
"items": {
"type": "object",
"properties": {
"storeId": { "type": "string" },
"storeName": { "type": "string" },
"address1": { "type": "string" },
"city": { "type": "string" },
"state": { "type": "string" },
"postalCode": { "type": "string" },
"countryCode": { "type": "string" }
},
"required": ["storeId", "storeName", "address1", "city", "state", "postalCode", "countryCode"]
}
}
},
"required": ["merchantId", "merchantName", "paymentChannels", "stores"]
}
Summary
This document provides the minimum framework required to ingest, validate, and store merchant/offers information, handle redemptions, and stub reporting, as specified by the Demand Partner Integration v1.2 document.
Updated about 12 hours ago