openapi: 3.2.0 info: title: Localytics Transactional Push API version: 2.0.0 description: 'Programmatic push messaging delivery. Submit a batch of pushes for an application; messages are forwarded to push-segmenter (for audience/profile/broadcast targeting) or message-delivery (for customer_id targeting). ## Per-message labels (all target types) Each entry in `messages` may carry its own labels (same `label1`..`label10`, string-valued rules as the top-level `labels`). Per-message labels are **merged with** the top-level `labels`, and per-message keys **win on conflict**. Two equivalent shapes are accepted on each message: 1. **Flat**: `labelN` fields directly on the message — `{ "target": "u1", "alert": "...", "label1": "rec-1" }` 2. **Nested**: a `labels` object on the message — `{ "target": "u1", "alert": "...", "labels": { "label1": "rec-1" } }` A single message may use one shape or the other, but **not both** — mixing returns HTTP 400. For `target_type: customer_id` this lets a caller bundle many distinct pushes into a single API call while still tagging each push with its own unique identifier (for example, an AI-generated request id), which is useful for time-window deliveries where the per-call rate limit would otherwise be a blocker. For `audience_id`, `profile`, and `broadcast` (which only allow a single message per batch) the per-message shape simply provides another spot to attach labels alongside the top-level `labels`. Note: `audience_id`, `profile`, and `broadcast` still allow only one message per batch — the per-message labels feature does not change that constraint.' servers: - url: / description: This service security: - basicAuth: [] tags: - name: push description: Transactional push send endpoints paths: /v2/push/{app_id}: post: tags: - push summary: Submit a transactional push batch description: 'Queues one or more push messages for delivery. The shape of `messages[*].target` depends on `target_type`. - `customer_id`: `target` is a customer id string or array of customer id strings. `messages` may contain many entries, each optionally carrying its own `labels` object. - `audience_id`: `target` is an integer audience id. `messages` must have exactly one entry. - `profile`: `target` is a profile object. `messages` must have exactly one entry. - `broadcast`: `target` is omitted or null. `messages` must have exactly one entry.' parameters: - name: app_id in: path required: true description: The Localytics application UUID. schema: type: string requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/BatchRequest' examples: customerId_singleMessage_topLevelLabels: summary: Single customer_id push with top-level labels value: request_id: 1234-1234-1234-1234 target_type: customer_id labels: label1: request-id-1234 messages: - target: user123 alert: Tickets for [Artist Name] at [Venue] are selling fast. Don't miss your chance - grab yours before they're gone! customerId_multipleMessages_perMessageLabels: summary: Multiple customer_id pushes in one call, each with its own labels value: request_id: 1234-1234-1234-1234 target_type: customer_id messages: - target: user123 alert: Tickets for [Artist Name] at [Venue] are selling fast. Don't miss your chance - grab yours before they're gone! labels: label1: request-id-1234 - target: user456 alert: Different text is here! labels: label1: request-id-0987-different-label-here customerId_mixedLabels: summary: Shared top-level labels merged with unique per-message label1 value: request_id: abc-123 target_type: customer_id labels: label2: presale_event_2026 messages: - target: user123 alert: msg 1 labels: label1: rec-id-1 - target: user456 alert: msg 2 labels: label1: rec-id-2 customerId_flatPerMessageLabels: summary: Per-message labels in the flat shape (labelN directly on each message), mixed with top-level labels value: request_id: 1234-1234-1234-1234 target_type: customer_id labels: label1: batch-1234 label5: spdata_99999 messages: - target: user123 alert: Tickets for [Artist Name] at [Venue] are selling fast. label2: vip-tier label3: campaign-spring-2026 - target: - user456 - user789 alert: title: Last chance! body: Only a few seats left. ios: sound: default badge: 1 content_available: true android: priority: high label1: message-override-0987 label4: fan-club customerId_mixedShapes_BAD: summary: 'REJECTED with HTTP 400: same message cannot mix nested ''labels'' and flat ''labelN''' value: target_type: customer_id messages: - target: user1 alert: boom labels: label1: nested label2: flat audienceId: summary: Audience-id push value: request_id: abc target_type: audience_id campaign_key: my_campaign messages: - target: 12345 alert: Hello, audience! audienceId_flatPerMessageLabel: summary: Audience-id push with a flat per-message label value: request_id: audience-batch-1 target_type: audience_id messages: - target: 9876 alert: Hi audience label1: livenation-audience-9876 broadcast: summary: Broadcast push value: request_id: abc target_type: broadcast campaign_key: ny-broadcast messages: - alert: Hello, everyone! broadcast_flatPerMessageLabel: summary: Broadcast push with a flat per-message label value: target_type: broadcast messages: - alert: Broadcast to everyone label1: marketing-campaign-12 profile_flatPerMessageLabel: summary: Profile push with a flat per-message label value: target_type: profile messages: - target: profile: criteria: - key: cats scope: Organization type: string op: in values: - Simba - Ofelia op: and alert: Hi cat people label1: cat-people-segment responses: '202': description: Batch accepted and queued for delivery content: application/json: schema: type: object properties: message: type: string example: Queued for delivery '400': description: Malformed request (bad JSON, invalid labels, duplicate request_id, campaign key creation limit, etc.) content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Missing or invalid API credentials content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Authenticated caller is not authorized for this app_id / audience_id, or app_id is misconfigured content: application/json: schema: $ref: '#/components/schemas/Error' '422': description: Unable to process entity (JSON cannot be parsed at all) content: application/json: schema: $ref: '#/components/schemas/Error' '429': description: Rate exceeded for the requested target_type content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/Error' components: schemas: MessageAudienceId: type: object additionalProperties: false required: - target description: Per-message labels can be supplied EITHER as the nested `labels` object OR as flat `label1`..`label10` fields directly on this object. Mixing both shapes in the same message returns HTTP 400. properties: target: type: integer description: Audience id. alert: $ref: '#/components/schemas/Alert' ios: $ref: '#/components/schemas/IosParams' android: $ref: '#/components/schemas/AndroidParams' web: $ref: '#/components/schemas/WebParams' labels: allOf: - $ref: '#/components/schemas/Labels' description: Optional labels scoped to THIS message (nested shape). Merged with the top-level `labels`; per-message keys take precedence on conflict. label1: type: string description: Optional flat-shape per-message label. label2: type: string description: Optional flat-shape per-message label. label3: type: string description: Optional flat-shape per-message label. label4: type: string description: Optional flat-shape per-message label. label5: type: string description: Optional flat-shape per-message label. label6: type: string description: Optional flat-shape per-message label. label7: type: string description: Optional flat-shape per-message label. label8: type: string description: Optional flat-shape per-message label. label9: type: string description: Optional flat-shape per-message label. label10: type: string description: Optional flat-shape per-message label. IosParams: type: object additionalProperties: false properties: sound: type: string badge: type: integer category: type: string extra: type: object additionalProperties: true content_available: type: boolean mutable_content: type: boolean AndroidParams: type: object additionalProperties: false properties: extra: type: object additionalProperties: true priority: type: string example: high MessageBroadcast: type: object additionalProperties: false description: Per-message labels can be supplied EITHER as the nested `labels` object OR as flat `label1`..`label10` fields directly on this object. Mixing both shapes in the same message returns HTTP 400. properties: target: description: Must be omitted or null. alert: $ref: '#/components/schemas/Alert' ios: $ref: '#/components/schemas/IosParams' android: $ref: '#/components/schemas/AndroidParams' web: $ref: '#/components/schemas/WebParams' labels: allOf: - $ref: '#/components/schemas/Labels' description: Optional labels scoped to THIS message (nested shape). Merged with the top-level `labels`; per-message keys take precedence on conflict. label1: type: string description: Optional flat-shape per-message label. label2: type: string description: Optional flat-shape per-message label. label3: type: string description: Optional flat-shape per-message label. label4: type: string description: Optional flat-shape per-message label. label5: type: string description: Optional flat-shape per-message label. label6: type: string description: Optional flat-shape per-message label. label7: type: string description: Optional flat-shape per-message label. label8: type: string description: Optional flat-shape per-message label. label9: type: string description: Optional flat-shape per-message label. label10: type: string description: Optional flat-shape per-message label. WebParams: type: object additionalProperties: false properties: badge: type: string dir: type: string extra: type: object additionalProperties: true icon: type: string renotify: type: boolean requireInteraction: type: boolean silent: type: boolean tag: type: string MessageProfile: type: object additionalProperties: false required: - target description: Per-message labels can be supplied EITHER as the nested `labels` object OR as flat `label1`..`label10` fields directly on this object. Mixing both shapes in the same message returns HTTP 400. properties: target: type: object description: Profile-targeting payload (criteria + outer op). additionalProperties: true alert: $ref: '#/components/schemas/Alert' ios: $ref: '#/components/schemas/IosParams' android: $ref: '#/components/schemas/AndroidParams' web: $ref: '#/components/schemas/WebParams' labels: allOf: - $ref: '#/components/schemas/Labels' description: Optional labels scoped to THIS message (nested shape). Merged with the top-level `labels`; per-message keys take precedence on conflict. label1: type: string description: Optional flat-shape per-message label. label2: type: string description: Optional flat-shape per-message label. label3: type: string description: Optional flat-shape per-message label. label4: type: string description: Optional flat-shape per-message label. label5: type: string description: Optional flat-shape per-message label. label6: type: string description: Optional flat-shape per-message label. label7: type: string description: Optional flat-shape per-message label. label8: type: string description: Optional flat-shape per-message label. label9: type: string description: Optional flat-shape per-message label. label10: type: string description: Optional flat-shape per-message label. Alert: description: Either a plain string alert or a structured alert. oneOf: - type: string example: Tickets are on sale now! - type: object properties: body: type: string title: type: string subtitle: type: string required: - body additionalProperties: false MessageCustomerId: type: object additionalProperties: false required: - target description: Per-message labels can be supplied EITHER as the nested `labels` object OR as flat `label1`..`label10` fields directly on this object. Mixing both shapes in the same message returns HTTP 400. properties: target: description: A customer id string or an array of customer id strings. oneOf: - type: string - type: array items: type: string alert: $ref: '#/components/schemas/Alert' ios: $ref: '#/components/schemas/IosParams' android: $ref: '#/components/schemas/AndroidParams' web: $ref: '#/components/schemas/WebParams' labels: allOf: - $ref: '#/components/schemas/Labels' description: Optional labels scoped to THIS message (nested shape). Merged with the top-level `labels`; per-message keys take precedence on conflict. Customer-id only. label1: type: string description: Optional flat-shape per-message label. label2: type: string description: Optional flat-shape per-message label. label3: type: string description: Optional flat-shape per-message label. label4: type: string description: Optional flat-shape per-message label. label5: type: string description: Optional flat-shape per-message label. label6: type: string description: Optional flat-shape per-message label. label7: type: string description: Optional flat-shape per-message label. label8: type: string description: Optional flat-shape per-message label. label9: type: string description: Optional flat-shape per-message label. label10: type: string description: Optional flat-shape per-message label. Labels: type: object description: Labels object. Keys must be of the form `label1`..`label10`; values must be strings. additionalProperties: type: string maxProperties: 10 example: label1: campaign-id-42 label2: presale_event_2026 BatchRequest: type: object required: - target_type - messages additionalProperties: false properties: request_id: type: string maxLength: 255 description: Optional caller-supplied id. For non-customer_id target types, duplicate request_ids in a rolling window are rejected with 400. campaign_key: type: string maxLength: 255 description: Optional caller-supplied label for the Localytics campaign. No whitespace. target_type: type: string enum: - customer_id - audience_id - profile - broadcast labels: allOf: - $ref: '#/components/schemas/Labels' description: Batch-level labels applied to every message. For customer_id, per-message `labels` override these on key conflicts. messages: type: array minItems: 1 description: 'Per `target_type`: customer_id allows many entries; audience_id / profile / broadcast must have exactly one.' items: oneOf: - $ref: '#/components/schemas/MessageCustomerId' - $ref: '#/components/schemas/MessageAudienceId' - $ref: '#/components/schemas/MessageProfile' - $ref: '#/components/schemas/MessageBroadcast' all_devices: type: boolean test: type: boolean Error: type: object properties: error: type: string securitySchemes: basicAuth: type: http scheme: basic description: HTTP Basic with `api_key:api_secret`.