Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions components/stadium/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Overview

Stadium is a global recognition, gifting, and branded swag platform. Use the Stadium API to embed gift, rewards, and branded swag capabilities into your own applications.

With Stadium's Pipedream integration, you can:

- Manage stores and browse product catalogs
- Place and checkout orders programmatically
- Send points and rewards to recipients
- Create and monitor automation orders
- Track order shipment status

## Limitations

- Stadium's API is available only to customers on Business and Enterprise packages.
- Access tokens are valid for 24 hours and must be refreshed.
- Automation orders may take up to 30 minutes to process.

# Example Use Cases

1. **Automated Employee Rewards** — Trigger Stadium point sends when milestones are reached in your HR system.
2. **E-commerce Integration** — Automatically place Stadium orders when customers make purchases on your platform.
3. **Event-Driven Gifting** — Send branded swag to attendees after event registration via webhook.
4. **Order Tracking** — Monitor shipment status and notify recipients when their gifts are on the way.
5. **Catalog Sync** — Keep your product catalog in sync with Stadium's latest offerings.

# Getting Started

## Creating a Stadium Account

1. Sign up for a free Stadium account at [bystadium.com](https://www.bystadium.com/).
2. Create a Stadium Shop and curate your product catalog.
3. Set up your funding source (wallet funds for order payments).
4. Contact [engineering@bystadium.com](mailto:engineering@bystadium.com) to receive API credentials.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Clarify what "API credentials" means in the setup instructions.

Line 34 directs users to contact engineering to "receive API credentials," but does not specify that these are the Client ID and Client Secret referenced in line 39. Users may be uncertain whether they have the right credentials when they receive them.

Revise to: "Contact engineering@bystadium.com to receive your Client ID and Client Secret."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/stadium/README.md` at line 34, In the README.md file for the
stadium component, the setup instructions at line 34 use vague terminology "API
credentials" when directing users to contact engineering. Replace "API
credentials" with the specific terms "Client ID and Client Secret" to match the
terminology referenced in line 39 and provide clarity to users about exactly
what credentials they should expect to receive. Update the contact instruction
text to explicitly mention these credential types.


## Connecting to Pipedream

1. In your Pipedream workflow, search for the **Stadium** app.
2. Click **Connect Stadium** and enter your Client ID and Client Secret.
3. Pipedream will handle token generation and renewal automatically.

## Sandbox Environment

For testing, Stadium provides a sandbox environment at `https://api.preprod.bystadium.com`. Contact [engineering@bystadium.com](mailto:engineering@bystadium.com) for sandbox credentials.
Comment on lines +42 to +44

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Sandbox environment setup is incomplete: no guidance on switching the API endpoint.

The README mentions a sandbox environment at https://api.preprod.bystadium.com, but the app module has a hardcoded base URL (https://api.bystadium.com/api/v2 from the _baseUrl() method) with no configuration option visible to users. Users who obtain sandbox credentials will not know how to point their requests to the sandbox endpoint.

Either:

  • Add a configurable apiUrl prop to the app connection so users can override the base URL, or
  • Clarify in the README that sandbox testing requires a custom deployment, or
  • Remove the sandbox section if it is not practical within the current app design.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/stadium/README.md` around lines 42 - 44, The README documents a
sandbox environment but the app module has a hardcoded base URL in the
`_baseUrl()` method that users cannot override. Either add a configurable
`apiUrl` prop to the app connection component that allows users to set a custom
API endpoint (defaulting to the production URL if not provided), update the
README to clarify that sandbox testing requires custom deployment modifications,
or remove the sandbox environment section entirely if it is not supported in the
current design. Choose one approach and ensure consistency between the code
capabilities and documentation.


# Troubleshooting

## Authentication Errors

If you receive a `401 Unauthorized` error, verify that:
- Your Client ID and Client Secret are correct.
- Your account is on a Business or Enterprise plan.
- Your access token has not expired (tokens are valid for 24 hours).

## Order Errors

- `422` errors typically indicate invalid request data. Check that store numbers, product IDs, and addresses are correctly formatted.
- `404` errors mean the specified resource (order, store, automation) was not found.

## Automation Orders

Automation orders may take up to 30 minutes to process. Use the **Check Automation Order Status** action to monitor progress.
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import stadium from "../../stadium.app.mjs";

export default {
key: "stadium-check-automation-order-status",
name: "Check Automation Order Status",
description: "Check the status of an automation order. [See the documentation](https://api.bystadium.com/api/v2/docs#tag/Automation-management/operation/checkOrderStatus)",
version: "0.0.1",
type: "action",
annotations: {
destructiveHint: false,
openWorldHint: false,
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
readOnlyHint: true,
},
props: {
stadium,
apiKey: {
type: "string",
label: "Automation API Key",
description: "API key of the webhook automation (e.g., `ryfMiGzMp8ZTisWYbZUhjkVL`)",
secret: true,
},
orderIdentifier: {
type: "string",
label: "Order Identifier",
description: "Identifier of the automation order to check",
},
},
async run({ $ }) {
const response = await this.stadium.checkAutomationOrderStatus({
$,
apiKey: this.apiKey,
data: {
order_identifier: this.orderIdentifier,
},
});
$.export("$summary", `Successfully retrieved status for automation order ${this.orderIdentifier}`);
return response;
},
};
38 changes: 38 additions & 0 deletions components/stadium/actions/checkout-order/checkout-order.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import stadium from "../../stadium.app.mjs";

export default {
key: "stadium-checkout-order",
name: "Checkout Order",
description: "Checkout a placed order using the specified payment method. [See the documentation](https://api.bystadium.com/api/v2/docs#tag/Order-management/operation/orderCheckout)",
version: "0.0.1",
type: "action",
annotations: {
destructiveHint: false,
openWorldHint: true,
readOnlyHint: false,
},
props: {
stadium,
orderNumber: {
propDefinition: [
stadium,
"orderNumber",
],
},
paymentMethod: {
propDefinition: [
stadium,
"paymentMethod",
],
},
},
async run({ $ }) {
const response = await this.stadium.checkoutOrder({
$,
orderNumber: this.orderNumber,
paymentMethod: this.paymentMethod,
});
$.export("$summary", `Successfully checked out order ${this.orderNumber}`);
return response;
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import stadium from "../../stadium.app.mjs";

export default {
key: "stadium-create-automation-order",
name: "Create Automation Order",
description: "Place an order for a webhook automation. May take up to 30 minutes to process. [See the documentation](https://api.bystadium.com/api/v2/docs#tag/Automation-management/operation/createAutomationOrder)",
version: "0.0.1",
type: "action",
annotations: {
destructiveHint: false,
openWorldHint: true,
readOnlyHint: false,
},
props: {
stadium,
apiKey: {
type: "string",
label: "Automation API Key",
description: "API key of the webhook automation (e.g., `ryfMiGzMp8ZTisWYbZUhjkVL`)",
secret: true,
},
contactEmails: {
type: "string[]",
label: "Contact Emails",
description: "Email addresses of recipients",
},
recipientMessage: {
type: "string",
label: "Recipient Message",
description: "Message shown to the recipient at redemption. If not set, the message configured during automation setup will be used",
optional: true,
},
senderName: {
type: "string",
label: "Sender Name",
description: "Name of the sender. If not provided, the sender name configured during automation setup will be used",
optional: true,
},
budget: {
type: "integer",
label: "Budget",
description: "Amount of points to be gifted. If not provided, the points budget configured during automation setup will be used",
optional: true,
},
},
async run({ $ }) {
const data = {
contact_emails: this.contactEmails,
};
if (this.recipientMessage) data.recipient_message = this.recipientMessage;
if (this.senderName) data.sender_name = this.senderName;
if (this.budget) data.budget = this.budget;
Comment on lines +50 to +52

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Avoid truthiness-gating optional payload fields.

These checks silently omit valid falsy inputs (e.g., budget: 0). For actions, optional props can be passed directly and @pipedream/platform axios will strip only undefined.

Suggested fix
   async run({ $ }) {
     const data = {
       contact_emails: this.contactEmails,
+      recipient_message: this.recipientMessage,
+      sender_name: this.senderName,
+      budget: this.budget,
     };
-    if (this.recipientMessage) data.recipient_message = this.recipientMessage;
-    if (this.senderName) data.sender_name = this.senderName;
-    if (this.budget) data.budget = this.budget;
 
     const response = await this.stadium.createAutomationOrder({
       $,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@components/stadium/actions/create-automation-order/create-automation-order.mjs`
around lines 50 - 52, The conditional checks for recipientMessage, senderName,
and budget properties use truthiness evaluation, which incorrectly omits valid
falsy values like 0 or false. Remove the truthiness conditions and directly
assign these optional properties to the data object. The `@pipedream/platform`
axios will automatically strip only undefined values, allowing falsy values like
0 to be properly included in the payload.

Sources: Coding guidelines, Path instructions


const response = await this.stadium.createAutomationOrder({
$,
apiKey: this.apiKey,
data,
});
$.export("$summary", `Successfully created automation order — Identifier: ${response.identifier}`);
return response;
},
};
101 changes: 101 additions & 0 deletions components/stadium/actions/create-order/create-order.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import stadium from "../../stadium.app.mjs";

