Docs

Plugins, Decisioners, and MCP tools

Add bidding, pricing, targeting, and other serving behavior with an ExtensionService plugin. Use a Decisioner for model-based decisions, or the Admin API and MCP for applications and agents. The examples below include local tests and installation instructions.

Riptide Console operability view with health checks and audit log
Monitoring and audit

Download working starters

Download source, tests, setup instructions, and a coding-agent prompt for each example. You can run them locally without a private Riptide checkout. To connect an example to serving, deploy the service and register it with an authorized tenant. See all examples and workflow prompts for API, reporting, serving and webhook integrations.

Decisioner (HTTP)

Test a floor-pricing rule locally, then compare it with the baseline in shadow mode. This Go HTTP service returns a decimal floor decision; the guide covers registration as an EXTERNAL_ENDPOINT model.

Download source ZIP · Source mirror

Extension sidecar

Start a custom bidding, targeting, pricing or rendering integration from a working gRPC service. The archive includes small policies for all eight plugin kinds, plus local tests for Describe, Health and Invoke.

Download source ZIP · Source mirror

Build with your coding agent

Copy this prompt and replace its final goal with your integration. Each archive also contains a focused PROMPT.md.

Agent prompt
You are helping me build a Riptide extension.

## Product context
Riptide combines an ad server, SSP, and DSP. Choose one of these integration types:
1. Plugin kinds for serving: BID_SOURCE, DEMAND_ADAPTER, ENRICHER, AUDIENCE_EVALUATOR, PRICING_MODULE, CREATIVE_RENDERER, VERIFICATION_VENDOR, DEMAND_ATTACHMENT. Each uses ExtensionService. Run one kind per process.
2. Decisioners: keep the deterministic baseline and evaluate candidate policies or models. Register with kind BASELINE, SIDECAR, or EXTERNAL_ENDPOINT, then assign in SHADOW, BOUNDED_AB, or LIVE mode. Promotion requires measured improvement.
3. Admin API and MCP: call existing operations for administrative work. Adding a core operation requires an OpenAPI change and regenerated MCP descriptors in a customer checkout.

Public overview: https://riptideads.com/docs/extensions

## Choose the integration type
- Custom serving behavior (bids, demand adapters, enrichment, verification, pricing, rendering, audiences, demand attachment) -> plugin kind / ExtensionService sidecar.
- Reporting customization -> query the typed reports catalog and build a client/export integration. New server-side dimensions require a typed catalog/schema change in a customer checkout; reporting is not an ExtensionService kind.
- Bid, floor, traffic shape, pace, creative, audience, insight, anomaly (and related) decisions with baseline + optional model -> Decisioner.
- Administrative application or agent -> existing Admin API or MCP tools. Adding a new core operation requires a customer checkout, Admin OpenAPI changes and regenerated MCP descriptors.

## Start from the published examples
Examples and additional workflow prompts: https://riptideads.com/docs/examples
- EXTERNAL_ENDPOINT Decisioner: download https://riptideads.com/examples/decisioner-http.zip, extract it and read README.md and PROMPT.md. Source mirror: https://github.com/naffis/riptide-example-decisioner.
- ExtensionService sidecar: download https://riptideads.com/examples/extension-sidecar.zip, extract it and read README.md and PROMPT.md. Source mirror: https://github.com/naffis/riptide-example-extension-sidecar.
The archives contain standalone source and tests. A local example can run without platform access; registration requires an authorized Riptide tenant and a reachable deployed service.

