Elocuenti Events API

The events API from Elocuenti — 1 operation(s) for events.

GitHub OpenAPI

Operations 1

POST /api/v1/events Send events of your contacts #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/elocuenti-com:elocuenti-com-events-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

elocuenti-com-events-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Elocuenti Events API
  version: 1.0.0
  description: 'The public REST API of Elocuenti: contacts, conversations, funnels, WhatsApp templates, knowledge base, automations, events, AI calls, webhooks and charges (Colombia).


    Authenticate every request with `Authorization: Bearer `. A key that starts with `eloc_live_` acts in production; one that starts with `eloc_sand_` is a sandbox key: it never messages or calls your customers, and the **Sandbox** line of each operation says what it does instead. Create keys in Settings → API Keys.


    Guides and reference: https://www.elocuenti.com/api/docs'
servers:
- url: https://www.elocuenti.com
tags:
- name: Events
paths:
  /api/v1/events:
    post:
      tags:
      - Events
      summary: Send events of your contacts
      description: 'Records up to 100 events at once: what your customers do in your own systems (a purchase, a sign-up, a form, a visit), so it stays in each contact''s history. Nothing is sent to your customers and the events are not reported to advertising platforms. See them in the dashboard, in Analytics → Explorer → Live Events (filter Custom).


        Each event names its contact with at least one of `contact_id`, `external_id`, `phone` or `email` (all the same contact if you send several), a name in `event`, your own `event_id` and, if you want, `properties` and `occurred_at`. The contact must already exist (`POST /api/v1/contacts`; one created a moment ago can receive events at once).


        Each event is judged on its own: the request is accepted (`202`) when its shape is right, and the answer says how many were recorded, which were already known (`duplicates`) and which were rejected, by position, with the field and the reason: fix only those and send them again. The same `event` with the same `event_id` is never recorded twice, so repeat a request whenever you are not sure it arrived (an `event_id` belongs to its `event` name). This operation does not use `Idempotency-Key`.


        `properties` holds up to 30 keys and 4 KB; `occurred_at` can be up to 30 days in the past and 24 hours ahead. A key records up to 10,000 new events in each 24-hour period, counted from its first event.


        **Errors:** `422` when the request itself is wrong (no events, more than 100, a field that is not listed): nothing is recorded. `413 payload_too_large`. `429 daily_limit_exceeded` past the day''s limit: nothing in that request is recorded. `503 service_unavailable`: nothing was recorded, try again. `503 outcome_unknown`: send the same request again; what was already recorded comes back in `duplicates`.


        **Permission:** `events:write` · **Sandbox:** checked, nothing is saved or sent (`simulated: true`) · **Max body:** 512 KB'
      operationId: send_events
      security:
      - ApiKey: []
      x-access:
        permission: events:write
        sandbox: simulate
        maxBody: 512 KB
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/EventsBody'
            examples:
              purchase:
                summary: A purchase, by phone
                value:
                  events:
                  - phone: '+573001234567'
                    event: purchase
                    event_id: order-1042
                    properties:
                      value: 189900
                      currency: COP
                      order_number: '1042'
                    occurred_at: '2026-10-27T15:04:05Z'
              mixed:
                summary: Several contacts and kinds of events
                value:
                  events:
                  - external_id: crm-10042
                    event: lead
                    event_id: form-88
                    properties:
                      source: landing
                      plan: pro
                  - email: ana@ejemplo.com
                    event: purchase
                    event_id: order-1043
                    properties:
                      value: 59900
                      currency: COP
        required: true
      responses:
        '202':
          description: The request was accepted. Look at `rejected` for the events that were not recorded. With a sandbox key, `simulated` is `true` and nothing was recorded.
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EventsResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '413':
          $ref: '#/components/responses/PayloadTooLarge'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          $ref: '#/components/responses/InternalError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
