First signals

Prerequisites

Sending signals

Send a signal by calling the SDK with an event name and optional attribution. Signals represent actions your agent takes; use them to drive billing, track delivered value, or both. To attach a signal to a customer’s product usage, provide both customer and product ids. Unattributed signals are still saved and visible in the dashboard.

1from paid import Paid, Signal, CustomerByExternalId, ProductByExternalId
2
3paid_client = Paid(token="YOUR_PAID_API_KEY")
4
5# ... your business logic ...
6
7# emit a signal for an action your agent takes
8res = paid_client.signals.create_signals(
9 signals=[
10 Signal(
11 event_name="email_sent",
12 customer=CustomerByExternalId(
13 external_customer_id="<your_external_customer_id>",
14 ),
15 attribution=ProductByExternalId(
16 external_product_id="<your_external_product_id>",
17 ),
18 data={"some_data": "some_value"},
19 )
20 ],
21)
22
23print(res)

Consuming multiple credits per signal

By default, each signal consumes the fixed credit cost defined in your product’s pricing configuration (typically 1 credit). To consume a variable number of credits per signal, you can configure your pricing rule to read a quantity value from signal data.

Pricing configuration

For quantity-based credit consumption to work, your product’s prepaid credits pricing line must have a quantity mapping configured. This tells Paid which field in the signal’s data object contains the quantity value. Configure this in the product’s pricing settings by adding a quantity property that maps to the signal data path (e.g., $.quantity).

Without this mapping, every signal consumes the fixed credit cost regardless of what you send in data.

Sending quantity in signals

Once the pricing rule is configured, pass a quantity field in the signal’s data object. This is useful when a single action should deduct more than one credit. For example, a long-running workflow that consumes 5 credits, or a batch operation where credit cost scales with the size of the work performed.

1paid_client.signals.create_signals(
2 signals=[
3 Signal(
4 event_name="document_processed",
5 customer=CustomerByExternalId(
6 external_customer_id="cus_acme",
7 ),
8 attribution=ProductByExternalId(
9 external_product_id="doc_processor",
10 ),
11 data={
12 "quantity": 5,
13 "pages": 47,
14 "format": "pdf",
15 },
16 )
17 ],
18)

The quantity value is multiplied by the credit cost on the pricing rule. For example, if the pricing rule defines a credit cost of 1 and the signal sends quantity: 5, that signal deducts 5 credits. If the credit cost is 2 and quantity is 3, that signal deducts 6 credits.

When quantity is omitted, it defaults to 1.

User-level tracking within a customer

Signals are attributed to customers and products, but you can also track which individual user within a customer organization performed the action. Pass external_user_id in the signal’s data field, matching the external ID of a user created via the user management API.

1paid_client.signals.create_signals(
2 signals=[
3 Signal(
4 event_name="chat_message",
5 customer=CustomerByExternalId(
6 external_customer_id="cus_acme",
7 ),
8 attribution=ProductByExternalId(
9 external_product_id="chatbot",
10 ),
11 data={
12 "external_user_id": "usr_jane_doe",
13 "model": "gpt-4o",
14 },
15 )
16 ],
17)

When external_user_id is present, Paid resolves the user and their seat assignment. If the user occupies a seat with seat-scoped credit balances, the credit spend is deducted from that seat’s balance. If no seat is found, credits are deducted from the organization pool as usual.

The data object is stored exactly as you send it, and the analytics API queries fields by their literal key names. Use consistent keys across all SDKs and services so that queries return complete results. The examples above use snake_case keys in both Python and Node.js for this reason.

All fields in the data object are also queryable through the analytics API, so you can break down credit consumption by user, team, department, or any other dimension you include in signal data.