export default {
key: "stadium-create-order",
name: "Create Order",
description: "Place a new order against a Stadium Shop. [See the documentation](https://api.bystadium.com/api/v2/docs#tag/Order-management/operation/createOrder)",
version: "0.0.1",
type: "action",
annotations: {
destructiveHint: false,
openWorldHint: true,
readOnlyHint: false,
},
props: {
stadium,
storeNumber: {
propDefinition: [
stadium,
"storeNumber",
],
},
countryIso: {
type: "string",
label: "Country ISO",
description: "ISO code of the country (e.g., `US`)",
},
firstName: {
type: "string",
label: "First Name",
description: "Recipient's first name",
},
lastName: {
type: "string",
label: "Last Name",
description: "Recipient's last name",
},
phone: {
type: "string",
label: "Phone",
description: "Recipient's phone number",
optional: true,
},
street1: {
type: "string",
label: "Address Line 1",
description: "First line of the shipping address",
},
street2: {
type: "string",
label: "Address Line 2",
description: "Second line of the shipping address",
optional: true,
},
city: {
type: "string",
label: "City",
description: "City",
},
stateName: {
type: "string",
label: "State",
description: "State name",
},
zipCode: {
type: "string",
label: "Zip Code",
description: "Zip code",
},
products: {
type: "string",
label: "Products",
description: "JSON array of products to order. Each product should have `id` (variant ID, e.g., `10/1/9`), `quantity`, and `product_type` (e.g., `Spree::Product`). Example: `[{\"id\":\"10/1/9\",\"quantity\":1,\"product_type\":\"Spree::Product\"}]`",
},
},
async run({ $ }) {
const products = typeof this.products === "string"
? JSON.parse(this.products)
: this.products;
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated

const response = await this.stadium.createOrder({
$,
data: {
store_number: this.storeNumber,
country_iso: this.countryIso,
address: {
first_name: this.firstName,
last_name: this.lastName,
phone: this.phone,
zip_code: this.zipCode,
street_1: this.street1,
street_2: this.street2,
city: this.city,
state_name: this.stateName,
},
products,
},
});
$.export("$summary", `Successfully created order ${response.number}`);
return response;
},
};
31 changes: 31 additions & 0 deletions components/stadium/actions/get-order-details/get-order-details.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import stadium from "../../stadium.app.mjs";

