Skip to main content
Builder Attribution lets applications earn an additional fee for routing Perps orders with a fee explicitly approved by the trader. The Builder operates the application and receives the fee in its Perps account. The Trader places orders through that application and approves the Builder fee.

Quickstart: Place an order with Builder Attribution

Use the Trader’s funded Perps account and owner signer to approve the Builder fee once, then place attributed orders. Approval remains valid across sessions until revoked or replaced. Each Builder is identified by its Perps account address. The Builder and Trader must be different accounts.
Use createSecureClient() from @polymarket/client with the Trader’s owner signer. This example uses Viem. See Wallet Integrations for other signer providers. Set builderAddress to the Builder’s EVM account address and instrumentId to the instrument selected in Prepare a Trade.
1

Create a Secure Client

Create a SecureClient for the Trader. Set POLYMARKET_WALLET_ADDRESS to the Polymarket wallet that owns the Perps account and PRIVATE_KEY to its owner’s signing key.
2

Open a Trader Session

Call client.openPerpsSession() with the Builder’s account address:
3

Approve the Builder Fee

Call session.approveBuilderFee with an explicit maxFeeRate before the Trader’s first attributed order. Skip this step if the Trader already has an active approval:
4

Place an Attributed Order

Call session.placeOrder() to submit an immediate-or-cancel buy using the session’s Builder:
The session applies the same terms to single orders, batches, and generated take-profit and stop-loss exits. Await approval before submitting orders that should use its terms.

Trader Operations

Read and manage the Trader’s consent, place attributed orders, and inspect the fees charged on executions.

Fetch Trader Approval

Check whether the Trader has already approved a Builder and the maximum fee they accepted. Read the saved approval before asking for consent again. A revoked approval remains in the account’s history with a zero fee limit.
Call session.fetchBuilderApprovals() on the Trader’s existing PerpsSession, filtering by the Builder’s account address:
An empty array means the Trader has no saved approval for this Builder. Otherwise, approval.maxFeeRate is the approved fee limit as a decimal string. Zero means consent was revoked. Compare the intended Builder fee with this limit to decide whether to request approval. approval.approvalVersion is the saved version, including after revocation.Omit the builder filter to fetch all of the Trader’s saved Builder approvals.

Grant Approval

Approve the Builder fee once before placing attributed orders. Existing approval remains valid across sessions until revoked or replaced. To approve a changed Builder fee, grant approval again.
The maximum Builder fee is currently 10 basis points (0.1%). This limit may change in the future.
Call session.approveBuilderFee on a Trader session opened with builderAttribution. Pass the maximum fee the Trader agrees to authorize:
maxFeeRate is required and has no default. This example approves 10 basis points (0.1%). To select a Builder when the session has none, or approve a different Builder, also pass its address:
After confirmation, the session refreshes the Builder cap and uses the lower of that cap and the approved maximum for new orders.

Revoke Approval

Revoke permission for new attributed orders. Existing accepted orders, including pending conditional orders, retain their saved fees. Cancel those orders to prevent further charges.
Call session.revokeBuilderFee() with the Builder’s account address:

Place Orders

The Trader must have granted fee approval for the Builder before submitting attributed orders. The order’s Builder fee must be covered by that approval. These examples place an immediate-or-cancel buy using an existing trading session or signed order.
Call session.placeOrder() on the Trader’s existing PerpsSession, opened with builderAttribution. The session uses the selected Builder and its saved approved fee. Set instrumentId to the instrument you want to trade:

Display Trader Fees

Show the total fee charged for each execution, with exchange and Builder fees as the breakdown. A maker rebate can make the total negative. Do not clamp it to zero.
Read fills with session.listFills() on the Trader’s PerpsSession:
Each item in fills has this shape. Use totalFee to display the total charge.
Private session fill events expose the same fee fields.

Rounding and PnL

Builder fees apply to eligible maker and taker executions, including voluntary closes. Forced liquidation legs, backstop transfers, and automatic deleveraging are excluded. An ordinary trading counterparty can still pay its saved fee. The exchange fee schedule applies separately. Builder fees do not change exchange-fee arithmetic or the precision of fee rates.

Builder Operations

Check Builder Availability

Check whether a Builder can receive attributed orders.
Call client.fetchPerpsBuilderStatus() on an existing SecureClient. Set builderAddress to the Builder’s Perps account address:

Reconcile Builder Earnings

Builders receive their full additional fee immediately in their Perps account. The credit can be used as collateral or withdrawn under the usual account rules. Earnings history reports settled activity. Use the account balance to determine spendable funds. Authenticate as the Builder account for reporting. The Trader’s session used above cannot read another account’s earnings.
Use fetchBuilderEarningsSummary() and listBuilderEarnings() on a PerpsSession opened by the Builder’s SecureClient. Here, builderSession is that session, created through Authenticated Sessions.
summary.snapshot fixes start, end, and asOfSequence so every page matches the summary. To select a window, pass start and end as Unix milliseconds to fetchBuilderEarningsSummary(). Use earningId to deduplicate receipts.

Reporting Rules

Exchange fee schedules, referral fee totals, and exchange revenue exclude Builder charges.

Follow Live Builder Fills

Use live receipts to update earnings as trades execute. Authenticate as the Builder account, as in the reporting examples above. The feed covers all Traders and markets attributed to that account.
Open a session with includeBuilderFills: true on the Builder’s SecureClient. Here, builderClient authenticates the Builder account through Authenticated Sessions.
builderFill is part of PerpsSessionEvent, alongside orders, fills, balances, and resync events. There is one session iterator and one connection lifecycle. includeBuilderFills defaults to false. Setting builderAttribution does not select whose receipts are delivered. Receipts belong to the authenticated Builder account.

Recover Missed Receipts

The feed has no initial history snapshot or exactly-once delivery guarantee. Its sequence numbers can skip values because other account activity shares the sequence. A gap alone does not prove receipts were lost. Use history to recover missed receipts after connecting or reconnecting:
1

Buffer Live Receipts

Start consuming the live feed and buffer receipts while fetching history.
2

Read Overlapping History

Select a window that starts before your last stored receipt. Fetch every page at the same indexed cutoff, using the reporting workflow above.
3

Merge Receipts

Deduplicate history and buffered receipts by their receipt identity. Keep the identity with your stored record so repeated recovery does not count an execution twice.
4

Check Indexing Progress

History can lag the feed. Repeat the overlapping read with a newer cutoff until indexing covers the interval being recovered. Do not treat the largest sequence on a receipt as the complete indexed cutoff.

Handle Order Errors

If an order is rejected because the Trader has not approved the Builder fee, request approval for that fee before placing another order. The examples below approve 10 basis points (0.1%) after the Trader accepts the fee.
session.placeOrder() throws RequestRejectedError with the message builder_approval_required when approval is missing, revoked, or does not cover the order’s Builder fee. Check error.message and call approveBuilderFee with the Builder address and the agreed rate:
Submit a new order after approval succeeds. For session.postOrders(), inspect each result’s status and error for the same rejection.