## Implementation requirements
- Use the example’s contracts and JSON/proto formats.
- Money and rates are decimal strings with 4 decimal places (for example "2.5000"), never floating point.
- Respect request deadlines and cancellation. Slow or failed sidecars are skipped; Decisioners fall back to the deterministic baseline.
- Keep secrets and tenant account credentials out of code and sample config; use env vars / secret stores.
- Decisioners: implement or keep a deterministic baseline path; register candidates in shadow before live.
- Sidecars: implement riptide.ext.v1.ExtensionService (Describe, Health, Invoke), declare name/version/kind/entitlement/latency budget.
- Request only needed context_fields; receive tenant settings through install-time config, not hardcoded accounts. Respect the host's per-kind fallback semantics.
- Publishing a stack product requires vendor entitlement and operator-verified conformance. The operator runs the harness before recording evidence with runExtensionConformance; that API does not run the harness.
- Install through installStackProduct using listing_id and config_json (a JSON-encoded string). Do not invent a direct tenant-extension create endpoint.
- External HTTP Decisioners require a public HTTPS endpoint; the localhost demo is only a smoke test. Register via createModel and assignModel in SHADOW; promotion uses the operator-gated promoteModel flow.
- MCP uses POST /mcp, initialize then tools/list and tools/call. A registered agent identity must sign the exact request bytes; follow /docs/mcp for key registration, canonical signing, and durable approval tasks.

## What I want you to build
(Replace this section with your goal. Examples: "EXTERNAL_ENDPOINT floor Decisioner that bumps floor by 0.10 CPM for PMP", "BidSource sidecar that bids floor+1 on video", "Enricher that adds a contextual category flag".)

1. Restate which surface and kind you will implement.
2. Download and extract the matching example above, then run its existing tests.
3. Implement the behavior with tests for successful requests, failures, and timeouts.
4. Document configuration, local smoke commands, expected output, deployment prerequisites and the registration API. Include how to disable the integration or return to the baseline.
5. Provide working code and meaningful tests for empty input, invalid input, timeouts, and the chosen behavior. State external services or tenant access still required.

Use the standalone example unless I provide a customer checkout.

Choose a plugin kind

Each sidecar process runs one plugin kind and implements riptide.ext.v1.ExtensionService with Describe, Health and Invoke. The archive's README maps each kind to its command, JSON payload, expected output and conformance test.

Kind / wire methodServing configurationOn failure
BID_SOURCE
GetBids
Adds bid candidates for the tenant. The auction applies its usual eligibility and pricing rules.No additional bids.
DEMAND_ADAPTER
BuildRequests / ParseResponse
Demand partner adapter must be sidecar; routes provide the buying configuration. The host performs outbound requests.No requests or bids from that integration.
ENRICHER
Enrich
Runs during enrichment when privacy permits; fills unresolved signals and adds segments.Request remains unchanged.
AUDIENCE_EVALUATOR
Evaluate
Audience custom_rules.evaluator names the configured dimension or *; matched segments feed targeting. Privacy gates still apply.No matching segments; evaluator returns pass=false.
PRICING_MODULE
ApplyPricing
Runs after pricing. Net price must stay between zero and gross price, and gross price cannot increase.Keep the original prices.
CREATIVE_RENDERER
Render
Select media in the install configuration. Supports platform-rendered display/native markup on OpenRTB and Decision API requests. VAST rendering is unsupported.Keep the platform-rendered markup.
VERIFICATION_VENDOR
PreBid
Configure verification_slot and pre_bid for pre-bid signals and pixel suppression, subject to privacy policy. External measurement SDKs require a separate integration.No extra verification signals; configured platform policies still apply.
DEMAND_ATTACHMENT
Pick
Select eligible non-rendered demand candidates for a carrier under the attachment policy. The baseline is used when no sidecar is installed.No extra attachments; the carrier remains. An installed sidecar failure does not retry the baseline.

Declare name, version, kind, entitlement, health behavior, a latency budget and a config schema. Serve-path budgets must be positive and at most 50 ms; aggregate extension budgets also need to fit the auction deadline. Honor cancellation and avoid network work beyond that budget. Declare only the request keys you need in config_schema.context_fields; receive per-tenant configuration through tenant_config. Money remains decimal strings, such as "2.5000".

The bundled policies use a local -config file and do not inspect tenant_config. Run separate instances for tenants with different policies, or implement and test tenant-config handling when adapting the starter. An installation's config_json selects host behavior such as renderer media; it does not automatically override the starter's process policy.