export default {
key: "stadium-get-order-details",
name: "Get Order Details",
description: "Get details for a placed order. [See the documentation](https://api.bystadium.com/api/v2/docs#tag/Order-management/operation/orderDetails)",
version: "0.0.1",
type: "action",
annotations: {
destructiveHint: false,
openWorldHint: false,
readOnlyHint: true,
},
Comment thread
coderabbitai[bot] marked this conversation as resolved.
props: {
stadium,
orderNumber: {
propDefinition: [
stadium,
"orderNumber",
],
},
},
async run({ $ }) {
const response = await this.stadium.getOrderDetails({
$,
orderNumber: this.orderNumber,
});
$.export("$summary", `Successfully retrieved details for order ${this.orderNumber}`);
return response;
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import stadium from "../../stadium.app.mjs";

export default {
key: "stadium-get-shipment-status",
name: "Get Shipment Status",
description: "Get shipment status and tracking details for a placed order. [See the documentation](https://api.bystadium.com/api/v2/docs#tag/Order-management/operation/orderShipmentDetails)",
version: "0.0.1",
type: "action",
annotations: {
destructiveHint: false,
openWorldHint: false,
readOnlyHint: true,
},
Comment thread
coderabbitai[bot] marked this conversation as resolved.
props: {
stadium,
orderNumber: {
propDefinition: [
stadium,
"orderNumber",
],
},
},
async run({ $ }) {
const response = await this.stadium.getShipmentStatus({
$,
orderNumber: this.orderNumber,
});
$.export("$summary", `Successfully retrieved shipment status for order ${this.orderNumber}`);
return response;
},
};
Loading