components:
  schemas:
    EventItem:
      type: object
      properties:
        contact_id:
          type: string
          format: uuid
          pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$
          description: The identifier of the contact, as returned by the contacts operations.
          examples:
          - 00000000-0000-4000-8000-0000000000d1
          title: Contact Id
        external_id:
          type: string
          minLength: 1
          maxLength: 255
          description: The identifier the contact has in your own system, the same one you sent when you created the contact (`external_id`).
          examples:
          - crm-10042
          title: External Id
        phone:
          type: string
          pattern: ^\+[1-9]\d{6,14}$
          description: 'The contact''s phone number in international format (E.164): a plus sign, the country code and the number, with no spaces or dashes. Old regional formats (for example a Mexican mobile written with the extra 1 after +52) are matched to the same contact as the current one.'
          examples:
          - '+573001234567'
          title: Phone
        email:
          type: string
          maxLength: 254
          format: email
          description: 'The contact''s email address. If two contacts share it, the event is refused as `ambiguous`: name the contact with `phone`, `external_id` or `contact_id` instead.'
          examples:
          - ana@ejemplo.com
          title: Email
        event:
          type: string
          pattern: ^[a-z][a-z0-9_.]{0,63}$
          description: 'The name of the event: lowercase letters, digits, `_` and `.`, from a letter, up to 64 characters. Use the same name every time the same thing happens. `purchase` and `lead` are the usual ones. A new name needs no setup: it exists from the first time you send it.'
          examples:
          - purchase
          title: Event
        event_id:
          type: string
          pattern: ^[A-Za-z0-9_.:-]{1,128}$
          description: 'Your own identifier for this occurrence (an order number, a form id): letters, digits and `_ . : -`, from 1 to 128 characters. Sending the same `event` with the same `event_id` again never records it twice, so you can retry safely. The same `event_id` under another `event` name is another event.'
          examples:
          - order-1042
          title: Event Id
        properties:
          $ref: '#/components/schemas/EventProperties'
        occurred_at:
          type: string
          format: date-time
          pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
          description: When it happened (ISO 8601, with a time zone). Up to 30 days in the past and 24 hours ahead. An event outside that window is rejected, unless it was already recorded (then it comes back as a duplicate). If you leave it out, it is the moment we receive the event.
          examples:
          - '2026-10-27T15:04:05Z'
          title: Occurred At
      required:
      - event
      - event_id
      additionalProperties: false
      description: One event of one contact. Name the contact with at least one of `contact_id`, `external_id`, `phone` or `email`; if you send several, they must all be the same contact.
      title: EventItem
    EventsBody:
      type: object
      properties:
        events:
          minItems: 1
          maxItems: 100
          type: array
          items:
            $ref: '#/components/schemas/EventItem'
          description: 'The events to record, from 1 to 100. Each one is checked on its own: the ones that pass are recorded and the answer lists, by position, the ones that did not.'
          title: Events
      required:
      - events
      additionalProperties: false
      description: The events to record.
      title: EventsBody
    EventsResult:
      type: object
      properties:
        accepted:
          type: integer
          description: How many events are new and were recorded. With a sandbox key, how many would have been.
          examples:
          - 2
          title: Accepted
        duplicates:
          type: array
          items:
            type: integer
          description: The positions of the events whose `event` and `event_id` were already recorded. They are not recorded again and you do not need to fix anything.
          examples:
          - - 1
          title: Duplicates
        rejected:
          type: array
          items:
            $ref: '#/components/schemas/EventRejection'
          description: The events that did not pass, one entry each. Fix those and send them again; the rest are already done.
          title: Rejected
      required:
      - accepted
      - duplicates
      - rejected
      description: What happened to each event of the request.
      examples:
      - accepted: 1
        duplicates:
        - 1
        rejected:
        - index: 2
          details:
          - field: events.2.phone
            issue: not_found
      title: EventsResult
    EventRejection:
      type: object
      properties:
        index:
          type: integer
          description: The position of the event in your request, starting at 0.
          examples:
          - 2
          title: Index
        details:
          type: array
          items:
            type: object
            properties:
              field:
                type: string
                description: The field that failed, as a path that starts with its position.
                examples:
                - events.2.phone
                title: Field
              issue:
                type: string
                description: 'What is wrong: an issue any field can have (`required`, `invalid_type`, `invalid_format`, `too_small`, `too_big`, `invalid_value`, `unrecognized_field`) or one specific to events: `identity_required` (no contact named), `not_found` (no contact with that value), `ambiguous` (two contacts share it, like an email: name the contact with `phone`, `external_id` or `contact_id`) or `identity_conflict` (the values name different contacts). It never repeats the value you sent.'
                examples:
                - not_found
                title: Issue
            required:
            - field
            - issue
          description: One entry per field that failed.
          title: Details
      required:
      - index
      - details
      description: An event that was not recorded, and why.
      title: EventRejection
    Error:
      type: object
      properties:
        error:
          type: string
          description: What happened and what to do about it, in English or Spanish (it follows the `Accept-Language` header). Meant for a person; do not parse it.
          examples:
          - The API key has expired. Create a new key in Settings → API Keys and use it instead.
          title: Error
        code:
          type: string
          enum:
          - missing_api_key
          - invalid_api_key
          - api_key_expired
          - api_key_inactive
          - forbidden
          - legacy_key_not_allowed
          - creator_cannot_attend_conversations
          - api_key_owner_inactive
          - sandbox_not_supported
          - not_found
          - media_expired
          - media_not_ready
          - conflict
          - template_name_taken
          - template_being_created
          - template_content_rejected
          - template_limit_reached
          - whatsapp_not_connected
          - whatsapp_connection_unavailable
          - whatsapp_rate_limited
          - webhook_limit_reached
          - rotation_in_progress
          - webhook_url_taken
          - webhook_content_not_allowed
          - webhook_inactive
          - contact_cannot_be_called
          - call_outside_window
          - calls_not_available
          - phone_line_unavailable
          - call_capacity_reached
          - call_in_progress
          - call_not_placed
          - request_in_progress
          - idempotency_key_reused
          - invalid_json
          - invalid_request
          - payload_too_large
          - rate_limit_exceeded
          - daily_limit_exceeded
          - temporary_conflict
          - outcome_unknown
          - service_unavailable
          - internal_error
          description: A stable identifier of the error. Branch on this, not on `error`. Every code is explained in the error guide.
          examples:
          - api_key_expired
          title: Code
        request_id:
          type: string
          description: The identifier of this request. Give it to support if you need help.
          examples:
          - 3f9a1c07d2b4
          title: Request Id
        details:
          description: 'On `invalid_request`: one entry per field that failed. A `404` or `409` that blames one field of your request (for example, an id that does not exist) names it here too.'
          type: array
          items:
            $ref: '#/components/schemas/FieldIssue'
          title: Details
        doc_url:
          type: string
          description: The section of the error guide that explains this code.
          examples:
          - https://www.elocuenti.com/api/docs/errors#api_key_expired
          title: Doc Url
      required:
      - error
      - code
      - request_id
      - doc_url
      description: The body of an error answer.
      title: Error
    EventsResponse:
      type: object
      properties:
        data:
          $ref: '#/components/schemas/EventsResult'
        request_id:
          type: string
          description: The identifier of this request. Give it to support if you need help.
          examples:
          - 3f9a1c07d2b4
          title: Request Id
        simulated:
          description: 'Present, and `true`, only when you used a sandbox key: the request was checked and answered as if it had worked, but nothing was saved.'
          type: boolean
          const: true
          title: Simulated
      required:
      - data
      - request_id
      title: EventsResponse
    FieldIssue:
      type: object
      properties:
        field:
          type: string
          description: 'The field that failed: its name, or a dotted path for a nested one (`items.0.name`).'
          examples:
          - name
          title: Field
        issue:
          type: string
          description: 'What is wrong with it: `required`, `invalid_type`, `invalid_format`, `too_small`, `too_big`, `invalid_value` or `unrecognized_field`. An operation that refers to another resource by id can also say `not_found` (that id does not exist in your business) or a reason specific to it, which its page explains. It never repeats the value you sent.'
          examples:
          - required
          title: Issue
      required:
      - field
      - issue
      description: One field that did not pass validation.
      title: FieldIssue
    EventProperties:
      type: object
      propertyNames:
        type: string
        pattern: ^[a-z][a-z0-9_]{0,63}$
      additionalProperties:
        anyOf:
        - type: string
          maxLength: 500
        - type: number
        - type: boolean
        - type: 'null'
      description: What happened, as a flat object of up to 30 keys. Keys are lowercase letters, digits and underscores, from a letter, up to 64 characters. Each value is a text (up to 500 characters), a number, `true`/`false` or `null`; nested objects and lists are refused. All of it, as JSON, fits in 4096 bytes.
      examples:
      - value: 189900
        currency: COP
        order_number: '1042'
      title: EventProperties
  headers:
    X-RateLimit-Reset:
      description: 'The moment that window ends, as a Unix timestamp (seconds since 1970-01-01 UTC). It is not the seconds to wait: for that, use `Retry-After`.'
      schema:
        type: integer
    Retry-After:
      description: 'When the answer asks you to wait (a rate limit, a request still being processed, a temporary failure): how many seconds to wait before sending the request again.'
      schema:
        type: integer
    X-RateLimit-Limit:
      description: How many requests the key may make in the window that applies to this answer.
      schema:
        type: integer
    X-RateLimit-Remaining:
      description: How many requests are left in that window.
      schema:
        type: integer
    X-Request-Id:
      description: The identifier of this request, also in the body as `request_id`. Send your own `X-Request-Id` (up to 128 letters, digits, `.`, `_`, `:` or `-`) and it comes back unchanged, so you can match your logs with ours.
      schema:
        type: string
  responses:
    TooManyRequests:
      description: 'Too many requests.


        - `whatsapp_rate_limited`: WhatsApp is limiting how fast the business can create or delete templates. Wait a few minutes and try again with the same Idempotency-Key. WhatsApp allows a limited number of new templates per hour.

        - `call_capacity_reached`: All the business''s phone lines for AI calls are busy right now. Nothing was dialed. Wait the seconds in the `Retry-After` header and send the request again; some lines are always kept free for your team''s own calls.

        - `rate_limit_exceeded`: Too many requests: the limit was reached. Wait the seconds in the `Retry-After` header and try again. Your key''s limits are in `GET /api/v1/me`.

        - `daily_limit_exceeded`: This API key reached the number of changes it can make in a day for this operation. Nothing was changed. Send only what changed since your last sync, or wait until tomorrow; the day''s limit is in the operation''s page.'
      headers:
        Retry-After:
          $ref: '#/components/headers/Retry-After'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    InternalError:
      description: 'Something went wrong on our side.


        - `internal_error`: An unexpected error happened on our side. Do not blindly repeat a write: check whether it was applied, or repeat it with the same Idempotency-Key. If it keeps failing, write to us with the `request_id`.'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    BadRequest:
      description: 'The request could not be read.


        - `invalid_json`: The request body is not valid JSON. Send a JSON object with the `Content-Type: application/json` header.'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    PayloadTooLarge:
      description: 'The request body is too large.


        - `payload_too_large`: The request body is bigger than this operation accepts. Send less data in a single request; each operation''s page states its maximum size.'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Forbidden:
      description: 'The API key is valid but cannot do this.


        - `forbidden`: The API key does not have the permission this operation needs. Create a new key with the permission the operation documents: the permissions of a key are set when it is created.

        - `legacy_key_not_allowed`: This operation is not available to the original business key (the one that starts with `eloq_` or `elocuenti_`). Create an API key in Settings → API Keys (it starts with `eloc_live_` or `eloc_sand_`) and use it.

        - `creator_cannot_attend_conversations`: The team that attends conversations is not shown to this key, because the person who created it does not attend conversations. Read the team with a key created by an owner or an administrator.

        - `sandbox_not_supported`: This operation is not available with a sandbox key. Use a production key (`eloc_live_`), or check the operation''s page to see how it behaves in sandbox.

        - `webhook_content_not_allowed`: Receiving the text of the messages needs a key with the `conversations:read` permission that was created by an owner or an administrator. The text of every message of the business would reach your address, so it is limited to who can read all the conversations. Create the subscription (or change it) with a key made by an owner or an administrator that holds `conversations:read`, or leave `include_message_content` off and read each message with the API.

        - `calls_not_available`: The business''s plan or billing status does not allow outbound calls. Nothing was dialed. Check the plan and the billing status in the dashboard (for example, a trial does not include voice calls).'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    ServiceUnavailable:
      description: 'The service could not complete the request.


        - `temporary_conflict`: The request collided with another change made at the same moment and was not applied. Send it again right away: nothing was changed, so repeating it is safe.

        - `outcome_unknown`: We could not confirm whether the operation was completed. If the operation accepts an Idempotency-Key, repeat it with the same key: if it was already applied, you will get the same result. If it does not accept one, check the state before repeating it.

        - `service_unavailable`: The service cannot answer right now. Try again in a few seconds. If it persists, write to us at contacto@elocuenti.com with the `request_id` of the answer.'
      headers:
        Retry-After:
          $ref: '#/components/headers/Retry-After'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Unauthorized:
      description: 'The API key was not accepted.


        - `missing_api_key`: The request has no API key. Send it in the Authorization header: `Authorization: Bearer <your key>`.

        - `invalid_api_key`: The API key is not recognized. Check that it is complete and was copied correctly. If it still fails, create a new one in Settings → API Keys.

        - `api_key_expired`: The API key has expired. Create a new key in Settings → API Keys and use it instead.

        - `api_key_inactive`: The API key was revoked. Create a new key in Settings → API Keys and use it instead.

        - `api_key_owner_inactive`: The person who created this key is no longer active in the business. Ask an owner or administrator to transfer it to another person in Settings → API Keys, or create a new one.'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    UnprocessableEntity:
      description: 'The request did not pass validation.


        - `template_content_rejected`: WhatsApp did not accept the content of the template, so it was not created. Look at `details`: it says which part (`header`, `body`, `footer`, `buttons`) and why. Fix it and send the request again with a new Idempotency-Key. If `details` only says `template`, WhatsApp gave no more information: review the text and the category against WhatsApp''s template rules, and write to us with the `request_id` if you cannot find the cause.

        - `call_not_placed`: The phone network did not accept the call, so it was not placed. Check that the contact''s number is a real number that can receive calls and that the country is one the business can call. Repeating the same request will be refused again; write to us with the `request_id` if the number is valid.

        - `idempotency_key_reused`: This Idempotency-Key was already used with a different request. Use a new Idempotency-Key for each different operation. Reuse a key only to repeat the exact same request.

        - `invalid_request`: The request does not pass validation. The `details` list says which fields and why. Fix each field listed in `details` and send the request again.'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  securitySchemes:
    ApiKey:
      type: http
      scheme: bearer
      bearerFormat: API key