Build report clients against the reporting catalog, and register Decisioners through the model workflow below. The retired REPORT_FIELD and DECISIONER ExtensionService kinds are rejected on new listings. Adding a stored report dimension requires a schema and catalog change in a customer checkout.

Publish and install a sidecar

Start with go test ./... and the smoke command in the extracted archive. Deploy the selected service where your Riptide cell can reach it, then arrange the endpoint reference and required secrets with the platform operator. Local tests do not install the service in a managed cell. Keep credentials in your secret store and out of listing metadata and source.

Admin operationWhat it does
createMarketplaceListingCreate a DRAFT STACK_PRODUCT listing with public metadata and pricing.
runExtensionConformanceOperator records the result of independently executed and reviewed conformance tests.
publishStackProductPublish after vendor entitlement, configuration, budgets and verified PASS checks.
installStackProductInstall a published listing with listing_id and a JSON-encoded config_json string.
listTenantExtensionsRead installed kinds and budgets; endpoint secrets are not returned.
uninstallStackProductRevoke the activation and remove its serving projection on the next plan refresh.

Listing metadata uses kind: STACK_PRODUCT, distribution: SIDECAR_ENDPOINT, extension_kinds, endpoint_ref, config_schema (JSON as a string), latency_budget_ms, conformance_run_id, trust requirements and decimal pricing. Publish requires vendor entitlement and a PASS with operator_verified=true. The runExtensionConformance endpoint does not execute the harness: an operator must run and review the tests before recording that evidence. Customer checkouts include the host harness at plugins/sidecar/conformance.

After publication, use installStackProduct: POST /v1/tenants/{tenant_id}/stack-products/install with your API key and a stable Idempotency-Key. Replace the listing ID and match the config to its schema. For a display renderer, the host selection includes media: banner:

{
  "listing_id": "018f0000-0000-7000-8000-000000000020",
  "config_json": "{\"media\":\"banner\"}"
}

Save the activation ID so you can uninstall later. Check the installation with listTenantExtensions, then wait for the next serving plan and send a test request that uses this plugin kind. Inspect request diagnostics and extension telemetry to confirm it ran. An uninstallStackProduct call revokes that activation; existing requests finish against their captured plan.

Decisioners: register a model and start in shadow

A Decisioner preserves a deterministic baseline and evaluates an optional candidate. BASELINE uses platform behavior, SIDECAR uses the separate gRPC DecisionService, and EXTERNAL_ENDPOINT accepts protojson DecideRequest over HTTP. The HTTP example implements a floor policy. Measure its effect on your traffic in shadow mode before considering promotion.

Deploy the HTTP starter behind public HTTPS with a valid certificate. The serving host rejects plain HTTP, loopback and private-network HTTP destinations. Replace the example hostname below, then call createModel at POST /v1/tenants/{tenant_id}/models with an idempotency key:

{
  "decision_point": "floor",
  "name": "my-floor-policy",
  "version": "1.0.0",
  "kind": "EXTERNAL_ENDPOINT",
  "config": {
    "url": "https://decisioner.example.com/decide"
  }
}

Use the returned model ID with assignModel at POST /v1/tenants/{tenant_id}/models/{model_id}/assignments:

{"decision_point":"floor","mode":"SHADOW","traffic_pct":"100.0000"}

SHADOW measures the candidate while baseline decisions serve. Review decision records and record an evaluation using recordEvaluationRun. Promotion through promoteModel (MCP riptide.model.promote_decisioner) requires the platform operator and measured evidence before bounded A/B or live use. Failure or timeout falls back to the baseline. Tenant creation/assignment/evaluation requires model.write; it does not grant model.promote.

Build applications with API and MCP

A reporting tool, campaign assistant or administration integration should call existing Admin API operations or MCP tools. New core operations require a customer checkout and contract regeneration. The examples page includes code and prompts for these workflows. You can also use the CLI's riptide ext init command to clone an example repository.

Start with a working example

Download a serving plugin or floor Decisioner, run its local tests, then adapt the policy to your integration. The capability guides explain what each example produces and how to connect it.