engineering
Integration Specification
Write integration specifications — defining data flows, API contracts, authentication, error handling, retry logic, and monitoring requirements for system-to-system connections.
integrationspecificationAPIdata-flowerror-handlingcontracts
Works well with agents
Works well with skills
$ npx skills add The-AI-Directory-Company/(…) --skill integration-specificationintegration-specification/
crm-to-billing-sync.md
Markdown
| 1 | # Integration Spec — HubSpot CRM to Stripe Billing Sync |
| 2 | |
| 3 | ## Overview |
| 4 | |
| 5 | One-way sync from HubSpot CRM (source) to Stripe (destination). When a deal closes in HubSpot, a Stripe customer and subscription are created automatically. Eliminates 15-20 min of manual data entry per deal and ~8% error rate. |
| 6 | |
| 7 | **Pattern:** Event-driven via HubSpot webhooks, processed by internal integration service. |
| 8 | |
| 9 | ## Data Flow |
| 10 | |
| 11 | | Flow | Source | Destination | Trigger | Frequency | |
| 12 | |------|--------|-------------|---------|-----------| |
| 13 | | Create customer | HubSpot | Stripe | Deal stage = "Closed Won" | ~40/week | |
| 14 | | Create subscription | HubSpot | Stripe | Same trigger, after customer created | ~40/week | |
| 15 | | Update customer | HubSpot | Stripe | Contact property change | ~120/week | |
| 16 | |
| 17 | ## API Contracts |
| 18 | |
| 19 | **Webhook receipt** — `POST https://api.acme.io/webhooks/hubspot` |
| 20 | ```json |
| 21 | {"eventId": 981723, "subscriptionType": "deal.propertyChange", |
| 22 | "propertyName": "dealstage", "propertyValue": "closedwon", |
| 23 | "objectId": 5048723901} |
| 24 | ``` |
| 25 | |
| 26 | **Create Stripe customer** — `POST /v1/customers` |
| 27 | ``` |
| 28 | name=Northwind+Traders&email=billing@northwind.io |
| 29 | &metadata[hubspot_company_id]=8827364012&metadata[hubspot_deal_id]=5048723901 |
| 30 | ``` |
| 31 | |
| 32 | **Create subscription** — `POST /v1/subscriptions` |
| 33 | ``` |
| 34 | customer=cus_R4xKj8mNvQ2p&items[0][price]=price_pro_monthly |
| 35 | &items[0][quantity]=25&idempotency_key=deal_5048723901_sub |
| 36 | ``` |
| 37 | |
| 38 | Price ID mapped from HubSpot line item product name via config lookup table. |
| 39 | |
| 40 | ## Authentication |
| 41 | |
| 42 | | System | Mechanism | Rotation | Storage | |
| 43 | |--------|-----------|----------|---------| |
| 44 | | HubSpot (inbound) | HMAC-SHA256 signature verification | Quarterly | AWS Secrets Manager | |
| 45 | | HubSpot (outbound) | OAuth 2.0 + refresh token | Access: 30 min, refresh: 6 mo | AWS Secrets Manager | |
| 46 | | Stripe | Restricted API key (customers + subscriptions write) | Quarterly | AWS Secrets Manager | |
| 47 | |
| 48 | ## Data Mapping |
| 49 | |
| 50 | | HubSpot Field | Stripe Field | Transform | |
| 51 | |---------------|-------------|-----------| |
| 52 | | `contact.email` | `customer.email` | Lowercase, trim | |
| 53 | | `company.name` | `customer.name` | Trim whitespace | |
| 54 | | `company.company_id` | `customer.metadata.hubspot_company_id` | Cast to string | |
| 55 | | `deal_line_item.product_name` | `subscription.items[].price` | Lookup: "Pro Monthly" -> `price_pro_monthly` | |
| 56 | | `company.country` | `customer.address.country` | Convert to ISO 3166-1 alpha-2 | |
| 57 | |
| 58 | ## Error Handling |
| 59 | |
| 60 | | Category | Examples | Action | |
| 61 | |----------|----------|--------| |
| 62 | | Transient | Stripe 429, 503, network timeout | Retry with backoff | |
| 63 | | Permanent | Stripe 400 (invalid email), 402 | Dead-letter queue + alert #billing-ops | |
| 64 | | Data issue | Deal missing email or line items | Reject, notify deal owner via HubSpot task | |
| 65 | | Duplicate | Webhook fires twice | Idempotency key `deal_{id}_sub` prevents duplicates | |
| 66 | |
| 67 | ## Retry & Circuit Breaker |
| 68 | |
| 69 | - **Strategy:** Exponential backoff with jitter (2s, 4s, 8s, 16s, 32s + 0-1s random) |
| 70 | - **Max retries:** 5. After exhaustion, message moves to `crm-sync-dlq` SQS queue. |
| 71 | - **Circuit breaker:** 8 consecutive failures opens for 5 min. Messages queue in SQS during open state. |
| 72 | - **Webhook deduplication:** Processed `eventId` values stored in Redis with 72-hour TTL. |
| 73 | |
| 74 | ## Monitoring |
| 75 | |
| 76 | | Metric | Threshold | Alert | |
| 77 | |--------|-----------|-------| |
| 78 | | Sync latency (webhook to Stripe created) | > 30s p95 | Slack warning | |
| 79 | | Error rate | > 5% / 15 min | PagerDuty critical | |
| 80 | | DLQ depth | > 0 | Slack warning | |
| 81 | | DLQ depth | > 10 | PagerDuty critical | |
| 82 | | OAuth token refresh failure | Any | PagerDuty critical | |
| 83 | | Daily sync count vs. closed deals | Mismatch > 2 | Slack warning | |
| 84 |