openapi: 3.2.0 info: title: Plainrouter Event API version: 0.5.0 description: 'Operations tagged Event across 2 of this provider''s published API definitions: dev-plainrouter-openapi.json, plainrouter-openapi.json. Each path carries the servers of the definition it was published in.' servers: - url: https://plainrouter.com/api/v1 description: Production security: - workspaceSecret: [] tags: - name: Event paths: /events: post: operationId: createEvent description: Accepts a consent-aware server-side conversion event and uses event_id or Idempotency-Key to make retries idempotent. summary: Submit a conversion event tags: - Event parameters: - name: Idempotency-Key in: header description: Optional idempotency key. When event_id is omitted, Plainrouter uses this value as event_id. If both are supplied, they must match. schema: type: string requestBody: description: Authenticated callers using the Server secret may supply client_ip_address and client_user_agent in user_data; browser traffic using the Publishable key takes those fields only from the configured edge. required: true content: application/json: schema: anyOf: - type: object properties: event_id: type: string description: Caller-supplied idempotency key; maximum 128 characters. event_name: type: string description: Signal event name; maximum 100 characters. parent_event_id: type: string description: Optional parent event id; maximum 128 characters. event_time: description: Unix timestamp or ISO-8601 date-time. Defaults to receipt time. anyOf: - type: integer - type: string event_source: type: string format: uri description: Optional absolute source URL. action_source: type: string description: Optional action source; defaults to website and is limited to 50 characters. visitor_id: type: string description: Optional visitor identifier; maximum 255 characters. consent_basis: type: string description: Legal basis for processing. Legitimate-interest server revenue retains identity only with admitted global visitor or buyer-country evidence and no opt-out. const: consent consent: type: object description: Consent state supplied with the event. additionalProperties: {} consent_mode: type: object description: Consent Mode v2 signal values supplied with the event. additionalProperties: {} tcf: type: object description: TCF v2 data containing string and optional captured_at. additionalProperties: {} user_data: type: object description: Identity fields accepted by the tracker. additionalProperties: {} click_ids: type: object description: Advertising click identifiers. additionalProperties: {} value_data: type: object description: Optional commerce data. Contents accepts at most 50 items and 16 KB serialized. properties: value: type: string currency: type: string order_id: type: string contents: type: array items: {} num_items: type: integer required: - event_name - consent_basis - type: object properties: event_id: type: string description: Caller-supplied idempotency key; maximum 128 characters. event_name: type: string description: Signal event name; maximum 100 characters. enum: - signal_verification - consent_withdrawal parent_event_id: type: string description: Optional parent event id; maximum 128 characters. event_time: description: Unix timestamp or ISO-8601 date-time. Defaults to receipt time. anyOf: - type: integer - type: string event_source: type: string format: uri description: Optional absolute source URL. action_source: type: string description: Optional action source; defaults to website and is limited to 50 characters. visitor_id: type: string description: Optional visitor identifier; maximum 255 characters. consent_basis: type: string description: Legal basis for processing. Legitimate-interest server revenue retains identity only with admitted global visitor or buyer-country evidence and no opt-out. const: legitimate_interest consent: type: object description: Consent state supplied with the event. additionalProperties: {} consent_mode: type: object description: Consent Mode v2 signal values supplied with the event. additionalProperties: {} tcf: type: object description: TCF v2 data containing string and optional captured_at. additionalProperties: {} user_data: type: object description: Identity fields accepted by the tracker. additionalProperties: {} click_ids: type: object description: Advertising click identifiers. additionalProperties: {} value_data: type: object description: Optional commerce data. Contents accepts at most 50 items and 16 KB serialized. properties: value: type: string currency: type: string order_id: type: string contents: type: array items: {} num_items: type: integer required: - event_name - consent_basis responses: '200': description: Duplicate event accepted idempotently. content: application/json: schema: type: object properties: event_id: type: string duplicate: type: boolean required: - event_id - duplicate headers: Location: description: Canonical event resource to poll for delivery state. schema: type: string format: uri Idempotency-Key: description: Echoes the Idempotency-Key supplied by the caller. schema: type: string '202': description: New event accepted for processing. content: application/json: schema: type: object properties: event_id: type: string duplicate: type: boolean warnings: type: array items: type: object properties: code: $ref: '#/components/schemas/IngestionWarningCode' field: type: string enum: - consent.captured_at - event_source message: type: string required: - code - field - message required: - event_id - duplicate - warnings headers: Location: description: Canonical event resource to poll for delivery state. schema: type: string format: uri Idempotency-Key: description: Echoes the Idempotency-Key supplied by the caller. schema: type: string '401': description: Invalid or missing Server secret. content: application/json: schema: $ref: '#/components/schemas/ErrorMessage' '422': description: Request validation failed. content: application/json: schema: $ref: '#/components/schemas/ValidationError' servers: - url: https://plainrouter.com/api/v1 description: Production /verification-events: post: operationId: verifySignalIngestion description: Records one idempotent, identity-free modeled event to confirm workspace-scoped ingestion. It does not count as real arrival evidence or complete onboarding. summary: Verify server-side Signal ingestion tags: - Event responses: '200': description: The idempotent server verification event already exists. content: application/json: schema: type: object properties: event_id: type: string duplicate: type: boolean required: - event_id - duplicate headers: Location: description: Canonical verification-event resource to poll. schema: type: string format: uri '202': description: Server-side Signal ingestion verified. content: application/json: schema: type: object properties: event_id: type: string duplicate: type: boolean required: - event_id - duplicate headers: Location: description: Canonical verification-event resource to poll. schema: type: string format: uri '401': description: Invalid or missing Server secret. content: application/json: schema: $ref: '#/components/schemas/ErrorMessage' servers: - url: https://plainrouter.com/api/v1 description: Production /events/{event}: get: operationId: getEvent description: Returns one retained customer-readable event with lineage and destination delivery state for scoped troubleshooting and acceptance checks. summary: Get an event and delivery trace tags: - Event parameters: - name: event in: path required: true schema: type: string responses: '200': description: Event, lineage, and destination delivery state. content: application/json: schema: type: object properties: event: type: object properties: id: type: string workspace_id: type: integer signal_tracker_id: type: string description: Deprecated alias of workspace_id; contains the workspace ID in decimal string form. deprecated: true parent_event_id: type: - string - 'null' event_name: type: string event_time: type: string action_source: type: string event_class: type: string order_id: type: - string - 'null' value_amount: type: - integer - 'null' value_currency: type: - string - 'null' created_at: type: string consent_basis: type: string measurement_class: type: string attribution_join: type: string enforcement_scope: type: string consent_normalization_version: type: string consent: anyOf: - type: object additionalProperties: {} - type: array items: {} - type: 'null' user_data_hashed: description: Deprecated compatibility field. The value is always null; delivery identity is never returned. anyOf: - type: object additionalProperties: {} - type: array items: {} - type: 'null' click_ids: anyOf: - type: object additionalProperties: {} - type: array items: {} - type: 'null' session: anyOf: - type: object additionalProperties: {} - type: array items: {} - type: 'null' value_data: anyOf: - type: object additionalProperties: {} - type: array items: {} - type: 'null' event_source: type: - string - 'null' payload_expired: type: boolean deliveries: type: array items: type: object properties: id: type: integer workspace_id: type: integer signal_tracker_id: type: string description: Deprecated alias of workspace_id; contains the workspace ID in decimal string form. deprecated: true event_id: type: string destination_id: type: - string - 'null' status: $ref: '#/components/schemas/DeliveryStatus' is_test: type: boolean attempt_count: type: integer last_error: anyOf: - type: object additionalProperties: {} - type: array items: {} - type: 'null' platform_response: anyOf: - type: object additionalProperties: {} - type: array items: {} - type: 'null' platform_trace_id: type: - string - 'null' next_attempt_at: type: - string - 'null' created_at: type: string updated_at: type: - string - 'null' required: - id - workspace_id - signal_tracker_id - event_id - destination_id - status - is_test - attempt_count - last_error - platform_response - platform_trace_id - next_attempt_at - created_at - updated_at required: - id - workspace_id - signal_tracker_id - parent_event_id - event_name - event_time - action_source - event_class - order_id - value_amount - value_currency - created_at - consent_basis - measurement_class - attribution_join - enforcement_scope - consent_normalization_version - consent - user_data_hashed - click_ids - session - value_data - event_source - payload_expired - deliveries lineage: type: object properties: parent: type: - object - 'null' properties: id: type: string workspace_id: type: integer signal_tracker_id: type: string description: Deprecated alias of workspace_id; contains the workspace ID in decimal string form. deprecated: true parent_event_id: type: - string - 'null' event_name: type: string event_time: type: string action_source: type: string event_class: type: string order_id: type: - string - 'null' value_amount: type: - integer - 'null' value_currency: type: - string - 'null' created_at: type: string consent_basis: type: string measurement_class: type: string attribution_join: type: string enforcement_scope: type: string consent_normalization_version: type: string consent: anyOf: - type: object additionalProperties: {} - type: array items: {} - type: 'null' user_data_hashed: description: Deprecated compatibility field. The value is always null; delivery identity is never returned. anyOf: - type: object additionalProperties: {} - type: array items: {} - type: 'null' click_ids: anyOf: - type: object additionalProperties: {} - type: array items: {} - type: 'null' session: anyOf: - type: object additionalProperties: {} - type: array items: {} - type: 'null' value_data: anyOf: - type: object additionalProperties: {} - type: array items: {} - type: 'null' event_source: type: - string - 'null' payload_expired: type: boolean required: - id - workspace_id - signal_tracker_id - parent_event_id - event_name - event_time - action_source - event_class - order_id - value_amount - value_currency - created_at - consent_basis - measurement_class - attribution_join - enforcement_scope - consent_normalization_version - consent - user_data_hashed - click_ids - session - value_data - event_source - payload_expired children: type: array items: type: object properties: id: type: string workspace_id: type: integer signal_tracker_id: type: string description: Deprecated alias of workspace_id; contains the workspace ID in decimal string form. deprecated: true parent_event_id: type: - string - 'null' event_name: type: string event_time: type: string action_source: type: string event_class: type: string order_id: type: - string - 'null' value_amount: type: - integer - 'null' value_currency: type: - string - 'null' created_at: type: string consent_basis: type: string measurement_class: type: string attribution_join: type: string enforcement_scope: type: string consent_normalization_version: type: string consent: anyOf: - type: object additionalProperties: {} - type: array items: {} - type: 'null' user_data_hashed: description: Deprecated compatibility field. The value is always null; delivery identity is never returned. anyOf: - type: object additionalProperties: {} - type: array items: {} - type: 'null' click_ids: anyOf: - type: object additionalProperties: {} - type: array items: {} - type: 'null' session: anyOf: - type: object additionalProperties: {} - type: array items: {} - type: 'null' value_data: anyOf: - type: object additionalProperties: {} - type: array items: {} - type: 'null' event_source: type: - string - 'null' payload_expired: type: boolean required: - id - workspace_id - signal_tracker_id - parent_event_id - event_name - event_time - action_source - event_class - order_id - value_amount - value_currency - created_at - consent_basis - measurement_class - attribution_join - enforcement_scope - consent_normalization_version - consent - user_data_hashed - click_ids - session - value_data - event_source - payload_expired required: - parent - children deliveries: type: array items: allOf: - type: object properties: id: type: integer workspace_id: type: integer signal_tracker_id: type: string description: Deprecated alias of workspace_id; contains the workspace ID in decimal string form. deprecated: true event_id: type: string destination_id: type: - string - 'null' status: $ref: '#/components/schemas/DeliveryStatus' is_test: type: boolean attempt_count: type: integer last_error: anyOf: - type: object additionalProperties: {} - type: array items: {} - type: 'null' platform_response: anyOf: - type: object additionalProperties: {} - type: array items: {} - type: 'null' platform_trace_id: type: - string - 'null' next_attempt_at: type: - string - 'null' created_at: type: string updated_at: type: - string - 'null' required: - id - workspace_id - signal_tracker_id - event_id - destination_id - status - is_test - attempt_count - last_error - platform_response - platform_trace_id - next_attempt_at - created_at - updated_at - type: object properties: explanation: type: string required: - explanation required: - event - lineage - deliveries '401': description: Invalid or missing Server secret. content: application/json: schema: $ref: '#/components/schemas/ErrorMessage' '404': description: Resource not found. content: application/json: schema: $ref: '#/components/schemas/ErrorMessage' servers: - url: https://plainrouter.com/api/v1 description: Production components: schemas: DeliveryStatus: type: string enum: - queued - sent - accepted - retrying - failed:auth - failed:permanent - failed:unknown - expired - skipped:consent - skipped:no_destination - skipped:duplicate title: DeliveryStatus ErrorMessage: type: object properties: message: type: string required: - message title: ErrorMessage ValidationError: type: object properties: message: type: string errors: type: object additionalProperties: type: array items: type: string required: - message - errors title: ValidationError IngestionWarningCode: type: string description: 'The closed set of non-rejection warnings returned by POST /events. ' enum: - consent_captured_at_invalid - event_source_invalid title: IngestionWarningCode DeliveryStatus_2: type: string enum: - queued - sent - held - accepted - retrying - failed:auth - failed:permanent - failed:unknown - expired - skipped:consent - skipped:no_destination - skipped:duplicate - skipped:lifecycle title: DeliveryStatus securitySchemes: workspaceSecret: type: http description: Per-workspace Server secret. It authenticates only the Signals workspace represented by the credential. scheme: bearer sandboxCredential: type: http description: Short-lived Sandbox key issued by POST /sandbox/keys. scheme: bearer workspaceActionKey: type: http description: Workspace key with read-actions for reads or propose-actions for writes. Unbound keys select an available advertising account with account_id. scheme: bearer planWriter: type: http description: An OAuth agent or account-bound Workspace Key with write access and the plan-create grant. scheme: bearer workspaceInventoryKey: type: http description: Workspace read key with the get_inventory_metrics grant. Account-bound keys can read only their bound account. scheme: bearer planReader: type: http description: An OAuth agent or account-bound Workspace Key with read access to the approved ad account. scheme: bearer creativeWriter: type: http description: Workspace-bound write credential with a grant authorizing creative intake. scheme: bearer testReader: type: http description: A workspace principal with read tier and the launch.plans.index and launch.plans.show grants for this account. scheme: bearer testWriter: type: http description: A workspace principal with write tier and the launch.plans.store grant for this account. scheme: bearer ruleReader: type: http description: 'A workspace-scoped key with read ability and actions.rules.index or actions.rules.show access to the bound account. Send Accept: application/json.' scheme: bearer ruleWriter: type: http description: 'A workspace-scoped key with write ability and the actions.rules.store or actions.rules.update grant. Send Accept: application/json.' scheme: bearer agentContextKey: type: http description: Workspace key with read ability, ad-account.read permission and the agent.context grant. scheme: bearer agentContextOAuth: type: oauth2 description: OAuth access token for an active approved agent principal with mcp:use, ad-account.read and agent.context authorization. Authorization code with PKCE and device authorization tokens are accepted. This scheme applies only to agent context. flows: authorizationCode: authorizationUrl: https://plainrouter.com/oauth2/authorize tokenUrl: https://plainrouter.com/oauth2/token refreshUrl: https://plainrouter.com/oauth2/token scopes: mcp:use: Use the approved agent principal. x-refined-from: - dev-plainrouter-openapi.json - plainrouter-openapi.json x-action-types: - increase_budget - decrease_budget - pause - resume - replace_creative - shift_spend - rollback - create_campaign - create_ad_set - create_ad - upload_asset x-signed: true