Who is this article for?
Developers integrating Product Attribution. For program manager overview, see Rewarding partners based on what customers buy.
Prerequisites
- Your PartnerStack public key and private key (Settings → API)
- At least one customer has already been created in PartnerStack
- Basic auth:
Authorization: Basic {base64(public_key:private_key)}
Overview
Product Attribution connects three records:
Product Catalog (Product Book)
↓
Product (per customer)
↓
Transaction (with subscription_key)The external_subscription_key on the Product and the subscription_key on the Transaction must match exactly. Values are case-sensitive.
Step 1: Create your Product Catalog
Define the products your company sells. Create one entry per product. This is a one-time setup.
Endpoint: POST /api/v2/product_book
Required fields:
| Field | Type | Description |
|---|---|---|
| name | string | Display name of the product |
Optional fields:
| Field | Type | Description |
|---|---|---|
| description | string | Short description |
| external_key | string | Your billing system's product ID |
Example request:
POST /api/v2/product_book
Authorization: Basic {credentials}
Content-Type: application/json
{
"name": "Inbox",
"description": "Shared team inbox for email",
"external_key": "stripe_prod_inbox"
}Example response:
{
"data": {
"archived": false,
"company_id": 95746372,
"created_at": 1775514585468,
"description": "Shared team inbox for email",
"external_key": "stripe_prod_inbox",
"id": null,
"key": "pbook_G9EVeoB85yungS",
"name": "Inbox 2",
"updated_at": 1775514585468
},
"message": "Product Book Created",
"status": 200
}Save the key — you'll use it as product_book_key in the next step.
Step 2: Create a Product for a customer
Define the products your company sells. Create one entry per product. This is a one-time setup.
When a customer purchases a product, create a Product record linking them to your catalog.
Endpoint: POST /api/v2/products
Required fields:
| Field | Type | Description |
|---|---|---|
| product_book_key | string | Key from Step 1 |
| customer_key | string | PartnerStack customer key |
| status | string |
trial, active, or churned
|
Optional fields:
| Field | Type | Description |
|---|---|---|
| partnership_key | string | Partner relationship to credit |
| stack_key | string | Individual partner member |
| external_subscription_key | string | Billing subscription ID — must match subscription_key in Step 3 |
| amount | integer | Value in cents |
| currency | string | ISO 3-letter code |
Example request:
Example request:
POST /api/v2/products
Authorization: Basic {credentials}
Content-Type: application/json
{
"product_book_key": "pbook_G9EVeoB85yungS",
"customer_key": "cus_def456",
"status": "active",
"amount": 19999,
"partnership_key": "part_xyz789",
"external_subscription_key": "stripe_prod_inbox",
"stack_key": "stck_lCuxlSpfTI0Kgo"
}Example response:
{
"data": {
"amount": 19999,
"click_xid": null,
"company_id": 95746372,
"created_at": 1775514895894,
"currency": null,
"customer_key": "cus_def456",
"external_subscription_key": "stripe_prod_inbox",
"field_data": null,
"key": "prod_tQofY1CbOSIlIQ",
"member_email": null,
"member_logo": null,
"member_name": null,
"metadata": null,
"name": null,
"partner_logo": null,
"partner_name": null,
"partnership_key": "part_xyz789",
"product_book_key": "pbook_G9EVeoB85yungS",
"stack_key": "stck_lCuxlSpfTI0Kgo",
"status": "active",
"team_color": null,
"updated_at": 1775514895894
},
"message": "Product created successfully",
"status": 201
}Edge cases:
-
customer_keydoesn't exist → 403 error. Create the customer first. -
partnership_keydoesn't belong to your company → 403 error. -
stack_keyisn't linked to an active partner → silently ignored. No error, but no attribution.
Step 3: Send transactions with a product reference
On each billing event, send a transaction. Include subscription_key to link it to the customer's product.
Endpoint: POST /api/v2/transactions
Required fields:
| Field | Type | Description |
|---|---|---|
| amount | integer | Amount in cents |
| currency | string | ISO 3-letter code |
| customer_key or customer_external_key or customer_email | string | Identifies the customer (provide one) |
For product attribution:
| Field | Type | Description |
|---|---|---|
| subscription_key | string | Must match external_subscription_key from Step 2 |
Example request:
POST /api/v2/transactions
Authorization: Basic {credentials}
Content-Type: application/json
{
"amount": 9900,
"currency": "USD",
"customer_key": "cus_def456",
"subscription_key": "pbook_G9EVeoB85yungS"
}What happens:
- PartnerStack looks for a Product where
external_subscription_keymatches - If found: transaction is linked to that product — product data is available for trigger rules
- If not found: transaction is created but without product data — no error returned
Verifying your integration
After sending a transaction with subscription_key:
- Retrieve it via
GET /api/v2/transactions?customer_key={cus_key} - Check that
product_keyis populated - If
null, thesubscription_keydidn't match any product — check for case mismatches
You can also check the customer's Products tab in the PartnerStack dashboard to confirm the product appears with the correct status.
Field reference
Product status values:
| Value | Meaning |
|---|---|
| trial | Customer is in trial |
| active | Active paid subscription |
| churned | Cancelled or lapsed |
If you need help integrating, reach out to support@partnerstack.com or your Customer Success Manager.
Related articles: