openapi: 3.2.0 info: title: Plainrouter Sandbox API version: 0.5.0 description: 'Operations tagged Sandbox 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: Sandbox paths: /sandbox: get: operationId: getSandbox description: Returns a ready-to-run synthetic event example that needs no account or key and cannot persist data or contact an advertising provider. summary: Discover the zero-auth sandbox tags: - Sandbox responses: '200': description: Sandbox capabilities and a ready-to-run example. content: application/json: schema: type: object properties: environment: type: string authentication_required: type: boolean account_required: type: boolean production_data: type: boolean persists_data: type: boolean provider_delivery: type: boolean description: type: string self_serve_key: type: object properties: method: type: string url: type: string authentication_required: type: boolean description: type: string issued_key: type: object properties: api_key: type: string token_type: type: string expires_in: type: integer expires_at: type: string scope: type: string production_access: type: boolean use: type: object properties: method: type: string url: type: string authorization: type: string required: - method - url - authorization required: - api_key - token_type - expires_in - expires_at - scope - production_access - use required: - method - url - authentication_required - description - issued_key try: type: object properties: method: type: string url: type: string content_type: type: string body: type: object properties: event_id: type: string event_name: type: string action_source: type: string value_data: type: object properties: value: type: string currency: type: string order_id: type: string required: - value - currency - order_id required: - event_id - event_name - action_source - value_data required: - method - url - content_type - body required: - environment - authentication_required - account_required - production_data - persists_data - provider_delivery - description - self_serve_key - try headers: Access-Control-Allow-Origin: schema: type: string const: '*' Cache-Control: schema: type: string const: no-store, private X-Content-Type-Options: schema: type: string const: nosniff security: [] servers: - url: https://plainrouter.com/api/v1 description: Production /sandbox/keys: get: operationId: getSandboxKey description: Returns a short-lived Sandbox key over GET so a read-only agent can obtain working credentials without issuing a write request. summary: Get a Sandbox key tags: - Sandbox responses: '200': description: Short-lived Sandbox key issued. content: application/json: schema: type: object properties: api_key: type: string token_type: type: string expires_in: type: integer expires_at: type: string scope: type: string production_access: type: boolean use: type: object properties: method: type: string url: type: string authorization: type: string required: - method - url - authorization required: - api_key - token_type - expires_in - expires_at - scope - production_access - use headers: Access-Control-Allow-Origin: schema: type: string const: '*' Cache-Control: schema: type: string const: no-store, private X-Content-Type-Options: schema: type: string const: nosniff security: [] post: operationId: createSandboxKey description: Issues a short-lived Sandbox key without an account, human approval, or production access. It is valid for synthetic events only. summary: Create a Sandbox key tags: - Sandbox responses: '201': description: Short-lived Sandbox key issued. content: application/json: schema: type: object properties: api_key: type: string token_type: type: string expires_in: type: integer expires_at: type: string scope: type: string production_access: type: boolean use: type: object properties: method: type: string url: type: string authorization: type: string required: - method - url - authorization required: - api_key - token_type - expires_in - expires_at - scope - production_access - use headers: Access-Control-Allow-Origin: schema: type: string const: '*' Cache-Control: schema: type: string const: no-store, private X-Content-Type-Options: schema: type: string const: nosniff security: [] servers: - url: https://plainrouter.com/api/v1 description: Production /sandbox/events: post: operationId: validateSandboxEvent description: Validates and immediately discards one identity-free synthetic event. It requires no account or key and never writes to the ledger or contacts Meta. summary: Validate a synthetic event tags: - Sandbox requestBody: required: true content: application/json: schema: type: object properties: event_id: type: string description: Optional synthetic idempotency key; maximum 128 characters. event_name: type: string description: Synthetic event name; maximum 100 characters. action_source: type: string description: Synthetic action source. examples: - website value_data: type: object description: Optional synthetic commerce data. properties: value: type: string currency: type: string order_id: type: string required: - event_name responses: '200': description: Synthetic event validated and discarded. content: application/json: schema: type: object properties: sandbox: type: boolean accepted: type: boolean event_id: type: string status: type: string persisted: type: boolean provider_delivery: type: boolean message: type: string required: - sandbox - accepted - event_id - status - persisted - provider_delivery - message headers: Access-Control-Allow-Origin: schema: type: string const: '*' Cache-Control: schema: type: string const: no-store, private X-Content-Type-Options: schema: type: string const: nosniff '422': description: Request validation failed. content: application/json: schema: $ref: '#/components/schemas/ValidationError' security: [] servers: - url: https://plainrouter.com/api/v1 description: Production /sandbox/keyed-events: post: operationId: validateSandboxEventWithKey description: Validates a synthetic event with a short-lived Sandbox key, then discards it without persisting data or contacting an advertising provider. summary: Validate a synthetic event with a Sandbox key tags: - Sandbox requestBody: required: true content: application/json: schema: type: object properties: event_id: type: string description: Optional synthetic idempotency key; maximum 128 characters. event_name: type: string description: Synthetic event name; maximum 100 characters. action_source: type: string description: Synthetic action source. examples: - website value_data: type: object description: Optional synthetic commerce data. properties: value: type: string currency: type: string order_id: type: string required: - event_name responses: '200': description: Synthetic event validated with a Sandbox key and discarded. content: application/json: schema: type: object properties: sandbox: type: boolean accepted: type: boolean event_id: type: string status: type: string persisted: type: boolean provider_delivery: type: boolean message: type: string required: - sandbox - accepted - event_id - status - persisted - provider_delivery - message '401': description: Sandbox key missing, invalid, or expired. content: application/json: schema: $ref: '#/components/schemas/ErrorMessage' '422': description: Request validation failed. content: application/json: schema: $ref: '#/components/schemas/ValidationError' security: - sandboxCredential: [] servers: - url: https://plainrouter.com/api/v1 description: Production components: schemas: ValidationError: type: object properties: message: type: string errors: type: object additionalProperties: type: array items: type: string required: - message - errors title: ValidationError ErrorMessage: type: object properties: message: type: string required: - message title: ErrorMessage 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